平台:VS2010 版本:1.04
我们先看看消息队列的数据结构:
typedef struct RAW_QUEUE { RAW_COMMON_BLOCK_OBJECT common_block_obj; RAW_MSG_Q msg_q; RAW_VOID (*queue_send_notify)(struct RAW_QUEUE *queue_ptr); } RAW_QUEUE;
RAW_MSG_Q:
typedef struct RAW_MSG_Q { RAW_VOID **queue_start; /* Pointer to start of queue data */ RAW_VOID **queue_end; /* Pointer to end of queue data */ RAW_VOID **write; /* Pointer to where next message will be inserted in the Q */ RAW_VOID **read; /* Pointer to where next message will be extracted from the Q */ MSG_SIZE_TYPE size; /* Size of queue (maximum number of entries) */ MSG_SIZE_TYPE current_numbers; /* Current number of entries in the queue */ MSG_SIZE_TYPE peak_numbers; /* Peak number of entries in the queue */ } RAW_MSG_Q;
Common_block_obj:
typedef struct RAW_COMMON_BLOCK_OBJECT { LIST block_list; RAW_U8 *name; RAW_U8 block_way; RAW_U8 object_type; } RAW_COMMON_BLOCK_OBJECT;
消息队列是用来在两个任务之间传递数据的,它相当于一个有存储功能的数据通道。例如:Task1把MSG1放入queue,则Task2可从queue中MSG1。需要注意的是消息传递是地址而不是数值。其实消息的通信机制和信号量是类似,只是一个需要传递参数一个不需要。下面我们就来看看源代码:
Raw_queue_creat:
RAW_U16 raw_queue_create(RAW_QUEUE *p_q, RAW_U8 *p_name, RAW_VOID **msg_start, MSG_SIZE_TYPE number) { #if (RAW_QUEUE_FUNCTION_CHECK > 0) if (p_q == 0) { return RAW_NULL_OBJECT; } if (msg_start == 0) { return RAW_NULL_POINTER; } if (number == 0u) { return RAW_ZERO_NUMBER; } #endif /*init the queue blocked list*/ list_init(&p_q->common_block_obj.block_list); p_q->common_block_obj.name = p_name; p_q->common_block_obj.block_way = RAW_BLOCKED_WAY_PRIO; p_q->msg_q.queue_start = msg_start; /* Initialize the queue */ p_q->msg_q.queue_end = &msg_start[number]; //warning:queue not include the queue_end p_q->msg_q.write = msg_start; p_q->msg_q.read = msg_start; p_q->msg_q.size = number; p_q->msg_q.current_numbers = 0u; p_q->msg_q.peak_numbers = 0u; p_q->queue_send_notify = 0; p_q->common_block_obj.object_type = RAW_QUEUE_OBJ_TYPE; TRACE_QUEUE_CREATE(raw_task_active, p_q); return RAW_SUCCESS; }
create函数最主要是对MSG结构进行赋值,都很好理解的。这里看三点:
1 block_way:PRIO or FIFO,消息支持的任务阻塞策略:任务优先级或者是先来先出和信号量相同
2 queue_end:注意queue队列不包含queue_end指向的地址,看到&msg_start[number]中number就应该明白了
3 peak_numbers:这个是queue队列中最多消息的数量
Msg_post:
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; RAW_SR_ALLOC(); RAW_CRITICAL_ENTER(); if (p_q->common_block_obj.object_type != RAW_QUEUE_OBJ_TYPE) { RAW_CRITICAL_EXIT(); return RAW_ERROR_OBJECT_TYPE; } 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; } /*Queue is not full here, if there is no blocked receive task*/ if (is_list_empty(block_list_head)) { 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 { /* Wrap read pointer to end if we are at the 1st queue entry */ if (p_q->msg_q.read == p_q->msg_q.queue_start) { p_q->msg_q.read = p_q->msg_q.queue_end; } p_q->msg_q.read--; *p_q->msg_q.read = p_void; /* Insert message into queue */ } RAW_CRITICAL_EXIT(); /*if queue is registered with notify function just call it*/ 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; } /*wake all the task blocked on this queue*/ 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(); do_possible_sche(); return RAW_SUCCESS; }
消息传递函数,我们来看下函数的执行过程:
1 判断消息队列的类型
2 判断消息队列是否满了
3 若消息队列中没有被阻塞的任务:
3.1 更新peak_number的值
3.2 根据opt_send_mathod参数将msg放置在消息队列中
3.2.1 消息添加到消息的最后,体会write指针的改变
3.2.2 消息添加到消息的最前,体会read指针的改变----为什么是改变read指针呢?看下满的获取msg函数
4 根据opt_wake_all参数选择唤醒最前面的task还是所有task
wake_send_msg函数和信号量的wake函数一样,只是在这里多一步给task的msg变量赋值的操作,这里就不在分析了。
在这看一点,当消息队列满时,怎么操作呢?raw宏定义了一个TRACE_QUEUE_MSG_POST(NOTE1)函数让你自己去实现。
Raw_queue_receive:
RAW_U16 raw_queue_receive(RAW_QUEUE *p_q, RAW_TICK_TYPE wait_option, RAW_VOID **msg) { RAW_VOID *pmsg; RAW_U16 result; RAW_SR_ALLOC(); #if (RAW_QUEUE_FUNCTION_CHECK > 0) if (raw_int_nesting) { return RAW_NOT_CALLED_BY_ISR; } if (p_q == 0) { return RAW_NULL_OBJECT; } if (msg == 0) { return RAW_NULL_POINTER; } #endif RAW_CRITICAL_ENTER(); if (p_q->common_block_obj.object_type != RAW_QUEUE_OBJ_TYPE) { RAW_CRITICAL_EXIT(); return RAW_ERROR_OBJECT_TYPE; } /*if queue has msgs, just receive it*/ if (p_q->msg_q.current_numbers) { pmsg = *p_q->msg_q.read++; if (p_q->msg_q.read == p_q->msg_q.queue_end) { /*wrap around to start*/ p_q->msg_q.read = p_q->msg_q.queue_start; } *msg = pmsg; p_q->msg_q.current_numbers--; RAW_CRITICAL_EXIT(); TRACE_QUEUE_GET_MSG(raw_task_active, p_q, wait_option, *msg); return RAW_SUCCESS; } if (wait_option == RAW_NO_WAIT) { *msg = (RAW_VOID *)0; RAW_CRITICAL_EXIT(); return RAW_NO_PEND_WAIT; } /*if system is locked, block operation is not allowed*/ SYSTEM_LOCK_PROCESS_QUEUE(); raw_pend_object((RAW_COMMON_BLOCK_OBJECT *)p_q, raw_task_active, wait_option); RAW_CRITICAL_EXIT(); TRACE_QUEUE_GET_BLOCK(raw_task_active, p_q, wait_option); raw_sched(); *msg = (RAW_VOID *)0; result = block_state_post_process(raw_task_active, msg); return result; }
获取msg函数分析如下:
1 判断消息队列类型
2 消息队列中有消息则立即获取后返回。看这里获取是操作read指针来进行着就是为什么消息插在最前面时修改read指针。在消息的传递和获取时都需要操作current_number成员,它用来判断消息队列的使用情况,空、满载和负载。
3 若消息队列中没有消息且wait_option参数为RAW_NO_WAIT则立即返回不等待消息
4 若消息队列中没有消息且wait_option参数不为RAW_NO_WAIT,则会raw_pend_object函数即task进入阻塞状态,具体不分析了因为信号量的阻塞是一样的
5 函数返回的值是msg,在block_state_post_process函数中直接将task的msg赋值给函数返回值
NOTE1:在函数前面加TRACE都是raw的宏定义函数让你自己去实现,看TRACE这个单词就明白了。
RAW-OS:消息队列