//http://gliethttp.cublog.cn
//----------------------------------------------------------------------
//1.OSMboxPend()函數
void *OSMboxPend (OS_EVENT *pevent, INT16U timeout, INT8U *perr)
{
void *pmsg;
INT8U pend_stat;
#if OS_CRITICAL_METHOD == 3
OS_CPU_SR cpu_sr = 0;
#endif
#if OS_ARG_CHK_EN > 0
if (perr == (INT8U *)0) {
return ((void *)0);
}
if (pevent == (OS_EVENT *)0) {
*perr = OS_ERR_PEVENT_NULL;
return ((void *)0);
}
#endif
if (pevent->OSEventType != OS_EVENT_TYPE_MBOX) {
//確保該event控制塊是Mbox類型
*perr = OS_ERR_EVENT_TYPE;
return ((void *)0);
}
if (OSIntNesting > 0) {
//ISR中,不能使用OSMboxPend()
*perr = OS_ERR_PEND_ISR;
return ((void *)0);
}
if (OSLockNesting > 0) {
//uCOS/II v2.85內核已經被強制鎖住
*perr = OS_ERR_PEND_LOCKED;
return ((void *)0);
}
//非法的統統不是,信號正常,所以有必要進一步處理
OS_ENTER_CRITICAL();
pmsg = pevent->OSEventPtr;
if (pmsg != (void *)0) {
//pevent->OSEventPtr存放對應的消息指針,如果為0,說明還沒有消息
//程序的其他地方已經觸發了事件
//所以該task無需懸停,直接獲得事件的使用權
pevent->OSEventPtr = (void *)0;
OS_EXIT_CRITICAL();
*perr = OS_ERR_NONE;
return (pmsg);
}
//當前還沒有任何事件發生,所以本task需要懸停,讓出cpu
OSTCBCur->OSTCBStat |= OS_STAT_MBOX;//是Mbox事件讓本task進入懸停等待的
OSTCBCur->OSTCBStatPend = OS_STAT_PEND_OK;//假定不是超時,為正常收到信號
//超時,如果timeout=0,那麼,本task將一直懸停,僅僅當收到事件觸發信號后才重新進入調度隊列
OSTCBCur->OSTCBDly = timeout;
//OS_EventTaskWait()函數實現的功能:
//把本task從就緒控制矩陣中摘下,放到pevent事件專有的進程事件控制矩陣表中.
OS_EventTaskWait(pevent);
OS_EXIT_CRITICAL();
//因為本task正在運行,所以本task現在的優先順序最高,現在本task已經將自己從就緒控制矩陣--調度器(x,y)矩形陣列中
//把自己摘掉,所以調度函數OS_Sched()一定會切換到另一個task中執行新task的代碼
OS_Sched();//具體參見《淺析uC/OS-II v2.85內核調度函數》
OS_ENTER_CRITICAL();
//可能因為OSMboxPend()中指定的timeout已經超時
//[由OSTimeTick()函數把本task重新置入了就緒隊列,具體參考《淺析uC/OS-II v2.85內核OSTimeDly()函數工作原理》],
//又或者確實在應用程序的某個地方調用了OSMboxPost(),以下代碼將具體解析是有什麼引起的:1.超時,2.收到正常信號
if (OSTCBCur->OSTCBStatPend != OS_STAT_PEND_OK) {
//是因為timeout超時,使得本task獲得重新執行的機會
pend_stat = OSTCBCur->OSTCBStatPend;
//清除event事件塊上本task的標誌
OS_EventTOAbort(pevent);
OS_EXIT_CRITICAL();
switch (pend_stat) {
case OS_STAT_PEND_TO:
default:
*perr = OS_ERR_TIMEOUT;
break;
case OS_STAT_PEND_ABORT:
*perr = OS_ERR_PEND_ABORT;
break;
}
return ((void *)0);
}
//由OSMboxPost()拋出正常事件,喚醒了本task,因為在OSMboxPost()時,
//已經將本task在event事件控制矩陣上的對應位清除掉,並且把本task放入了就緒控制矩陣中,
//否則本task也不會執行至此.
pmsg = OSTCBCur->OSTCBMsg;//由OSMboxPost()傳遞來的消息指針
OSTCBCur->OSTCBMsg = (void *)0;//清空消息指針
//狀態ok,等待os調度登記到就緒控制矩陣中的自己
OSTCBCur->OSTCBStat = OS_STAT_RDY;
OSTCBCur->OSTCBEventPtr = (OS_EVENT *)0;//現在本task不懸停在任何event事件上
OS_EXIT_CRITICAL();
*perr = OS_ERR_NONE;
return (pmsg);
}
//----------------------------------------------------------------------
//2.OS_EventTaskWait()函數
void OS_EventTaskWait (OS_EVENT *pevent)
{
INT8U y;
//pevent為此次task掛起的EventPtr單元
OSTCBCur->OSTCBEventPtr = pevent;
//清除調度器中該task對應的標誌位
y = OSTCBCur->OSTCBY;
OSRdyTbl[y] &= ~OSTCBCur->OSTCBBitX;
if (OSRdyTbl[y] == 0) {
//當前y行對應的8個或16個task都已經懸停,那麼當前y行也清除.
OSRdyGrp &= ~OSTCBCur->OSTCBBitY;
}
//將該task的prio添加到pevent事件控制矩陣中,這個矩陣的功能和OSRdyGrp、OSRdyTbl就緒控制矩陣沒有區別
//都是用來就算出已經就緒tasks中的優先順序最高的那個
pevent->OSEventTbl[OSTCBCur->OSTCBY] |= OSTCBCur->OSTCBBitX;
pevent->OSEventGrp |= OSTCBCur->OSTCBBitY;
}
//----------------------------------------------------------------------
//3.OS_EventTOAbort()函數
void OS_EventTOAbort (OS_EVENT *pevent)
{
INT8U y;
//清除event事件控制矩陣上本task的標誌,因為OSTimeTick()函數未清除該單元
//它僅僅把本task放入就緒控制矩陣,使得本task重新獲得被OS調度的機會而已
//具體的清除工作還要自己完成
//具體參考《淺析uC/OS-II v2.85內核OSTimeDly()函數工作原理》
y = OSTCBCur->OSTCBY;
pevent->OSEventTbl[y] &= ~OSTCBCur->OSTCBBitX;
if (pevent->OSEventTbl[y] == 0x00) {
pevent->OSEventGrp &= ~OSTCBCur->OSTCBBitY;
}
OSTCBCur->OSTCBStatPend = OS_STAT_PEND_OK;
OSTCBCur->OSTCBStat = OS_STAT_RDY;
OSTCBCur->OSTCBEventPtr = (OS_EVENT *)0;//現在本task不懸停在任何event事件上
}
//----------------------------------------------------------------------
//3.OSMboxPost()函數
INT8U OSMboxPost (OS_EVENT *pevent, void *pmsg)
{
#if OS_CRITICAL_METHOD == 3
OS_CPU_SR cpu_sr = 0;//方式3將把cpsr狀態寄存器推入臨時堆棧cpu_sr中,可以安全返回之前的中斷狀態
#endif
#if OS_ARG_CHK_EN > 0
if (pevent == (OS_EVENT *)0) {
return (OS_ERR_PEVENT_NULL);
}
if (pmsg == (void *)0) {
return (OS_ERR_POST_NULL_PTR);
}
#endif
if (pevent->OSEventType != OS_EVENT_TYPE_MBOX) {
return (OS_ERR_EVENT_TYPE);
}
OS_ENTER_CRITICAL();
if (pevent->OSEventGrp != 0) {
//OS_EventTaskRdy()函數將摘掉等待在pevent事件控制矩陣上的task中優先順序最高的task
//如果該task僅僅等待該pevent事件,那麼將該task添加到就緒控制矩陣中
//OSRdyGrp |= bity;
//OSRdyTbl[y] |= bitx;這樣調度程序就會根據情況調度OS_Sched()該task了
(void)OS_EventTaskRdy(pevent, pmsg, OS_STAT_MBOX, OS_STAT_PEND_OK);
OS_EXIT_CRITICAL();
//可能剛剛放到就緒控制矩陣上的被喚醒的task的優先順序比調用OSMboxPost()函數的進程B優先順序高
//所以需要調用shedule函數,
//如果真的高,那麼調用OSMboxPost()函數的進程B就要被搶佔,os將會切換到新的task去執行
//如果沒有調用OSMboxPost()函數的進程B優先順序高,那麼os不會切換,仍然繼續執行進程B,OSMboxPost()正常返回
OS_Sched();
return (OS_ERR_NONE);
}
//沒有任何一個task懸停在本event事件控制矩陣上
if (pevent->OSEventPtr != (void *)0) {
OS_EXIT_CRITICAL();
return (OS_ERR_MBOX_FULL);//郵箱已經滿了
}
pevent->OSEventPtr = pmsg;//把該消息指針推到pevent->OSEventPtr中
OS_EXIT_CRITICAL();
return (OS_ERR_NONE);
}
//----------------------------------------------------------------------
//5.OS_EventTaskRdy()函數
INT8U OS_EventTaskRdy (OS_EVENT *pevent, void *pmsg, INT8U msk, INT8U pend_stat)
{
OS_TCB *ptcb;
INT8U x;
INT8U y;
INT8U prio;
#if OS_LOWEST_PRIO <= 63
INT8U bitx;
INT8U bity;
#else
INT16U bitx;
INT16U bity;
INT16U *ptbl;
#endif
#if OS_LOWEST_PRIO <= 63
//小於64個task時,快速計算
//最有優先權的task位於事件控制矩陣中的第y行的第x列
y = OSUnMapTbl[pevent->OSEventGrp];
bity = (INT8U)(1 << y);
x = OSUnMapTbl[pevent->OSEventTbl[y]];
bitx = (INT8U)(1 << x);
prio = (INT8U)((y << 3) + x);
#else
//對於256個task
//最有優先權的task位於事件控制矩陣中的第y行的第x列
//以下的操作原理具體參見《淺析uC/OS-II v2.85內核調度函數》
if ((pevent->OSEventGrp & 0xFF) != 0) {
y = OSUnMapTbl[pevent->OSEventGrp & 0xFF];
} else {
y = OSUnMapTbl[(pevent->OSEventGrp >> 8) & 0xFF] + 8;
}
bity = (INT16U)(1 << y);
ptbl = &pevent->OSEventTbl[y];
if ((*ptbl & 0xFF) != 0) {
x = OSUnMapTbl[*ptbl & 0xFF];
} else {
x = OSUnMapTbl[(*ptbl >> 8) & 0xFF] + 8;
}
bitx = (INT16U)(1 << x);
prio = (INT8U)((y << 4) + x);
//該task對應的prio優先順序值
//ok,等待在event事件上的所有task中,只有在事件控制矩陣中的第y行的第x列task
//優先順序最高、最值的成為此次事件的喚醒對象
#endif
//清除此task在event事件控制矩陣中的bit位
pevent->OSEventTbl[y] &= ~bitx;
if (pevent->OSEventTbl[y] == 0) {
pevent->OSEventGrp &= ~bity;
}
//通過prio優先順序找到該prio唯一對應的task對應的ptcb進程上下文控制塊
ptcb = OSTCBPrioTbl[prio];
ptcb->OSTCBDly = 0;//復原為正常
ptcb->OSTCBEventPtr = (OS_EVENT *)0;//現在本task不懸停在任何event事件上
#if ((OS_Q_EN > 0) && (OS_MAX_QS > 0)) || (OS_MBOX_EN > 0)
ptcb->OSTCBMsg = pmsg;//傳遞消息指針
#else
pmsg = pmsg;
#endif
ptcb->OSTCBStatPend = pend_stat;//懸停狀態值
ptcb->OSTCBStat &= ~msk;//該msk事件已經發生,清除task上下文控制塊上的msk位,如:OS_STAT_MBOX
if (ptcb->OSTCBStat == OS_STAT_RDY) {
//如果當前task只是等待該事件,那麼把該task放到就緒控制矩陣中,允許內核調度本task
OSRdyGrp |= bity;
OSRdyTbl[y] |= bitx;
}
return (prio);//返回本task對應的優先順序值
}
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
PS:"所以從這裡來看,os中的各個功能單元管理著自己的事情,就像面向對象的封裝一樣,"
"事件控制矩陣和就緒控制矩陣是各個對象獨立自治的關鍵因素"
"其他對象,都努力說服自己相信別的對象是獨立的、可信任的、安全的"[gliethttp]
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
[admin via 研發互助社區 ] uCOS II v2.85內核OSMboxPend()和OSMboxPost()函數工作原理已經有3809次圍觀
http://cocdig.com/docs/show-post-42162.html