|
//----------------------------------------------------------------------# I0 ]! Q* b1 C [' b) e2 o //1.OSSemPend()函数: g% @2 f) b/ T5 Y$ j0 Y void OSSemPend (OS_EVENT *pevent, INT16U timeout, INT8U *perr)" r( u+ V+ g+ ~" N) u) D5 t {2 p o- {" o: i; e INT8U pend_stat; #if OS_CRITICAL_METHOD == 3 OS_CPU_SR cpu_sr = 0; #endif0 K- Y0 ?; x% ~ 7 o: W! O7 ?; ?' v8 | #if OS_ARG_CHK_EN > 0 if (perr == (INT8U *)0) { return;; [$ a' K. C3 Q }* D& B) b2 D) ^: Q; E. P if (pevent == (OS_EVENT *)0) {) a+ d- k7 D7 J$ u' {- O3 m *perr = OS_ERR_PEVENT_NULL; return; } #endif if (pevent->OSEventType != OS_EVENT_TYPE_SEM) { //确保该event控制块是Sem类型 *perr = OS_ERR_EVENT_TYPE;5 l$ Z4 G$ t/ s0 k; V, C$ v2 E( L return;' ^- _5 G" j* k( @! ? }7 z+ Z, z) [* f+ \; n if (OSIntNesting > 0) { //ISR中,不能使用OSSemPend()# H& u* d# s- p& k0 W" x9 @5 Q *perr = OS_ERR_PEND_ISR;# E5 y' p" P- F3 e3 A- K return; } if (OSLockNesting > 0) { //μCOS/II v2.85内核已经被强制锁住 *perr = OS_ERR_PEND_LOCKED; return;/ }2 u& d. @1 [6 J } //非法的统统不是,信号正常,所以有必要进一步处理' M3 _; v3 \8 X% T OS_ENTER_CRITICAL();) B3 r2 T! l- ~* k! F1 {6 A3 U if (pevent->OSEventCnt > 0) {; E6 N( q9 B" F$ ~! E //程序的其他地方已经触发了事件,异或在初始化时设定了n,如:OSSemCreate(2);" V' ^$ S: @ M* v' d$ f //所以该task无需悬停,直接获得事件的使用权 pevent->OSEventCnt--;- u5 w$ J4 H1 x/ V, K1 `+ ? T OS_EXIT_CRITICAL(); *perr = OS_ERR_NONE; return; C8 `- b& J7 L2 z6 B }8 [2 _+ k) r7 H //当前还没有任何事件发生,所以本task需要悬停,让出cpu[gliethttp]/ c# D- f0 Y) A: G+ s2 } OSTCBCur->OSTCBStat |= OS_STAT_SEM;//是sem事件让本task进入悬停等待的" U; [- }. j, i. Q/ N3 y% D9 c OSTCBCur->OSTCBStatPend = OS_STAT_PEND_OK;//假定不是超时,为正常收到信号 //超时,如果timeout=0,那么,本task将一直悬停,仅仅当收到事件触发信号后才重新进入调度队列3 g5 T6 }4 E4 {: X( w! w9 D OSTCBCur->OSTCBDly = timeout;! y) d( |! B2 j- U //OS_EventTaskWait()函数实现的功能:4 P& ], k+ b- o G, x //把本task从就绪控制矩阵中摘下,放到pevent事件专有的进程事件控制矩阵表中./ X- @1 Z; G. a0 |3 u2 U | OS_EventTaskWait(pevent); OS_EXIT_CRITICAL(); //因为本task正在运行,所以本task现在的优先级最高,现在本task已经将自己从就绪控制矩阵--调度器(x,y)矩形阵列中 i1 s9 w# ?/ M$ d //把自己摘掉,所以调度函数OS_Sched()一定会切换到另一个task中执行新task的代码[gliethttp] OS_Sched();//具体参见《浅析μC/OS-II v2.85内核调度函数》/ R' _: o! ~; s( @ //2007-09-09 gliethttp/ c, W8 B2 u: `$ e. e# T //可能因为OSSemPend()中指定的timeout已经超时 //[由OSTimeTick()函数把本task重新置入了就绪控制矩阵,具体参考《浅析μC/OS-II v2.85内核OSTimeDly()函数工作原理》],( a8 l. b* N# p0 e //又或者确实在应用程序的某个地方调用了OSSemPost(),以下代码将具体解析是有什么引起的:1.超时,2.收到正常信号 OS_ENTER_CRITICAL();3 a. y. g7 j2 H% t" F7 a! t if (OSTCBCur->OSTCBStatPend != OS_STAT_PEND_OK) {, f5 G; i9 c; a: p c //是因为timeout超时,使得本task获得重新执行的机会 pend_stat = OSTCBCur->OSTCBStatPend;; w2 X0 c8 d2 `0 f( W' o- `$ | //清除event事件块上本task的标志) f/ l, A0 e. t3 H8 s' r- m! L OS_EventTOAbort(pevent); OS_EXIT_CRITICAL(); switch (pend_stat) { case OS_STAT_PEND_TO:* C, V7 ]6 G% K0 l0 n% @2 }$ G default:! j9 T$ Z! e, L$ l4 L* B5 O *perr = OS_ERR_TIMEOUT;5 @$ U# `! M, y" p: I% I/ R break; case OS_STAT_PEND_ABORT:) n$ h0 `. F9 r I5 u( W *perr = OS_ERR_PEND_ABORT; break;* M6 v6 j+ N. u% E5 }- l }% i' I7 d/ |* L return; } //由OSSemPost()抛出正常事件,唤醒了本task,因为在OSSemPost()时,8 l: m7 o. M* U/ ]5 ^; x: `* P //已经将本task在event事件控制矩阵上的对应位清除掉,并且把本task放入了就绪控制矩阵中,4 \5 s+ b3 b! R. [ //否则本task也不会执行至此. OSTCBCur->OSTCBEventPtr = (OS_EVENT *)0;//现在本task不悬停在任何event事件上 OS_EXIT_CRITICAL(); *perr = OS_ERR_NONE;9 Q* G1 y; c; n- n* ] }6 H' x" U* \; Z( Z( ^3 Z" h4 [ //----------------------------------------------------------------------: P; ^& y; {6 Y1 i1 a+ F //2.OS_EventTaskWait()函数* _( `4 u1 |1 r& }6 O) B void OS_EventTaskWait (OS_EVENT *pevent) {0 K# T0 E5 g; A5 a M' T INT8U y; //2007-09-09 gliethttp //pevent为此次task挂起的EventPtr单元3 `& T' R3 n; y p: x OSTCBCur->OSTCBEventPtr = pevent; //清除调度器中该task对应的标志位3 R4 u4 w, }- } t9 D Z y = OSTCBCur->OSTCBY; OSRdyTbl[y &= ~OSTCBCur->OSTCBBitX;- l! D% O0 z5 G4 k if (OSRdyTbl[y == 0) {/ ]; q& @" H1 F- q& V& } //当前y行对应的8个或16个task都已经悬停,那么当前y行也清除. OSRdyGrp &= ~OSTCBCur->OSTCBBitY; } //2007-09-09 gliethttp% Y+ q, X: A9 B4 ^! U9 X3 F //将该task的prio添加到pevent事件控制矩阵中,这个矩阵的功能和OSRdyGrp、OSRdyTbl没有区别2 M, r* j* a* j, x" ]' p2 r$ c //都是用来计算出已经就绪tasks中的优先级最高的那个 pevent->OSEventTbl[OSTCBCur->OSTCBY |= OSTCBCur->OSTCBBitX; pevent->OSEventGrp |= OSTCBCur->OSTCBBitY; }+ ~9 @/ r$ R/ E8 b& x( x3 B //----------------------------------------------------------------------: j. }$ C3 l( e0 b* n0 F3 |* m( U //3.OS_EventTOAbort()函数 void OS_EventTOAbort (OS_EVENT *pevent) { INT8U y;0 D: T/ B. O% U //清除event事件控制矩阵上本task的标志,因为OSTimeTick()函数未清除该单元. o6 a- R: Z& j3 i' f! K) P7 W //它仅仅把本task放入就绪控制矩阵中,使得本task重新获得被OS调度的机会而已+ D. d! l2 Y8 l //具体的清除工作还要自己完成0 @% e. ?) z7 H" Z2 a" _ //具体参考《浅析μC/OS-II v2.85内核OSTimeDly()函数工作原理》 y = OSTCBCur->OSTCBY;$ h! h8 W) C5 |8 ?, u pevent->OSEventTbl[y &= ~OSTCBCur->OSTCBBitX; if (pevent->OSEventTbl[y == 0x00) {. _* s' N& l. }7 h pevent->OSEventGrp &= ~OSTCBCur->OSTCBBitY;9 W. f n. L- o6 J- } } OSTCBCur->OSTCBStatPend = OS_STAT_PEND_OK; OSTCBCur->OSTCBStat = OS_STAT_RDY; OSTCBCur->OSTCBEventPtr = (OS_EVENT *)0;//现在本task不悬停在任何event事件上 }3 c" m, g9 ]. c1 i //---------------------------------------------------------------------- //4.OSSemPost()函数 INT8U OSSemPost (OS_EVENT *pevent) { #if OS_CRITICAL_METHOD == 3* v/ N7 C: m6 `! A: G& T; [ OS_CPU_SR cpu_sr = 0;//方式3将把cpsr状态寄存器推入临时堆栈cpu_sr中,可以安全返回之前的中断状态' I" `/ c8 A, D( j: W2 {+ X5 m #endif / e u' D, v1 z) ^* U [9 i #if OS_ARG_CHK_EN > 0" G3 H) {4 M) ]. {9 {: K' r if (pevent == (OS_EVENT *)0) { return (OS_ERR_PEVENT_NULL); } #endif9 R2 }* p8 ?+ n$ S: ? if (pevent->OSEventType != OS_EVENT_TYPE_SEM) {% w5 Y- ?! n( N return (OS_ERR_EVENT_TYPE); } OS_ENTER_CRITICAL();2 O4 v, C7 Y5 g; M4 w/ Q) @. Y0 r0 E if (pevent->OSEventGrp != 0) { //2007-09-09 gliethttp //OS_EventTaskRdy()函数将摘掉等待在pevent事件控制矩阵上的task中优先级最高的task //如果该task仅仅等待该pevent事件,那么将该task添加到就绪控制矩阵中8 i g$ r4 {% L //OSRdyGrp |= bity; //OSRdyTbl[y] |= bitx;这样调度程序就会根据情况调度OS_Sched()该task了, s+ a' c+ h0 P$ R. k1 w6 ]9 n; b, ^+ B (void)OS_EventTaskRdy(pevent, (void *)0, OS_STAT_SEM, OS_STAT_PEND_OK); OS_EXIT_CRITICAL();1 F9 h: g" |% o% H* } //可能刚刚放到就绪控制矩阵上的被唤醒的task的优先级比调用OSSemPost()函数的进程B优先级高 //所以需要调用shedule函数, //如果真的高,那么调用OSSemPost()函数的进程B就要被抢占,os将会切换到新的task去执行[gliethttp] //如果没有调用OSSemPost()函数的进程B优先级高,那么os不会切换,仍然继续执行进程B,OSSemPost()正常返回4 e3 C% G0 w9 r- k! N OS_Sched(); return (OS_ERR_NONE); } E: {& ]) U, L0 d2 B //没有任何一个task悬停在本event事件控制矩阵上, //那么单纯的对pevent->OSEventCnt++加操作.. t4 N. H- k9 h4 {( j: { if (pevent->OSEventCnt < 65535u) {8 d" W. U+ L7 N5 D! P v pevent->OSEventCnt++;/ ^. K' A2 M' k1 o8 x/ c- P OS_EXIT_CRITICAL();) ~# Z; k; ^4 f# G/ R6 l return (OS_ERR_NONE);1 t! u8 m; a" x' l1 f1 R) l } //已经堆积了0xffff次,溢出 OS_EXIT_CRITICAL();4 C, c. [3 `/ t3 l3 p! N. M; } return (OS_ERR_SEM_OVF);7 s- c3 Q6 P( e2 `& S& V) m } //---------------------------------------------------------------------- //5.OS_EventTaskRdy()函数4 E7 H7 s5 F, x4 S: Z4 G% ] INT8U OS_EventTaskRdy (OS_EVENT *pevent, void *pmsg, INT8U msk, INT8U pend_stat) { OS_TCB *ptcb; INT8U x;2 L) B& m& ~& E, D" e INT8U y; INT8U prio;" {( z( p+ [8 l2 j #if OS_LOWEST_PRIO <= 63* W5 r8 z7 r0 p7 x9 j" p INT8U bitx; INT8U bity;4 n' {2 S9 M3 W #else, k% t, [0 ^, f5 U/ u5 E) _3 _ INT16U bitx; INT16U bity; INT16U *ptbl;8 }2 {; u" ~6 `6 k8 W/ |' Q #endif: ^8 T3 s, U9 S #if OS_LOWEST_PRIO <= 63# R; t% z% a3 c: y //小于64个task时,快速计算; W5 T/ d4 `. I" t! O$ w //最有优先权的task位于事件控制矩阵中的第y行的第x列0 ]8 J/ W9 o* I; z! r y = OSUnMapTbl[pevent->OSEventGrp;2 C7 X+ z& ]8 c' ?+ M Q bity = (INT8U)(1 << y);; w5 g7 I3 q9 T% T) g. L( J& z x = OSUnMapTbl[pevent->OSEventTbl[y; bitx = (INT8U)(1 << x); prio = (INT8U)((y << 3) + x); #else //对于256个task, x% |# k: I3 x4 [- A //最有优先权的task位于事件控制矩阵中的第y行的第x列1 E3 g( F' [2 C- k4 ?8 \ //以下的操作原理具体参见《浅析μC/OS-II v2.85内核调度函数》 if ((pevent->OSEventGrp & 0xFF) != 0) { y = OSUnMapTbl[pevent->OSEventGrp & 0xFF;+ l$ z" n8 \' N4 J+ |: @; q$ @ } else { y = OSUnMapTbl[(pevent->OSEventGrp >> 8) & 0xFF + 8;$ C) T3 j; b: Y' R+ ` H } bity = (INT16U)(1 << y); ptbl = &pevent->OSEventTbl[y;& g) e9 }* Z+ n4 G. z5 {% W6 D. M5 J if ((*ptbl & 0xFF) != 0) {% J1 e, @! Z$ T4 ?3 L x = OSUnMapTbl[*ptbl & 0xFF;1 _, P5 ~5 v7 w } else { x = OSUnMapTbl[(*ptbl >> 8) & 0xFF + 8;3 x& B. t7 E3 t } bitx = (INT16U)(1 << x);9 y( q, ^0 z: q7 l' w# y' X prio = (INT8U)((y << 4) + x);//该task对应的prio优先级值 //ok,等待在event事件上的所有task中,只有在事件控制矩阵中的第y行的第x列task. V x6 l5 `' T/ F' c0 k/ d //优先级最高、最值的成为此次事件的唤醒对象[gliethttp], x( T9 b1 n1 I2 j3 u% i7 r #endif //清除此task在event事件控制矩阵中的bit位 pevent->OSEventTbl[y &= ~bitx;# \+ t; c, u. t# ^6 b/ _/ [ if (pevent->OSEventTbl[y == 0) {0 E4 u M9 I* q' P! ~ pevent->OSEventGrp &= ~bity; } //通过prio优先级找到该prio唯一对应的task对应的ptcb进程上下文控制块2 F; J9 S& \1 C V7 y0 O ptcb = OSTCBPrioTbl[prio;1 \ s9 n3 d8 S$ n ptcb->OSTCBDly = 0;//复原为正常9 R. o9 f, c. `" F% T1 ]0 B( G! U 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$ \2 R( m7 G; A) j% e/ Q! ] ptcb->OSTCBStatPend = pend_stat;//悬停状态值 ptcb->OSTCBStat &= ~msk;//该msk事件已经发生,清除task上下文控制块上的msk位,如:OS_STAT_SEM! Y/ g5 e) g, D# ~! q6 @ if (ptcb->OSTCBStat == OS_STAT_RDY) {- n' S0 r, s& z' s. X" l //如果当前task只是等待该事件,那么把该task放到就绪控制矩阵中,允许内核调度本task6 t$ W: |. Z& U; L' k/ P* ^# T8 S. X OSRdyGrp |= bity; OSRdyTbl[y |= bitx;5 b3 F! K9 [4 f8 R9 { } return (prio);//返回本task对应的优先级值 } //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ PS:"所以从这里来看,os中的各个功能单元管理着自己的事情,就像面向对象的封装一样,"% w' b+ {, R' `8 [& Z) N* y "事件控制矩阵和就绪控制矩阵是各个对象独立自治的关键因素"3 v- j# D5 G+ t" G) ~. b "其他对象,都努力说服自己相信别的对象是独立的、可信任的、安全的"[gliethttp# b1 k9 w! u5 n& a6 |# U2 w K. t //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
| 看看 |
微信公众号
手机版