這個函數(shù)是請求信號量,郵箱,消息隊列的,但是對互斥信號量和標志不起作用。
#if ((OS_EVENT_EN) && (OS_EVENT_MULTI_EN > 0u))
INT16U OSEventPendMulti (OS_EVENT **pevents_pend,//掛起的事件組(需要請求資源)
OS_EVENT **pevents_rdy, //就緒的事件組
void **pmsgs_rdy, //保存請求中返回的信息
INT32U timeout, //請求資源的時間,如果超時任務(wù)進入休眠態(tài)
INT8U *perr)
{
OS_EVENT **pevents;
OS_EVENT *pevent;
#if ((OS_Q_EN > 0u) && (OS_MAX_QS > 0u))
OS_Q *pq; //如果使用隊列且最大隊列控制塊數(shù)大于0則申請一個隊列控制塊指針
#endif
BOOLEAN events_rdy; //是否有準備好的事件標志
INT16U events_rdy_nbr; //準備好的事件數(shù)
INT8U events_stat; //事件狀態(tài)
#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
//驗證各個參數(shù)的有效性
#if (OS_ARG_CHK_EN > 0u)
if (pevents_pend == (OS_EVENT **)0) {
*perr = OS_ERR_PEVENT_NULL;
return (0u);
}
if (*pevents_pend == (OS_EVENT *)0) {
*perr = OS_ERR_PEVENT_NULL;
return (0u);
}
if (pevents_rdy == (OS_EVENT **)0) {
*perr = OS_ERR_PEVENT_NULL;
return (0u);
}
if (pmsgs_rdy == (void **)0) {
*perr = OS_ERR_PEVENT_NULL;
return (0u);
}
#endif
//初始化指向就緒事件數(shù)組的指針為NULL
*pevents_rdy = (OS_EVENT *)0;
//pevents指向掛起等待的事件組,已經(jīng)處于就緒態(tài)的事件組是不需要再判斷的,pevent指向該事件組中的事件.
pevents = pevents_pend;
pevent = *pevents;
//對事件組中的所有事件進行類型檢查
while (pevent != (OS_EVENT *)0) {
switch (pevent->OSEventType) {
#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))
case OS_EVENT_TYPE_Q:
break;
#endif
case OS_EVENT_TYPE_MUTEX:
case OS_EVENT_TYPE_FLAG:
default:
*perr = OS_ERR_EVENT_TYPE;
return (0u);
}
pevents++; //即數(shù)組地址+1
pevent = *pevents;//指向下一個元素
}
//不能在中斷程序中調(diào)用
if (OSIntNesting > 0u) {
*perr = OS_ERR_PEND_ISR;
return (0u);
}
//任務(wù)被鎖住也是不能掛起的
if (OSLockNesting > 0u) {
*perr = OS_ERR_PEND_LOCKED;
return (0u);
}
OS_ENTER_CRITICAL(); //進入中斷沿
events_rdy = OS_FALSE; //事件就緒標志初始化為0
events_rdy_nbr = 0u; //就緒事件數(shù)初始化為0
events_stat = OS_STAT_RDY; //事件狀態(tài)初始化為就緒態(tài)
pevents = pevents_pend; //pevents指向掛起等待的事件組 pevent指向事件組中的事件
pevent = *pevents;
while (pevent != (OS_EVENT *)0) { //當最后一個元素值為(OS_EVENT *)0時等待事件組都判斷完了
switch (pevent->OSEventType) { //對事件組中請求特定資源的事件做特定處理
#if (OS_SEM_EN > 0u)
case OS_EVENT_TYPE_SEM: //信號量事件,信號量大于0說明資源是可用的
if (pevent->OSEventCnt > 0u) {
pevent->OSEventCnt--;
//請求得到滿足,可用的信號量數(shù)就減少了所以要--
*pevents_rdy++ = pevent;
//這個事件進入就緒事件表
events_rdy = OS_TRUE;
//標志一下有事件就緒了
*pmsgs_rdy++ = (void *)0;
//信號量沒有返回消息
events_rdy_nbr++;
//就緒的事件數(shù)加1
} else {
events_stat |= OS_STAT_SEM;
//請求失敗則標記為事件組等待信號量
}
break;
#endif
#if (OS_MBOX_EN > 0u)
case OS_EVENT_TYPE_MBOX://是郵箱事件如果郵箱有東西則請求得到滿足
if (pevent->OSEventPtr != (void *)0) { *pmsgs_rdy++=(void *)pevent->OSEventPtr;
//把郵箱的消息地址保存在message_ready數(shù)組中
pevent->OSEventPtr = (void *)0;
//請求了一個郵箱郵箱就由非空狀態(tài)變空
*pevents_rdy++=pevent;
//這個事件進入就緒態(tài)
events_rdy=OS_TRUE;
//標志一下有事件就緒了
events_rdy_nbr++;
//準備好的事件數(shù)加1
} else {
events_stat |= OS_STAT_MBOX;
//請求郵箱失敗標記事件組等待郵箱
}
break;
#endif
#if ((OS_Q_EN > 0u) && (OS_MAX_QS > 0u))
case OS_EVENT_TYPE_Q: //如果是隊列事件
pq = (OS_Q *)pevent->OSEventPtr;//pq指向隊列事件指針
if (pq->OSQEntries > 0u) { //如果隊列非空
*pmsgs_rdy++ = (void *)*pq->OSQOut++;
//把隊列的消息保存在pmsgs_rdy的數(shù)組中
if (pq->OSQOut == pq->OSQEnd) {
pq->OSQOut = pq->OSQStart;
} //隊列的鏈表要把首尾連接起來
pq->OSQEntries--;
//請求了一個隊列隊列中消息就減少了(隊列是鏈表,其中一塊少了即入口少了)
*pevents_rdy++ = pevent;
//請求得到允許事件進入就緒態(tài)
events_rdy = OS_TRUE; //標志一下有事件就緒了
events_rdy_nbr++; //就緒事件數(shù)加1
} else {
events_stat |= OS_STAT_Q; }
//請求隊列未得到允許則標志事件組狀態(tài)為等待隊列
break;
#endif
case OS_EVENT_TYPE_MUTEX:
case OS_EVENT_TYPE_FLAG:
//對互斥信號量事件和標志事件則不做處理
default:
//如果都不是這些事件類型則退出中斷沿并返回事件類型錯誤
OS_EXIT_CRITICAL();
*pevents_rdy = (OS_EVENT *)0;//這里用這個(OS_EVENT *)0返回空的消息
//因為是先保存再加所以出現(xiàn)錯誤不會有后續(xù)判斷這里就不用++
*perr= OS_ERR_EVENT_TYPE;
return (events_rdy_nbr); //返回就緒的事件數(shù)
}
pevents++;
pevent = *pevents;
//對事件組中的每一個事件做判斷
}
if ( events_rdy == OS_TRUE) {
*pevents_rdy = (OS_EVENT *)0;
//所有的事件都判斷完了補上一個 (OS_EVENT *)0的結(jié)束標志
OS_EXIT_CRITICAL();
*perr = OS_ERR_NONE;
return (events_rdy_nbr); //返回事件的就緒數(shù)(調(diào)用這個函數(shù)的任務(wù)繼續(xù)運行)
}
//如果沒有事件就緒即所有請求都失敗則掛起調(diào)用該函數(shù)的函數(shù)
OSTCBCur->OSTCBStat |= events_stat | OS_STAT_MULTI;
//標記當前事件控制塊中的事件狀態(tài)為等待資源而且是等待多個資源
OSTCBCur->OSTCBStatPend = OS_STAT_PEND_OK;
//配置當前事件控制塊中的事件狀態(tài)標志為等待完成,因為這個事件即將被切換掉,進入掛起態(tài)
OSTCBCur->OSTCBDly = timeout;
//設(shè)置該任務(wù)掛起等待的時間為timeout時間,超時任務(wù)就被切換掉。
OS_EventTaskWaitMulti(pevents_pend);
//暫停任務(wù)直到出現(xiàn)新的事件呼叫或者掛起時間到
OS_EXIT_CRITICAL();
//退出中斷沿
OS_Sched();
//如果當前任務(wù)不處于就緒態(tài)將進行任務(wù)調(diào)度將優(yōu)先級最高的任務(wù)調(diào)入運行態(tài)
OS_ENTER_CRITICAL();
//進入中斷沿
//對當前最高優(yōu)先級的事件進行狀態(tài)判斷(下一個任務(wù)或還是之前的任務(wù))
switch (OSTCBCur->OSTCBStatPend) {
case OS_STAT_PEND_OK: //等待完成和等待終止都進行相同處理
case OS_STAT_PEND_ABORT:
pevent = OSTCBCur->OSTCBEventPtr;
if (pevent != (OS_EVENT *)0) {
//有任務(wù)就緒了
*pevents_rdy++ = pevent;
//把這個任務(wù)的地址存儲到pevents_rdy數(shù)組中
*pevents_rdy = (OS_EVENT *)0;
//最后一個標志為結(jié)束符
events_rdy_nbr++;
//就緒事件數(shù)加1
} else {
OSTCBCur->OSTCBStatPend = OS_STAT_PEND_TO;
//如果沒有任務(wù)就緒標志為超時處理,這里不明白########
OS_EventTaskRemoveMulti(OSTCBCur, pevents_pend);
//解除暫停將任務(wù)從等待列表中刪除
}
break;
case OS_STAT_PEND_TO:
default:
OS_EventTaskRemoveMulti(OSTCBCur, pevents_pend);//掛起時間到將任務(wù)從等待列表中刪除
break;
}
//這個switch是用來消息傳遞的
switch (OSTCBCur->OSTCBStatPend) {
case OS_STAT_PEND_OK: //掛起完成也標志該事件又處在就緒態(tài)了
switch (pevent->OSEventType) {
#if (OS_SEM_EN > 0u)
case OS_EVENT_TYPE_SEM:
*pmsgs_rdy++ = (void *)0;
//信號量沒有返回消息
break;
#endif
#if ((OS_MBOX_EN > 0u) ||((OS_Q_EN > 0u) && (OS_MAX_QS > 0u)))
case OS_EVENT_TYPE_MBOX:
case OS_EVENT_TYPE_Q:
*pmsgs_rdy++ = (void *)OSTCBCur->OSTCBMsg;
break; //把郵箱和隊列中的消息保存在pmsgs_rdy數(shù)組中
#endif
case OS_EVENT_TYPE_MUTEX:
case OS_EVENT_TYPE_FLAG:
default:
OS_EXIT_CRITICAL();
*pevents_rdy = (OS_EVENT *)0;
*perr = OS_ERR_EVENT_TYPE;
return (events_rdy_nbr);
}
*perr = OS_ERR_NONE;
break;
case OS_STAT_PEND_ABORT: //等待終止返回空消息
*pmsgs_rdy++ = (void *)0;
*perr = OS_ERR_PEND_ABORT;
break;
case OS_STAT_PEND_TO: //等待超時也返回空消息
default:
*pmsgs_rdy++ = (void *)0;
*perr = OS_ERR_TIMEOUT;
break;
}
OSTCBCur->OSTCBStat = OS_STAT_RDY;
//事件標記為就緒態(tài)
OSTCBCur->OSTCBStatPend = OS_STAT_PEND_OK;
//清除掛起標志
OSTCBCur->OSTCBEventPtr = (OS_EVENT *)0;
OSTCBCur->OSTCBEventMultiPtr = (OS_EVENT **)0;
#if ((OS_MBOX_EN > 0u) ||((OS_Q_EN > 0u) && (OS_MAX_QS > 0u)))
OSTCBCur->OSTCBMsg = (void *)0;
#endif
OS_EXIT_CRITICAL();
return (events_rdy_nbr);
}
#endif