if( xReturn == pdPASS ) {
if( ( void * ) pxCreatedTask != NULL )
{
/*将新创建任务的tcb返回给调用者
*pxCreatedTask = ( xTaskHandle ) pxNewTCB;
}
/*如果调度器已经运行*/
if( xSchedulerRunning != pdFALSE )
{
/*如果新创建的任务的优先级高于当前正在运行的任务,则调度 */
if( pxCurrentTCB->uxPriority < uxPriority )
{
taskYIELD();
}
}
}
return xReturn;
}
其中prvAllocateTCBAndStack分配tcb和stack内存,这个里面调用了pvportMalloc和pvPortFree函数来分配和释放内存,这两个函数对应于C标准库里面的malloc和free。但是标准库中的mallo和free存在以下缺点:并不是在所有的嵌入式系统中都可用,要占用不定的程序空间,可重人性欠缺以及执行时间具有不可确定性,而且多次反复调用可能导致严重的内存碎片。因此freertos在内存管理那块自己实现了这两个函数。
static tskTCB *prvAllocateTCBAndStack( unsigned portSHORT usStackDepth )
{
tskTCB *pxNewTCB;
/* Allocate space for the TCB. Where the memory comes from depends on
the implementation of the port malloc function. */
pxNewTCB = ( tskTCB * ) pvPortMalloc( sizeof( tskTCB ) );
if( pxNewTCB != NULL )
{
/* Allocate space for the stack used by the task being created.
The base of the stack memory stored in the TCB so the task can
be deleted later if required. */
pxNewTCB->pxStack = ( portSTACK_TYPE * ) pvPortMalloc( ( ( size_t )usStackDepth ) * sizeof( portSTACK_TYPE ) );
if( pxNewTCB->pxStack == NULL )
{
/* Could not allocate the stack. Delete the allocated TCB. */
vPortFree( pxNewTCB );
pxNewTCB = NULL;
}
else
{
/* Just to help debugging. */
memset( pxNewTCB->pxStack, tskSTACK_FILL_BYTE, usStackDepth * sizeof( portSTACK_TYPE ) );
}
}
return pxNewTCB;
}
再看任务删除。
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();
…………………………….
这里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
} |