uC/OS-II源码解析(os_q.c)

来源:互联网 发布:针对接口编程 编辑:程序博客网 时间:2024/06/05 07:20
/*** ver   : 2.52** file  : os_q.c** brief : 消息队列相关操作 C 文件*/#ifndef  OS_MASTER_FILE#include "includes.h"            /* 包含头文件 */#endif#if (OS_Q_EN > 0) && (OS_MAX_QS > 0)/************************************************************************************************                                      无等待的请求消息队列** breif    : 该函数用于无等待的请求消息队列中的消息.** pevent   : 指向事件控制块的指针** Returns  : != (void *)0  队列中有可用消息*            == (void *)0  未获得消息***********************************************************************************************/#if OS_Q_ACCEPT_EN > 0void  *OSQAccept (OS_EVENT *pevent){#if OS_CRITICAL_METHOD == 3                            OS_CPU_SR  cpu_sr;#endif    void      *msg;    OS_Q      *pq;#if OS_ARG_CHK_EN > 0    if (pevent == (OS_EVENT *)0) {               /* 无效的事件控制块指针 */        return ((void *)0);    }    if (pevent->OSEventType != OS_EVENT_TYPE_Q) {/* 错误的事件类型       */        return ((void *)0);    }#endif    OS_ENTER_CRITICAL();    pq = (OS_Q *)pevent->OSEventPtr;             /* 获得队列控制块       */    if (pq->OSQEntries > 0) {                    /* 判断队列中是否有消息 */        msg = *pq->OSQOut++;                     /* 将消息取出来返回     */        pq->OSQEntries--;                        /* 消息数减1            */        if (pq->OSQOut == pq->OSQEnd) {          /* 调整已实现循环队列   */            pq->OSQOut = pq->OSQStart;        }    } else {        msg = (void *)0;                         /* 队列为空             */    }    OS_EXIT_CRITICAL();    return (msg);                                    }#endif/*$PAGE*//*******************************************************************************************                                        创建消息队列** brief   : 该函数用于创建消息队列.** start   : 消息队列的基地址.该数组必须被声明为void类型**             void *MessageStorage[size]** size    : 消息数组的大小** Returns : != (OS_EVENT *)0  消息队列创建成功*           == (OS_EVENT *)0  消息队列创建失败******************************************************************************************/OS_EVENT  *OSQCreate (void **start, INT16U size){#if OS_CRITICAL_METHOD == 3                         OS_CPU_SR  cpu_sr;#endif    OS_EVENT  *pevent;    OS_Q      *pq;    if (OSIntNesting > 0) {                      /* 不允许中断内创建消息队列 */        return ((OS_EVENT *)0);                                   }    OS_ENTER_CRITICAL();    pevent = OSEventFreeList;                    /* 获取事件控制块           */    if (OSEventFreeList != (OS_EVENT *)0) {      /* 调整剩余事件控制块链表   */        OSEventFreeList = (OS_EVENT *)OSEventFreeList->OSEventPtr;    }    OS_EXIT_CRITICAL();    if (pevent != (OS_EVENT *)0) {                           OS_ENTER_CRITICAL();        pq = OSQFreeList;                        /* 获取队列控制块      */        if (pq != (OS_Q *)0) {                   /* 存在剩余队列控制块  */            OSQFreeList         = OSQFreeList->OSQPtr;/* 调整队列控制块链表 */            OS_EXIT_CRITICAL();            pq->OSQStart        = start;              /* 初始化队列     */            pq->OSQEnd          = &start[size];            pq->OSQIn           = start;            pq->OSQOut          = start;            pq->OSQSize         = size;            pq->OSQEntries      = 0;            pevent->OSEventType = OS_EVENT_TYPE_Q;            pevent->OSEventCnt  = 0;            pevent->OSEventPtr  = pq;            OS_EventWaitListInit(pevent);             /* 初始化等待任务表 */        } else {                                      /* 无可用队列控制块 */            pevent->OSEventPtr = (void *)OSEventFreeList; /* 返还事件控制块  */            OSEventFreeList    = pevent;            OS_EXIT_CRITICAL();            pevent = (OS_EVENT *)0;        }    }    return (pevent);}/*$PAGE*//******************************************************************************************                                        删除消息队列** brief    : 该函数用于删除消息队列.** pevent   : 指向事件控制块的指针** opt      : 删除选项*              opt == OS_DEL_NO_PEND   无任务等待时删除*              opt == OS_DEL_ALWAYS    无条件删除,就绪所有等待任务** err      : 指向错误代码的指针,可能取值:*              OS_NO_ERR               成功*              OS_ERR_DEL_ISR          不允许在中断中删除队列*              OS_ERR_INVALID_OPT      无效的删除选项*              OS_ERR_TASK_WAITING     有任务正在等待队列中的消息*              OS_ERR_EVENT_TYPE       错误的时间类型*              OS_ERR_PEVENT_NULL      I无效的事件控制块指针** Returns    : pevent        删除失败*              (OS_EVENT *)0 删除成功*******************************************************************************************/#if OS_Q_DEL_EN > 0OS_EVENT  *OSQDel (OS_EVENT *pevent, INT8U opt, INT8U *err){#if OS_CRITICAL_METHOD == 3                                 OS_CPU_SR  cpu_sr;#endif    BOOLEAN    tasks_waiting;    OS_Q      *pq;    if (OSIntNesting > 0) {                        /* 不允许中断内删除      */        *err = OS_ERR_DEL_ISR;                            return ((OS_EVENT *)0);    }#if OS_ARG_CHK_EN > 0    if (pevent == (OS_EVENT *)0) {                 /* 无效的事件控制块指针  */        *err = OS_ERR_PEVENT_NULL;        return (pevent);    }    if (pevent->OSEventType != OS_EVENT_TYPE_Q) {  /* 错误的事件类型        */        *err = OS_ERR_EVENT_TYPE;        return (pevent);    }#endif    OS_ENTER_CRITICAL();    if (pevent->OSEventGrp != 0x00) {                      /* 是否有任务等待消息 */        tasks_waiting = TRUE;                              /* 有任务等待         */    } else {        tasks_waiting = FALSE;                             /* 无任务等待         */    }    switch (opt) {        case OS_DEL_NO_PEND:                               /* 无任务等待删除    */             if (tasks_waiting == FALSE) {                 pq                  = (OS_Q *)pevent->OSEventPtr;  /* 返还队列控制块 */                 pq->OSQPtr          = OSQFreeList;                 OSQFreeList         = pq;                 pevent->OSEventType = OS_EVENT_TYPE_UNUSED;                 pevent->OSEventPtr  = OSEventFreeList;    /* 返还事件控制块  */                 OSEventFreeList     = pevent;                              OS_EXIT_CRITICAL();                 *err = OS_NO_ERR;                 return ((OS_EVENT *)0);                                    } else {                 OS_EXIT_CRITICAL();                 *err = OS_ERR_TASK_WAITING;                 return (pevent);             }        case OS_DEL_ALWAYS:                                /* 无条件删除       */             while (pevent->OSEventGrp != 0x00) {          /* 就绪所有等待任务 */                 OS_EventTaskRdy(pevent, (void *)0, OS_STAT_Q);             }             pq                  = (OS_Q *)pevent->OSEventPtr;/* 返还队列控制块 */             pq->OSQPtr          = OSQFreeList;             OSQFreeList         = pq;             pevent->OSEventType = OS_EVENT_TYPE_UNUSED;             pevent->OSEventPtr  = OSEventFreeList;        /* 返还事件控制块 */             OSEventFreeList     = pevent;                                    OS_EXIT_CRITICAL();             if (tasks_waiting == TRUE) {                                  OS_Sched();                               /* 任务调度 */             }             *err = OS_NO_ERR;             return ((OS_EVENT *)0);                               default:             OS_EXIT_CRITICAL();             *err = OS_ERR_INVALID_OPT;             return (pevent);    }}#endif/*$PAGE*//*********************************************************************************************                                           清空消息队列** brief       : 该函数用于清空队列内的消息** pevent      : 指向事件控制块的指针** Returns     : OS_NO_ERR           成功*               OS_ERR_EVENT_TYPE   错误的事件类型*               OS_ERR_PEVENT_NULL  无效的事件控制块指针*********************************************************************************************/#if OS_Q_FLUSH_EN > 0INT8U  OSQFlush (OS_EVENT *pevent){#if OS_CRITICAL_METHOD == 3                           OS_CPU_SR  cpu_sr;#endif    OS_Q      *pq;#if OS_ARG_CHK_EN > 0    if (pevent == (OS_EVENT *)0) {                    /* 无效的事件控制块指针          */        return (OS_ERR_PEVENT_NULL);    }    if (pevent->OSEventType != OS_EVENT_TYPE_Q) {     /* 错误的事件类型                */        return (OS_ERR_EVENT_TYPE);    }#endif    OS_ENTER_CRITICAL();    pq             = (OS_Q *)pevent->OSEventPtr;      /* 获取队列控制块               */    pq->OSQIn      = pq->OSQStart;                    /* 清空队列                     */    pq->OSQOut     = pq->OSQStart;    pq->OSQEntries = 0;    OS_EXIT_CRITICAL();    return (OS_NO_ERR);}#endif/*$PAGE*//************************************************************************************************                                     请求消息** brief     : 该函数用于从消息队列中请求一则消息** pevent    : 指向事件控制块的指针** timeout   : 超时时限**  err      : 指向错误代码的指针,可能取值:**               OS_NO_ERR           成功*               OS_TIMEOUT          超时*               OS_ERR_EVENT_TYPE   错误的事件类型*               OS_ERR_PEVENT_NULL  无效的事件控制块指针*               OS_ERR_PEND_ISR     不能再中断中请求** Returns    : != (void *)0  请求成功*              == (void *)0  请求失败************************************************************************************************/void  *OSQPend (OS_EVENT *pevent, INT16U timeout, INT8U *err){#if OS_CRITICAL_METHOD == 3                           OS_CPU_SR  cpu_sr;#endif    void      *msg;    OS_Q      *pq;    if (OSIntNesting > 0) {                      /* 不允许中断中请求消息 */        *err = OS_ERR_PEND_ISR;                                       return ((void *)0);    }#if OS_ARG_CHK_EN > 0    if (pevent == (OS_EVENT *)0) {               /* 无效的事件控制块     */        *err = OS_ERR_PEVENT_NULL;        return ((void *)0);    }    if (pevent->OSEventType != OS_EVENT_TYPE_Q) {/* 错误的事件类型       */        *err = OS_ERR_EVENT_TYPE;        return ((void *)0);    }#endif    OS_ENTER_CRITICAL();    pq = (OS_Q *)pevent->OSEventPtr;             /* 获取队列控制块       */    if (pq->OSQEntries > 0) {                    /* 队列中是否有消息     */        msg = *pq->OSQOut++;                     /* 取出消息             */        pq->OSQEntries--;                        /* 消息数减1            */        if (pq->OSQOut == pq->OSQEnd) {          /* 调整指针实现循环队列 */            pq->OSQOut = pq->OSQStart;        }        OS_EXIT_CRITICAL();        *err = OS_NO_ERR;        return (msg);                                              }    OSTCBCur->OSTCBStat |= OS_STAT_Q;            /* 等待消息状态  */    OSTCBCur->OSTCBDly   = timeout;              /* 记录超时时限  */    OS_EventTaskWait(pevent);                    /* 使任务进入等待状态 */    OS_EXIT_CRITICAL();    OS_Sched();                                  /* 任务调度      */    OS_ENTER_CRITICAL();    msg = OSTCBCur->OSTCBMsg;    if (msg != (void *)0) {                      /* 是否收到了消息 */        OSTCBCur->OSTCBMsg      = (void *)0;     /* 请空消息       */        OSTCBCur->OSTCBStat     = OS_STAT_RDY;   /* 就绪态         */        OSTCBCur->OSTCBEventPtr = (OS_EVENT *)0; /* 取消关联       */        OS_EXIT_CRITICAL();        *err                    = OS_NO_ERR;        return (msg);                                                     }    OS_EventTO(pevent);                          /* 超时使任务就绪 */    OS_EXIT_CRITICAL();    *err = OS_TIMEOUT;                           /* Indicate a timeout       */    return ((void *)0);                                                  }/*$PAGE*//************************************************************************************************                                        向队列发送一则消息** breif    : 该函数用于向队列发送一则消息,由.OSQIn插入,先进先出** pevent   : 指向事件控制块的指针** msg      : 指向消息的指针** Returns  : OS_NO_ERR             成功*            OS_Q_FULL             队列已满*            OS_ERR_EVENT_TYPE     错误的事件类型*            OS_ERR_PEVENT_NULL    无效的事件控制块指针*            OS_ERR_POST_NULL_PTR  发送的消息不能为空************************************************************************************************/#if OS_Q_POST_EN > 0INT8U  OSQPost (OS_EVENT *pevent, void *msg){#if OS_CRITICAL_METHOD == 3                        OS_CPU_SR  cpu_sr;#endif    OS_Q      *pq;#if OS_ARG_CHK_EN > 0    if (pevent == (OS_EVENT *)0) {                    /* 无效的事件控制块指针 */        return (OS_ERR_PEVENT_NULL);    }    if (msg == (void *)0) {                           /* 发送的消息不能为空   */        return (OS_ERR_POST_NULL_PTR);    }    if (pevent->OSEventType != OS_EVENT_TYPE_Q) {     /* 错误的事件类型       */        return (OS_ERR_EVENT_TYPE);    }#endif    OS_ENTER_CRITICAL();    if (pevent->OSEventGrp != 0x00) {                 /* 是否有任务等待       */        OS_EventTaskRdy(pevent, msg, OS_STAT_Q);      /* 就绪最高优先级任务   */        OS_EXIT_CRITICAL();        OS_Sched();                                   /* 任务调度             */        return (OS_NO_ERR);    }    pq = (OS_Q *)pevent->OSEventPtr;                  /* 获取队列控制块       */    if (pq->OSQEntries >= pq->OSQSize) {              /* 队列已满             */        OS_EXIT_CRITICAL();        return (OS_Q_FULL);    }    *pq->OSQIn++ = msg;                               /* 插入消息             */    pq->OSQEntries++;                                 /* 消息数加1            */    if (pq->OSQIn == pq->OSQEnd) {                    /* 调整指针实现循环队列 */        pq->OSQIn = pq->OSQStart;    }    OS_EXIT_CRITICAL();    return (OS_NO_ERR);}#endif/*$PAGE*//*********************************************************************************************                                   向队列发送一则消息** breif   : 该函数用于向队列发送一则消息,由.OSQOut插入,先进后出** pevent  : 指向事件控制块的指针** msg     : 指向消息的指针** Returns : OS_NO_ERR             成功*           OS_Q_FULL             队列已满*           OS_ERR_EVENT_TYPE     错误的时间类型*           OS_ERR_PEVENT_NULL    无效的事件控制块指针*           OS_ERR_POST_NULL_PTR  发送的消息不能为空********************************************************************************************/#if OS_Q_POST_FRONT_EN > 0INT8U  OSQPostFront (OS_EVENT *pevent, void *msg){#if OS_CRITICAL_METHOD == 3                             OS_CPU_SR  cpu_sr;#endif    OS_Q      *pq;#if OS_ARG_CHK_EN > 0    if (pevent == (OS_EVENT *)0) {                    /* 无效的事件控制块指针 */        return (OS_ERR_PEVENT_NULL);    }    if (msg == (void *)0) {                           /* 发送的消息不能为空  */        return (OS_ERR_POST_NULL_PTR);    }    if (pevent->OSEventType != OS_EVENT_TYPE_Q) {     /* 错误的事件类型       */        return (OS_ERR_EVENT_TYPE);    }#endif    OS_ENTER_CRITICAL();    if (pevent->OSEventGrp != 0x00) {                 /* 是否有任务在等待消息 */        OS_EventTaskRdy(pevent, msg, OS_STAT_Q);      /* 就绪最高级等待任务   */        OS_EXIT_CRITICAL();        OS_Sched();                                   /* 任务调度             */        return (OS_NO_ERR);    }    pq = (OS_Q *)pevent->OSEventPtr;                  /* 获取队列控制块       */    if (pq->OSQEntries >= pq->OSQSize) {              /* 队列已满             */        OS_EXIT_CRITICAL();        return (OS_Q_FULL);    }    if (pq->OSQOut == pq->OSQStart) {                 /* 调整指针    */        pq->OSQOut = pq->OSQEnd;    }    pq->OSQOut--;    *pq->OSQOut = msg;                                /* 插入消息    */    pq->OSQEntries++;                                 /* 消息数加1   */    OS_EXIT_CRITICAL();    return (OS_NO_ERR);}#endif/*$PAGE*//*********************************************************************************************                                        向队列发送一则消息** breif     : 该函数用于向队列发送一则消息** pevent    : 指向事件控制块的指针** msg       : 指向消息的指针** opt       : 发送选项,可能取值:*               OS_POST_OPT_NONE         先进先出*               OS_POST_OPT_BROADCAST    广播*               OS_POST_OPT_FRONT        先进后出** Returns   : OS_NO_ERR             成功*             OS_Q_FULL             队列已满*             OS_ERR_EVENT_TYPE     错误的事件类型*             OS_ERR_PEVENT_NULL    无效的事件控制块指针*             OS_ERR_POST_NULL_PTR  发送的消息不能为空********************************************************************************************/#if OS_Q_POST_OPT_EN > 0INT8U  OSQPostOpt (OS_EVENT *pevent, void *msg, INT8U opt){#if OS_CRITICAL_METHOD == 3                         OS_CPU_SR  cpu_sr;#endif    OS_Q      *pq;#if OS_ARG_CHK_EN > 0    if (pevent == (OS_EVENT *)0) {                    /* 无效的事件控制块指针 */        return (OS_ERR_PEVENT_NULL);    }    if (msg == (void *)0) {                           /* 发送的消息不能为空   */        return (OS_ERR_POST_NULL_PTR);    }    if (pevent->OSEventType != OS_EVENT_TYPE_Q) {     /* 错误的事件类型        */        return (OS_ERR_EVENT_TYPE);    }#endif    OS_ENTER_CRITICAL();    if (pevent->OSEventGrp != 0x00) {                 /* 是否有任务等待消息 */        if ((opt & OS_POST_OPT_BROADCAST) != 0x00) {  /* 是否广播消息       */            while (pevent->OSEventGrp != 0x00) {      /* 就绪所有等待任务   */                OS_EventTaskRdy(pevent, msg, OS_STAT_Q);            }        } else {            OS_EventTaskRdy(pevent, msg, OS_STAT_Q);  /* 就绪最高优先级任务  */        }        OS_EXIT_CRITICAL();        OS_Sched();                                   /* 任务调度     */        return (OS_NO_ERR);    }    pq = (OS_Q *)pevent->OSEventPtr;                  /* 或许队列控制块       */    if (pq->OSQEntries >= pq->OSQSize) {              /* 队列已满             */        OS_EXIT_CRITICAL();        return (OS_Q_FULL);    }    if ((opt & OS_POST_OPT_FRONT) != 0x00) {          /* 先进后出         */        if (pq->OSQOut == pq->OSQStart) {                        pq->OSQOut = pq->OSQEnd;                               }        pq->OSQOut--;        *pq->OSQOut = msg;                            /* 先进先出          */    } else {                                                                    *pq->OSQIn++ = msg;                                   if (pq->OSQIn == pq->OSQEnd) {                            pq->OSQIn = pq->OSQStart;        }    }    pq->OSQEntries++;                                 /* 消息数加1         */    OS_EXIT_CRITICAL();    return (OS_NO_ERR);}#endif/*$PAGE*//*************************************************************************************************                                        查询队列** brief     : 该函数用与查询消息队列信息.** pevent    : 指向事件控制块的指针** pdata     : 指向消息队列信息的数据结构指针** Returns   : OS_NO_ERR           成功*             OS_ERR_EVENT_TYPE   错误的事件类型*             OS_ERR_PEVENT_NULL  无效的事件控制块指针*************************************************************************************************/#if OS_Q_QUERY_EN > 0INT8U  OSQQuery (OS_EVENT *pevent, OS_Q_DATA *pdata){#if OS_CRITICAL_METHOD == 3                                   OS_CPU_SR  cpu_sr;#endif    OS_Q      *pq;    INT8U     *psrc;    INT8U     *pdest;#if OS_ARG_CHK_EN > 0    if (pevent == (OS_EVENT *)0) {                         /* 无效的事件控制块指针 */        return (OS_ERR_PEVENT_NULL);    }    if (pevent->OSEventType != OS_EVENT_TYPE_Q) {          /* 错误的时间类型        */        return (OS_ERR_EVENT_TYPE);    }#endif    OS_ENTER_CRITICAL();    pdata->OSEventGrp = pevent->OSEventGrp;                /* 复制等待任务链表       */    psrc              = &pevent->OSEventTbl[0];    pdest             = &pdata->OSEventTbl[0];#if OS_EVENT_TBL_SIZE > 0    *pdest++          = *psrc++;#endif#if OS_EVENT_TBL_SIZE > 1    *pdest++          = *psrc++;#endif#if OS_EVENT_TBL_SIZE > 2    *pdest++          = *psrc++;#endif#if OS_EVENT_TBL_SIZE > 3    *pdest++          = *psrc++;#endif#if OS_EVENT_TBL_SIZE > 4    *pdest++          = *psrc++;#endif#if OS_EVENT_TBL_SIZE > 5    *pdest++          = *psrc++;#endif#if OS_EVENT_TBL_SIZE > 6    *pdest++          = *psrc++;#endif#if OS_EVENT_TBL_SIZE > 7    *pdest            = *psrc;#endif    pq = (OS_Q *)pevent->OSEventPtr;                       /* 获取队列控制块 */    if (pq->OSQEntries > 0) {        pdata->OSMsg = *pq->OSQOut;                        /* 取出消息       */    } else {        pdata->OSMsg = (void *)0;    }    pdata->OSNMsgs = pq->OSQEntries;                       /* 消息数   */    pdata->OSQSize = pq->OSQSize;                          /* 队列大小 */    OS_EXIT_CRITICAL();    return (OS_NO_ERR);}#endif                                                                    /*$PAGE*//*****************************************************************************************                                      初始化消息队列** brief : 被函数 OSInit() 调用去初始化消息队列,你的应用中不应该调用该函数. ******************************************************************************************/void  OS_QInit (void){#if OS_MAX_QS == 1    OSQFreeList         = &OSQTbl[0];            /* 只有一个 */    OSQFreeList->OSQPtr = (OS_Q *)0;#endif#if OS_MAX_QS >= 2                               /* 超过一个 */    INT16U  i;    OS_Q   *pq1;    OS_Q   *pq2;    pq1 = &OSQTbl[0];    pq2 = &OSQTbl[1];    for (i = 0; i < (OS_MAX_QS - 1); i++) {    /* 初始化队列控制块为单向量表 */        pq1->OSQPtr = pq2;        pq1++;        pq2++;    }    pq1->OSQPtr = (OS_Q *)0;                    /* 对后一个队列控制块    */    OSQFreeList = &OSQTbl[0];                   /* 空队列控制块链表表头  */#endif}#endif