1. 程式人生 > >Raw-OS源代碼分析之消息系統-Queue_Buffer

Raw-OS源代碼分析之消息系統-Queue_Buffer

存儲倉庫 ive 優先 free avi 都是 部分 沒有 mar

分析的內核版本號截止到2014-04-15,基於1.05正式版。blogs會及時跟進最新版本號的內核開發進度,若源代碼凝視出現”???”字樣,則是未深究理解部分。

Raw-OS官方站點:http://www.raw-os.org/

Raw-OS托管地址:https://github.com/jorya/raw-os/

有了之前的queue和queue_size的解讀之後。這個queue_buffer就很之簡單了~對於queue是轉發消息的指針,queue_size則是轉發消息指針和消息大小。那麽queue_buffer不在轉存消息的指針,而是將消息copy一份,轉發消息內容和消息大小。

這個定義一個queue_buffer消息的概念~

技術分享

一個queue_buffer消息包含消息的大小,消息詳細數據內容,然後依照上圖的結構進行排列~那麽在queue_buffer中,詳細消息是封裝成以上的結構進行轉發的~

那麽在queue_buffer建立的內部數據存儲倉庫,queue_buffer的消息按這樣排列的

技術分享


當中,head指針指向queue_buffer消息存在的開始位置。tail指針指向queue_buffer消息存在的末尾位置,剩余的沒轉存消息的位置稱為空暇消息

還有註意一點的就是。queue_buffer的queue_buffer消息一定要按4字節對齊的形式存儲在queue_buffer的存儲倉中,原因的話要詳細看代碼才幹說明確

技術分享

Queue_buffer消息的轉存過程和queue和queue_size一樣,僅僅是內核多了復制詳細數據這一部的操作,至於在轉存倉庫的組織形式,都是按各自的消息結構體來組織。queue消息是指向消息的void指針,queue_size就是以消息指針和消息大小組成的queue_size結構體,那麽到這裏queue_buffer就是以消息長度+消息實際內容的形式。

代碼僅僅說明queue_buffer建立。發送queue_buffer消息到queue_buffer的部分

1.queue_buffer的創建

RAW_U16 raw_queue_buffer_create(RAW_QUEUE_BUFFER *q_b, RAW_U8 *p_name, RAW_VOID *msg_buffer, MSG_SIZE_TYPE buffer_size, MSG_SIZE_TYPE max_msg_size)
{
	MSG_SIZE_TYPE bufsz;
	RAW_U8        queue_buffer_align_mask;
	/* 檢查創建消息buffer的邊界條件 */
	#if (RAW_QUEUE_BUFFER_FUNCTION_CHECK > 0)
	if (q_b == 0) {
		return RAW_NULL_OBJECT;
	}

	if (msg_buffer == 0) {
		return RAW_NULL_POINTER;
	}
	#endif
	/* 消息buffer的大小必須滿足4字節的整數倍 */
	bufsz = ROUND_BUFFER_SIZE(buffer_size);
	/* 消息buffer大小為0時,錯誤返回 */
	if (bufsz == 0) {
		return RAW_QUEUE_BUFFER_SIZE_0;
	}
	/* 消息buffer大小不滿足4字節對齊時,錯誤返回 */
	if (bufsz != buffer_size) {
		return RAW_QUEUE_BUFFER_INVALID_SIZE;
	}

	queue_buffer_align_mask = HEADERSZ - 1u;
	/* 消息buffer的內部存儲消息的倉庫的地址相同也要滿足4字節的整數倍對齊 */
	if (((RAW_U32)msg_buffer & queue_buffer_align_mask)){
		return RAW_INVALID_ALIGN;
	}

	/* 初始化消息buffer的堵塞鏈表頭 */
	list_init(&q_b->common_block_obj.block_list);

	q_b->bufsz = bufsz;
	q_b->frbufsz = bufsz;
	q_b->buffer = msg_buffer;
	q_b->maxmsz = max_msg_size;
	q_b->head = 0;
	q_b->tail = 0;

	q_b->common_block_obj.name = p_name;
	q_b->common_block_obj.block_way = RAW_BLOCKED_WAY_PRIO;
	q_b->common_block_obj.object_type = RAW_QUEUE_BUFFER_OBJ_TYPE;

	TRACE_QUEUE_BUFFER_CREATE(raw_task_active, q_b);

	return RAW_SUCCESS;

}


2.發送queue_buffer消息

RAW_U16 raw_queue_buffer_end_post(RAW_QUEUE_BUFFER *q_b, RAW_VOID *p_void, MSG_SIZE_TYPE msg_size)
{
	/* 發送queue buffer消息時的邊界條件檢查 */
	#if (RAW_QUEUE_BUFFER_FUNCTION_CHECK > 0)
	if (q_b == 0) {
		return RAW_NULL_OBJECT;
	}

	if (p_void == 0) {
		return RAW_NULL_POINTER;
	}
	/* 發送queue buffer消息長度不能超過創建queue_buffer定義的最大消息長度 */
	if (msg_size > q_b->maxmsz) {
		return RAW_EXCEED_QUEUE_BUFFER_MSG_SIZE;
	}
	#endif

	/* 開啟0中斷特性後。不能在中斷ISR中發送queue_buffer,而queue和queue_size能夠,想想為什麽??? */
	#if (CONFIG_RAW_ZERO_INTERRUPT > 0)
	if (raw_int_nesting) {
		return RAW_NOT_CALLED_BY_ISR;
	}
	#endif

	return queue_buffer_post(q_b, p_void, msg_size, SEND_TO_END);
}


存儲queue_buffer的核心代碼

RAW_U16 queue_buffer_post(RAW_QUEUE_BUFFER *q_b, RAW_VOID *p_void, MSG_SIZE_TYPE msg_size, RAW_U8 opt_send_method)
{
	LIST *block_list_head;
	RAW_TASK_OBJ *task_ptr;

 	RAW_SR_ALLOC();

	RAW_CRITICAL_ENTER();

	if (q_b->common_block_obj.object_type != RAW_QUEUE_BUFFER_OBJ_TYPE) {

		RAW_CRITICAL_EXIT();
		return RAW_ERROR_OBJECT_TYPE;
	}

	block_list_head = &q_b->common_block_obj.block_list;

	if (!is_queue_buffer_free(q_b, msg_size)) {

		RAW_CRITICAL_EXIT();

		TRACE_QUEUE_BUFFER_MAX(raw_task_active, q_b, p_void, msg_size, opt_send_method);

		return RAW_QUEUE_BUFFER_FULL;
	}

	/* 當queue_buffer內部存儲倉未滿時,就會將消息轉存到存儲倉裏面。並且內部僅僅實現發送存儲倉末尾的操作 */
	if (is_list_empty(block_list_head)) {

		if (opt_send_method == SEND_TO_END)  {
			msg_to_end_buffer(q_b, p_void, msg_size);
		}

		else {
			/* 沒有定義有除發送到存儲倉末尾外的操作 */
		}

		RAW_CRITICAL_EXIT();

		TRACE_QUEUE_BUFFER_POST(raw_task_active, q_b, p_void, msg_size, opt_send_method);

		return RAW_SUCCESS;
	}
	/*
	 * 假設有任務堵塞在queue_buffer上等待消息,個人覺得以下這些操作是為了加快消息傳遞,
	 * 不由queue_buffer的內部存儲倉轉存數據內容。少了一個二次copy的過程
	 *
	 * 找到queue_buffer的堵塞鏈表的最高優先級任務,然後直接將消息內容和大小copy到任務控制塊中,然後喚醒該任務
	 */
	task_ptr = list_entry(block_list_head->next, RAW_TASK_OBJ, task_list);

	raw_memcpy(task_ptr->msg, p_void, msg_size);
	task_ptr->qb_msg_size = msg_size;

	raw_wake_object(task_ptr);

	RAW_CRITICAL_EXIT();

	TRACE_QUEUE_BUFFER_WAKE_TASK(raw_task_active, list_entry(block_list_head->next, RAW_TASK_OBJ, task_list), p_void, msg_size, opt_send_method);

	raw_sched();
	return RAW_SUCCESS;
}


Raw-OS源代碼分析之消息系統-Queue_Buffer