歡迎您光臨本站 登入註冊首頁

概述

//http://gliethttp.cublog.cn//----------------------------------------------------------------------……

//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