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

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

[复制链接]
zero99 发布时间:2016-6-17 00:26
//----------------------------------------------------------------------8 O' L) x/ ^( X  ?7 l0 A
//1.OSSemPend()函数
' c5 `2 p' m5 c: z' l3 {void OSSemPend (OS_EVENT *pevent, INT16U timeout, INT8U *perr)
5 N4 m; S1 }4 J{
0 ^2 R, E4 E7 G' m    INT8U pend_stat;3 \. E: D% o/ f8 Q5 x
#if OS_CRITICAL_METHOD == 3
) f- M- M& q- k8 J    OS_CPU_SR cpu_sr = 0;
# q3 h+ x; r- U; l$ F9 u2 n#endif7 W" H# V, H& a$ H, o$ c

! v# R, \1 T+ d# @#if OS_ARG_CHK_EN > 0
/ ^3 F* g" i, V1 w    if (perr == (INT8U *)0) {
. Y/ k* W6 b5 f& t. {3 U, m" Q' w! b        return;
" A% m" d/ g3 P) e2 N; e" J8 ]    }
2 G7 i4 g4 j/ L/ G& a    if (pevent == (OS_EVENT *)0) {4 J: z7 K  j5 _1 e6 k
        *perr = OS_ERR_PEVENT_NULL;
" d0 j- Y, K3 r        return;
. N' f! `- z7 X3 p    }
. I, K% L& H+ h' R#endif
+ u! c  g/ W+ i8 L& {' k6 s    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;
* d# h" j8 v* K        return;) n9 B- F8 b3 ?8 l
    }  x! C7 g3 Y2 e, n3 |
    if (OSIntNesting > 0) {
6 x/ ?, t9 R* m/ }5 O  R8 ?' n0 F//ISR中,不能使用OSSemPend()
6 n  X' y% ~( G) V9 b        *perr = OS_ERR_PEND_ISR;
9 m3 Y: ?  y3 }* j' j1 U' m2 T, P        return;
. u1 Q, P  g+ l    }0 ?. _8 b! `* X( d  |
    if (OSLockNesting > 0) {
7 M' r5 R5 Y, ]+ L6 s6 W9 K//μ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
//非法的统统不是,信号正常,所以有必要进一步处理
4 q: ?% l1 X* R7 x" @    OS_ENTER_CRITICAL();5 n+ {& Z, U7 E, ]
    if (pevent->OSEventCnt > 0) {
; z1 _: ~, k. `4 ^//程序的其他地方已经触发了事件,异或在初始化时设定了n,如:OSSemCreate(2);" K, f& m( }+ Y2 {) U/ u
//所以该task无需悬停,直接获得事件的使用权+ _- {9 d! n) V* J- u+ F# V4 U
        pevent->OSEventCnt--;
9 b5 U0 }, x3 E. U; B7 }        OS_EXIT_CRITICAL();
: E: l- @6 S; N! ?% k: k        *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]
0 T; T$ G) F. o( Q% M2 c    OSTCBCur->OSTCBStat |= OS_STAT_SEM;//是sem事件让本task进入悬停等待的
7 b8 f& F& P% |1 j4 M1 A1 s7 U    OSTCBCur->OSTCBStatPend = OS_STAT_PEND_OK;//假定不是超时,为正常收到信号. H. x2 S% k6 R( k& E& x
//超时,如果timeout=0,那么,本task将一直悬停,仅仅当收到事件触发信号后才重新进入调度队列
$ I# M/ f. h7 v% b/ D- Q: Q$ t    OSTCBCur->OSTCBDly = timeout;
+ G5 m4 C- M' r//OS_EventTaskWait()函数实现的功能:
4 @9 k' ?, f. t% n5 C6 `//把本task从就绪控制矩阵中摘下,放到pevent事件专有的进程事件控制矩阵表中./ p1 d1 w2 Z4 z
    OS_EventTaskWait(pevent);% H8 I( b* M) d, S3 `2 d$ f
    OS_EXIT_CRITICAL();
. ?" i) U% F9 j8 L  o5 n//因为本task正在运行,所以本task现在的优先级最高,现在本task已经将自己从就绪控制矩阵--调度器(x,y)矩形阵列中/ P0 V: L& F) ^
//把自己摘掉,所以调度函数OS_Sched()一定会切换到另一个task中执行新task的代码[gliethttp]
( E1 W1 ]3 L6 r; i    OS_Sched();//具体参见《浅析μC/OS-II v2.85内核调度函数》. X2 H/ d9 {5 i
//2007-09-09 gliethttp
6 @, b- q; y  d//可能因为OSSemPend()中指定的timeout已经超时- |( V  B! v4 C0 X
//[由OSTimeTick()函数把本task重新置入了就绪控制矩阵,具体参考《浅析μC/OS-II v2.85内核OSTimeDly()函数工作原理》],
( h- N& U. e* F; x" F( L" R//又或者确实在应用程序的某个地方调用了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获得重新执行的机会
3 ?4 I% S4 ~4 y8 Q7 V0 U# C5 H        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();
3 [0 S2 ?4 `: p# R( k6 Z& F- R# `        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;
+ Y0 _! w* [5 N: ]6 w                 break;
+ y# i" C; Z  h7 y            case OS_STAT_PEND_ABORT:
: p* i4 O2 R# Z2 e$ u. k% [6 `                 *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()时,
8 E7 u9 l6 x( A# D$ Y//已经将本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();
8 q4 g( Q/ {* r- q  W; n3 g    *perr = OS_ERR_NONE;
: t' D# `( K1 x& i8 \' H}) 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)
1 k; L: S7 F; L& q5 O6 D: `{
+ x, z, w  D  g) @& N    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) {
4 W4 \: w, X' c% ^: F! P//当前y行对应的8个或16个task都已经悬停,那么当前y行也清除.
. l1 m6 L( |# B" g5 D3 O        OSRdyGrp &= ~OSTCBCur->OSTCBBitY;
/ K" T0 s0 |: e' Y9 Q+ j  n    }
8 Y$ n, O. s! n. ~- h% ~$ P//2007-09-09 gliethttp
% R0 T8 n8 _# v% I//将该task的prio添加到pevent事件控制矩阵中,这个矩阵的功能和OSRdyGrp、OSRdyTbl没有区别7 @$ j3 b( e" {: J) H
//都是用来计算出已经就绪tasks中的优先级最高的那个
& ^, C# I+ T% N! }# t# N    pevent->OSEventTbl[OSTCBCur->OSTCBY |= OSTCBCur->OSTCBBitX;
) z) b' f6 `* D' Z4 B; E% i/ Y! |    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()函数
: \! x* [8 t( L  s  Nvoid OS_EventTOAbort (OS_EVENT *pevent)
, q3 E/ d; `) e+ a7 }5 u{3 _/ v: Y7 F# c  Z
    INT8U y;
3 q% p+ e8 k2 P7 K7 ?* q//清除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()函数工作原理》
3 n5 x! t( f4 Q9 ~, X! ^    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;
# \2 g; o) H1 \2 C  O    }, X6 P, w1 l: K6 u7 W) e9 Z
    OSTCBCur->OSTCBStatPend = OS_STAT_PEND_OK;
( ^$ X: H0 f2 i: V, L    OSTCBCur->OSTCBStat = OS_STAT_RDY;
" r6 F# v7 [% P2 \+ u( |    OSTCBCur->OSTCBEventPtr = (OS_EVENT *)0;//现在本task不悬停在任何event事件上
6 P% H4 L9 A% L) o( D/ Q& T}
  n; P" z8 k3 u/ c& {//----------------------------------------------------------------------
  w: k8 e, c3 q7 C  p2 e//4.OSSemPost()函数
! X1 T- J6 J# J2 iINT8U OSSemPost (OS_EVENT *pevent)& |2 F# V/ q% T9 O" d" {9 A! b
{
& X5 k2 o9 M! f#if OS_CRITICAL_METHOD == 34 Y& U  x3 g6 U7 v
    OS_CPU_SR cpu_sr = 0;//方式3将把cpsr状态寄存器推入临时堆栈cpu_sr中,可以安全返回之前的中断状态
4 t* _7 K) y4 ^  |& Z/ [- i9 p#endif1 R: i- {8 r2 L: T0 w+ K7 J

5 R, h6 q' l0 Y6 h1 Q2 l#if OS_ARG_CHK_EN > 0
+ r4 L% x6 w; Z1 M: O2 h    if (pevent == (OS_EVENT *)0) {# R% }2 D0 _  `2 v$ E
        return (OS_ERR_PEVENT_NULL);
* P7 i( h) N* @" J    }
( Y1 O* F+ I; G) I+ x- ?7 k9 j9 [#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
    }
  a6 n; P! G5 E) N% I4 f, p    OS_ENTER_CRITICAL();
: W( p% t. o- Z- o# v    if (pevent->OSEventGrp != 0) {; g( ?: ^) n9 F% U
    //2007-09-09 gliethttp/ _' W' F6 S& ^2 G
    //OS_EventTaskRdy()函数将摘掉等待在pevent事件控制矩阵上的task中优先级最高的task
8 r4 L: }- F" G& g* q9 J    //如果该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);
" ?( e# b# b5 f0 M( F        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]
; |. H, R( U, y" I; ]: y   
//如果没有调用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);
& k' x2 S  _2 T8 \    }
- W: `% f2 Q1 b. ?   
//没有任何一个task悬停在本event事件控制矩阵上,
2 v; }4 K* e0 k6 P) h1 m2 x; l   
//那么单纯的对pevent->OSEventCnt++加操作.6 d* O7 ?, K0 e) x# m
    if (pevent->OSEventCnt < 65535u) {
2 B2 i- m2 R; T        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);
! q* C' {) O: t( k  d; x    }
2 Y, w# ?7 \6 P, x  w. q   
//已经堆积了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
//----------------------------------------------------------------------
  C4 C# B: i9 H3 X8 O# _3 [
//5.OS_EventTaskRdy()函数
( e/ ]8 x. o" nINT8U OS_EventTaskRdy (OS_EVENT *pevent, void *pmsg, INT8U msk, INT8U pend_stat)
1 a  `. _; q, _7 A! a7 T5 x{
9 B& u# v* l1 T4 `* \1 f    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;
5 ^, I6 X4 o  S#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;
3 v3 M3 u# U2 F3 u    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时,快速计算
/ f5 @" V. F* z. x4 ^
//最有优先权的task位于事件控制矩阵中的第y行的第x列/ \# U7 k5 E/ _( m
    y = OSUnMapTbl[pevent->OSEventGrp;# ^, r/ ^) S, ?. w3 L
    bity = (INT8U)(1 << y);
0 U! o  y# C6 i( x8 w    x = OSUnMapTbl[pevent->OSEventTbl[y;1 L/ \( D5 r8 A2 y, [- l
    bitx = (INT8U)(1 << x);
4 ^- w% S& w) I3 e2 P9 L5 e    prio = (INT8U)((y << 3) + x);
8 i5 b; [& U& @  G# s#else* Q# }; P% D1 b" @/ t
//对于256个task8 x9 y) ~0 K: H* I; a( n
//最有优先权的task位于事件控制矩阵中的第y行的第x列
$ V  c7 j- a! e' w; ~8 v7 |
//以下的操作原理具体参见《浅析μ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;
/ D8 s$ u3 |) ~3 n  p8 D0 f    } else {) U- [& R3 x5 s1 w: F- ]2 N. q* D
        y = OSUnMapTbl[(pevent->OSEventGrp >> 8) & 0xFF + 8;
; [' t/ Y4 ^# ^! {* N    }
# I3 M' g6 ^; w5 ?7 p  q$ l0 K    bity = (INT16U)(1 << y);
; n6 _) l# g* M    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 {
, c2 V0 u: D9 ^  ^# u        x = OSUnMapTbl[(*ptbl >> 8) & 0xFF + 8;
9 Z: S6 J( r7 K0 c$ t5 K0 ?& Z% x    }) ~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]
3 s! w# w- c9 W+ k2 y* M! C/ X  M#endif. Y$ T* i" k1 r# T# u$ e6 f
//清除此task在event事件控制矩阵中的bit位# X8 U1 S* W" R8 d) E) \
    pevent->OSEventTbl[y &= ~bitx;
4 y* W) e2 C+ r' O+ j8 _    if (pevent->OSEventTbl[y == 0) {! V- L" m/ d' ~! P, `4 w  l) q
        pevent->OSEventGrp &= ~bity;
5 H9 c9 c/ W, t& [  Y9 p- T+ L$ ?2 |    }
* {6 g+ K: W* l5 J* U
//通过prio优先级找到该prio唯一对应的task对应的ptcb进程上下文控制块
) p- P/ `& y: S) C! X    ptcb = OSTCBPrioTbl[prio;
2 J3 Z. `+ V8 W$ K1 z3 `    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)
" u- f7 ]3 @) h  A) C    ptcb->OSTCBMsg = pmsg;//传递消息指针
( u: J  V3 O1 A8 m) h' u#else. R: x% s' C4 v+ I
    pmsg = pmsg;- {2 L) D# e2 U/ p
#endif
& K6 ]$ D4 C6 {! Z5 E4 e. L    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
6 p5 d% H4 W2 \: v        OSRdyGrp |= bity;9 u( \1 e. f& v/ ^
        OSRdyTbl[y |= bitx;7 _3 K9 k% B6 p  n" `) w
    }
0 c& o7 M. `7 r0 J! B    return (prio);//返回本task对应的优先级值7 I& \, ~9 b! V0 j5 ?& I
}
! k6 D5 ?4 ^3 p! F: k7 n2 ~//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ P/ c* i  B( ]5 h, n. E4 q. C
PS:"所以从这里来看,os中的各个功能单元管理着自己的事情,就像面向对象的封装一样,"
: }+ S4 Z- q' z! l- ?5 a   "事件控制矩阵和就绪控制矩阵是各个对象独立自治的关键因素"4 ?0 c8 O* a/ C( y9 t: s
   "其他对象,都努力说服自己相信别的对象是独立的、可信任的、安全的"[gliethttp
. J$ a# W3 B* _) Z5 L; g  R1 {
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  u- F1 s* {7 m
赞 收藏 评论1 发布时间:2016-6-17 00:26

举报

1个回答
yuxin-366840 回答时间:2016-6-21 16:16:43
看看
关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
人形机器人运动控制、感知与智能配电
半导体创新技术与应用方向
EE架构与软件定义汽车
12V/48V 汽车智能配电(SPD)
区域控制单元(ZCU)与分区架构
关注我们
st-img 微信公众号
st-img 手机版