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

📄 msgq.c

📁 Rabbit 32Bit RTOS源代码
💻 C
字号:
/*********************************************************************
*                   Copyright (c) 2011-2012,李士伟
*                     All rights reserved.
*文 件 名:msgq.c
*描    述:消息队列源文件
*当前版本:V1.00
*作    者:李士伟
*创建日期:2012.01.21
**********************************************************************/
#include <kernel\msgq.h>
#include <kernel\flag.h>
#include <kernel\sched.h>
#include <kernel\kd.h>
#include <kernel\asm.h>
#include <mm\memory.h>

/*********************************************************************
*函 数 名:API_CreateMsgQ
*描    述:创建一个消息队列
*输入参数:q_size: 消息队列可存储消息数
*输出参数:无
*返 回 值:消息队列指针
*注    意:
**********************************************************************/
OS_MSGQ *API_CreateMsgQ(INT32U q_size)
{
    OS_MSGQ *pq;

    pq = (OS_MSGQ *)malloc(sizeof(OS_MSGQ)+ sizeof(void *) * q_size);
    if (pq == NULL)
    {
        return NULL;
    }
    pq->QStart = (void **)((INT32U)pq + sizeof(OS_MSGQ));
    pq->QEnd   = pq->QStart + q_size - 1;
    pq->QOut   = pq->QStart;
    pq->QIn    = pq->QStart;
    pq->QSize  = q_size;
    pq->QCount = 0;
    pq->WaitQ  = NULL;

    return pq;
}

/*********************************************************************
*函 数 名:API_DeleteMsgQ
*描    述:删除消息队列
*输入参数:pq: 消息队列指针
*输出参数:无
*返 回 值:0,删除失败;1,删除成功
*注    意:
**********************************************************************/
INT32U API_DeleteMsgQ(OS_MSGQ *pq)
{
    if (pq == NULL)
    {
        return 0;
    }

    OS_ENTER_CRITICAL();

    if (pq->WaitQ != NULL)
    {
        OS_EXIT_CRITICAL();
        return 0;
    }

    free(pq);

    OS_EXIT_CRITICAL();

    return 1;
}

/*********************************************************************
*函 数 名:API_MsgQPend
*描    述:请求消息队列
*输入参数:pq: 消息队列指针
*          timeout:等待时限
*输出参数:err: 错误标志
*返 回 值:消息指针,NULL表示未获得消息
*注    意:
**********************************************************************/
void *API_MsgQPend(OS_MSGQ *pq, INT32U timeout, INT32U *err)
{
    void *msg = NULL;

    if ((pq == NULL) || (OSIntNesting > 0))
    {
        *err = OS_ERR;
        return NULL;
    }
    OS_ENTER_CRITICAL();
    if (pq->QCount > 0)
    {
        msg = *(pq->QOut++);
        pq->QCount--;
        if (pq->QOut > pq->QEnd)
        {
            pq->QOut = pq->QStart;
        }
        OS_EXIT_CRITICAL();
        *err = OS_NO_ERR;
        return msg;
    }

    OSTCBCur->Delay = timeout;
    OS_EnterWaitQHead(&(pq->WaitQ), OSTCBCur);
    OS_Sched();
    if (OSTCBCur->MsgPtr != NULL)  /* 获得消息 */
    {
        msg = OSTCBCur->MsgPtr;   /* 获得消息指针 */
        OSTCBCur->MsgPtr = NULL;  /* 清除TCB消息指针,为下次等待消息准备 */
        OSTCBCur->Delay = 0;  /* 清除等待时限 */
        OS_EXIT_CRITICAL();
        *err = OS_NO_ERR;
        return msg;
    }

    /* 超时,未获得消息 */
    OS_EXIT_CRITICAL();
    *err = OS_OVERTIME;
    return NULL;
}

/*********************************************************************
*函 数 名:API_MsgQAccept
*描    述:无等待获得消息
*输入参数:pq: 消息队列指针
*输出参数:无
*返 回 值:消息指针,NULL表示未获得消息
*注    意:
**********************************************************************/
void *API_MsgQAccept(OS_MSGQ *pq)
{
    void *msg = NULL;
    if (pq == NULL)
    {
        return NULL;
    }
    OS_ENTER_CRITICAL();
    if (pq->QCount > 0)
    {
        msg = *(pq->QOut++);
        pq->QCount--;
        if (pq->QOut > pq->QEnd)
        {
            pq->QOut = pq->QStart;
        }
        OS_EXIT_CRITICAL();
        return msg;
    }
    OS_EXIT_CRITICAL();
    return msg;
}

/*********************************************************************
*函 数 名:API_MsgQPost
*描    述:发送消息到队尾
*输入参数:pq: 消息队列指针
*          msg: 消息指针
*          method: 发送方式
*                 OS_BASE_PRIO 基于优先级方式发送
*                 OS_BASE_BROADCAST 广播方式发送
*输出参数:无
*返 回 值:OS_MSGQ_INVALID 消息队列不存在,无效
*          OS_MSGQ_FULL    消息队列已满,发送失败
*          OS_MSGQ_SAVE    没有任务在等待消息,消息存入队列
*          OS_MSGQ_SEND    消息发送到任务
*注    意:
**********************************************************************/
INT32U API_MsgQPost(OS_MSGQ *pq, void *msg, INT32U method)
{
    INT32U prio = 0;
    OS_TCB *ptcb;
    OS_TCB *wptcb=NULL;

    if (pq == NULL)
    {
        return OS_MSGQ_INVALID;
    }

    OS_ENTER_CRITICAL();
    
    ptcb  = pq->WaitQ;
    wptcb = ptcb;
    if (ptcb != NULL)  /* 有任务在等待消息 */
    {
        prio = ptcb->Prio;
    }
    else  /* 没有任务在等待消息 */
    {
        if (pq->QCount == pq->QSize)  /* 消息队列已满, 不保存消息 */
        {
            OS_EXIT_CRITICAL();
            return OS_MSGQ_FULL;
        }
        else  /* 消息未满,将消息存入队列尾部 */
        {
            *(pq->QIn++) = msg;
            if (pq->QIn > pq->QEnd)
            {
                pq->QIn = pq->QStart;
            }
            pq->QCount++;
            OS_EXIT_CRITICAL();
            return OS_MSGQ_SAVE;
        }
    }

    /* 基于优先级发送消息给一个高优先级任务 */
    if (method == OS_BASE_PRIO)  
    {
        while (ptcb != NULL)  /* 从等待队列查询一个高优先级任务 */
        {
            if (prio <= ptcb->Prio)
            {
                prio = ptcb->Prio;
                wptcb= ptcb;
            }
            ptcb = ptcb->QNext;
        }

        wptcb->MsgPtr  = msg;  /* 将消息指针存入TCB中 */
        OS_EnterRunQ(wptcb);  /* 加入运行队列 */

    }

    /* 广播方式唤醒所有等待该消息队列的任务 */
    else if (method == OS_BASE_BROADCAST)  
    {
        while (ptcb != NULL)
        {
            ptcb->MsgPtr = msg;  /* 将消息指针存入TCB中 */
            wptcb = ptcb->QNext;
            OS_EnterRunQ(ptcb);  /* 加入运行队列 */
            ptcb = wptcb;
        }
    }

    OS_EXIT_CRITICAL();
    OS_Sched();
    return OS_MSGQ_SEND;
}

/*********************************************************************
*函 数 名:API_MsgQPostFront
*描    述:发送消息到队首
*输入参数:pq: 消息队列指针
*          msg: 消息指针
*          method: 发送方式
*                 OS_BASE_PRIO 基于优先级方式发送
*                 OS_BASE_BROADCAST 广播方式发送
*输出参数:无
*返 回 值:OS_MSGQ_INVALID 消息队列不存在,无效
*          OS_MSGQ_FULL    消息队列已满,发送失败
*          OS_MSGQ_SAVE    没有任务在等待消息,消息存入队列
*          OS_MSGQ_SEND    消息发送到任务
*注    意:
**********************************************************************/
INT32U API_MsgQPostFront(OS_MSGQ *pq, void *msg, INT32U method)
{
    INT32U prio = 0;
    OS_TCB *ptcb;
    OS_TCB *wptcb=NULL;

    if (pq == NULL)
    {
        return OS_MSGQ_INVALID;
    }

    OS_ENTER_CRITICAL();

    ptcb  = pq->WaitQ;
    wptcb = ptcb;
    if (ptcb != NULL)  /* 有任务在等待消息 */
    {
        prio = ptcb->Prio;
    }
    else  /* 没有任务在等待消息 */
    {
        if (pq->QCount == pq->QSize)  /* 消息队列已满, 不保存消息 */
        {
            OS_EXIT_CRITICAL();
            return OS_MSGQ_FULL;
        }
        else  /* 消息未满,将消息存入队列首部 */
        {
            if (pq->QOut == pq->QStart)
            {
                pq->QOut = pq->QEnd;
            }
            else
            {
                --(pq->QOut);
            }
            *(pq->QOut) = msg;
            pq->QCount++;
            OS_EXIT_CRITICAL();
            return OS_MSGQ_SAVE;
        }
    }

    /* 基于优先级发送消息给一个高优先级任务 */
    if (method == OS_BASE_PRIO)  
    {
        while (ptcb != NULL)  /* 从等待队列查询一个高优先级任务 */
        {
            if (prio <= ptcb->Prio)
            {
                prio = ptcb->Prio;
                wptcb= ptcb;
            }
            ptcb = ptcb->QNext;
        }

        wptcb->MsgPtr  = msg;  /* 将消息指针存入TCB中 */
        OS_EnterRunQ(wptcb);  /* 加入运行队列 */

    }

    /* 广播方式唤醒所有等待该消息队列的任务 */
    else if (method == OS_BASE_BROADCAST)
    {
        while (ptcb != NULL)
        {
            ptcb->MsgPtr = msg;  /* 将消息指针存入TCB中 */
            wptcb = ptcb->QNext;
            OS_EnterRunQ(ptcb);  /* 加入运行队列 */
            ptcb = wptcb;
        }
    }

    OS_EXIT_CRITICAL();
    OS_Sched();
    return OS_MSGQ_SEND;
}

⌨️ 快捷键说明

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