自学内容网 自学内容网

μC/OS-Ⅱ源码学习(4)---信号量

        快速回顾

μC/OS-Ⅱ中的多任务

μC/OS-Ⅱ源码学习(1)---多任务系统的实现

μC/OS-Ⅱ源码学习(2)---多任务系统的实现(下)

μC/OS-Ⅱ源码学习(3)---事件模型

        本文进一步解析事件模型中,信号量类型的函数源码。

         先回顾一下上一节的通用事件控制块类型OS_EVENT

//ucos_ii.h
typedef struct os_event {
    INT8U    OSEventType;      /* 事件类型,有六种(其中一种是UNUSED) */
    void    *OSEventPtr;       /* OSEventPtr是一个多用途的指针,当作为链表时,可以指向下一个控制块;当作为具体的事件控制块时,指向具体的事件结构,如OS_Q。信号量不使用该指针 */  
    INT16U   OSEventCnt;       /* 信号量计数器,其它事件类型不使用该成员 */
    OS_PRIO  OSEventGrp;       /* 等待信号的任务优先级组,和OSEventTbl共同组成”事件等待表“ */
    OS_PRIO  OSEventTbl[OS_EVENT_TBL_SIZE];  /* 等待信号的组内优先级 */

#if OS_EVENT_NAME_EN > 0u
    INT8U   *OSEventName;      //事件名称
#endif
} OS_EVENT;

信号量的创建

        信号量的创建函数为OSSemCreate(cnt),传入的cnt会作为初始值填入OSEventCnt成员,由于信号量没有自己的专属结构,因此OSEventPtr指向空。

//os_sem.c
OS_EVENT  *OSSemCreate (INT16U cnt)
{
    OS_EVENT  *pevent;
#if OS_CRITICAL_METHOD == 3u            /* 初始化临界区变量 */
    OS_CPU_SR  cpu_sr = 0u;
#endif



#ifdef OS_SAFETY_CRITICAL_IEC61508       //IEC标准,可以忽略
    if (OSSafetyCriticalStartFlag == OS_TRUE) {
        OS_SAFETY_CRITICAL_EXCEPTION();
    }
#endif

    if (OSIntNesting > 0u) {        /* 不能在中断中创建信号量         */
        return ((OS_EVENT *)0);
    }
    OS_ENTER_CRITICAL();
    pevent = OSEventFreeList;       /* 从空白事件控制块链表中取一个 */
    if (OSEventFreeList != (OS_EVENT *)0) {       /* 如果空白事件控制块链表还有剩余,则将链表头指向下一个,以便下一次获取 */
        OSEventFreeList = (OS_EVENT *)OSEventFreeList->OSEventPtr;
    }
    OS_EXIT_CRITICAL();
    if (pevent != (OS_EVENT *)0) {          /* 只有非空的事件控制块才能填装 */
        pevent->OSEventType    = OS_EVENT_TYPE_SEM;
        pevent->OSEventCnt     = cnt;         /* 填装传入的信号量初始值 */
        pevent->OSEventPtr     = (void *)0;       /* 内部指针指向空,断开和原链表的联系,信号量也没有自己的事件结构需要链接 */
#if OS_EVENT_NAME_EN > 0u
        pevent->OSEventName    = (INT8U *)(void *)"?";
#endif
        OS_EventWaitListInit(pevent);       /* 初始化等待任务表,就是把OSEventGrp和OSEventTbl清零 */
    }
    return (pevent);
}
 

信号量的操作

        信号量的操作有很多种,最常用的就是等待(Pend)和释放(Post)了,接下来依次探究各个信号量操作函数源码。

OSSemPend(OS_EVENT *pevent, INT32U timeout, INT8U *perr)

        先描述该函数的作用:

①任务使用该语句时,表明需要等待信号量pevent,当信号量计数器大于0时,直接减1并返回继续执行任务;当计数器等于0时,则要等待其它任务释放信号量。

②如果给定了timeout不为0,则若timeout减至0时都没有取得信号量,直接返回执行;若传入的timeout为0,则一直等待直到获得信号量。

//os_sem.c
void  OSSemPend (OS_EVENT  *pevent,
                 INT32U     timeout,
                 INT8U     *perr)
{
#if OS_CRITICAL_METHOD == 3u       /* 初始化临界区变量 */
    OS_CPU_SR  cpu_sr = 0u;
#endif



#ifdef OS_SAFETY_CRITICAL        //IEC标准,可以忽略
    if (perr == (INT8U *)0) {
        OS_SAFETY_CRITICAL_EXCEPTION();
    }
#endif

#if OS_ARG_CHK_EN > 0u
    if (pevent == (OS_EVENT *)0) {       /* 传入的信号量不能为空 */
        *perr = OS_ERR_PEVENT_NULL;
        return;
    }
#endif
    if (pevent->OSEventType != OS_EVENT_TYPE_SEM) {      /* 传入的是事件类型必须是信号量 */
        *perr = OS_ERR_EVENT_TYPE;
        return;
    }
    if (OSIntNesting > 0u) {        /* 不能在中断中调用 */
        *perr = OS_ERR_PEND_ISR;
        return;
    }
    if (OSLockNesting > 0u) {        /* 当调度器上锁时不能调用 */
        *perr = OS_ERR_PEND_LOCKED;
        return;
    }
    OS_ENTER_CRITICAL();
    if (pevent->OSEventCnt > 0u) {        /* 信号量计数器大于0 */
        pevent->OSEventCnt--;         /* 计数器减1,并返回继续执行任务 */
        OS_EXIT_CRITICAL();
        *perr = OS_ERR_NONE;
        return;
    }
   
    /* 计数器为0时,则必须等待其它任务释放信号量 */
    OSTCBCur->OSTCBStat     |= OS_STAT_SEM;       /* 当前任务状态变为“等待信号量” */
    OSTCBCur->OSTCBStatPend  = OS_STAT_PEND_OK;       //任务Pending状态为OK(只要没出问题都是OK)
    OSTCBCur->OSTCBDly       = timeout;
    OS_EventTaskWait(pevent);        /* 将任务和事件的等待双向绑定,后面会具体展开 */
    OS_EXIT_CRITICAL();
    OS_Sched();             /* 找到高优先级任务并执行上下文切换,之后的代码将延期执行 */
    OS_ENTER_CRITICAL();    //再次回到这,只能是由以下三种原因引起
    switch (OSTCBCur->OSTCBStatPend) {        /* 检查任务的Pend状态,查看任务就绪原因 */
        case OS_STAT_PEND_OK:        //成功获取了信号量,导致回到OK状态
             *perr = OS_ERR_NONE;
             break;

        case OS_STAT_PEND_ABORT:     /* 调用了OSSemPendAbort()导致取消了Pend状态 */
             *perr = OS_ERR_PEND_ABORT;        
             break;

        case OS_STAT_PEND_TO:        /* 设定的延时超时 */
        default:
             OS_EventTaskRemove(OSTCBCur, pevent);    //将事件的等待表上的当前任务优先级移除
             *perr = OS_ERR_TIMEOUT;                  
             break;
    }
    OSTCBCur->OSTCBStat          =  OS_STAT_RDY;      /* 将任务状态设置为就绪 */
    OSTCBCur->OSTCBStatPend      =  OS_STAT_PEND_OK;  /* Pending状态OK */
    OSTCBCur->OSTCBEventPtr      = (OS_EVENT  *)0;    /* 清除任务等待事件 */
#if (OS_EVENT_MULTI_EN > 0u)
    OSTCBCur->OSTCBEventMultiPtr = (OS_EVENT **)0;    //如果设置了多重事件等待,则都清除
#endif
    OS_EXIT_CRITICAL();
}

        当执行OS_Sched()执行上下文切换后,后面的代码就不会立即执行了,而是等待任务再次就绪(可能是信号量大于0,或调用OSSemPendAbort()取消等待,也可能是等待超时)并被别的任务执行OS_Sched()调度后才能回到该处继续执行。

        这里面还涉及到两个关键函数,第一个是链接任务和事件的函数OS_EventTaskWait(),发生在任务开始等待事件时,将任务等待的事件控制块记录在TCB内,并将事件等待表中对应任务的优先级置1。在这之后,将优先级就绪表中的任务对应优先级清除(个人觉得这最后一步可以另外做个函数调用,因为和上面的操作关联性不高)。

//os_core.c
void  OS_EventTaskWait (OS_EVENT *pevent)
{
    INT8U  y;


    OSTCBCur->OSTCBEventPtr               = pevent;      /* 在任务TCB中存储等待的事件控制块指针 */

    pevent->OSEventTbl[OSTCBCur->OSTCBY] |= OSTCBCur->OSTCBBitX;    /* 将任务优先级记录到事件等待表中,包括优先级组和组内优先级 */
    pevent->OSEventGrp                   |= OSTCBCur->OSTCBBitY;

    /* 将优先级就绪表中的对应任务优先级清除,即取消就绪状态 */
    y             =  OSTCBCur->OSTCBY;
    OSRdyTbl[y]  &= (OS_PRIO)~OSTCBCur->OSTCBBitX;
    if (OSRdyTbl[y] == 0u) {    
        OSRdyGrp &= (OS_PRIO)~OSTCBCur->OSTCBBitY;
    }
}

        另一个是取消链接函数OS_EventTaskRemove():发生在等待事件超时,将事件等待表中对应任务的优先级清除。这里只有事件对任务的单向解绑定,没有任务对事件的解绑,和上面的双向绑定有出入,同时也没有后面优先级就绪表的操作。这是因为很多操作都在系统Tick中断中进行了,显得和绑定的函数不成对。

//os_core.c
void  OS_EventTaskRemove (OS_TCB   *ptcb,
                          OS_EVENT *pevent)
{
    INT8U  y;

    y                       =  ptcb->OSTCBY;
    pevent->OSEventTbl[y]  &= (OS_PRIO)~ptcb->OSTCBBitX;    /* 将事件等代表中的对应任务优先级清除 */
    if (pevent->OSEventTbl[y] == 0u) {
        pevent->OSEventGrp &= (OS_PRIO)~ptcb->OSTCBBitY;
    }
}

OSSemAccept(OS_EVENT *pevent)

        功能描述:获取信号量并执行,无论信号量是否大于0,都立即返回(返回-1后的信号量计数器),不会进入等待。当发生错误时(如事件为空或非信号量类型),返回0。

//os_sem.c
INT16U  OSSemAccept (OS_EVENT *pevent)
{
    INT16U     cnt;
#if OS_CRITICAL_METHOD == 3u         /* 初始化临界值变量 */
    OS_CPU_SR  cpu_sr = 0u;
#endif

#if OS_ARG_CHK_EN > 0u
    if (pevent == (OS_EVENT *)0) {        /* 检查信号量不为空 */
        return (0u);
    }
#endif
    if (pevent->OSEventType != OS_EVENT_TYPE_SEM) {     /* 检查事件类型必须为信号量 */
        return (0u);
    }
    OS_ENTER_CRITICAL();
    cnt = pevent->OSEventCnt;
    if (cnt > 0u) {           /* 检查信号量计数器是否大于0,大于0就减1 */
        pevent->OSEventCnt--;          
    }
    OS_EXIT_CRITICAL();
    return (cnt);       /*返回减1后的信号量计数器 */
}

OSSemPendAbort(OS_EVENT *pevent, INT8U opt, INT8U *perr)

        功能描述:取消任务对pevent事件的等待,可选项opt有两种:

//ucos_ii.h
#define  OS_PEND_OPT_NONE         0u  /* 就绪一个最高优先级的等待任务 */
#define  OS_PEND_OPT_BROADCAST    1u  /* 就绪所有等待该事件的任务 */

         函数最终返回恢复的任务数量。

//os_sem.c
INT8U  OSSemPendAbort (OS_EVENT  *pevent,
                       INT8U      opt,
                       INT8U     *perr)
{
    INT8U      nbr_tasks;
#if OS_CRITICAL_METHOD == 3u      /* 初始化临界区变量 */
    OS_CPU_SR  cpu_sr = 0u;
#endif

#ifdef OS_SAFETY_CRITICAL
    if (perr == (INT8U *)0) {
        OS_SAFETY_CRITICAL_EXCEPTION();
    }
#endif

#if OS_ARG_CHK_EN > 0u
    if (pevent == (OS_EVENT *)0) {         /* 事件不能为空 */
        *perr = OS_ERR_PEVENT_NULL;
        return (0u);
    }
#endif
    if (pevent->OSEventType != OS_EVENT_TYPE_SEM) {     /* 事件类型必须是信号量 */
        *perr = OS_ERR_EVENT_TYPE;
        return (0u);
    }
    OS_ENTER_CRITICAL();
    if (pevent->OSEventGrp != 0u) {       /* 事件等待表非空才需要操作,否则直接返回 */
        nbr_tasks = 0u;
        switch (opt) {
            case OS_PEND_OPT_BROADCAST:        /* 取消所有正在等待的任务 */
                 while (pevent->OSEventGrp != 0u) {    /* 将所有等待信号量的任务调整为就绪状态 */
                     (void)OS_EventTaskRdy(pevent, (void *)0, OS_STAT_SEM, OS_STAT_PEND_ABORT);
                     nbr_tasks++;
                 }
                 break;

            case OS_PEND_OPT_NONE:     /* 就绪一个最高优先级的等待任务 */
            default:               
                 (void)OS_EventTaskRdy(pevent, (void *)0, OS_STAT_SEM, OS_STAT_PEND_ABORT);
                 nbr_tasks++;
                 break;
        }
        OS_EXIT_CRITICAL();
        OS_Sched();                                   /* Find HPT ready to run                         */
        *perr = OS_ERR_PEND_ABORT;
        return (nbr_tasks);
    }
    OS_EXIT_CRITICAL();
    *perr = OS_ERR_NONE;
    return (0u);                                      /* No tasks waiting on semaphore                 */
}

        这里面涉及一个重要操作OS_EventTaskRdy(),该函数的作用是从等待pevent事件的所有任务中,就绪一个最高优先级的任务(即HPTHighest Priority Task),并返回该任务的优先级。

//os_core.c
INT8U  OS_EventTaskRdy (OS_EVENT  *pevent,
                        void      *pmsg,
                        INT8U      msk,
                        INT8U      pend_stat)
{
    OS_TCB   *ptcb;
    INT8U     y;
    INT8U     x;
    INT8U     prio;
#if OS_LOWEST_PRIO > 63u
    OS_PRIO  *ptbl;
#endif

#if OS_LOWEST_PRIO <= 63u      //任务数量小于64个,使用8位OS_PRIO
    y    = OSUnMapTbl[pevent->OSEventGrp];       /* 找到等待事件的最高优先级任务 */
    x    = OSUnMapTbl[pevent->OSEventTbl[y]];
    prio = (INT8U)((y << 3u) + x);              /* 还原任务的原始优先级(0-254) */
#else       //任务数量大于63个,使用16位OS_PRIO
    if ((pevent->OSEventGrp & 0xFFu) != 0u) {
        y = OSUnMapTbl[ pevent->OSEventGrp & 0xFFu];
    } else {
        y = OSUnMapTbl[(OS_PRIO)(pevent->OSEventGrp >> 8u) & 0xFFu] + 8u;
    }
    ptbl = &pevent->OSEventTbl[y];
    if ((*ptbl & 0xFFu) != 0u) {
        x = OSUnMapTbl[*ptbl & 0xFFu];
    } else {
        x = OSUnMapTbl[(OS_PRIO)(*ptbl >> 8u) & 0xFFu] + 8u;
    }
    prio = (INT8U)((y << 4u) + x);
#endif

    ptcb                  =  OSTCBPrioTbl[prio];      /* 找到该优先级对应的TCB */
    ptcb->OSTCBDly        =  0u;       /* 等待延时归零,防止OSTimeTick()恢复任务 */
#if ((OS_Q_EN > 0u) && (OS_MAX_QS > 0u)) || (OS_MBOX_EN > 0u)
    ptcb->OSTCBMsg        =  pmsg;      /* 如果使用了队列或邮箱,则将传入的消息存到该任务TCB中 */
#else
    pmsg                  =  pmsg;      /* 防止没使用到pmsg导致编译告警 */
#endif
    ptcb->OSTCBStat      &= (INT8U)~msk;      /* 清除任务状态,msk在这里是OS_STAT_SEM */
    ptcb->OSTCBStatPend   =  pend_stat;      /* 设置pend状态为OS_STAT_PEND_ABORT */
                                                        /* See if task is ready (could be susp'd)      */
    if ((ptcb->OSTCBStat &   OS_STAT_SUSPEND) == OS_STAT_RDY) {
        OSRdyGrp         |=  ptcb->OSTCBBitY;     /* 任务没有挂起,则进入就绪,将优先级就绪表相应位置1 */
        OSRdyTbl[y]      |=  ptcb->OSTCBBitX;
    }

    OS_EventTaskRemove(ptcb, pevent);     /* 将事件等待表中的对应任务优先级清零(解除绑定) */
#if (OS_EVENT_MULTI_EN > 0u)
    if (ptcb->OSTCBEventMultiPtr != (OS_EVENT **)0) {   /* 移除多重等待表中的任务优先级 */
        OS_EventTaskRemoveMulti(ptcb, ptcb->OSTCBEventMultiPtr);
        ptcb->OSTCBEventPtr       = (OS_EVENT  *)pevent;
    }
#endif

    return (prio);
}

OSSemPost(OS_EVENT *pevent)

        功能描述:释放一个传入的信号量(pevent计数器加1),如果有任务在等待,则执行上下文切换。

//os_sem.c
INT8U  OSSemPost (OS_EVENT *pevent)
{
#if OS_CRITICAL_METHOD == 3u       /* 初始化临界区变量 */
    OS_CPU_SR  cpu_sr = 0u;
#endif

#if OS_ARG_CHK_EN > 0u
    if (pevent == (OS_EVENT *)0) {       /* 事件不能为空 */
        return (OS_ERR_PEVENT_NULL);
    }
#endif
    if (pevent->OSEventType != OS_EVENT_TYPE_SEM) {    /* 事件类型必须是信号量 */
        return (OS_ERR_EVENT_TYPE);
    }
    OS_ENTER_CRITICAL();
    if (pevent->OSEventGrp != 0u) {       /* 检查是否有任务在等待该信号量 */
        /* 在等待该信号量的任务中就绪一个最高优先级的 */
        (void)OS_EventTaskRdy(pevent, (void *)0, OS_STAT_SEM, OS_STAT_PEND_OK);
        OS_EXIT_CRITICAL();
        OS_Sched();        /* 尝试执行上下文切换 */
        return (OS_ERR_NONE);
    }
    if (pevent->OSEventCnt < 65535u) {       /* 信号量上溢出判断 */
        pevent->OSEventCnt++;        /* 信号量计数器加1 */
        OS_EXIT_CRITICAL();
        return (OS_ERR_NONE);
    }
    OS_EXIT_CRITICAL();                               /* Semaphore value has reached its maximum       */
    return (OS_ERR_SEM_OVF);
}

        有一个和OSSemPend()对应的细节:

①在pend信号量时,如果信号量计数器大于0,则计数器直接减1,并继续执行。而有任务post时,如果没有任务在等待,则计数器直接加1,同样继续执行。

①在pend信号量的时候,如果信号量计数器为0,则直接阻塞等待,不会对计数器进行操作。当有任务post信号量时,如果有任务在等待,则直接切换上下文,同样不会对计数器进行操作。

OSSemSet(OS_EVENT *pevent, INT16U cnt, INT8U *perr)

        功能描述:手动设置信号量的计数器值。这一操作不是一定能成功的,只有当当前计数器值大于0或没有任务等待该信号量时,才能成功设置(这也是合理的,如果有任务正在苦苦等待该信号量,手动设置一个新值会让该任务立即就绪,从而影响了系统的执行时序。μC/OSⅡ不推荐强制修改,这个功能默认也不会开启)。

//os_sem.c
void  OSSemSet (OS_EVENT  *pevent,
                INT16U     cnt,
                INT8U     *perr)
{
#if OS_CRITICAL_METHOD == 3u       /* 初始化临界区变量 */
    OS_CPU_SR  cpu_sr = 0u;
#endif

#ifdef OS_SAFETY_CRITICAL
    if (perr == (INT8U *)0) {
        OS_SAFETY_CRITICAL_EXCEPTION();
    }
#endif

#if OS_ARG_CHK_EN > 0u
    if (pevent == (OS_EVENT *)0) {        /* 事件不能为空 */
        *perr = OS_ERR_PEVENT_NULL;
        return;
    }
#endif
    if (pevent->OSEventType != OS_EVENT_TYPE_SEM) {      /* 事件类型必须是信号量 */
        *perr = OS_ERR_EVENT_TYPE;
        return;
    }
    OS_ENTER_CRITICAL();
    *perr = OS_ERR_NONE;
    if (pevent->OSEventCnt > 0u) {       /* 如果信号量计数器大于0,直接设为传入值  */
        pevent->OSEventCnt = cnt;        
    } else {                                      
        if (pevent->OSEventGrp == 0u) {      /* 没有任务等待该信号量,也可以直接设为传入值 */
            pevent->OSEventCnt = cnt; 
        } else {      //有任务在等待该信号量,则暂时无法设置
            *perr              = OS_ERR_TASK_WAITING;
        }
    }
    OS_EXIT_CRITICAL();
}
#endif

信号量的删除

        信号量创建后一般是没必要删除的,μC/OSⅡ默认也不会开启删除功能,但为了逻辑的连贯性,这里也分析一下删除的源码OSSemDel()

        该函数支持传入选项:

//ucos_ii.h
#define  OS_DEL_NO_PEND    0u    //没有任务等待才删除,有任务等待则相当于什么都不做
#define  OS_DEL_ALWAYS     1u    //无论有没有任务等待,都立即删除,并将等待的任务重新就绪

        接下来看源码:

//os_sem.c
OS_EVENT  *OSSemDel (OS_EVENT  *pevent,
                     INT8U      opt,
                     INT8U     *perr)
{
    BOOLEAN    tasks_waiting;
    OS_EVENT  *pevent_return;
#if OS_CRITICAL_METHOD == 3u        /* 初始化临界区变量 */
    OS_CPU_SR  cpu_sr = 0u;
#endif

#ifdef OS_SAFETY_CRITICAL
    if (perr == (INT8U *)0) {
        OS_SAFETY_CRITICAL_EXCEPTION();
    }
#endif

#if OS_ARG_CHK_EN > 0u
    if (pevent == (OS_EVENT *)0) {       /* 事件不能为空 */
        *perr = OS_ERR_PEVENT_NULL;
        return (pevent);
    }
#endif
    if (pevent->OSEventType != OS_EVENT_TYPE_SEM) {      /* 事件必须是信号量类型 */
        *perr = OS_ERR_EVENT_TYPE;
        return (pevent);
    }
    if (OSIntNesting > 0u) {       /* 不能在中断内调用 */
        *perr = OS_ERR_DEL_ISR;                            
        return (pevent);
    }
    OS_ENTER_CRITICAL();
    if (pevent->OSEventGrp != 0u) {       /* 检查是否有任务等待该信号量 */
        tasks_waiting = OS_TRUE;
    } else {
        tasks_waiting = OS_FALSE;
    }
    switch (opt) {
        case OS_DEL_NO_PEND:      /* 只有在没有任务等待该信号量时,才进行删除 */
             if (tasks_waiting == OS_FALSE) {     //没有任务等待,则复位事件控制块数据
#if OS_EVENT_NAME_EN > 0u
                 pevent->OSEventName    = (INT8U *)(void *)"?";
#endif
                 pevent->OSEventType    = OS_EVENT_TYPE_UNUSED;
                 pevent->OSEventPtr     = OSEventFreeList;     /* 将事件控制块归还空白事件控制块链表 */
                 pevent->OSEventCnt     = 0u;
                 OSEventFreeList        = pevent;      /* 将链表头重新指向该归还的事件控制块 */
                 OS_EXIT_CRITICAL();
                 *perr                  = OS_ERR_NONE;
                 pevent_return          = (OS_EVENT *)0;     /* 返回空事件 */
             } else {     //有任务在等待,无法删除,返回信号本身
                 OS_EXIT_CRITICAL();
                 *perr                  = OS_ERR_TASK_WAITING;
                 pevent_return          = pevent;
             }
             break;

        case OS_DEL_ALWAYS:        /* 强制删除 */
             while (pevent->OSEventGrp != 0u) {       /* 将所有等待的任务重新就绪 */
                 (void)OS_EventTaskRdy(pevent, (void *)0, OS_STAT_SEM, OS_STAT_PEND_OK);
             }
#if OS_EVENT_NAME_EN > 0u
             pevent->OSEventName    = (INT8U *)(void *)"?";
#endif
             pevent->OSEventType    = OS_EVENT_TYPE_UNUSED;
             pevent->OSEventPtr     = OSEventFreeList;     /* 归还事件控制块,同上面操作 */
             pevent->OSEventCnt     = 0u;
             OSEventFreeList        = pevent;
             OS_EXIT_CRITICAL();
             if (tasks_waiting == OS_TRUE) {      /* 如果有事件等待该信号量,则尝试执行上下文切换 */
                 OS_Sched();       /* 找到最高优先级的就绪任务并执行 */
             }
             *perr                  = OS_ERR_NONE;
             pevent_return          = (OS_EVENT *)0;       /* 返回空事件 */
             break;

        default:
             OS_EXIT_CRITICAL();
             *perr                  = OS_ERR_INVALID_OPT;   //非法选项
             pevent_return          = pevent;     //返回事件本身
             break;
    }
    return (pevent_return);
}


原文地址:https://blog.csdn.net/sherlock_cp/article/details/144429603

免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!