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

【经验分享】STM32 FreeRTOS列表和列表项详解

[复制链接]
STMCU小助手 发布时间:2022-6-18 17:00
01. 概述, o4 {$ [+ l) v# ~( [* _/ D: U( d
要想看懂FreeRTOS 源码并学习其原理,有一个东西绝对跑不了,那就是FreeRTOS 的列表和列表项。列表和列表项是FreeRTOS 的一个数据结构,FreeRTOS 大量使用到了列表和列表项,它是FreeRTOS 的基石。要想深入学习并理解FreeRTOS,那么列表和列表项就必须首先掌握,否则后面根本就没法进行。$ W( n: z" ?+ _1 B3 I

* l  v" w7 x* d( I' T: r列表被FreeRTOS调度器使用,用于跟踪任务,处于就绪、挂起、延时的任务,都会被挂接到各自的列表中。用户程序如果有需要,也可以使用列表。
# n  ~8 N% v# ]! l0 _, S- a, L9 V9 ^  E/ c7 K2 N: b7 \
FreeRTOS列表使用指针指向列表项。一个列表(list)下面可能有很多个列表项(list item),每个列表项都有一个指针指向列表。如下图所示。' {; a! m7 W/ r) w  Y
3 J0 j" V' V  u* R
I2O2RI0XDTX)A[0Q6EU]KRE.png
$ ^* o! t# I$ }! V! i. l3 @" W" T5 H9 d% I
02. 列表
5 K5 G3 F. @% B( d列表是FreeRTOS 中的一个数据结构,概念上和链表有点类似,列表被用来跟踪FreeRTOS中的任务。与列表相关的全部东西都在文件list.c 和list.h 中。在list.h 中定义了一个叫List_t 的结构体,如下:
' G! h% O; a6 Y# d) f" k  ^  [. I
* {$ m5 ~8 R. W1 R  U- V
  1. typedef struct xLIST% K1 V- A3 w+ I. E# h
  2. {
    ( |1 _; S& S7 T) _
  3.      listFIRST_LIST_INTEGRITY_CHECK_VALUE                        /*用于检测列表项数据是否完整*/: u6 B6 j3 A+ e1 |
  4.      configLIST_VOLATILE UBaseType_t uxNumberOfItems;
      Q+ C% A1 v" F% w: m. @7 y' z3 h; V
  5.      ListItem_t * configLIST_VOLATILE pxIndex;                   /*用于遍历列表*/0 |4 F: ~0 B0 x& o$ f  c7 f
  6.      MiniListItem_t xListEnd;                                    /*列表项*/
    0 y% F* h4 _1 }) X) ]
  7.      listSECOND_LIST_INTEGRITY_CHECK_VALUE                       /*用于检测列表项数据是否完整*/% k* i! d7 A# c0 g/ @' d  C% {
  8. }List_t;
复制代码
4 _1 ]( r9 P) |2 w' L
  F3 t: Q) D; T- E2 a

4 I7 R, r$ h' q/ q(1) 和(5) 、这两个都是用来检查列表完整性的, 需要将宏configUSE_LIST_DATA_INTEGRITY_CHECK_BYTES 设置为1,开启以后会向这两个地方分别添加一个变量xListIntegrityValue1 和xListIntegrityValue2,在初始化列表的时候会这两个变量中写入一个特殊的值,默认不开启这个功能。$ @# O2 {1 d* X
(2)、uxNumberOfItems 用来记录列表中列表项的数量。( U  R) L+ A! |0 ~9 o# G" o
(3)、pxIndex 用来记录当前列表项索引号,用于遍历列表。
5 C5 Z8 I& C* J! ^(4)、列表中最后一个列表项,用来表示列表结束,此变量类型为MiniListItem_t,这是一个迷你列表项。
7 y/ W& X2 X, y/ f% Q# S3 C$ Q2 X: v- S
03. 列表项

$ v1 }- g; d/ l! }" r列表项就是存放在列表中的项目,FreeRTOS 提供了两种列表项:列表项和迷你列表项。这两个都在文件list.h 中有定义。
$ Y* @+ z: e# h: e
# T+ T7 M* Y1 x, K4 Y) }3 W. PxLIST_ITEM列表项
3 @' ?% @3 o5 \8 ^- l  K* {; I
& O! a! I& Y" ^! }
  1. struct xLIST_ITEM  W8 L: i/ i# \9 s3 O$ t9 ^+ I
  2. {
    $ t; U2 K8 @0 e/ m
  3.      listFIRST_LIST_ITEM_INTEGRITY_CHECK_VALUE           /*用于检测列表项数据是否完整*/
    5 H. E0 F: {3 U; Q  y# Y
  4.      configLIST_VOLATILETickType_t xItemValue;           /*列表项值*/
    9 Z" F3 K1 A3 K* i2 o5 e
  5.      struct xLIST_ITEM * configLIST_VOLATILE pxNext;      /*指向列表中下一个列表项*/9 I8 Z- _$ N. A
  6.      struct xLIST_ITEM * configLIST_VOLATILE pxPrevious;  /*指向列表中上一个列表项*/
    - N0 c0 |% n9 k. U+ K  n( J
  7.      void * pvOwner;                                     /*指向一个任务TCB*/
    : X$ l+ y: @% Z& c! R( `" E8 Q
  8.      void * configLIST_VOLATILE pvContainer;             /*指向包含该列表项的列表 */3 x/ q. a% ~% h
  9.      listSECOND_LIST_ITEM_INTEGRITY_CHECK_VALUE          /*用于检测列表项数据是否完整*/
    * q3 ~! x9 N% v+ T; n1 q  c
  10. };, Y7 H9 x! Y. n9 d
  11. typedef struct xLIST_ITEM ListItem_t;
复制代码
0 j5 n1 J7 E* ]! Z$ I* O/ W" O* p
29{HXM74_0D3OH75ZXAV50N.png
* L, n; m3 a3 m- d$ L( D- s# q
" r. [. V7 X6 p/ q# P7 B(1)和(7)、用法和列表一样,用来检查列表项完整性的。以后我们在学习列表项的时候不讨论这个功能!
3 ]4 s4 V$ M1 [(2)、xItemValue 为列表项值。
, T- ~/ a3 j& a6 W& ?3 ^2 t1 O+ N. s! e(3)、pxNext 指向下一个列表项。( N! z0 S; l7 Y* S$ n. A; A7 T3 n
(4)、pxPrevious 指向前一个列表项,和pxNext 配合起来实现类似双向链表的功能。
& L; P. E6 f- L* ~  g/ e: g(5)、pvOwner 记录此链表项归谁拥有,通常是任务控制块。5 a; `! x& e9 k
(6)、pvContainer 用来记录此列表项归哪个列表。注意和pvOwner 的区别,在前面讲解任务控制块TCB_t 的时候说了在TCB_t 中有两个变量xStateListItem 和xEventListItem,这两个变量的类型就是ListItem_t,也就是说这两个成员变量都是列表项。以xStateListItem 为例,当创建一个任务以后xStateListItem 的pvOwner 变量就指向这个任务的任务控制块,表示xSateListItem属于此任务。当任务就绪态以后xStateListItem 的变量pvContainer 就指向就绪列表,表明此列表项在就绪列表中。举个通俗一点的例子:小王在上二年级,他的父亲是老王。如果把小王比作列表项,那么小王的pvOwner 属性值就是老王,小王的pvContainer 属性值就是二年级。/ f' n/ F0 @/ _% y

1 t. b# N) Q& txMINI_LIST_ITEM列表项
, w+ E3 K$ Q) x
% O, s; }3 I. S
  1. struct xMINI_LIST_ITEM
    , U0 v/ S( u) p4 S: L/ q3 f. S
  2. {
    + e2 A  Z, }+ O- _
  3.      listFIRST_LIST_ITEM_INTEGRITY_CHECK_VALUE           /*用于检测列表项数据是否完整*/; d% R: K1 j+ W7 m9 G) H# f
  4.      configLIST_VOLATILE TickType_t xItemValue;) n. F0 {8 L, j
  5.      struct xLIST_ITEM * configLIST_VOLATILE pxNext;
    ; e( e) H! ]: J" F7 z/ E, ~
  6.      struct xLIST_ITEM * configLIST_VOLATILE pxPrevious;. |$ r, t5 A/ w
  7. };
    1 X+ Z: H: z/ x% t/ x, v
  8. typedef struct xMINI_LIST_ITEM MiniListItem_t;
复制代码

- }9 m) [( s! D ME~S{{H3IK71Q$H9_3D26{9.png 4 E% y' V2 ~! i2 v6 S5 R
# K$ V# F) K* U" |
(1)、用于检查迷你列表项的完整性。( e( k, ~. U) b$ r; b
" n/ \! L1 d' u+ J, L( `; [: m
(2)、xItemValue 记录列表列表项值。1 ^# N% `( k7 u9 y- e
(3)、pxNext 指向下一个列表项。
' K* H" R* ^9 b3 m( u(4)、pxPrevious 指向上一个列表项。
, O# ]4 V  w5 j0 z+ D' e可以看出迷你列表项只是比列表项少了几个成员变量,迷你列表项有的成员变量列表项都有的,没感觉有什么本质区别啊?那为什么要弄个迷你列表项出来呢?那是因为有些情况下我们不需要列表项这么全的功能,可能只需要其中的某几个成员变量,如果此时用列表项的话会造成内存浪费!比如上面列表结构体List_t 中表示最后一个列表项的成员变量xListEnd 就是MiniListItem_t 类型的。
" B2 g4 O0 n0 }" B6 R2 n6 H4 [% F0 R9 C
04. 列表相关宏
% F, T* q, y' t# H; O
  1. /*
    % l7 t3 \1 j) I1 O
  2. * Access macro to set the owner of a list item.  The owner of a list item
    1 q7 @9 k$ m! Q
  3. * is the object (usually a TCB) that contains the list item.
    * f& v% W" F7 V: c& p) E! s8 Q
  4. *" s# _# [8 G" L# U1 M% B% P
  5. * \page listSET_LIST_ITEM_OWNER listSET_LIST_ITEM_OWNER
    " o; f+ b- M* W3 T
  6. * \ingroup LinkedList4 t2 j) U! W% V
  7. */. Y5 w, X5 d! j# m( E* k0 M+ @
  8. #define listSET_LIST_ITEM_OWNER( pxListItem, pxOwner )    ( ( pxListItem )->pvOwner = ( void * ) ( pxOwner ) )1 S) K& @! X! X2 Y  ?  [3 J
  9. 5 \9 |* N' v! B
  10. /*
    5 D5 z' z9 k" J1 C
  11. * Access macro to get the owner of a list item.  The owner of a list item
    . U& H9 Q" o. x2 `1 y% H
  12. * is the object (usually a TCB) that contains the list item.' J$ G' R8 Z% _& \* N. u6 ]
  13. *
    ( h6 f3 @3 E" M
  14. * \page listGET_LIST_ITEM_OWNER listSET_LIST_ITEM_OWNER8 u) s# K! y( P, H
  15. * \ingroup LinkedList
    : {- f5 U9 W' {/ r& ~2 Y
  16. */
    ' \# s( f- R" c* `
  17. #define listGET_LIST_ITEM_OWNER( pxListItem )             ( ( pxListItem )->pvOwner )8 y4 c& o" m/ i6 R3 o# k8 T9 ^
  18. 1 _  q3 H- W( n* W# ~
  19. /*
    5 E2 Z( X4 J2 h# t5 a
  20. * Access macro to set the value of the list item.  In most cases the value is
    : c8 ]. g3 p. u3 d
  21. * used to sort the list in descending order.
    . z. o9 H4 R* j1 k
  22. *+ }, C  W& k- F" {# d" U& t
  23. * \page listSET_LIST_ITEM_VALUE listSET_LIST_ITEM_VALUE2 Q- y9 ~& s4 D0 {9 |9 `- H* L. k2 \
  24. * \ingroup LinkedList
    / p9 O4 H: p9 c$ q  l
  25. */% Y( r! @2 l9 Q8 O: _* g5 t2 l
  26. #define listSET_LIST_ITEM_VALUE( pxListItem, xValue )     ( ( pxListItem )->xItemValue = ( xValue ) )# \( m1 Y" \) c1 a

  27. + }3 C9 y/ ]6 N. d
  28. /*2 B) U5 M* m# ?7 v4 {
  29. * Access macro to retrieve the value of the list item.  The value can3 U& B9 c5 P4 k6 a+ Q$ X
  30. * represent anything - for example the priority of a task, or the time at
    ' b- {- ?- R3 `/ X  @
  31. * which a task should be unblocked.3 y9 ~3 B% {: }' N: w( Y' C
  32. *
    $ Y# `$ g% S6 L7 Z& H0 N
  33. * \page listGET_LIST_ITEM_VALUE listGET_LIST_ITEM_VALUE" C; I! Y/ o' X4 M5 c, H( g
  34. * \ingroup LinkedList! w* c- X1 y3 W5 H# u
  35. */
    + N% d6 s5 _; L4 o/ }- J; B3 A
  36. #define listGET_LIST_ITEM_VALUE( pxListItem )             ( ( pxListItem )->xItemValue )
    # m9 Y7 A8 g) K& p7 G
  37. ' N5 n' \3 K! A3 i& K& @
  38. /*. G9 V# S4 _" i$ h: I
  39. * Access macro to retrieve the value of the list item at the head of a given
    : J8 `% I0 B8 C# e/ Y7 U4 W+ {* o$ f
  40. * list.& O% w0 ?/ M; o7 {% s6 C( B6 T) d
  41. *
    6 h( P, {: i# w$ |0 ^4 v- f; `0 K! Z! a
  42. * \page listGET_LIST_ITEM_VALUE listGET_LIST_ITEM_VALUE& T5 S0 C) A7 p
  43. * \ingroup LinkedList
    % l) }, w- V( T: m6 q5 W
  44. */
      z6 A+ Z4 D' G( O8 n' ~
  45. #define listGET_ITEM_VALUE_OF_HEAD_ENTRY( pxList )        ( ( ( pxList )->xListEnd ).pxNext->xItemValue )
    $ H' D4 j3 c3 b- ~$ G4 R1 c2 o

  46. 8 Q# G2 a2 ]4 s4 J6 d
  47. /*
    9 y2 D6 \3 Z0 y$ \" j
  48. * Return the list item at the head of the list.: e/ Y; d; ^9 b) a. e
  49. *
    7 a( R: r1 s1 z9 P5 t
  50. * \page listGET_HEAD_ENTRY listGET_HEAD_ENTRY
    ) y, @) A$ d) e; _+ `8 f, t
  51. * \ingroup LinkedList
    % `0 U8 l/ O: b& Y# N
  52. */
    : i. U8 l; g- ^: N! g+ z: R6 [" D
  53. #define listGET_HEAD_ENTRY( pxList )                      ( ( ( pxList )->xListEnd ).pxNext )
    : L' s) p7 }2 S  r

  54. / q/ a% m1 H) J8 r$ H
  55. /*
    9 t. B+ Y( w# x9 ^5 n* ~; N. O! b
  56. * Return the next list item.
    ( J, B" R( m% ?% f5 v# T  L) r5 ?
  57. *9 v7 E7 A3 p1 l" }& t7 W
  58. * \page listGET_NEXT listGET_NEXT( w: h" Q- n+ Z
  59. * \ingroup LinkedList
    ! x8 ]  V0 [7 X: U
  60. */. Q9 w% M; E" \# s' W6 X' Q
  61. #define listGET_NEXT( pxListItem )                        ( ( pxListItem )->pxNext )
    4 L; e) w' ^) `6 w: C

  62. 3 X% d3 X1 A1 a1 ?4 ]/ a% [" c% g
  63. /*, o+ J, H' J6 A* M
  64. * Return the list item that marks the end of the list
    1 E3 b( A0 ~" h: V* d  V
  65. *
    , {7 T' Y3 k- P( ]' l
  66. * \page listGET_END_MARKER listGET_END_MARKER
    ; {0 {2 M5 o" R5 I6 q, o$ b; k
  67. * \ingroup LinkedList" ?; g8 ]) a5 {  N3 ?) ?# L
  68. */
    / [+ @+ x* e0 T- i0 b* e
  69. #define listGET_END_MARKER( pxList )                      ( ( ListItem_t const * ) ( &( ( pxList )->xListEnd ) ) )
    & k9 r: W2 j: Y9 ]! T  h. W

  70. 3 y, [- M5 [" g9 q
  71. /*
    ; c% v2 j- a; K+ E. u6 J
  72. * Access macro to determine if a list contains any items.  The macro will" w$ {+ y  e0 B, R
  73. * only have the value true if the list is empty.
    ( X" N0 P/ ^7 e" G9 S& v
  74. *' S! ^+ h: I- J$ w/ @* G1 m1 ~) [
  75. * \page listLIST_IS_EMPTY listLIST_IS_EMPTY
    ) ~  k; D8 ^% h; [  r7 t
  76. * \ingroup LinkedList, [! Y: Z/ v1 Z' B9 q) V
  77. */
    , y3 l4 i3 K( B4 p1 k
  78. #define listLIST_IS_EMPTY( pxList )                       ( ( ( pxList )->uxNumberOfItems == ( UBaseType_t ) 0 ) ? pdTRUE : pdFALSE )
    ; E- C4 s4 i( P, u; H' I

  79. 0 |6 o4 g) G- h2 E: Z" ]$ r% V% o" B
  80. /*5 b- y% F2 j0 ~% \
  81. * Access macro to return the number of items in the list.; d" w0 k) ^% m0 \/ d$ p
  82. */" c, A" u$ S& u. K, c
  83. #define listCURRENT_LIST_LENGTH( pxList )                 ( ( pxList )->uxNumberOfItems )
    ! c* i2 T+ t8 Z2 V! a7 s! A  L

  84. 9 W( c9 K. U8 ^7 `# y3 o( N
  85. /*
    $ u3 k: `% f2 n  e
  86. * Access function to obtain the owner of the next entry in a list.6 ?7 L  f+ o2 G! q' f2 D" i4 t
  87. *8 n+ L: A! y" @1 _, ?* ]4 i9 V
  88. * The list member pxIndex is used to walk through a list.  Calling4 w: H  |' A; e) \2 B
  89. * listGET_OWNER_OF_NEXT_ENTRY increments pxIndex to the next item in the list
    5 p; ^! E  Q! ?; |4 _9 f
  90. * and returns that entry's pxOwner parameter.  Using multiple calls to this
    & s. V, E* A9 q; v. {! w
  91. * function it is therefore possible to move through every item contained in
    9 w# c: P# k; o: t
  92. * a list.
    & `( }: F% @1 Y+ R6 |
  93. *
    ) |, p8 Z7 K2 ~- B$ _
  94. * The pxOwner parameter of a list item is a pointer to the object that owns
    # `( w+ c5 O+ R; K% O; m
  95. * the list item.  In the scheduler this is normally a task control block.
    * y; M6 _4 a4 g: r2 E( H# l( {) ]
  96. * The pxOwner parameter effectively creates a two way link between the list
    7 T0 F5 [6 L/ u8 w
  97. * item and its owner.
    # x9 G; o' D+ a) l2 \8 p
  98. *% u& M  {$ B6 Y* E
  99. * @param pxTCB pxTCB is set to the address of the owner of the next list item.( M7 L$ i7 F. t% a
  100. * @param pxList The list from which the next item owner is to be returned.
    - \$ d- M, P/ o* }( Z2 L
  101. *" I/ N% F. o: Y' A' @$ `
  102. * \page listGET_OWNER_OF_NEXT_ENTRY listGET_OWNER_OF_NEXT_ENTRY
    - V. p0 |8 d; k: G$ R
  103. * \ingroup LinkedList
    " ]" g6 f4 W  W9 `2 ]
  104. */' ?6 B! t9 h' Q$ d  [, ^* C
  105. #define listGET_OWNER_OF_NEXT_ENTRY( pxTCB, pxList )                                           \
    5 Y9 G, c" K, {+ W, L: X+ i+ z
  106.     {                                                                                          \
    : X6 X- _3 x% \8 a9 s( T
  107.         List_t * const pxConstList = ( pxList );                                               \( e7 |- @1 t$ W
  108.         /* Increment the index to the next item and return the item, ensuring */               \0 W9 h3 B! b* T$ Z; r8 O
  109.         /* we don't return the marker used at the end of the list.  */                         \
    " v+ J. g8 \( j/ ~1 f! m% h6 i* t
  110.         ( pxConstList )->pxIndex = ( pxConstList )->pxIndex->pxNext;                           \$ A2 s; L' }$ h, E  T2 ]& M: m+ I
  111.         if( ( void * ) ( pxConstList )->pxIndex == ( void * ) &( ( pxConstList )->xListEnd ) ) \, H9 j) t) Q$ Q8 K$ q
  112.         {                                                                                      \8 X" S: t/ T- W
  113.             ( pxConstList )->pxIndex = ( pxConstList )->pxIndex->pxNext;                       \
    ' X+ [1 n! x- E' O) k' q
  114.         }                                                                                      \% J( W9 L0 x/ i! d# j
  115.         ( pxTCB ) = ( pxConstList )->pxIndex->pvOwner;                                         \
    4 [5 C; {3 j: p
  116.     }- M, d( q! |6 v0 `' A% z" ]# o

  117. - q( X. d  m" }8 t9 \* D( W- _/ j

  118. . g. i' q9 C1 z3 G( o/ x
  119. /*: K7 u9 x9 a0 q. q3 T6 j, m
  120. * Access function to obtain the owner of the first entry in a list.  Lists
      t1 A( {) B' j- _3 c$ N
  121. * are normally sorted in ascending item value order.; F9 ~: |8 I$ `5 l- l6 }: U. d1 G
  122. *
    5 M4 o8 a8 W) ]: P# }
  123. * This function returns the pxOwner member of the first item in the list.& B2 j# C/ n8 l& r
  124. * The pxOwner parameter of a list item is a pointer to the object that owns3 N; u1 ~/ d1 b
  125. * the list item.  In the scheduler this is normally a task control block., c" S8 ~2 |1 K1 g
  126. * The pxOwner parameter effectively creates a two way link between the list
      L. i3 P2 W  p
  127. * item and its owner.3 Q- y1 p0 J6 u! ?; j
  128. *
    , z: o( F, i& }& R# L$ E
  129. * @param pxList The list from which the owner of the head item is to be7 H, X* u; R6 P0 J& O6 B7 V
  130. * returned.
    3 i( q) m1 h6 ~7 L$ ]6 L
  131. *# w- I& W9 ?3 O2 |7 P' f1 p
  132. * \page listGET_OWNER_OF_HEAD_ENTRY listGET_OWNER_OF_HEAD_ENTRY
    : r2 L( Y* u7 f9 m% Z# c  x" S- t, `: l
  133. * \ingroup LinkedList
    + u! l0 V& W# R  w' U
  134. */2 }% r' b; o- W( U) F0 r' Z
  135. #define listGET_OWNER_OF_HEAD_ENTRY( pxList )            ( ( &( ( pxList )->xListEnd ) )->pxNext->pvOwner )
    / O+ U. [. @3 Z. J" G
  136. ) k9 @& ]6 X, x" I" R0 R5 ]6 i
  137. /*
    . q. E5 e# Y% [; Y9 Q
  138. * Check to see if a list item is within a list.  The list item maintains a
    * V& q* c7 Z% ]' |
  139. * "container" pointer that points to the list it is in.  All this macro does
    / N8 _0 Q, O! x1 p# `7 G" y
  140. * is check to see if the container and the list match.  r; ~! ]- ?3 x+ m1 E! ]5 w
  141. *
    8 b0 Z0 E* N9 a5 s* m/ p
  142. * @param pxList The list we want to know if the list item is within.
    2 l) k- T8 E: T; r9 X, v4 c% A
  143. * @param pxListItem The list item we want to know if is in the list.; `0 i; t" M" n9 X/ ^
  144. * @return pdTRUE if the list item is in the list, otherwise pdFALSE.
    % d& L5 X/ R: u
  145. */2 M) |3 p, _  e7 A, e9 n" i0 _
  146. #define listIS_CONTAINED_WITHIN( pxList, pxListItem )    ( ( ( pxListItem )->pxContainer == ( pxList ) ) ? ( pdTRUE ) : ( pdFALSE ) )
    ! D0 |( f/ k" j! K% C

  147. 5 W$ e$ f  s0 `: i. t" [& D4 a8 }
  148. /*
    - M2 l8 B9 G" H0 K
  149. * Return the list a list item is contained within (referenced from).# i* ^7 }- B, _' e, p. d
  150. *
    / M- j' [3 `6 i9 }, m' S
  151. * @param pxListItem The list item being queried.
    1 F7 ?8 I7 s. D% g) a/ b) [
  152. * @return A pointer to the List_t object that references the pxListItem7 Y5 X% D+ Y" N1 p' x7 K
  153. */
    6 d& M7 i. z- z4 W& f4 X" D
  154. #define listLIST_ITEM_CONTAINER( pxListItem )            ( ( pxListItem )->pxContainer )
    4 b) P6 D% R4 \. {& Y4 O  [3 _0 |
  155. 7 ?6 t1 Z3 i( x9 G7 e) K
  156. /*7 f% m. v  d* @
  157. * This provides a crude means of knowing if a list has been initialised, as
    " s; ^0 D* }0 B7 `+ C; p
  158. * pxList->xListEnd.xItemValue is set to portMAX_DELAY by the vListInitialise()
    2 p; x0 A# z& _
  159. * function.) m4 z* v1 V" H+ i
  160. */
    & K$ _! e" y  a
  161. #define listLIST_IS_INITIALISED( pxList )                ( ( pxList )->xListEnd.xItemValue == portMAX_DELAY )
复制代码

: R: x8 W# t* [; V+ j05. 列表相关函数
# y* a6 c  B  b: [5.1 初始化列表

( s. ?* V2 s+ C# e  M列表结构体中包含一个列表项成员,主要用于标记列表结束。初始化列表就是把这个列表项插入到列表中。
$ f4 ]; b! f1 ]5 F  @" v3 Z# ~( `
. _; i* ^# t3 R5 a1 B' m7 w
  1. void vListInitialise( List_t * const pxList ). u# v( @8 \0 d4 i3 b( D
  2. {
    , b3 }% D- W* F: n# z2 a( E
  3.      /*列表索引指向列表项*// `0 f( h$ H. D2 H- a
  4.      pxList->pxIndex = ( ListItem_t * )&( pxList->xListEnd );                  
    0 D$ R! d7 f! p3 ^- `
  5.      /* 设置为最大可能值 *// f2 P9 k! y/ h6 C
  6.      pxList->xListEnd.xItemValue =portMAX_DELAY;
    1 S) @) C* M/ m
  7. 0 l  D* J7 e8 I1 _) Q8 D
  8.      /* 列表项xListEnd的pxNext和pxPrevious指针指向了它自己 */5 u4 Y  W9 a, ?  [
  9.      pxList->xListEnd.pxNext = (ListItem_t * ) &( pxList->xListEnd );
    ; A7 @, r1 c5 x6 J5 j& P
  10.      pxList->xListEnd.pxPrevious= ( ListItem_t * ) &( pxList->xListEnd );
    $ l8 u9 s* i) a
  11.      pxList->uxNumberOfItems = ( UBaseType_t) 0U;: S9 o0 t9 O$ Y1 T8 H
  12. : {6 W+ B. ]4 O- m* r5 h
  13.      /* 设置为已知值,用于检测列表数据是否完整*/
    * |& d& `$ h, U$ i' d  z& q% n1 r
  14.      listSET_LIST_INTEGRITY_CHECK_1_VALUE(pxList );
    + P6 \7 {. W8 C* `0 ~! `
  15.      listSET_LIST_INTEGRITY_CHECK_2_VALUE(pxList );
    ! Q0 y/ ~/ ~: n3 w' q( c
  16. }
复制代码
0 O0 p" L' ~$ Z6 j* F! |
如果宏configUSE_LIST_DATA_INTEGRITY_CHECK_BYTES设置为1,则使能列表项数据完整性检查,则宏listSET_LIST_INTEGRITY_CHECK_1_VALUE()和listSET_LIST_INTEGRITY_CHECK_2_VALUE被一个已知值代替,默认为0x5a5a(16位架构)或者0x5a5a5a5a(32位架构)。. n0 V: p. T6 @$ S, F% ^" {6 o

6 S. ?* z3 T2 P1 J& b P27PILXP(KBZ1I~E4YVFB2W.png
5 s6 S) L0 @$ J5 I- L2 e  p4 k, o. V; w  V
5.2 初始化列表项
6 r. n) p+ ^% o- {& v1 C: b  W列表项的初始比较简单,只要确保列表项不在任何列表中即可。
: M4 u6 ], b: V1 _  {$ _4 D% P( O" Z
  1. void vListInitialiseItem( ListItem_t * const pxItem )( I8 ?% e0 \) g( V. U
  2. {
    0 a0 Q, l- j$ E: Y7 C" w
  3.      pxItem->pvContainer = NULL;3 Z' p3 ^2 T" e1 |! o" G$ |' m! \4 g
  4. 8 p6 R* P& b- s& c$ X
  5.      /*设置为已知值,用于检测列表项数据是否完整*/4 G8 T6 ~8 \0 j% `
  6.      listSET_FIRST_LIST_ITEM_INTEGRITY_CHECK_VALUE(pxItem );" K9 M6 t3 g8 h& h
  7.      listSET_SECOND_LIST_ITEM_INTEGRITY_CHECK_VALUE(pxItem );
    ) V9 @7 K5 E/ M% B, ~; }! g) G
  8. }
复制代码
" D5 S& @% Y) @4 a0 @
如果宏configUSE_LIST_DATA_INTEGRITY_CHECK_BYTES设置为1,则使能列表项数据完整性检查,则宏listFIRST_LIST_ITEM_INTEGRITY_CHECK_VALUE和listSECOND_LIST_ITEM_INTEGRITY_CHECK_VALUE会被两个已知的数值代替,默认为0x5a5a(16位架构)或者0x5a5a5a5a(32位架构)。
" ]( e( w- `/ {! p! j3 z3 t  u8 t$ j
5.3 列表项插入函数
; c9 c0 D. @' L2 ?+ V每个列表项对象都有一个列表项值(xItemValue),通常是一个被跟踪的任务优先级或是一个调度事件的计数器值。调用API函数vListInsert( List_t * const pxList, ListItem_t * const pxNewListItem)可以将pxNewListItem指向的列表项插入到pxList指向的列表中,列表项在列表的位置由pxNewListItem->xItemValue决定,按照升序排列。
. H% A; e# H, u7 j0 J5 R$ ?+ o8 W  [0 A: b( H" f3 c
  1. void vListInsert( List_t * const pxList,
    2 {5 x- O" f# r; I, X
  2.                   ListItem_t * const pxNewListItem )2 x9 h2 U: x! @) Z% l' t8 \! ^$ x
  3. {
    5 A2 }5 U" z  d2 M; f3 j
  4.     ListItem_t * pxIterator;
    4 Q& f5 M7 Q; x, o
  5.     const TickType_t xValueOfInsertion = pxNewListItem->xItemValue;
    ) |8 D9 A8 g2 v! o, L
  6. ' m. @8 }9 c. A" n1 N* D# H9 p
  7.     /* 检查列表和列表项数据的完整性,仅当configASSERT()定义时有效。*/
    ) D) _' L/ A' ]9 B
  8.     /* Only effective when configASSERT() is also defined, these tests may catch3 N3 H% w; n2 D' P" A% K
  9.      * the list data structures being overwritten in memory.  They will not catch+ A9 Y9 X8 }! ?" V  b
  10.      * data errors caused by incorrect configuration or use of FreeRTOS. */
    , v- X8 s8 |. U4 _7 v
  11.     listTEST_LIST_INTEGRITY( pxList );  H7 S& u4 }; `- {$ j% y# N
  12.     listTEST_LIST_ITEM_INTEGRITY( pxNewListItem );
    : A! ~* q/ r" e3 u
  13. 5 }' K2 O* ^+ O& t- y- e: L
  14.     /* Insert the new list item into the list, sorted in xItemValue order.
    & E/ d0 S# @) A( {" z( B7 |4 s+ T
  15.      *; c5 t) z7 ~& G
  16.      * If the list already contains a list item with the same item value then the
    " C5 X* J, c/ T; t3 {% s8 Y
  17.      * new list item should be placed after it.  This ensures that TCBs which are, Q  M# l9 H/ i! q" r
  18.      * stored in ready lists (all of which have the same xItemValue value) get a
    # D3 h& N2 A# j& K+ I8 d7 [
  19.      * share of the CPU.  However, if the xItemValue is the same as the back marker% G6 n+ V9 ^" {% G3 W) H- v
  20.      * the iteration loop below will not end.  Therefore the value is checked
    & J& O2 \5 L4 q8 K1 Z" D0 C4 F" x, s
  21.      * first, and the algorithm slightly modified if necessary. */9 Y6 Z- h: M) Y4 \$ k7 V! e2 m" A/ \
  22.     /*将新的列表项插入到列表,根据xItemValue的值升序插入列表。*/
    + k! H& w1 V7 ~/ K: g' _6 D
  23.     if( xValueOfInsertion == portMAX_DELAY )  C" O1 A5 O; b" D7 T* Y
  24.     {
    , I4 G. |+ \, ?- u" T
  25.         pxIterator = pxList->xListEnd.pxPrevious;0 \) |) l; E2 s! I1 @
  26.     }8 {' t8 }6 K. C2 X1 O
  27.     else, O5 b" |* i6 A, z4 t# O) B+ q
  28.     {5 \' a* ]+ V. @! ]  m- ?! h
  29.         /* *** NOTE ***********************************************************
    % U5 Q& m( S- I4 P: }% _8 `! B7 r- t
  30.         *  If you find your application is crashing here then likely causes are6 |- r1 j  z9 \8 y; t
  31.         *  listed below.  In addition see  for8 p* p. N  ^- l/ D2 Y
  32.         *  more tips, and ensure configASSERT() is defined!
    * |8 R! P1 K- M& b6 }: A
  33.         *
    + \) G9 T1 @% {$ M- ~6 U
  34.         *
    , J* o# U7 Y' J/ U
  35.         *   1) Stack overflow -
    % Q# d7 }3 y. \
  36.         *      see
    % R: ~( j+ i, j+ i! J% Q' C) x
  37.         *   2) Incorrect interrupt priority assignment, especially on Cortex-M
    9 \! T% u8 O& [3 y
  38.         *      parts where numerically high priority values denote low actual- y5 n0 D. ~6 T( S2 b
  39.         *      interrupt priorities, which can seem counter intuitive.  See
    7 w) q1 ?0 y' b$ J- V/ e$ P
  40.         *     and the definition: f! {3 K4 ?  u% J; z6 g1 M( Y
  41.         *      of configMAX_SYSCALL_INTERRUPT_PRIORITY on
    " h( A, c" P3 t4 g! X
  42.         *    # @( l2 `, g- \
  43.         *   3) Calling an API function from within a critical section or when" ?$ G  S; w7 Q; q
  44.         *      the scheduler is suspended, or calling an API function that does
    - ^, k# w5 R, I4 w# `
  45.         *      not end in "FromISR" from an interrupt.8 L# z1 Y! h3 b
  46.         *   4) Using a queue or semaphore before it has been initialised or
    : A: T0 P, Q; w! ]0 c* P! l  i
  47.         *      before the scheduler has been started (are interrupts firing
    + e/ w: E  M5 |% }+ G, J! `: ~
  48.         *      before vTaskStartScheduler() has been called?).0 t0 {7 r* f- i( N
  49.         **********************************************************************/; b# r  Q( I, l0 j* Y
  50.   s/ l' M& h3 g* @
  51.         //xListEnd表示列表的末尾
    4 w; Z) N* u3 f7 |' [0 {4 [
  52.         for( pxIterator = ( ListItem_t * ) &( pxList->xListEnd ); pxIterator->pxNext->xItemValue <= xValueOfInsertion; pxIterator = pxIterator->pxNext ) /*lint !e826 !e740 !e9087 The mini list structure is used as the list end to save RAM.  This is checked and valid. *//*lint !e440 The iterator moves to a different value, not xValueOfInsertion. */  ~! n: n* s5 q) U% ~3 p; m
  53.         {+ p# a* U" ]2 N4 T
  54.             /* There is nothing to do here, just iterating to the wanted: D; a0 T) I3 n2 D4 B/ }0 m
  55.              * insertion position. */5 v! p; m1 T/ I9 n! x+ j* g1 q- H
  56.         }
    6 W3 J" P6 P: s) b, w% k3 M
  57.     }! E* a: q( w; C1 a. d$ p

  58. ! E- C, |2 G) T: g
  59.     pxNewListItem->pxNext = pxIterator->pxNext;* P. W# u/ [0 a  V5 I
  60.     pxNewListItem->pxNext->pxPrevious = pxNewListItem;; U& ]: t- w1 U) d
  61.     pxNewListItem->pxPrevious = pxIterator;: v6 ^( W* c6 S! i6 t" \! T
  62.     pxIterator->pxNext = pxNewListItem;
    9 c. N) a( O2 @8 _1 ~1 G
  63. ) u  t; s$ B$ K  Z. K
  64.     /* Remember which list the item is in.  This allows fast removal of the
    $ K2 L* T% p4 Q6 B
  65.      * item later. */
    9 r  g2 T) y! r) N( x7 p7 I
  66.     pxNewListItem->pxContainer = pxList;
    7 a- p, o+ o) d* Y4 E' u( l

  67. % D6 _2 I. ~0 w& `0 j
  68.     ( pxList->uxNumberOfItems )++;
    1 l  |  k5 O+ h, Y" k0 M2 ~4 Y1 V
  69. }
复制代码
$ q6 r4 V! ~7 ~' f3 z5 U
根据xItemValue的值将新的列表项插入到列表。如果列表中存在与新列表项xItemValue值相同的列表项,则新插入的列表项位于它之后。如果列表项的xItemValue值等于portMAX_DELAY(列表结束标记,我们在讲列表数据结构时,说到每个列表数据结构体中都有一个列表项成员xListEnd,用于标记列表结束。xListEnd.xItemValue被初始化为一个常数,其值与硬件架构相关,为0xFFFF或者0xFFFFFFFF。这个常数在移植层定义,即宏portMAX_DELAY),则表示到达了列表结束位置。
( F2 I5 S8 k: F: ^; Q, w' o( k! M0 G4 }- P. q
5.4 列表项末尾插入
8 L% U! n; S0 x+ Q, {; B
API函数vListInsertEnd()是简单的将列表项插入到列表的末端。
% I' Z* d! G1 N: C- O
; R2 F/ X0 |7 }" Z2 H$ i
  1. void vListInsertEnd( List_t * const pxList, ListItem_t * const pxNewListItem )# [: B  V2 S% k
  2. {
    / P$ {# _/ b1 o% P* ]
  3. ListItem_t* const pxIndex = pxList->pxIndex;
    % i+ e, l0 y; m3 `2 J5 n
  4. 1 i% ~- a2 {0 m1 n6 i6 r
  5.          /*检查列表和列表项数据的完整性,仅当configASSERT()定义时有效。*/& o7 _; ~+ w. c4 Z. d. @0 O& Q, B7 X
  6.          listTEST_LIST_INTEGRITY( pxList );
    & j  ^6 z0 ]8 ^' g4 g+ p1 o
  7.          listTEST_LIST_ITEM_INTEGRITY(pxNewListItem );
    8 Z' c# \$ J: t' C7 z+ K& @0 q

  8. 6 q1 j6 A8 l- y1 O- T5 E- [' u
  9.          /*向列表中插入新的列表项*/3 K4 k6 c/ Z- a( K: l+ y6 c
  10.          pxNewListItem->pxNext = pxIndex;. W  |2 z/ r5 C7 X( q, v  P
  11.          pxNewListItem->pxPrevious =pxIndex->pxPrevious;- |4 ]7 p, y) Q+ Y

  12. 1 z! Z4 f; V, F4 b( Q
  13.          mtCOVERAGE_TEST_DELAY();) K) z# H, K1 }- h

  14. ; C2 I- K4 [0 ~0 Q; k: E7 O
  15.          pxIndex->pxPrevious->pxNext =pxNewListItem;2 s) [; R, y* w1 v$ Y- F1 X( I
  16.          pxIndex->pxPrevious = pxNewListItem;! O  }+ n  G- q# k8 |7 J8 f) X

  17. 9 X6 B2 @$ ?( G7 D1 t, `
  18.          pxNewListItem->pvContainer = ( void* ) pxList;
    8 [6 E" F2 m' [6 z5 ~
  19. 3 R. m/ u7 O% v2 q
  20.          ( pxList->uxNumberOfItems )++;! W- `0 f# p, ~0 M9 P
  21. }
复制代码

; S; ]2 v, c& r6 P' R5.5 列表项删除8 y( |1 C, K' N, q) @  m2 i: K7 g
列表项的删除只是将指定的列表项从列表中删除,并不会将这个列表项的内存给释放掉。, i7 ?' c& y, l# q

& L8 S) ^7 S, [1 v; m* ?
  1. UBaseType_t uxListRemove( ListItem_t * const pxItemToRemove )0 Z$ N( G. j  ?! ^. Y- q+ q
  2. {3 N4 B) x: y& ~
  3. /* The list item knows which list it is in.  Obtain the list from the list! [' d1 M3 O" Q7 d$ S
  4. * item. */
    ( g( d" X0 I0 Q: h: l! k
  5.     List_t * const pxList = pxItemToRemove->pxContainer;
    6 M* K8 D/ z+ O
  6. " Q! ?& N* l6 G" u
  7.     pxItemToRemove->pxNext->pxPrevious = pxItemToRemove->pxPrevious;' |. A% v. n2 f  x- h% ?
  8.     pxItemToRemove->pxPrevious->pxNext = pxItemToRemove->pxNext;# C7 h  i  F- Y& V

  9. $ Y+ k# r# Y7 C7 _9 J
  10.     /* Only used during decision coverage testing. */
    ( c1 Z' v: E' Y' F
  11.     mtCOVERAGE_TEST_DELAY();
    . D+ c+ P4 T6 f! K7 T2 s

  12. # f. Y5 L8 `$ Q" f9 W% d! t; Y& G
  13.     /* Make sure the index is left pointing to a valid item. */2 C2 K9 I" m9 b6 _; b) B; h
  14.     if( pxList->pxIndex == pxItemToRemove )
    * w" P& r: q/ m& T: d
  15.     {
    # i: V+ e+ _' D. f* b! c
  16.         pxList->pxIndex = pxItemToRemove->pxPrevious;
    8 E  `( a9 D+ @, e% L+ c4 Z, U
  17.     }
    1 l* K- ~+ U! e4 L
  18.     else
    , _* F/ x2 l  \, w$ k
  19.     {, j5 G  v3 `$ ^8 a% m7 k
  20.         mtCOVERAGE_TEST_MARKER();  M, |) i0 g# N# c! ~
  21.     }1 m% n3 G1 [" ~+ y: h- }

  22. ! r* F% @9 L4 R+ I4 U2 ]- r
  23.     pxItemToRemove->pxContainer = NULL;
    * ?) T3 y  u2 R: g
  24.     ( pxList->uxNumberOfItems )--;
    0 c2 c  g. p6 f# f& s

  25. 5 o' |) t0 S- s9 `5 J* n0 [  r
  26.     return pxList->uxNumberOfItems;9 \/ J* G! `. ^! n) V1 q/ ]8 X
  27. }
复制代码
4 \4 G1 T. D; X, r9 K& j1 b
5.6 列表遍历( k" T; @$ d& Y. E6 ^
  1. #define listGET_OWNER_OF_NEXT_ENTRY( pxTCB, pxList )                                           \! e) u+ h: d0 H( G3 y
  2.     {                                                                                          \. f3 }1 d: p3 @: V
  3.         List_t * const pxConstList = ( pxList );                                               \% k* F; F% m, R* x' h
  4.         /* Increment the index to the next item and return the item, ensuring */               \
    8 e" \( y4 @0 j+ [6 O
  5.         /* we don't return the marker used at the end of the list.  */                         \! Y! l, U2 a1 o: X
  6.         ( pxConstList )->pxIndex = ( pxConstList )->pxIndex->pxNext;                           \
    % ~! E4 k, f2 _5 j7 K. U' ^2 C# K# T% ~
  7.         if( ( void * ) ( pxConstList )->pxIndex == ( void * ) &( ( pxConstList )->xListEnd ) ) \
    6 N9 y. h3 D9 @: P: z# u0 j
  8.         {                                                                                      \
    ) g" R2 Y7 E: a5 Q
  9.             ( pxConstList )->pxIndex = ( pxConstList )->pxIndex->pxNext;                       \  U) N7 u6 ~! I7 h* q+ i4 j
  10.         }                                                                                      \
    & F) J% y/ m6 T4 i6 R% q
  11.         ( pxTCB ) = ( pxConstList )->pxIndex->pvOwner;                                         \. N# L2 ]1 q9 B, ]' @1 ~
  12.     }7 E; F# ~0 j9 W# E& Y: J
复制代码

5 G; ?0 t8 l+ V/ |. f0 N* i& O: [0 H, Y

4 x4 X# b+ C8 d9 y( k1 q" \( C, y( _
赞 收藏 评论0 发布时间:2022-6-18 17:00

举报

0个回答

所属标签

相似技术帖

官网相关资源

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