<?xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" />

 

2009-5-11      

 

也看了一些代码,至此才发现如果不对这个 tskTCB 结构有一定的认识,接下来根本就
无法再走下去了。故在此深刻研究下这个结构,该结构的定义如下:【在 task.c 文件中】其他很多地方都直接 typedef void tskTCB
typedef struct tskTaskControlBlock

{

/*< Points to the location of the last item placed on the tasks stack.  THIS MUST BE THE FIRST MEMBER OF THE STRUCT. */

       volatile portSTACK_TYPE     *pxTopOfStack;    

 

       /*< List item used to place the TCB in ready and blocked queues. */

       xListItem                      xGenericListItem;  

/*< List item used to place the TCB in event lists. */

xListItem                      xEventListItem;            

 

/*< The priority of the task where 0 is the lowest priority. */

       unsigned portBASE_TYPE    uxPriority;                          

 

       /*< Points to the start of the stack. */

portSTACK_TYPE               *pxStack;                    

 

/*< Descriptive name given to the task when created.  Facilitates debugging only. */

       signed portCHAR                 pcTaskName[ configMAX_TASK_NAME_LEN ];

 

       #if ( portSTACK_GROWTH > 0 )

/*< Used for stack overflow checking on architectures where the stack grows up from low memory. */

              portSTACK_TYPE *pxEndOfStack;                  

       #endif

 

       #if ( portCRITICAL_NESTING_IN_TCB == 1 )

              unsigned portBASE_TYPE uxCriticalNesting;

       #endif

 

       #if ( configUSE_TRACE_FACILITY == 1 )

              /*< This is used for tracing the scheduler and making debugging easier only. */

              unsigned portBASE_TYPE    uxTCBNumber;            

       #endif    

             

       #if ( configUSE_MUTEXES == 1 )

              unsigned portBASE_TYPE uxBasePriority;

       #endif

 

       #if ( configUSE_APPLICATION_TASK_TAG == 1 )

              pdTASK_HOOK_CODE pxTaskTag;

       #endif

             

} tskTCB;

一个 task 在创建完 TCP 和初始化栈之后,一般情况下就会被放入 readytask 链表中。上面的结构对我来说,比较难理解的应该是两个 xListItem 元素的变量了,不管如何,先看下这个结构的实现吧:

* Definition of the only type of object that a list can contain.

struct xLIST_ITEM

{

       /*< The value being listed.  In most cases this is used to sort the list in descending order. */

       portTickType xItemValue;                         

 

       /*< Pointer to the next xListItem in the list. */

       volatile struct xLIST_ITEM * pxNext; 

 

       /*< Pointer to the previous xListItem in the list. */

       volatile struct xLIST_ITEM * pxPrevious;

 

/*< Pointer to the object (normally a TCB) that contains the list item.  There is therefore a two way link between the object containing the list item and the list item itself. */

       void * pvOwner;                                             

 

       /*< Pointer to the list in which this list item is placed (if any). */

       void * pvContainer;                                         

};

 

/* For some reason lint wants this as two separate definitions. */

typedef struct xLIST_ITEM xListItem;             
嗯,到这里还算明白了一些,上面的两个 xListItem 变量是用来在某个什么时候作为一个 item 填充队列或链表。好了,问题来了,那具体是在什么时候,什么地方被加入的呢?

 

       还记得 prvInitialiseTaskLists ,前面提到过,但是没有深入讲解。这里就分析一下。

(1)       针对所有优先级,每个优先级创建一个链表,这个链表中存放的是该优先级已 ready task

(2)       一个 xDelayedTaskList1 链表

(3)       一个 xDelayedTaskList2 链表,主要是为了防止前面一个链表中 item 不够用的情况

(4)       一个 xPendingReadyList 链表

(5)       两个可选的链表: xTasksWaitingTermination xSuspendedTaskList

从名字上可以看出这些链表的作用所在。那接下来就有必要说下 xList 这个结构体,其定义如下:

* Definition of the type of queue used by the scheduler.

typedef struct xLIST

{

       volatile unsigned portBASE_TYPE uxNumberOfItems;

 

/*< Used to walk through the list.  Points to the last item returned by a call to pvListGetOwnerOfNextEntry (). */

       volatile xListItem * pxIndex;               

 

/*< List item that contains the maximum possible item value meaning it is always at the end of the list and is therefore used as a marker. */

       volatile xMiniListItem xListEnd;          

} xList;

这里说明一下,通过对各个使用 xList 的函数分析,该结构中的 xListEnd 是个环形链表。

struct xMINI_LIST_ITEM

{

       portTickType xItemValue;

       volatile struct xLIST_ITEM *pxNext;

       volatile struct xLIST_ITEM *pxPrevious;

};

这样就可以理解 xList 结构中的 pxIndex 的使用了,具体可参考 vListInsertEnd 的实现。同时 vListInitialise 函数的实现就可想而知了,以及 vListInsert vListRemove 都一块解决掉了。

 

嗯,是的,至此 freertos 中的三个重要的文件: queue.c list.c task.c ,我们已经解决了一个了。