多任务挂起函数,先附一张流程图:

/*$PAGE*/
/*
*********************************************************************************************************
*                                      PEND ON MULTIPLE EVENTS
*                                       多任务挂起
* Description: This function waits for multiple events.  If multiple events are ready at the start of the
*              pend call, then all available events are returned as ready.  If the task must pend on the
*              multiple events, then only the first posted or aborted event is returned as ready.
*描述:该功能是用来等待多个事件。如果在挂起调用开始时,多个事件已准备充分,那么这些事件被转化为就绪状态。
如果一个任务必须挂起多个事件,那么只将第一个准备好的事件转为就绪状态。
* Arguments  : pevents_pend  is a pointer to a NULL-terminated array of event control blocks to wait for.
*参数:                     --pevent_pend 是一个指向指针(1)的指针(2),(1)指针指向挂起的事件控制块数组;(2)指针指向(1)指针构成的数组。该数组用null作为结束
*              pevents_rdy   is a pointer to an array to return which event control blocks are available
*                            or ready.  The size of the array MUST be greater than or equal to the size
*                            of the 'pevents_pend' array, including terminating NULL.
*                           --pevents_rdy指向一个指针数组,也是指针(1)的指针(2),(1)指针指向可用或就绪的事件控制块数组;(2)指针指向(1)指针数组。(2)指针指向的数组的大小必须大于或等于pevents_pend指向的数组的大小(包括最后的null)。
*              pmsgs_rdy     is a pointer to an array to return messages from any available message-type
*                            events.  The size of the array MUST be greater than or equal to the size of
*                            the 'pevents_pend' array, excluding the terminating NULL.  Since NULL
*                            messages are valid messages, this array cannot be NULL-terminated.  Instead,
*                            every available message-type event returns its messages in the 'pmsgs_rdy'
*                            array at the same index as the event is returned in the 'pevents_rdy' array.
*                            All other 'pmsgs_rdy' array indices are filled with NULL messages.
*                           --pmsgs_rdy也是指针(1)的指针(2)。(1)指针指向消息数组;(2)指针指向(1)指针数组。该数组用来返回从信息类型事件获得的消息。数组的大小必须大于或等于pevents_pend指向数组的大小(除去最后的NULL)。由于null消息是无效的消息,因而这个数组不能是以null结束的。每个可用的信息类型的事件返回它在pmsgs_rdy数组中的消息。该消息与该事件的下标同步变化。所有其他pmsgs_rdy数组索引都用空消息填充
*              timeout       is an optional timeout period (in clock ticks).  If non-zero, your task will
*                            wait for the resources up to the amount of time specified by this argument.
*                            If you specify 0, however, your task will wait forever for the specified
*                            events or, until the resources becomes available (or the events occur).
*                           --timeout是一个可选择的超时片(时钟节拍),也就是请求资源的时间。如果超时,就进入睡眠状态。如果非0,任务将等待资源直到满足该参数指定的时间数。如果是0,任务将永远处于睡眠状态,除非有专门的事件或者可以获得资源(或该事件发生)
*              perr          is a pointer to where an error message will be deposited.  Possible error
*                            messages are:
*                           --perr是一个指向错误信息将被存放的地方的指针。可能的错误信息如下:
*                            OS_ERR_NONE         The call was successful and your task owns the resources
*                                                or, the events you are waiting for occurred; check the
*                                                'pevents_rdy' array for which events are available.--OS_ERR_NONE无错误:该调用时成功的,你的任务获得了资源或者正在等待的事件发生了;然后检测pevents_rdy数组,看哪个事件是准备就绪的。
*                            OS_ERR_PEND_ABORT   The wait on the events was aborted; check the
*                                                'pevents_rdy' array for which events were aborted.--OS_ERR_PEND_ABORT取消挂起事件:取消正在等待的事件:检测pevents_rdy数组,确定是哪个事件被取消
*                            OS_ERR_TIMEOUT      The events were not received within the specified
*                                                'timeout'.-- OS_ERR_TIMEOUT超时错:事件在规定时间片内没有被接收处理
*                            OS_ERR_PEVENT_NULL  If 'pevents_pend', 'pevents_rdy', or 'pmsgs_rdy' is a
*                                                NULL pointer.--OS_ERR_PEVENT_NULL空指针:pevents_pend,pevents_rdy,pmsgs_rdy为空指针
*                            OS_ERR_EVENT_TYPE   If you didn't pass a pointer to an array of semaphores,
*                                                mailboxes, and/or queues.--OS_ERR_EVENT_TYPE事件类型错:没有指针指向信号量、邮箱或者队列
*                            OS_ERR_PEND_ISR     If you called this function from an ISR and the result
*                                                would lead to a suspension.--OS_ERR_PEND_ISR中断:如果调用了该中断函数,就会引发一个中断
*                            OS_ERR_PEND_LOCKED  If you called this function when the scheduler is locked.
*                                               --OS_ERR_PEND_LOCKED挂起锁:调度程序被锁时调用该功能会引发错误
* Returns    : >  0          the number of events returned as ready or aborted.
*              == 0          if no events are returned as ready because of timeout or upon error.
*返回值:>0:当就绪或取消时返回的任务数量=0:由于超时或者以上的错误而无法准备就绪而导致没有返回的事件时,返回值为0
* Notes      : 1) a. Validate 'pevents_pend' array as valid OS_EVENTs :
*                        semaphores, mailboxes, queues
*                   --a:当OS_EVENT有效时(是信号量、邮箱或者队列),pevents_pend数组才有效
*                 b. Return ALL available events and messages, if any
*                   --b:如果有可用的事件和消息时,返回所有的事件和消息
*                 c. Add    current task priority as pending to   each events's wait list
*                      Performed in OS_EventTaskWaitMulti()
*                   --c:将当前挂起任务的优先级添加到每个事件的等待列表中。具体操作在OS_EventTaskWaitMulti()函数中执行
*                 d. Wait on any of multiple events
*                   --d:等待多事件的任何一个
*                 e. Remove current task priority as pending from each events's wait list
*                      Performed in OS_EventTaskRdy(), if events posted or aborted
*                   --e:如果事件延迟或被取消,将当前挂起任务的优先级从每个事件等待列表中移除。具体操作在OS_EventTaskRdy()函数中执行。
*                 f. Return any event posted or aborted, if any
*                      else
*                    Return timeout
*                   --f:如果有事件被取消或延迟,返回该事件,否则的话返回timeout
*              2) 'pevents_rdy' initialized to NULL PRIOR to all other validation or function handling in
*                 case of any error(s).--pevents_rdy在所有其他有效值或功能前初始化为null,以防出错。
*********************************************************************************************************
*/
/*$PAGE*/
#if ((OS_EVENT_EN) && (OS_EVENT_MULTI_EN > 0u))              /*如果可以生成事件并且可以生成多个事件*/
INT16U  OSEventPendMulti(OS_EVENT  **pevents_pend,          /*调用多个事件挂起函数(事件挂起指针、就绪事件指针、就绪消息指针、时间片、错误码指针)*/OS_EVENT  **pevents_rdy,                              void      **pmsgs_rdy,INT32U      timeout,INT8U      *perr)
{OS_EVENT  **pevents;                               /*指针的指针,最终指向事件控制块*/OS_EVENT   *pevent;                                   /*指针,指向事件控制块*/
#if ((OS_Q_EN > 0u) && (OS_MAX_QS > 0u))              /*如果允许生成队列并且最大队列数>0*/OS_Q       *pq;                                     /*指定一个指向队列的指针*/
#endifBOOLEAN     events_rdy;                               /*事件就绪*/INT16U      events_rdy_nbr;                         /*准备好的事件数目*/INT8U       events_stat;                            /*事件状态*/
#if (OS_CRITICAL_METHOD == 3u)                          /* Allocate storage for CPU status register中断类型为3    */OS_CPU_SR   cpu_sr = 0u;
#endif#ifdef OS_SAFETY_CRITICAL                             /*定义安全中断*/if (perr == (INT8U *)0) {                           /*如果错误信息为0号错误*/OS_SAFETY_CRITICAL_EXCEPTION();                  /*调用安全中断异常函数*/}
#endif#if (OS_ARG_CHK_EN > 0u)                               /*检查参数*/if (pevents_pend == (OS_EVENT **)0) {               /* Validate 'pevents_pend'有效化 pevents_pend */*perr = OS_ERR_PEVENT_NULL;                       /*pevents_pend为0时,将错误信息置为OS_ERR_PEVENT_NULL*/return (0u);                                    /*返回值为0*/}if (*pevents_pend == (OS_EVENT *)0) {              /* Validate 'pevents_pend'有效化*pevents_pend*/*perr = OS_ERR_PEVENT_NULL;                       /* *pevents_pend为0时,将错误信息置为OS_ERR_PEVENT_NULL*/return (0u);                                  /*返回值为0*/}if (pevents_rdy == (OS_EVENT **)0) {               /* Validate 'pevents_rdy'有效化pevents_rdy */*perr = OS_ERR_PEVENT_NULL;                     /*pevents_rdy为0时,将错误信息置为OS_ERR_PEVENT_NULL*/return (0u);                                 /*返回值为0*/}if (pmsgs_rdy == (void **)0) {                      /* Validate 'pmsgs_rdy'有效化pmsgs_rdy */*perr = OS_ERR_PEVENT_NULL;                        /*当pmsgs_rdy为0时,将错误信息设置为OS_ERR_PEVENT_NULL*/return (0u);                                 /*返回值为0*/}
#endif*pevents_rdy = (OS_EVENT *)0;                        /* Init array to NULL in case of errors将数组初始化为null以防错误 */pevents = pevents_pend;                               /*将pevents_pend指针赋值给pevents。此时pevents和pevents_pend的指向一样,指向指针数组*/pevent = *pevents;                                  /*将指针数组首地址下的指针赋值给pevent,此时pevent为指向事件控制块的指针*//*将首地址下的内容赋值给*/while (pevent != (OS_EVENT *)0) {                   /*当pevent不为0时,即有指向的事件控制块时*/switch (pevent->OSEventType) {                  /* Validate event block types有效化事件块类型,看此时pevent指向的事件类型*/
#if (OS_SEM_EN  > 0u)                                    /*如果允许生成信号量*/case OS_EVENT_TYPE_SEM:                            break;
#endif
#if (OS_MBOX_EN > 0u)                                    /*如果生成邮箱*/case OS_EVENT_TYPE_MBOX:break;
#endif
#if ((OS_Q_EN   > 0u) && (OS_MAX_QS > 0u))                /*如果允许生成队列并且队列最大数>0*/case OS_EVENT_TYPE_Q:break;
#endif
/*上面三个if下的情况:事件块类型为信号量、邮箱或者队列时,不做任何处理,跳出循环进行下一步*/case OS_EVENT_TYPE_MUTEX:                     /*如果是事件块类型互斥量或者是标志类型或者默认情况,将错误信息设置成错误事件类型OS_ERR_EVENT_TYPE,返回值为0*/case OS_EVENT_TYPE_FLAG:default:*perr = OS_ERR_EVENT_TYPE;return (0u);}pevents++;                                        /*指向指针数组的指针加1,看下一个事件控制块*/pevent = *pevents;                             /*找到事件控制块*/}if (OSIntNesting > 0u) {                           /* See if called from ISR ... 看是否是调用中断函数  */*perr = OS_ERR_PEND_ISR;                        /* ... can't PEND from an ISR 如果是,中断函数不能被挂起。错误信息置为OS_ERR_PEND_ISR*/return (0u);                                  /*返回值为0*/}if (OSLockNesting > 0u) {                           /* See if called with scheduler locked ...看调度程序是否调用了已加锁的函数*/*perr = OS_ERR_PEND_LOCKED;                     /* ... can't PEND when locked 不能将已上锁的函数挂起  */return (0u);                                    /*返回值为0*/}/*$PAGE*/OS_ENTER_CRITICAL();                             /*关中断*/events_rdy = OS_FALSE;                              /*将事件就绪标志设置为false,即没有事件准备好*/events_rdy_nbr = 0u;                                /*准备好的事件数目为0*/events_stat = OS_STAT_RDY;                           /*事件状态设置为就绪态*/pevents = pevents_pend;                              /*该行和下一行表示找到准备好的事件控制块*/pevent = *pevents;                                  while (pevent != (OS_EVENT *)0) {                   /* See if any events already available 看是否有事件是可获得的,即已经准备好。!=0说明有 */switch (pevent->OSEventType) {                   /*查看事件类型*/
#if (OS_SEM_EN > 0u)                                 /*如果允许生成信号量*/case OS_EVENT_TYPE_SEM:                        /*如果是信号量*/if (pevent->OSEventCnt > 0u) {         /* If semaphore count > 0, resource available; 如果信号量数量>0,资源也是可获得的*/pevent->OSEventCnt--;              /* ... decrement semaphore, 则将信号量数目减1... */*pevents_rdy++ = pevent;           /* ... and return available semaphore event 并且返回可用的信号量事件。将该事件控制块放到就绪事件数组中 */events_rdy = OS_TRUE;              /*将事件设置为就绪态*/*pmsgs_rdy++ = (void *)0;         /* NO message returned  for semaphores对于信号量没有信息可以返回,置为0,但是索引(指针)跟着一起变化,最上面的注释提到过 */events_rdy_nbr++;             /*就绪事件数量加1*/}else {events_stat |= OS_STAT_SEM;      /* Configure multi-pend for semaphore events将信号量事件设置为多事件挂起状态*/}break;
#endif#if (OS_MBOX_EN > 0u)                              /*允许生成邮箱*/case OS_EVENT_TYPE_MBOX:                  /*如果为邮箱类型*/if (pevent->OSEventPtr != (void *)0) { /* If mailbox NOT empty;邮箱不为空 ... *//* ... return available message,返回可获得的消息 ... */*pmsgs_rdy++ = (void *)pevent->OSEventPtr;/*将该消息地址(指针)放到消息就绪数组中*/pevent->OSEventPtr = (void *)0;     /*将指向消息的指针重新设置为0,即请求了一个邮箱,邮箱旧有非空态变为空*/*pevents_rdy++ = pevent;     /* ... and return available mailbox event并且返回可用的邮箱事件*/events_rdy = OS_TRUE;         /*将事件就绪标志设置为true*/events_rdy_nbr++;          /*就绪事件数目加1*/}else {events_stat |= OS_STAT_MBOX;      /* Configure multi-pend for mailbox events 邮箱事件的多事件挂起状态    */}break;
#endif#if ((OS_Q_EN > 0u) && (OS_MAX_QS > 0u))        /*如果允许生成队列并且最大队列数>0*/case OS_EVENT_TYPE_Q:                   /*如果事件类型是队列*/pq = (OS_Q *)pevent->OSEventPtr;   /*事件控制块中的事件指针强制转化为队列类型*/if (pq->OSQEntries > 0u) {             /* If queue NOT empty; 队列不为空 ... *//* ... return available message,返回可用的消息,即把队列的消息保存在pmsgs_rdy数组中*/*pmsgs_rdy++ = (void *)*pq->OSQOut++;if (pq->OSQOut == pq->OSQEnd) {    /* If OUT ptr at queue end, ... */pq->OSQOut = pq->OSQStart;    /* ... wrap   to queue start队列的链表要将首尾连接起来*/}pq->OSQEntries--;                  /* Update number of queue entries 队列数量减一:请求了一个队列,队列的数量就要减1 */*pevents_rdy++ = pevent;            /* ... and return available queue event返回可用的队列事件*/events_rdy = OS_TRUE;          /*将事件就绪标志设置为true*/events_rdy_nbr++;               /*将就绪事件数量加1*/}else {events_stat |= OS_STAT_Q;         /* Configure multi-pend for queue events队列事件设置为多事件挂起状态 */}break;
#endifcase OS_EVENT_TYPE_MUTEX:             /*如果事件类型是互斥量或者标志量或默认情况*/case OS_EVENT_TYPE_FLAG:default:OS_EXIT_CRITICAL();                 /*开中断*/*pevents_rdy = (OS_EVENT *)0;           /* NULL terminate return event array将null返回到事件数组 *///因为是先保存再加,所以出现错误后不会有后续判断,所以这里就不用++*perr = OS_ERR_EVENT_TYPE;           /*将错误信息置为OS_ERR_EVENT_TYPE*/return (events_rdy_nbr);            /*返回就绪事件数*/}pevents++;                                /*指针后移,进行下一个事件的判断*/pevent = *pevents;}if (events_rdy == OS_TRUE) {                       /* Return any events already available 如果事件就绪标志为true*/
*pevents_rdy = (OS_EVENT *)0;                  /* NULL terminate return event array所有的事件都判断完了补上一个 (OS_EVENT *)0的结束标志 */
OS_EXIT_CRITICAL();/*关中断*/
*perr = OS_ERR_NONE;/*将错误中断设置为OS_ERR_NONE*/
return (events_rdy_nbr);/*返回就绪事件的数量*/
}/* Otherwise, must wait until any event occurs 否则的话,就必须等待直到任何一个事件发生,就会一直进行上面的while循环*/
这一部分主要说的是:如果有准备好的事件,分析其事件类型(邮箱、信号量还是队列),然后分别执行相应的操作。
这篇是该函数的一部分,下篇介绍另一部分。

OS_CORE.C(2)相关推荐

  1. OS_CORE.C(11)

    OS_SchedNew(void)找到将要运行的最高优先级任务函数 和任务调度函数OS_Sched(void): /* **************************************** ...

  2. OS_CORE.C(10)

    今天看os_core.c文件中的各种初始化函数. OS_EventWaitListInit(OS_EVENT *pevent)初始化事件控制块的等待列表: /*$PAGE*/ /*2018/2/8 * ...

  3. Error: L6406E: No space in execution regions with .ANY selector matching os_core.o(.bss).

    试验原因 正在移植ucosii. 移植前的环境是STM32F103VE + lwip2.1.2 在ucosii_v2.92.07文件迁移进工程后, 可以编译过. 这时要修改启动文件 startup_s ...

  4. OS_CORE.C(总结)

    在内核的功能模块中,重点函数为: static  void  OS_InitEventList(void);/*初始化事件列表*/ static  void  OS_InitMisc(void);/* ...

  5. OS_CORE.C(9)

    本篇介绍以下几个函数: OSVersion()获得版本号函数. OS_Dummy()虚拟函数. OS_EventTaskRdy (OS_EVENT *pevent, void *msg, INT8U ...

  6. OS_CORE.C(8)

    本篇介绍的是OSStart()函数和OSStatInit()函数和OSTimeTick()函数. OSStart()多任务开始函数: /*$PAGE*/ /* ******************** ...

  7. OS_CORE.C(7)

    本篇介绍的是调度器的上锁和解锁: 调度器上锁函数OSSchedlock()的功能是用于禁止任务调度,使任务保持对CPU的控制权. 调度器开锁函数OSSchedUnlock()的功能是解除对任务调度的禁 ...

  8. OS_CORE.C(6)

    先介绍一下优先级反转的相关知识: 优先级翻转是当一个高优先级任务通过信号量机制访问共享资源时,该信号量已被一低优先级任务占有,因此造成高优先级任务被许多具有较低优先级任务阻塞,实时性难以得到保证. 例 ...

  9. OS_CORE.C(5)

    /*$PAGE*/ /* *************************************************************************************** ...

  10. OS_CORE.C(4)

    /*$PAGE*/ /* *************************************************************************************** ...

最新文章

  1. Canvas入门-利用Canvas绘制好玩的电子时钟
  2. mysql出现ERROR1698(28000):Access denied for user root@localhost错误解决方法
  3. 让 Netty “榨干” 你的CPU!
  4. python【蓝桥杯vip练习题库】ADV-105 不同单词个数统计(集合)
  5. MailScanner相关规则设置
  6. android面试题总结加强
  7. 【原创】user.id字段
  8. aspnet_regsql在哪里 怎么运行它 以及功能介绍
  9. apk 反编译_APK反编译与回编译修改包名实现分身
  10. 清华大学 计算机 林伟,研究人员
  11. FreeMarker模板文件的组成(2)
  12. VC窗口形状的绘制---SetWindowRgn
  13. notepad设置中文
  14. redis源码剖析(四)跳表
  15. mysql工作表格制作教程_Access制作复杂报表
  16. Bootstrap让内容块居中
  17. vue项目中npm install初始化报错以及‘cross-env’ 不是内部或外部命令问题
  18. od send断点 下_Win7 od下send断点
  19. linux sed
  20. netstat -an|awk '/^tcp/ {++s[$NF]} END {for( a in s) {print a,s[a]}}'

热门文章

  1. PHP Fatal error: Allowed memory size of 134217728 bytes exhausted (tried to allocate 8192 bytes)
  2. word下设置多个起始页面
  3. window 命令行大全
  4. 听说你,对薪酬待遇不太满意。。。
  5. 软件开发中的开源协议详解!
  6. 掌握这 11 个方法论,搞定一场完美技术面试!
  7. Why Spring Boot
  8. 初识Kubernetes
  9. websocket导致spring boot 项目单元测试启动失败的问题解决
  10. 区分TTL、MSL、RTT