//---------------------------------------------------------------------- //1.OSSemPend()函数 void OSSemPend (OS_EVENT *pevent, INT16U timeout, INT8U *perr)! D; `/ d" |7 a8 D6 I: Z* r {# J6 Y% n5 l/ C( w( d3 r' | INT8U pend_stat;% p' e0 k, i$ I' D9 O$ c #if OS_CRITICAL_METHOD == 3 OS_CPU_SR cpu_sr = 0;3 f5 L" ^% }% D/ k. _' P3 Q5 i4 V #endif & r Y' w' X1 _* c, K #if OS_ARG_CHK_EN > 00 k1 p) W: ^) x. h if (perr == (INT8U *)0) { return; }; c9 u9 Z5 K; U" ~+ G if (pevent == (OS_EVENT *)0) {; a2 e* s R6 S3 M, [ *perr = OS_ERR_PEVENT_NULL;* l& S9 x6 q3 M* B" w. ?' y4 C8 p return;4 f4 `! L2 n& s, m" M6 p }9 [8 U! d7 Z% V6 P* @8 y6 c #endif0 W7 r& Q! p! k" m if (pevent->OSEventType != OS_EVENT_TYPE_SEM) {3 C. C D7 r% ^' t2 P //确保该event控制块是Sem类型 *perr = OS_ERR_EVENT_TYPE;; G' p+ R! e1 | return; } if (OSIntNesting > 0) { //ISR中,不能使用OSSemPend() *perr = OS_ERR_PEND_ISR; return; } if (OSLockNesting > 0) {: h, P( I9 Q( k) ^ Q //μCOS/II v2.85内核已经被强制锁住 *perr = OS_ERR_PEND_LOCKED;! W+ ?# _# T6 j! H2 J2 | return;; H5 M2 j0 u$ f4 G( O& B } //非法的统统不是,信号正常,所以有必要进一步处理" ^, Z! ~& G* d* s OS_ENTER_CRITICAL(); if (pevent->OSEventCnt > 0) {% C7 S& B# s9 K* Q$ s; i //程序的其他地方已经触发了事件,异或在初始化时设定了n,如:OSSemCreate(2);$ ^ T0 S4 P0 e, ` //所以该task无需悬停,直接获得事件的使用权9 l, \" i! i0 z pevent->OSEventCnt--; OS_EXIT_CRITICAL(); *perr = OS_ERR_NONE;1 G; T' B8 T6 @# _, T return; }3 F% N% Q6 ?& Q2 C- @6 i //当前还没有任何事件发生,所以本task需要悬停,让出cpu[gliethttp] OSTCBCur->OSTCBStat |= OS_STAT_SEM;//是sem事件让本task进入悬停等待的 OSTCBCur->OSTCBStatPend = OS_STAT_PEND_OK;//假定不是超时,为正常收到信号 R. j/ g$ Q$ b% Z6 ^. r1 }6 [ //超时,如果timeout=0,那么,本task将一直悬停,仅仅当收到事件触发信号后才重新进入调度队列. @( e8 N$ e& p. @; i7 ~5 r OSTCBCur->OSTCBDly = timeout; //OS_EventTaskWait()函数实现的功能: //把本task从就绪控制矩阵中摘下,放到pevent事件专有的进程事件控制矩阵表中.! N" K# j1 ?0 @; z+ K2 d, I+ ~ OS_EventTaskWait(pevent); OS_EXIT_CRITICAL(); //因为本task正在运行,所以本task现在的优先级最高,现在本task已经将自己从就绪控制矩阵--调度器(x,y)矩形阵列中 //把自己摘掉,所以调度函数OS_Sched()一定会切换到另一个task中执行新task的代码[gliethttp]2 o! }& \; n0 J$ V OS_Sched();//具体参见《浅析μC/OS-II v2.85内核调度函数》/ R- ^0 s e: i j' u; ~4 ` //2007-09-09 gliethttp& ~/ L1 r+ v/ g6 F //可能因为OSSemPend()中指定的timeout已经超时 //[由OSTimeTick()函数把本task重新置入了就绪控制矩阵,具体参考《浅析μC/OS-II v2.85内核OSTimeDly()函数工作原理》],9 K' ?0 \6 B, o' t' o. m, I' ] //又或者确实在应用程序的某个地方调用了OSSemPost(),以下代码将具体解析是有什么引起的:1.超时,2.收到正常信号 OS_ENTER_CRITICAL();1 l" `$ G% C) s4 z: _ if (OSTCBCur->OSTCBStatPend != OS_STAT_PEND_OK) { //是因为timeout超时,使得本task获得重新执行的机会 pend_stat = OSTCBCur->OSTCBStatPend; //清除event事件块上本task的标志 OS_EventTOAbort(pevent); OS_EXIT_CRITICAL();* R5 s, g( n) f, O- e; z- E switch (pend_stat) { case OS_STAT_PEND_TO: default:5 \( ^. }4 d9 s1 G1 @. `& x *perr = OS_ERR_TIMEOUT; break; case OS_STAT_PEND_ABORT: *perr = OS_ERR_PEND_ABORT;* t+ b# n5 | I) b0 w5 T. m break;& r- d" q! V2 q. E } return; }) D8 J' Z4 c' }$ \, j5 K: d0 R' A //由OSSemPost()抛出正常事件,唤醒了本task,因为在OSSemPost()时, //已经将本task在event事件控制矩阵上的对应位清除掉,并且把本task放入了就绪控制矩阵中,! }- d; g) \( C: y$ q6 r" c8 e1 S1 _ //否则本task也不会执行至此./ b! k5 Z1 h3 ?) w5 i OSTCBCur->OSTCBEventPtr = (OS_EVENT *)0;//现在本task不悬停在任何event事件上 OS_EXIT_CRITICAL(); *perr = OS_ERR_NONE;/ Z" Z- K, Q: b7 i% E# Y( b } //----------------------------------------------------------------------0 j3 a0 {& c' R) C1 k. X //2.OS_EventTaskWait()函数 void OS_EventTaskWait (OS_EVENT *pevent)9 u* [, ~( K9 K+ o: R8 v {# S% ^' J. U+ z1 r INT8U y; //2007-09-09 gliethttp //pevent为此次task挂起的EventPtr单元 OSTCBCur->OSTCBEventPtr = pevent;6 l* A. @( Y# ^3 ] //清除调度器中该task对应的标志位- ?8 E5 h t2 u! G# ?$ I6 H9 O y = OSTCBCur->OSTCBY;* A1 U J9 o. U: F* }( f; ?$ e OSRdyTbl[y &= ~OSTCBCur->OSTCBBitX; if (OSRdyTbl[y == 0) { //当前y行对应的8个或16个task都已经悬停,那么当前y行也清除. OSRdyGrp &= ~OSTCBCur->OSTCBBitY; }# ?- h' X8 [( f F //2007-09-09 gliethttp //将该task的prio添加到pevent事件控制矩阵中,这个矩阵的功能和OSRdyGrp、OSRdyTbl没有区别 //都是用来计算出已经就绪tasks中的优先级最高的那个" C7 j' L: V' y1 N; [3 V* u# P2 F pevent->OSEventTbl[OSTCBCur->OSTCBY |= OSTCBCur->OSTCBBitX; pevent->OSEventGrp |= OSTCBCur->OSTCBBitY;- V( L. q7 q2 K, Q* \+ y# l }* S" V; @" d3 P0 F$ D1 j3 H //----------------------------------------------------------------------. X- G! }: R: m: m //3.OS_EventTOAbort()函数 void OS_EventTOAbort (OS_EVENT *pevent); M/ [9 o: m2 n { INT8U y;" W; F" F/ o" F; k //清除event事件控制矩阵上本task的标志,因为OSTimeTick()函数未清除该单元: K6 f/ n" s* J //它仅仅把本task放入就绪控制矩阵中,使得本task重新获得被OS调度的机会而已6 U/ L: Z+ G! V5 x1 p //具体的清除工作还要自己完成 //具体参考《浅析μC/OS-II v2.85内核OSTimeDly()函数工作原理》7 j5 y$ [* x' }1 E0 n' x/ u, q y = OSTCBCur->OSTCBY;1 J: e: z% u( T% i4 y! N6 z w8 K pevent->OSEventTbl[y &= ~OSTCBCur->OSTCBBitX; if (pevent->OSEventTbl[y == 0x00) { q$ C& v2 Y/ n% C8 R; d pevent->OSEventGrp &= ~OSTCBCur->OSTCBBitY;3 b) n3 e1 t% m( N } OSTCBCur->OSTCBStatPend = OS_STAT_PEND_OK; OSTCBCur->OSTCBStat = OS_STAT_RDY;: M7 Q; b" X: Z6 ? OSTCBCur->OSTCBEventPtr = (OS_EVENT *)0;//现在本task不悬停在任何event事件上 }4 g' @( i, j: S% ?# `- l# g //---------------------------------------------------------------------- //4.OSSemPost()函数& P, U5 V0 x& x7 W0 l2 e- ]1 | INT8U OSSemPost (OS_EVENT *pevent)5 w& b' F# Z4 T% n% @ {' }& m7 ?9 J2 x% W- g. t #if OS_CRITICAL_METHOD == 3+ }7 e! Q* i5 j4 W V8 u OS_CPU_SR cpu_sr = 0;//方式3将把cpsr状态寄存器推入临时堆栈cpu_sr中,可以安全返回之前的中断状态) Z/ F }" B9 {! p5 f #endif #if OS_ARG_CHK_EN > 0 if (pevent == (OS_EVENT *)0) {" _: D! K5 m3 a9 X return (OS_ERR_PEVENT_NULL); S/ R/ c$ Q+ j } #endif: v% E* `; |+ `9 W/ s* D if (pevent->OSEventType != OS_EVENT_TYPE_SEM) {0 I9 F: I8 \/ n& J h- p7 \2 t return (OS_ERR_EVENT_TYPE);3 ?' R' ~ s0 ~) ^3 C2 D }2 f' E5 a# v# u" | OS_ENTER_CRITICAL();. m# z! ]/ N9 ]: O7 c+ K* l2 d if (pevent->OSEventGrp != 0) { //2007-09-09 gliethttp6 D& e3 c( B$ D //OS_EventTaskRdy()函数将摘掉等待在pevent事件控制矩阵上的task中优先级最高的task //如果该task仅仅等待该pevent事件,那么将该task添加到就绪控制矩阵中 //OSRdyGrp |= bity;4 k0 x) v% ~- {# @ //OSRdyTbl[y] |= bitx;这样调度程序就会根据情况调度OS_Sched()该task了 (void)OS_EventTaskRdy(pevent, (void *)0, OS_STAT_SEM, OS_STAT_PEND_OK);9 i2 ` k$ s. V3 p% H* r% e OS_EXIT_CRITICAL();3 G; ^" z0 ~! M9 a# z# v //可能刚刚放到就绪控制矩阵上的被唤醒的task的优先级比调用OSSemPost()函数的进程B优先级高3 v9 _: J" B8 S9 x2 } //所以需要调用shedule函数,$ j4 |3 C2 ~( F- r" R //如果真的高,那么调用OSSemPost()函数的进程B就要被抢占,os将会切换到新的task去执行[gliethttp]' j' L D: b0 M- l' v //如果没有调用OSSemPost()函数的进程B优先级高,那么os不会切换,仍然继续执行进程B,OSSemPost()正常返回6 w4 _1 e }$ R& `. E OS_Sched();8 `, K- A; u0 I return (OS_ERR_NONE); } //没有任何一个task悬停在本event事件控制矩阵上," C( s6 O+ g# \$ B" T8 \ //那么单纯的对pevent->OSEventCnt++加操作.6 ^( o/ O; j% u6 F if (pevent->OSEventCnt < 65535u) { pevent->OSEventCnt++;$ u: B5 `% L0 ~& T @7 t' A9 a OS_EXIT_CRITICAL(); return (OS_ERR_NONE);& l3 w; H% u6 b; [$ @ }+ E& s% G1 R$ W$ s //已经堆积了0xffff次,溢出2 `3 J' B% W L( J7 B OS_EXIT_CRITICAL();% [& V2 b8 n% ]. ?( n Q- l i6 R return (OS_ERR_SEM_OVF); }) ]) \0 ~# M8 f* V( D //----------------------------------------------------------------------7 H# n; Z. |* S1 [3 W% d //5.OS_EventTaskRdy()函数 INT8U OS_EventTaskRdy (OS_EVENT *pevent, void *pmsg, INT8U msk, INT8U pend_stat) _' t( D7 A! D6 W { OS_TCB *ptcb; INT8U x;& d4 h1 [ \. i6 X# k6 j& U INT8U y; INT8U prio; #if OS_LOWEST_PRIO <= 63 INT8U bitx;* S+ V+ c% v1 k X8 ~ INT8U bity;$ A6 `5 H0 m3 R, X* k; M #else2 X' s7 v$ h' z$ q* l INT16U bitx;+ H; ?' f( R4 O4 ~/ ~, s+ U) M! v INT16U bity;. L7 W4 G) H0 q& a* b INT16U *ptbl; #endif 7 n3 h. U. y% @4 W0 D #if OS_LOWEST_PRIO <= 63; l! z/ d8 n( \# T8 Y5 C+ L' L //小于64个task时,快速计算 //最有优先权的task位于事件控制矩阵中的第y行的第x列 y = OSUnMapTbl[pevent->OSEventGrp;( M8 B( p7 {3 y, f3 V3 n bity = (INT8U)(1 << y);' P5 ?* ~5 }- s4 ^$ n x = OSUnMapTbl[pevent->OSEventTbl[y; bitx = (INT8U)(1 << x);. \, h1 V3 ^% C! I9 W9 R3 S prio = (INT8U)((y << 3) + x); j \; v2 u& q3 { #else //对于256个task //最有优先权的task位于事件控制矩阵中的第y行的第x列 //以下的操作原理具体参见《浅析μC/OS-II v2.85内核调度函数》 if ((pevent->OSEventGrp & 0xFF) != 0) {: s; K) }' q- m W& h y = OSUnMapTbl[pevent->OSEventGrp & 0xFF; } else { y = OSUnMapTbl[(pevent->OSEventGrp >> 8) & 0xFF + 8;& t3 Y: n: q1 t: G; f( F } bity = (INT16U)(1 << y);1 ]2 b' `) _2 h$ j4 M( { ptbl = &pevent->OSEventTbl[y; if ((*ptbl & 0xFF) != 0) { x = OSUnMapTbl[*ptbl & 0xFF;- ], M! o- H8 @1 I! _# f# X } else { x = OSUnMapTbl[(*ptbl >> 8) & 0xFF + 8; } bitx = (INT16U)(1 << x); prio = (INT8U)((y << 4) + x);//该task对应的prio优先级值 //ok,等待在event事件上的所有task中,只有在事件控制矩阵中的第y行的第x列task //优先级最高、最值的成为此次事件的唤醒对象[gliethttp]6 x$ t5 y0 Y/ k. C: f. e3 S #endif //清除此task在event事件控制矩阵中的bit位+ W2 e% s/ j0 B: L; U& _6 Z% ` pevent->OSEventTbl[y &= ~bitx; if (pevent->OSEventTbl[y == 0) { pevent->OSEventGrp &= ~bity; } //通过prio优先级找到该prio唯一对应的task对应的ptcb进程上下文控制块( f& j+ m: f3 i& t ptcb = OSTCBPrioTbl[prio; ptcb->OSTCBDly = 0;//复原为正常; T. X0 t6 m7 J$ i ptcb->OSTCBEventPtr = (OS_EVENT *)0;//现在本task不悬停在任何event事件上 #if ((OS_Q_EN > 0) && (OS_MAX_QS > 0)) || (OS_MBOX_EN > 0)+ _4 o9 y& P/ ?! \, O& G ptcb->OSTCBMsg = pmsg;//传递消息指针 #else6 t6 R0 I0 y. p* X pmsg = pmsg; #endif4 w, |5 ]$ w, r ?4 \) {% c ptcb->OSTCBStatPend = pend_stat;//悬停状态值 ptcb->OSTCBStat &= ~msk;//该msk事件已经发生,清除task上下文控制块上的msk位,如:OS_STAT_SEM, n6 b1 R$ }, s if (ptcb->OSTCBStat == OS_STAT_RDY) { //如果当前task只是等待该事件,那么把该task放到就绪控制矩阵中,允许内核调度本task OSRdyGrp |= bity; OSRdyTbl[y |= bitx; }( R5 M' o$ }' N( ?9 a/ H return (prio);//返回本task对应的优先级值 } //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++" B3 F. ~' J; U, w9 R PS:"所以从这里来看,os中的各个功能单元管理着自己的事情,就像面向对象的封装一样,"5 a- `$ S; B& e5 X( k, F. O% c: L$ N "事件控制矩阵和就绪控制矩阵是各个对象独立自治的关键因素" "其他对象,都努力说服自己相信别的对象是独立的、可信任的、安全的"[gliethttp //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
看看 |