2009年3月15日 星期日

task schedule & Semaphore--uc/os ii

// 記錄原因 :
task TCB 有用 dual linker pointer 指針串接每一task
--> 目的 -> 管理
但調度與上面指針(串接)沒有很大的關係,有另外映射的機制

// 記錄 task 資訊
static OS_TCB OSTCBTbl[OS_MAX_TASKS + OS_N_SYS_TASKS];

OS_EXT idata OS_TCB *OSTCBCur; /* Pointer to currently running TCB */
OS_EXT OS_TCB *OSTCBFreeList; /* Pointer to list of free TCBs */
OS_EXT idata OS_TCB *OSTCBHighRdy; /* Pointer to highest priority TCB ready to run */
OS_EXT OS_TCB *OSTCBList; /* Pointer to doubly linked list of TCBs */
OS_EXT OS_TCB *OSTCBPrioTbl[OS_LOWEST_PRIO + 1];/* Table of pointers to created TCBs */

task -TCB 以指針串接,以 OSTCBList 為始; 但一般當 OSTimeTick 的時候才會遍尋所有的TCB
(也沒辦法,因為工作中有 delay....要遍尋每一個 )

找出優先權的 task 以這樣遍尋的手法會很浪費時間,所以以
*OSTCBPrioTbl[OS_LOWEST_PRIO + 1]; 記錄工作於這個 "指標陣列" 之中, task 的優先權與之結合,故只要找出 "最高優先權",便可以找到該 task,

task priority from 0~63,你要如何找出呢 ?? 難不成也遍尋 ?? 上面就失去意義了 ??
手法 : 將每個 enable 的 task , 其分配一個特定的優先權( 0~ 63), 以 bit 表示一個 task enable, 8 個 Byte 共有 64 個 bit, bit 的位置就是其優先權-----OSRdyTbl[7]

又是要遍尋嗎 ??
原本遍尋 64 個任務,現在遍尋 8 個 Byte中的每一個 bit ?? 也是 64 次,有做等於沒做
否,還有更好的方法嗎 ?? 遍尋 8 個 Byte, 每個Byte "映射" 找出優先權最高的任務 ??
---> 還是要遍尋 8 次 , 還有更好的方法嗎 ??

再透過一個 Byte (OSRdyGrp) 中的每一個 bit,表示 8 個 Byte 中的每一個 Byte 是否有任務 ??
遍尋 8 個 bit ?? No, 也是以映射的方式,找出優先權最高

OSRdyGrp : 可能的排列組合,XXXX 表示 don't care

xxxx-xxx1 --> 映射到 "0" ; 有 2^7 個組合
xxxx-xx10 --> 映射到 "1" ; 有 2^6 個組合
xxxx-x100 --> 映射到 "2" ; 有 2^5 個組合
xxxx-1000 --> 映射到 "3" ; 有 2^4 個組合
xxx1-0000 --> 映射到 "4" ; 有 2^3 個組合
xx10-0000 --> 映射到 "5" ; 有 2^2 個組合
x100-0000 --> 映射到 "6" ; 有 2^1 個組合 ; 故 64,196 映射成 6
1000-0000 --> 映射到 "7" ; 有 2^0 個組合
----------------------------------------------------
這是一個等比級數,老祖宗有教過 ; Sn=(r^n-1)/(r-1) = (2^8 -1)/(2-1)=255

以這個為例 : x100-0000 --> 映射到 "6" ; 有 2^1 個組合 ; 故 64,196 映射成 6
注意 : 下面 table 內紅色的數字

code INT8U const OSUnMapTbl[] = {
0, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
5, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
6, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
5, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
7, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
5, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
6, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
5, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0
};

// 補充 : 將 priority 0~63 資訊轉成 bit 資訊, 以 OSRdyGrp &OSRdyTbl表達
ptcb->OSTCBY = prio >> 3; /* Pre-compute X, Y, BitX and BitY */
ptcb->OSTCBBitY = OSMapTbl[ptcb->OSTCBY];
ptcb->OSTCBX = prio & 0x07;

ptcb->OSTCBBitX = OSMapTbl[ptcb->OSTCBX];


&
OSRdyGrp |= ptcb->OSTCBBitY; /* Make task ready to run */ OSRdyTbl[ptcb->OSTCBY] |= ptcb->OSTCBBitX;


//-----------------------------------------------//
void OSSched (void) reentrant
{
INT8U y;
OS_ENTER_CRITICAL();
if ((OSLockNesting | OSIntNesting) == 0) {
y = OSUnMapTbl[OSRdyGrp];
OSPrioHighRdy = (INT8U)((y << 3) + OSUnMapTbl[OSRdyTbl[y]]);
if (OSPrioHighRdy != OSPrioCur)
{
OSTCBHighRdy = OSTCBPrioTbl[OSPrioHighRdy];
OSCtxSwCtr++;
OS_TASK_SW(); /* Perform a context switch */
}
}
OS_EXIT_CRITICAL();
}




// 與 task 實做很像

OSSemPend 的時候,需將 task 移出( 這樣排程不到這個 task--delay的時候也是以移出的手法)
所以OSEventGrp,OSEventTbl 記錄 task 資訊; (OsEventTaskWait)
-- 因記錄,所以等會可以恢復----
1. timeout 時,OSEventGrp/OSEventTbl 移除,
2. task 資訊 --OSRdyGrp/OSRdyTbl 於 OSTimeTick 恢復

OSSemPost --> OSEventTaskRdy
1. 透過 Fun_Sem 找出優先權最高的"等待 task",
移除此資訊OSEventGrp/OSEventTbl
2. task 資訊 OSRdyGrp/OSRdyTb 恢復

Note :
OS_EVENT *Fun_Sem;

typedef struct {
void *OSEventPtr; /* Pointer to message or queue structure */
INT8U OSEventTbl[OS_EVENT_TBL_SIZE]; /* List of tasks waiting for event to occur */
INT16U OSEventCnt; /* Count of used when event is a semaphore */
INT8U OSEventType; /* OS_EVENT_TYPE_MBOX, OS_EVENT_TYPE_Q or OS_EVENT_TYPE_SEM */
INT8U OSEventGrp; /* Group corresponding to tasks waiting for event to occur */
} OS_EVENT;



// 測試有 timeout 時的路徑, OSSemPend -> OSEventTaskWait -> OSSched -> OSEventTO
for(;;){

OSSemPend(Fun_Sem,10,&err);

PrintStr("\nAAAA is active.");
OSSemPost(Fun_Sem);
OSTimeDly(OS_TICKS_PER_SEC);
if(P4_3==0)
{

GotoIsp();

}
}




why write this : 1.OSSemPend & OSSemPost 看不出來需求
ptcb->OSTCBEventPtr原因,

查找關鍵字ptcb->OSTCBEventPtr


OSTaskChangePrio() & OSTaskDel 中要判斷到 OSTCBEventPtr

if ((pevent = ptcb->OSTCBEventPtr) != (OS_EVENT *)0) { /* Remove from event wait list */
if ((pevent->OSEventTbl[ptcb->OSTCBY] &= ~ptcb->OSTCBBitX) == 0) {
pevent->OSEventGrp &= ~ptcb->OSTCBBitY;
}
pevent->OSEventGrp |= bity; /* Add new priority to wait list */
pevent->OSEventTbl[y] |= bitx;

/---------------
OSSemPend --> OSEventTaskWait
OSTCBCur->OSTCBStat |= OS_STAT_SEM;
OSTCBCur->OSTCBDly = timeout;

pevent->OSEventTbl[OSTCBCur->OSTCBY] |= OSTCBCur->OSTCBBitX;
pevent->OSEventGrp |= OSTCBCur->OSTCBBitY;



/*-------------------------------------------*/
OSCtxSw_in 改名為 OSCtxSw_out 比較容易理解,另外不會與其他名稱很相似
ex> OSCtxSw,OSIntCtxSw_in

/*---------------------------------------------*/
OSTimeTick 不會安排新工作,只是輪詢所有TCB 的 delay,然後有可能 task 回復運形態

OSIntExit 才是安排新工作的地方

LCALL _?OSIntEnter
LCALL _?OSTimeTick
LCALL _?OSIntExit

/*------------------------------------------*/
void OSIntEnter (void) reentrant
{
OS_ENTER_CRITICAL();
OSIntNesting++; /* Increment ISR nesting level */
OS_EXIT_CRITICAL();
}

/*------------------------------------------*/
void OSIntExit (void) reentrant
{
OS_ENTER_CRITICAL();
if ((--OSIntNesting | OSLockNesting) == 0) { /* Reschedule only if all ISRs completed & not locked */
OSIntExitY = OSUnMapTbl[OSRdyGrp];
OSPrioHighRdy = (INT8U)((OSIntExitY << 3) + OSUnMapTbl[OSRdyTbl[OSIntExitY]]);
if (OSPrioHighRdy != OSPrioCur) { /* No context switch if current task is highest ready */
OSTCBHighRdy = OSTCBPrioTbl[OSPrioHighRdy];
OSCtxSwCtr++; /* Keep track of the number of context switches */
OSIntCtxSw(); /* Perform interrupt level context switch */
}
}
OS_EXIT_CRITICAL();
}
/*------------------------------------------*/

沒有留言:

張貼留言