it's this section's map.函数
事件初始化代码在操做系统初始化函数OS_Init中被调用,其函数名为OS_InitEventList,定义以下post
1 static void OS_InitEventList (void) 2 { 3 #if (OS_EVENT_EN) && (OS_MAX_EVENTS > 0) 4 #if (OS_MAX_EVENTS > 1) 5 INT16U i; 6 OS_EVENT *pevent1; 7 OS_EVENT *pevent2; 8 9 10 OS_MemClr((INT8U *)&OSEventTbl[0], sizeof(OSEventTbl)); /* Clear the event table */ 11 pevent1 = &OSEventTbl[0]; 12 pevent2 = &OSEventTbl[1]; 13 for (i = 0; i < (OS_MAX_EVENTS - 1); i++) { /* Init. list of free EVENT control blocks */ 14 pevent1->OSEventType = OS_EVENT_TYPE_UNUSED; 15 pevent1->OSEventPtr = pevent2; 16 #if OS_EVENT_NAME_SIZE > 1 17 pevent1->OSEventName[0] = '?'; /* Unknown name */ 18 pevent1->OSEventName[1] = OS_ASCII_NUL; 19 #endif 20 pevent1++; 21 pevent2++; 22 } 23 pevent1->OSEventType = OS_EVENT_TYPE_UNUSED; 24 pevent1->OSEventPtr = (OS_EVENT *)0; 25 #if OS_EVENT_NAME_SIZE > 1 26 pevent1->OSEventName[0] = '?'; 27 pevent1->OSEventName[1] = OS_ASCII_NUL; 28 #endif 29 OSEventFreeList = &OSEventTbl[0]; 30 #else 31 OSEventFreeList = &OSEventTbl[0]; /* Only have ONE event control block */ 32 OSEventFreeList->OSEventType = OS_EVENT_TYPE_UNUSED; 33 OSEventFreeList->OSEventPtr = (OS_EVENT *)0; 34 #if OS_EVENT_NAME_SIZE > 1 35 OSEventFreeList->OSEventName[0] = '?'; /* Unknown name */ 36 OSEventFreeList->OSEventName[1] = OS_ASCII_NUL; 37 #endif 38 #endif 39 #endif 40 }
line 10清空了以前的事件表this
line 13~ line 22对除了最后一个以外的全部ECB进行了初始化,并构建了单向链表。spa
line 23~ line24使最后一个ECB指向了空地址0.操作系统
最后line 29将表头地址赋给全局变量OSEventFreeList.指针
当创建一个事件或消息时,如信号量的创建函数OSSemCreate等,须要对事件等待表进行初始化。事件等待表初始化函数实现对制定任务块中事件等待表和时间等待组清零,可悲操做系统的其它函数调用。code
1 #if (OS_EVENT_EN) 2 void OS_EventWaitListInit (OS_EVENT *pevent) 3 { 4 #if OS_LOWEST_PRIO <= 63 5 INT8U *ptbl; 6 #else 7 INT16U *ptbl; 8 #endif 9 INT8U i; 10 11 12 pevent->OSEventGrp = 0; /* No task waiting on event */ 13 ptbl = &pevent->OSEventTbl[0]; 14 15 for (i = 0; i < OS_EVENT_TBL_SIZE; i++) { 16 *ptbl++ = 0; 17 } 18 } 19 #endif
总的来讲,这个函数的功能即把事件等待表再次初始化了一遍,作的和第一个函数中line 13~line 22中同样的工做,最后一个OSEventTbl被无视。blog
可是我不知道为何要再Init一遍。队列
这三块我以为与以前任务管理部分的操做有些相似,因此放一起讲。类比在看完源码后给出。事件
当任务等待事件发生,并得到ECB后,须要在ECB中标记任务在等待事件的发生。才能够在事件发生时取消任务的阻塞。将任务在ECB中进行登记的函数是OS_EventTaskWait,参数是事件控制块的指针。
与OS_EventWaitListInit相似,OS_EventTaskWait在任务调用信号量、邮箱等时间等待函数时被对应函数调用。由于任务优先级能够经过当前TCB指针OSTCBCur获得,所以没有做为参数传递。
源码以下
1 #if (OS_EVENT_EN) 2 void OS_EventTaskWait (OS_EVENT *pevent) 3 { 4 INT8U y; 5 6 7 OSTCBCur->OSTCBEventPtr = pevent; /* Store ptr to ECB in TCB */ 8 9 pevent->OSEventTbl[OSTCBCur->OSTCBY] |= OSTCBCur->OSTCBBitX; /* Put task in waiting list */ 10 pevent->OSEventGrp |= OSTCBCur->OSTCBBitY; 11 12 y = OSTCBCur->OSTCBY; /* Task no longer ready */ 13 OSRdyTbl[y] &= ~OSTCBCur->OSTCBBitX; 14 if (OSRdyTbl[y] == 0) { 15 OSRdyGrp &= ~OSTCBCur->OSTCBBitY; /* Clear event grp bit if this was only task pending */ 16 } 17 } 18 #endif
line 7中:在TCB的OSTCBEventPtr域存储ECB指针,之后经过该任务的TCB能够直接找到这个事件的ECB。
以后作了两件事——标记和取消标记。听闻这里的操做和就绪表中设置就绪标志的彻底一致的,那便先放着吧。
这个函数与上一个函数是相反的操做。当一个事件因为某种缘由再也不须要等待事件时,就须要在事件的等待表中取消该事件的等待标志。
1 #if (OS_EVENT_EN) 2 void OS_EventTaskRemove (OS_TCB *ptcb, 3 OS_EVENT *pevent) 4 { 5 INT8U y; 6 7 8 y = ptcb->OSTCBY; 9 pevent->OSEventTbl[y] &= ~ptcb->OSTCBBitX; /* Remove task from wait list */ 10 if (pevent->OSEventTbl[y] == 0) { 11 pevent->OSEventGrp &= ~ptcb->OSTCBBitY; 12 } 13 } 14 #endif
line 9:在事件等待表中删除事件等待标志
line 10:若该行已没有任务等待
line 11:删除事件等待组的事件等待标志
任务由于等待时间而在ECB中登记本身的等待,当事件发生时,若是该任务是事件等待表中优先级最高的任务,就绪就取消等待而回到就绪状态。
源码以下:
1 #if (OS_EVENT_EN) 2 INT8U OS_EventTaskRdy (OS_EVENT *pevent, void *pmsg, INT8U msk, INT8U pend_stat) 3 { 4 OS_TCB *ptcb; 5 INT8U y; 6 INT8U x; 7 INT8U prio; 8 #if OS_LOWEST_PRIO > 63 9 INT16U *ptbl; 10 #endif 11 12 13 #if OS_LOWEST_PRIO <= 63 14 y = OSUnMapTbl[pevent->OSEventGrp]; /* Find HPT waiting for message */ 15 x = OSUnMapTbl[pevent->OSEventTbl[y]]; 16 prio = (INT8U)((y << 3) + x); /* Find priority of task getting the msg */ 17 #else 18 if ((pevent->OSEventGrp & 0xFF) != 0) { /* Find HPT waiting for message */ 19 y = OSUnMapTbl[ pevent->OSEventGrp & 0xFF]; 20 } else { 21 y = OSUnMapTbl[(pevent->OSEventGrp >> 8) & 0xFF] + 8; 22 } 23 ptbl = &pevent->OSEventTbl[y]; 24 if ((*ptbl & 0xFF) != 0) { 25 x = OSUnMapTbl[*ptbl & 0xFF]; 26 } else { 27 x = OSUnMapTbl[(*ptbl >> 8) & 0xFF] + 8; 28 } 29 prio = (INT8U)((y << 4) + x); /* Find priority of task getting the msg */ 30 #endif 31 32 ptcb = OSTCBPrioTbl[prio]; /* Point to this task's OS_TCB */ 33 ptcb->OSTCBDly = 0; /* Prevent OSTimeTick() from readying task */ 34 #if ((OS_Q_EN > 0) && (OS_MAX_QS > 0)) || (OS_MBOX_EN > 0) 35 ptcb->OSTCBMsg = pmsg; /* Send message directly to waiting task */ 36 #else 37 pmsg = pmsg; /* Prevent compiler warning if not used */ 38 #endif 39 ptcb->OSTCBStat &= ~msk; /* Clear bit associated with event type */ 40 ptcb->OSTCBStatPend = pend_stat; /* Set pend status of post or abort */ 41 /* See if task is ready (could be susp'd) */ 42 if ((ptcb->OSTCBStat & OS_STAT_SUSPEND) == OS_STAT_RDY) { 43 OSRdyGrp |= ptcb->OSTCBBitY; /* Put task in the ready to run list */ 44 OSRdyTbl[y] |= ptcb->OSTCBBitX; 45 } 46 47 OS_EventTaskRemove(ptcb, pevent); /* Remove this task from event wait list */ 48 #if (OS_EVENT_MULTI_EN > 0) 49 if (ptcb->OSTCBEventMultiPtr != (OS_EVENT **)0) { /* Remove this task from events' wait lists */ 50 OS_EventTaskRemoveMulti(ptcb, ptcb->OSTCBEventMultiPtr); 51 ptcb->OSTCBEventPtr = (OS_EVENT *)pevent;/* Return event as first multi-pend event ready*/ 52 } 53 #endif 54 55 return (prio); 56 } 57 #endif
几个参数的解析以下:
line 13~ line 30在事件等待表和事件等待组中找到最高优先级的等待任务的优先级(line 17~ line 30是任务数多于63的状况,书上未提);
line 32 根据优先级在优先级指针表中找到该任务的TCB指针;
line 33~ line 40对TCB的相关参数进行赋值;
line 42~ line 45判断任务是否被挂起,若是未被挂起就将任务就绪,完成从阻塞态到就绪态的转换;
line 47 调用OS_EventTaskRemove函数在ECB的事件等待表中删除该任务;
line 55返回任务优先级。
这三个函数的关系如图(略简陋)
Done