你的浏览器版本过低,可能导致网站不能正常访问!
为了你能正常使用网站功能,请使用这些浏览器。

关于μCOS/II v2.85内核OSSemPend()和OSSemPost()函数工作原理

[复制链接]
zero99 发布时间:2016-6-17 00:26
//----------------------------------------------------------------------
& O0 g: @) ]5 M4 o2 K0 z% f6 b8 o//1.OSSemPend()函数
  _* v* h) `9 s1 T* ivoid 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
( J4 ]% q  p5 h; p* m    OS_CPU_SR cpu_sr = 0;3 f5 L" ^% }% D/ k. _' P3 Q5 i4 V
#endif
) x7 J1 N( O5 f( A: Q& r  Y' w' X1 _* c, K
#if OS_ARG_CHK_EN > 00 k1 p) W: ^) x. h
    if (perr == (INT8U *)0) {
- \7 U1 `2 g9 B. b: t8 U; L& N        return;
( ^' z1 i0 @4 w    }; 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类型
2 i+ s, V; p; a; Z8 ^: n        *perr = OS_ERR_EVENT_TYPE;; G' p+ R! e1 |
        return;
# T) E  q+ `- s3 G& u: {3 Z    }
4 W0 h. A7 O7 z    if (OSIntNesting > 0) {
8 o5 p: v+ R/ v( v8 r//ISR中,不能使用OSSemPend()
" d( ]9 l$ Q0 D2 W        *perr = OS_ERR_PEND_ISR;
% X5 Z  F4 ?8 Q% Z% D( M& a        return;
. O6 I  Q* k# ^! X$ r    }
2 E8 E/ p, B# g0 e- e" w    if (OSLockNesting > 0) {: h, P( I9 Q( k) ^  Q
//μCOS/II v2.85内核已经被强制锁住
' e3 O4 K  B, W0 j        *perr = OS_ERR_PEND_LOCKED;! W+ ?# _# T6 j! H2 J2 |
        return;; H5 M2 j0 u$ f4 G( O& B
    }
3 ]1 ]& j* L! ]" C' H: z7 @7 H//非法的统统不是,信号正常,所以有必要进一步处理" ^, Z! ~& G* d* s
    OS_ENTER_CRITICAL();
' [/ b7 y2 {; q# Q8 d    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--;
4 O/ a. i, z6 {# i; c. r        OS_EXIT_CRITICAL();
+ ?# R) _) w6 z( ^0 x        *perr = OS_ERR_NONE;1 G; T' B8 T6 @# _, T
        return;
3 F4 S2 X; o3 f6 E) i$ r' e    }3 F% N% Q6 ?& Q2 C- @6 i
//当前还没有任何事件发生,所以本task需要悬停,让出cpu[gliethttp]
! X  H& T9 m2 K6 K: o    OSTCBCur->OSTCBStat |= OS_STAT_SEM;//是sem事件让本task进入悬停等待的
5 c2 O) r( q6 E$ D) ]' F. z    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;
8 {' x/ B# U) g3 v//OS_EventTaskWait()函数实现的功能:
! e7 x: W6 {0 w( F6 T2 n//把本task从就绪控制矩阵中摘下,放到pevent事件专有的进程事件控制矩阵表中.! N" K# j1 ?0 @; z+ K2 d, I+ ~
    OS_EventTaskWait(pevent);
' @' S/ _9 l1 B) v, {* _: I    OS_EXIT_CRITICAL();
: N1 `* M. m2 v+ o" A//因为本task正在运行,所以本task现在的优先级最高,现在本task已经将自己从就绪控制矩阵--调度器(x,y)矩形阵列中
+ Q6 t5 r% W: Q//把自己摘掉,所以调度函数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已经超时
9 [2 M0 r  a3 p* Z6 `+ g5 m//[由OSTimeTick()函数把本task重新置入了就绪控制矩阵,具体参考《浅析μC/OS-II v2.85内核OSTimeDly()函数工作原理》],9 K' ?0 \6 B, o' t' o. m, I' ]
//又或者确实在应用程序的某个地方调用了OSSemPost(),以下代码将具体解析是有什么引起的:1.超时,2.收到正常信号
6 h* i. @) Z  e% S0 S& ]4 K    OS_ENTER_CRITICAL();1 l" `$ G% C) s4 z: _
    if (OSTCBCur->OSTCBStatPend != OS_STAT_PEND_OK) {
% w9 [4 r- h9 ^- ?5 T. K& d% ]" t9 a//是因为timeout超时,使得本task获得重新执行的机会
- B9 X! j6 S% p7 W9 v( |        pend_stat = OSTCBCur->OSTCBStatPend;
: u% C& y; ]  p0 g//清除event事件块上本task的标志
3 h; m5 L! H) S" X% w3 s( t        OS_EventTOAbort(pevent);
! t2 @0 U1 i* p( A        OS_EXIT_CRITICAL();* R5 s, g( n) f, O- e; z- E
        switch (pend_stat) {
( K& W3 _. Z* P7 v* Q  P            case OS_STAT_PEND_TO:
4 v, z* g6 S' Q6 i) o* O, b            default:5 \( ^. }4 d9 s1 G1 @. `& x
                 *perr = OS_ERR_TIMEOUT;
4 Z9 M* j& U. U8 s7 j  b- q                 break;
& C6 a( I+ Y$ r            case OS_STAT_PEND_ABORT:
( x5 [% d% \' R                 *perr = OS_ERR_PEND_ABORT;* t+ b# n5 |  I) b0 w5 T. m
                 break;& r- d" q! V2 q. E
        }
/ O$ c  B( Y: J. Q: Y* y' k  @        return;
& D* u/ w/ N& b' n) u    }) D8 J' Z4 c' }$ \, j5 K: d0 R' A
//由OSSemPost()抛出正常事件,唤醒了本task,因为在OSSemPost()时,
8 P! m( Q" v) ?% I# D5 ]//已经将本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事件上
9 ~; a: b0 t; [) n: Y    OS_EXIT_CRITICAL();
7 a% s- h2 ]" |* i' E    *perr = OS_ERR_NONE;/ Z" Z- K, Q: b7 i% E# Y( b
}
$ U% v' D" n. y9 J2 D' Y8 H4 Z) y//----------------------------------------------------------------------0 j3 a0 {& c' R) C1 k. X
//2.OS_EventTaskWait()函数
# a/ N% Y# k9 ~6 i8 P5 \- Lvoid OS_EventTaskWait (OS_EVENT *pevent)9 u* [, ~( K9 K+ o: R8 v
{# S% ^' J. U+ z1 r
    INT8U y;
9 V& q( w, b) q0 x" f/ H) v" w! L//2007-09-09 gliethttp
4 V& n* j2 L8 l# b4 P( A//pevent为此次task挂起的EventPtr单元
2 H1 C7 c5 Y, g3 {& w4 e/ w$ b) p    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;
( r, N& q( G; B7 `; D0 ?! l    if (OSRdyTbl[y == 0) {
; k, B2 w! Z+ n* _  m9 {0 @: ]//当前y行对应的8个或16个task都已经悬停,那么当前y行也清除.
* @& X$ Z  l$ l( V, V; l6 G        OSRdyGrp &= ~OSTCBCur->OSTCBBitY;
. _( [% y; V) }3 W  M8 p/ h) L    }# ?- h' X8 [( f  F
//2007-09-09 gliethttp
( |7 f- e$ K* t) n//将该task的prio添加到pevent事件控制矩阵中,这个矩阵的功能和OSRdyGrp、OSRdyTbl没有区别
5 _6 y! R9 Z* v  A. G6 b//都是用来计算出已经就绪tasks中的优先级最高的那个" C7 j' L: V' y1 N; [3 V* u# P2 F
    pevent->OSEventTbl[OSTCBCur->OSTCBY |= OSTCBCur->OSTCBBitX;
( ~/ w3 X% t! Y& _; T8 u! D    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()函数
& G7 u3 g3 C' d! y% Z; @; _void OS_EventTOAbort (OS_EVENT *pevent); M/ [9 o: m2 n
{
8 D+ M( }; B; |5 N  w; m    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
//具体的清除工作还要自己完成
1 v* \1 g) [5 C5 n//具体参考《浅析μ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;
- q, n" K1 N1 x, T1 I    if (pevent->OSEventTbl[y == 0x00) {  q$ C& v2 Y/ n% C8 R; d
        pevent->OSEventGrp &= ~OSTCBCur->OSTCBBitY;3 b) n3 e1 t% m( N
    }
6 |4 F; G5 U5 S- ~# u    OSTCBCur->OSTCBStatPend = OS_STAT_PEND_OK;
* i) T5 C! w) h& ?5 U* j5 q9 V5 x    OSTCBCur->OSTCBStat = OS_STAT_RDY;: M7 Q; b" X: Z6 ?
    OSTCBCur->OSTCBEventPtr = (OS_EVENT *)0;//现在本task不悬停在任何event事件上
3 o( Y; H  v  S* a/ p0 Z, ~}4 g' @( i, j: S% ?# `- l# g
//----------------------------------------------------------------------
  {6 f' A( N/ O& H//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
& f) d! C, ]3 V: Q% g$ {
2 i, O. K" n3 B2 u! g" e#if OS_ARG_CHK_EN > 0
; ]0 [0 r# }+ N+ }    if (pevent == (OS_EVENT *)0) {" _: D! K5 m3 a9 X
        return (OS_ERR_PEVENT_NULL);  S/ R/ c$ Q+ j
    }
/ o' H; C( r1 j& r: s8 c, L#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) {
$ ]5 s7 d  q7 ~  T3 s2 J    //2007-09-09 gliethttp6 D& e3 c( B$ D
    //OS_EventTaskRdy()函数将摘掉等待在pevent事件控制矩阵上的task中优先级最高的task
" a5 M' y* h. A6 k7 e# B! x    //如果该task仅仅等待该pevent事件,那么将该task添加到就绪控制矩阵中
5 g# @- K0 i6 j, n    //OSRdyGrp |= bity;4 k0 x) v% ~- {# @
    //OSRdyTbl[y] |= bitx;这样调度程序就会根据情况调度OS_Sched()该task了
2 b" Q7 w9 o( Q( \        (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);
/ `# \+ Z' [- v; }+ [" X" `" D    }
" O( g0 t! {" _: X! W5 y) E8 K   
//没有任何一个task悬停在本event事件控制矩阵上," C( s6 O+ g# \$ B" T8 \
   
//那么单纯的对pevent->OSEventCnt++加操作.6 ^( o/ O; j% u6 F
    if (pevent->OSEventCnt < 65535u) {
8 D. k) T8 f  |; i        pevent->OSEventCnt++;$ u: B5 `% L0 ~& T  @7 t' A9 a
        OS_EXIT_CRITICAL();
$ W: _. U& K. }! ?7 z" W, t0 c. n        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);
3 \3 s# J1 I: V. n  q& Q}) ]) \0 ~# M8 f* V( D
//----------------------------------------------------------------------7 H# n; Z. |* S1 [3 W% d
//5.OS_EventTaskRdy()函数
& }0 A0 a! `/ sINT8U OS_EventTaskRdy (OS_EVENT *pevent, void *pmsg, INT8U msk, INT8U pend_stat)  _' t( D7 A! D6 W
{
& u+ l' U8 o( \( C& p, h  l    OS_TCB *ptcb;
8 z$ d8 Y0 ~9 M% C% b# e4 I+ a    INT8U x;& d4 h1 [  \. i6 X# k6 j& U
    INT8U y;
. u% }; G' \# o4 D8 s    INT8U prio;
* S2 `& `' \' a3 r#if OS_LOWEST_PRIO <= 63
% C. }4 T( C: e" {1 @: g    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;
3 H. o1 G/ E7 P, C% N# A% ~7 b+ a9 L#endif
+ J6 G) r" b% N, ^: }( T! s. Z7 n3 h. U. y% @4 W0 D
#if OS_LOWEST_PRIO <= 63; l! z/ d8 n( \# T8 Y5 C+ L' L
//小于64个task时,快速计算
6 a/ X+ O& W* Y+ ^8 Z; L9 F
//最有优先权的task位于事件控制矩阵中的第y行的第x列
& D0 x8 f1 e; a' }7 Q3 I    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;
+ o) `, K/ y; E    bitx = (INT8U)(1 << x);. \, h1 V3 ^% C! I9 W9 R3 S
    prio = (INT8U)((y << 3) + x);  j  \; v2 u& q3 {
#else
' A& _* K2 S9 A7 N7 r1 s4 Q
//对于256个task
. R- `# }; W1 M- _) m6 Y$ n
//最有优先权的task位于事件控制矩阵中的第y行的第x列
( _! i% a( W/ `$ |; y! B( N
//以下的操作原理具体参见《浅析μC/OS-II v2.85内核调度函数》
0 w* z' z7 ^3 W6 s    if ((pevent->OSEventGrp & 0xFF) != 0) {: s; K) }' q- m  W& h
        y = OSUnMapTbl[pevent->OSEventGrp & 0xFF;
% e! ~7 Q# u4 @, O0 ]5 V    } else {
9 f0 o% \9 `, G1 @6 ^        y = OSUnMapTbl[(pevent->OSEventGrp >> 8) & 0xFF + 8;& t3 Y: n: q1 t: G; f( F
    }
4 f5 Z2 _$ y* Z0 ~! j, O. R    bity = (INT16U)(1 << y);1 ]2 b' `) _2 h$ j4 M( {
    ptbl = &pevent->OSEventTbl[y;
6 l$ v0 R# S4 u9 o+ b/ j& a    if ((*ptbl & 0xFF) != 0) {
' A2 k) R. N8 W+ G        x = OSUnMapTbl[*ptbl & 0xFF;- ], M! o- H8 @1 I! _# f# X
    } else {
; U7 H: n' g0 H$ W3 x        x = OSUnMapTbl[(*ptbl >> 8) & 0xFF + 8;
/ {/ C$ c/ d/ t, E    }
( F9 g4 ?2 i# _# c- a! W# Y    bitx = (INT16U)(1 << x);
) D( \' _1 ?4 c4 p4 R    prio = (INT8U)((y << 4) + x);
//该task对应的prio优先级值
, Q3 Z: d, d3 O  P: o2 B- t; T  ~
//ok,等待在event事件上的所有task中,只有在事件控制矩阵中的第y行的第x列task
) ~5 y2 x1 G! O5 \2 F
//优先级最高、最值的成为此次事件的唤醒对象[gliethttp]6 x$ t5 y0 Y/ k. C: f. e3 S
#endif
( N& q$ m2 G, W2 R# c: g
//清除此task在event事件控制矩阵中的bit位+ W2 e% s/ j0 B: L; U& _6 Z% `
    pevent->OSEventTbl[y &= ~bitx;
2 n$ [# H, r) r% {" V    if (pevent->OSEventTbl[y == 0) {
1 x* \3 U; G! }        pevent->OSEventGrp &= ~bity;
4 F6 \: ~* M" \  g5 }    }
# S+ K& H+ y% q8 y/ u8 n
//通过prio优先级找到该prio唯一对应的task对应的ptcb进程上下文控制块( f& j+ m: f3 i& t
    ptcb = OSTCBPrioTbl[prio;
& e" ^0 k" e# I    ptcb->OSTCBDly = 0;
//复原为正常; T. X0 t6 m7 J$ i
    ptcb->OSTCBEventPtr = (OS_EVENT *)0;
//现在本task不悬停在任何event事件上
( H4 w$ ^6 e6 a8 a' ?#if ((OS_Q_EN > 0) && (OS_MAX_QS > 0)) || (OS_MBOX_EN > 0)+ _4 o9 y& P/ ?! \, O& G
    ptcb->OSTCBMsg = pmsg;//传递消息指针
, s- [3 n4 p1 S* M#else6 t6 R0 I0 y. p* X
    pmsg = pmsg;
# v  k, @8 B! j8 T#endif4 w, |5 ]$ w, r  ?4 \) {% c
    ptcb->OSTCBStatPend = pend_stat;
//悬停状态值
, S0 j2 o6 S7 X. V+ Z6 K; U    ptcb->OSTCBStat &= ~msk;
//该msk事件已经发生,清除task上下文控制块上的msk位,如:OS_STAT_SEM, n6 b1 R$ }, s
    if (ptcb->OSTCBStat == OS_STAT_RDY) {
, i* }/ M8 @/ E) g$ N    //如果当前task只是等待该事件,那么把该task放到就绪控制矩阵中,允许内核调度本task
( H5 {$ _3 W5 V3 K4 Q2 v. }' T/ k        OSRdyGrp |= bity;
! h* G' N6 g# B* |        OSRdyTbl[y |= bitx;
. g: _, k' V' |- n- t0 |0 g  ~    }( R5 M' o$ }' N( ?9 a/ H
    return (prio);//返回本task对应的优先级值
+ @/ w$ m- s4 ^& `  g2 u}
! J  D5 M  H( d! {//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++" B3 F. ~' J; U, w9 R
PS:"所以从这里来看,os中的各个功能单元管理着自己的事情,就像面向对象的封装一样,"5 a- `$ S; B& e5 X( k, F. O% c: L$ N
   "事件控制矩阵和就绪控制矩阵是各个对象独立自治的关键因素"
9 o( W' ^* `! ~+ R   "其他对象,都努力说服自己相信别的对象是独立的、可信任的、安全的"[gliethttp
, C0 K. x+ w& T5 F+ ?+ o0 D
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

" V  K% W5 g: S4 b& w; Y0 Z8 l' H+ E
收藏 评论1 发布时间:2016-6-17 00:26

举报

1个回答
yuxin-366840 回答时间:2016-6-21 16:16:43
看看

所属标签

相似分享

关于意法半导体
我们是谁
投资者关系
意法半导体可持续发展举措
创新和工艺
招聘信息
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
关注我们
st-img 微信公众号
st-img 手机版