|
//----------------------------------------------------------------------8 O' L) x/ ^( X ?7 l0 A //1.OSSemPend()函数 void OSSemPend (OS_EVENT *pevent, INT16U timeout, INT8U *perr) { INT8U pend_stat;3 \. E: D% o/ f8 Q5 x #if OS_CRITICAL_METHOD == 3 OS_CPU_SR cpu_sr = 0; #endif7 W" H# V, H& a$ H, o$ c #if OS_ARG_CHK_EN > 0 if (perr == (INT8U *)0) { return; } if (pevent == (OS_EVENT *)0) {4 J: z7 K j5 _1 e6 k *perr = OS_ERR_PEVENT_NULL; return; } #endif if (pevent->OSEventType != OS_EVENT_TYPE_SEM) {0 \ ~6 _2 s8 K O //确保该event控制块是Sem类型5 V5 h t ]3 m *perr = OS_ERR_EVENT_TYPE; return;) n9 B- F8 b3 ?8 l } x! C7 g3 Y2 e, n3 | if (OSIntNesting > 0) { //ISR中,不能使用OSSemPend() *perr = OS_ERR_PEND_ISR; return; }0 ?. _8 b! `* X( d | if (OSLockNesting > 0) { //μCOS/II v2.85内核已经被强制锁住$ e5 B1 k' _( i p1 L$ W& p: _ *perr = OS_ERR_PEND_LOCKED;) {" G: G9 _: o( x' ~ return;; _1 ~, l- U9 q }7 S# J0 A0 `4 t/ A6 w //非法的统统不是,信号正常,所以有必要进一步处理 OS_ENTER_CRITICAL();5 n+ {& Z, U7 E, ] if (pevent->OSEventCnt > 0) { //程序的其他地方已经触发了事件,异或在初始化时设定了n,如:OSSemCreate(2);" K, f& m( }+ Y2 {) U/ u //所以该task无需悬停,直接获得事件的使用权+ _- {9 d! n) V* J- u+ F# V4 U pevent->OSEventCnt--; OS_EXIT_CRITICAL(); *perr = OS_ERR_NONE;( m& U0 X$ V5 L I, h# ?* S- X( ? Q return;7 [- w& o" F! Z# s; w8 A }* {& v; N$ q& D4 q5 c //当前还没有任何事件发生,所以本task需要悬停,让出cpu[gliethttp] OSTCBCur->OSTCBStat |= OS_STAT_SEM;//是sem事件让本task进入悬停等待的 OSTCBCur->OSTCBStatPend = OS_STAT_PEND_OK;//假定不是超时,为正常收到信号. H. x2 S% k6 R( k& E& x //超时,如果timeout=0,那么,本task将一直悬停,仅仅当收到事件触发信号后才重新进入调度队列 OSTCBCur->OSTCBDly = timeout; //OS_EventTaskWait()函数实现的功能: //把本task从就绪控制矩阵中摘下,放到pevent事件专有的进程事件控制矩阵表中./ p1 d1 w2 Z4 z OS_EventTaskWait(pevent);% H8 I( b* M) d, S3 `2 d$ f OS_EXIT_CRITICAL(); //因为本task正在运行,所以本task现在的优先级最高,现在本task已经将自己从就绪控制矩阵--调度器(x,y)矩形阵列中/ P0 V: L& F) ^ //把自己摘掉,所以调度函数OS_Sched()一定会切换到另一个task中执行新task的代码[gliethttp] OS_Sched();//具体参见《浅析μC/OS-II v2.85内核调度函数》. X2 H/ d9 {5 i //2007-09-09 gliethttp //可能因为OSSemPend()中指定的timeout已经超时- |( V B! v4 C0 X //[由OSTimeTick()函数把本task重新置入了就绪控制矩阵,具体参考《浅析μC/OS-II v2.85内核OSTimeDly()函数工作原理》], //又或者确实在应用程序的某个地方调用了OSSemPost(),以下代码将具体解析是有什么引起的:1.超时,2.收到正常信号% p' h' ^, K7 C% e1 m' L OS_ENTER_CRITICAL();2 j2 D+ Z+ A b' U+ b& l if (OSTCBCur->OSTCBStatPend != OS_STAT_PEND_OK) {8 X; x0 ~6 D, y# A1 n6 _ //是因为timeout超时,使得本task获得重新执行的机会 pend_stat = OSTCBCur->OSTCBStatPend;- G7 Y, q) \2 @, X+ Z- k) _8 I4 c- N8 P //清除event事件块上本task的标志- [4 a- e, F) ]1 g: b" D OS_EventTOAbort(pevent);$ {- K7 ~, a Q6 H' s' k/ F4 b OS_EXIT_CRITICAL(); switch (pend_stat) {& l% X" N9 t j) [ case OS_STAT_PEND_TO:% p1 |9 T6 K( {0 a default:7 u: L/ c: r% r8 X *perr = OS_ERR_TIMEOUT; break; case OS_STAT_PEND_ABORT: *perr = OS_ERR_PEND_ABORT;6 T/ p2 t/ U, a1 @2 y* N6 N break;' ^: n' I' t3 t; A! j8 g }# j7 y+ ~. p) _! d% B- i9 I return;; c' T7 h3 p+ ~* g0 T# q }( @3 l5 r- _* N- x/ P //由OSSemPost()抛出正常事件,唤醒了本task,因为在OSSemPost()时, //已经将本task在event事件控制矩阵上的对应位清除掉,并且把本task放入了就绪控制矩阵中,6 X" r5 K: }( ~$ J //否则本task也不会执行至此.; S6 _: S' |/ D) L OSTCBCur->OSTCBEventPtr = (OS_EVENT *)0;//现在本task不悬停在任何event事件上. s. F# X3 k' F OS_EXIT_CRITICAL(); *perr = OS_ERR_NONE; }) L6 U) [ e' q //----------------------------------------------------------------------: S |; p5 M7 g1 m //2.OS_EventTaskWait()函数1 [# c/ Q" O( X" A& @5 j void OS_EventTaskWait (OS_EVENT *pevent) { INT8U y;* B% i R g s //2007-09-09 gliethttp' ~" e0 z+ @1 p6 t //pevent为此次task挂起的EventPtr单元9 }0 D$ N3 K9 A& V OSTCBCur->OSTCBEventPtr = pevent;" k* \% k% B& [0 Z //清除调度器中该task对应的标志位2 m, ^& _* m* s+ n8 a2 @5 i y = OSTCBCur->OSTCBY;2 P/ ?# P* z, ^% o' L/ r/ m# Y OSRdyTbl[y &= ~OSTCBCur->OSTCBBitX;1 b$ i l2 h' x# T- }* p if (OSRdyTbl[y == 0) { //当前y行对应的8个或16个task都已经悬停,那么当前y行也清除. OSRdyGrp &= ~OSTCBCur->OSTCBBitY; } //2007-09-09 gliethttp //将该task的prio添加到pevent事件控制矩阵中,这个矩阵的功能和OSRdyGrp、OSRdyTbl没有区别7 @$ j3 b( e" {: J) H //都是用来计算出已经就绪tasks中的优先级最高的那个 pevent->OSEventTbl[OSTCBCur->OSTCBY |= OSTCBCur->OSTCBBitX; pevent->OSEventGrp |= OSTCBCur->OSTCBBitY; }# _% F* M. u }9 W) g7 o' M5 J8 w7 s& D; z //----------------------------------------------------------------------" M+ r; B; Z4 N6 w //3.OS_EventTOAbort()函数 void OS_EventTOAbort (OS_EVENT *pevent) {3 _/ v: Y7 F# c Z INT8U y; //清除event事件控制矩阵上本task的标志,因为OSTimeTick()函数未清除该单元% ^5 q! P/ v9 r, T" f, |8 T8 n: b //它仅仅把本task放入就绪控制矩阵中,使得本task重新获得被OS调度的机会而已7 J# T* z" i, u6 s //具体的清除工作还要自己完成& P& d! u$ s5 @0 u- ]7 T9 C //具体参考《浅析μC/OS-II v2.85内核OSTimeDly()函数工作原理》 y = OSTCBCur->OSTCBY;( D9 j2 o0 X/ O1 c pevent->OSEventTbl[y &= ~OSTCBCur->OSTCBBitX;+ O3 R- b' E }3 W% @! j1 o9 b if (pevent->OSEventTbl[y == 0x00) {# `. M. t, D( x pevent->OSEventGrp &= ~OSTCBCur->OSTCBBitY; }, X6 P, w1 l: K6 u7 W) e9 Z OSTCBCur->OSTCBStatPend = OS_STAT_PEND_OK; OSTCBCur->OSTCBStat = OS_STAT_RDY; OSTCBCur->OSTCBEventPtr = (OS_EVENT *)0;//现在本task不悬停在任何event事件上 } //---------------------------------------------------------------------- //4.OSSemPost()函数 INT8U OSSemPost (OS_EVENT *pevent)& |2 F# V/ q% T9 O" d" {9 A! b { #if OS_CRITICAL_METHOD == 34 Y& U x3 g6 U7 v OS_CPU_SR cpu_sr = 0;//方式3将把cpsr状态寄存器推入临时堆栈cpu_sr中,可以安全返回之前的中断状态 #endif1 R: i- {8 r2 L: T0 w+ K7 J #if OS_ARG_CHK_EN > 0 if (pevent == (OS_EVENT *)0) {# R% }2 D0 _ `2 v$ E return (OS_ERR_PEVENT_NULL); } #endif4 {0 A1 b8 D% M6 ^ if (pevent->OSEventType != OS_EVENT_TYPE_SEM) {" T. [1 H$ M; j' w. U7 K% k return (OS_ERR_EVENT_TYPE);& g$ k# y: t+ R) t; X" _& B } OS_ENTER_CRITICAL(); if (pevent->OSEventGrp != 0) {; g( ?: ^) n9 F% U //2007-09-09 gliethttp/ _' W' F6 S& ^2 G //OS_EventTaskRdy()函数将摘掉等待在pevent事件控制矩阵上的task中优先级最高的task //如果该task仅仅等待该pevent事件,那么将该task添加到就绪控制矩阵中" p. P* b/ a/ k Y //OSRdyGrp |= bity; C( G, d* M0 a: u //OSRdyTbl[y] |= bitx;这样调度程序就会根据情况调度OS_Sched()该task了) A( D& T# M* E3 r (void)OS_EventTaskRdy(pevent, (void *)0, OS_STAT_SEM, OS_STAT_PEND_OK); OS_EXIT_CRITICAL();- p6 G- Y$ J( F, r) {$ s" U& w7 ` //可能刚刚放到就绪控制矩阵上的被唤醒的task的优先级比调用OSSemPost()函数的进程B优先级高& D0 b2 t! t3 C( O: w4 c! ` //所以需要调用shedule函数,' P8 E' U# d3 O# i5 v3 k# n //如果真的高,那么调用OSSemPost()函数的进程B就要被抢占,os将会切换到新的task去执行[gliethttp] //如果没有调用OSSemPost()函数的进程B优先级高,那么os不会切换,仍然继续执行进程B,OSSemPost()正常返回 }3 L) v: s+ O; y9 z q OS_Sched();# @" C& E* U- g. n& U9 V return (OS_ERR_NONE); } //没有任何一个task悬停在本event事件控制矩阵上, //那么单纯的对pevent->OSEventCnt++加操作.6 d* O7 ?, K0 e) x# m if (pevent->OSEventCnt < 65535u) { pevent->OSEventCnt++;% n. a5 a/ R- \& c: u6 }3 C# Q& j' L OS_EXIT_CRITICAL();7 a. b/ Z: F+ j3 c# o return (OS_ERR_NONE); } //已经堆积了0xffff次,溢出: B* v$ f! G6 r8 B; c$ J OS_EXIT_CRITICAL();; i6 u5 i$ l% u% S return (OS_ERR_SEM_OVF);8 p Q( D( g! g- T# ^' f7 K- ? }3 B. ]4 m2 v. g/ q- g' J+ h% u7 t8 C //---------------------------------------------------------------------- //5.OS_EventTaskRdy()函数 INT8U OS_EventTaskRdy (OS_EVENT *pevent, void *pmsg, INT8U msk, INT8U pend_stat) { OS_TCB *ptcb;2 u) T/ O! \8 m8 w/ G INT8U x;) h! |. f U( _ z( o5 M+ K INT8U y;) `3 b8 `( S* @) f INT8U prio; #if OS_LOWEST_PRIO <= 63; n( D7 F& m# I! F* m INT8U bitx;5 T; Q+ o2 c$ h7 j2 j, V% W INT8U bity;+ ^# y. f8 S9 f3 n2 W0 V #else' \" d6 ~ d) y0 } INT16U bitx;/ t: g: {/ r- `4 w; @# V INT16U bity; INT16U *ptbl;7 Q: H- l6 U! S) e3 ]2 |; E& S #endif, j! L+ Q" B+ G$ G( m# B . ~( t3 S0 j1 r9 e x1 W$ S$ G #if OS_LOWEST_PRIO <= 63, B% d4 F- y3 S; T5 Z //小于64个task时,快速计算 //最有优先权的task位于事件控制矩阵中的第y行的第x列/ \# U7 k5 E/ _( m y = OSUnMapTbl[pevent->OSEventGrp;# ^, r/ ^) S, ?. w3 L bity = (INT8U)(1 << y); x = OSUnMapTbl[pevent->OSEventTbl[y;1 L/ \( D5 r8 A2 y, [- l bitx = (INT8U)(1 << x); prio = (INT8U)((y << 3) + x); #else* Q# }; P% D1 b" @/ t //对于256个task8 x9 y) ~0 K: H* I; a( n //最有优先权的task位于事件控制矩阵中的第y行的第x列 //以下的操作原理具体参见《浅析μC/OS-II v2.85内核调度函数》8 n" M0 ]/ ^: ~ if ((pevent->OSEventGrp & 0xFF) != 0) {& ]4 ?3 p8 W/ h% q7 ^$ ~' F* Z y = OSUnMapTbl[pevent->OSEventGrp & 0xFF; } else {) U- [& R3 x5 s1 w: F- ]2 N. q* D y = OSUnMapTbl[(pevent->OSEventGrp >> 8) & 0xFF + 8; } bity = (INT16U)(1 << y); ptbl = &pevent->OSEventTbl[y;) K/ ]3 C. p8 s% A# c7 j if ((*ptbl & 0xFF) != 0) {( v5 D' {# q( K* [ x = OSUnMapTbl[*ptbl & 0xFF;: w/ `8 T6 w# p* w } else { x = OSUnMapTbl[(*ptbl >> 8) & 0xFF + 8; }) ~9 }; ]+ C X8 F bitx = (INT16U)(1 << x);9 v+ e" F: [7 T. U5 l7 m6 R$ x prio = (INT8U)((y << 4) + x);//该task对应的prio优先级值: y# `5 ?1 w6 o7 ?6 k* A //ok,等待在event事件上的所有task中,只有在事件控制矩阵中的第y行的第x列task- N1 N# k% n7 V; e //优先级最高、最值的成为此次事件的唤醒对象[gliethttp] #endif. Y$ T* i" k1 r# T# u$ e6 f //清除此task在event事件控制矩阵中的bit位# X8 U1 S* W" R8 d) E) \ pevent->OSEventTbl[y &= ~bitx; if (pevent->OSEventTbl[y == 0) {! V- L" m/ d' ~! P, `4 w l) q pevent->OSEventGrp &= ~bity; } //通过prio优先级找到该prio唯一对应的task对应的ptcb进程上下文控制块 ptcb = OSTCBPrioTbl[prio; ptcb->OSTCBDly = 0;//复原为正常" V8 g7 ~5 [3 C ptcb->OSTCBEventPtr = (OS_EVENT *)0;//现在本task不悬停在任何event事件上# t# Y4 L+ }. h2 G$ W #if ((OS_Q_EN > 0) && (OS_MAX_QS > 0)) || (OS_MBOX_EN > 0) ptcb->OSTCBMsg = pmsg;//传递消息指针 #else. R: x% s' C4 v+ I pmsg = pmsg;- {2 L) D# e2 U/ p #endif ptcb->OSTCBStatPend = pend_stat;//悬停状态值# R" \4 f& ]+ I/ U: S& A ptcb->OSTCBStat &= ~msk;//该msk事件已经发生,清除task上下文控制块上的msk位,如:OS_STAT_SEM5 y( M# g: b6 B0 z- }0 b if (ptcb->OSTCBStat == OS_STAT_RDY) {4 T; w) Q% u) v# u //如果当前task只是等待该事件,那么把该task放到就绪控制矩阵中,允许内核调度本task OSRdyGrp |= bity;9 u( \1 e. f& v/ ^ OSRdyTbl[y |= bitx;7 _3 K9 k% B6 p n" `) w } return (prio);//返回本task对应的优先级值7 I& \, ~9 b! V0 j5 ?& I } //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ P/ c* i B( ]5 h, n. E4 q. C PS:"所以从这里来看,os中的各个功能单元管理着自己的事情,就像面向对象的封装一样," "事件控制矩阵和就绪控制矩阵是各个对象独立自治的关键因素"4 ?0 c8 O* a/ C( y9 t: s "其他对象,都努力说服自己相信别的对象是独立的、可信任的、安全的"[gliethttp //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ u- F1 s* {7 m |
| 看看 |
微信公众号
手机版