/*$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是一個指向錯誤信息將被存放的地方的指針??赡艿腻e誤信息如下:
* 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循環*/
這一部分主要說的是:如果有準備好的事件,分析其事件類型(郵箱、信號量還是隊列),然后分別執行相應的操作。
這篇是該函數的一部分,下篇介紹另一部分。