⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 os_q.c

📁 ucos_ii在S3C2410上的移植
💻 C
📖 第 1 页 / 共 3 页
字号:
/*
*********************************************************************************************************
*                                                uC/OS-II 实时内核
*                                                 消息队列管理
*
*                            (c) 版权 1992-2002, 所有版权归Jean J. Labrosse, Weston, FL 所有
*                                         
*
* 文件名称 :          OS_Q.C
* 程序作者 :          Jean J. Labrosse 
*********************************************************************************************************
*/
#ifndef  OS_MASTER_FILE
#include "includes.h"
#endif

#if (OS_Q_EN > 0) && (OS_MAX_QS > 0)
/*
*********************************************************************************************************
*                                      从队列中获取消息
*
* 函数描述: 该函数检查队列看消息是否有效。不象 OSMboxPend(),如果消息无效,函数OSMboxAccept()不会挂起
*           调用的函数。
*
* 输入参数  : pevent        指向ECB的指针
*
* 返回值    : != (void *)0  如果有效是在队列中的消息。OSQAccept() 再次被调用则队列清零队列为空。
*             == (void *)0  队列为空,
*                           'pevent' 是空指针,
*                           没有传递适当的事件指针
*********************************************************************************************************
*/

#if OS_Q_ACCEPT_EN > 0
void  *OSQAccept (OS_EVENT *pevent)
{
#if OS_CRITICAL_METHOD == 3                                  /* 为CPU状态寄存器分配存储变量           */
    OS_CPU_SR  cpu_sr;
#endif
    void      *msg;
    OS_Q      *pq;


#if OS_ARG_CHK_EN > 0
    if (pevent == (OS_EVENT *)0) 
    {                                                                          /* 无效的 'pevent'     */
        return ((void *)0);
    }
    if (pevent->OSEventType != OS_EVENT_TYPE_Q) 
    {                                                               /* 无效的事件块类型               */
        return ((void *)0);
    }
#endif
    OS_ENTER_CRITICAL();
    pq = (OS_Q *)pevent->OSEventPtr;             /* 指向QCB                      */
    if (pq->OSQEntries > 0)                      /* 看队列中是否有消息?                   */
    {                                              
        msg = *pq->OSQOut++;                     /* 是,提取最先进入的消息         */
        pq->OSQEntries--;                        /* 更新队列中的消息数          */
        if (pq->OSQOut == pq->OSQEnd)            /* 进行边界检查 */
        {                                          
            pq->OSQOut = pq->OSQStart;
        }
    } 
    else 
    {
        msg = (void *)0;                         /* 队列中的消息为空                                    */
    }
    OS_EXIT_CRITICAL();
    return (msg);                                /* 返回接收的消息 (或空指针)                 */
}
#endif
/*$PAGE*/
/*
*********************************************************************************************************
*                                        建立一个消息队列
*
* 函数描述:    如果空余ECB有效,该函数创建消息队列。
*
* 输入参数:   start         指向消息队列存储区基址的指针。存储区必须声明指向空的指针阵列,如下:
*
*                            void *MessageStorage[size]
*
*              size          存储区的单元数
*
* 返回值:     != (OS_EVENT *)0  指向带有已创建的队列的ECB的指针
*             == (OS_EVENT *)0  ECB无效或出错
*********************************************************************************************************
*/

OS_EVENT  *OSQCreate (void **start, INT16U size)
{
#if OS_CRITICAL_METHOD == 3                      /* 为CPU状态寄存器分配存储变量           */
    OS_CPU_SR  cpu_sr;
#endif
    OS_EVENT  *pevent;
    OS_Q      *pq;


    if (OSIntNesting > 0) 
    {                                            /* 看调用是否来自ISR ...     */
        return ((OS_EVENT *)0);                  /* ... 从 ISR中不能创建       */
    }
    OS_ENTER_CRITICAL();
    pevent = OSEventFreeList;                    /* 得到空余的ECB      */
    if (OSEventFreeList != (OS_EVENT *)0)       /* 看空余ECB池是否为空?    */
     {                                           
        OSEventFreeList = (OS_EVENT *)OSEventFreeList->OSEventPtr;
    }
    OS_EXIT_CRITICAL();
    if (pevent != (OS_EVENT *)0) 
    {                                               /* 看是否有一个ECB? */
        OS_ENTER_CRITICAL();
        pq = OSQFreeList;                         /* 得到一个队列控制块     */
        if (pq != (OS_Q *)0)                               /* 队列控制块是否为空 ?        */
        {                                         
            OSQFreeList         = OSQFreeList->OSQPtr;     /* 不为空, 得到QCB */
            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;  /* 空,  返回ECB出错  */
            OSEventFreeList    = pevent;
            OS_EXIT_CRITICAL();
            pevent = (OS_EVENT *)0;
        }
    }
    return (pevent);
}
/*$PAGE*/
/*
*********************************************************************************************************
*                                       删除一个消息队列
*
* 函数描述:   该函数删除一个消息队列和就绪等待消息队列的所有任务。
*
* 输入参数  : pevent        指向带有期望消息队列的ECB的指针
*
*             opt           决定删除的选项如下:
*                           opt == OS_DEL_NO_PEND   只在无任务等待时,才删除队列
*                           opt == OS_DEL_ALWAYS    即使有任务等待,也要删除队列
*                                                    该种情况下,所有等待任务将就绪.
*
*             err           指向下列值之一的出错代码的指针:
*                           OS_NO_ERR               调用成功,队列被删除
*                           OS_ERR_DEL_ISR          从 ISR中删除队列
*                           OS_ERR_INVALID_OPT      指定选项无效
*                           OS_ERR_TASK_WAITING     一个或更多的任务正等待队列
*                           OS_ERR_EVENT_TYPE       没有传递一个指向队列的指针
*                           OS_ERR_PEVENT_NULL      'pevent' 是一个空指针
*
* 返回值    : pevent        upon error
*              (OS_EVENT *)0 队列成功删除.
*
* 注释    :    1) 该函数使用时要小心。期望消息队列的任务一定要检查OSQPend()的返回值。
*              2) OSQAccept() 的调用函数将不会知道消息邮箱已被删除,除非检查'pevent'是一个空指针。
*              3) 这种调用潜在的关闭中断很长时间。中断关闭时间直接正比于等待消息队列的任务的数量。
*              4) 由于所有等待消息队列的任务将被就绪。所以,必须小心处理队列用在互斥上,因为资源不再受队列保护。
*              5) 如果消息队列的存储动态分配(如使用 malloc() 调用),那么,应用程序必须使用相配的动态释放存储区。
*                 如果存储区静态创建,存储能重用。
*********************************************************************************************************
*/

#if OS_Q_DEL_EN > 0
OS_EVENT  *OSQDel (OS_EVENT *pevent, INT8U opt, INT8U *err)
{
#if OS_CRITICAL_METHOD == 3                                          /* 为CPU状态寄存器分配存储变量 */
    OS_CPU_SR  cpu_sr;
#endif
    BOOLEAN    tasks_waiting;
    OS_Q      *pq;


    if (OSIntNesting > 0) 
    {                                                                /* 如果调用来自 ISR ...              */
        *err = OS_ERR_DEL_ISR;                                          /* ... 从ISR中不能删除            */
        return ((OS_EVENT *)0);
    }
#if OS_ARG_CHK_EN > 0
    if (pevent == (OS_EVENT *)0) 
    {                                                           /* 无效的 'pevent'                          */
        *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;  /*   返回 OS_Q 空余列表        */
                 pq->OSQPtr          = OSQFreeList;
                 OSQFreeList         = pq;
                 pevent->OSEventType = OS_EVENT_TYPE_UNUSED;
                 pevent->OSEventPtr  = OSEventFreeList;    /* 返回ECB到空余链表中  */
                 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;      /* 返回 OS_Q 空余列表        */
             pq->OSQPtr          = OSQFreeList;
             OSQFreeList         = pq;
             pevent->OSEventType = OS_EVENT_TYPE_UNUSED;
             pevent->OSEventPtr  = OSEventFreeList;        /* 返回ECB到空余链表中  */
             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);

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -