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

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

[复制链接]
STMCU小助手 发布时间:2022-3-26 14:00
01. 概述, O; X( S9 G" U4 K
要想看懂FreeRTOS 源码并学习其原理,有一个东西绝对跑不了,那就是FreeRTOS 的列表和列表项。列表和列表项是FreeRTOS 的一个数据结构,FreeRTOS 大量使用到了列表和列表项,它是FreeRTOS 的基石。要想深入学习并理解FreeRTOS,那么列表和列表项就必须首先掌握,否则后面根本就没法进行。/ ?8 X( ?* V: j  g( ?2 C2 r# [
% A5 {' i+ U2 U: G  I6 b' g8 i
列表被FreeRTOS调度器使用,用于跟踪任务,处于就绪、挂起、延时的任务,都会被挂接到各自的列表中。用户程序如果有需要,也可以使用列表。
% W' w. D6 X  ]+ \- K5 |# g+ a; y: G4 g: o
FreeRTOS列表使用指针指向列表项。一个列表(list)下面可能有很多个列表项(list item),每个列表项都有一个指针指向列表。如下图所示。
: V" B5 }! v2 U) Z
1 T# p( r- U# {, A 1K2XUWH(U$[(NNQ]HB2$@_9.png ' Q+ y8 q- x2 R$ y7 s" S

0 C6 {- C4 u  B' I/ L- ~. m02. 列表
% }7 b& e  z7 {- z, E; e; M3 g* R列表是FreeRTOS 中的一个数据结构,概念上和链表有点类似,列表被用来跟踪FreeRTOS中的任务。与列表相关的全部东西都在文件list.c 和list.h 中。在list.h 中定义了一个叫List_t 的结构体,如下:
# F; O3 b- }6 {( m
) K3 k6 t! F2 m# G1 ?, G
  1. typedef struct xLIST
    + v! |0 i& A/ E6 y1 W" w3 P
  2. {
    * I* E7 @4 C4 h% C8 y5 ^7 e
  3.      listFIRST_LIST_INTEGRITY_CHECK_VALUE                        /*用于检测列表项数据是否完整*/: K4 G) g; V/ A# z
  4.      configLIST_VOLATILE UBaseType_t uxNumberOfItems;
    $ S- f" N* ~# \( }) J# j3 q: q5 e5 |9 q
  5.      ListItem_t * configLIST_VOLATILE pxIndex;                   /*用于遍历列表*/
    + T8 A# v# g3 s! F8 \
  6.      MiniListItem_t xListEnd;                                    /*列表项*/
    " V: h- M2 G% }
  7.      listSECOND_LIST_INTEGRITY_CHECK_VALUE                       /*用于检测列表项数据是否完整*/
    , ?0 b  w) b2 s3 m3 r- \# Z- I7 T+ \
  8. }List_t;
复制代码
- s% v, f+ U0 v" s  o
@SXG_R@99Y5(WI_8J~~@H4Q.png / B' h- p/ P( U% t

* b2 C) L" x4 \$ B  D  o) s(1) 和(5) 、这两个都是用来检查列表完整性的, 需要将宏configUSE_LIST_DATA_INTEGRITY_CHECK_BYTES 设置为1,开启以后会向这两个地方分别添加一个变量xListIntegrityValue1 和xListIntegrityValue2,在初始化列表的时候会这两个变量中写入一个特殊的值,默认不开启这个功能。
" y; p! y# c9 Z4 ?(2)、uxNumberOfItems 用来记录列表中列表项的数量。
8 Q# L5 e  p9 M  n' |- I(3)、pxIndex 用来记录当前列表项索引号,用于遍历列表。! e2 X: \6 j  D) G
(4)、列表中最后一个列表项,用来表示列表结束,此变量类型为MiniListItem_t,这是一个迷你列表项。
* _) K% }2 E" O8 N. O8 `2 @$ t# q; Q# A3 b* p% O1 V2 J
03. 列表项& G/ Y2 s% H! Q$ ?, Q! ^3 X+ \# N
列表项就是存放在列表中的项目,FreeRTOS 提供了两种列表项:列表项和迷你列表项。这两个都在文件list.h 中有定义。! b0 [  W" G0 y' a" L
6 ^- J  d/ T9 M, b5 ?, ~1 s% Z. U  Q6 z
xLIST_ITEM列表项
8 p1 T/ W; s0 S- }+ d' K. ~" G  C% B2 s# ^+ \7 I! w& N2 `
  1. struct xLIST_ITEM8 O# Z) G* c; y$ [5 Y
  2. {
    6 \! K! f1 A0 I7 g% A, G8 h
  3.      listFIRST_LIST_ITEM_INTEGRITY_CHECK_VALUE           /*用于检测列表项数据是否完整*/3 u1 X/ W. ?8 Q/ ^; w, a
  4.      configLIST_VOLATILETickType_t xItemValue;           /*列表项值*/
    & ?! _3 z5 A* J  L0 }: t. V
  5.      struct xLIST_ITEM * configLIST_VOLATILE pxNext;      /*指向列表中下一个列表项*/9 p7 }. b6 y  Z' b0 H' g
  6.      struct xLIST_ITEM * configLIST_VOLATILE pxPrevious;  /*指向列表中上一个列表项*/) q% t! ~3 ^% k
  7.      void * pvOwner;                                     /*指向一个任务TCB*/0 \( w. x5 k! H; H
  8.      void * configLIST_VOLATILE pvContainer;             /*指向包含该列表项的列表 */
    . u9 M3 [  ?9 n) S
  9.      listSECOND_LIST_ITEM_INTEGRITY_CHECK_VALUE          /*用于检测列表项数据是否完整*/
    8 i5 u: _; Y9 \$ H) S( R
  10. };
    . R9 g) H& X4 l/ T/ a2 K
  11. typedef struct xLIST_ITEM ListItem_t;
复制代码
2 i+ I9 z7 K5 G$ _5 A
N%7G}3){B3XZ1T4SG)FW@VP.png
2 k6 ]8 y# w% V. j/ n  c) g4 P9 ?! Y# _
(1)和(7)、用法和列表一样,用来检查列表项完整性的。以后我们在学习列表项的时候不讨论这个功能!4 t) c) d5 _) y" {, W- u) z* b5 u
(2)、xItemValue 为列表项值。
1 k4 W. M5 t! m# j3 l( R3 @(3)、pxNext 指向下一个列表项。# m  H6 x3 ^4 [* M3 p2 c' L
(4)、pxPrevious 指向前一个列表项,和pxNext 配合起来实现类似双向链表的功能。  D; F# Q$ c: d" ]
(5)、pvOwner 记录此链表项归谁拥有,通常是任务控制块。
: L* U  g8 z& _; m(6)、pvContainer 用来记录此列表项归哪个列表。注意和pvOwner 的区别,在前面讲解任务控制块TCB_t 的时候说了在TCB_t 中有两个变量xStateListItem 和xEventListItem,这两个变量的类型就是ListItem_t,也就是说这两个成员变量都是列表项。以xStateListItem 为例,当创建一个任务以后xStateListItem 的pvOwner 变量就指向这个任务的任务控制块,表示xSateListItem属于此任务。当任务就绪态以后xStateListItem 的变量pvContainer 就指向就绪列表,表明此列表项在就绪列表中。举个通俗一点的例子:小王在上二年级,他的父亲是老王。如果把小王比作列表项,那么小王的pvOwner 属性值就是老王,小王的pvContainer 属性值就是二年级。+ w8 J. `0 Q* [2 f
, ~4 [4 k' x# i7 l# j4 h) L
xMINI_LIST_ITEM列表项) p, e& F2 ^+ E3 Q  x

8 H/ U0 A, E, L7 l0 C5 ~
  1. struct xMINI_LIST_ITEM
    2 z: q7 j$ D( h0 i0 |; I% r( x2 i
  2. {
    # j5 t; f, ^+ y
  3.      listFIRST_LIST_ITEM_INTEGRITY_CHECK_VALUE           /*用于检测列表项数据是否完整*/
    ; @8 u# l9 m+ Q- J" b
  4.      configLIST_VOLATILE TickType_t xItemValue;
    ( Z, x( k/ ?  D" Y% b4 |2 K. H
  5.      struct xLIST_ITEM * configLIST_VOLATILE pxNext;3 k4 ~2 o+ h: I2 W4 {" }" x6 n6 F2 ^
  6.      struct xLIST_ITEM * configLIST_VOLATILE pxPrevious;% R- f3 h2 V$ N  p9 Q' W
  7. };
    + R5 M+ O( }, m: x( \1 R1 j5 F  P
  8. typedef struct xMINI_LIST_ITEM MiniListItem_t;
复制代码
6 r2 X8 I) c- j, b$ a
$A`B7_1A1`S(1@90`[7OHZX.png
2 r5 Y4 P% I5 D  |2 W5 J$ t/ S/ u* G7 I4 S  K0 N- M( p
(1)、用于检查迷你列表项的完整性。& b$ c( D. I" x5 |8 L( a. p
* q) a' V$ Q3 @* P! X' W6 a9 n7 N
(2)、xItemValue 记录列表列表项值。; L0 U2 t8 T2 O( o4 b
(3)、pxNext 指向下一个列表项。
  A% c8 @- c( u4 F  m% Y: a( F(4)、pxPrevious 指向上一个列表项。* m$ S! q5 ]* R+ A
可以看出迷你列表项只是比列表项少了几个成员变量,迷你列表项有的成员变量列表项都有的,没感觉有什么本质区别啊?那为什么要弄个迷你列表项出来呢?那是因为有些情况下我们不需要列表项这么全的功能,可能只需要其中的某几个成员变量,如果此时用列表项的话会造成内存浪费!比如上面列表结构体List_t 中表示最后一个列表项的成员变量xListEnd 就是MiniListItem_t 类型的。/ z. K! U  d" K# X! _8 I

  i6 h. ^: n, j' R04. 列表相关宏# k0 M! l7 _8 W  F' b8 g
  1. /*
    : g& @, p( E% F( X" g3 M
  2. * Access macro to set the owner of a list item.  The owner of a list item
    + K+ {/ G! ^$ |  T9 r! \- E0 ^( I
  3. * is the object (usually a TCB) that contains the list item.
    ) V( n- F9 b2 K9 [* X- l* H8 a
  4. *2 d8 t% d) s1 m2 w
  5. * \page listSET_LIST_ITEM_OWNER listSET_LIST_ITEM_OWNER
    - M' G8 Q4 i% n% R) t
  6. * \ingroup LinkedList! v9 i+ k; H* P# F; r- n9 I! s3 u
  7. */  K$ L, C; u6 g( ~( [. o
  8. #define listSET_LIST_ITEM_OWNER( pxListItem, pxOwner )    ( ( pxListItem )->pvOwner = ( void * ) ( pxOwner ) )& a* h1 f8 x+ ?, P# l) S

  9. ( v. n, |' E" l  N# e# S
  10. /*! ?/ |% v* ~# N: C5 R" `  w" I
  11. * Access macro to get the owner of a list item.  The owner of a list item9 B2 f1 d$ J* M
  12. * is the object (usually a TCB) that contains the list item.
    & A! @& P$ A% H! w; w1 J6 `3 J
  13. *, K# ]) d7 \# [$ H; f: r
  14. * \page listGET_LIST_ITEM_OWNER listSET_LIST_ITEM_OWNER$ k  A: r+ v% j' d; W
  15. * \ingroup LinkedList6 v1 l! b0 W) {8 s; O- A
  16. */' i0 n4 n; O( }
  17. #define listGET_LIST_ITEM_OWNER( pxListItem )             ( ( pxListItem )->pvOwner )1 Q: J6 f  G" F; I
  18. / T$ ?9 ?8 T4 ?! c  a$ G
  19. /*1 U# E1 p: z, W3 E9 Y9 P: m
  20. * Access macro to set the value of the list item.  In most cases the value is
    ' `8 i7 `$ B7 q4 R
  21. * used to sort the list in descending order., I3 V7 V. Y: U0 f
  22. *' T5 c3 s  C3 c( L" j
  23. * \page listSET_LIST_ITEM_VALUE listSET_LIST_ITEM_VALUE
    : k! a* z9 R' V( h2 \
  24. * \ingroup LinkedList
    . q, p. J3 T$ B0 `0 X) e
  25. */
    % O! [+ y! @( {# T
  26. #define listSET_LIST_ITEM_VALUE( pxListItem, xValue )     ( ( pxListItem )->xItemValue = ( xValue ) )' x3 h0 g$ L6 R! u  G5 s+ N2 [; X: O
  27. 2 [  Q/ b! ^2 @2 i5 Y- s* K% `
  28. /*
    5 g) S4 P0 S5 O* z: O
  29. * Access macro to retrieve the value of the list item.  The value can
    0 _0 J2 H* b) G
  30. * represent anything - for example the priority of a task, or the time at
    ) U/ ~3 ]/ Z, h
  31. * which a task should be unblocked.
    & c* H' D. {5 }( D2 w
  32. *
    7 r; }1 {- I, }
  33. * \page listGET_LIST_ITEM_VALUE listGET_LIST_ITEM_VALUE
    * v# v0 ]/ ]2 b, f: ^$ O
  34. * \ingroup LinkedList) \% P% d" t- U% H" ^
  35. */
    ( _: n5 q. A, I1 A$ v
  36. #define listGET_LIST_ITEM_VALUE( pxListItem )             ( ( pxListItem )->xItemValue )
    9 }% y1 |2 i! F# ]0 }3 O5 Z, _  p
  37. ) `  I8 i5 e3 p: [
  38. /*
    - M+ [% n8 j: c* T1 o) q
  39. * Access macro to retrieve the value of the list item at the head of a given+ |6 }# b: M: z# l7 o, d
  40. * list.2 p6 y* g( j# ?
  41. *
    * e) L2 n. |' o
  42. * \page listGET_LIST_ITEM_VALUE listGET_LIST_ITEM_VALUE2 L: N* Y% m+ f: J
  43. * \ingroup LinkedList
    : d6 p- s- q- e6 s$ t6 W
  44. */
    0 u8 G$ n$ x  H5 c
  45. #define listGET_ITEM_VALUE_OF_HEAD_ENTRY( pxList )        ( ( ( pxList )->xListEnd ).pxNext->xItemValue )
    5 m* [* z+ }! z0 |8 g% F1 k
  46. : O$ n% U, C+ [+ _& D2 i/ `
  47. /*  w7 b' m: L) F* S* w
  48. * Return the list item at the head of the list.3 w; K8 ?! _) Z8 V- D4 P
  49. *
    9 G8 M0 @' G( H. U4 d, h
  50. * \page listGET_HEAD_ENTRY listGET_HEAD_ENTRY& N/ R# b* ~) {- i0 b2 D2 `. D
  51. * \ingroup LinkedList
    ' I( [5 o0 f' x( Q. f( W9 p% }
  52. */
    $ B9 Q% ~/ |" ^1 \$ o
  53. #define listGET_HEAD_ENTRY( pxList )                      ( ( ( pxList )->xListEnd ).pxNext )
    ( ~; u% H& |3 v# v  @
  54. 3 l; ]4 ?9 X+ F! Y
  55. /*
    ! n, Y, p  }3 A: O0 d. }
  56. * Return the next list item.
    & x) ?; G5 z3 q7 V# a3 _
  57. *& r! X) M: @. i) E+ v; Y
  58. * \page listGET_NEXT listGET_NEXT% A0 M# `  M" M$ r2 L4 D
  59. * \ingroup LinkedList5 ~2 z: d% X3 Q- G
  60. */) _6 T" V4 Y8 a8 C7 t" L0 G  j
  61. #define listGET_NEXT( pxListItem )                        ( ( pxListItem )->pxNext )/ X6 L1 D; r) t; h6 C4 w

  62. # Q/ C0 H6 R! ~1 N) A. c
  63. /*
    : j% y8 p. E: J3 r# P, C: |
  64. * Return the list item that marks the end of the list
    3 a. _: ^9 S, o7 [: w
  65. *3 B3 ^) @. L1 s' U4 }' b. x1 R
  66. * \page listGET_END_MARKER listGET_END_MARKER: C; M% N' ]8 s3 Z' h
  67. * \ingroup LinkedList4 O: V# V: G% S
  68. */
    6 ?( z3 T! A7 o
  69. #define listGET_END_MARKER( pxList )                      ( ( ListItem_t const * ) ( &( ( pxList )->xListEnd ) ) )
    8 q" l: W0 f. e: ^
  70. # t8 F( ~4 x3 ?% |( B1 n3 M: T
  71. /*) @5 B: L% u$ ~. r
  72. * Access macro to determine if a list contains any items.  The macro will
    3 b9 u  @7 p* O0 N" e
  73. * only have the value true if the list is empty.) J0 q' s+ {$ r& T; b. y) D
  74. *3 N" I1 |4 g. I6 Q: W% J
  75. * \page listLIST_IS_EMPTY listLIST_IS_EMPTY
    & L7 }+ L  D$ c' g
  76. * \ingroup LinkedList. N9 Z% I4 o$ S5 o8 X" a9 y! E3 Q4 d
  77. */
    . V* ~% W9 ^- q. c
  78. #define listLIST_IS_EMPTY( pxList )                       ( ( ( pxList )->uxNumberOfItems == ( UBaseType_t ) 0 ) ? pdTRUE : pdFALSE )
    , h1 J) T# ^+ L- T
  79. 8 _: @% i" M; x! _
  80. /*" l+ v& M# z3 i' E
  81. * Access macro to return the number of items in the list.
    ) ~; P3 {( o5 H( R' s
  82. */
    ) K4 z1 R( H& w5 A2 D* [) ]
  83. #define listCURRENT_LIST_LENGTH( pxList )                 ( ( pxList )->uxNumberOfItems )& E9 X+ o8 j1 X& C1 p
  84. 8 d4 H" P" Y7 O0 `# {% t! D
  85. /*
    - P. V1 C7 ]1 ^7 F, }7 ]
  86. * Access function to obtain the owner of the next entry in a list.' ]9 C" w+ I- W, x1 O
  87. *
    1 x  H5 L4 T% x. e. g( u
  88. * The list member pxIndex is used to walk through a list.  Calling
    : o' [  f! K, P
  89. * listGET_OWNER_OF_NEXT_ENTRY increments pxIndex to the next item in the list- z# T  v8 p+ Y; a  O( |' N* @
  90. * and returns that entry's pxOwner parameter.  Using multiple calls to this
    . _7 \1 t1 J1 @6 B% R
  91. * function it is therefore possible to move through every item contained in" g. k3 H$ b4 S0 j" w( k
  92. * a list.  o0 b8 I; [$ y6 F, w5 H
  93. *3 w! D  q1 N+ S1 `5 Y
  94. * The pxOwner parameter of a list item is a pointer to the object that owns$ k! ~) F" V* p( q) B
  95. * the list item.  In the scheduler this is normally a task control block.
    " o3 T; d3 g! _. I8 G3 q
  96. * The pxOwner parameter effectively creates a two way link between the list
    7 ^9 f2 j8 \* x, W" m
  97. * item and its owner.
    ( v- r9 \/ Y5 T. H+ q
  98. *  J6 s5 W0 l2 ?; D
  99. * @param pxTCB pxTCB is set to the address of the owner of the next list item.
    6 {3 r$ G! l* F  h. ^$ E
  100. * @param pxList The list from which the next item owner is to be returned.0 q/ l) e5 n- ]6 Z3 L
  101. *  r# _+ n8 v5 D4 d' s. {4 l
  102. * \page listGET_OWNER_OF_NEXT_ENTRY listGET_OWNER_OF_NEXT_ENTRY& }2 b5 H4 S  H, C  B, t9 t  H7 d
  103. * \ingroup LinkedList
    $ i2 G( L1 R2 `* Y
  104. */
    5 c% K7 S4 d- p& j3 g, K, U
  105. #define listGET_OWNER_OF_NEXT_ENTRY( pxTCB, pxList )                                           \2 B& U1 s; d/ b8 ^3 r) V: @& n
  106.     {                                                                                          \/ E& h$ p! p4 A8 H
  107.         List_t * const pxConstList = ( pxList );                                               \
    ! ]; j% @9 b4 W- c2 S
  108.         /* Increment the index to the next item and return the item, ensuring */               \
    # ~& O1 o9 w- K% M4 S" t) u
  109.         /* we don't return the marker used at the end of the list.  */                         \
    $ T2 C; K: C9 `! c( u+ @) A5 s' Q0 b
  110.         ( pxConstList )->pxIndex = ( pxConstList )->pxIndex->pxNext;                           \
    9 M( ?5 \1 I, _" |+ n
  111.         if( ( void * ) ( pxConstList )->pxIndex == ( void * ) &( ( pxConstList )->xListEnd ) ) \5 Y7 F0 R' v0 w& x( y/ `! P
  112.         {                                                                                      \+ _0 z5 \6 |& T
  113.             ( pxConstList )->pxIndex = ( pxConstList )->pxIndex->pxNext;                       \
    * u% K7 ]* B* U3 c+ Z7 y
  114.         }                                                                                      \
    . d* j* a& {) Z% ^
  115.         ( pxTCB ) = ( pxConstList )->pxIndex->pvOwner;                                         \
    + Y9 L4 R$ e- O. \4 D0 F6 I! w6 _
  116.     }
    0 l  Y) _- @' V

  117. 7 V: a3 x: \0 z1 A/ t) ~, }

  118. 3 _& j- G% i8 w# S* W, `. @
  119. /*6 D( I: @( V. T# O- A; N
  120. * Access function to obtain the owner of the first entry in a list.  Lists
    / f$ H3 m: x2 N# ?* L. F
  121. * are normally sorted in ascending item value order.0 z2 B$ A" T" T3 C
  122. *
      t2 L! b. w5 E: J( x! t
  123. * This function returns the pxOwner member of the first item in the list./ u6 e, y: @( p# n
  124. * The pxOwner parameter of a list item is a pointer to the object that owns- a" s& r& q# E
  125. * the list item.  In the scheduler this is normally a task control block.
    + W( S/ V2 M. y7 |0 ]
  126. * The pxOwner parameter effectively creates a two way link between the list2 T. Q2 M, {0 m% H
  127. * item and its owner.
    ! r7 W& ~& p0 z1 i3 J  Z
  128. *
      E. a3 i; g; p" V9 Y( x* {8 N7 Y
  129. * @param pxList The list from which the owner of the head item is to be: `( {+ ?* @9 L2 o, f4 `1 A& x* g
  130. * returned.' Z6 U: o% R) A
  131. *. R* g7 q9 D6 o9 Y
  132. * \page listGET_OWNER_OF_HEAD_ENTRY listGET_OWNER_OF_HEAD_ENTRY$ f( m1 Z: ]. S* s
  133. * \ingroup LinkedList3 z; G" a: g% m9 V4 F
  134. */
    - R2 `* I7 D+ g: D- J
  135. #define listGET_OWNER_OF_HEAD_ENTRY( pxList )            ( ( &( ( pxList )->xListEnd ) )->pxNext->pvOwner )
    7 [8 j* p+ b; T3 Q2 H0 i
  136.   x9 h: \6 u4 a8 Y% l2 B' f
  137. /*/ X: _6 F" u0 G# f: I
  138. * Check to see if a list item is within a list.  The list item maintains a8 c) j" Q# }( M( Y' L% S* _
  139. * "container" pointer that points to the list it is in.  All this macro does
    0 _% \9 S" q: p8 P* V( K
  140. * is check to see if the container and the list match.
    6 o- O+ s% _# M' E
  141. *
    % s/ U5 p5 \6 [1 a" m3 M. }
  142. * @param pxList The list we want to know if the list item is within.4 h% U9 ]& }' g8 e( @
  143. * @param pxListItem The list item we want to know if is in the list.
    & P$ T- ?  w1 g- z$ i
  144. * @return pdTRUE if the list item is in the list, otherwise pdFALSE.
    # {2 |/ h% b$ x8 c0 `
  145. */
    ! T8 T1 n- p7 n
  146. #define listIS_CONTAINED_WITHIN( pxList, pxListItem )    ( ( ( pxListItem )->pxContainer == ( pxList ) ) ? ( pdTRUE ) : ( pdFALSE ) )
    : P( @+ I7 ^% z# r

  147. 5 B( s3 B% `. H1 r3 t2 [1 S+ t
  148. /*
    9 H; }/ \8 h- B7 e+ Y
  149. * Return the list a list item is contained within (referenced from).
    4 m4 Q$ t' `) x. b8 R
  150. *% q& r/ U1 P# P- l( N
  151. * @param pxListItem The list item being queried.3 }' x. N" D+ ?
  152. * @return A pointer to the List_t object that references the pxListItem
    3 B9 F4 b) J! [: J  J* @
  153. */
    + u5 ?, H- `5 T, s7 W/ j! m. H
  154. #define listLIST_ITEM_CONTAINER( pxListItem )            ( ( pxListItem )->pxContainer )
    $ q6 c, C; e& |0 C* G; g+ m$ d( D

  155. $ N9 e2 V- ^  p& ^! g/ u
  156. /*
    + Q* W0 L: q! Z  B% f" P) l
  157. * This provides a crude means of knowing if a list has been initialised, as
    + p' b* l" A3 M) r: {; i% Y' M
  158. * pxList->xListEnd.xItemValue is set to portMAX_DELAY by the vListInitialise(); r) p8 z6 R0 T
  159. * function.3 Y) V8 N; ?: b- M3 C2 m1 P* m" X
  160. */( G+ a5 P5 Y) n; @/ t
  161. #define listLIST_IS_INITIALISED( pxList )                ( ( pxList )->xListEnd.xItemValue == portMAX_DELAY )# v0 ~+ _5 N9 L! I& R5 D
复制代码
' V% a' Q9 I$ S% A5 q  r
05. 列表相关函数; |/ q7 Z# S: W! k& o  t2 W- h: W
5.1 初始化列表

- D" G: [- b' L8 ?8 N列表结构体中包含一个列表项成员,主要用于标记列表结束。初始化列表就是把这个列表项插入到列表中。
. C! u* w' o. M  ^
+ ]( S  R) Z5 @+ g( u1 f) e$ \$ p
  1. void vListInitialise( List_t * const pxList )
    2 F) W9 t1 g7 j) _+ M8 _3 w
  2. {
    % T5 x( i( t+ q: i8 s6 d
  3.      /*列表索引指向列表项*/
    2 a- {- x1 \1 T
  4.      pxList->pxIndex = ( ListItem_t * )&( pxList->xListEnd );                  8 z, w% c; c  j# n
  5.      /* 设置为最大可能值 */0 Y. ^; x- u% `2 b8 @
  6.      pxList->xListEnd.xItemValue =portMAX_DELAY;
    , t2 f1 j/ E2 g- v% Y; w) E

  7. % j. }% L2 a( l
  8.      /* 列表项xListEnd的pxNext和pxPrevious指针指向了它自己 */
    / j$ d- A3 N+ U+ q6 O. T$ F( ~
  9.      pxList->xListEnd.pxNext = (ListItem_t * ) &( pxList->xListEnd );
    # K2 U: q, o$ J$ O) u/ n$ f+ b. K
  10.      pxList->xListEnd.pxPrevious= ( ListItem_t * ) &( pxList->xListEnd );
    7 \" l: f/ u  ?, M+ ]+ G4 [3 k
  11.      pxList->uxNumberOfItems = ( UBaseType_t) 0U;: S0 _' _2 K! C5 X5 [
  12. : }' r& D; W  T/ t$ h1 U% [
  13.      /* 设置为已知值,用于检测列表数据是否完整*/
    : v5 I2 ]. `- {# o% `' U, n
  14.      listSET_LIST_INTEGRITY_CHECK_1_VALUE(pxList );* y* }( g; G! l1 x( j
  15.      listSET_LIST_INTEGRITY_CHECK_2_VALUE(pxList );' N2 H8 {# k- l: I/ R
  16. }. Z, y4 Y5 f) C) d( M4 l8 N
复制代码

! b% C& J, O2 e& M如果宏configUSE_LIST_DATA_INTEGRITY_CHECK_BYTES设置为1,则使能列表项数据完整性检查,则宏listSET_LIST_INTEGRITY_CHECK_1_VALUE()和listSET_LIST_INTEGRITY_CHECK_2_VALUE被一个已知值代替,默认为0x5a5a(16位架构)或者0x5a5a5a5a(32位架构)。
; [+ W! @' W  i6 @; Y, ]1 X( n; z7 e1 B  x& T# W
PQ7TE`T~5F]2RUTXY97~6%Q.png 2 n# N2 ~+ a2 B, I

: X# g' F& n! b8 r' C6 Y5.2 初始化列表项8 ^, v# K7 ~% D, z
列表项的初始比较简单,只要确保列表项不在任何列表中即可。
: b0 L$ t- C! A: v- _
  1. void vListInitialiseItem( ListItem_t * const pxItem )7 t  V* Z1 k+ F  x# x3 h9 g5 P
  2. {) ?- j4 z( y+ M& V+ J1 D
  3.      pxItem->pvContainer = NULL;* a) U- a: [! y. l
  4. 6 N! Z9 @1 v. s
  5.      /*设置为已知值,用于检测列表项数据是否完整*/; D" o6 H+ Y6 s( x
  6.      listSET_FIRST_LIST_ITEM_INTEGRITY_CHECK_VALUE(pxItem );
    & B2 C3 e+ \6 p/ R' X9 i, A' g
  7.      listSET_SECOND_LIST_ITEM_INTEGRITY_CHECK_VALUE(pxItem );
    - D3 l# C7 n7 Z) N4 [
  8. }
复制代码

  O& m- c: D& |( q/ [4 M# W如果宏configUSE_LIST_DATA_INTEGRITY_CHECK_BYTES设置为1,则使能列表项数据完整性检查,则宏listFIRST_LIST_ITEM_INTEGRITY_CHECK_VALUE和listSECOND_LIST_ITEM_INTEGRITY_CHECK_VALUE会被两个已知的数值代替,默认为0x5a5a(16位架构)或者0x5a5a5a5a(32位架构)。* x1 u/ h* z$ ]! t" y

, E& M, V) ]. g, `0 \' X5.3 列表项插入函数
% T: k3 T. k4 l5 t+ h每个列表项对象都有一个列表项值(xItemValue),通常是一个被跟踪的任务优先级或是一个调度事件的计数器值。调用API函数vListInsert( List_t * const pxList, ListItem_t * const pxNewListItem)可以将pxNewListItem指向的列表项插入到pxList指向的列表中,列表项在列表的位置由pxNewListItem->xItemValue决定,按照升序排列。* s5 J9 p8 T% _; G( C

7 ]3 B+ n# f' G; x7 a7 f
  1. void vListInsert( List_t * const pxList,( A# ^0 j, n; o/ U1 _5 m
  2.                   ListItem_t * const pxNewListItem )
    / T$ f2 ]% H9 N% U# C: x+ Y
  3. {
    1 ^2 u* ?  p# S6 h* \# X
  4.     ListItem_t * pxIterator;% o, I# B8 i& E
  5.     const TickType_t xValueOfInsertion = pxNewListItem->xItemValue;
    1 O% I, D7 m  L

  6. ; L- J, a8 r9 w  Z8 [. p1 `! b
  7.     /* 检查列表和列表项数据的完整性,仅当configASSERT()定义时有效。*/
    ' }/ K$ O# e" M6 _
  8.     /* Only effective when configASSERT() is also defined, these tests may catch, ?7 T! V4 m+ t0 L5 W  V
  9.      * the list data structures being overwritten in memory.  They will not catch
      Y1 J7 E& k: K9 F" H
  10.      * data errors caused by incorrect configuration or use of FreeRTOS. */
    ) A/ ?/ Q+ O1 ?. ^
  11.     listTEST_LIST_INTEGRITY( pxList );& j- k. s5 Y! I  r
  12.     listTEST_LIST_ITEM_INTEGRITY( pxNewListItem );, ?, {- v  ~2 C

  13. , T  C" _* m9 J0 t4 @8 z
  14.     /* Insert the new list item into the list, sorted in xItemValue order.. ^) w" K" L& S* x2 T% J  U/ n
  15.      *6 ]9 T7 G; `0 s: d' j  G  T
  16.      * If the list already contains a list item with the same item value then the- h+ N* i2 G4 E  ~+ y1 N( e
  17.      * new list item should be placed after it.  This ensures that TCBs which are5 I" `: ?  d' M
  18.      * stored in ready lists (all of which have the same xItemValue value) get a7 r4 _' }6 H% i6 F( i) B
  19.      * share of the CPU.  However, if the xItemValue is the same as the back marker
    % [0 {1 G4 }) `( e
  20.      * the iteration loop below will not end.  Therefore the value is checked
    - S6 N4 g) B! @( j4 A8 C
  21.      * first, and the algorithm slightly modified if necessary. */1 C% b" ?. s, S1 }, s& q
  22.     /*将新的列表项插入到列表,根据xItemValue的值升序插入列表。*/
    7 j+ r3 j5 k$ F5 |5 ?+ F5 Q! y
  23.     if( xValueOfInsertion == portMAX_DELAY )
    7 O4 g' q: d8 B' {- x
  24.     {2 a. u- L6 F2 o! Q) m
  25.         pxIterator = pxList->xListEnd.pxPrevious;
    , Z) G/ u! _1 c0 S0 Q( e
  26.     }! H, N8 g. E% Y& k- [* V
  27.     else5 W: p6 c$ U5 O7 P5 x  j5 ^
  28.     {
    " G* c/ K8 K  i) w4 D
  29.         /* *** NOTE ***********************************************************
    . H6 R" i; q- ~& P7 [8 D
  30.         *  If you find your application is crashing here then likely causes are6 d3 H0 C& }* v% V' I; y) R, b' Z
  31.         *  listed below.  In addition see <a href="https://www.FreeRTOS.org/FAQHelp.html" target="_blank">https://www.FreeRTOS.org/FAQHelp.html</a> for
      F/ v! R# F! Q1 z4 b
  32.         *  more tips, and ensure configASSERT() is defined!  ]: O* Z- X$ ?& ^$ a; c( [& \, q! |" |
  33.         *  <a href="https://www.FreeRTOS.org/a00110.html#configASSERT" target="_blank">https://www.FreeRTOS.org/a00110.html#configASSERT</a>: i4 v5 k* A6 a1 W
  34.         *# ~! t. e5 Z: F7 u3 X: z$ u
  35.         *   1) Stack overflow -
    7 @' j( `( e. K6 q, H
  36.         *      see <a href="https://www.FreeRTOS.org/Stacks-and-stack-overflow-checking.html" target="_blank">https://www.FreeRTOS.org/Stacks-and-stack-overflow-checking.html</a>) s' b& g" o8 _2 a1 g* a) o
  37.         *   2) Incorrect interrupt priority assignment, especially on Cortex-M
    $ G- ~2 D( F& A3 s, ~# K/ l
  38.         *      parts where numerically high priority values denote low actual
    - A3 M9 w* W; j$ g8 Q  R
  39.         *      interrupt priorities, which can seem counter intuitive.  See, P7 o. l* A2 I' o* y
  40.         *      and the definition
    ' z' M0 g3 C8 \# @, [5 g4 \  w- e
  41.         *      of configMAX_SYSCALL_INTERRUPT_PRIORITY on7 d# }7 p, Q; M" Z5 h5 |( K
  42.         *        _* R6 e% r: K( A
  43.         *   3) Calling an API function from within a critical section or when
    # I, q( p9 F5 J) j' W* a) M
  44.         *      the scheduler is suspended, or calling an API function that does
    8 {# n2 ^; M+ [, ~
  45.         *      not end in "FromISR" from an interrupt.$ b+ W( d0 `8 i2 B$ c, {0 c
  46.         *   4) Using a queue or semaphore before it has been initialised or: v! g/ o+ p) K
  47.         *      before the scheduler has been started (are interrupts firing
    2 M1 s2 m3 u' X8 C* s- @5 h+ q
  48.         *      before vTaskStartScheduler() has been called?).
    . f7 O& U+ ~" ?5 }" Q5 x! H
  49.         **********************************************************************/
    6 R3 m! |2 X5 F7 f# {: |2 [. ]

  50. 0 H9 b5 B5 m3 C4 ^# [
  51.         //xListEnd表示列表的末尾
    $ ^$ F- K7 W& ?+ Z6 k, E
  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. */
    " K; A' f6 }- d% u, _6 ?; @) s
  53.         {
    8 j8 |! y& K" D9 g" @. Z
  54.             /* There is nothing to do here, just iterating to the wanted# ~) i; Z" j" T5 O
  55.              * insertion position. */' P6 ^; n% Z9 ?8 X
  56.         }& P$ i  n4 ]9 Z; H* m
  57.     }
    % r: F7 h" r6 R" b( x

  58. 5 v9 q" d, S- U9 R7 @: u1 A
  59.     pxNewListItem->pxNext = pxIterator->pxNext;" u: {4 _+ S7 |0 O% Q7 j! y. J
  60.     pxNewListItem->pxNext->pxPrevious = pxNewListItem;
      A# w* ^0 t2 l3 |; ?8 I1 o
  61.     pxNewListItem->pxPrevious = pxIterator;
      I! C) W( A0 |+ G" L! Z6 @
  62.     pxIterator->pxNext = pxNewListItem;
    & ~+ p. R4 [2 W% Z& G- o: s
  63. 5 w! g* K$ E& f$ I( G
  64.     /* Remember which list the item is in.  This allows fast removal of the& p7 q4 e! f  E5 M: \& u
  65.      * item later. */
    $ g9 a4 O. b- q3 l0 |
  66.     pxNewListItem->pxContainer = pxList;$ o8 _3 C4 Q! P  a; ^

  67. , `3 J* [0 e. w. p+ d3 Y
  68.     ( pxList->uxNumberOfItems )++;
    : O! |/ Y" ?1 O0 i6 F
  69. }
    ) @  {; J0 W  W
复制代码
  ]) p) h; L$ i' A1 T0 g6 v  {
根据xItemValue的值将新的列表项插入到列表。如果列表中存在与新列表项xItemValue值相同的列表项,则新插入的列表项位于它之后。如果列表项的xItemValue值等于portMAX_DELAY(列表结束标记,我们在讲列表数据结构时,说到每个列表数据结构体中都有一个列表项成员xListEnd,用于标记列表结束。xListEnd.xItemValue被初始化为一个常数,其值与硬件架构相关,为0xFFFF或者0xFFFFFFFF。这个常数在移植层定义,即宏portMAX_DELAY),则表示到达了列表结束位置。
$ n1 p: g& w( j' N+ ?# I) B1 c2 v+ g( K* ^( L! \4 L8 L
5.4 列表项末尾插入
# P5 x4 [) W- S; ?" aAPI函数vListInsertEnd()是简单的将列表项插入到列表的末端。
" c( @% x; g* k, |
, x. Y- k  x0 S
  1. void vListInsertEnd( List_t * const pxList, ListItem_t * const pxNewListItem )9 O1 T( R8 l% A
  2. {6 ]! I9 o6 Z4 Z! y, Z; y6 w
  3. ListItem_t* const pxIndex = pxList->pxIndex;
      S* b% t; F8 C9 s& x0 O

  4. 6 \- q( {/ W( c8 q- B
  5.          /*检查列表和列表项数据的完整性,仅当configASSERT()定义时有效。*/
    0 o* }- s6 j( N
  6.          listTEST_LIST_INTEGRITY( pxList );
    ' y: s, J' G& O! [. F# `
  7.          listTEST_LIST_ITEM_INTEGRITY(pxNewListItem );
    9 w( k6 ~- O* ^7 b7 z- W

  8. ( i; F/ g8 X/ p
  9.          /*向列表中插入新的列表项*/' b+ L6 d& Z% {0 L
  10.          pxNewListItem->pxNext = pxIndex;
    / w* w* K0 N: a, h, j* F" Y
  11.          pxNewListItem->pxPrevious =pxIndex->pxPrevious;
    0 u8 ?/ Y- Z2 O% p: `! d: I. L) l
  12. : {, q! Y( r# g, B1 L, [# [$ D
  13.          mtCOVERAGE_TEST_DELAY();' s& q8 q3 S3 K% j" d, o0 `
  14. + [) p1 N, N8 J( I/ U
  15.          pxIndex->pxPrevious->pxNext =pxNewListItem;( U4 v$ _) A1 j9 H9 ~& S
  16.          pxIndex->pxPrevious = pxNewListItem;, D0 ?+ L) Q5 r- g
  17. 0 x# t7 K- t4 J: U$ D
  18.          pxNewListItem->pvContainer = ( void* ) pxList;3 ?5 w- c0 F; F4 b+ \

  19. 8 x, O# F) z: G1 O- R+ ^7 ?/ j- O
  20.          ( pxList->uxNumberOfItems )++;$ p7 s# w9 u, K1 n
  21. }
复制代码
) s3 e1 E. w% ^: G9 g, @5 K' C( u, A
5.5 列表项删除+ I) o8 f* W# Q7 C; I) i" P
列表项的删除只是将指定的列表项从列表中删除,并不会将这个列表项的内存给释放掉。
0 h/ M& G+ N: \: S) z& ]
; {- A3 |1 m, K$ e5 z" B
  1. UBaseType_t uxListRemove( ListItem_t * const pxItemToRemove )+ X4 g+ e/ i  W% `
  2. {
    & {1 r' v5 `* b
  3. /* The list item knows which list it is in.  Obtain the list from the list( D2 j! _( v; M9 W4 P+ I) ~
  4. * item. */1 O/ g) f7 P# l/ p# M
  5.     List_t * const pxList = pxItemToRemove->pxContainer;- y& \+ Z# x4 q5 z5 o, h
  6. 8 q" s+ j5 ], a* G' c
  7.     pxItemToRemove->pxNext->pxPrevious = pxItemToRemove->pxPrevious;
    ! ~2 H3 B; E& M$ j) D
  8.     pxItemToRemove->pxPrevious->pxNext = pxItemToRemove->pxNext;4 \: e" L" x# N- K; m  Y
  9. 8 h3 u/ B6 a- }9 A3 l
  10.     /* Only used during decision coverage testing. */" _3 Q* M' b" K
  11.     mtCOVERAGE_TEST_DELAY();9 C( P- X7 K1 d
  12. 3 V- R2 t! x+ T8 Q0 V
  13.     /* Make sure the index is left pointing to a valid item. */8 k1 Q* V1 U( F
  14.     if( pxList->pxIndex == pxItemToRemove )
    & a8 X/ y" {' V: R
  15.     {, R( U  Z" u3 W7 O( B+ Z
  16.         pxList->pxIndex = pxItemToRemove->pxPrevious;) k" k: O( z& [3 v: |
  17.     }
    : K+ Q1 |9 V4 K
  18.     else
    1 P8 l9 n" r- B
  19.     {+ F& x: m3 N: P! ]0 O5 h
  20.         mtCOVERAGE_TEST_MARKER();2 `. \- p  t( q
  21.     }1 y5 G/ i# l# b$ E2 @- v

  22. 9 u0 f  ]1 _9 G9 a( x! m
  23.     pxItemToRemove->pxContainer = NULL;& T7 U4 o) A+ g6 F7 ?* |: ^8 P2 ~
  24.     ( pxList->uxNumberOfItems )--;
    4 l1 g( @7 z7 {$ t; y

  25. , R: E& ]3 v8 `2 ~
  26.     return pxList->uxNumberOfItems;2 P. q( U* ?' A( C( [6 Y
  27. }
    % q# ^+ u8 e0 {/ f+ s; G; Z
复制代码

+ B' a& M; Y; |5.6 列表遍历
; F  @3 h5 z9 i( t- y* e; Z
  1. #define listGET_OWNER_OF_NEXT_ENTRY( pxTCB, pxList )                                           \
    6 G3 x) n0 F" z& u
  2.     {                                                                                          \; x, f; W, g5 E6 w# f' U
  3.         List_t * const pxConstList = ( pxList );                                               \& ]" }3 \2 Q. F3 H5 A8 I
  4.         /* Increment the index to the next item and return the item, ensuring */               \4 M% @+ e6 m, r9 c) L
  5.         /* we don't return the marker used at the end of the list.  */                         \: f5 p- ?! Z8 i# G9 I/ A$ s3 x
  6.         ( pxConstList )->pxIndex = ( pxConstList )->pxIndex->pxNext;                           \
    6 H7 h. d2 Y3 v0 ^" x7 _
  7.         if( ( void * ) ( pxConstList )->pxIndex == ( void * ) &( ( pxConstList )->xListEnd ) ) \' f5 E1 O+ E, O
  8.         {                                                                                      \/ A3 U( W3 v1 v5 g# Y) S% T, H
  9.             ( pxConstList )->pxIndex = ( pxConstList )->pxIndex->pxNext;                       \
    ; {' A; u0 C. ~# _
  10.         }                                                                                      \8 f1 y# d3 N* a/ y$ v* l0 B
  11.         ( pxTCB ) = ( pxConstList )->pxIndex->pvOwner;                                         \- j: Z1 K- z# x5 q2 i/ m8 y$ M
  12.     }
    ! L% S+ y! {9 w0 z( y, z) ^. g# t

  13. - O, N  ]6 M  K$ |- u3 X6 x* ^2 m
复制代码
  p" O" E1 N3 x8 @

$ Z( I: r5 _3 d% }8 w
赞 收藏 评论0 发布时间:2022-3-26 14:00

举报

0个回答

所属标签

相似技术帖

官网相关资源

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