首页 | 新闻 | 新品 | 文库 | 方案 | 视频 | 下载 | 商城 | 开发板 | 数据中心 | 座谈新版 | 培训 | 工具 | 博客 | 论坛 | 百科 | GEC | 活动 | 主题月 | 电子展
返回列表 回复 发帖

FreeRTOS分析(3)

FreeRTOS分析(3)

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
}
继承事业,薪火相传
返回列表