Chinaunix首页 | 论坛 | 博客
  • 博客访问: 1138172
  • 博文数量: 241
  • 博客积分: 10
  • 博客等级: 民兵
  • 技术积分: 2279
  • 用 户 组: 普通用户
  • 注册时间: 2012-11-27 19:53
个人简介

JustForFun

文章分类

全部博文(241)

文章存档

2023年(8)

2022年(2)

2021年(3)

2020年(30)

2019年(11)

2018年(27)

2017年(54)

2016年(83)

2015年(23)

我的朋友

分类: 嵌入式

2015-07-21 22:20:00

ucos os_q.c消息队列机制解剖
图片
图片

typedef struct os_event {
    INT8U    OSEventType;                    /* Type of event control block (see OS_EVENT_TYPE_xxxx)    */
    void    *OSEventPtr;                     /* Pointer to message or queue structure    */
// 不用的时候
将OSEventTbl[OS_MAX_EVENTS]连成链表,被使用时pevent->OSEventPtr     = pq;pq是OS_Q *型。见OSQCreate 
    INT16U   OSEventCnt;                     /* Semaphore Count (not used if other EVENT type)          */
#if OS_LOWEST_PRIO <= 63
    INT8U    OSEventGrp;                     /* Group corresponding to tasks waiting for event to occur */
    INT8U    OSEventTbl[OS_EVENT_TBL_SIZE];  /* List of tasks waiting for event to occur                */
#else
    INT16U   OSEventGrp;                     /* Group corresponding to tasks waiting for event to occur */
    INT16U   OSEventTbl[OS_EVENT_TBL_SIZE];  /* List of tasks waiting for event to occur                */
#endif
#if OS_EVENT_NAME_SIZE > 1
    INT8U    OSEventName[OS_EVENT_NAME_SIZE];
#endif
} OS_EVENT;

ucos_ii.h
OS_EXT  OS_EVENT         *OSEventFreeList;          /* Pointer to list of free EVENT control blocks    */
OS_EXT  OS_EVENT          OSEventTbl[OS_MAX_EVENTS];/* Table of EVENT control blocks                   */
os_core.c中static  void  OS_InitEventList (void)有OSEventFreeList                 = &OSEventTbl[0];


typedef struct os_q {                   /* QUEUE CONTROL BLOCK                                         */
    struct os_q   *OSQPtr;   /* Link to next queue control block in list of free blocks */将OSQTbl[OS_MAX_QS]链接成链表(OS_QInit中)
    void         **OSQStart;            /* Pointer to start of queue data                              */
    void         **OSQEnd;              /* Pointer to end   of queue data                              */
    void         **OSQIn;               /* Pointer to where next message will be inserted  in   the Q  */
    void         **OSQOut;              /* Pointer to where next message will be extracted from the Q  */
    INT16U         OSQSize;             /* Size of queue (maximum number of entries)                   */
    INT16U         OSQEntries;          /* Current number of entries in the queue                      */
} OS_Q;

ucos_ii.h中
OS_EXT  OS_Q             *OSQFreeList;              /* Pointer to list of free QUEUE control blocks    */
OS_EXT  OS_Q              OSQTbl[OS_MAX_QS];        /* Table of QUEUE control blocks                   */
os_q.c中void  OS_QInit (void)有OSQFreeList         = &OSQTbl[0];                /* Only ONE queue!                                */

void  OS_QInit (void)
{
    OSQFreeList         = &OSQTbl[0];                /* Only ONE queue!                                */
    OSQFreeList->OSQPtr = (OS_Q *)0;
    INT16U  i;
    OS_Q   *pq1;
    OS_Q   *pq2;
    OS_MemClr((INT8U *)&OSQTbl[0], sizeof(OSQTbl));  /* Clear the queue table                          */
    pq1 = &OSQTbl[0];
    pq2 = &OSQTbl[1];
    for (i = 0; i < (OS_MAX_QS - 1); i++) {          /* Init. list of free QUEUE control blocks        */
        pq1->OSQPtr = pq2;
        pq1++;
        pq2++;
    }
    pq1->OSQPtr = (OS_Q *)0;
    OSQFreeList = &OSQTbl[0];
}


typedef struct os_q_data {               //此结构有什么用????????
    void          *OSMsg;               /* Pointer to next message to be extracted from queue          */
    INT16U         OSNMsgs;             /* Number of messages in message queue                         */
    INT16U         OSQSize;             /* Size of message queue                                       */
#if OS_LOWEST_PRIO <= 63
    INT8U          OSEventTbl[OS_EVENT_TBL_SIZE];  /* List of tasks waiting for event to occur         */
    INT8U          OSEventGrp;          /* Group corresponding to tasks waiting for event to occur     */
#else
    INT16U         OSEventTbl[OS_EVENT_TBL_SIZE];  /* List of tasks waiting for event to occur         */
    INT16U         OSEventGrp;          /* Group corresponding to tasks waiting for event to occur     */
#endif
} OS_Q_DATA;


os_core.c中
static  void  OS_InitEventList (void)
{
#if (OS_EVENT_EN) && (OS_MAX_EVENTS > 0)
#if (OS_MAX_EVENTS > 1)
    INT16U     i;
    OS_EVENT  *pevent1;
    OS_EVENT  *pevent2;

    OS_MemClr((INT8U *)&OSEventTbl[0], sizeof(OSEventTbl)); /* Clear the event table                   */
    pevent1 = &OSEventTbl[0];
    pevent2 = &OSEventTbl[1];
    for (i = 0; i < (OS_MAX_EVENTS - 1); i++) {             /* Init. list of free EVENT control blocks */
        pevent1->OSEventType    = OS_EVENT_TYPE_UNUSED; 
        pevent1->OSEventPtr     = pevent2;  //将OSEventTbl[OS_MAX_EVENTS]连成链表
// OS_EXT  OS_EVENT          OSEventTbl[OS_MAX_EVENTS];/* Table of EVENT control blocks                   */
        pevent1++;
        pevent2++;
    }
    pevent1->OSEventType            = OS_EVENT_TYPE_UNUSED;
    pevent1->OSEventPtr             = (OS_EVENT *)0;
    OSEventFreeList                 = &OSEventTbl[0];
#endif
#endif
}
OS_EVENT  *OSQCreate (void **start, INT16U size)
{
    OS_EVENT  *pevent;
    OS_Q      *pq; 
    OS_ENTER_CRITICAL();
    pevent = OSEventFreeList;                    /* Get next free event control block                  */
    OS_EXIT_CRITICAL();
    if (pevent != (OS_EVENT *)0)
    {
         /* See if we have an event control block              */
        OS_ENTER_CRITICAL();
        pq = OSQFreeList;                        /* Get a free queue control block                     */
        if (pq != (OS_Q *)0)
        {                   /* Were we able to get a queue control block ?        */
            OSQFreeList            = OSQFreeList->OSQPtr; /* Yes, Adjust free list pointer to next free*/
            OS_EXIT_CRITICAL();
            pq->OSQStart           = start;               /*      Initialize the queue                 */
            pq->OSQEnd             = &start[size];
            pq->OSQIn              = start;             //post有消息从此插入
            pq->OSQOut             = start;           // pend 请求消息从此取出
            pq->OSQSize            = size;
            pq->OSQEntries         = 0;
            pevent->OSEventType    = OS_EVENT_TYPE_Q;
            pevent->OSEventCnt     = 0;
            pevent->OSEventPtr     = pq; //这个指针之前是用来串成链表的。现在换用途了。见结构体的解释
            OS_EventWaitListInit(pevent);                 /*      Initalize the wait list              */
        }
        else
       {
            pevent->OSEventPtr = (void *)OSEventFreeList; /* No,  Return event control block on error  */
            OSEventFreeList    = pevent;
            OS_EXIT_CRITICAL();
            pevent = (OS_EVENT *)0;
        }
    }
    return (pevent);   //将事件头指针通过函数返回值返回给程序员用
}

/*
*********************************************************************************************************
*                                 INITIALIZE EVENT CONTROL BLOCK'S WAIT LIST
*
* Description: This function is called by other uC/OS-II services to initialize the event wait list.
*
* Arguments  : pevent    is a pointer to the event control block allocated to the event.
*
* Returns    : none
*
* Note       : This function is INTERNAL to uC/OS-II and your application should not call it.
*********************************************************************************************************
*/
os_core.c
void  OS_EventWaitListInit (OS_EVENT *pevent)
{
#if OS_LOWEST_PRIO <= 63
    INT8U  *ptbl;
#else
    INT16U *ptbl;
#endif
    INT8U   i;

    pevent->OSEventGrp = 0;                      /* No task waiting on event                           */
    ptbl               = &pevent->OSEventTbl[0];
    for (i = 0; i < OS_EVENT_TBL_SIZE; i++) {
        *ptbl++ = 0;
    }
}

/*
*********************************************************************************************************
*                                   MAKE TASK WAIT FOR EVENT TO OCCUR
*
* Description: This function is called by other uC/OS-II services to suspend a task because an event has
*              not occurred.
*
* Arguments  : pevent   is a pointer to the event control block for which the task will be waiting for.
*
* Returns    : none
*
* Note       : This function is INTERNAL to uC/OS-II and your application should not call it.
*********************************************************************************************************
*/
os_core.c
void  OS_EventTaskWait (OS_EVENT *pevent)
{
    INT8U  y;

    OSTCBCur->OSTCBEventPtr =  pevent;            /* Store pointer to event control block in TCB       */
//将pevent绑到当前任务TCB的OSTCBEventPtr 成员上。
    y                       =  OSTCBCur->OSTCBY;  /* Task no longer ready                              */
    OSRdyTbl[y]            &= ~OSTCBCur->OSTCBBitX;
    if (OSRdyTbl[y] == 0) {
        OSRdyGrp &= ~OSTCBCur->OSTCBBitY;         /* Clear event grp bit if this was only task pending */
    }
    pevent->OSEventTbl[OSTCBCur->OSTCBY] |= OSTCBCur->OSTCBBitX;          /* Put task in waiting list  */这是等待
    pevent->OSEventGrp                   |= OSTCBCur->OSTCBBitY;
//对比函数INT8U  OS_TCBInit (INT8U prio, OS_STK *ptos, OS_STK *pbos, INT16U id, INT32U stk_size, void *pext, INT16U opt)
 //        OSRdyGrp               |= ptcb->OSTCBBitY;         /* Make task ready to run                   */这是运行,一个等待,一个运行。不同。
 //       OSRdyTbl[ptcb->OSTCBY] |= ptcb->OSTCBBitX; 

}
/*
*********************************************************************************************************
*                             MAKE TASK READY TO RUN BASED ON EVENT OCCURING
*
* Description: This function is called by other uC/OS-II services and is used to ready a task that was
*              waiting for an event to occur.

*
* Arguments  : pevent      is a pointer to the event control block corresponding to the event.
*
*              pmsg        is a pointer to a message.  This pointer is used by message oriented services
*                          such as MAILBOXEs and QUEUEs.  The pointer is not used when called by other
*                          service functions.
*
*              msk         is a mask that is used to clear the status byte of the TCB.  For example,
*                          OSSemPost() will pass OS_STAT_SEM, OSMboxPost() will pass OS_STAT_MBOX etc.
*
*              pend_stat   is used to indicate the readied task's pending status:
*
*                          OS_STAT_PEND_OK      Task ready due to a post (or delete), not a timeout or
*                                               an abort.
*                          OS_STAT_PEND_ABORT   Task ready due to an abort.
*
* Returns    : none
*
* Note       : This function is INTERNAL to uC/OS-II and your application should not call it.
*********************************************************************************************************
*/
os_core.c
INT8U  OS_EventTaskRdy (OS_EVENT *pevent, void *pmsg, INT8U msk, INT8U pend_stat)
{
    OS_TCB  *ptcb;
    INT8U    x;
    INT8U    y;
    INT8U    prio;
#if OS_LOWEST_PRIO <= 63
    INT8U    bitx;
    INT8U    bity;
#else
    INT16U   bitx;
    INT16U   bity;
    INT16U  *ptbl;
#endif
//本函数通过pevent带的优先级信息计算出等待这个消息的是哪个优先级的任务。
#if OS_LOWEST_PRIO <= 63
    y     = OSUnMapTbl[pevent->OSEventGrp];             /* Find HPT waiting for message                */
//看看OS_EventTaskWait 函数不难理解吧。
    bity  = (INT8U)(1 << y);
    x     = OSUnMapTbl[pevent->OSEventTbl[y]];
    bitx  = (INT8U)(1 << x);
    prio  = (INT8U)((y << 3) + x);                      /* Find priority of task getting the msg       */

#else
    if ((pevent->OSEventGrp & 0xFF) != 0) {             /* Find HPT waiting for message                */
        y = OSUnMapTbl[pevent->OSEventGrp & 0xFF];
    } else {
        y = OSUnMapTbl[(pevent->OSEventGrp >> 8) & 0xFF] + 8;
    }
    bity = (INT16U)(1 << y);
    ptbl = &pevent->OSEventTbl[y];
    if ((*ptbl & 0xFF) != 0) {
        x = OSUnMapTbl[*ptbl & 0xFF];
    } else {
        x = OSUnMapTbl[(*ptbl >> 8) & 0xFF] + 8;
    }
    bitx = (INT16U)(1 << x);
    prio = (INT8U)((y << 4) + x);                       /* Find priority of task getting the msg       */
#endif
    pevent->OSEventTbl[y] &= ~bitx;                     /* Remove this task from the waiting list      */
    if (pevent->OSEventTbl[y] == 0) {
        pevent->OSEventGrp &= ~bity;                    /* Clr group bit if this was only task pending */
    }
    ptcb                 =  OSTCBPrioTbl[prio];         /* Point to this task's OS_TCB                 */
    ptcb->OSTCBDly       =  0;                          /* Prevent OSTimeTick() from readying task     */
    ptcb->OSTCBEventPtr  = (OS_EVENT *)0;               /* Unlink ECB from this task                   */
#if ((OS_Q_EN > 0) && (OS_MAX_QS > 0)) || (OS_MBOX_EN > 0)
    ptcb->OSTCBMsg       =  pmsg;                       /* Send message directly to waiting task       */
#else
    pmsg                 =  pmsg;                       /* Prevent compiler warning if not used        */
#endif
    ptcb->OSTCBStatPend  =  pend_stat;                  /* Set pend status of post or abort            */
    ptcb->OSTCBStat     &= ~msk;                        /* Clear bit associated with event type        */
    if (ptcb->OSTCBStat ==  OS_STAT_RDY) {              /* See if task is ready (could be susp'd)      */
        OSRdyGrp        |=  bity;                       /* Put task in the ready to run list           */
//这个优先级的任务就已经进入ready状态了,见《uc/os_II优先级判定表OSUnMapTbl》
        OSRdyTbl[y]     |=  bitx;
    }
    return (prio);
}
/*
*********************************************************************************************************
*                          MAKE TASK READY TO RUN BASED ON EVENT TIMEOUT OR ABORT
*
* Description: This function is called by other uC/OS-II services to make a task ready to run because a
*              timeout or abort occurred.

*
* Arguments  : pevent   is a pointer to the event control block which is readying a task.
*
* Returns    : none
*
* Note       : This function is INTERNAL to uC/OS-II and your application should not call it.
*********************************************************************************************************
*/
os_core.c
void  OS_EventTOAbort (OS_EVENT *pevent)//
{
    INT8U  y;
//本函数不通过pevent带的优先级信息计算出等待这个消息的是哪个优先级的任务。而是任务自己 timeout or abort occurred
    y                       =  OSTCBCur->OSTCBY;
    pevent->OSEventTbl[y]  &= ~OSTCBCur->OSTCBBitX;    /* Remove task from wait list                   */
    if (pevent->OSEventTbl[y] == 0x00) {
        pevent->OSEventGrp &= ~OSTCBCur->OSTCBBitY;
    }
    OSTCBCur->OSTCBStatPend =  OS_STAT_PEND_OK;        /* Clear pend status                            */
    OSTCBCur->OSTCBStat     =  OS_STAT_RDY;            /* Set status to ready                          */
    OSTCBCur->OSTCBEventPtr = (OS_EVENT *)0;           /* No longer waiting for event                  */
}





INT8U  OSQPost (OS_EVENT *pevent, void *pmsg)
{
    OS_Q      *pq;
    if (pevent->OSEventType != OS_EVENT_TYPE_Q) {      /* Validate event block type                    */
        return (OS_ERR_EVENT_TYPE);
    }
    OS_ENTER_CRITICAL();
    if (pevent->OSEventGrp != 0)
   {                     /* See if any task pending on queue             */
                                                       /* Ready highest priority task waiting on event */
        (void)OS_EventTaskRdy(pevent, pmsg, OS_STAT_Q, OS_STAT_PEND_OK);
        OS_EXIT_CRITICAL();
        OS_Sched();                                    /* Find highest priority task ready to run      */
        return (OS_ERR_NONE);
    }
    pq = (OS_Q *)pevent->OSEventPtr;                   /* Point to queue control block                 */取出消息OS_Q
    if (pq->OSQEntries >= pq->OSQSize)                  //OSQEntries是进入消息队列中的消息个数
    {               /* Make sure queue is not full                  */
        OS_EXIT_CRITICAL();
        return (OS_ERR_Q_FULL);
    }
    *pq->OSQIn++ = pmsg;                               /* Insert message into queue                    */   
         //*pq->OSQIn=pmsg存入消息后     ++是让OSQIn指针指向下一个地址待下一个消息
    pq->OSQEntries++;                                  /* Update the nbr of entries in the queue       */进入的消息数++
    if (pq->OSQIn == pq->OSQEnd) {                     /* Wrap IN ptr if we are at end of queue     */  消息队列是循环的链表 满则指回Start
        pq->OSQIn = pq->OSQStart;

    }
    OS_EXIT_CRITICAL();
    return (OS_ERR_NONE);
}





void  *OSQPend (OS_EVENT *pevent, INT16U timeout, INT8U *perr)
{
    void      *pmsg;
    OS_Q      *pq;

    OS_ENTER_CRITICAL();
    pq = (OS_Q *)pevent->OSEventPtr;             /* Point at queue control block                       */
    if (pq->OSQEntries > 0)             //有消息在队列中则大于0     OSQEntries是消息队列中的消息总数
    {                    /* See if any messages in the queue                   */
        pmsg = *pq->OSQOut++;                    /* Yes, extract oldest message from the queue         */
        //pmsg=*pq->OSQOut  从消息队列中取出消息  然后++指向下一个待提取的消息
        pq->OSQEntries--;                        /* Update the number of entries in the queue          */消息总数——
        if (pq->OSQOut == pq->OSQEnd) {          /* Wrap OUT pointer if we are at the end of the queue */循环链表满则指回Start
            pq->OSQOut = pq->OSQStart;
        }
        OS_EXIT_CRITICAL();
        *perr = OS_ERR_NONE;
        return (pmsg);                           /* Return message received                            */ 将接收到的的消息通过函数返回值返回
    }
    OSTCBCur->OSTCBStat     |= OS_STAT_Q;        /* Task will have to pend for a message to be posted  */
    //OS_TCB{INT8U   OSTCBStat;/* Task  status */ INT8U  OSTCBStatPend;  /* Task PEND status   } 
   OSTCBCur->OSTCBStatPend  = OS_STAT_PEND_OK; //任务被挂起标志  挂起原因OSTCBCur->OSTCBStat   |= OS_STAT_Q
    OSTCBCur->OSTCBDly       = timeout;          /* Load timeout into TCB                              */
    OS_EventTaskWait(pevent);                    /* Suspend task until event or timeout occurs         */
    OS_EXIT_CRITICAL();
    OS_Sched();                                  /* Find next highest priority task ready to run       */
    OS_ENTER_CRITICAL();
    switch (OSTCBCur->OSTCBStatPend) {                /* See if we timed-out or aborted                */
        case OS_STAT_PEND_OK:                         /* Extract message from TCB (Put there by QPost) */
             pmsg =  OSTCBCur->OSTCBMsg;
//当下次有消息是 ptcb->OSTCBMsg        =  pmsg; (在函数post的子函数OS_EventTaskRdy(pevent, pmsg, OS_STAT_Q, OS_STAT_PEND_OK)中)ptcb->OSTCBEventPtr       = (OS_EVENT  *)pevent;/* Return event as first multi-pend event ready*/
   
如果在规定的时间里面收到消息的话,任务将通过OSTCBCur->OSTCBMsg;        传递消息并继续的执行。特别注意,这里使用 OSTCBCur->OSTCBMsg        而不是pevent->OSEventPtr,主要是因为在多任务消息传递的时候,   可以将消息直接的赋值给各个任务的OSTCBCur->OSTCBMsg;
            *perr =  OS_ERR_NONE;
             break;
        case OS_STAT_PEND_ABORT:
             pmsg = (void *)0;
            *perr =  OS_ERR_PEND_ABORT;               /* Indicate that we aborted                      */
             break;
        case OS_STAT_PEND_TO:
        default:
             OS_EventTaskRemove(OSTCBCur, pevent);
             pmsg = (void *)0;
            *perr =  OS_ERR_TIMEOUT;                  /* Indicate that we didn't get event within TO   */
             break;
    }
    OSTCBCur->OSTCBStat          =  OS_STAT_RDY;      /* Set   task  status to ready                   */
    OSTCBCur->OSTCBStatPend      =  OS_STAT_PEND_OK;  /* Clear pend  status                            */
    OSTCBCur->OSTCBEventPtr      = (OS_EVENT  *)0;    /* Clear event pointers                          */
#if (OS_EVENT_MULTI_EN > 0)
    OSTCBCur->OSTCBEventMultiPtr = (OS_EVENT **)0;
#endif
    OSTCBCur->OSTCBMsg           = (void      *)0;    /* Clear  received message                       */
    OS_EXIT_CRITICAL();
    return (pmsg);            /* Return rec eived message  */为什么此处还有返回消息。因没消息被挂起的任务再次接消息是在此处????
}
 
 
以下是
* File    : OS_Q.C
* By      : Jean J. Labrosse
* Version : V2.85
这个版本的OSQPend 看看红色的地方的不同点,对比以下。
 

/*
*********************************************************************************************************
*                                     PEND ON A QUEUE FOR A MESSAGE
*
* Description: This function waits for a message to be sent to a queue
*
* Arguments  : pevent        is a pointer to the event control block associated with the desired queue
*
*              timeout       is an optional timeout period (in clock ticks).  If non-zero, your task will
*                            wait for a message to arrive at the queue up to the amount of time
*                            specified by this argument.  If you specify 0, however, your task will wait
*                            forever at the specified queue or, until a message arrives.
*
*              perr          is a pointer to where an error message will be deposited.  Possible error
*                            messages are:
*
*                            OS_ERR_NONE         The call was successful and your task received a
*                                                message.
*                            OS_ERR_TIMEOUT      A message was not received within the specified 'timeout'.
*                            OS_ERR_PEND_ABORT   The wait on the queue was aborted.
*                            OS_ERR_EVENT_TYPE   You didn't pass a pointer to a queue
*                            OS_ERR_PEVENT_NULL  If 'pevent' is a NULL pointer
*                            OS_ERR_PEND_ISR     If you called this function from an ISR and the result
*                                                would lead to a suspension.
*                            OS_ERR_PEND_LOCKED  If you called this function with the scheduler is locked
*
* Returns    : != (void *)0  is a pointer to the message received
*              == (void *)0  if you received a NULL pointer message or,
*                            if no message was received or,
*                            if 'pevent' is a NULL pointer or,
*                            if you didn't pass a pointer to a queue.
*
* Note(s)    : As of V2.60, this function allows you to receive NULL pointer messages.
*********************************************************************************************************
*/
void  *OSQPend (OS_EVENT *pevent, INT16U timeout, INT8U *perr)
{
    void      *pmsg;
    OS_Q      *pq;
    INT8U      pend_stat;
#if OS_CRITICAL_METHOD == 3                      /* Allocate storage for CPU status register           */
    OS_CPU_SR  cpu_sr = 0;
#endif
 
#if OS_ARG_CHK_EN > 0
    if (perr == (INT8U *)0) {                    /* Validate 'perr'                                    */
        return ((void *)0);
    }
    if (pevent == (OS_EVENT *)0) {               /* Validate 'pevent'                                  */
        *perr = OS_ERR_PEVENT_NULL;
        return ((void *)0);
    }
    if (pevent->OSEventType != OS_EVENT_TYPE_Q) {/* Validate event block type                          */
        *perr = OS_ERR_EVENT_TYPE;
        return ((void *)0);
    }
#endif
    if (OSIntNesting > 0) {                      /* See if called from ISR ...                         */
        *perr = OS_ERR_PEND_ISR;                 /* ... can't PEND from an ISR                         */
        return ((void *)0);
    }
    if (OSLockNesting > 0) {                     /* See if called with scheduler locked ...            */
        *perr = OS_ERR_PEND_LOCKED;              /* ... can't PEND when locked                         */
        return ((void *)0);
    }
    OS_ENTER_CRITICAL();
    pq = (OS_Q *)pevent->OSEventPtr;             /* Point at queue control block                       */
    if (pq->OSQEntries > 0) {                    /* See if any messages in the queue                   */
        pmsg = *pq->OSQOut++;                    /* Yes, extract oldest message from the queue         */
        pq->OSQEntries--;                        /* Update the number of entries in the queue          */
        if (pq->OSQOut == pq->OSQEnd) {          /* Wrap OUT pointer if we are at the end of the queue */
            pq->OSQOut = pq->OSQStart;
        }
        OS_EXIT_CRITICAL();
        *perr = OS_ERR_NONE;
        return (pmsg);                           /* Return message received                            */
    }
    OSTCBCur->OSTCBStat     |= OS_STAT_Q;        /* Task will have to pend for a message to be posted  */
    OSTCBCur->OSTCBStatPend  = OS_STAT_PEND_OK;
    OSTCBCur->OSTCBDly       = timeout;          /* Load timeout into TCB                              */
    OS_EventTaskWait(pevent);                    /* Suspend task until event or timeout occurs         */
    OS_EXIT_CRITICAL();
    OS_Sched();                                  /* Find next highest priority task ready to run       */
    OS_ENTER_CRITICAL();
    if (OSTCBCur->OSTCBStatPend != OS_STAT_PEND_OK) { /* Was task readied because timed-out or aborted?*/
        pend_stat = OSTCBCur->OSTCBStatPend;
        OS_EventTOAbort(pevent);//新加的,上面那个版本的函数是这个地方没有这个函数的。
        OS_EXIT_CRITICAL();
        switch (pend_stat) {
            case OS_STAT_PEND_TO:
            default:
                 *perr = OS_ERR_TIMEOUT;         /*     Indicate a timeout occured                     */
                 break;
            case OS_STAT_PEND_ABORT:
                 *perr = OS_ERR_PEND_ABORT;      /*     Indicate that we aborted                       */
                 break;
        }
        return ((void *)0);                      /*     No message received                            */
    }

    pmsg                    = OSTCBCur->OSTCBMsg;/* No, Extract message from TCB (Put there by QPost)  */
    OSTCBCur->OSTCBMsg      = (void *)0;
    OSTCBCur->OSTCBStat     = OS_STAT_RDY;
    OSTCBCur->OSTCBEventPtr = (OS_EVENT *)0;     /*     No longer waiting for event                    */
    OS_EXIT_CRITICAL();
    *perr                   = OS_ERR_NONE;
    return (pmsg);                               /*     Return message received                        */
}
阅读(3036) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~