声明:该篇文转载自:http://bluefish.blog.51cto.com/214870/158404
tskTCB结构的定义这里就不再给出来了,需要注意的是其中uxBasePriority元素,它用于解决优先级反转,freertos采用优先级继承的办法解决这个问题,在继承时,将任务原先的优先级保存在这个成员中,将来再从这里恢复任务的优先级。
两个延时链表的正解
:
freertos
弄出两个延时链表是因为它的延时任务管理的需要。
freertos
根据任务延时时间的长短按序将任务插入这两个链表之一。在插入前先把任务将要延时的
xTicksToDelay
数加上系统当前
tick
数,这样得到了一个任务延时
due time
(到期时间)的绝对数值。但是有可能这个相加操作会导致溢出,如果溢出则加入到
pxOverflowDelayedTaskList
指向的那个链表,否则加入
pxDelayedTaskList
指向的链表。
xPendingReadyList;
这个链表用在调度器被lock
(就是禁止调度了)的时期,如果一个任务从非就绪状态变为就绪状态,它不直接加到就绪链表中,而是加到这个pending链表中。等调度器重新启动(unlock)的时候再检查这个链表,把里面的任务加到就绪链表中。
任务管理:
freertos
与
ucosii
不同,它的任务控制块并不是静态分配的,而是在创建任务的时候动态分配。另外,
freertos
的优先级是优先级数越大优先级越高,和
ucosii
正好相反。任务控制块中也没有任务状态的成员变量,这是因为
freertos
中的任务总是根据他们的状态连入对应的链表,没有必要在任务控制块中维护一个状态。此外
freertos
对任务的数量没有限制,而且同一个优先级可以有多个任务。
任务删除:
任务创建过程前面讲过了,这里就直接看任务删除的工程。
freertos
的任务删除分两步完成,第一步在vTaskDelete
中完成,FreeRTOS先把要删除的任务从就绪任务链表和事件等待链表中删除,然后把此任务添加到任务删除链表(即那个xTasksWaitingTermination),若删除的任务是当前运行任务,系统就执行任务调度函数.第2步则是在idle任务中完成,idle任务运行时,检查xTasksWaitingTermination链表,如果有任务在这个表上,释放该任务占用的内存空间,并把该任务从任务删除链表中删除。
/****************************************************************
**
参数:pxTaskToDelete
是一个指向被删除任务的句柄,这里其实就是等价于任务控制块
**
如果这个句柄==NULL
,则表示要删除当前任务
*******************************************************************/
void vTaskDelete( xTaskHandle pxTaskToDelete )
{
tskTCB *pxTCB;
taskENTER_CRITICAL();
{
/*
如果删除的是当前任务,则删除完成后需要进行调度*/
if( pxTaskToDelete == pxCurrentTCB )
{
pxTaskToDelete = NULL;
}
/*
通过传进来的任务句柄得到对应的tcb*/
pxTCB = prvGetTCBFromHandle( pxTaskToDelete );
traceTASK_DELETE( pxTCB );
/*
把任务从就绪链表或者延时链表或者挂起链表中删除*/
vListRemove( &( pxTCB->xGenericListItem ) );
/*
判断任务是否在等待事件(semaphore
消息队列等) */
if( pxTCB->xEventListItem.pvContainer )
{//
如果是,则把它从事件等待链表中删除
vListRemove( &( pxTCB->xEventListItem ) );
}
//
插入等待删除链表
vListInsertEnd( ( xList * ) &xTasksWaitingTermination, &( pxTCB->xGenericListItem ) );
//
增加uxTasksDeleted
计数
++uxTasksDeleted;
}
taskEXIT_CRITICAL();
/*
如果调度器已经运行,并且删除的是当前任务,则调度*/
if( xSchedulerRunning != pdFALSE )
{
if( ( void * ) pxTaskToDelete == NULL )
{
taskYIELD();
}
}
}
再看空闲任务做的第2
步工作:
static portTASK_FUNCTION( prvIdleTask, pvParameters )
{
/* Stop warnings. */
( void ) pvParameters;
for( ;; )
{
/* See if any tasks have been deleted. */
prvCheckTasksWaitingTermination();
…………………………….
÷
* The portTASK_FUNCTION() macro is used to allow port/compiler specific
* language extensions. The equivalent prototype for this function is:
* void prvIdleTask( void *pvParameters );
这里prvCheckTasksWaitingTermination()
就是干这第2步的工作:每次调用它删除一个任务
static void prvCheckTasksWaitingTermination( void )
{
#if ( INCLUDE_vTaskDelete == 1 )
{
portBASE_TYPE xListIsEmpty;
/* ucTasksDeleted is used to prevent vTaskSuspendAll() being called
too often in the idle task. */
if( uxTasksDeleted > ( unsigned portBASE_TYPE ) 0 )
{
//
禁止调度
vTaskSuspendAll();
//打开调度
xListIsEmpty = listLIST_IS_EMPTY( &xTasksWaitingTermination );
xTaskResumeAll();
if( !xListIsEmpty )
{
tskTCB *pxTCB;
//
关中断
portENTER_CRITICAL();
{
pxTCB = ( tskTCB * ) listGET_OWNER_OF_HEAD_ENTRY( ( ( xList * ) &xTasksWaitingTermination ) );
vListRemove( &( pxTCB->xGenericListItem ) );
--uxCurrentNumberOfTasks;
--uxTasksDeleted;
}
portEXIT_CRITICAL();
//
释放内存,删除tcb
prvDeleteTCB( pxTCB );
}
}
}
#endif
}
本文出自 “bluefish” 博客,请务必保留此出处http://bluefish.blog.51cto.com/214870/158404