1. 程式人生 > >RAW-OS學習之——訊息佇列(queue)

RAW-OS學習之——訊息佇列(queue)

RAW_U16 raw_queue_end_post(RAW_QUEUE *p_q, RAW_VOID *p_void) /* p_void為一個void型別的指標 */ 
{
	#if (RAW_QUEUE_FUNCTION_CHECK > 0)
	/* 無效的RAW_QUEUE對像 */ 
	if (p_q == 0) {		
		return RAW_NULL_OBJECT;
	}
	/* 無效的訊息儲存地址 */
	if (p_void == 0) {		
		return RAW_NULL_POINTER;
	}	
	#endif

	TRACE_QUEUE_EP_TIME_RECORD(p_q, p_void);
	/*開了最大關中斷0us,則要用int_msg_post轉發 */ 
	#if (CONFIG_RAW_ZERO_INTERRUPT > 0)	
	if (raw_int_nesting && raw_sched_lock) {		
		return int_msg_post(RAW_TYPE_Q_END, p_q, p_void, 0, 0, 0);
	}	
	#endif
	/* 正常情況下的訊息傳送,喚醒一個任務 */ 
	return msg_post(p_q, p_void,  SEND_TO_END, WAKE_ONE_QUEUE);	
}
3.傳送訊息raw_queue_front_post()原始碼分析,此函式是把訊息發到佇列頭部:
RAW_U16 raw_queue_front_post(RAW_QUEUE *p_q, RAW_VOID *p_void)
{
	#if (RAW_QUEUE_FUNCTION_CHECK > 0)
	/* 無效的RAW_QUEUE OBJECT */
	if (p_q == 0) {		
		return RAW_NULL_OBJECT;
	}
	/* 無效的訊息儲存地址,p_void本身是一個指標變數 */
	if (p_void == 0) {		
		return RAW_NULL_POINTER;
	}	
	#endif

	TRACE_QUEUE_FP_TIME_RECORD(p_q, p_void);
	/* 最大關中斷0特性開啟,則通過task_0轉發 */
	#if (CONFIG_RAW_ZERO_INTERRUPT > 0)
	if (raw_int_nesting && raw_sched_lock) {		
		return int_msg_post(RAW_TYPE_Q_FRONT, p_q, p_void, 0, 0, 0);
	}	
	#endif
	/*正常情況下發送訊息,喚醒一個任務 */
	return msg_post(p_q, p_void,SEND_TO_FRONT, WAKE_ONE_QUEUE);
}
注意到raw_queue_end_post和raw_queue_front_post最終都是呼叫了msg_post,下面看下msg_post原始碼,看它完成了什麼工作
/*
函式名稱:msg_post
引數說明:p_q:目標操作佇列; p_void: 指向將要傳送的訊息的指標的地址
		  opt_send_method: 傳送到頭部(SEND_TO_FRONT)還尾部(SEND_TO_END)
		  opt_wake_all: 響醒一個任務還是喚醒所有任務
返回值: RAW_SUCCESS:傳送成功;RAW_MSG_MAX:佇列已滿
*/
RAW_U16 msg_post(RAW_QUEUE *p_q, RAW_VOID *p_void, RAW_U8 opt_send_method, RAW_U8 opt_wake_all) {
	LIST *block_list_head;	/* pend list head */ 

 	RAW_SR_ALLOC();
	RAW_CRITICAL_ENTER();
	/* block object type error */
	if (p_q->common_block_obj.object_type != RAW_QUEUE_OBJ_TYPE) {		
		RAW_CRITICAL_EXIT();
		return RAW_ERROR_OBJECT_TYPE;
	}
	/* 指向Pend list頭部 */
	block_list_head = &p_q->common_block_obj.block_list;
	/* 佇列已滿,直接返回,注意此時會丟棄資料 */
	if (p_q->msg_q.current_numbers >= p_q->msg_q.size) { 
		RAW_CRITICAL_EXIT();		
		TRACE_QUEUE_MSG_MAX(raw_task_active, p_q, p_void, opt_send_method);
		return RAW_MSG_MAX;
	}
	/* 程式執行到此說明佇列不滿,且pend list為空(沒有任務阻塞),則把訊息加到隊中*/
	if (is_list_empty(block_list_head)) {        
		/* 佇列中的訊息數目+1 */
		p_q->msg_q.current_numbers++;                                

		/*update peak_numbers for debug*/
		if (p_q->msg_q.current_numbers > p_q->msg_q.peak_numbers) {
			p_q->msg_q.peak_numbers = p_q->msg_q.current_numbers;
		}
		/* 傳送訊息到佇列的尾部 */
		if (opt_send_method == SEND_TO_END)  {
			/* 更新寫指標指向最新加入的訊息 */
			*p_q->msg_q.write++ = p_void;                              
			/* 寫指標寫到了尾部,則從頭開始寫 */
			if (p_q->msg_q.write == p_q->msg_q.queue_end) {  			
				p_q->msg_q.write = p_q->msg_q.queue_start;				
			} 
		}
		/* 傳送訊息到佇列的頭部 */
		else {
			 /* 如果讀指標現在在頭部,則要把訊息加到隊尾 */
			if (p_q->msg_q.read == p_q->msg_q.queue_start) {                
	        	p_q->msg_q.read = p_q->msg_q.queue_end;
	    	}
			/* 讀指標-1 */
			p_q->msg_q.read--;
			/* 更新讀指標指向最新入隊的訊息 */
			*p_q->msg_q.read = p_void; 
		}		
		RAW_CRITICAL_EXIT();
		/* 用於多對像阻塞時的回撥 */		
		if (p_q->queue_send_notify) {
			p_q->queue_send_notify(p_q);	
		}
		TRACE_QUEUE_MSG_POST(raw_task_active, p_q, p_void, opt_send_method); 
		return RAW_SUCCESS;
	}

	/*程式執行到此,說明pend list非空,如果是WAKE ALL,則逐個喚醒pend task */
	if (opt_wake_all) {
		while (!is_list_empty(block_list_head)) {			
			wake_send_msg(list_entry(block_list_head->next, RAW_TASK_OBJ, task_list),  p_void);				
			TRACE_QUEUE_WAKE_TASK(raw_task_active, list_entry(block_list_head->next, RAW_TASK_OBJ, task_list), p_void, opt_wake_all);
		}		
	}
	/*wake hignhest priority task blocked on this queue and send msg to it*/
	else {		
		wake_send_msg(list_entry(block_list_head->next, RAW_TASK_OBJ, task_list),  p_void);		
		TRACE_QUEUE_WAKE_TASK(raw_task_active, list_entry(block_list_head->next, RAW_TASK_OBJ, task_list), p_void, opt_wake_all);
	}	
	RAW_CRITICAL_EXIT();
	/* 執行一次任務排程 */
	raw_sched();    
	return RAW_SUCCESS;
}

上面程式中喚醒任務的同時把訊息指標也給任務控制塊的訊息指標了了,wake_send_msg原始碼如下: