0413

等待一个消息队列中的消息,OSQPend()

  1. 程序清单 L6.22是OSQPend()函数的源代码。OSQPend()函数首先检查事件控制块是否是由OSQCreate()函数建立的[L6.22(1)],接着,该函数检查消息队列中是否有消息可用(即.OSQEntries是否大于0)[L6.22(2)]。如果有,OSQPend()函数将指向消息的指针复制到msg变量中,并让.OSQOut指针指向队列中的下一个单元[L6.22(3)],然后将队列中的有效消息数减1 [L6.22(4)]。因为消息队列是一个循环的缓冲区,OSQPend()函数需要检查.OSQOut是否超过了队列中的最后一个单元 [L6.22(5)]。当发生这种越界时,就要将.OSQOut重新调整到指向队列的起始单元 [L6.22(6)]。这是我们调用OSQPend()函数时所期望的,也是执行OSQPend()函数最快的路径。  
  2.   
  3. 程序清单 L6.22 在一个消息队列中等待一条消息  
  4. void *OSQPend (OS_EVENT *pevent, INT16U timeout, INT8U *err)  
  5. {  
  6.     void  *msg;  
  7.     OS_Q  *pq;  
  8.   
  9.   
  10.     OS_ENTER_CRITICAL();  
  11.     if (pevent->OSEventType != OS_EVENT_TYPE_Q) {                     (1)  
  12.         OS_EXIT_CRITICAL();  
  13.         *err = OS_ERR_EVENT_TYPE;  
  14.         return ((void *)0);  
  15.     }  
  16.     pq = pevent->OSEventPtr;  
  17.     if (pq->OSQEntries != 0) {                                       (2)  
  18.         msg = *pq->OSQOut++;                                       (3)  
  19.         pq->OSQEntries--;                                             (4)  
  20.         if (pq->OSQOut == pq->OSQEnd) {                              (5)            pq->OSQOut = pq->OSQStart;                              (6)  
  21.         }  
  22.         OS_EXIT_CRITICAL();  
  23.         *err = OS_NO_ERR;  
  24.     } else if (OSIntNesting > 0) {                                   (7)  
  25.         OS_EXIT_CRITICAL();  
  26.         *err = OS_ERR_PEND_ISR;  
  27.     } else {  
  28.         OSTCBCur->OSTCBStat    |= OS_STAT_Q;                       (8)  
  29.         OSTCBCur->OSTCBDly      = timeout;  
  30.         OSEventTaskWait(pevent);  
  31.         OS_EXIT_CRITICAL();  
  32.         OSSched();                                                  (9)  
  33.         OS_ENTER_CRITICAL();  
  34.         if ((msg = OSTCBCur->OSTCBMsg) != (void *)0) {              (10)  
  35.             OSTCBCur->OSTCBMsg      = (void *)0;  
  36.             OSTCBCur->OSTCBStat     = OS_STAT_RDY;  
  37.             OSTCBCur->OSTCBEventPtr = (OS_EVENT *)0;              (11)  
  38.             OS_EXIT_CRITICAL();  
  39.             *err                    = OS_NO_ERR;  
  40.         } else if (OSTCBCur->OSTCBStat & OS_STAT_Q) {                (12)  
  41.             OSEventTO(pevent);                                     (13)  
  42.             OS_EXIT_CRITICAL();  
  43.             msg                     = (void *)0;                     (14)  
  44.             *err                    = OS_TIMEOUT;  
  45.         } else {  
  46.             msg = *pq->OSQOut++;                                  (15)  
  47.             pq->OSQEntries--;  
  48.             if (pq->OSQOut == pq->OSQEnd) {  
  49.                 pq->OSQOut = pq->OSQStart;  
  50.             }  
  51.             OSTCBCur->OSTCBEventPtr = (OS_EVENT *)0;              (16)  
  52.             OS_EXIT_CRITICAL();  
  53.             *err = OS_NO_ERR;  
  54.         }  
  55.     }  
  56.     return (msg);                                                   (17)  
  57. }如果这时消息队列中没有消息(.OSEventEntries是0),OSQPend()函数检查它的调用者是否是中断服务子程序[L6.22(7)]。象OSSemPend()和OSMboxPend()函数一样,不能在中断服务子程序中调用OSQPend(),因为中断服务子程序是不能等待的。但是,如果消息队列中有消息,即使从中断服务子程序中调用OSQPend()函数,也一样是成功的。  
  58. 如果消息队列中没有消息,调用OSQPend()函数的任务被挂起[L6.22(8)]。当有其它的任务向该消息队列发送了消息或者等待时间超时,并且该任务成为最高优先级任务时,OSSched()返回[L6.22(9)]。这时,OSQPend()要检查是否有消息被放到该任务的任务控制块中[L6.22(10)]。如果有,那么该次函数调用成功,把任务的任务控制块中指向消息队列的指针删除[L6.22(17)],并将对应的消息被返回到调用函数[L6.22(17)]。  
  59. 在OSQPend()函数中,通过检查任务的任务控制块中的.OSTCBStat域,可以知道是否等到时间超时。如果其对应的OS_STAT_Q位被置1,说明任务等待已经超时[L6.22(12)]。这时,通过调用函数OSEventTo()可以将任务从消息队列的等待任务列表中删除[L6.22(13)]。这时,因为消息队列中没有消息,所以返回的指针是NULL[L6.22(14)]。  
  60. 如果任务控制块标志位中的OS_STAT_Q位没有被置1,说明有任务发出了一条消息。OSQPend()函数从队列中取出该消息[L6.22(15)]。然后,将任务的任务控制中指向事件控制块的指针删除[L6.22(16)]。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值