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
$ ^* 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- typedef struct xLIST% K1 V- A3 w+ I. E# h
- {
( |1 _; S& S7 T) _ - listFIRST_LIST_INTEGRITY_CHECK_VALUE /*用于检测列表项数据是否完整*/: u6 B6 j3 A+ e1 |
- configLIST_VOLATILE UBaseType_t uxNumberOfItems;
Q+ C% A1 v" F% w: m. @7 y' z3 h; V - ListItem_t * configLIST_VOLATILE pxIndex; /*用于遍历列表*/0 |4 F: ~0 B0 x& o$ f c7 f
- MiniListItem_t xListEnd; /*列表项*/
0 y% F* h4 _1 }) X) ] - listSECOND_LIST_INTEGRITY_CHECK_VALUE /*用于检测列表项数据是否完整*/% k* i! d7 A# c0 g/ @' d C% {
- }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" ^! }- struct xLIST_ITEM W8 L: i/ i# \9 s3 O$ t9 ^+ I
- {
$ t; U2 K8 @0 e/ m - listFIRST_LIST_ITEM_INTEGRITY_CHECK_VALUE /*用于检测列表项数据是否完整*/
5 H. E0 F: {3 U; Q y# Y - configLIST_VOLATILETickType_t xItemValue; /*列表项值*/
9 Z" F3 K1 A3 K* i2 o5 e - struct xLIST_ITEM * configLIST_VOLATILE pxNext; /*指向列表中下一个列表项*/9 I8 Z- _$ N. A
- struct xLIST_ITEM * configLIST_VOLATILE pxPrevious; /*指向列表中上一个列表项*/
- N0 c0 |% n9 k. U+ K n( J - void * pvOwner; /*指向一个任务TCB*/
: X$ l+ y: @% Z& c! R( `" E8 Q - void * configLIST_VOLATILE pvContainer; /*指向包含该列表项的列表 */3 x/ q. a% ~% h
- listSECOND_LIST_ITEM_INTEGRITY_CHECK_VALUE /*用于检测列表项数据是否完整*/
* q3 ~! x9 N% v+ T; n1 q c - };, Y7 H9 x! Y. n9 d
- typedef struct xLIST_ITEM ListItem_t;
复制代码 0 j5 n1 J7 E* ]! Z$ I* O/ W" O* p
* 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- struct xMINI_LIST_ITEM
, U0 v/ S( u) p4 S: L/ q3 f. S - {
+ e2 A Z, }+ O- _ - listFIRST_LIST_ITEM_INTEGRITY_CHECK_VALUE /*用于检测列表项数据是否完整*/; d% R: K1 j+ W7 m9 G) H# f
- configLIST_VOLATILE TickType_t xItemValue;) n. F0 {8 L, j
- struct xLIST_ITEM * configLIST_VOLATILE pxNext;
; e( e) H! ]: J" F7 z/ E, ~ - struct xLIST_ITEM * configLIST_VOLATILE pxPrevious;. |$ r, t5 A/ w
- };
1 X+ Z: H: z/ x% t/ x, v - typedef struct xMINI_LIST_ITEM MiniListItem_t;
复制代码
- }9 m) [( s! D
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
- /*
% l7 t3 \1 j) I1 O - * Access macro to set the owner of a list item. The owner of a list item
1 q7 @9 k$ m! Q - * is the object (usually a TCB) that contains the list item.
* f& v% W" F7 V: c& p) E! s8 Q - *" s# _# [8 G" L# U1 M% B% P
- * \page listSET_LIST_ITEM_OWNER listSET_LIST_ITEM_OWNER
" o; f+ b- M* W3 T - * \ingroup LinkedList4 t2 j) U! W% V
- */. Y5 w, X5 d! j# m( E* k0 M+ @
- #define listSET_LIST_ITEM_OWNER( pxListItem, pxOwner ) ( ( pxListItem )->pvOwner = ( void * ) ( pxOwner ) )1 S) K& @! X! X2 Y ? [3 J
- 5 \9 |* N' v! B
- /*
5 D5 z' z9 k" J1 C - * Access macro to get the owner of a list item. The owner of a list item
. U& H9 Q" o. x2 `1 y% H - * is the object (usually a TCB) that contains the list item.' J$ G' R8 Z% _& \* N. u6 ]
- *
( h6 f3 @3 E" M - * \page listGET_LIST_ITEM_OWNER listSET_LIST_ITEM_OWNER8 u) s# K! y( P, H
- * \ingroup LinkedList
: {- f5 U9 W' {/ r& ~2 Y - */
' \# s( f- R" c* ` - #define listGET_LIST_ITEM_OWNER( pxListItem ) ( ( pxListItem )->pvOwner )8 y4 c& o" m/ i6 R3 o# k8 T9 ^
- 1 _ q3 H- W( n* W# ~
- /*
5 E2 Z( X4 J2 h# t5 a - * Access macro to set the value of the list item. In most cases the value is
: c8 ]. g3 p. u3 d - * used to sort the list in descending order.
. z. o9 H4 R* j1 k - *+ }, C W& k- F" {# d" U& t
- * \page listSET_LIST_ITEM_VALUE listSET_LIST_ITEM_VALUE2 Q- y9 ~& s4 D0 {9 |9 `- H* L. k2 \
- * \ingroup LinkedList
/ p9 O4 H: p9 c$ q l - */% Y( r! @2 l9 Q8 O: _* g5 t2 l
- #define listSET_LIST_ITEM_VALUE( pxListItem, xValue ) ( ( pxListItem )->xItemValue = ( xValue ) )# \( m1 Y" \) c1 a
+ }3 C9 y/ ]6 N. d- /*2 B) U5 M* m# ?7 v4 {
- * Access macro to retrieve the value of the list item. The value can3 U& B9 c5 P4 k6 a+ Q$ X
- * represent anything - for example the priority of a task, or the time at
' b- {- ?- R3 `/ X @ - * which a task should be unblocked.3 y9 ~3 B% {: }' N: w( Y' C
- *
$ Y# `$ g% S6 L7 Z& H0 N - * \page listGET_LIST_ITEM_VALUE listGET_LIST_ITEM_VALUE" C; I! Y/ o' X4 M5 c, H( g
- * \ingroup LinkedList! w* c- X1 y3 W5 H# u
- */
+ N% d6 s5 _; L4 o/ }- J; B3 A - #define listGET_LIST_ITEM_VALUE( pxListItem ) ( ( pxListItem )->xItemValue )
# m9 Y7 A8 g) K& p7 G - ' N5 n' \3 K! A3 i& K& @
- /*. G9 V# S4 _" i$ h: I
- * 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 - * list.& O% w0 ?/ M; o7 {% s6 C( B6 T) d
- *
6 h( P, {: i# w$ |0 ^4 v- f; `0 K! Z! a - * \page listGET_LIST_ITEM_VALUE listGET_LIST_ITEM_VALUE& T5 S0 C) A7 p
- * \ingroup LinkedList
% l) }, w- V( T: m6 q5 W - */
z6 A+ Z4 D' G( O8 n' ~ - #define listGET_ITEM_VALUE_OF_HEAD_ENTRY( pxList ) ( ( ( pxList )->xListEnd ).pxNext->xItemValue )
$ H' D4 j3 c3 b- ~$ G4 R1 c2 o
8 Q# G2 a2 ]4 s4 J6 d- /*
9 y2 D6 \3 Z0 y$ \" j - * Return the list item at the head of the list.: e/ Y; d; ^9 b) a. e
- *
7 a( R: r1 s1 z9 P5 t - * \page listGET_HEAD_ENTRY listGET_HEAD_ENTRY
) y, @) A$ d) e; _+ `8 f, t - * \ingroup LinkedList
% `0 U8 l/ O: b& Y# N - */
: i. U8 l; g- ^: N! g+ z: R6 [" D - #define listGET_HEAD_ENTRY( pxList ) ( ( ( pxList )->xListEnd ).pxNext )
: L' s) p7 }2 S r
/ q/ a% m1 H) J8 r$ H- /*
9 t. B+ Y( w# x9 ^5 n* ~; N. O! b - * Return the next list item.
( J, B" R( m% ?% f5 v# T L) r5 ? - *9 v7 E7 A3 p1 l" }& t7 W
- * \page listGET_NEXT listGET_NEXT( w: h" Q- n+ Z
- * \ingroup LinkedList
! x8 ] V0 [7 X: U - */. Q9 w% M; E" \# s' W6 X' Q
- #define listGET_NEXT( pxListItem ) ( ( pxListItem )->pxNext )
4 L; e) w' ^) `6 w: C
3 X% d3 X1 A1 a1 ?4 ]/ a% [" c% g- /*, o+ J, H' J6 A* M
- * Return the list item that marks the end of the list
1 E3 b( A0 ~" h: V* d V - *
, {7 T' Y3 k- P( ]' l - * \page listGET_END_MARKER listGET_END_MARKER
; {0 {2 M5 o" R5 I6 q, o$ b; k - * \ingroup LinkedList" ?; g8 ]) a5 { N3 ?) ?# L
- */
/ [+ @+ x* e0 T- i0 b* e - #define listGET_END_MARKER( pxList ) ( ( ListItem_t const * ) ( &( ( pxList )->xListEnd ) ) )
& k9 r: W2 j: Y9 ]! T h. W
3 y, [- M5 [" g9 q- /*
; c% v2 j- a; K+ E. u6 J - * Access macro to determine if a list contains any items. The macro will" w$ {+ y e0 B, R
- * only have the value true if the list is empty.
( X" N0 P/ ^7 e" G9 S& v - *' S! ^+ h: I- J$ w/ @* G1 m1 ~) [
- * \page listLIST_IS_EMPTY listLIST_IS_EMPTY
) ~ k; D8 ^% h; [ r7 t - * \ingroup LinkedList, [! Y: Z/ v1 Z' B9 q) V
- */
, y3 l4 i3 K( B4 p1 k - #define listLIST_IS_EMPTY( pxList ) ( ( ( pxList )->uxNumberOfItems == ( UBaseType_t ) 0 ) ? pdTRUE : pdFALSE )
; E- C4 s4 i( P, u; H' I
0 |6 o4 g) G- h2 E: Z" ]$ r% V% o" B- /*5 b- y% F2 j0 ~% \
- * Access macro to return the number of items in the list.; d" w0 k) ^% m0 \/ d$ p
- */" c, A" u$ S& u. K, c
- #define listCURRENT_LIST_LENGTH( pxList ) ( ( pxList )->uxNumberOfItems )
! c* i2 T+ t8 Z2 V! a7 s! A L
9 W( c9 K. U8 ^7 `# y3 o( N- /*
$ u3 k: `% f2 n e - * Access function to obtain the owner of the next entry in a list.6 ?7 L f+ o2 G! q' f2 D" i4 t
- *8 n+ L: A! y" @1 _, ?* ]4 i9 V
- * The list member pxIndex is used to walk through a list. Calling4 w: H |' A; e) \2 B
- * listGET_OWNER_OF_NEXT_ENTRY increments pxIndex to the next item in the list
5 p; ^! E Q! ?; |4 _9 f - * and returns that entry's pxOwner parameter. Using multiple calls to this
& s. V, E* A9 q; v. {! w - * function it is therefore possible to move through every item contained in
9 w# c: P# k; o: t - * a list.
& `( }: F% @1 Y+ R6 | - *
) |, p8 Z7 K2 ~- B$ _ - * The pxOwner parameter of a list item is a pointer to the object that owns
# `( w+ c5 O+ R; K% O; m - * the list item. In the scheduler this is normally a task control block.
* y; M6 _4 a4 g: r2 E( H# l( {) ] - * The pxOwner parameter effectively creates a two way link between the list
7 T0 F5 [6 L/ u8 w - * item and its owner.
# x9 G; o' D+ a) l2 \8 p - *% u& M {$ B6 Y* E
- * @param pxTCB pxTCB is set to the address of the owner of the next list item.( M7 L$ i7 F. t% a
- * @param pxList The list from which the next item owner is to be returned.
- \$ d- M, P/ o* }( Z2 L - *" I/ N% F. o: Y' A' @$ `
- * \page listGET_OWNER_OF_NEXT_ENTRY listGET_OWNER_OF_NEXT_ENTRY
- V. p0 |8 d; k: G$ R - * \ingroup LinkedList
" ]" g6 f4 W W9 `2 ] - */' ?6 B! t9 h' Q$ d [, ^* C
- #define listGET_OWNER_OF_NEXT_ENTRY( pxTCB, pxList ) \
5 Y9 G, c" K, {+ W, L: X+ i+ z - { \
: X6 X- _3 x% \8 a9 s( T - List_t * const pxConstList = ( pxList ); \( e7 |- @1 t$ W
- /* Increment the index to the next item and return the item, ensuring */ \0 W9 h3 B! b* T$ Z; r8 O
- /* we don't return the marker used at the end of the list. */ \
" v+ J. g8 \( j/ ~1 f! m% h6 i* t - ( pxConstList )->pxIndex = ( pxConstList )->pxIndex->pxNext; \$ A2 s; L' }$ h, E T2 ]& M: m+ I
- if( ( void * ) ( pxConstList )->pxIndex == ( void * ) &( ( pxConstList )->xListEnd ) ) \, H9 j) t) Q$ Q8 K$ q
- { \8 X" S: t/ T- W
- ( pxConstList )->pxIndex = ( pxConstList )->pxIndex->pxNext; \
' X+ [1 n! x- E' O) k' q - } \% J( W9 L0 x/ i! d# j
- ( pxTCB ) = ( pxConstList )->pxIndex->pvOwner; \
4 [5 C; {3 j: p - }- M, d( q! |6 v0 `' A% z" ]# o
- q( X. d m" }8 t9 \* D( W- _/ j
. g. i' q9 C1 z3 G( o/ x- /*: K7 u9 x9 a0 q. q3 T6 j, m
- * Access function to obtain the owner of the first entry in a list. Lists
t1 A( {) B' j- _3 c$ N - * are normally sorted in ascending item value order.; F9 ~: |8 I$ `5 l- l6 }: U. d1 G
- *
5 M4 o8 a8 W) ]: P# } - * This function returns the pxOwner member of the first item in the list.& B2 j# C/ n8 l& r
- * The pxOwner parameter of a list item is a pointer to the object that owns3 N; u1 ~/ d1 b
- * the list item. In the scheduler this is normally a task control block., c" S8 ~2 |1 K1 g
- * The pxOwner parameter effectively creates a two way link between the list
L. i3 P2 W p - * item and its owner.3 Q- y1 p0 J6 u! ?; j
- *
, z: o( F, i& }& R# L$ E - * @param pxList The list from which the owner of the head item is to be7 H, X* u; R6 P0 J& O6 B7 V
- * returned.
3 i( q) m1 h6 ~7 L$ ]6 L - *# w- I& W9 ?3 O2 |7 P' f1 p
- * \page listGET_OWNER_OF_HEAD_ENTRY listGET_OWNER_OF_HEAD_ENTRY
: r2 L( Y* u7 f9 m% Z# c x" S- t, `: l - * \ingroup LinkedList
+ u! l0 V& W# R w' U - */2 }% r' b; o- W( U) F0 r' Z
- #define listGET_OWNER_OF_HEAD_ENTRY( pxList ) ( ( &( ( pxList )->xListEnd ) )->pxNext->pvOwner )
/ O+ U. [. @3 Z. J" G - ) k9 @& ]6 X, x" I" R0 R5 ]6 i
- /*
. q. E5 e# Y% [; Y9 Q - * Check to see if a list item is within a list. The list item maintains a
* V& q* c7 Z% ]' | - * "container" pointer that points to the list it is in. All this macro does
/ N8 _0 Q, O! x1 p# `7 G" y - * is check to see if the container and the list match. r; ~! ]- ?3 x+ m1 E! ]5 w
- *
8 b0 Z0 E* N9 a5 s* m/ p - * @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 - * @param pxListItem The list item we want to know if is in the list.; `0 i; t" M" n9 X/ ^
- * @return pdTRUE if the list item is in the list, otherwise pdFALSE.
% d& L5 X/ R: u - */2 M) |3 p, _ e7 A, e9 n" i0 _
- #define listIS_CONTAINED_WITHIN( pxList, pxListItem ) ( ( ( pxListItem )->pxContainer == ( pxList ) ) ? ( pdTRUE ) : ( pdFALSE ) )
! D0 |( f/ k" j! K% C
5 W$ e$ f s0 `: i. t" [& D4 a8 }- /*
- M2 l8 B9 G" H0 K - * Return the list a list item is contained within (referenced from).# i* ^7 }- B, _' e, p. d
- *
/ M- j' [3 `6 i9 }, m' S - * @param pxListItem The list item being queried.
1 F7 ?8 I7 s. D% g) a/ b) [ - * @return A pointer to the List_t object that references the pxListItem7 Y5 X% D+ Y" N1 p' x7 K
- */
6 d& M7 i. z- z4 W& f4 X" D - #define listLIST_ITEM_CONTAINER( pxListItem ) ( ( pxListItem )->pxContainer )
4 b) P6 D% R4 \. {& Y4 O [3 _0 | - 7 ?6 t1 Z3 i( x9 G7 e) K
- /*7 f% m. v d* @
- * This provides a crude means of knowing if a list has been initialised, as
" s; ^0 D* }0 B7 `+ C; p - * pxList->xListEnd.xItemValue is set to portMAX_DELAY by the vListInitialise()
2 p; x0 A# z& _ - * function.) m4 z* v1 V" H+ i
- */
& K$ _! e" y a - #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- void vListInitialise( List_t * const pxList ). u# v( @8 \0 d4 i3 b( D
- {
, b3 }% D- W* F: n# z2 a( E - /*列表索引指向列表项*// `0 f( h$ H. D2 H- a
- pxList->pxIndex = ( ListItem_t * )&( pxList->xListEnd );
0 D$ R! d7 f! p3 ^- ` - /* 设置为最大可能值 *// f2 P9 k! y/ h6 C
- pxList->xListEnd.xItemValue =portMAX_DELAY;
1 S) @) C* M/ m - 0 l D* J7 e8 I1 _) Q8 D
- /* 列表项xListEnd的pxNext和pxPrevious指针指向了它自己 */5 u4 Y W9 a, ? [
- pxList->xListEnd.pxNext = (ListItem_t * ) &( pxList->xListEnd );
; A7 @, r1 c5 x6 J5 j& P - pxList->xListEnd.pxPrevious= ( ListItem_t * ) &( pxList->xListEnd );
$ l8 u9 s* i) a - pxList->uxNumberOfItems = ( UBaseType_t) 0U;: S9 o0 t9 O$ Y1 T8 H
- : {6 W+ B. ]4 O- m* r5 h
- /* 设置为已知值,用于检测列表数据是否完整*/
* |& d& `$ h, U$ i' d z& q% n1 r - listSET_LIST_INTEGRITY_CHECK_1_VALUE(pxList );
+ P6 \7 {. W8 C* `0 ~! ` - listSET_LIST_INTEGRITY_CHECK_2_VALUE(pxList );
! Q0 y/ ~/ ~: n3 w' q( c - }
复制代码 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
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
- void vListInitialiseItem( ListItem_t * const pxItem )( I8 ?% e0 \) g( V. U
- {
0 a0 Q, l- j$ E: Y7 C" w - pxItem->pvContainer = NULL;3 Z' p3 ^2 T" e1 |! o" G$ |' m! \4 g
- 8 p6 R* P& b- s& c$ X
- /*设置为已知值,用于检测列表项数据是否完整*/4 G8 T6 ~8 \0 j% `
- listSET_FIRST_LIST_ITEM_INTEGRITY_CHECK_VALUE(pxItem );" K9 M6 t3 g8 h& h
- listSET_SECOND_LIST_ITEM_INTEGRITY_CHECK_VALUE(pxItem );
) V9 @7 K5 E/ M% B, ~; }! g) G - }
复制代码 " 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
- void vListInsert( List_t * const pxList,
2 {5 x- O" f# r; I, X - ListItem_t * const pxNewListItem )2 x9 h2 U: x! @) Z% l' t8 \! ^$ x
- {
5 A2 }5 U" z d2 M; f3 j - ListItem_t * pxIterator;
4 Q& f5 M7 Q; x, o - const TickType_t xValueOfInsertion = pxNewListItem->xItemValue;
) |8 D9 A8 g2 v! o, L - ' m. @8 }9 c. A" n1 N* D# H9 p
- /* 检查列表和列表项数据的完整性,仅当configASSERT()定义时有效。*/
) D) _' L/ A' ]9 B - /* Only effective when configASSERT() is also defined, these tests may catch3 N3 H% w; n2 D' P" A% K
- * the list data structures being overwritten in memory. They will not catch+ A9 Y9 X8 }! ?" V b
- * data errors caused by incorrect configuration or use of FreeRTOS. */
, v- X8 s8 |. U4 _7 v - listTEST_LIST_INTEGRITY( pxList ); H7 S& u4 }; `- {$ j% y# N
- listTEST_LIST_ITEM_INTEGRITY( pxNewListItem );
: A! ~* q/ r" e3 u - 5 }' K2 O* ^+ O& t- y- e: L
- /* Insert the new list item into the list, sorted in xItemValue order.
& E/ d0 S# @) A( {" z( B7 |4 s+ T - *; c5 t) z7 ~& G
- * If the list already contains a list item with the same item value then the
" C5 X* J, c/ T; t3 {% s8 Y - * new list item should be placed after it. This ensures that TCBs which are, Q M# l9 H/ i! q" r
- * stored in ready lists (all of which have the same xItemValue value) get a
# D3 h& N2 A# j& K+ I8 d7 [ - * share of the CPU. However, if the xItemValue is the same as the back marker% G6 n+ V9 ^" {% G3 W) H- v
- * the iteration loop below will not end. Therefore the value is checked
& J& O2 \5 L4 q8 K1 Z" D0 C4 F" x, s - * first, and the algorithm slightly modified if necessary. */9 Y6 Z- h: M) Y4 \$ k7 V! e2 m" A/ \
- /*将新的列表项插入到列表,根据xItemValue的值升序插入列表。*/
+ k! H& w1 V7 ~/ K: g' _6 D - if( xValueOfInsertion == portMAX_DELAY ) C" O1 A5 O; b" D7 T* Y
- {
, I4 G. |+ \, ?- u" T - pxIterator = pxList->xListEnd.pxPrevious;0 \) |) l; E2 s! I1 @
- }8 {' t8 }6 K. C2 X1 O
- else, O5 b" |* i6 A, z4 t# O) B+ q
- {5 \' a* ]+ V. @! ] m- ?! h
- /* *** NOTE ***********************************************************
% U5 Q& m( S- I4 P: }% _8 `! B7 r- t - * If you find your application is crashing here then likely causes are6 |- r1 j z9 \8 y; t
- * listed below. In addition see for8 p* p. N ^- l/ D2 Y
- * more tips, and ensure configASSERT() is defined!
* |8 R! P1 K- M& b6 }: A - *
+ \) G9 T1 @% {$ M- ~6 U - *
, J* o# U7 Y' J/ U - * 1) Stack overflow -
% Q# d7 }3 y. \ - * see
% R: ~( j+ i, j+ i! J% Q' C) x - * 2) Incorrect interrupt priority assignment, especially on Cortex-M
9 \! T% u8 O& [3 y - * parts where numerically high priority values denote low actual- y5 n0 D. ~6 T( S2 b
- * interrupt priorities, which can seem counter intuitive. See
7 w) q1 ?0 y' b$ J- V/ e$ P - * and the definition: f! {3 K4 ? u% J; z6 g1 M( Y
- * of configMAX_SYSCALL_INTERRUPT_PRIORITY on
" h( A, c" P3 t4 g! X - * # @( l2 `, g- \
- * 3) Calling an API function from within a critical section or when" ?$ G S; w7 Q; q
- * the scheduler is suspended, or calling an API function that does
- ^, k# w5 R, I4 w# ` - * not end in "FromISR" from an interrupt.8 L# z1 Y! h3 b
- * 4) Using a queue or semaphore before it has been initialised or
: A: T0 P, Q; w! ]0 c* P! l i - * before the scheduler has been started (are interrupts firing
+ e/ w: E M5 |% }+ G, J! `: ~ - * before vTaskStartScheduler() has been called?).0 t0 {7 r* f- i( N
- **********************************************************************/; b# r Q( I, l0 j* Y
- s/ l' M& h3 g* @
- //xListEnd表示列表的末尾
4 w; Z) N* u3 f7 |' [0 {4 [ - 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
- {+ p# a* U" ]2 N4 T
- /* There is nothing to do here, just iterating to the wanted: D; a0 T) I3 n2 D4 B/ }0 m
- * insertion position. */5 v! p; m1 T/ I9 n! x+ j* g1 q- H
- }
6 W3 J" P6 P: s) b, w% k3 M - }! E* a: q( w; C1 a. d$ p
! E- C, |2 G) T: g- pxNewListItem->pxNext = pxIterator->pxNext;* P. W# u/ [0 a V5 I
- pxNewListItem->pxNext->pxPrevious = pxNewListItem;; U& ]: t- w1 U) d
- pxNewListItem->pxPrevious = pxIterator;: v6 ^( W* c6 S! i6 t" \! T
- pxIterator->pxNext = pxNewListItem;
9 c. N) a( O2 @8 _1 ~1 G - ) u t; s$ B$ K Z. K
- /* Remember which list the item is in. This allows fast removal of the
$ K2 L* T% p4 Q6 B - * item later. */
9 r g2 T) y! r) N( x7 p7 I - pxNewListItem->pxContainer = pxList;
7 a- p, o+ o) d* Y4 E' u( l
% D6 _2 I. ~0 w& `0 j- ( pxList->uxNumberOfItems )++;
1 l | k5 O+ h, Y" k0 M2 ~4 Y1 V - }
复制代码 $ 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- void vListInsertEnd( List_t * const pxList, ListItem_t * const pxNewListItem )# [: B V2 S% k
- {
/ P$ {# _/ b1 o% P* ] - ListItem_t* const pxIndex = pxList->pxIndex;
% i+ e, l0 y; m3 `2 J5 n - 1 i% ~- a2 {0 m1 n6 i6 r
- /*检查列表和列表项数据的完整性,仅当configASSERT()定义时有效。*/& o7 _; ~+ w. c4 Z. d. @0 O& Q, B7 X
- listTEST_LIST_INTEGRITY( pxList );
& j ^6 z0 ]8 ^' g4 g+ p1 o - listTEST_LIST_ITEM_INTEGRITY(pxNewListItem );
8 Z' c# \$ J: t' C7 z+ K& @0 q
6 q1 j6 A8 l- y1 O- T5 E- [' u- /*向列表中插入新的列表项*/3 K4 k6 c/ Z- a( K: l+ y6 c
- pxNewListItem->pxNext = pxIndex;. W |2 z/ r5 C7 X( q, v P
- pxNewListItem->pxPrevious =pxIndex->pxPrevious;- |4 ]7 p, y) Q+ Y
1 z! Z4 f; V, F4 b( Q- mtCOVERAGE_TEST_DELAY();) K) z# H, K1 }- h
; C2 I- K4 [0 ~0 Q; k: E7 O- pxIndex->pxPrevious->pxNext =pxNewListItem;2 s) [; R, y* w1 v$ Y- F1 X( I
- pxIndex->pxPrevious = pxNewListItem;! O }+ n G- q# k8 |7 J8 f) X
9 X6 B2 @$ ?( G7 D1 t, `- pxNewListItem->pvContainer = ( void* ) pxList;
8 [6 E" F2 m' [6 z5 ~ - 3 R. m/ u7 O% v2 q
- ( pxList->uxNumberOfItems )++;! W- `0 f# p, ~0 M9 P
- }
复制代码
; 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* ?- UBaseType_t uxListRemove( ListItem_t * const pxItemToRemove )0 Z$ N( G. j ?! ^. Y- q+ q
- {3 N4 B) x: y& ~
- /* The list item knows which list it is in. Obtain the list from the list! [' d1 M3 O" Q7 d$ S
- * item. */
( g( d" X0 I0 Q: h: l! k - List_t * const pxList = pxItemToRemove->pxContainer;
6 M* K8 D/ z+ O - " Q! ?& N* l6 G" u
- pxItemToRemove->pxNext->pxPrevious = pxItemToRemove->pxPrevious;' |. A% v. n2 f x- h% ?
- pxItemToRemove->pxPrevious->pxNext = pxItemToRemove->pxNext;# C7 h i F- Y& V
$ Y+ k# r# Y7 C7 _9 J- /* Only used during decision coverage testing. */
( c1 Z' v: E' Y' F - mtCOVERAGE_TEST_DELAY();
. D+ c+ P4 T6 f! K7 T2 s
# f. Y5 L8 `$ Q" f9 W% d! t; Y& G- /* Make sure the index is left pointing to a valid item. */2 C2 K9 I" m9 b6 _; b) B; h
- if( pxList->pxIndex == pxItemToRemove )
* w" P& r: q/ m& T: d - {
# i: V+ e+ _' D. f* b! c - pxList->pxIndex = pxItemToRemove->pxPrevious;
8 E `( a9 D+ @, e% L+ c4 Z, U - }
1 l* K- ~+ U! e4 L - else
, _* F/ x2 l \, w$ k - {, j5 G v3 `$ ^8 a% m7 k
- mtCOVERAGE_TEST_MARKER(); M, |) i0 g# N# c! ~
- }1 m% n3 G1 [" ~+ y: h- }
! r* F% @9 L4 R+ I4 U2 ]- r- pxItemToRemove->pxContainer = NULL;
* ?) T3 y u2 R: g - ( pxList->uxNumberOfItems )--;
0 c2 c g. p6 f# f& s
5 o' |) t0 S- s9 `5 J* n0 [ r- return pxList->uxNumberOfItems;9 \/ J* G! `. ^! n) V1 q/ ]8 X
- }
复制代码 4 \4 G1 T. D; X, r9 K& j1 b
5.6 列表遍历( k" T; @$ d& Y. E6 ^
- #define listGET_OWNER_OF_NEXT_ENTRY( pxTCB, pxList ) \! e) u+ h: d0 H( G3 y
- { \. f3 }1 d: p3 @: V
- List_t * const pxConstList = ( pxList ); \% k* F; F% m, R* x' h
- /* Increment the index to the next item and return the item, ensuring */ \
8 e" \( y4 @0 j+ [6 O - /* we don't return the marker used at the end of the list. */ \! Y! l, U2 a1 o: X
- ( pxConstList )->pxIndex = ( pxConstList )->pxIndex->pxNext; \
% ~! E4 k, f2 _5 j7 K. U' ^2 C# K# T% ~ - if( ( void * ) ( pxConstList )->pxIndex == ( void * ) &( ( pxConstList )->xListEnd ) ) \
6 N9 y. h3 D9 @: P: z# u0 j - { \
) g" R2 Y7 E: a5 Q - ( pxConstList )->pxIndex = ( pxConstList )->pxIndex->pxNext; \ U) N7 u6 ~! I7 h* q+ i4 j
- } \
& F) J% y/ m6 T4 i6 R% q - ( pxTCB ) = ( pxConstList )->pxIndex->pvOwner; \. N# L2 ]1 q9 B, ]' @1 ~
- }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( _ |