μC/OS III - 常用功能及其API源代码解析

本文主要介绍μC/OS III 中常用的功能和API,包括内核中常见的内部接口、事件标志组OS_FLAG_GRP、计数信号量OS_SEM、互斥信号量OS_MUTEX、消息OS_MSG、消息队列OS_Q、软件定时器OS_TMR以及任务相关的API等。

一. 内核中常见的内部接口

1. OS_TaskBlock

OS_TaskBlock的实现如下:

[os_core.c OS_TaskBlock函数]

void  OS_TaskBlock (OS_TCB   *p_tcb,
                    OS_TICK   timeout)
{
#if (OS_CFG_TASK_TICK_EN == DEF_DISABLED)
    (void)timeout;
#endif

#if (OS_CFG_TASK_TICK_EN == DEF_ENABLED)
#if (OS_CFG_DYN_TICK_EN == DEF_ENABLED)
        OS_TICK tick_ctr;
#endif

    //如果timeout入参大于0,
    //就把`p_tcb`放入到`OSTickListTimeout`这个`TickList`中
    if (timeout > 0u) {
#if (OS_CFG_DYN_TICK_EN == DEF_ENABLED)
        tick_ctr = BSP_OS_TickGet();
        OS_TickListInsert(&OSTickListTimeout, p_tcb, timeout + (tick_ctr - OSTickCtr));
#else
        OS_TickListInsert(&OSTickListTimeout, p_tcb, timeout);
#endif
        //设置任务为Pend + TimeOut状态
        p_tcb->TaskState = OS_TASK_STATE_PEND_TIMEOUT;
    } else {
        //设置任务为Pend状态
        p_tcb->TaskState = OS_TASK_STATE_PEND;
    }
#else
    //设置任务为Pend状态
    p_tcb->TaskState = OS_TASK_STATE_PEND;
#endif
    //把`p_tcb`从就绪队列中移除
    OS_RdyListRemove(p_tcb);
}

这个函数判断timeout的值是否为0,如果不为0的话,把任务加入到OSTickListTimeout这个TickList中。并把任务从就绪列表中移除。这个函数时μC/OS III的内部函数,用户不能主动的调用它。

2. OS_Pend

OS_Pend的实现如下:

[os_core.c OS_Pend函数]

void  OS_Pend (OS_PEND_OBJ  *p_obj,
            OS_STATE      pending_on,
            OS_TICK       timeout)
{
    OS_PEND_LIST  *p_pend_list;

    OSTCBCurPtr->PendOn     = pending_on;
    OSTCBCurPtr->PendStatus = OS_STATUS_PEND_OK;

    //如果timeout不为0,加入到TickList中,并
    //把任务从ReadyList中移除
    OS_TaskBlock(OSTCBCurPtr,
                timeout);

    if (p_obj != (OS_PEND_OBJ *)0) {
        p_pend_list             = &p_obj->PendList;
        OSTCBCurPtr->PendObjPtr =  p_obj;
        //插入到PendList中
        OS_PendListInsertPrio(p_pend_list, OSTCBCurPtr);

    } else {
        OSTCBCurPtr->PendObjPtr = (OS_PEND_OBJ *)0;
    }
#if (OS_CFG_DBG_EN == DEF_ENABLED)
    OS_PendDbgNameAdd(p_obj,
                    OSTCBCurPtr);
#endif
}

OS_PEND_OBJ *p_obj可以是事件标志组OS_FLAG_GRP、互斥信号量OS_MUTEX、消息队列OS_Q、计数信号量OS_SEM等中的一种。同时也可以为0,有一些Pend操作可以是没有内核对象的Pend操作,比如任务自身的消息队列以及任务自身的计数信号量。

OS_STATE pending_on可以是以下:

OS_STATE说明是否有OS_PEND_OBJ
OS_TASK_PEND_ON_FLAG事件标志组的Pend操作必须有
OS_TASK_PEND_ON_TASK_Q任务自身的消息队列的Pend操作没有
OS_TASK_PEND_ON_MUTEX互斥信号量的Pend操作必须有
OS_TASK_PEND_ON_Q消息队列的Pend操作必须有
OS_TASK_PEND_ON_SEM计数信号量的Pend操作必须有
OS_TASK_PEND_ON_TASK_SEM任务自身的技术信号量的Pend操作没有

这个函数设置PendOnPendStatus,调用OS_TaskBlock(如果传入的timeout不为0,就把这个任务加入到TickList中。把他从ReadyList中移除),如果OS_PEND_OBJ *p_obj不为0,再把这个任务插入到这个内核对象的PendList中。

3. OS_PendAbort

OS_PendAbort的实现如下:

[os_core.c OS_PendAbort函数]

void  OS_PendAbort (OS_TCB     *p_tcb,
                    CPU_TS      ts,
                    OS_STATUS   reason)
{
#if (OS_CFG_TS_EN == DEF_DISABLED)
    (void)ts;
#endif
    switch (p_tcb->TaskState) {
        case OS_TASK_STATE_PEND:
        case OS_TASK_STATE_PEND_TIMEOUT:
#if (OS_MSG_EN == DEF_ENABLED)
            p_tcb->MsgPtr     = (void *)0;
            p_tcb->MsgSize    =         0u;
#endif
#if (OS_CFG_TS_EN == DEF_ENABLED)
            p_tcb->TS         = ts;
#endif
            //如果存在某个PendList中
            //则把他从这个PendList中移除
            OS_PendListRemove(p_tcb);

#if (OS_CFG_TASK_TICK_EN == DEF_ENABLED)

            //如果存在于某个TickList中
            //则把他从这个TickList中移除
            if (p_tcb->TaskState == OS_TASK_STATE_PEND_TIMEOUT) {
                OS_TickListRemove(p_tcb);
            }
#endif

            //如果不是suspend状态状态,则把他放入到就绪列表中
            OS_RdyListInsert(p_tcb);
            p_tcb->TaskState  = OS_TASK_STATE_RDY;
            p_tcb->PendStatus = reason;
            p_tcb->PendOn     = OS_TASK_PEND_ON_NOTHING;
            break;

        //这里包含了suspended状态,
        //只把它从PendList或者TickList中移除,但不放入就绪列表中
        case OS_TASK_STATE_PEND_SUSPENDED:
        case OS_TASK_STATE_PEND_TIMEOUT_SUSPENDED:
#if (OS_MSG_EN == DEF_ENABLED)
            p_tcb->MsgPtr     = (void *)0;
            p_tcb->MsgSize    =         0u;
#endif
#if (OS_CFG_TS_EN == DEF_ENABLED)
            p_tcb->TS         = ts;
#endif
            OS_PendListRemove(p_tcb);
#if (OS_CFG_TASK_TICK_EN == DEF_ENABLED)
            if (p_tcb->TaskState == OS_TASK_STATE_PEND_TIMEOUT_SUSPENDED) {
                OS_TickListRemove(p_tcb);
            }
#endif
            p_tcb->TaskState  = OS_TASK_STATE_SUSPENDED;
            p_tcb->PendStatus = reason;
            p_tcb->PendOn     = OS_TASK_PEND_ON_NOTHING;
            break;
        case OS_TASK_STATE_RDY:
        case OS_TASK_STATE_DLY:
        case OS_TASK_STATE_SUSPENDED:
        case OS_TASK_STATE_DLY_SUSPENDED:
        default:
            break;
    }
}

首先会根据任务的状态,来判断其处于什么任务列表中(PendListTickListPendList + TickList),然后将其从任务列表中移除,并判断是否处于Suspended状态,如果不是,再把这个任务加入到就绪列表ReadyList中。

4. OS_Post

OS_Post函数的实现如下:

[os_core.c OS_Post函数]

void  OS_Post (OS_PEND_OBJ  *p_obj,
            OS_TCB       *p_tcb,
            void         *p_void,
            OS_MSG_SIZE   msg_size,
            CPU_TS        ts)
{
#if (OS_CFG_TS_EN == DEF_DISABLED)
    (void)ts;
#endif
#if (OS_MSG_EN == DEF_DISABLED)
    (void)p_void;
    (void)msg_size;
#endif

    switch (p_tcb->TaskState) {
        case OS_TASK_STATE_RDY:
        case OS_TASK_STATE_DLY:
        case OS_TASK_STATE_SUSPENDED:
        case OS_TASK_STATE_DLY_SUSPENDED:
            break;

        case OS_TASK_STATE_PEND:
        case OS_TASK_STATE_PEND_TIMEOUT:
#if (OS_MSG_EN == DEF_ENABLED)
            p_tcb->MsgPtr  = p_void;
            p_tcb->MsgSize = msg_size;
#endif
#if (OS_CFG_TS_EN == DEF_ENABLED)
                p_tcb->TS      = ts;
#endif
            //如果这个任务处于某个PendList中
            //把这个任务从这个PendList中移除
            if (p_obj != (OS_PEND_OBJ *)0) {
                OS_PendListRemove(p_tcb);
            }
#if (OS_CFG_DBG_EN == DEF_ENABLED)
            OS_PendDbgNameRemove(p_obj, p_tcb);
#endif
#if (OS_CFG_TASK_TICK_EN == DEF_ENABLED)
            //如果这个任务处于某个TickList中
            //把这个任务从这个TickList中移除
            if (p_tcb->TaskState == OS_TASK_STATE_PEND_TIMEOUT) {
                OS_TickListRemove(p_tcb);
            }
#endif
            //没有包含suspended状态的任务
            //插入到就绪列表ReadyList中
            OS_RdyListInsert(p_tcb);
            p_tcb->TaskState  = OS_TASK_STATE_RDY;
            p_tcb->PendStatus = OS_STATUS_PEND_OK;
            p_tcb->PendOn     = OS_TASK_PEND_ON_NOTHING;
            break;

        //包含有suspend状态的任务,
        //只把他们从相应的TickList和PendList中移除
        //但是不把他们加入到ReadyList中
        case OS_TASK_STATE_PEND_SUSPENDED:
        case OS_TASK_STATE_PEND_TIMEOUT_SUSPENDED:
#if (OS_MSG_EN == DEF_ENABLED)
            p_tcb->MsgPtr  = p_void;
            p_tcb->MsgSize = msg_size;
#endif
#if (OS_CFG_TS_EN == DEF_ENABLED)
            p_tcb->TS      = ts;
#endif
            if (p_obj != (OS_PEND_OBJ *)0) {
                OS_PendListRemove(p_tcb);
            }
#if (OS_CFG_DBG_EN == DEF_ENABLED)
            OS_PendDbgNameRemove(p_obj, p_tcb);
#endif
#if (OS_CFG_TASK_TICK_EN == DEF_ENABLED)
            if (p_tcb->TaskState == OS_TASK_STATE_PEND_TIMEOUT_SUSPENDED) {
                OS_TickListRemove(p_tcb);
            }
#endif
            p_tcb->TaskState  = OS_TASK_STATE_SUSPENDED;
            p_tcb->PendStatus = OS_STATUS_PEND_OK;
            p_tcb->PendOn     = OS_TASK_PEND_ON_NOTHING;
            break;

        default:
            break;
    }
}

这个函数会判断这个任务处于什么样的列表中(PendListTickListPendList + TickList),将他们从中移除,如果任务状态不包含Suspended状态,则把他们加入到就绪列表ReadyList中。

二. 事件标志组OS_FLAG_GRP

1. 创建事件标志组OSFlagCreate

OSFlagCreate函数片段1:

[os_flag.c  OSFlagCreate函数片段1]

void  OSFlagCreate (OS_FLAG_GRP  *p_grp,
                    CPU_CHAR     *p_name,
                    OS_FLAGS      flags,
                    OS_ERR       *p_err)
{
    CPU_SR_ALLOC();

    //p_err的入参判断
    #ifdef OS_SAFETY_CRITICAL
        if (p_err == (OS_ERR *)0) {
            OS_SAFETY_CRITICAL_EXCEPTION();
            return;
        }
    #endif

    #ifdef OS_SAFETY_CRITICAL_IEC61508
        if (OSSafetyCriticalStartFlag == DEF_TRUE) {
        *p_err = OS_ERR_ILLEGAL_CREATE_RUN_TIME;
            return;
        }
    #endif

    //不能处于`ISR`中
    #if (OS_CFG_CALLED_FROM_ISR_CHK_EN == DEF_ENABLED)
        if (OSIntNestingCtr > 0u) {
        *p_err = OS_ERR_CREATE_ISR;
            return;
        }
    #endif

    //p_grp的入参判断
    #if (OS_CFG_ARG_CHK_EN == DEF_ENABLED)
        if (p_grp == (OS_FLAG_GRP *)0) {
        *p_err = OS_ERR_OBJ_PTR_NULL;
            return;
        }
#endif

这一段代码做一些入参判断,并规定,不能中断处理函数ISR中调用这个函数。

OSFlagCreate函数片段2:

[os_flag.c  OSFlagCreate函数片段2]

    CPU_CRITICAL_ENTER();

    //设置内核对象的类型
#if (OS_OBJ_TYPE_REQ == DEF_ENABLED)
    p_grp->Type    = OS_OBJ_TYPE_FLAG;
#endif
    //设置内核对象的名字
#if (OS_CFG_DBG_EN == DEF_ENABLED)
    p_grp->NamePtr = p_name;
#else
    (void)p_name;
#endif
    //设置Flags
    p_grp->Flags   = flags;
#if (OS_CFG_TS_EN == DEF_ENABLED)
    p_grp->TS      = 0u;
#endif
    //初始化`PendList`
    OS_PendListInit(&p_grp->PendList);

#if (OS_CFG_DBG_EN == DEF_ENABLED)
    OS_FlagDbgListAdd(p_grp);
    OSFlagQty++;
#endif

    OS_TRACE_FLAG_CREATE(p_grp, p_name);

    CPU_CRITICAL_EXIT();
    *p_err = OS_ERR_NONE;
}

这一段代码主要设置内核对象的类型和名字,并设置Flags,以及初始化这个事件标志组的PendList

2. 删除事件标志组OSFlagDel

OSFlagDel函数片段1:

[os_flag.c  OSFlagDel函数片段1]

OS_OBJ_QTY  OSFlagDel (OS_FLAG_GRP  *p_grp,
                    OS_OPT        opt,
                    OS_ERR       *p_err)
{

    ...

#ifdef OS_SAFETY_CRITICAL
    //p_err的入参判断
    if (p_err == (OS_ERR *)0) {
        OS_SAFETY_CRITICAL_EXCEPTION();
        return (0u);
    }
#endif

    OS_TRACE_FLAG_DEL_ENTER(p_grp, opt);

#ifdef OS_SAFETY_CRITICAL_IEC61508
    if (OSSafetyCriticalStartFlag == DEF_TRUE) {
        OS_TRACE_FLAG_DEL_EXIT(OS_ERR_ILLEGAL_DEL_RUN_TIME);
        *p_err = OS_ERR_ILLEGAL_DEL_RUN_TIME;
        return (0u);
    }
#endif

#if (OS_CFG_CALLED_FROM_ISR_CHK_EN == DEF_ENABLED)
    //不能在中断处理函数`ISR`中调用
    if (OSIntNestingCtr > 0u) {
        *p_err = OS_ERR_DEL_ISR;
        OS_TRACE_FLAG_DEL_EXIT(OS_ERR_DEL_ISR);
        return (0u);
    }
#endif

#if (OS_CFG_INVALID_OS_CALLS_CHK_EN == DEF_ENABLED)
    //不能在`OS`没有运行前调用
    if (OSRunning != OS_STATE_OS_RUNNING) {
        OS_TRACE_FLAG_DEL_EXIT(OS_ERR_OS_NOT_RUNNING);
        *p_err = OS_ERR_OS_NOT_RUNNING;
        return (0u);
    }
#endif

#if (OS_CFG_ARG_CHK_EN == DEF_ENABLED)
    //p_grp的入参判断
    if (p_grp == (OS_FLAG_GRP *)0) {
        OS_TRACE_FLAG_DEL_EXIT(OS_ERR_OBJ_PTR_NULL);
        *p_err  = OS_ERR_OBJ_PTR_NULL;
        return (0u);
    }
#endif

#if (OS_CFG_OBJ_TYPE_CHK_EN == DEF_ENABLED)
    //p_grp的内核对象类型判断
    if (p_grp->Type != OS_OBJ_TYPE_FLAG) {
        OS_TRACE_FLAG_DEL_EXIT(OS_ERR_OBJ_TYPE);
        *p_err = OS_ERR_OBJ_TYPE;
        return (0u);
    }
#endif

函数片段1主要做一些入参的出错判断,并规定,不能在中断处理函数中调用,不能在OS没有运行前调用。

OSFlagDel函数片段2:

[os_flag.c  OSFlagDel函数片段2]

    CPU_CRITICAL_ENTER();
    p_pend_list = &p_grp->PendList;
    nbr_tasks   = 0u;
    switch (opt) {
        //当`PendList`中没有任务时才删除
        case OS_OPT_DEL_NO_PEND:
            //如果`PendList`没有任务
            if (p_pend_list->HeadPtr == (OS_TCB *)0) {
#if (OS_CFG_DBG_EN == DEF_ENABLED)
                OS_FlagDbgListRemove(p_grp);
                OSFlagQty--;
#endif
                OS_TRACE_FLAG_DEL(p_grp);
                //清零OS_FLAG_GRP里的变量和初始化`PendList`
                OS_FlagClr(p_grp);

                CPU_CRITICAL_EXIT();

                *p_err = OS_ERR_NONE;
            } else {
                CPU_CRITICAL_EXIT();
                *p_err = OS_ERR_TASK_WAITING;
            }
            break;

        //不管`PendList`中有没有任务都删除
        case OS_OPT_DEL_ALWAYS:
#if (OS_CFG_TS_EN == DEF_ENABLED)
            ts = OS_TS_GET();
#else
            ts = 0u;
#endif
            //对`PendList`中的每一个任务都调用`OS_PendAbort`
            while (p_pend_list->HeadPtr != (OS_TCB *)0) {
                p_tcb = p_pend_list->HeadPtr;

                //设置状态为OS_STATUS_PEND_DEL
                //告诉内核这个任务的Pend操作是被删除的
                OS_PendAbort(p_tcb,
                            ts,
                            OS_STATUS_PEND_DEL);
                nbr_tasks++;
            }
#if (OS_CFG_DBG_EN == DEF_ENABLED)
            OS_FlagDbgListRemove(p_grp);
            OSFlagQty--;
#endif
            OS_TRACE_FLAG_DEL(p_grp);

            //清零OS_FLAG_GRP里的变量和初始化`PendList`
            OS_FlagClr(p_grp);
            CPU_CRITICAL_EXIT();

            //引发一次调度
            OSSched();
            *p_err = OS_ERR_NONE;
            break;

        default:
            CPU_CRITICAL_EXIT();
            *p_err = OS_ERR_OPT_INVALID;
            break;
    }

    OS_TRACE_FLAG_DEL_EXIT(*p_err);

    return (nbr_tasks);
}

OS_OPT_DEL_NO_PEND指的是,只有PendList中没有任务的时候才删除这个OS_FLAG_GRP

OS_OPT_DEL_ALWAYS指的是,不管PendList中有没有任务,把这些任务都调用OS_PendAbort从相应的PendList以及TickList中移除,在调用OS_PendAbort时最后一个传参是OS_STATUS_PEND_DEL,因为Pend Abort操作会使那些任务的Pend操作从阻塞状态继续向下进行,这个时候,需要告诉内核,他们是由于内核对象的删除才被放入到ReadyList中(如果这个任务没有suspended)的,这个会在OSFlagPend函数中详解。然后再调用OS_FlagClr清零OS_FLAG_GRP里的变量和初始化PendList。最终调用OSSched引发一次调度。

3. 事件标志组Pend操作OSFlagPend

OSFlagPend函数片段1:

[os_flag.c  OSFlagPend 函数片段1]

OS_FLAGS  OSFlagPend (OS_FLAG_GRP  *p_grp,
                      OS_FLAGS      flags,
                      OS_TICK       timeout,
                      OS_OPT        opt,
                      CPU_TS       *p_ts,
                      OS_ERR       *p_err)
{
    CPU_BOOLEAN  consume;
    OS_FLAGS     flags_rdy;
    OS_OPT       mode;
    CPU_SR_ALLOC();


#ifdef OS_SAFETY_CRITICAL
    //p_err合法性判断
    if (p_err == (OS_ERR *)0) {
        OS_SAFETY_CRITICAL_EXCEPTION();
        return (0u);
    }
#endif

    OS_TRACE_FLAG_PEND_ENTER(p_grp, flags, timeout, opt, p_ts);

#if (OS_CFG_CALLED_FROM_ISR_CHK_EN == DEF_ENABLED)
    //不能在中断处理函数ISR中调用
    if (OSIntNestingCtr > 0u) {
    *p_err = OS_ERR_PEND_ISR;
        OS_TRACE_FLAG_PEND_FAILED(p_grp);
        OS_TRACE_FLAG_PEND_EXIT(OS_ERR_PEND_ISR);
        return ((OS_FLAGS)0);
    }
#endif

#if (OS_CFG_INVALID_OS_CALLS_CHK_EN == DEF_ENABLED)
    //不能在系统没运行之前调用
    if (OSRunning != OS_STATE_OS_RUNNING) {
        OS_TRACE_FLAG_PEND_EXIT(OS_ERR_OS_NOT_RUNNING);
        *p_err = OS_ERR_OS_NOT_RUNNING;
        return (0u);
    }
#endif

#if (OS_CFG_ARG_CHK_EN == DEF_ENABLED)
    //p_grp合法性判断
    if (p_grp == (OS_FLAG_GRP *)0) {
        OS_TRACE_FLAG_PEND_FAILED(p_grp);
        OS_TRACE_FLAG_PEND_EXIT(OS_ERR_OBJ_PTR_NULL);
    *p_err = OS_ERR_OBJ_PTR_NULL;
        return (0u);
    }
    //opt合法性判断
    switch (opt) {
        case OS_OPT_PEND_FLAG_CLR_ALL:
        case OS_OPT_PEND_FLAG_CLR_ANY:
        case OS_OPT_PEND_FLAG_SET_ALL:
        case OS_OPT_PEND_FLAG_SET_ANY:
        case OS_OPT_PEND_FLAG_CLR_ALL | OS_OPT_PEND_FLAG_CONSUME:
        case OS_OPT_PEND_FLAG_CLR_ANY | OS_OPT_PEND_FLAG_CONSUME:
        case OS_OPT_PEND_FLAG_SET_ALL | OS_OPT_PEND_FLAG_CONSUME:
        case OS_OPT_PEND_FLAG_SET_ANY | OS_OPT_PEND_FLAG_CONSUME:
        case OS_OPT_PEND_FLAG_CLR_ALL | OS_OPT_PEND_NON_BLOCKING:
        case OS_OPT_PEND_FLAG_CLR_ANY | OS_OPT_PEND_NON_BLOCKING:
        case OS_OPT_PEND_FLAG_SET_ALL | OS_OPT_PEND_NON_BLOCKING:
        case OS_OPT_PEND_FLAG_SET_ANY | OS_OPT_PEND_NON_BLOCKING:
        case OS_OPT_PEND_FLAG_CLR_ALL | (OS_OPT)(OS_OPT_PEND_FLAG_CONSUME | OS_OPT_PEND_NON_BLOCKING):
        case OS_OPT_PEND_FLAG_CLR_ANY | (OS_OPT)(OS_OPT_PEND_FLAG_CONSUME | OS_OPT_PEND_NON_BLOCKING):
        case OS_OPT_PEND_FLAG_SET_ALL | (OS_OPT)(OS_OPT_PEND_FLAG_CONSUME | OS_OPT_PEND_NON_BLOCKING):
        case OS_OPT_PEND_FLAG_SET_ANY | (OS_OPT)(OS_OPT_PEND_FLAG_CONSUME | OS_OPT_PEND_NON_BLOCKING):
            break;

        default:
            OS_TRACE_FLAG_PEND_FAILED(p_grp);
            OS_TRACE_FLAG_PEND_EXIT(OS_ERR_OPT_INVALID);
            *p_err = OS_ERR_OPT_INVALID;
            return (0u);
    }
#endif

#if (OS_CFG_OBJ_TYPE_CHK_EN == DEF_ENABLED)
    //确保p_grp的类型正确,确保其已经被创建(create函数)。
    if (p_grp->Type != OS_OBJ_TYPE_FLAG) {
        OS_TRACE_FLAG_PEND_FAILED(p_grp);
        OS_TRACE_FLAG_PEND_EXIT(OS_ERR_OBJ_TYPE);
        *p_err = OS_ERR_OBJ_TYPE;
        return (0u);
    }
#endif

    //consume 的意思是指,如果pend操作等到了相应的bit,
    //那么这次Pend操作满足条件后会将相应的bit全部设置为条件不满足
    if ((opt & OS_OPT_PEND_FLAG_CONSUME) != 0u) {
        consume = DEF_TRUE;
    } else {
        consume = DEF_FALSE;
    }

    if (p_ts != (CPU_TS *)0) {
    *p_ts = 0u;
    }

上面的代码规定,不能在ISR中调用这个函数,不能在OS运行起来之前调用这个函数。另外这个函数做了一些入参出错判断。

随后就根据opt的选项来进行相应的处理:

[os_flag.c  OSFlagPend 函数片段2]

//只获取`PendFlag`相关的信息
mode = opt & OS_OPT_PEND_FLAG_MASK;
CPU_CRITICAL_ENTER();
switch (mode) {

    //SET ALL 指的是,等待所有的bit都为1
    case OS_OPT_PEND_FLAG_SET_ALL:
        flags_rdy = (p_grp->Flags & flags);
        //如果条件全部满足
        if (flags_rdy == flags) {
            //如果有consume操作,那么把成立的条件全部清空
            if (consume == DEF_TRUE) {
                p_grp->Flags &= ~flags_rdy;
            }
            OSTCBCurPtr->FlagsRdy = flags_rdy;
#if (OS_CFG_TS_EN == DEF_ENABLED)
            if (p_ts != (CPU_TS *)0) {
               *p_ts = p_grp->TS;
            }
#endi
            CPU_CRITICAL_EXIT();
            OS_TRACE_FLAG_PEND(p_grp);
            OS_TRACE_FLAG_PEND_EXIT(OS_ERR_NONE);
            *p_err = OS_ERR_NONE;
            //条件成立直接返回
            return (flags_rdy);
        //如果不满足条件
        } else {
            //如果是非阻塞模式
            if ((opt & OS_OPT_PEND_NON_BLOCKING) != 0u) {
                CPU_CRITICAL_EXIT();
                OS_TRACE_FLAG_PEND_FAILED(p_grp);
                OS_TRACE_FLAG_PEND_EXIT(OS_ERR_PEND_WOULD_BLOCK);
               *p_err = OS_ERR_PEND_WOULD_BLOCK;
                //返回出去,不阻塞
                return ((OS_FLAGS)0);
            //如果是阻塞模式
            } else {
               //如果锁住了调度器
                if (OSSchedLockNestingCtr > 0u) {
                    CPU_CRITICAL_EXIT();
                    OS_TRACE_FLAG_PEND_FAILED(p_grp);
                    OS_TRACE_FLAG_PEND_EXIT(OS_ERR_SCHED_LOCKED);
                   *p_err = OS_ERR_SCHED_LOCKED;
                    //返回,不调度
                    return (0u);
                }
            }
            //调用OS_FlagBlock,
            //最终调用OS_Pend,将其加入相应的PendList和TickList
            OS_FlagBlock(p_grp,
                         flags,
                         opt,
                         timeout);
            CPU_CRITICAL_EXIT();
        }
        break;

    //SET ANY值得是,只要有一个bit条件成立就可以
    case OS_OPT_PEND_FLAG_SET_ANY:
        flags_rdy = (p_grp->Flags & flags);
        //如果条件满足
        if (flags_rdy != 0u) {
            //如果设置了 consume ,清除那个Bit
            if (consume == DEF_TRUE) {
                p_grp->Flags &= ~flags_rdy;
            }
            OSTCBCurPtr->FlagsRdy = flags_rdy;
#if (OS_CFG_TS_EN == DEF_ENABLED)
            if (p_ts != (CPU_TS *)0) {
               *p_ts  = p_grp->TS;
            }
#endif
           CPU_CRITICAL_EXIT();
           OS_TRACE_FLAG_PEND(p_grp);
           OS_TRACE_FLAG_PEND_EXIT(OS_ERR_NONE);
           *p_err = OS_ERR_NONE;
           //条件成立直接返回
           return (flags_rdy);
        //如果条件不满足
        } else {
            //如果不阻塞模式
            if ((opt & OS_OPT_PEND_NON_BLOCKING) != 0u) {
                CPU_CRITICAL_EXIT();
                OS_TRACE_FLAG_PEND_EXIT(OS_ERR_PEND_WOULD_BLOCK);
                *p_err = OS_ERR_PEND_WOULD_BLOCK;
                //直接返回不阻塞
                return ((OS_FLAGS)0);
            //如果是阻塞模式
            } else {
                //处于所锁调度的状态
                if (OSSchedLockNestingCtr > 0u) {
                    CPU_CRITICAL_EXIT();
                    OS_TRACE_FLAG_PEND_EXIT(OS_ERR_SCHED_LOCKED);
                    *p_err = OS_ERR_SCHED_LOCKED;
                    //直接返回不调度
                    return ((OS_FLAGS)0);
                }
            }
            //调用OS_FlagBlock,
            //最终调用OS_Pend,将其加入相应的PendList和TickList
            OS_FlagBlock(p_grp,
                         flags,
                         opt,
                         timeout);
            CPU_CRITICAL_EXIT();
        }
        break;

#if (OS_CFG_FLAG_MODE_CLR_EN == DEF_ENABLED)
    //CLR ALL 指的是,等待到所有bit都为0时。
    case OS_OPT_PEND_FLAG_CLR_ALL:
        flags_rdy = (OS_FLAGS)(~p_grp->Flags & flags);
        //如果条件成立,及都为0时
        if (flags_rdy == flags) {
            //如果设置了consume,把这个成立的条件全部清除(即设为1)
            if (consume == DEF_TRUE) {
                p_grp->Flags |= flags_rdy;
            }
            OSTCBCurPtr->FlagsRdy = flags_rdy;
#if (OS_CFG_TS_EN == DEF_ENABLED)
            if (p_ts != (CPU_TS *)0) {
               *p_ts  = p_grp->TS;
            }
#endif
            CPU_CRITICAL_EXIT();
            OS_TRACE_FLAG_PEND(p_grp);
            OS_TRACE_FLAG_PEND_EXIT(OS_ERR_NONE);
            *p_err = OS_ERR_NONE;
            //条件成立直接返回
            return (flags_rdy);
        //如果条件不成立
        } else {
            //如果设置的时非阻塞模式
            if ((opt & OS_OPT_PEND_NON_BLOCKING) != 0u) {
                CPU_CRITICAL_EXIT();
                OS_TRACE_FLAG_PEND_EXIT(OS_ERR_PEND_WOULD_BLOCK);
                *p_err = OS_ERR_PEND_WOULD_BLOCK;
                //直接返回,不阻塞
                return ((OS_FLAGS)0);
            //如果设置的时阻塞模式
            } else {
                //如果锁住了调度器
                if (OSSchedLockNestingCtr > 0u) {
                    CPU_CRITICAL_EXIT();
                    OS_TRACE_FLAG_PEND_EXIT(OS_ERR_SCHED_LOCKED);
                    *p_err = OS_ERR_SCHED_LOCKED;
                    //直接返回不调度
                    return (0);
                }
            }
            //调用OS_FlagBlock,
            //最终调用OS_Pend,将其加入相应的PendList和TickList
            OS_FlagBlock(p_grp,
                         flags,
                         opt,
                         timeout);
            CPU_CRITICAL_EXIT();
        }
        break;

    //CLR ANY 值得时,只要有一个等待的bit为0,那么就条件成立
    case OS_OPT_PEND_FLAG_CLR_ANY:
        flags_rdy = (~p_grp->Flags & flags);
        //如果条件成立
        if (flags_rdy != 0u) {
            //如果设置了consume,则把成立的条件bit设置1
            if (consume == DEF_TRUE) {
                p_grp->Flags |= flags_rdy;
            }
            OSTCBCurPtr->FlagsRdy = flags_rdy;
#if (OS_CFG_TS_EN == DEF_ENABLED)
            if (p_ts != (CPU_TS *)0) {
               *p_ts  = p_grp->TS;
            }
#endif
            CPU_CRITICAL_EXIT();
            OS_TRACE_FLAG_PEND(p_grp);
            OS_TRACE_FLAG_PEND_EXIT(OS_ERR_NONE);
            *p_err = OS_ERR_NONE;
            //条件成立直接返回
            return (flags_rdy);
        //如果条件不成立
        } else {
            //如果是非阻塞模式
            if ((opt & OS_OPT_PEND_NON_BLOCKING) != 0u) {
                CPU_CRITICAL_EXIT();
                OS_TRACE_FLAG_PEND_EXIT(OS_ERR_PEND_WOULD_BLOCK);
                *p_err = OS_ERR_PEND_WOULD_BLOCK;
                //直接返回不阻塞
                return ((OS_FLAGS)0);
            //如果是阻塞模式
            } else {
                //如果锁住了调度器
                if (OSSchedLockNestingCtr > 0u) {
                    CPU_CRITICAL_EXIT();
                    OS_TRACE_FLAG_PEND_EXIT(OS_ERR_SCHED_LOCKED);
                    *p_err = OS_ERR_SCHED_LOCKED;
                    //直接返回不调度
                    return (0u);
                }
            }

            //调用OS_FlagBlock,
            //最终调用OS_Pend,将其加入相应的PendList和TickList
            OS_FlagBlock(p_grp,
                         flags,
                         opt,
                         timeout);
            CPU_CRITICAL_EXIT();
        }
        break;
#endif
    default:
        CPU_CRITICAL_EXIT();
        OS_TRACE_FLAG_PEND_FAILED(p_grp);
        OS_TRACE_FLAG_PEND_EXIT(OS_ERR_OPT_INVALID);
        *p_err = OS_ERR_OPT_INVALID;
        return (0u);
}

OS_TRACE_FLAG_PEND_BLOCK(p_grp);

//如果条件不成立 + 阻塞模式 + 调度器没上锁
//进行一次调度
OSSched();

上面的代码片段是根据相应的Pend Flag来进行判断函数等待条件成立的方式,以及是否是阻塞式的等待,是否包含consume等。最后如果条件不成立,并且是阻塞模式和调度器没上锁的时候,才会调用一次OSSched引发一次调度,这个时候当前任务已经处于PendList或者TickList中了,而没在ReadyList。等到其他任务或中断有Post操作,或者Abort操作,或者删除操作,或者timeout超时的话,才会切换到这个任务,继续向下进行:

[os_flag.c  OSFlagPend 函数片段3]

    CPU_CRITICAL_ENTER();
    //检查PendStatus
    switch (OSTCBCurPtr->PendStatus) {
        //条件满足
        case OS_STATUS_PEND_OK:
#if (OS_CFG_TS_EN == DEF_ENABLED)
            if (p_ts != (CPU_TS *)0) {
                *p_ts = OSTCBCurPtr->TS;
            }
#endif
            OS_TRACE_FLAG_PEND(p_grp);
            //设置为OS_ERR_NONE
            *p_err = OS_ERR_NONE;
            break;

        //Abort 操作
        case OS_STATUS_PEND_ABORT:
#if (OS_CFG_TS_EN == DEF_ENABLED)
            if (p_ts != (CPU_TS *)0) {
                *p_ts = OSTCBCurPtr->TS;
            }
#endif
            CPU_CRITICAL_EXIT();
            OS_TRACE_FLAG_PEND_FAILED(p_grp);
            *p_err = OS_ERR_PEND_ABORT;
            break;
        case OS_STATUS_PEND_TIMEOUT:
            if (p_ts != (CPU_TS *)0) {
                *p_ts = 0u;
            }
            CPU_CRITICAL_EXIT();
            OS_TRACE_FLAG_PEND_FAILED(p_grp);
            *p_err = OS_ERR_TIMEOUT;
            break;

        //删除操作
        case OS_STATUS_PEND_DEL:
#if (OS_CFG_TS_EN == DEF_ENABLED)
            if (p_ts != (CPU_TS *)0) {
                *p_ts = OSTCBCurPtr->TS;
            }
#endif
            CPU_CRITICAL_EXIT();
            OS_TRACE_FLAG_PEND_FAILED(p_grp);
            *p_err = OS_ERR_OBJ_DEL;
            break;

        //其他非法的值
        default:
            CPU_CRITICAL_EXIT();
            OS_TRACE_FLAG_PEND_FAILED(p_grp);
            *p_err = OS_ERR_STATUS_INVALID;
            break;
    }
    //如果不是条件满足,返回退出
    if (*p_err != OS_ERR_NONE) {
        OS_TRACE_FLAG_PEND_EXIT(*p_err);
        return (0u);
    }

    //如果是条件满足,才执行以下操作
    flags_rdy = OSTCBCurPtr->FlagsRdy;

    //如果设置了consume,清除相应的条件
    if (consume == DEF_TRUE) {
        switch (mode) {
            case OS_OPT_PEND_FLAG_SET_ALL:
            case OS_OPT_PEND_FLAG_SET_ANY:
                p_grp->Flags &= ~flags_rdy;
                break;
    #if (OS_CFG_FLAG_MODE_CLR_EN == DEF_ENABLED)
            case OS_OPT_PEND_FLAG_CLR_ALL:
            case OS_OPT_PEND_FLAG_CLR_ANY:
                p_grp->Flags |=  flags_rdy;
                break;
    #endif
            default:
                CPU_CRITICAL_EXIT();
                OS_TRACE_FLAG_PEND_EXIT(OS_ERR_OPT_INVALID);
                *p_err = OS_ERR_OPT_INVALID;
                return (0u);
        }
    }
    CPU_CRITICAL_EXIT();
    OS_TRACE_FLAG_PEND_EXIT(OS_ERR_NONE);
    *p_err = OS_ERR_NONE;
    return (flags_rdy);
}

又跑到这个任务之后,会去检查任务从Pend处返回到继续运行的状态,如果是因为条件满足而返回的话,那么就再根据consume的设置而选择清除那些条件。

4. 事件标志组的PendAbort操作OSFlagPendAbort

这个函数把因为这个事件标志组的Pend操作而被放入PendList中或者TickList中的任务,从PendList或者TickList中移除,重新的被放入ReadyList中(如果这个任务没有被suspended的话)。OS_OPT_PEND_ABORT_1值得是只对PendList中优先级最高的任务有效;OS_OPT_PEND_ABORT_ALL指的是对PendList中所有的任务都有效。

OSFlagPendAbort的定义如下:

[os_flag.c  OSFlagPendAbort 函数]

OS_OBJ_QTY  OSFlagPendAbort (OS_FLAG_GRP  *p_grp,
                            OS_OPT        opt,
                            OS_ERR       *p_err)
{
    OS_PEND_LIST  *p_pend_list;
    OS_TCB        *p_tcb;
    CPU_TS         ts;
    OS_OBJ_QTY     nbr_tasks;
    CPU_SR_ALLOC();


#ifdef OS_SAFETY_CRITICAL
    //p_err入参的合法性检查
    if (p_err == (OS_ERR *)0) {
        OS_SAFETY_CRITICAL_EXCEPTION();
        return ((OS_OBJ_QTY)0u);
    }
#endif

#if (OS_CFG_CALLED_FROM_ISR_CHK_EN == DEF_ENABLED)
    //ISR中不能调用这个函数
    if (OSIntNestingCtr > 0u) {
        *p_err = OS_ERR_PEND_ABORT_ISR;
        return (0u);
    }
#endif

#if (OS_CFG_INVALID_OS_CALLS_CHK_EN == DEF_ENABLED)
    //内核没有运行起来时不能调用这个函数
    if (OSRunning != OS_STATE_OS_RUNNING) {
        *p_err = OS_ERR_OS_NOT_RUNNING;
        return (0u);
    }
#endif

#if (OS_CFG_ARG_CHK_EN == DEF_ENABLED)
    //p_grp合法性检查
    if (p_grp == (OS_FLAG_GRP *)0) {
        *p_err  =  OS_ERR_OBJ_PTR_NULL;
        return (0u);
    }
    switch (opt) {
        case OS_OPT_PEND_ABORT_1:
        case OS_OPT_PEND_ABORT_ALL:
        case OS_OPT_PEND_ABORT_1   | OS_OPT_POST_NO_SCHED:
        case OS_OPT_PEND_ABORT_ALL | OS_OPT_POST_NO_SCHED:
            break;

        default:
            *p_err = OS_ERR_OPT_INVALID;
            return (0u);
    }
#endif

#if (OS_CFG_OBJ_TYPE_CHK_EN == DEF_ENABLED)
    //确保p_grp已经通过了create函数,确实存在
    if (p_grp->Type != OS_OBJ_TYPE_FLAG) {
        *p_err = OS_ERR_OBJ_TYPE;
        return (0u);
    }
#endif

    CPU_CRITICAL_ENTER();
    p_pend_list = &p_grp->PendList;

    //如果PendList中的函数为空,则直接退出
    if (p_pend_list->HeadPtr == (OS_TCB *)0) {
        CPU_CRITICAL_EXIT();
        *p_err = OS_ERR_PEND_ABORT_NONE;
        return (0u);
    }

    nbr_tasks = 0u;
#if (OS_CFG_TS_EN == DEF_ENABLED)
    ts        = OS_TS_GET();
#else
    ts        = 0u;
#endif

    //遍历PendList
    while (p_pend_list->HeadPtr != (OS_TCB *)0) {
        p_tcb = p_pend_list->HeadPtr;

        //对每一个任务都调用PendAbort,将他们从相应的PendList和TickList中移除
        //并放入到ReadyList中(如果没有suspended)
        //最后一个参数是OS_STATUS_PEND_ABORT,告诉内核这些任务是因为Abort操作
        //才被放入到`ReadyList`中的
        OS_PendAbort(p_tcb,
                    ts,
                    OS_STATUS_PEND_ABORT);
        nbr_tasks++;

        //如果没有OS_OPT_PEND_ABORT_ALL
        //那么只对第一个任务操作,就是优先级最高的任务。
        if (opt != OS_OPT_PEND_ABORT_ALL) {
            break;
        }
    }
    CPU_CRITICAL_EXIT();

    //如果没加OS_OPT_POST_NO_SCHED
    //则引发一次调度
    if ((opt & OS_OPT_POST_NO_SCHED) == 0u) {
        OSSched();
    }

    *p_err = OS_ERR_NONE;
    return (nbr_tasks);
}

OSFlagPendAbort是将PendList中的所有任务从PendList(和TickList)中移除,并放入ReadyList中(如果任务没有suspended的话)。

5. 获取当前任务的就绪标志OSFlagPendGetFlagsRdy

OSFlagPendGetFlagsRdy 函数实现如下:

[os_flag.c  OSFlagPendGetFlagsRdy 函数]

OS_FLAGS  OSFlagPendGetFlagsRdy (OS_ERR  *p_err)
{
    OS_FLAGS  flags;
    CPU_SR_ALLOC();


#ifdef OS_SAFETY_CRITICAL
    //p_err的入参合法性判断
    if (p_err == (OS_ERR *)0) {
        OS_SAFETY_CRITICAL_EXCEPTION();
        return ((OS_FLAGS)0);
    }
#endif

#if (OS_CFG_INVALID_OS_CALLS_CHK_EN == DEF_ENABLED)
    //内核没有运行之前不能调用
    if (OSRunning != OS_STATE_OS_RUNNING) {
    *p_err = OS_ERR_OS_NOT_RUNNING;
        return (0u);
    }
#endif

#if (OS_CFG_CALLED_FROM_ISR_CHK_EN == DEF_ENABLED)
    //ISR中不能调用
    if (OSIntNestingCtr > 0u) {
    *p_err = OS_ERR_PEND_ISR;
        return (0u);
    }
#endif

    CPU_CRITICAL_ENTER();

    //获取OSTCBCurPtr->FlagsRdy
    flags = OSTCBCurPtr->FlagsRdy;
    CPU_CRITICAL_EXIT();
    *p_err = OS_ERR_NONE;
    return (flags);
}

这个函数在ISR中不能调用,同时也不能在内核运行前调用。

6. 事件标志组的Post操作OSFlagPost

OSFlagPost函数实现如下:

[os_flag.c  OSFlagPost 函数片段1]

OS_FLAGS  OSFlagPost (OS_FLAG_GRP  *p_grp,
                    OS_FLAGS      flags,
                    OS_OPT        opt,
                    OS_ERR       *p_err)
{

    OS_FLAGS       flags_cur;
    OS_FLAGS       flags_rdy;
    OS_OPT         mode;
    OS_PEND_LIST  *p_pend_list;
    OS_TCB        *p_tcb;
    OS_TCB        *p_tcb_next;
    CPU_TS         ts;
    CPU_SR_ALLOC();


#ifdef OS_SAFETY_CRITICAL
    //p_err入参合法性判断
    if (p_err == (OS_ERR *)0) {
        OS_SAFETY_CRITICAL_EXCEPTION();
        return (0u);
    }
#endif

    OS_TRACE_FLAG_POST_ENTER(p_grp, flags, opt);

#if (OS_CFG_INVALID_OS_CALLS_CHK_EN == DEF_ENABLED)
    //内核运行前不能调用
    if (OSRunning != OS_STATE_OS_RUNNING) {
        OS_TRACE_FLAG_POST_EXIT(OS_ERR_OS_NOT_RUNNING);
        *p_err = OS_ERR_OS_NOT_RUNNING;
        return (0u);
    }
#endif

#if (OS_CFG_ARG_CHK_EN == DEF_ENABLED)
    //p_grp入参合法性判断
    if (p_grp == (OS_FLAG_GRP *)0) {
        OS_TRACE_FLAG_POST_FAILED(p_grp);
        OS_TRACE_FLAG_POST_EXIT(OS_ERR_OBJ_PTR_NULL);
        *p_err  = OS_ERR_OBJ_PTR_NULL;
        return (0u);
    }
#endif

#if (OS_CFG_OBJ_TYPE_CHK_EN == DEF_ENABLED)
    //确保p_grp已经经过了create函数
    if (p_grp->Type != OS_OBJ_TYPE_FLAG) {
        OS_TRACE_FLAG_POST_FAILED(p_grp);
        OS_TRACE_FLAG_POST_EXIT(OS_ERR_OBJ_TYPE);
        *p_err = OS_ERR_OBJ_TYPE;
        return (0u);
    }
#endif

#if (OS_CFG_TS_EN == DEF_ENABLED)
    ts = OS_TS_GET();
#else
    ts = 0u;
#endif

    OS_TRACE_FLAG_POST(p_grp);

这个函数片段1做一些合法性的判断,他不能在内核运行前调用,和Pend操作不同的是,他可以在ISR中调用。

[os_flag.c  OSFlagPost 函数片段2]

    switch (opt) {
        //如果是SET操作
        case OS_OPT_POST_FLAG_SET:
        case OS_OPT_POST_FLAG_SET | OS_OPT_POST_NO_SCHED:
            CPU_CRITICAL_ENTER();
            //把相应的位置1
            p_grp->Flags |=  flags;
            break;

        //如果是CLR操作
        case OS_OPT_POST_FLAG_CLR:
        case OS_OPT_POST_FLAG_CLR | OS_OPT_POST_NO_SCHED:
            CPU_CRITICAL_ENTER();
            //把相应的位置0
            p_grp->Flags &= ~flags;
            break;

        default:
            *p_err = OS_ERR_OPT_INVALID;
            OS_TRACE_FLAG_POST_EXIT(*p_err);
            return (0u);
    }
#if (OS_CFG_TS_EN == DEF_ENABLED)
    p_grp->TS   = ts;
#endif
    p_pend_list = &p_grp->PendList;

    //如果PendList中为空
    if (p_pend_list->HeadPtr == (OS_TCB *)0) {
        CPU_CRITICAL_EXIT();
        *p_err = OS_ERR_NONE;
        OS_TRACE_FLAG_POST_EXIT(*p_err);
        //返回
        return (p_grp->Flags);
    }

    p_tcb = p_pend_list->HeadPtr;

    //遍历PendList中的每一个任务
    while (p_tcb != (OS_TCB *)0) {
        p_tcb_next = p_tcb->PendNextPtr;
        mode       = p_tcb->FlagsOpt & OS_OPT_PEND_FLAG_MASK;
        switch (mode) {

            //全部Bit设为1才满足
            case OS_OPT_PEND_FLAG_SET_ALL:
                flags_rdy = (p_grp->Flags & p_tcb->FlagsPend);
                if (flags_rdy == p_tcb->FlagsPend) {
                    OS_FlagTaskRdy(p_tcb,
                                    flags_rdy,
                                    ts);
                }
                break;

            //只要有一个Bit为1就满足
            case OS_OPT_PEND_FLAG_SET_ANY:
                flags_rdy = (p_grp->Flags & p_tcb->FlagsPend);
                if (flags_rdy != 0u) {
                    OS_FlagTaskRdy(p_tcb,
                                    flags_rdy,
                                    ts);
                }
                break;

#if (OS_CFG_FLAG_MODE_CLR_EN == DEF_ENABLED)
            //全部Bit为0才满足
            case OS_OPT_PEND_FLAG_CLR_ALL:
                flags_rdy = (OS_FLAGS)(~p_grp->Flags & p_tcb->FlagsPend);
                if (flags_rdy == p_tcb->FlagsPend) {
                    OS_FlagTaskRdy(p_tcb,
                                    flags_rdy,
                                    ts);
                }
                break;

            //主要有一个为0才满足
            case OS_OPT_PEND_FLAG_CLR_ANY:
                flags_rdy = (OS_FLAGS)(~p_grp->Flags & p_tcb->FlagsPend);
                if (flags_rdy != 0u) {
                    OS_FlagTaskRdy(p_tcb,
                                    flags_rdy,
                                    ts);
                }
                break;
#endif
            default:
                CPU_CRITICAL_EXIT();
                *p_err = OS_ERR_FLAG_PEND_OPT;
                OS_TRACE_FLAG_POST_EXIT(*p_err);
                return (0u);
        }

        p_tcb = p_tcb_next;
    }
    CPU_CRITICAL_EXIT();

    if ((opt & OS_OPT_POST_NO_SCHED) == 0u) {
        OSSched();
    }

    CPU_CRITICAL_ENTER();
    flags_cur = p_grp->Flags;
    CPU_CRITICAL_EXIT();
    *p_err     = OS_ERR_NONE;

    OS_TRACE_FLAG_POST_EXIT(*p_err);
    return (flags_cur);
}

如果PendList列表为空,则直接返回,否则遍历整个PendList,对其中所有满足条件的任务调用OS_FlagTaskRdy函数,其定义如下:

[os_flag.c  OS_FlagTaskRdy 函数]

void   OS_FlagTaskRdy (OS_TCB    *p_tcb,
                    OS_FLAGS   flags_rdy,
                    CPU_TS     ts)
{
#if (OS_CFG_TS_EN == DEF_DISABLED)
    (void)ts;
#endif

    p_tcb->FlagsRdy   = flags_rdy;

    //设置为OS_STATUS_PEND_OK,告诉内核这个任务的Pend等待的条件已满足
    p_tcb->PendStatus = OS_STATUS_PEND_OK;
    p_tcb->PendOn     = OS_TASK_PEND_ON_NOTHING;

#if (OS_CFG_TS_EN == DEF_ENABLED)
    p_tcb->TS         = ts;
#endif
    switch (p_tcb->TaskState) {

        //如果是Pend或者Pend + TimeOut,没有suspended
        case OS_TASK_STATE_PEND:
        case OS_TASK_STATE_PEND_TIMEOUT:
#if (OS_CFG_TASK_TICK_EN == DEF_ENABLED)
            if (p_tcb->TaskState == OS_TASK_STATE_PEND_TIMEOUT) {
                //如果是OS_TASK_STATE_PEND_TIMEOUT从TickList中移除
                OS_TickListRemove(p_tcb);
            }
#endif
            //如果没有suspend插入到就绪队列表中
            OS_RdyListInsert(p_tcb);
            //设置任务为就绪态
            p_tcb->TaskState = OS_TASK_STATE_RDY;
            break;

        //如果是suspended
        case OS_TASK_STATE_PEND_SUSPENDED:
        case OS_TASK_STATE_PEND_TIMEOUT_SUSPENDED:
            p_tcb->TaskState = OS_TASK_STATE_SUSPENDED;
            break;

        case OS_TASK_STATE_RDY:
        case OS_TASK_STATE_DLY:
        case OS_TASK_STATE_DLY_SUSPENDED:
        case OS_TASK_STATE_SUSPENDED:
        default:
            break;
    }
    //从PendList中移除
    OS_PendListRemove(p_tcb);
}

OS_FlagTaskRdy这个函数就是从PendList(可能也从TickList)中把这个任务移除,如果没有Suspended并加入就绪列表ReadyList中。

将每个任务都调用OS_FlagTaskRdy之后,如果没有特别的声明OS_OPT_POST_NO_SCHED这个选项,那么就调用OSSched引发一次调度。

三. 计数信号量OS_SEM

1. 创建计数信号量OSSemCreate

创建信号量OSSemCreate的实现如下:

[os_sem.c OSSemCreate 函数]

void  OSSemCreate (OS_SEM      *p_sem,
                   CPU_CHAR    *p_name,
                   OS_SEM_CTR   cnt,
                   OS_ERR      *p_err)
{
    CPU_SR_ALLOC();


#ifdef OS_SAFETY_CRITICAL
    //p_err入参合法性的判断
    if (p_err == (OS_ERR *)0) {
        OS_SAFETY_CRITICAL_EXCEPTION();
        return;
    }
#endif

#ifdef OS_SAFETY_CRITICAL_IEC61508
    if (OSSafetyCriticalStartFlag == DEF_TRUE) {
        *p_err = OS_ERR_ILLEGAL_CREATE_RUN_TIME;
        return;
    }
#endif

#if (OS_CFG_CALLED_FROM_ISR_CHK_EN == DEF_ENABLED)
    //不能在ISR中调用这个函数
    if (OSIntNestingCtr > 0u) {
        *p_err = OS_ERR_CREATE_ISR;
        return;
    }
#endif

#if (OS_CFG_ARG_CHK_EN == DEF_ENABLED)
    //p_sem入参合法性判断
    if (p_sem == (OS_SEM *)0) {
        *p_err = OS_ERR_OBJ_PTR_NULL;
        return;
    }
#endif

    CPU_CRITICAL_ENTER();
#if (OS_OBJ_TYPE_REQ == DEF_ENABLED)
    p_sem->Type    = OS_OBJ_TYPE_SEM;
#endif
    p_sem->Ctr     = cnt;
#if (OS_CFG_TS_EN == DEF_ENABLED)
    p_sem->TS      = 0u;
#endif
#if (OS_CFG_DBG_EN == DEF_ENABLED)
    p_sem->NamePtr = p_name;
#else
    (void)p_name;
#endif
    //初始化PendList
    OS_PendListInit(&p_sem->PendList);

#if (OS_CFG_DBG_EN == DEF_ENABLED)
    OS_SemDbgListAdd(p_sem);
    OSSemQty++;
#endif

    OS_TRACE_SEM_CREATE(p_sem, p_name);

    CPU_CRITICAL_EXIT();
    *p_err = OS_ERR_NONE;
}

可以总结为如下:

  1. 不能在中断中使用;
  2. 设置默认计数ctr和名字NamePtr
  3. 初始化这个计数信号量的PendList

2. 删除计数信号量OSSemDel

删除信号量OSSemDel函数的实现如下:

[os_sem.c OSSemDel 函数]

OS_OBJ_QTY  OSSemDel (OS_SEM  *p_sem,
                      OS_OPT   opt,
                      OS_ERR  *p_err)
{
    OS_OBJ_QTY     nbr_tasks;
    OS_PEND_LIST  *p_pend_list;
    OS_TCB        *p_tcb;
    CPU_TS         ts;
    CPU_SR_ALLOC();


#ifdef OS_SAFETY_CRITICAL
    //p_err入参合法性判断
    if (p_err == (OS_ERR *)0) {
        OS_SAFETY_CRITICAL_EXCEPTION();
        return (0u);
    }
#endif

    OS_TRACE_SEM_DEL_ENTER(p_sem, opt);

#ifdef OS_SAFETY_CRITICAL_IEC61508
    if (OSSafetyCriticalStartFlag == DEF_TRUE) {
        OS_TRACE_SEM_DEL_EXIT(OS_ERR_ILLEGAL_DEL_RUN_TIME);
        *p_err = OS_ERR_ILLEGAL_DEL_RUN_TIME;
        return (0u);
    }
#endif

#if (OS_CFG_CALLED_FROM_ISR_CHK_EN == DEF_ENABLED)
    //不能在ISR中使用
    if (OSIntNestingCtr > 0u) {
        OS_TRACE_SEM_DEL_EXIT(OS_ERR_DEL_ISR);
        *p_err = OS_ERR_DEL_ISR;
        return (0u);
    }
#endif

#if (OS_CFG_INVALID_OS_CALLS_CHK_EN == DEF_ENABLED)
    //内核运行之前不能调用这个函数
    if (OSRunning != OS_STATE_OS_RUNNING) {
        OS_TRACE_SEM_DEL_EXIT(OS_ERR_OS_NOT_RUNNING);
        *p_err = OS_ERR_OS_NOT_RUNNING;
        return (0u);
    }
#endif

#if (OS_CFG_ARG_CHK_EN == DEF_ENABLED)
    //p_sem入参合法性判断
    if (p_sem == (OS_SEM *)0) {
        OS_TRACE_SEM_DEL_EXIT(OS_ERR_OBJ_PTR_NULL);
        *p_err = OS_ERR_OBJ_PTR_NULL;
        return (0u);
    }
#endif

#if (OS_CFG_OBJ_TYPE_CHK_EN == DEF_ENABLED)
    //确保p_sem已经经过create函数
    if (p_sem->Type != OS_OBJ_TYPE_SEM) {
        OS_TRACE_SEM_DEL_EXIT(OS_ERR_OBJ_TYPE);
        *p_err = OS_ERR_OBJ_TYPE;
        return (0u);
    }
#endif

    CPU_CRITICAL_ENTER();
    p_pend_list = &p_sem->PendList;
    nbr_tasks   = 0u;
    switch (opt) {

        //当PendList中没有任务时才删除
        case OS_OPT_DEL_NO_PEND:
            //如果PendList为空
            if (p_pend_list->HeadPtr == (OS_TCB *)0) {
#if (OS_CFG_DBG_EN == DEF_ENABLED)
                OS_SemDbgListRemove(p_sem);
                OSSemQty--;
#endif
                OS_TRACE_SEM_DEL(p_sem);

                //初始化OS_SEM中的成员,并初始化PendList
                OS_SemClr(p_sem);

                CPU_CRITICAL_EXIT();
                *p_err = OS_ERR_NONE;
            } else {
                CPU_CRITICAL_EXIT();
                *p_err = OS_ERR_TASK_WAITING;
            }
            break;

        //不管PendList中是否为空都删除
        case OS_OPT_DEL_ALWAYS:
#if (OS_CFG_TS_EN == DEF_ENABLED)
            ts = OS_TS_GET();
#else
            ts = 0u;
#endif
            //遍历整个PendList
            while (p_pend_list->HeadPtr != (OS_TCB *)0) {
                p_tcb = p_pend_list->HeadPtr;

                //对每个任务调用OS_PendAbort
                //最后一个入参是OS_STATUS_PEND_DEL
                OS_PendAbort(p_tcb,
                            ts,
                            OS_STATUS_PEND_DEL);
                nbr_tasks++;
            }
#if (OS_CFG_DBG_EN == DEF_ENABLED)
            OS_SemDbgListRemove(p_sem);
            OSSemQty--;
#endif
            OS_TRACE_SEM_DEL(p_sem);

            //初始化OS_SEM中的成员,并初始化PendList
            OS_SemClr(p_sem);
            CPU_CRITICAL_EXIT();

            //调用OSSched,引发一次调度
            OSSched();
            *p_err = OS_ERR_NONE;
            break;

        default:
            CPU_CRITICAL_EXIT();
            *p_err = OS_ERR_OPT_INVALID;
            break;
    }

    OS_TRACE_SEM_DEL_EXIT(*p_err);

    return (nbr_tasks);
}

他的中opt可以为OS_OPT_DEL_NO_PENDOS_OPT_DEL_ALWAYS

  1. OS_OPT_DEL_NO_PEND意思是指只有在这个计数信号量的PendList中没有任务的时候,才会删除。当PendList为空时,调用OS_SemClrOS_SEM中的各个变量清0,并初始化PendList
  2. OS_OPT_DEL_ALWAYS意思是指不管PendList有没有任务都会被删除,如果有任务的话,这些任务的Pend操作都会直接Pass。调用OS_PendAbort,这个函数的实现如下(这里最后一个入参为OS_STATUS_PEND_DEL):

把这些任务全部从相应的PendListTickList中移除并放入ReadyList之后,再调用OS_SemClr初始化OS_SEM中的变量和PendList。最后调用一次OSSched引发一次调度。

3. 计数信号量的Pend操作OSSemPend

OSSemPend函数片段1

[os_sem.c OSSemPend 函数 片段1]

OS_SEM_CTR  OSSemPend (OS_SEM   *p_sem,
                    OS_TICK   timeout,
                    OS_OPT    opt,
                    CPU_TS   *p_ts,
                    OS_ERR   *p_err)
{
    OS_SEM_CTR  ctr;
    CPU_SR_ALLOC();


#if (OS_CFG_TS_EN == DEF_DISABLED)
    (void)p_ts;
#endif

#ifdef OS_SAFETY_CRITICAL
    //p_err入参合法性检查
    if (p_err == (OS_ERR *)0) {
        OS_SAFETY_CRITICAL_EXCEPTION();
        return (0u);
    }
#endif

    OS_TRACE_SEM_PEND_ENTER(p_sem, timeout, opt, p_ts);

#if (OS_CFG_CALLED_FROM_ISR_CHK_EN == DEF_ENABLED)
    //不能在ISR中调用这个函数
    if (OSIntNestingCtr > 0u) {
        OS_TRACE_SEM_PEND_FAILED(p_sem);
        OS_TRACE_SEM_PEND_EXIT(OS_ERR_PEND_ISR);
    *p_err = OS_ERR_PEND_ISR;
        return (0u);
    }
#endif

#if (OS_CFG_INVALID_OS_CALLS_CHK_EN == DEF_ENABLED)
    //不能在内核运行之前调用
    if (OSRunning != OS_STATE_OS_RUNNING) {
        OS_TRACE_SEM_PEND_EXIT(OS_ERR_OS_NOT_RUNNING);
        *p_err = OS_ERR_OS_NOT_RUNNING;
        return (0u);
    }
#endif

#if (OS_CFG_ARG_CHK_EN == DEF_ENABLED)
    //p_sem的合法性判断
    if (p_sem == (OS_SEM *)0) {
        OS_TRACE_SEM_PEND_EXIT(OS_ERR_OBJ_PTR_NULL);
        *p_err = OS_ERR_OBJ_PTR_NULL;
        return (0u);
    }
    //opt的合法性判断
    switch (opt) {
        case OS_OPT_PEND_BLOCKING:
        case OS_OPT_PEND_NON_BLOCKING:
            break;

        default:
            OS_TRACE_SEM_PEND_FAILED(p_sem);
            OS_TRACE_SEM_PEND_EXIT(OS_ERR_OPT_INVALID);
            *p_err = OS_ERR_OPT_INVALID;
            return (0u);
    }
#endif

#if (OS_CFG_OBJ_TYPE_CHK_EN == DEF_ENABLED)
    //确保p_sem已经经过create函数
    if (p_sem->Type != OS_OBJ_TYPE_SEM) {
        OS_TRACE_SEM_PEND_FAILED(p_sem);
        OS_TRACE_SEM_PEND_EXIT(OS_ERR_OBJ_TYPE);
        *p_err = OS_ERR_OBJ_TYPE;
        return (0u);
    }
#endif

代码片段1,主要是入参的合法性判断,规定这个函数不能在ISR中运行,不能在内核运行前调用。

[os_sem.c OSSemPend 函数 片段2]

    CPU_CRITICAL_ENTER();

    //如果Ctr > 0,即满足等待条件
    if (p_sem->Ctr > 0u) {
        //自减操作
        p_sem->Ctr--;
#if (OS_CFG_TS_EN == DEF_ENABLED)
        if (p_ts != (CPU_TS *)0) {
        *p_ts = p_sem->TS;
        }
#endif
        ctr   = p_sem->Ctr;
        OS_TRACE_SEM_PEND(p_sem);
        CPU_CRITICAL_EXIT();
        OS_TRACE_SEM_PEND_EXIT(OS_ERR_NONE);

        //错误码设置为OS_ERR_NONE
        *p_err = OS_ERR_NONE;

        //直接返回
        return (ctr);
    }

    //下面是不满足等待条件

    //如果是非阻塞模式
    if ((opt & OS_OPT_PEND_NON_BLOCKING) != 0u) {
#if (OS_CFG_TS_EN == DEF_ENABLED)
        if (p_ts != (CPU_TS *)0) {
        *p_ts = 0u;
        }
#endif
        ctr   = p_sem->Ctr;
        CPU_CRITICAL_EXIT();
        OS_TRACE_SEM_PEND_FAILED(p_sem);
        OS_TRACE_SEM_PEND_EXIT(OS_ERR_PEND_WOULD_BLOCK);

        //错误码设置为OS_ERR_PEND_WOULD_BLOCK
        *p_err = OS_ERR_PEND_WOULD_BLOCK;

        //立即返回
        return (ctr);

    //如果是阻塞模式
    } else {

        //如果锁住了调度器
        if (OSSchedLockNestingCtr > 0u) {
#if (OS_CFG_TS_EN == DEF_ENABLED)
            if (p_ts != (CPU_TS *)0) {
            *p_ts = 0u;
            }
#endif
            CPU_CRITICAL_EXIT();
            OS_TRACE_SEM_PEND_FAILED(p_sem);
            OS_TRACE_SEM_PEND_EXIT(OS_ERR_SCHED_LOCKED);

            //错误码设置为OS_ERR_SCHED_LOCKED
            *p_err = OS_ERR_SCHED_LOCKED;

            //直接返回
            return (0u);
        }
    }

    //如果不满足条件,阻塞模式,并且没有锁住调度器
    //调用OS_Pend,加入PendList(如果timeout不为0并加入TickList)
    //从ReadyList中移除
    OS_Pend((OS_PEND_OBJ *)((void *)p_sem),
            OS_TASK_PEND_ON_SEM,
            timeout);
    CPU_CRITICAL_EXIT();
    OS_TRACE_SEM_PEND_BLOCK(p_sem);

    //调用OSSched引发一次调度
    OSSched();

这部分代码是判断是否满足条件(Ctr > 0),满足条件就对Ctr做自减操作,如果不满足,根据入参选项是否阻塞做相应的处理。如果阻塞的话,把任务加入PendList(如果Timeout不为零也加入TickList),并从ReadyList中移除,然后调用OSSched进行一次调度。

[os_sem.c OSSemPend 函数 片段3]

    CPU_CRITICAL_ENTER();
    switch (OSTCBCurPtr->PendStatus) {

        //PEND_OK,即满足条件
        case OS_STATUS_PEND_OK:
#if (OS_CFG_TS_EN == DEF_ENABLED)
            if (p_ts != (CPU_TS *)0) {
                *p_ts = OSTCBCurPtr->TS;
            }
#endif
            OS_TRACE_SEM_PEND(p_sem);
            //错误码设置为OS_ERR_NONE
            *p_err = OS_ERR_NONE;
            break;

        //PEND_ABORT,即为调用了Abort函数
        case OS_STATUS_PEND_ABORT:
#if (OS_CFG_TS_EN == DEF_ENABLED)
            if (p_ts != (CPU_TS *)0) {
                *p_ts = OSTCBCurPtr->TS;
            }
#endif
            OS_TRACE_SEM_PEND_FAILED(p_sem);
            //错误码设置为OS_ERR_PEND_ABORT
            *p_err = OS_ERR_PEND_ABORT;
            break;

        //PEND_TIMEOUT,超时
        case OS_STATUS_PEND_TIMEOUT:
#if (OS_CFG_TS_EN == DEF_ENABLED)
            if (p_ts != (CPU_TS *)0) {
                *p_ts = 0u;
            }
#endif
            OS_TRACE_SEM_PEND_FAILED(p_sem);
            //错误码设置为OS_ERR_TIMEOUT
            *p_err = OS_ERR_TIMEOUT;
            break;

        //PEND_TIMEOUT,删除了计数信号量
        case OS_STATUS_PEND_DEL:
#if (OS_CFG_TS_EN == DEF_ENABLED)
            if (p_ts != (CPU_TS *)0) {
                *p_ts = OSTCBCurPtr->TS;
            }
#endif
            OS_TRACE_SEM_PEND_FAILED(p_sem);
            //错误码设置为OS_ERR_OBJ_DEL
            *p_err = OS_ERR_OBJ_DEL;
            break;

        //非预期值
        default:
            OS_TRACE_SEM_PEND_FAILED(p_sem);
            //错误码设置为OS_ERR_STATUS_INVALID
            *p_err = OS_ERR_STATUS_INVALID;
            CPU_CRITICAL_EXIT();
            OS_TRACE_SEM_PEND_EXIT(*p_err);
            return (0u);
    }
    ctr = p_sem->Ctr;
    CPU_CRITICAL_EXIT();
    OS_TRACE_SEM_PEND_EXIT(*p_err);
    return (ctr);
}

CPU又重新执行此任务时,会有三种情况:条件满足、对计数信号量执行了Abort操作、删除了计数信号量。分别对这三种情况设置不同的错误码。

4. 计数信号量的Abort操作OSSemPendAbort

这个函数把因为这个计数信号量的Pend操作而被放入PendList中或者TickList中的任务,从PendList或者TickList中移除,重新的被放入ReadyList中(如果这个任务没有被suspended的话)。OS_OPT_PEND_ABORT_1值得是只对PendList中优先级最高的任务有效;OS_OPT_PEND_ABORT_ALL指的是对PendList中所有的任务都有效。

OSSemPendAbort的函数实现如下:

[os_sem.c OSSemPendAbort 函数]

OS_OBJ_QTY  OSSemPendAbort (OS_SEM  *p_sem,
                            OS_OPT   opt,
                            OS_ERR  *p_err)
{
    OS_PEND_LIST  *p_pend_list;
    OS_TCB        *p_tcb;
    CPU_TS         ts;
    OS_OBJ_QTY     nbr_tasks;
    CPU_SR_ALLOC();


#ifdef OS_SAFETY_CRITICAL
    //p_err入参合法性判断
    if (p_err == (OS_ERR *)0) {
        OS_SAFETY_CRITICAL_EXCEPTION();
        return (0u);
    }
#endif

#if (OS_CFG_CALLED_FROM_ISR_CHK_EN == DEF_ENABLED)
    //不能在中断处理函数中调用
    if (OSIntNestingCtr > 0u) {
        *p_err =  OS_ERR_PEND_ABORT_ISR;
        return (0u);
    }
#endif

#if (OS_CFG_INVALID_OS_CALLS_CHK_EN == DEF_ENABLED)
    //不能在内核运行前调用
    if (OSRunning != OS_STATE_OS_RUNNING) {
        *p_err = OS_ERR_OS_NOT_RUNNING;
        return (0u);
    }
#endif

#if (OS_CFG_ARG_CHK_EN == DEF_ENABLED)
    //p_sem入参合法性判断
    if (p_sem == (OS_SEM *)0) {
        *p_err =  OS_ERR_OBJ_PTR_NULL;
        return (0u);
    }

    //opt入参合法性判断
    switch (opt) {
        case OS_OPT_PEND_ABORT_1:
        case OS_OPT_PEND_ABORT_ALL:
        case OS_OPT_PEND_ABORT_1   | OS_OPT_POST_NO_SCHED:
        case OS_OPT_PEND_ABORT_ALL | OS_OPT_POST_NO_SCHED:
            break;

        default:
            *p_err =  OS_ERR_OPT_INVALID;
            return (0u);
    }
#endif

#if (OS_CFG_OBJ_TYPE_CHK_EN == DEF_ENABLED)
    //确保p_sem经过了create函数
    if (p_sem->Type != OS_OBJ_TYPE_SEM) {
    *p_err =  OS_ERR_OBJ_TYPE;
        return (0u);
    }
#endif

    CPU_CRITICAL_ENTER();
    p_pend_list = &p_sem->PendList;
    //如果PendList为空,直接返回
    if (p_pend_list->HeadPtr == (OS_TCB *)0) {
        CPU_CRITICAL_EXIT();
        *p_err =  OS_ERR_PEND_ABORT_NONE;
        return (0u);
    }

    nbr_tasks = 0u;
#if (OS_CFG_TS_EN == DEF_ENABLED)
    ts        = OS_TS_GET();
#else
    ts        = 0u;
#endif
    //遍历PendList中的每一个任务
    while (p_pend_list->HeadPtr != (OS_TCB *)0) {
        p_tcb = p_pend_list->HeadPtr;

        //将每一个任务都从PendList中移除
        //如果这个任务也处于TickList中,也将其移除
        //如果这个任务没有suspended,把他放入ReadyList中
        OS_PendAbort(p_tcb,
                    ts,
                    OS_STATUS_PEND_ABORT);
        nbr_tasks++;
        if (opt != OS_OPT_PEND_ABORT_ALL) {
            break;
        }
    }
    CPU_CRITICAL_EXIT();

    //如果没有特殊声明OS_OPT_POST_NO_SCHED
    if ((opt & OS_OPT_POST_NO_SCHED) == 0u) {
        //引发一次调度
        OSSched();
    }

    *p_err = OS_ERR_NONE;
    return (nbr_tasks);
}

这个函数不能在ISR中被调用,也不能在内核运行前被调用。遍历PendList,把其中每一个任务从PendList中移除,如果这个任务也存在于TickList中,也将其移除,如果这个任务没有被Suspended,那么再将他插入就绪列表ReadyList中。最后如果没有特殊声明OS_OPT_POST_NO_SCHED,那么将调用OSSched进行一次调度。

5. 计数信号量的Post操作OSSemPost

OSSemPost函数实现如下:

[os_sem.c OSSemPost 函数]

OS_SEM_CTR  OSSemPost (OS_SEM  *p_sem,
                    OS_OPT   opt,
                    OS_ERR  *p_err)
{
    OS_SEM_CTR     ctr;
    OS_PEND_LIST  *p_pend_list;
    OS_TCB        *p_tcb;
    OS_TCB        *p_tcb_next;
    CPU_TS         ts;
    CPU_SR_ALLOC();


#ifdef OS_SAFETY_CRITICAL
    //p_err入参合法性检查
    if (p_err == (OS_ERR *)0) {
        OS_SAFETY_CRITICAL_EXCEPTION();
        return (0u);
    }
#endif

    OS_TRACE_SEM_POST_ENTER(p_sem, opt);

#if (OS_CFG_INVALID_OS_CALLS_CHK_EN == DEF_ENABLED)
    //不能在内核运行前调用
    if (OSRunning != OS_STATE_OS_RUNNING) {
        OS_TRACE_SEM_POST_EXIT(OS_ERR_OS_NOT_RUNNING);
        *p_err = OS_ERR_OS_NOT_RUNNING;
        return (0u);
    }
#endif

#if (OS_CFG_ARG_CHK_EN == DEF_ENABLED)
    //p_sem入参合法性判断
    if (p_sem == (OS_SEM *)0) {
        OS_TRACE_SEM_POST_FAILED(p_sem);
        OS_TRACE_SEM_POST_EXIT(OS_ERR_OBJ_PTR_NULL);
        *p_err  = OS_ERR_OBJ_PTR_NULL;
        return (0u);
    }
    //opt合法性判断
    switch (opt) {
        case OS_OPT_POST_1:
        case OS_OPT_POST_ALL:
        case OS_OPT_POST_1   | OS_OPT_POST_NO_SCHED:
        case OS_OPT_POST_ALL | OS_OPT_POST_NO_SCHED:
            break;

        default:
            OS_TRACE_SEM_POST_FAILED(p_sem);
            OS_TRACE_SEM_POST_EXIT(OS_ERR_OPT_INVALID);
            *p_err =  OS_ERR_OPT_INVALID;
            return (0u);
    }
#endif

#if (OS_CFG_OBJ_TYPE_CHK_EN == DEF_ENABLED)
    //确保p_sem经过了create函数
    if (p_sem->Type != OS_OBJ_TYPE_SEM) {
        OS_TRACE_SEM_POST_FAILED(p_sem);
        OS_TRACE_SEM_POST_EXIT(OS_ERR_OBJ_TYPE);
        *p_err = OS_ERR_OBJ_TYPE;
        return (0u);
    }
#endif
#if (OS_CFG_TS_EN == DEF_ENABLED)
    ts = OS_TS_GET();
#else
    ts = 0u;
#endif

    OS_TRACE_SEM_POST(p_sem);
    CPU_CRITICAL_ENTER();
    p_pend_list = &p_sem->PendList;

    //如果PendList为空
    if (p_pend_list->HeadPtr == (OS_TCB *)0) {

        //如果Ctr为-1
        if (p_sem->Ctr == (OS_SEM_CTR)-1) {
            CPU_CRITICAL_EXIT();

            //设置错误码为OS_ERR_SEM_OVF
            *p_err = OS_ERR_SEM_OVF;
            OS_TRACE_SEM_POST_EXIT(*p_err);
            return (0u);
        }

        //增加一个计数信号量
        p_sem->Ctr++;
        ctr       = p_sem->Ctr;
#if (OS_CFG_TS_EN == DEF_ENABLED)
        p_sem->TS = ts;
#endif
        CPU_CRITICAL_EXIT();
        *p_err     = OS_ERR_NONE;
        OS_TRACE_SEM_POST_EXIT(*p_err);
        return (ctr);
    }

    p_tcb = p_pend_list->HeadPtr;

    //如果PendList不为空,遍历整个PendList
    while (p_tcb != (OS_TCB *)0) {

        p_tcb_next = p_tcb->PendNextPtr;

        //对任务调用OS_Post,将其从PendList中移除
        //如果他也处于TickList中,也将其移除
        //如果没有被Suspended,将其加入ReadyList
        OS_Post((OS_PEND_OBJ *)((void *)p_sem),
                p_tcb,
                (void *)0,
                0u,
                ts);

        //如果没有设置OS_OPT_POST_ALL
        //每一次Post操作只Post一个任务
        if ((opt & OS_OPT_POST_ALL) == 0u) {
            break;
        }
        p_tcb = p_tcb_next;
    }
    CPU_CRITICAL_EXIT();

    //如果没有特殊声明OS_OPT_POST_NO_SCHED
    if ((opt & OS_OPT_POST_NO_SCHED) == 0u) {

        //引发一次调度
        OSSched();
    }
    *p_err = OS_ERR_NONE;

    OS_TRACE_SEM_POST_EXIT(*p_err);
    return (0u);
}

如果PendList为空,则将Ctr加1。如果PendList不为空,再检查是否设置了OS_OPT_POST_ALL,如果设置了,就代表一次Post操作,就可以将所有PendList中的任务全部放入到ReadyList中(前提是这个任务没有被Suspended);如果没有设置OS_OPT_POST_ALL,那么每一次Post操作只能将一个任务移出PendList放入到ReadyList。最后如果没有特别声明OS_OPT_POST_NO_SCHED,就调用一次OSSched进行一次调度。

6. 设置计数信号量的个数OSSemSet

OSSemSet函数的实现如下:

[os_sem.c OSSemSet 函数]

void  OSSemSet (OS_SEM      *p_sem,
                OS_SEM_CTR   cnt,
                OS_ERR      *p_err)
{
    OS_PEND_LIST  *p_pend_list;
    CPU_SR_ALLOC();


#ifdef OS_SAFETY_CRITICAL
    //p_err入参合法性检查
    if (p_err == (OS_ERR *)0) {
        OS_SAFETY_CRITICAL_EXCEPTION();
        return;
    }
#endif

#if (OS_CFG_CALLED_FROM_ISR_CHK_EN == DEF_ENABLED)
    //不能在ISR中调用
    if (OSIntNestingCtr > 0u) {
        *p_err = OS_ERR_SET_ISR;
        return;
    }
#endif

#if (OS_CFG_ARG_CHK_EN == DEF_ENABLED)
    //p_sem入参合法性检查
    if (p_sem == (OS_SEM *)0) {
        *p_err = OS_ERR_OBJ_PTR_NULL;
        return;
    }
#endif

#if (OS_CFG_OBJ_TYPE_CHK_EN == DEF_ENABLED)
    //确保p_sem已经经过create函数
    if (p_sem->Type != OS_OBJ_TYPE_SEM) {
        *p_err = OS_ERR_OBJ_TYPE;
        return;
    }
#endif

    *p_err = OS_ERR_NONE;
    CPU_CRITICAL_ENTER();

    //如果Ctr > 0
    if (p_sem->Ctr > 0u) {

        //直接设置个数
        p_sem->Ctr = cnt;

    //如果Ctr <=0
    } else {
        p_pend_list = &p_sem->PendList;

        //如果PendList为空
        if (p_pend_list->HeadPtr == (OS_TCB *)0) {

            //直接设置个数
            p_sem->Ctr = cnt;

        //如果PendList不为空
        } else {
            //出错,返回错误码OS_ERR_TASK_WAITING
            *p_err      = OS_ERR_TASK_WAITING;
        }
    }
    CPU_CRITICAL_EXIT();
}

这个函数在不能在ISR中调用,也不能在PendList不为空时调用。一般用在给计数信号量设置一个初始值,或者重置信号量的值。不能把他当作Post一样的操作来用。

四. 互斥信号量Mutex

1. 创建互斥信号量OSMutexCreate

OSMutexCreate函数的实现如下:

[os_mutex.c OSMutexCreate 函数]

void  OSMutexCreate (OS_MUTEX  *p_mutex,
                    CPU_CHAR  *p_name,
                    OS_ERR    *p_err)
{
    CPU_SR_ALLOC();

#ifdef OS_SAFETY_CRITICAL
    //p_err的入参合法性检查
    if (p_err == (OS_ERR *)0) {
        OS_SAFETY_CRITICAL_EXCEPTION();
        return;
    }
#endif

#ifdef OS_SAFETY_CRITICAL_IEC61508
    if (OSSafetyCriticalStartFlag == DEF_TRUE) {
    *p_err = OS_ERR_ILLEGAL_CREATE_RUN_TIME;
        return;
    }
#endif

#if (OS_CFG_CALLED_FROM_ISR_CHK_EN == DEF_ENABLED)
    //不能在ISR中调用
    if (OSIntNestingCtr > 0u) {
    *p_err = OS_ERR_CREATE_ISR;
        return;
    }
#endif

#if (OS_CFG_ARG_CHK_EN == DEF_ENABLED)
    //p_mutex合法性检查
    if (p_mutex == (OS_MUTEX *)0) {
    *p_err = OS_ERR_OBJ_PTR_NULL;
        return;
    }
#endif

    CPU_CRITICAL_ENTER();
#if (OS_OBJ_TYPE_REQ == DEF_ENABLED)
    //初始化PendObj类型
    p_mutex->Type              =  OS_OBJ_TYPE_MUTEX;
#endif
#if (OS_CFG_DBG_EN == DEF_ENABLED)
    p_mutex->NamePtr           =  p_name;
#else
    (void)p_name;
#endif
    p_mutex->MutexGrpNextPtr   = (OS_MUTEX *)0;
    p_mutex->OwnerTCBPtr       = (OS_TCB   *)0;
    p_mutex->OwnerNestingCtr   =             0u;
#if (OS_CFG_TS_EN == DEF_ENABLED)
    p_mutex->TS                =             0u;
#endif
    //初始化PendList
    OS_PendListInit(&p_mutex->PendList);

#if (OS_CFG_DBG_EN == DEF_ENABLED)
    OS_MutexDbgListAdd(p_mutex);
    OSMutexQty++;
#endif

    OS_TRACE_MUTEX_CREATE(p_mutex, p_name);
    CPU_CRITICAL_EXIT();
    *p_err = OS_ERR_NONE;
}

这个函数不能在ISR中调用,主要初始化OS_SEM里的成员(名字,PendObj类型等),并初始化PendList

2. 删除互斥信号量OSMutexDel

OSMutexDel函数片段1:

[os_mutex.c OSMutexDel 函数片段1]

OS_OBJ_QTY  OSMutexDel (OS_MUTEX  *p_mutex,
                        OS_OPT     opt,
                        OS_ERR    *p_err)
{
    OS_OBJ_QTY     nbr_tasks;
    OS_PEND_LIST  *p_pend_list;
    OS_TCB        *p_tcb;
    OS_TCB        *p_tcb_owner;
    CPU_TS         ts;
#if (OS_CFG_MUTEX_EN == DEF_ENABLED)
    OS_PRIO        prio_new;
#endif
    CPU_SR_ALLOC();


#ifdef OS_SAFETY_CRITICAL
    //p_err入参合法性判断
    if (p_err == (OS_ERR *)0) {
        OS_SAFETY_CRITICAL_EXCEPTION();
        return (0u);
    }
#endif

    OS_TRACE_MUTEX_DEL_ENTER(p_mutex, opt);

#ifdef OS_SAFETY_CRITICAL_IEC61508
    if (OSSafetyCriticalStartFlag == DEF_TRUE) {
        OS_TRACE_MUTEX_DEL_EXIT(OS_ERR_ILLEGAL_DEL_RUN_TIME);
        *p_err = OS_ERR_ILLEGAL_DEL_RUN_TIME;
        return (0u);
    }
#endif

#if (OS_CFG_CALLED_FROM_ISR_CHK_EN == DEF_ENABLED)
    //不准在ISR中调用
    if (OSIntNestingCtr > 0u) {
        OS_TRACE_MUTEX_DEL_EXIT(OS_ERR_DEL_ISR);
        *p_err = OS_ERR_DEL_ISR;
        return (0u);
    }
#endif

#if (OS_CFG_INVALID_OS_CALLS_CHK_EN == DEF_ENABLED)
    //不能在内核运行前调用
    if (OSRunning != OS_STATE_OS_RUNNING) {
        OS_TRACE_MUTEX_DEL_EXIT(OS_ERR_OS_NOT_RUNNING);
        *p_err = OS_ERR_OS_NOT_RUNNING;
        return (0u);
    }
#endif

#if (OS_CFG_ARG_CHK_EN == DEF_ENABLED)
    //p_mutex入参合法性判断
    if (p_mutex == (OS_MUTEX *)0) {
        OS_TRACE_MUTEX_DEL_EXIT(OS_ERR_OBJ_PTR_NULL);
        *p_err = OS_ERR_OBJ_PTR_NULL;
        return (0u);
    }
#endif

#if (OS_CFG_OBJ_TYPE_CHK_EN == DEF_ENABLED)
    //确保p_mutex已经经过create函数
    if (p_mutex->Type != OS_OBJ_TYPE_MUTEX) {
        OS_TRACE_MUTEX_DEL_EXIT(OS_ERR_OBJ_TYPE);
        *p_err = OS_ERR_OBJ_TYPE;
        return (0u);
    }
#endif

函数片段1规定这个函数不能在ISR中调用,不能在内核运行前调用,并做了一些入参的合法性判断。

[os_mutex.c OSMutexDel 函数片段2]

    CPU_CRITICAL_ENTER();
    p_pend_list = &p_mutex->PendList;
    nbr_tasks   = 0u;
    switch (opt) {

        //只有当PendList中没有任务的时候才删除
        case OS_OPT_DEL_NO_PEND:
            //如果PendList中没有任务
            if (p_pend_list->HeadPtr == (OS_TCB *)0) {
#if (OS_CFG_DBG_EN == DEF_ENABLED)
                OS_MutexDbgListRemove(p_mutex);
                OSMutexQty--;
#endif
                OS_TRACE_MUTEX_DEL(p_mutex);
                //如果这个Mutex属于某个任务
                if (p_mutex->OwnerTCBPtr != (OS_TCB *)0) {
                    //把这个Mutex从这个任务的MutexGroup中移除
                    OS_MutexGrpRemove(p_mutex->OwnerTCBPtr, p_mutex);
                }
                //调用OS_MutexClr,初始化Mutex内部的成员变量和PendList
                OS_MutexClr(p_mutex);
                CPU_CRITICAL_EXIT();
                *p_err = OS_ERR_NONE;

            //如果PendList中有任务
            } else {
                CPU_CRITICAL_EXIT();

                //设置错误码为OS_ERR_TASK_WAITING
                *p_err = OS_ERR_TASK_WAITING;
            }
            break;

        //不管PendList是否为空,都删除
        case OS_OPT_DEL_ALWAYS:
#if (OS_CFG_TS_EN == DEF_ENABLED)
            ts = OS_TS_GET();
#else
            ts = 0u;
#endif
            //遍历PendList中的每一个任务
            while (p_pend_list->HeadPtr != (OS_TCB *)0) {
                p_tcb = p_pend_list->HeadPtr;
                //把这些任务从PendList或者TickList中移除
                //如果这些任务没有suspended,加入ReadyList
                OS_PendAbort(p_tcb,
                            ts,
                            OS_STATUS_PEND_DEL);
                nbr_tasks++;
            }
#if (OS_CFG_DBG_EN == DEF_ENABLED)
            OS_MutexDbgListRemove(p_mutex);
            OSMutexQty--;
#endif
            OS_TRACE_MUTEX_DEL(p_mutex);
            //这个Mutex的所有者
            p_tcb_owner = p_mutex->OwnerTCBPtr;
            if (p_tcb_owner != (OS_TCB *)0) {
                //把这个Mutex从其所有者的MutexGroup中移除
                OS_MutexGrpRemove(p_tcb_owner, p_mutex);
            }

            //因为这个Mutex被删除之后,这个任务就相当于获取到了这个Mutex(不是阻塞状态了)
            //那么就应该把这个任务的优先级设置为,
            //在这个任务的MutexGrop中的所有Mutex的PendList中的所有任务的最高优先级
            if (p_tcb_owner != (OS_TCB *)0) {
                if (p_tcb_owner->Prio != p_tcb_owner->BasePrio) {
                    prio_new = OS_MutexGrpPrioFindHighest(p_tcb_owner);
                    prio_new = (prio_new > p_tcb_owner->BasePrio) ? p_tcb_owner->BasePrio : prio_new;
                    OS_TaskChangePrio(p_tcb_owner, prio_new);
                    OS_TRACE_MUTEX_TASK_PRIO_DISINHERIT(p_tcb_owner, p_tcb_owner->Prio);
                }
            }

            //调用OS_MutexClr清除Mutex的成员变量,初始化PendList
            OS_MutexClr(p_mutex);
            CPU_CRITICAL_EXIT();

            //调用OSSched,引发一次调度
            OSSched();
            *p_err = OS_ERR_NONE;
            break;

        default:
            CPU_CRITICAL_EXIT();
            *p_err = OS_ERR_OPT_INVALID;
            break;
    }
    OS_TRACE_MUTEX_DEL_EXIT(*p_err);
    return (nbr_tasks);
}

上面的代码片段2可以总结为:

  1. OS_OPT_DEL_NO_PEND意思只有PendList中没有任务的话才删除。如果这个Mutex被一个任务所拥有,先把这个Mutex从其拥有着的MutexGroup中移除。调用OS_MutexClr清除Mutex的成员变量,初始化PendList
  2. OS_OPT_DEL_ALWAYS指的是不管PendList中有没有任务都删除。先遍历PendList中的每一个任务,调用OS_PendAbort把这些任务都从PendList中移除,如果他们处于TickList中,再把他们从TickList中移除。最后如果没有被suspended的话,把他们放入ReadyList中。如果这个Mutex被一个人任务所拥有,先把这个Mutex从其所有的任务的MutexGroup中移除,再把这个任务的优先级设置到其MutexGroup中的所有PendList中的任务的最高优先级,来防止优先级反转的问题。然后调用OS_MutexClr清除Mutex的成员变量,初始化PendList。最后,调用OSSched引发一次调度。

3. 互斥信号量的Pend操作OSMutexPend

OSMutexPend的代码片段1:

[os_mutex.c OSMutexPend 函数片段1]

void  OSMutexPend (OS_MUTEX  *p_mutex,
                OS_TICK    timeout,
                OS_OPT     opt,
                CPU_TS    *p_ts,
                OS_ERR    *p_err)
{
    OS_TCB  *p_tcb;
    CPU_SR_ALLOC();


#if (OS_CFG_TS_EN == DEF_DISABLED)
    (void)p_ts;
#endif

#ifdef OS_SAFETY_CRITICAL
    //p_err入参合法性判断
    if (p_err == (OS_ERR *)0) {
        OS_SAFETY_CRITICAL_EXCEPTION();
        return;
    }
#endif

    OS_TRACE_MUTEX_PEND_ENTER(p_mutex, timeout, opt, p_ts);

#if (OS_CFG_CALLED_FROM_ISR_CHK_EN == DEF_ENABLED)
    //不能在ISR中调用
    if (OSIntNestingCtr > 0u) {
        OS_TRACE_MUTEX_PEND_FAILED(p_mutex);
        OS_TRACE_MUTEX_PEND_EXIT(OS_ERR_PEND_ISR);
        *p_err = OS_ERR_PEND_ISR;
        return;
    }
#endif

#if (OS_CFG_INVALID_OS_CALLS_CHK_EN == DEF_ENABLED)
    //内核运行前不能调用
    if (OSRunning != OS_STATE_OS_RUNNING) {
        OS_TRACE_MUTEX_PEND_EXIT(OS_ERR_OS_NOT_RUNNING);
        *p_err = OS_ERR_OS_NOT_RUNNING;
        return;
    }
#endif

#if (OS_CFG_ARG_CHK_EN == DEF_ENABLED)
    //p_mutex入参合法性判断
    if (p_mutex == (OS_MUTEX *)0) {
        OS_TRACE_MUTEX_PEND_FAILED(p_mutex);
        OS_TRACE_MUTEX_PEND_EXIT(OS_ERR_OBJ_PTR_NULL);
        *p_err = OS_ERR_OBJ_PTR_NULL;
        return;
    }
    //opt入参合法性判断
    switch (opt) {
        case OS_OPT_PEND_BLOCKING:
        case OS_OPT_PEND_NON_BLOCKING:
            break;

        default:
            OS_TRACE_MUTEX_PEND_FAILED(p_mutex);
            OS_TRACE_MUTEX_PEND_EXIT(OS_ERR_OPT_INVALID);
            *p_err = OS_ERR_OPT_INVALID;
            return;
    }
#endif

#if (OS_CFG_OBJ_TYPE_CHK_EN == DEF_ENABLED)
    //确保p_mutex经过了create函数
    if (p_mutex->Type != OS_OBJ_TYPE_MUTEX) {
        OS_TRACE_MUTEX_PEND_FAILED(p_mutex);
        OS_TRACE_MUTEX_PEND_EXIT(OS_ERR_OBJ_TYPE);
        *p_err = OS_ERR_OBJ_TYPE;
        return;
    }
#endif

代码片段1做了规定这个函数不能在ISR中调用,不能在内核运行前调用,并做了一些入参合法性的判断。

[os_mutex.c OSMutexPend 函数片段2]

    CPU_CRITICAL_ENTER();
    //如果这个mutex不属于任何任务
    if (p_mutex->OwnerNestingCtr == 0u) {
        //设置这个mutex属于当前任务
        p_mutex->OwnerTCBPtr     = OSTCBCurPtr;
        //设置OwnerNestingCtr为1
        p_mutex->OwnerNestingCtr = 1u;
#if (OS_CFG_TS_EN == DEF_ENABLED)
        if (p_ts != (CPU_TS *)0) {
        *p_ts = p_mutex->TS;
        }
#endif

        //把这个mutex插入到当前任务的MutexGroup列表的最前面
        OS_MutexGrpAdd(OSTCBCurPtr, p_mutex);

        CPU_CRITICAL_EXIT();
        OS_TRACE_MUTEX_PEND(p_mutex);
        OS_TRACE_MUTEX_PEND_EXIT(OS_ERR_NONE);
        //获取锁,设置错误码为OS_ERR_NONE
        *p_err = OS_ERR_NONE;
        //返回
        return;
    }

    //如果这个mutex属于当前任务
    if (OSTCBCurPtr == p_mutex->OwnerTCBPtr) {

        //如果OwnerNestingCtr为-1说明没有Pend就做了Post操作
        if (p_mutex->OwnerNestingCtr == (OS_NESTING_CTR)-1) {
            CPU_CRITICAL_EXIT();
            OS_TRACE_MUTEX_PEND_FAILED(p_mutex);
            OS_TRACE_MUTEX_PEND_EXIT(OS_ERR_MUTEX_OVF);
            //错误码设为OS_ERR_MUTEX_OVF
            *p_err = OS_ERR_MUTEX_OVF;
            return;
        }

        //当前任务对这个Mutex的Pend嵌套操作,把OwnerNestingCtr++
        p_mutex->OwnerNestingCtr++;
#if (OS_CFG_TS_EN == DEF_ENABLED)
        if (p_ts != (CPU_TS *)0) {
            *p_ts = p_mutex->TS;
        }
#endif
        CPU_CRITICAL_EXIT();
        OS_TRACE_MUTEX_PEND_FAILED(p_mutex);
        OS_TRACE_MUTEX_PEND_EXIT(OS_ERR_MUTEX_OWNER);
        //设置错误码为OS_ERR_MUTEX_OWNER
        *p_err = OS_ERR_MUTEX_OWNER;
        //返回出去
        return;
    }

    //这里以下是没有拿到Mutex

    //如果是非阻塞
    if ((opt & OS_OPT_PEND_NON_BLOCKING) != 0u) {
        CPU_CRITICAL_EXIT();
#if (OS_CFG_TS_EN == DEF_ENABLED)
        if (p_ts != (CPU_TS *)0) {
        *p_ts = 0u;
        }
#endif
        OS_TRACE_MUTEX_PEND_FAILED(p_mutex);
        OS_TRACE_MUTEX_PEND_EXIT(OS_ERR_PEND_WOULD_BLOCK);
        //设置错误码为OS_ERR_PEND_WOULD_BLOCK
        *p_err = OS_ERR_PEND_WOULD_BLOCK;
        //返回出去
        return;

    //如果是阻塞
    } else {
        //如果锁住了调度器
        if (OSSchedLockNestingCtr > 0u) {
            CPU_CRITICAL_EXIT();
#if (OS_CFG_TS_EN == DEF_ENABLED)
            if (p_ts != (CPU_TS *)0) {
            *p_ts = 0u;
            }
#endif
            OS_TRACE_MUTEX_PEND_FAILED(p_mutex);
            OS_TRACE_MUTEX_PEND_EXIT(OS_ERR_SCHED_LOCKED);
            //错误码设置为OS_ERR_SCHED_LOCKED
            *p_err = OS_ERR_SCHED_LOCKED;
            //返回
            return;
        }
    }

    //下面是没有拿到Mutex,而且是阻塞模式,调度器没上锁

    p_tcb = p_mutex->OwnerTCBPtr;
    //解决优先级反转的问题
    //如果等待Mutex的任务的优先级比拥有Mutex任务的优先级高
    if (p_tcb->Prio > OSTCBCurPtr->Prio) {
        //那么把拥有Mutex的任务的优先级提升至和等待Mutex的任务的优先级一样
        OS_TaskChangePrio(p_tcb, OSTCBCurPtr->Prio);
        OS_TRACE_MUTEX_TASK_PRIO_INHERIT(p_tcb, p_tcb->Prio);
    }

    //没有拿到Mutex,阻塞模式,调度器没上锁
    //调用OS_Pend,把当前任务从ReadyList中移除,
    //加入到PendList中,如果TimeOut不为0,再加入到TickList中
    OS_Pend((OS_PEND_OBJ *)((void *)p_mutex),
            OS_TASK_PEND_ON_MUTEX,
            timeout);

    CPU_CRITICAL_EXIT();
    OS_TRACE_MUTEX_PEND_BLOCK(p_mutex);

    //引发一次调度
    OSSched();

上面的代码片段2可以总结为如下:

  1. 任务拿到了Mutex。把Mutex的拥有着设置为这个任务,这个MutexOwnerNestingCtr设置为1,并把这个Mutex插入到这个任务的MutexGroup链表的头部,然后直接返回出去。
  2. 如果任务没有拿到Mutex。如果是非阻塞状态,设置好错误码之后就返回出去,如果是阻塞状态,看调度器是否是锁住的,如果是锁着的,设置好错误码返回。如果没锁住,解决优先级反转的问题,然后调用OS_Pend把当前任务从ReadyList中移除,加入到PendList中,如果TimeOut不为0,再加入到TickList中。
  3. 最后调用OSSched引发一次调度。

等到函数继续向下进行时,说明这个任务已经拿到了这个Mutex,或者因为其他原因这个任务被放入到了就绪列表中:

[os_mutex.c OSMutexPend 函数片段3]

    CPU_CRITICAL_ENTER();

    //判断任务又重新运行的原因
    switch (OSTCBCurPtr->PendStatus) {

        //获取到了Mutex
        case OS_STATUS_PEND_OK:
#if (OS_CFG_TS_EN == DEF_ENABLED)
            if (p_ts != (CPU_TS *)0) {
                *p_ts = OSTCBCurPtr->TS;
            }
#endif
            OS_TRACE_MUTEX_PEND(p_mutex);
            *p_err = OS_ERR_NONE;
            break;

        //因为Abort操作
        case OS_STATUS_PEND_ABORT:
#if (OS_CFG_TS_EN == DEF_ENABLED)
            if (p_ts != (CPU_TS *)0) {
                *p_ts = OSTCBCurPtr->TS;
            }
#endif
            OS_TRACE_MUTEX_PEND_FAILED(p_mutex);
            *p_err = OS_ERR_PEND_ABORT;
            break;

        //因为超时
        case OS_STATUS_PEND_TIMEOUT:
#if (OS_CFG_TS_EN == DEF_ENABLED)
            if (p_ts != (CPU_TS *)0) {
                *p_ts = 0u;
            }
#endif
            OS_TRACE_MUTEX_PEND_FAILED(p_mutex);
            *p_err = OS_ERR_TIMEOUT;
            break;

        //因为Mutex被删除
        case OS_STATUS_PEND_DEL:
#if (OS_CFG_TS_EN == DEF_ENABLED)
            if (p_ts != (CPU_TS *)0) {
                *p_ts = OSTCBCurPtr->TS;
            }
#endif
            OS_TRACE_MUTEX_PEND_FAILED(p_mutex);
            *p_err = OS_ERR_OBJ_DEL;
            break;

        default:
            OS_TRACE_MUTEX_PEND_FAILED(p_mutex);
            *p_err = OS_ERR_STATUS_INVALID;
            break;
    }

    CPU_CRITICAL_EXIT();
    OS_TRACE_MUTEX_PEND_EXIT(*p_err);
}

根据不同的原因设置好不同的错误码,返回出去。

4. 互斥信号量的PendAbort操作OSMutexPendAbort

这个函数把因为这个互斥信号量的Pend操作而被放入PendList中或者TickList中的任务,从PendList或者TickList中移除,重新的被放入ReadyList中(如果这个任务没有被suspended的话)。OS_OPT_PEND_ABORT_1值得是只对PendList中优先级最高的任务有效;OS_OPT_PEND_ABORT_ALL指的是对PendList中所有的任务都有效。

OSMutexPendAbort函数实现如下:

OS_OBJ_QTY  OSMutexPendAbort (OS_MUTEX  *p_mutex,
                            OS_OPT     opt,
                            OS_ERR    *p_err)
{
    OS_PEND_LIST  *p_pend_list;
    OS_TCB        *p_tcb;
    OS_TCB        *p_tcb_owner;
    CPU_TS         ts;
    OS_OBJ_QTY     nbr_tasks;
    OS_PRIO        prio_new;
    CPU_SR_ALLOC();


#ifdef OS_SAFETY_CRITICAL
    //p_err的入参合法性判断
    if (p_err == (OS_ERR *)0) {
        OS_SAFETY_CRITICAL_EXCEPTION();
        return ((OS_OBJ_QTY)0u);
    }
#endif

#if (OS_CFG_CALLED_FROM_ISR_CHK_EN == DEF_ENABLED)
    //不能在ISR中调用
    if (OSIntNestingCtr > 0u) {
        *p_err =  OS_ERR_PEND_ABORT_ISR;
        return (0u);
    }
#endif

#if (OS_CFG_INVALID_OS_CALLS_CHK_EN == DEF_ENABLED)
    //不能在内核运行前调用
    if (OSRunning != OS_STATE_OS_RUNNING) {
        *p_err = OS_ERR_OS_NOT_RUNNING;
        return (0u);
    }
#endif

#if (OS_CFG_ARG_CHK_EN == DEF_ENABLED)
    //p_mutex入参的合法性判断
    if (p_mutex == (OS_MUTEX *)0) {
        *p_err =  OS_ERR_OBJ_PTR_NULL;
        return (0u);
    }
    //opt的入参合法性判断
    switch (opt) {
        case OS_OPT_PEND_ABORT_1:
        case OS_OPT_PEND_ABORT_ALL:
        case OS_OPT_PEND_ABORT_1   | OS_OPT_POST_NO_SCHED:
        case OS_OPT_PEND_ABORT_ALL | OS_OPT_POST_NO_SCHED:
            break;

        default:
            *p_err =  OS_ERR_OPT_INVALID;
            return (0u);
    }
#endif

#if (OS_CFG_OBJ_TYPE_CHK_EN == DEF_ENABLED)
    //确保p_mutex经过了Create函数
    if (p_mutex->Type != OS_OBJ_TYPE_MUTEX) {
    *p_err =  OS_ERR_OBJ_TYPE;
        return (0u);
    }
#endif

    CPU_CRITICAL_ENTER();
    p_pend_list = &p_mutex->PendList;
    //如果其PendList为空
    if (p_pend_list->HeadPtr == (OS_TCB *)0) {
        CPU_CRITICAL_EXIT();
        //设置好错误码,直接返回
        *p_err =  OS_ERR_PEND_ABORT_NONE;
        return (0u);
    }

    nbr_tasks = 0u;
#if (OS_CFG_TS_EN == DEF_ENABLED)
    ts        = OS_TS_GET();
#else
    ts        = 0u;
#endif
    //遍历整个PendList
    while (p_pend_list->HeadPtr != (OS_TCB *)0) {
        p_tcb = p_pend_list->HeadPtr;

        //对每一个任务都调用OS_PendAbort
        //将这个任务从其
        OS_PendAbort(p_tcb,
                    ts,
                    OS_STATUS_PEND_ABORT);
        p_tcb_owner = p_mutex->OwnerTCBPtr;
        prio_new    = p_tcb_owner->Prio;

        //如果这个Mutex的所属者的优先级被提升过,
        //而且和这个任务的优先级相同(这个任务的优先级在这个PendList中最高)
        //又因为这个任务被从这个PendList中移除了,
        //所以得从其拥有着的MutexGroup中所有的PendList中另寻最高优先级
        if ((p_tcb_owner->Prio != p_tcb_owner->BasePrio) &&
            (p_tcb_owner->Prio == p_tcb->Prio)) {
            //另寻最高优先级
            prio_new = OS_MutexGrpPrioFindHighest(p_tcb_owner);
            prio_new = (prio_new > p_tcb_owner->BasePrio) ? p_tcb_owner->BasePrio : prio_new;
        }

        //如果另寻的最高优先级不跟其拥有着的优先级相同
        if(prio_new != p_tcb_owner->Prio) {
            //更改其拥有者的优先级
            OS_TaskChangePrio(p_tcb_owner, prio_new);
            OS_TRACE_MUTEX_TASK_PRIO_DISINHERIT(p_tcb_owner, p_tcb_owner->Prio);
        }

        nbr_tasks++;
        if (opt != OS_OPT_PEND_ABORT_ALL) {
            break;
        }
    }
    CPU_CRITICAL_EXIT();

    //如果没有特殊设置OS_OPT_POST_NO_SCHED
    if ((opt & OS_OPT_POST_NO_SCHED) == 0u) {
        //引发一次调度
        OSSched();
    }

*p_err = OS_ERR_NONE;
    return (nbr_tasks);
}

5. 互斥信号量的Post操作OSMutexPost

OSMutexPost函数代码片段1:

[os_mutex.c OSMutexPost 函数代码片段1 ]

void  OSMutexPost (OS_MUTEX  *p_mutex,
                OS_OPT     opt,
                OS_ERR    *p_err)
{
    OS_PEND_LIST  *p_pend_list;
    OS_TCB        *p_tcb;
    CPU_TS         ts;
    OS_PRIO        prio_new;
    CPU_SR_ALLOC();


#ifdef OS_SAFETY_CRITICAL
    //p_err的合法性判断
    if (p_err == (OS_ERR *)0) {
        OS_SAFETY_CRITICAL_EXCEPTION();
        return;
    }
#endif

    OS_TRACE_MUTEX_POST_ENTER(p_mutex, opt);

#if (OS_CFG_CALLED_FROM_ISR_CHK_EN == DEF_ENABLED)
    //不能在ISR中调用
    if (OSIntNestingCtr > 0u) {
        OS_TRACE_MUTEX_POST_FAILED(p_mutex);
        OS_TRACE_MUTEX_POST_EXIT(OS_ERR_POST_ISR);
        *p_err = OS_ERR_POST_ISR;
        return;
    }
#endif

#if (OS_CFG_INVALID_OS_CALLS_CHK_EN == DEF_ENABLED)
    //不能在内核运行前调用
    if (OSRunning != OS_STATE_OS_RUNNING) {
        OS_TRACE_MUTEX_POST_EXIT(OS_ERR_OS_NOT_RUNNING);
        *p_err = OS_ERR_OS_NOT_RUNNING;
        return;
    }
#endif

#if (OS_CFG_ARG_CHK_EN == DEF_ENABLED)
    //p_mutex入参的合法性判断
    if (p_mutex == (OS_MUTEX *)0) {
        OS_TRACE_MUTEX_POST_FAILED(p_mutex);
        OS_TRACE_MUTEX_POST_EXIT(OS_ERR_OBJ_PTR_NULL);
        *p_err = OS_ERR_OBJ_PTR_NULL;
        return;
    }
    //opt入参的合法性判断
    switch (opt) {
        case OS_OPT_POST_NONE:
        case OS_OPT_POST_NO_SCHED:
            break;

        default:
            OS_TRACE_MUTEX_POST_FAILED(p_mutex);
            OS_TRACE_MUTEX_POST_EXIT(OS_ERR_OPT_INVALID);
            *p_err =  OS_ERR_OPT_INVALID;
            return;
    }
#endif

#if (OS_CFG_OBJ_TYPE_CHK_EN == DEF_ENABLED)
    //确保p_mutex已经经过了create函数
    if (p_mutex->Type != OS_OBJ_TYPE_MUTEX) {
        OS_TRACE_MUTEX_POST_FAILED(p_mutex);
        OS_TRACE_MUTEX_POST_EXIT(OS_ERR_OBJ_TYPE);
        *p_err = OS_ERR_OBJ_TYPE;
        return;
    }
#endif

    CPU_CRITICAL_ENTER();

函数代码片段1规定这个函数不能在ISR中使用,不能在内核运行前使用。并做了入参的合法性判断。

[os_mutex.c OSMutexPost 函数代码片段2 ]

    //如果Post操作的任务不是Mutex的拥有者,肯定是错误的
    if (OSTCBCurPtr != p_mutex->OwnerTCBPtr) {
        CPU_CRITICAL_EXIT();
        OS_TRACE_MUTEX_POST_FAILED(p_mutex);
        OS_TRACE_MUTEX_POST_EXIT(OS_ERR_MUTEX_NOT_OWNER);
        //设置错误码为OS_ERR_MUTEX_NOT_OWNER
        *p_err = OS_ERR_MUTEX_NOT_OWNER;
        //返回
        return;
    }

    OS_TRACE_MUTEX_POST(p_mutex);

#if (OS_CFG_TS_EN == DEF_ENABLED)
    ts          = OS_TS_GET();
    p_mutex->TS = ts;
#else
    ts          = 0u;
#endif
    //把OwnerNestingCtr做自减操作
    p_mutex->OwnerNestingCtr--;

    //如果OwnerNestingCtr还大于0,说明Mutex出与嵌套操作中
    if (p_mutex->OwnerNestingCtr > 0u) {
        CPU_CRITICAL_EXIT();
        OS_TRACE_MUTEX_POST_EXIT(OS_ERR_MUTEX_NESTING);
        //设置错误码为OS_ERR_MUTEX_NESTING
        *p_err = OS_ERR_MUTEX_NESTING;
        //返回
        return;
    }

    //把这个Mutex从当前任务的MutexGroup中移除
    OS_MutexGrpRemove(OSTCBCurPtr, p_mutex);

    p_pend_list = &p_mutex->PendList;
    //如果PendList中没任务
    if (p_pend_list->HeadPtr == (OS_TCB *)0) {
        //嵌套次数和拥有者的值都清0,代表没有嵌套次数,没有拥有者
        p_mutex->OwnerTCBPtr     = (OS_TCB *)0;
        p_mutex->OwnerNestingCtr =           0u;
        CPU_CRITICAL_EXIT();
        OS_TRACE_MUTEX_POST_EXIT(OS_ERR_NONE);

        //设置错误码并返回
        *p_err = OS_ERR_NONE;
        return;
    }

    //下面是如果PendList中有任务

    //如果当前任务的优先级被提升过
    //而且,当前任务的MutexGroup变动过,
    //所以得从其新的MutexGroup中需要寻找最新的最高优先级
    if (OSTCBCurPtr->Prio != OSTCBCurPtr->BasePrio) {
        //新的优先级
        prio_new = OS_MutexGrpPrioFindHighest(OSTCBCurPtr);

        //新的优先级和基础优先级,取优先级最高的
        //注意,Prio的值越高,优先级越低
        prio_new = (prio_new > OSTCBCurPtr->BasePrio) ? OSTCBCurPtr->BasePrio : prio_new;

        //如果新算出来的优先级小于原来的优先级
        if (prio_new > OSTCBCurPtr->Prio) {
            //先把这个任务从ReadyList中移出来
            OS_RdyListRemove(OSTCBCurPtr);
            //再更改优先级
            OSTCBCurPtr->Prio = prio_new;
            OS_TRACE_MUTEX_TASK_PRIO_DISINHERIT(OSTCBCurPtr, prio_new);
            //更改后再插入到ReadyList中,插入到新优先级任务列表的尾部
            OS_PrioInsert(prio_new);
            OS_RdyListInsertTail(OSTCBCurPtr);
            OSPrioCur         = prio_new;
        }
    }

    //寻找Mutex中PendList的下一个任务,把他当作Mutex的拥有者
    p_tcb                    = p_pend_list->HeadPtr;
    p_mutex->OwnerTCBPtr     = p_tcb;
    p_mutex->OwnerNestingCtr = 1u;

    //把Mutex加入到拥有者的PendList中
    OS_MutexGrpAdd(p_tcb, p_mutex);

    //调用OS_Post,把其拥有者从PendList(TickList)中移除
    //再把他加入ReadyList
    OS_Post((OS_PEND_OBJ *)((void *)p_mutex),
                        p_tcb,
                        (void *)0,
                        0u,
                        ts);

    CPU_CRITICAL_EXIT();

    //如果没有特别声明OS_OPT_POST_NO_SCHED
    if ((opt & OS_OPT_POST_NO_SCHED) == 0u) {
        //引发一次调度
        OSSched();
    }
    OS_TRACE_MUTEX_POST_EXIT(OS_ERR_NONE);
    *p_err = OS_ERR_NONE;
}

这段代码解释了OSMutexPost真正做的事情,一个是因为优先级反转问题的处理,一个是释放这个Mutex,为其找到新的拥有者。并把拥有者从PendList(也可能有TickList)中移除,如果没有被suspended的话放入ReadyList中,这里需要注意,如果一个任务拿到了一个Mutex,但是他却被suspended了,那么其他等待这个Mutex的任务将都得不到运行。

五. 消息队列OS_Q

μC/OS III 中有一个消息池OSMsgPool,用来暂存消息。他是一个单向不循环列表。

1. 创建消息队列OSQCreate

OSQCreate函数实现如下:

[os_q.c OSQCreate 函数]

void  OSQCreate (OS_Q        *p_q,
                CPU_CHAR    *p_name,
                OS_MSG_QTY   max_qty,
                OS_ERR      *p_err)

{
    CPU_SR_ALLOC();


#ifdef OS_SAFETY_CRITICAL
    //p_err入参判断
    if (p_err == (OS_ERR *)0) {
        OS_SAFETY_CRITICAL_EXCEPTION();
        return;
    }
#endif

#ifdef OS_SAFETY_CRITICAL_IEC61508
    if (OSSafetyCriticalStartFlag == DEF_TRUE) {
        *p_err = OS_ERR_ILLEGAL_CREATE_RUN_TIME;
        return;
    }
#endif

#if (OS_CFG_CALLED_FROM_ISR_CHK_EN == DEF_ENABLED)
    //不能在ISR中调用
    if (OSIntNestingCtr > 0u) {
        *p_err = OS_ERR_CREATE_ISR;
        return;
    }
#endif

#if (OS_CFG_ARG_CHK_EN == DEF_ENABLED)
    //p_q入参合法性判断
    if (p_q == (OS_Q *)0) {
        *p_err = OS_ERR_OBJ_PTR_NULL;
        return;
    }
    if (max_qty == 0u) {
        *p_err = OS_ERR_Q_SIZE;
        return;
    }
#endif

    CPU_CRITICAL_ENTER();
#if (OS_OBJ_TYPE_REQ == DEF_ENABLED)
    p_q->Type    = OS_OBJ_TYPE_Q;
#endif
#if (OS_CFG_DBG_EN == DEF_ENABLED)
    p_q->NamePtr = p_name;
#else
    (void)p_name;
#endif
    //初始化消息队列OS_MSG_Q
    OS_MsgQInit(&p_q->MsgQ,
                max_qty);
    //初始化消息队列中的PendList
    OS_PendListInit(&p_q->PendList);

#if (OS_CFG_DBG_EN == DEF_ENABLED)
    OS_QDbgListAdd(p_q);
    OSQQty++;
#endif

    OS_TRACE_Q_CREATE(p_q, p_name);
    CPU_CRITICAL_EXIT();
    *p_err = OS_ERR_NONE;
}

这个函数不能在ISR中调用,将Type设置为OS_OBJ_TYPE_Q,初始化消息队列和PendList

2. 删除消息队列OSQDel

OSQDel函数实现如下:

[os_q.c OSQDel 函数]

OS_OBJ_QTY  OSQDel (OS_Q    *p_q,
                    OS_OPT   opt,
                    OS_ERR  *p_err)
{
    OS_OBJ_QTY     nbr_tasks;
    OS_PEND_LIST  *p_pend_list;
    OS_TCB        *p_tcb;
    CPU_TS         ts;
    CPU_SR_ALLOC();


#ifdef OS_SAFETY_CRITICAL
    //p_err入参合法性判断
    if (p_err == (OS_ERR *)0) {
        OS_SAFETY_CRITICAL_EXCEPTION();
        return (0u);
    }
#endif

    OS_TRACE_Q_DEL_ENTER(p_q, opt);

#ifdef OS_SAFETY_CRITICAL_IEC61508
    if (OSSafetyCriticalStartFlag == DEF_TRUE) {
        OS_TRACE_Q_DEL_EXIT(OS_ERR_ILLEGAL_DEL_RUN_TIME);
        *p_err = OS_ERR_ILLEGAL_DEL_RUN_TIME;
        return (0u);
    }
#endif

#if (OS_CFG_CALLED_FROM_ISR_CHK_EN == DEF_ENABLED)
    //不能在`ISR`中使用
    if (OSIntNestingCtr > 0u) {
        OS_TRACE_Q_DEL_EXIT(OS_ERR_DEL_ISR);
        *p_err = OS_ERR_DEL_ISR;
        return (0u);
    }
#endif

#if (OS_CFG_INVALID_OS_CALLS_CHK_EN == DEF_ENABLED)
    //不能在内核运行前使用
    if (OSRunning != OS_STATE_OS_RUNNING) {
        OS_TRACE_Q_DEL_EXIT(OS_ERR_OS_NOT_RUNNING);
        *p_err = OS_ERR_OS_NOT_RUNNING;
        return (0u);
    }
#endif

#if (OS_CFG_ARG_CHK_EN == DEF_ENABLED)
    //p_q入参合法性判断
    if (p_q == (OS_Q *)0) {
        OS_TRACE_Q_DEL_EXIT(OS_ERR_OBJ_PTR_NULL);
        *p_err =  OS_ERR_OBJ_PTR_NULL;
        return (0u);
    }
#endif

#if (OS_CFG_OBJ_TYPE_CHK_EN == DEF_ENABLED)
    //确保p_q已经经过create函数
    if (p_q->Type != OS_OBJ_TYPE_Q) {
        OS_TRACE_Q_DEL_EXIT(OS_ERR_OBJ_TYPE);
        *p_err = OS_ERR_OBJ_TYPE;
        return (0u);
    }
#endif

    CPU_CRITICAL_ENTER();
    p_pend_list = &p_q->PendList;
    nbr_tasks   = 0u;
    switch (opt) {

        //只有当PendList为空时才删除
        case OS_OPT_DEL_NO_PEND:
            //如果PendList为空
            if (p_pend_list->HeadPtr == (OS_TCB *)0) {
#if (OS_CFG_DBG_EN == DEF_ENABLED)
                OS_QDbgListRemove(p_q);
                OSQQty--;
#endif
                OS_TRACE_Q_DEL(p_q);

                //调用OS_QClr初始化OS_MSG_Q和PendList
                OS_QClr(p_q);
                CPU_CRITICAL_EXIT();
                *p_err = OS_ERR_NONE;

            //如果PendList不为空
            } else {
                CPU_CRITICAL_EXIT();
                //设置错误码为OS_ERR_TASK_WAITING
                *p_err = OS_ERR_TASK_WAITING;
            }
            break;

        //不管PendList是否为空都删除
        case OS_OPT_DEL_ALWAYS:
#if (OS_CFG_TS_EN == DEF_ENABLED)
            ts = OS_TS_GET();
#else
            ts = 0u;
#endif
            //遍历整个PendList
            while (p_pend_list->HeadPtr != (OS_TCB *)0) {
                p_tcb = p_pend_list->HeadPtr;

                //将每一个任务都调用OS_PendAbort
                //将任务从PendList中移除
                //如果任务同时还处于TickList,也将其移除
                //如果没有被suspended,将其让如ReadyList
                //表明任务被移到ReadyList是因为OS_STATUS_PEND_DEL
                OS_PendAbort(p_tcb,
                            ts,
                            OS_STATUS_PEND_DEL);
                nbr_tasks++;
            }
#if (OS_CFG_DBG_EN == DEF_ENABLED)
            OS_QDbgListRemove(p_q);
            OSQQty--;
#endif
            OS_TRACE_Q_DEL(p_q);

            //初始化OS_MSG_Q和PendList
            OS_QClr(p_q);
            CPU_CRITICAL_EXIT();

            //引发一次调度
            OSSched();
            *p_err = OS_ERR_NONE;
            break;

        default:
            CPU_CRITICAL_EXIT();
            *p_err = OS_ERR_OPT_INVALID;
            break;
    }
    OS_TRACE_Q_DEL_EXIT(*p_err);
    return (nbr_tasks);
}

OS_OPT_DEL_NO_PEND指的是只有PendList为空时才删除。OS_OPT_DEL_ALWAYS指的是不管PendList是否为空都删除。当PendList中有任务时,将所有任务都从PendList中移除,如果这个任务同时还处于TickList中,也将其移除,最后如果这个任务没有被suspended,将其放入到ReadyList中。然后调用OS_QClr初始化OS_MSG_QPendList。最后调用OSSched进行一次调度。

3. 冲掉消息队列里的所有消息OSQFlush

OSQFlush函数的实现如下:

[os_q.c OSQFlush 函数]

OS_MSG_QTY  OSQFlush (OS_Q *p_q, OS_ERR *p_err)
{
    OS_MSG_QTY  entries;
    CPU_SR_ALLOC();

#ifdef OS_SAFETY_CRITICAL
    //p_err的入参非法性判断
    if (p_err == (OS_ERR *)0) {
        OS_SAFETY_CRITICAL_EXCEPTION();
        return (0u);
    }
#endif

#if (OS_CFG_CALLED_FROM_ISR_CHK_EN == DEF_ENABLED)
    //不能在ISR中调用这个函数
    if (OSIntNestingCtr > 0u) {
        *p_err = OS_ERR_FLUSH_ISR;
        return (0u);
    }
#endif

#if (OS_CFG_INVALID_OS_CALLS_CHK_EN == DEF_ENABLED)
    //不能在内核运行前调用这个函数
    if (OSRunning != OS_STATE_OS_RUNNING) {
        *p_err = OS_ERR_OS_NOT_RUNNING;
        return (0u);
    }
#endif

#if (OS_CFG_ARG_CHK_EN == DEF_ENABLED)
    //p_q的入参合法性判断
    if (p_q == (OS_Q *)0) {
        *p_err = OS_ERR_OBJ_PTR_NULL;
        return (0u);
    }
#endif

#if (OS_CFG_OBJ_TYPE_CHK_EN == DEF_ENABLED)
    //确保p_q已经经过create函数
    if (p_q->Type != OS_OBJ_TYPE_Q) {
        *p_err = OS_ERR_OBJ_TYPE;
        return (0u);
    }
#endif

    CPU_CRITICAL_ENTER();
    //释放消息队列中的所有的消息
    entries = OS_MsgQFreeAll(&p_q->MsgQ);
    CPU_CRITICAL_EXIT();
    *p_err   = OS_ERR_NONE;
    return (entries);
}

这个函数不能在内核运行前调用,不能再ISR中调用。最后调用OS_MsgQFreeAll

[os_msg.c OS_MsgQFreeAll 函数]

OS_MSG_QTY  OS_MsgQFreeAll (OS_MSG_Q  *p_msg_q)
{
    OS_MSG      *p_msg;
    OS_MSG_QTY   qty;

    qty = p_msg_q->NbrEntries;
    if (p_msg_q->NbrEntries > 0u) {
        p_msg                   = p_msg_q->InPtr;
        p_msg->NextPtr          = OSMsgPool.NextPtr;
        OSMsgPool.NextPtr       = p_msg_q->OutPtr;
        OSMsgPool.NbrUsed      -= p_msg_q->NbrEntries;
        OSMsgPool.NbrFree      += p_msg_q->NbrEntries;
        p_msg_q->NbrEntries     =           0u;
#if (OS_CFG_DBG_EN == DEF_ENABLED)
        p_msg_q->NbrEntriesMax  =           0u;
#endif
        p_msg_q->InPtr          = (OS_MSG *)0;
        p_msg_q->OutPtr         = (OS_MSG *)0;
    }
    return (qty);
}

4. 消息队列的Pend操作OSQPend

OSQPend函数片段1:

[os_q.c OSQPend 函数片段1]

void  *OSQPend (OS_Q         *p_q,
                OS_TICK       timeout,
                OS_OPT        opt,
                OS_MSG_SIZE  *p_msg_size,
                CPU_TS       *p_ts,
                OS_ERR       *p_err)
{
    void  *p_void;
    CPU_SR_ALLOC();


#ifdef OS_SAFETY_CRITICAL
    //p_err入参的合法性判断
    if (p_err == (OS_ERR *)0) {
        OS_SAFETY_CRITICAL_EXCEPTION();
        return ((void *)0);
    }
#endif

    OS_TRACE_Q_PEND_ENTER(p_q, timeout, opt, p_msg_size, p_ts);

#if (OS_CFG_CALLED_FROM_ISR_CHK_EN == DEF_ENABLED)
    //不能在`ISR`中调用
    if (OSIntNestingCtr > 0u) {
        OS_TRACE_Q_PEND_FAILED(p_q);
        OS_TRACE_Q_PEND_EXIT(OS_ERR_PEND_ISR);
    *p_err = OS_ERR_PEND_ISR;
        return ((void *)0);
    }
#endif

#if (OS_CFG_INVALID_OS_CALLS_CHK_EN == DEF_ENABLED)
    //内核运行前不能调用
    if (OSRunning != OS_STATE_OS_RUNNING) {
        OS_TRACE_Q_PEND_EXIT(OS_ERR_OS_NOT_RUNNING);
        *p_err = OS_ERR_OS_NOT_RUNNING;
        return ((void *)0);
    }
#endif

#if (OS_CFG_ARG_CHK_EN == DEF_ENABLED)
    //p_q的入参合法性判断
    if (p_q == (OS_Q *)0) {
        OS_TRACE_Q_PEND_FAILED(p_q);
        OS_TRACE_Q_PEND_EXIT(OS_ERR_OBJ_PTR_NULL);
        *p_err = OS_ERR_OBJ_PTR_NULL;
        return ((void *)0);
    }
    //p_msg_size,消息长度的入参合法性判断
    if (p_msg_size == (OS_MSG_SIZE *)0) {
        OS_TRACE_Q_PEND_FAILED(p_q);
        OS_TRACE_Q_PEND_EXIT(OS_ERR_PTR_INVALID);
        *p_err = OS_ERR_PTR_INVALID;
        return ((void *)0);
    }
    //opt的入参合法性判断
    switch (opt) {
        case OS_OPT_PEND_BLOCKING:
        case OS_OPT_PEND_NON_BLOCKING:
            break;

        default:
            OS_TRACE_Q_PEND_FAILED(p_q);
            OS_TRACE_Q_PEND_EXIT(OS_ERR_OPT_INVALID);
            *p_err = OS_ERR_OPT_INVALID;
            return ((void *)0);
    }
#endif

#if (OS_CFG_OBJ_TYPE_CHK_EN == DEF_ENABLED)
    //确保p_q已经经过了create函数
    if (p_q->Type != OS_OBJ_TYPE_Q) {
        OS_TRACE_Q_PEND_FAILED(p_q);
        OS_TRACE_Q_PEND_EXIT(OS_ERR_OBJ_TYPE);
    *p_err = OS_ERR_OBJ_TYPE;
        return ((void *)0);
    }
#endif

    if (p_ts != (CPU_TS *)0) {
        *p_ts = 0u;
    }

片段1主要是入参的合法性判断,并规定不能在ISR中调用,不能在内核运行前调用。

[os_q.c OSQPend 函数片段2]

    CPU_CRITICAL_ENTER();

    //从消息队列里获取一个消息
    p_void = OS_MsgQGet(&p_q->MsgQ,
                        p_msg_size,
                        p_ts,
                        p_err);
    //如果获取到了消息
    if (*p_err == OS_ERR_NONE) {
        OS_TRACE_Q_PEND(p_q);
        CPU_CRITICAL_EXIT();
        OS_TRACE_Q_PEND_EXIT(OS_ERR_NONE);
        //直接返回
        return (p_void);
    }

    //下面是没有获取到消息

    //如果是非阻塞模式
    if ((opt & OS_OPT_PEND_NON_BLOCKING) != 0u) {
        CPU_CRITICAL_EXIT();
        OS_TRACE_Q_PEND_FAILED(p_q);
        OS_TRACE_Q_PEND_EXIT(OS_ERR_PEND_WOULD_BLOCK);
        //设置相应错误码
        *p_err = OS_ERR_PEND_WOULD_BLOCK;
        //返回出去
        return ((void *)0);

    //如果是阻塞模式
    } else {
        //如果调度器被锁住了
        if (OSSchedLockNestingCtr > 0u) {
            CPU_CRITICAL_EXIT();
            OS_TRACE_Q_PEND_FAILED(p_q);
            OS_TRACE_Q_PEND_EXIT(OS_ERR_SCHED_LOCKED);
            //设置好错误码
            *p_err = OS_ERR_SCHED_LOCKED;
            //直接返回
            return ((void *)0);
        }
    }

    //没有获取消息,阻塞模式,调度器没上锁

    //调用OS_Pend把当前任务从ReadyList移动到PendList。
    //如果TimeOut不为0,同时插入到TickList中
    OS_Pend((OS_PEND_OBJ *)((void *)p_q),
            OS_TASK_PEND_ON_Q,
            timeout);
    CPU_CRITICAL_EXIT();
    OS_TRACE_Q_PEND_BLOCK(p_q);

    //调用OSSched,引发一次调度
    OSSched();

片段2是先尝试从消息队列中获取消息,如果获取到了消息,直接返回出去;如果没有获取到消息,再判断是阻塞模式还是非阻塞模式,如果是非阻塞模式,设置好错误码直接返回。如果是阻塞模式并且调度器没上锁的话,就把这个任务从ReadyList中移除,加入到这个消息队列的PendList中。如果TimeOut不为0,再加入到TickList中。最后调用OSSched引发一次调度。

下面的片段3,是这个任务从新又被放入到ReadyList之后才能运行到的:

[os_q.c OSQPend 函数片段3]

    CPU_CRITICAL_ENTER();

    //重新被放入ReadyList的原因
    switch (OSTCBCurPtr->PendStatus) {

        //得到了消息
        case OS_STATUS_PEND_OK:
            p_void     = OSTCBCurPtr->MsgPtr;
            *p_msg_size = OSTCBCurPtr->MsgSize;
#if (OS_CFG_TS_EN == DEF_ENABLED)
            if (p_ts  != (CPU_TS *)0) {
                *p_ts  =  OSTCBCurPtr->TS;
            }
#endif
            OS_TRACE_Q_PEND(p_q);
            //设置错误码为OS_ERR_NONE
            *p_err      = OS_ERR_NONE;
            break;

        //因为PendAbort的操作
        case OS_STATUS_PEND_ABORT:
            p_void     = (void *)0;
            *p_msg_size =         0u;
#if (OS_CFG_TS_EN == DEF_ENABLED)
            if (p_ts  != (CPU_TS *)0) {
                *p_ts  =  OSTCBCurPtr->TS;
            }
#endif
            OS_TRACE_Q_PEND_FAILED(p_q);
            //设置错误码为OS_ERR_PEND_ABORT
            *p_err      = OS_ERR_PEND_ABORT;
            break;

        //因为超时
        case OS_STATUS_PEND_TIMEOUT:
            p_void     = (void *)0;
            *p_msg_size =         0u;
            OS_TRACE_Q_PEND_FAILED(p_q);
            //设置错误码为OS_ERR_TIMEOUT
            *p_err      = OS_ERR_TIMEOUT;
            break;

        //因为删除了消息队列
        case OS_STATUS_PEND_DEL:
            p_void     = (void *)0;
            *p_msg_size =         0u;
#if (OS_CFG_TS_EN == DEF_ENABLED)
            if (p_ts  != (CPU_TS *)0) {
                *p_ts  =  OSTCBCurPtr->TS;
            }
#endif
            OS_TRACE_Q_PEND_FAILED(p_q);
            *p_err      = OS_ERR_OBJ_DEL;
            break;

        //异常原因
        default:
            p_void     = (void *)0;
            *p_msg_size =         0u;
            OS_TRACE_Q_PEND_FAILED(p_q);
            *p_err      = OS_ERR_STATUS_INVALID;
            break;
    }
    CPU_CRITICAL_EXIT();
    OS_TRACE_Q_PEND_EXIT(*p_err);
    return (p_void);
}

最后任务又被放回到ReadyList之后,根据不同的原因选择不同的错误码。

5. 消息队列的PendAbort操作OSQPendAbort

OSQPendAbort函数的实现如下:

[os_q.c OSQPendAbort 函数]

OS_OBJ_QTY  OSQPendAbort (OS_Q    *p_q,
                        OS_OPT   opt,
                        OS_ERR  *p_err)
{
    OS_PEND_LIST  *p_pend_list;
    OS_TCB        *p_tcb;
    CPU_TS         ts;
    OS_OBJ_QTY     nbr_tasks;
    CPU_SR_ALLOC();


#ifdef OS_SAFETY_CRITICAL
    //p_err入参合法性判断
    if (p_err == (OS_ERR *)0) {
        OS_SAFETY_CRITICAL_EXCEPTION();
        return (0u);
    }
#endif

#if (OS_CFG_CALLED_FROM_ISR_CHK_EN == DEF_ENABLED)
    //函数不能在ISR中调用
    if (OSIntNestingCtr > 0u) {
        *p_err =  OS_ERR_PEND_ABORT_ISR;
        return (0u);
    }
#endif

#if (OS_CFG_INVALID_OS_CALLS_CHK_EN == DEF_ENABLED)
    //函数不能再内核运行前调用
    if (OSRunning != OS_STATE_OS_RUNNING) {
        *p_err = OS_ERR_OS_NOT_RUNNING;
        return (0u);
    }
#endif

#if (OS_CFG_ARG_CHK_EN == DEF_ENABLED)
    //p_q入参合法性判断
    if (p_q == (OS_Q *)0) {
        *p_err =  OS_ERR_OBJ_PTR_NULL;
        return (0u);
    }

    //opt合法性判断
    switch (opt) {
        case OS_OPT_PEND_ABORT_1:
        case OS_OPT_PEND_ABORT_ALL:
        case OS_OPT_PEND_ABORT_1   | OS_OPT_POST_NO_SCHED:
        case OS_OPT_PEND_ABORT_ALL | OS_OPT_POST_NO_SCHED:
            break;

        default:
            *p_err =  OS_ERR_OPT_INVALID;
            return (0u);
    }
#endif

#if (OS_CFG_OBJ_TYPE_CHK_EN == DEF_ENABLED)
    //确保p_q已经经过create函数
    if (p_q->Type != OS_OBJ_TYPE_Q) {
        *p_err =  OS_ERR_OBJ_TYPE;
        return (0u);
    }
#endif

    CPU_CRITICAL_ENTER();
    p_pend_list = &p_q->PendList;

    //如果PendList为空
    if (p_pend_list->HeadPtr == (OS_TCB *)0) {
        CPU_CRITICAL_EXIT();
        //设置错误码为OS_ERR_PEND_ABORT_NONE
        *p_err =  OS_ERR_PEND_ABORT_NONE;
        //返回
        return (0u);
    }

    nbr_tasks = 0u;
#if (OS_CFG_TS_EN == DEF_ENABLED)
    ts        = OS_TS_GET();
#else
    ts        = 0u;
#endif
    //如果PendList不为空,遍历整个PendList
    while (p_pend_list->HeadPtr != (OS_TCB *)0) {
        p_tcb = p_pend_list->HeadPtr;
        //调用OS_PendAbort将每个任务从PendList和TickList中移除
        //如果没有被suspended,那么再将他们放入到ReadyList中
        OS_PendAbort(p_tcb,
                    ts,
                    OS_STATUS_PEND_ABORT);
        nbr_tasks++;
        if (opt != OS_OPT_PEND_ABORT_ALL) {
            break;
        }
    }
    CPU_CRITICAL_EXIT();

    //如果没有特殊声明OS_OPT_POST_NO_SCHED
    if ((opt & OS_OPT_POST_NO_SCHED) == 0u) {
        //调用OSSched
        OSSched();
    }

    *p_err = OS_ERR_NONE;
    return (nbr_tasks);
}

不能在ISR中调用,不能在内核运行前调用。将PendList中的所有任务从PendList中移除,并从其TickList中移除,如果没有被suspended再把他们放入到ReadyList中。如果没有特殊声明OS_OPT_POST_NO_SCHED,调用OSSched引发一次调度。

6. 消息队列的Post操作OSQPost

[os_q.c OSQPost 函数]

void  OSQPost (OS_Q         *p_q,
            void         *p_void,
            OS_MSG_SIZE   msg_size,
            OS_OPT        opt,
            OS_ERR       *p_err)
{
    OS_OPT         post_type;
    OS_PEND_LIST  *p_pend_list;
    OS_TCB        *p_tcb;
    OS_TCB        *p_tcb_next;
    CPU_TS         ts;
    CPU_SR_ALLOC();


#ifdef OS_SAFETY_CRITICAL
    //p_err的入参合法性判断
    if (p_err == (OS_ERR *)0) {
        OS_SAFETY_CRITICAL_EXCEPTION();
        return;
    }
#endif

    OS_TRACE_Q_POST_ENTER(p_q, p_void, msg_size, opt);

#if (OS_CFG_INVALID_OS_CALLS_CHK_EN == DEF_ENABLED)
    //不能在内核运行前调用这个函数
    if (OSRunning != OS_STATE_OS_RUNNING) {
        OS_TRACE_Q_POST_EXIT(OS_ERR_OS_NOT_RUNNING);
        *p_err = OS_ERR_OS_NOT_RUNNING;
        return;
    }
#endif

#if (OS_CFG_ARG_CHK_EN == DEF_ENABLED)
    //p_q入参合法性判断
    if (p_q == (OS_Q *)0) {
        OS_TRACE_Q_POST_FAILED(p_q);
        OS_TRACE_Q_POST_EXIT(OS_ERR_OBJ_PTR_NULL);
        *p_err = OS_ERR_OBJ_PTR_NULL;
        return;
    }
    //opt入参合法性判断
    switch (opt) {
        case OS_OPT_POST_FIFO:
        case OS_OPT_POST_LIFO:
        case OS_OPT_POST_FIFO | OS_OPT_POST_ALL:
        case OS_OPT_POST_LIFO | OS_OPT_POST_ALL:
        case OS_OPT_POST_FIFO | OS_OPT_POST_NO_SCHED:
        case OS_OPT_POST_LIFO | OS_OPT_POST_NO_SCHED:
        case OS_OPT_POST_FIFO | (OS_OPT)(OS_OPT_POST_ALL | OS_OPT_POST_NO_SCHED):
        case OS_OPT_POST_LIFO | (OS_OPT)(OS_OPT_POST_ALL | OS_OPT_POST_NO_SCHED):
            break;

        default:
            OS_TRACE_Q_POST_FAILED(p_q);
            OS_TRACE_Q_POST_EXIT(OS_ERR_OPT_INVALID);
            *p_err =  OS_ERR_OPT_INVALID;
            return;
    }
#endif

#if (OS_CFG_OBJ_TYPE_CHK_EN == DEF_ENABLED)
    //确保p_q已经经过了create函数
    if (p_q->Type != OS_OBJ_TYPE_Q) {
        OS_TRACE_Q_POST_FAILED(p_q);
        OS_TRACE_Q_POST_EXIT(OS_ERR_OBJ_TYPE);
        *p_err = OS_ERR_OBJ_TYPE;
        return;
    }
#endif
#if (OS_CFG_TS_EN == DEF_ENABLED)
    ts = OS_TS_GET();
#else
    ts = 0u;
#endif

    OS_TRACE_Q_POST(p_q);

    CPU_CRITICAL_ENTER();
    p_pend_list = &p_q->PendList;

    //如果PendList中没有任务
    if (p_pend_list->HeadPtr == (OS_TCB *)0) {
        //放入消息的方向
        if ((opt & OS_OPT_POST_LIFO) == 0u) {
            post_type = OS_OPT_POST_FIFO;
        } else {
            post_type = OS_OPT_POST_LIFO;
        }

        //把消息插入到消息队列中,
        //占用OSMsgPool消息池一个位置
        OS_MsgQPut(&p_q->MsgQ,
                    p_void,
                    msg_size,
                    post_type,
                    ts,
                    p_err);
        CPU_CRITICAL_EXIT();
        OS_TRACE_Q_POST_EXIT(*p_err);

        //返回出去
        return;
    }

    //下面是如果PendList不为空,
    //那么说明消息队列里没有消息

    p_tcb = p_pend_list->HeadPtr;
    while (p_tcb != (OS_TCB *)0) {
        p_tcb_next = p_tcb->PendNextPtr;

        //把这个消息给每一个人任务
        //并且把这个任务从PendList或者TickList移除
        //如果这个任务没有suspended,那么这个任务就被放入到ReadyList中
        OS_Post((OS_PEND_OBJ *)((void *)p_q),
                p_tcb,
                p_void,
                msg_size,
                ts);

        //如果声明了OS_OPT_POST_ALL,那么就是把告诉PendList中的所有任务
        if ((opt & OS_OPT_POST_ALL) == 0u)  {
            break;
        }
        p_tcb = p_tcb_next;
    }

    CPU_CRITICAL_EXIT();

    //如果没有特殊声明OS_OPT_POST_NO_SCHED
    if ((opt & OS_OPT_POST_NO_SCHED) == 0u) {

        //引发一次调度
        OSSched();
    }

    *p_err = OS_ERR_NONE;
    OS_TRACE_Q_POST_EXIT(*p_err);
}

如果PendList中没有任务,那么就把消息放入到全局的消息池OSMsgPool中,并插入到消息队列里,根据插入的防线过的不同:OS_OPT_POST_FIFO是插入到队列的头部(先进队列的先出去);OS_OPT_POST_LIFO是插入到队列的尾部(后进队列的先出去)。

如果PendList中有任务,说明消息队列中没有消息,那么就直接把这个消息发送给PendList中的任务。如果是声明了OS_OPT_POST_ALL,那么就告诉PendList中的所有任务,反之就只告诉PendList中的第一任务。这些得到消息的任务,会被移除PendListTickList)。如果没有被suspended,会被加入到ReadyList中。最后调用一次OSSched进行一次调度(如果没有特殊声明OS_OPT_POST_NO_SCHED的话)。

六. 任务相关的API

1. 创建任务OSTaskCreate

OSTaskCreate是创建一个任务,具体的内容在μC/OS III-任务调度Ⅰ:调度过程和调度点中有详细介绍。

2. 删除任务OSTaskDel

OSTaskDel是删除一个任务这个函数的定义为:

[os_task.c OSTaskDel() 片段 1 ]

void  OSTaskDel (OS_TCB  *p_tcb, OS_ERR  *p_err)
{
#if (OS_CFG_MUTEX_EN == DEF_ENABLED)
    OS_TCB   *p_tcb_owner;
    OS_PRIO   prio_new;
#endif

#ifdef OS_SAFETY_CRITICAL
    if (p_err == (OS_ERR *)0) {
        //p_err入参合法性检查
        OS_SAFETY_CRITICAL_EXCEPTION();
        return;
    }
#endif

#ifdef OS_SAFETY_CRITICAL_IEC61508
    if (OSSafetyCriticalStartFlag == DEF_TRUE) {
        *p_err = OS_ERR_ILLEGAL_DEL_RUN_TIME;
        return;
    }
#endif

CPU_SR_ALLOC();

#if (OS_CFG_CALLED_FROM_ISR_CHK_EN == DEF_ENABLED)
    //不能在ISR中调用
    if (OSIntNestingCtr > 0u) {
        *p_err = OS_ERR_TASK_DEL_ISR;
        return;
    }
#endif

#if (OS_CFG_INVALID_OS_CALLS_CHK_EN == DEF_ENABLED)
    //不能在系统运行前调用
    if (OSRunning != OS_STATE_OS_RUNNING) {
        *p_err = OS_ERR_OS_NOT_RUNNING;
        return;
    }
#endif

#if (OS_CFG_TASK_IDLE_EN == DEF_ENABLED)
    //不能删除空闲任务
    if (p_tcb == &OSIdleTaskTCB) {
        *p_err = OS_ERR_TASK_DEL_IDLE;
        return;
    }
#endif

上面的片段代码说明:不能在中断处理函数中删除一个任务;不能在μC/OS III没有处于运行状态的时候删除一个任务;不能删除空闲任务IDLE TASK

[os_task.c OSTaskDel() 片段 2 ]

if (p_tcb == (OS_TCB *)0) {   /* Delete 'Self'?  */
    CPU_CRITICAL_ENTER();
    p_tcb  = OSTCBCurPtr;     /* Yes.           */
    CPU_CRITICAL_EXIT();
}

如果传入的p_tcb为0的话,就是删除本身。

[os_task.c OSTaskDel() 片段 3 ]

switch (p_tcb->TaskState) {
    //如果任务初始Ready状态
    case OS_TASK_STATE_RDY:
        //从ReadyList中删除
        OS_RdyListRemove(p_tcb);
        break;
    case OS_TASK_STATE_SUSPENDED:
        break;
    //如果有Dly,那么从TickList中删除
    case OS_TASK_STATE_DLY:
    case OS_TASK_STATE_DLY_SUSPENDED:
#if (OS_CFG_TASK_TICK_EN == DEF_ENABLED)
        OS_TickListRemove(p_tcb);
#endif
        break;
    //如果有Pend
    case OS_TASK_STATE_PEND:
    case OS_TASK_STATE_PEND_SUSPENDED:
    case OS_TASK_STATE_PEND_TIMEOUT:
    case OS_TASK_STATE_PEND_TIMEOUT_SUSPENDED:
        switch (p_tcb->PendOn) {
            case OS_TASK_PEND_ON_NOTHING:
            case OS_TASK_PEND_ON_TASK_Q:
            case OS_TASK_PEND_ON_TASK_SEM:
                break;
            //如果Pend操作不是任务自身的Pend
            //有内核对象的Pend
            case OS_TASK_PEND_ON_FLAG:
            case OS_TASK_PEND_ON_Q:
            case OS_TASK_PEND_ON_SEM:
                //如果PendList中移除
                OS_PendListRemove(p_tcb);
                break;
#if (OS_CFG_MUTEX_EN == DEF_ENABLED)
            //Mutex特殊处理
            case OS_TASK_PEND_ON_MUTEX:
                p_tcb_owner = ((OS_MUTEX *)((void *)p_tcb->PendObjPtr))->OwnerTCBPtr;
                prio_new = p_tcb_owner->Prio;
                //如果PendList中移除
                OS_PendListRemove(p_tcb);

                //解决MutexGroup优先级的问题
                if ((p_tcb_owner->Prio != p_tcb_owner->BasePrio) &&
                    (p_tcb_owner->Prio == p_tcb->Prio)) {
                    prio_new = OS_MutexGrpPrioFindHighest(p_tcb_owner);
                    prio_new = (prio_new > p_tcb_owner->BasePrio) ? p_tcb_owner->BasePrio : prio_new;
                }
                p_tcb->PendOn = OS_TASK_PEND_ON_NOTHING;
                if (prio_new != p_tcb_owner->Prio) {
                    OS_TaskChangePrio(p_tcb_owner, prio_new);
                    OS_TRACE_MUTEX_TASK_PRIO_DISINHERIT(p_tcb_owner, p_tcb_owner->Prio);
                }
                break;
#endif
            default:
                break;
        }
#if (OS_CFG_TASK_TICK_EN == DEF_ENABLED)
        if ((p_tcb->TaskState == OS_TASK_STATE_PEND_TIMEOUT) ||
            (p_tcb->TaskState == OS_TASK_STATE_PEND_TIMEOUT_SUSPENDED)) {
            //如果有TimeOut,那么从TickList中移除
            OS_TickListRemove(p_tcb);
        }
#endif
        break;
    default:
        CPU_CRITICAL_EXIT();
    *p_err = OS_ERR_STATE_INVALID;
        return;
}

#if (OS_CFG_MUTEX_EN == DEF_ENABLED)
    //因为整个任务被删除了,她所占用的Mutex全被释放
    //所有要MutexGroup里的所有Mutex做Post操作
    if(p_tcb->MutexGrpHeadPtr != (OS_MUTEX *)0) {
        OS_MutexGrpPostAll(p_tcb);
    }
#endif

#if (OS_CFG_TASK_Q_EN == DEF_ENABLED)
    //释放这个任务相关的MsgQ
    (void)OS_MsgQFreeAll(&p_tcb->MsgQ);
#endif

    //调用OSTaskDelHook钩子函数
    OSTaskDelHook(p_tcb);

#if defined(OS_CFG_TLS_TBL_SIZE) && (OS_CFG_TLS_TBL_SIZE > 0u)
    OS_TLS_TaskDel(p_tcb);
#endif

#if (OS_CFG_DBG_EN == DEF_ENABLED)
    OS_TaskDbgListRemove(p_tcb);
#endif

    OSTaskQty--;

    OS_TRACE_TASK_DEL(p_tcb);

#if (OS_CFG_TASK_STK_REDZONE_EN != DEF_ENABLED)
    OS_TaskInitTCB(p_tcb);
#endif
    p_tcb->TaskState = (OS_STATE)OS_TASK_STATE_DEL;

    *p_err = OS_ERR_NONE;
    CPU_CRITICAL_EXIT();

    //最后引发一次调度
    OSSched();
}

判断通过判断p_tcb->TaskState的值,来判断当前任务处于什么状态中,便可以知道这个任务处于哪个任务列表中,将其从相应的任务列表中删除。并且在Mutex中需要注意优先级反转的问题。以及对这个任务中的MutexGroup所有的Mutex做一次Post,释放这个函数相关的消息队列MsgQ中的所有消息。然后调用任务函数的钩子函数OSTaskDelHook,最后调用OSSched引发一次调度,从就绪列表中找到优先级最高的任务开始执行。

3. 更改任务优先级OSTaskChangePrio

[os_task.c OSTaskChangePrio函数]

void  OSTaskChangePrio (OS_TCB   *p_tcb,
                        OS_PRIO   prio_new,
                        OS_ERR   *p_err)
{
#if (OS_CFG_MUTEX_EN == DEF_ENABLED)
    OS_PRIO  prio_high;
#endif
    CPU_SR_ALLOC();


#ifdef OS_SAFETY_CRITICAL
    //p_err的入参合法性判断
    if (p_err == (OS_ERR *)0) {
        OS_SAFETY_CRITICAL_EXCEPTION();
        return;
    }
#endif

#if (OS_CFG_ARG_CHK_EN == DEF_ENABLED)
    //p_tcb入参合法性判断,不能对已经删除的任务做此操作
    if ((p_tcb != (OS_TCB *)0) && (p_tcb->TaskState == OS_TASK_STATE_DEL)) {
        *p_err = OS_ERR_STATE_INVALID;
        return;
    }
#endif

#if (OS_CFG_CALLED_FROM_ISR_CHK_EN == DEF_ENABLED)
    //不能在ISR中调用
    if (OSIntNestingCtr > 0u) {
        *p_err = OS_ERR_TASK_CHANGE_PRIO_ISR;
        return;
    }
#endif

    //不能更改成空闲任务的优先级
    if (prio_new >= (OS_CFG_PRIO_MAX - 1u)) {
        *p_err = OS_ERR_PRIO_INVALID;
        return;
    }

    CPU_CRITICAL_ENTER();

    //如果p_tcb为0,那么就是更改自己的优先级
    if (p_tcb == (OS_TCB *)0) {
        if (OSRunning != OS_STATE_OS_RUNNING) {
            CPU_CRITICAL_EXIT();
            *p_err = OS_ERR_OS_NOT_RUNNING;
            return;
        }
        p_tcb = OSTCBCurPtr;
    }

#if (OS_CFG_MUTEX_EN == DEF_ENABLED)
    p_tcb->BasePrio = prio_new;

    //MutexGroup的优先级问题
    if (p_tcb->MutexGrpHeadPtr != (OS_MUTEX *)0) {
        if (prio_new > p_tcb->Prio) {
            prio_high = OS_MutexGrpPrioFindHighest(p_tcb);
            if (prio_new > prio_high) {
                prio_new = prio_high;
            }
        }
    }
#endif

    //更改优先级
    OS_TaskChangePrio(p_tcb, prio_new);

    OS_TRACE_TASK_PRIO_CHANGE(p_tcb, prio_new);
    CPU_CRITICAL_EXIT();

    //如果内核已经运行了起来
    if (OSRunning == OS_STATE_OS_RUNNING) {
        //引发一次调度
        OSSched();
    }

    *p_err = OS_ERR_NONE;
}

这个函数是更改一个任务的优先级。同样的,在中断处理函数中不能调用,p_tcb为0时,是更改当前任务的优先级。同时也得考虑Mutex的情况。OS_TaskChangePrio这个函数是更改过优先级之后,需要把当前任务所在的列表中的位置进行更改,因为某些列表的排序是根据优先级进行排序的(PendListReadyList)。最后如果OS处于运行状态的话,调用一次OSSched引发一次调度。

4. 暂停任务OSTaskSuspend

OSTaskSuspend函数的实现如下:

[os_task.c OSTaskSuspend 函数]

void   OSTaskSuspend (OS_TCB  *p_tcb,
                    OS_ERR  *p_err)
{
    CPU_SR_ALLOC();


#ifdef OS_SAFETY_CRITICAL
    //p_err的入参合法性判断
    if (p_err == (OS_ERR *)0) {
        OS_SAFETY_CRITICAL_EXCEPTION();
        return;
    }
#endif

#if (OS_CFG_CALLED_FROM_ISR_CHK_EN == DEF_ENABLED)
    //不能在ISR中调用
    if (OSIntNestingCtr > 0u) {
    *p_err = OS_ERR_TASK_SUSPEND_ISR;
        return;
    }
#endif

#if (OS_CFG_TASK_IDLE_EN == DEF_ENABLED)
    //不能暂停空闲状态
    if (p_tcb == &OSIdleTaskTCB) {
        *p_err = OS_ERR_TASK_SUSPEND_IDLE;
        return;
    }
#endif

    OS_TRACE_TASK_SUSPEND(p_tcb);

    CPU_CRITICAL_ENTER();
    //如果p_tcb为0
    if (p_tcb == (OS_TCB *)0) {
        //如果内核没运行
        if (OSRunning != OS_STATE_OS_RUNNING) {
            CPU_CRITICAL_EXIT();
            *p_err = OS_ERR_OS_NOT_RUNNING;
            return;
        }
        //暂停自己
        p_tcb = OSTCBCurPtr;
    }

    //如果是自己
    if (p_tcb == OSTCBCurPtr) {
        //如果是锁住了调度器,则不能暂停自己,因为没办法调度到新的任务
        if (OSSchedLockNestingCtr > 0u) {
            CPU_CRITICAL_EXIT();
            *p_err = OS_ERR_SCHED_LOCKED;
            return;
        }
    }

    *p_err = OS_ERR_NONE;
    switch (p_tcb->TaskState) {
        //如果任务是ready状态
        case OS_TASK_STATE_RDY:
            //设置状态为suspended
            p_tcb->TaskState  =  OS_TASK_STATE_SUSPENDED;
            //设置suspended嵌套次数为1
            p_tcb->SuspendCtr = 1u;
            //从readyList中移除
            OS_RdyListRemove(p_tcb);
            CPU_CRITICAL_EXIT();
            break;

        //如果是delay状态
        case OS_TASK_STATE_DLY:
            //设置状态delay + suspended
            p_tcb->TaskState  = OS_TASK_STATE_DLY_SUSPENDED;
            p_tcb->SuspendCtr = 1u;
            CPU_CRITICAL_EXIT();
            break;

        //如果是pend状态
        case OS_TASK_STATE_PEND:
            //设置状态pend + suspended
            p_tcb->TaskState  = OS_TASK_STATE_PEND_SUSPENDED;
            //设置suspended嵌套次数为1
            p_tcb->SuspendCtr = 1u;
            CPU_CRITICAL_EXIT();
            break;

        //如果是pend + timeout
        case OS_TASK_STATE_PEND_TIMEOUT:
            //设置状态pend + timeout + suspended
            p_tcb->TaskState  = OS_TASK_STATE_PEND_TIMEOUT_SUSPENDED;
            //设置suspended嵌套次数为1
            p_tcb->SuspendCtr = 1u;
            CPU_CRITICAL_EXIT();
            break;

        //如果已经包含了suspended,那么是嵌套的暂停
        case OS_TASK_STATE_SUSPENDED:
        case OS_TASK_STATE_DLY_SUSPENDED:
        case OS_TASK_STATE_PEND_SUSPENDED:
        case OS_TASK_STATE_PEND_TIMEOUT_SUSPENDED:
            //如果之前的嵌套次数是-1,肯定有错误
            if (p_tcb->SuspendCtr == (OS_NESTING_CTR)-1) {
                CPU_CRITICAL_EXIT();
                *p_err = OS_ERR_TASK_SUSPEND_CTR_OVF;
                return;
            }
            //增加嵌套次数
            p_tcb->SuspendCtr++;
            CPU_CRITICAL_EXIT();
            break;

        default:
            CPU_CRITICAL_EXIT();
            *p_err = OS_ERR_STATE_INVALID;
            return;
    }

    //如果内核处于运行状态
    if (OSRunning == OS_STATE_OS_RUNNING) {
        //进行一次调度
        OSSched();
    }
}

不能在ISR中调用,如果是从ready状态暂停,把任务从ReadyList中移除。给任务的状态加上suspended。如果之前不包含suspended状态,那么把嵌套次数设置为1,如果之前包含suspended状态,那么把嵌套暂停次数增加1。最后如果内核已经运行,调用一次OSSched进行一次调度。

5. 恢复暂停的任务OSTaskResume

OSTaskResume函数的实现:

[os_task.c OSTaskResume 函数]

void  OSTaskResume (OS_TCB  *p_tcb,
                    OS_ERR  *p_err)
{
    CPU_SR_ALLOC();


#ifdef OS_SAFETY_CRITICAL
    //p_err入参合法性判断
    if (p_err == (OS_ERR *)0) {
        OS_SAFETY_CRITICAL_EXCEPTION();
        return;
    }
#endif

#if (OS_CFG_CALLED_FROM_ISR_CHK_EN == DEF_ENABLED)
    //ISR中不能调用这个函数
    if (OSIntNestingCtr > 0u) {
        *p_err = OS_ERR_TASK_RESUME_ISR;
        return;
    }
#endif

#if (OS_CFG_INVALID_OS_CALLS_CHK_EN == DEF_ENABLED)
    //内核运行前不能调用这个函数
    if (OSRunning != OS_STATE_OS_RUNNING) {
        *p_err = OS_ERR_OS_NOT_RUNNING;
        return;
    }
#endif


#if (OS_CFG_ARG_CHK_EN == DEF_ENABLED)
    CPU_CRITICAL_ENTER();

    //p_tcb入参合法性判断,不能对自己做恢复暂停的操作
    if ((p_tcb == (OS_TCB *)0) ||
        (p_tcb == OSTCBCurPtr)) {
        CPU_CRITICAL_EXIT();
        *p_err  = OS_ERR_TASK_RESUME_SELF;
        return;
    }
    CPU_CRITICAL_EXIT();
#endif

    CPU_CRITICAL_ENTER();
    *p_err  = OS_ERR_NONE;

    //如果任务不处于暂停状态,不包含suspended状态
    switch (p_tcb->TaskState) {
        case OS_TASK_STATE_RDY:
        case OS_TASK_STATE_DLY:
        case OS_TASK_STATE_PEND:
        case OS_TASK_STATE_PEND_TIMEOUT:
            CPU_CRITICAL_EXIT();
            *p_err = OS_ERR_TASK_NOT_SUSPENDED;
            break;

        //处于suspended状态
        case OS_TASK_STATE_SUSPENDED:
            p_tcb->SuspendCtr--;
            //嵌套暂停全部恢复
            if (p_tcb->SuspendCtr == 0u) {
                //设置状态为ready态
                p_tcb->TaskState = OS_TASK_STATE_RDY;
                //插入到ReadyList中
                OS_RdyListInsert(p_tcb);
            }
            CPU_CRITICAL_EXIT();
            break;

        //delay + suspended状态
        case OS_TASK_STATE_DLY_SUSPENDED:
            p_tcb->SuspendCtr--;
            //嵌套暂停全部恢复
            if (p_tcb->SuspendCtr == 0u) {
                //改成Dleay状态
                p_tcb->TaskState = OS_TASK_STATE_DLY;
            }
            CPU_CRITICAL_EXIT();
            break;

        //pend + suspended状态
        case OS_TASK_STATE_PEND_SUSPENDED:
            p_tcb->SuspendCtr--;
            //嵌套暂停全部恢复
            if (p_tcb->SuspendCtr == 0u) {
                //改成pend状态
                p_tcb->TaskState = OS_TASK_STATE_PEND;
            }
            CPU_CRITICAL_EXIT();
            break;

        //Pend + timeout + suspended状态
        case OS_TASK_STATE_PEND_TIMEOUT_SUSPENDED:
            p_tcb->SuspendCtr--;
            //嵌套暂停全部恢复
            if (p_tcb->SuspendCtr == 0u) {
                //设置成pend + timeout
                p_tcb->TaskState = OS_TASK_STATE_PEND_TIMEOUT;
            }
            CPU_CRITICAL_EXIT();
            break;

        default:
            CPU_CRITICAL_EXIT();
            *p_err = OS_ERR_STATE_INVALID;
            return;
    }

    OS_TRACE_TASK_RESUME(p_tcb);

    //引发一次调度
    OSSched();
}

ISR中不能调用这个函数,内核运行前不能调用这个函数,不能给自己做恢复暂停操作(事实上这个是不可能的,如果做了的话,一定有BUG)。如果任务只是suspended状态,恢复之后把任务放入到ReadyList中。如果还有其他的状态(DelayPendPend + Timeout),则只去掉suspended,而不放入ReadyList中。

6. 任务自身的信号量、消息队列的操作

任务自身的计数信号量操作、消息队列的操作,只跟这个任务有关系,OS_PEND_OBJ内核对象:

任务自身的计数信号量函数说明
OSTaskSemPend任务自身计数信号量的Pend操作
OSTaskSemPendAbort任务自身计数信号量的PendAbort操作
OSTaskSemPost任务自身计数信号量的Pos操作
OSTaskSemSet任务自身计数信号量的Set操作
任务自身的消息队列函数说明
OSTaskQFlush冲掉任务自身消息队列中的所有消息
OSTaskQPend任务自身消息队列的Pend操作
OSTaskQPendAbort任务自身消息队列的PendAbort操作
OSTaskQPost任任务自身消息队列的Post操作

七. 时间相关的API

1. 延时函数OSTimeDly

OSTimeDly函数的实现如下:

[os_time.c OSTimeDly函数]

void  OSTimeDly (OS_TICK   dly,
                OS_OPT    opt,
                OS_ERR   *p_err)
{
#if (OS_CFG_TASK_TICK_EN == DEF_ENABLED)
    CPU_SR_ALLOC();
#endif


#ifdef OS_SAFETY_CRITICAL
    //p_err入参合法性判断
    if (p_err == (OS_ERR *)0) {
        OS_SAFETY_CRITICAL_EXCEPTION();
        return;
    }
#endif

#if (OS_CFG_CALLED_FROM_ISR_CHK_EN == DEF_ENABLED)
    //不能在ISR中调用
    if (OSIntNestingCtr > 0u) {
        *p_err = OS_ERR_TIME_DLY_ISR;
        return;
    }
#endif

#if (OS_CFG_INVALID_OS_CALLS_CHK_EN == DEF_ENABLED)
    //不能在内核运行前调用
    if (OSRunning != OS_STATE_OS_RUNNING) {
        *p_err = OS_ERR_OS_NOT_RUNNING;
        return;
    }
#endif

    //内核调度上锁时
    if (OSSchedLockNestingCtr > 0u) {
        *p_err = OS_ERR_SCHED_LOCKED;
        return;
    }

    //opt入参合法性判断
    switch (opt) {
        case OS_OPT_TIME_DLY:
        case OS_OPT_TIME_TIMEOUT:
        case OS_OPT_TIME_PERIODIC:
            if (dly == 0u) {
                *p_err = OS_ERR_TIME_ZERO_DLY;
                return;
            }
            break;

        case OS_OPT_TIME_MATCH:
            break;

        default:
            *p_err = OS_ERR_OPT_INVALID;
            return;
    }

#if (OS_CFG_TASK_TICK_EN == DEF_ENABLED)
    CPU_CRITICAL_ENTER();

    //将让如插入到OSTickListDly中
    OS_TickListInsertDly(OSTCBCurPtr,
                        dly,
                        opt,
                        p_err);
    if (*p_err != OS_ERR_NONE) {
        CPU_CRITICAL_EXIT();
        return;
    }

    OS_TRACE_TASK_DLY(dly);
    //将任务从ReadyList中移除
    OS_RdyListRemove(OSTCBCurPtr);
    CPU_CRITICAL_EXIT();

    //引发一次调度
    OSSched();
#endif
}

这个函数不能在ISR中调用,不能在内核运行前调用。把任务放入到OSTickListDly中。最后调用OSSched进行一次调度。

2. 按时分秒毫秒的延时函数OSTimeDlyHMSM

[os_time.c OSTimeDlyHMSM 函数]

void  OSTimeDlyHMSM (CPU_INT16U   hours,
                    CPU_INT16U   minutes,
                    CPU_INT16U   seconds,
                    CPU_INT32U   milli,
                    OS_OPT       opt,
                    OS_ERR      *p_err)
{
#if (OS_CFG_ARG_CHK_EN == DEF_ENABLED)
    CPU_BOOLEAN  opt_invalid;
    CPU_BOOLEAN  opt_non_strict;
#endif
    OS_OPT       opt_time;
    OS_RATE_HZ   tick_rate;
    OS_TICK      ticks;
#if (OS_CFG_TASK_TICK_EN == DEF_ENABLED)
    CPU_SR_ALLOC();
#endif



#ifdef OS_SAFETY_CRITICAL
    //p_err入参合法性判断
    if (p_err == (OS_ERR *)0) {
        OS_SAFETY_CRITICAL_EXCEPTION();
        return;
    }
#endif

#if (OS_CFG_CALLED_FROM_ISR_CHK_EN == DEF_ENABLED)
    //不能在ISR中调用
    if (OSIntNestingCtr > 0u) {
        *p_err = OS_ERR_TIME_DLY_ISR;
        return;
    }
#endif

#if (OS_CFG_INVALID_OS_CALLS_CHK_EN == DEF_ENABLED)
    //不能在内核运行前调用
    if (OSRunning != OS_STATE_OS_RUNNING) {
        *p_err = OS_ERR_OS_NOT_RUNNING;
        return;
    }
#endif

    //内核调度上锁时
    if (OSSchedLockNestingCtr > 0u) {
        *p_err = OS_ERR_SCHED_LOCKED;
        return;
    }

    opt_time = opt & OS_OPT_TIME_MASK;
    switch (opt_time) {
        case OS_OPT_TIME_DLY:
        case OS_OPT_TIME_TIMEOUT:
        case OS_OPT_TIME_PERIODIC:
            if (milli == 0u) {
                if (seconds == 0u) {
                    if (minutes == 0u) {
                        if (hours == 0u) {
                            *p_err = OS_ERR_TIME_ZERO_DLY;
                            return;
                        }
                    }
                }
            }
            break;

        case OS_OPT_TIME_MATCH:
            break;

        default:
            *p_err = OS_ERR_OPT_INVALID;
            return;
    }

#if (OS_CFG_ARG_CHK_EN == DEF_ENABLED)
    opt_invalid = DEF_BIT_IS_SET_ANY(opt, ~OS_OPT_TIME_OPTS_MASK);
    if (opt_invalid == DEF_YES) {
    *p_err = OS_ERR_OPT_INVALID;
        return;
    }

    opt_non_strict = DEF_BIT_IS_SET(opt, OS_OPT_TIME_HMSM_NON_STRICT);
    if (opt_non_strict != DEF_YES) {
        if (milli   > 999u) {
            *p_err = OS_ERR_TIME_INVALID_MILLISECONDS;
            return;
        }
        if (seconds > 59u) {
            *p_err = OS_ERR_TIME_INVALID_SECONDS;
            return;
        }
        if (minutes > 59u) {
            *p_err = OS_ERR_TIME_INVALID_MINUTES;
            return;
        }
        if (hours   > 99u) {
            *p_err = OS_ERR_TIME_INVALID_HOURS;
            return;
        }
    } else {
        if (minutes > 9999u) {
            *p_err = OS_ERR_TIME_INVALID_MINUTES;
            return;
        }
        if (hours   > 999u) {
            *p_err = OS_ERR_TIME_INVALID_HOURS;
            return;
        }
    }
#endif


    tick_rate = OSCfg_TickRate_Hz;

    //换算时间成Tick
    ticks     = ((((OS_TICK)hours * (OS_TICK)3600u) + ((OS_TICK)minutes * (OS_TICK)60u) + (OS_TICK)seconds) * tick_rate)
            + ((tick_rate * ((OS_TICK)milli + ((OS_TICK)500u / tick_rate))) / (OS_TICK)1000u);

    //如果延时超过一个tick
    if (ticks > 0u) {
#if (OS_CFG_TASK_TICK_EN == DEF_ENABLED)
        CPU_CRITICAL_ENTER();

        //将让如插入到OSTickListDly中
        OS_TickListInsertDly(OSTCBCurPtr,
                            ticks,
                            opt_time,
                            p_err);
        if (*p_err != OS_ERR_NONE) {
            CPU_CRITICAL_EXIT();
            return;
        }

        OS_TRACE_TASK_DLY(ticks);

        //从ReadyList中移除
        OS_RdyListRemove(OSTCBCurPtr);
        CPU_CRITICAL_EXIT();

        //引发一次调度
        OSSched();
#endif
        *p_err = OS_ERR_NONE;

    //没超过一个ticks
    } else {
        *p_err = OS_ERR_TIME_ZERO_DLY;
    }
}

其实和OSTimeDly基本相同,只不过把时分秒换算成Ticks

3. 从延时状态恢复OSTimeDlyResume

OSTimeDlyResume函数实现:

[os_time.c OSTimeDlyResume 函数]

void  OSTimeDlyResume (OS_TCB  *p_tcb,
                    OS_ERR  *p_err)
{
    CPU_SR_ALLOC();



#ifdef OS_SAFETY_CRITICAL
    //p_err入参合法性判断
    if (p_err == (OS_ERR *)0) {
        OS_SAFETY_CRITICAL_EXCEPTION();
        return;
    }
#endif

#if (OS_CFG_CALLED_FROM_ISR_CHK_EN == DEF_ENABLED)
    //不能在`ISR`中调用
    if (OSIntNestingCtr > 0u) {
        *p_err = OS_ERR_TIME_DLY_RESUME_ISR;
        return;
    }
#endif

#if (OS_CFG_ARG_CHK_EN == DEF_ENABLED)
    //p_tcb合法性判断
    if (p_tcb == (OS_TCB *)0) {
        *p_err = OS_ERR_TCB_INVALID;
        return;
    }
#endif

#if (OS_CFG_INVALID_OS_CALLS_CHK_EN == DEF_ENABLED)
    //不能在内核运行前调用
    if (OSRunning != OS_STATE_OS_RUNNING) {
        *p_err = OS_ERR_OS_NOT_RUNNING;
        return;
    }
#endif

    CPU_CRITICAL_ENTER();
    switch (p_tcb->TaskState) {
        //如果没有delay状态,返回出错
        case OS_TASK_STATE_RDY:
        case OS_TASK_STATE_PEND:
        case OS_TASK_STATE_PEND_TIMEOUT:
        case OS_TASK_STATE_SUSPENDED:
        case OS_TASK_STATE_PEND_SUSPENDED:
        case OS_TASK_STATE_PEND_TIMEOUT_SUSPENDED:
            CPU_CRITICAL_EXIT();
            *p_err = OS_ERR_TASK_NOT_DLY;
            break;

        //delay状态
        case OS_TASK_STATE_DLY:
            p_tcb->TaskState = OS_TASK_STATE_RDY;
#if (OS_CFG_TASK_TICK_EN == DEF_ENABLED)
            //如果TickList中移除
            OS_TickListRemove(p_tcb);
            //插入到ReadyList
            OS_RdyListInsert(p_tcb);
#endif
            CPU_CRITICAL_EXIT();
            *p_err = OS_ERR_NONE;
            break;

        //如果delay + suspended
        case OS_TASK_STATE_DLY_SUSPENDED:
            //状态改为suspended
            p_tcb->TaskState = OS_TASK_STATE_SUSPENDED;
#if (OS_CFG_TASK_TICK_EN == DEF_ENABLED)
            //只从TickList中移除,不放入ReadyList
            OS_TickListRemove(p_tcb);
#endif
            CPU_CRITICAL_EXIT();
            *p_err            = OS_ERR_TASK_SUSPENDED;
            break;

        default:
            CPU_CRITICAL_EXIT();
            *p_err = OS_ERR_STATE_INVALID;
            break;
    }

    //引发一次调度
    OSSched();
}

这个函数不能在ISR中调用,不能在内核运行前调用。如果没有delay,则返回出错。如果是只有delay状态,把任务从TickList中移除,放入到ReadyList。如果是delay + suspended,只从TickList中移除,不放回ReadyList。最后调用OSSched引发一次调度。

4. 时间戳的获取和设置

  1. OSTimeGet获取时间戳
  2. OSTimeSet设置时间戳
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值