3.系统全局变量
freertos将任务根据他们的状态分成几个链表。所有就绪状态的任务根据任务优先级加到对应的就绪链表中。系统为每个优先级定义了一个xList。如下:
static xList pxReadyTasksLists[ configMAX_PRIORITIES ]; /*< Prioritised ready tasks. */
此外,所有延时的任务加入到两个延时链表之一。
static xList xDelayedTaskList1;
static xList xDelayedTaskList2;
还定义了两个指向延时链表的指针:
static xList * volatile pxDelayedTaskList;
static xList * volatile pxOverflowDelayedTaskList;
freertos弄出两个延时链表是因为它的延时任务管理的需要。freertos根据任务延时时间的长短按序将任务插入这两个链表之一。在插入前先把任务将要延时的xTicksToDelay数加上系统当前tick数,这样得到了一个任务延时due time(到期时间)的绝对数值。但是有可能这个相加操作会导致溢出,如果溢出则加入到pxOverflowDelayedTaskList指向的那个链表,否则加入pxDelayedTaskList指向的链表。
freertos还定义了个pending链表:
static xList xPendingReadyList;
这个链表用在调度器被lock(就是禁止调度了)的时期,如果一个任务从非就绪状态变为就绪状态,它不直接加到就绪链表中,而是加到这个pending链表中。等调度器重新启动(unlock)的时候再检查这个链表,把里面的任务加到就绪链表中
static volatile xList xTasksWaitingTermination; /*< Tasks that have been deleted - but the their memory not yet freed. */
static volatile unsigned portBASE_TYPE uxTasksDeleted = ( unsigned portBASE_TYPE ) 0;
一个任务被删除的时候加入到xTasksWaitingTermination链表中,uxTasksDeleted跟中系统中有多少任务被删除(即加到xTasksWaitingTermination链表的任务数目).
static xList xSuspendedTaskList; /*< Tasks that are currently suspended. */
这个链表记录着所有被xTaskSuspend挂起的任务,注意这不是那些等待信号量的任务。
static volatile unsigned portBASE_TYPE uxCurrentNumberOfTasks;记录了当前系统任务的数目
static volatile portTickType xTickCount;是自启动以来系统运行的ticks数
static unsigned portBASE_TYPE uxTopUsedPriority;记录当前系统中被使用的最高优先级,
static volatile unsigned portBASE_TYPE uxTopReadyPriority;记录当前系统中处于就绪状态的最高优先级。
static volatile signed portBASE_TYPE xSchedulerRunning ;表示当前调度器是否在运行,也即内核是否启动了
4.任务管理
freertos与ucosii不同,它的任务控制块并不是静态分配的,而是在创建任务的时候动态分配。另外,freertos的优先级是优先级数越大优先级越高,和ucosii正好相反。任务控制块中也没有任务状态的成员变量,这是因为freertos中的任务总是根据他们的状态连入对应的链表,没有必要在任务控制块中维护一个状态。此外freertos对任务的数量没有限制,而且同一个优先级可以有多个任务。
先看任务创建:
/***************************************************************
**参数: pvTaskCode---任务函数名称
** pcName---任务名字,可选
**ucStackDepth---任务堆栈的深度,即大小
** pvParamenters---参数,即传给任务函数的参数,所有的任务函数原型是void task (void *pvParameters)
** uxPriority—任务优先级
** pxCreatedTask—可选,通过它返回被创建任务的tcb
*******************************************************************/
signed portBASE_TYPE xTaskCreate( pdTASK_CODE pvTaskCode, const signed portCHAR * const pcName, unsigned portSHORT usStackDepth, void *pvParameters, unsigned portBASE_TYPE uxPriority, xTaskHandle *pxCreatedTask )
{
signed portBASE_TYPE xReturn;
tskTCB * pxNewTCB;
#if ( configUSE_TRACE_FACILITY == 1 )
static unsigned portBASE_TYPE uxTaskNumber = 0; /*lint !e956 Static is deliberate - this is guarded before use. */
#endif
/*动态分配tcb和任务堆栈*/
pxNewTCB = prvAllocateTCBAndStack( usStackDepth );
/*如果分配成功的话*/
if( pxNewTCB != NULL )
{
portSTACK_TYPE *pxTopOfStack;
/*初始化tcb*/
prvInitialiseTCBVariables( pxNewTCB, pcName, uxPriority );
/*计算堆栈的顶*/
#if portSTACK_GROWTH < 0
{
pxTopOfStack = pxNewTCB->pxStack + ( usStackDepth - 1 );
}
#else
{
pxTopOfStack = pxNewTCB->pxStack;
}
#endif
/* 初始化任务堆栈,并将返回地址保存在tcb中的pxTopOfStack变量*/
pxNewTCB->pxTopOfStack = pxPortInitialiseStack( pxTopOfStack, pvTaskCode, pvParameters );
/*关中断*/
portENTER_CRITICAL();
{ /*更新系统的任务数*/
uxCurrentNumberOfTasks++;
if( uxCurrentNumberOfTasks == ( unsigned portBASE_TYPE ) 1 )
{
/*如果这是系统中第一个任务,则把它设为当前任务*/
pxCurrentTCB = pxNewTCB;
/*如果这是系统中的第一个任务,那也就意味着内核刚准备启动,实际上这第一个任务一定是idle任务,这个时候我们要做一些系统初始化,即初始化那些全局链表*/
prvInitialiseTaskLists();
}
else
{
/* 如果内核还没有运行,则把当前任务设成已经创建的任务中优先级最高的那个,将来内核一旦运行,调度器会马上选择它运行*/
if( xSchedulerRunning == pdFALSE )
{
if( pxCurrentTCB->uxPriority <= uxPriority )
{
pxCurrentTCB = pxNewTCB;
}
}
}
/*我们记录下当前使用的最高优先级,这为了方便任务调度*/
if( pxNewTCB->uxPriority > uxTopUsedPriority )
{
uxTopUsedPriority = pxNewTCB->uxPriority;
}
#if ( configUSE_TRACE_FACILITY == 1 )
{
/* Add a counter into the TCB for tracing only. */
pxNewTCB->uxTCBNumber = uxTaskNumber;
uxTaskNumber++;
}
#endif
/*把新创建的任务加到就绪链表*/
prvAddTaskToReadyQueue( pxNewTCB );
xReturn = pdPASS;
traceTASK_CREATE( pxNewTCB );
}
portEXIT_CRITICAL();
}
/*如果分配内存失败,我们返回错误*/
else
{
xReturn = errCOULD_NOT_ALLOCATE_REQUIRED_MEMORY;
traceTASK_CREATE_FAILED( pxNewTCB );
} |