平台:VS2010 版本:1.04
1:传递地址
我们先看看消息队列的数据结构:
RAW_QUEUE:
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) {rn RAW_ZERO_NUMBER;
}
/*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这个单词就明白了。
转载于:https://blog.51cto.com/pregnant/1411255