对FreeRTOS的task.c文件源码的分析笔记(一)

task.c文件

TCB结构体分析

typedef struct tskTaskControlBlock
{
	volatile StackType_t	*pxTopOfStack;

	#if ( portUSING_MPU_WRAPPERS == 1 )
		xMPU_SETTINGS	xMPUSettings;
	#endif

	ListItem_t			xStateListItem;								//状态列表项
	ListItem_t			xEventListItem;								//事件列表项
	UBaseType_t			uxPriority;									//优先级
	StackType_t			*pxStack;									//任务堆栈
	char				pcTaskName[ configMAX_TASK_NAME_LEN ];		//任务名

	#if ( portSTACK_GROWTH > 0 )
    	//该指针指向一个由低地址向上生长的堆栈的尾部
		StackType_t		*pxEndOfStack;
	#endif

	#if ( portCRITICAL_NESTING_IN_TCB == 1 )
		UBaseType_t		uxCriticalNesting;
	#endif

    //可视化追踪相关
	#if ( configUSE_TRACE_FACILITY == 1 )
		UBaseType_t		uxTCBNumber;
		UBaseType_t		uxTaskNumber;
	#endif

    //互斥信号量相关
	#if ( configUSE_MUTEXES == 1 )
		UBaseType_t		uxBasePriority;
		UBaseType_t		uxMutexesHeld;
	#endif

    //任务标签相关
	#if ( configUSE_APPLICATION_TASK_TAG == 1 )
		TaskHookFunction_t pxTaskTag;
	#endif

	#if( configNUM_THREAD_LOCAL_STORAGE_POINTERS > 0 )
		void *pvThreadLocalStoragePointers[ configNUM_THREAD_LOCAL_STORAGE_POINTERS ];
	#endif
    
	//运行时间统计功能相关
	#if( configGENERATE_RUN_TIME_STATS == 1 )
		uint32_t		ulRunTimeCounter;
	#endif

	#if ( configUSE_NEWLIB_REENTRANT == 1 )
		struct	_reent xNewLib_reent;
	#endif

    //开启任务通知功能,默认开启
	#if( configUSE_TASK_NOTIFICATIONS == 1 )
		volatile uint32_t ulNotifiedValue;
		volatile uint8_t ucNotifyState;
	#endif

    //与静态创建任务相关,不为0时说明允许静态创建任务
	#if( tskSTATIC_AND_DYNAMIC_ALLOCATION_POSSIBLE != 0 )
		uint8_t	ucStaticallyAllocated;
	#endif

	#if( INCLUDE_xTaskAbortDelay == 1 )
		uint8_t ucDelayAborted;
	#endif

} tskTCB;

一些私有成员变量的说明

/* Lists for ready and blocked tasks. --------------------*/
//就绪态任务列表数组,按优先级顺序排列
PRIVILEGED_DATA static List_t pxReadyTasksLists[ configMAX_PRIORITIES ];
//delay任务列表1
PRIVILEGED_DATA static List_t xDelayedTaskList1;	
//delay任务列表2
PRIVILEGED_DATA static List_t xDelayedTaskList2;
//delay任务列表指针,指向当前正在使用的延迟任务列表
PRIVILEGED_DATA static List_t * volatile pxDelayedTaskList;	
//超时任务列表指针,指向当前等待超时的任务列表
PRIVILEGED_DATA static List_t * volatile pxOverflowDelayedTaskList;
//在调度器被被挂起时已就绪的任务,当调度程序恢复时,它们就会移动到就绪列表
PRIVILEGED_DATA static List_t xPendingReadyList;
list when the scheduler is resumed. */

#if( INCLUDE_vTaskDelete == 1 )
    /* 任务被删除后,它所占用的内存空间还没被释放,要释放掉 */
	//任务等待终止列表
	PRIVILEGED_DATA static List_t xTasksWaitingTermination;	
	//被删除的任务等待清除的标志
	PRIVILEGED_DATA static volatile UBaseType_t uxDeletedTasksWaitingCleanUp = ( UBaseType_t ) 0U;

#endif

#if ( INCLUDE_vTaskSuspend == 1 )
	//当前被挂起的任务列表
	PRIVILEGED_DATA static List_t xSuspendedTaskList;

#endif

/* Other file private variables. --------------------------------*/

//当前任务数量
PRIVILEGED_DATA static volatile UBaseType_t uxCurrentNumberOfTasks 	= ( UBaseType_t ) 0U;
//系统时钟节拍计数器,存储systick的值,用来给系统提供时间信息
PRIVILEGED_DATA static volatile TickType_t xTickCount 				= ( TickType_t ) 0U;
//就绪态任务的最高优先级
PRIVILEGED_DATA static volatile UBaseType_t uxTopReadyPriority 		= tskIDLE_PRIORITY;
//调度器运行标志
PRIVILEGED_DATA static volatile BaseType_t xSchedulerRunning 		= pdFALSE;
//任务被挂起时,记录被挂起的时间,用于补充调度器漏掉的时间
PRIVILEGED_DATA static volatile UBaseType_t uxPendedTicks 			= ( UBaseType_t ) 0U;
//当被移除的任务优先级高于当前任务时,xYieldPending会被置为pdTRUE
//当调度器被挂起时(不允许上下文切换),xYieldPending也会被置为pdTRUE
PRIVILEGED_DATA static volatile BaseType_t xYieldPending 			= pdFALSE;
//保存xTickCount溢出的次数
PRIVILEGED_DATA static volatile BaseType_t xNumOfOverflows 			= ( BaseType_t ) 0;
//任务序号,每创建一个任务,这个值加1,调试用
PRIVILEGED_DATA static UBaseType_t uxTaskNumber 					= ( UBaseType_t ) 0U;
//下一个任务解除阻塞的时间
PRIVILEGED_DATA static volatile TickType_t xNextTaskUnblockTime		= ( TickType_t ) 0U; 
//空闲任务句柄
PRIVILEGED_DATA static TaskHandle_t xIdleTaskHandle					= NULL;			

动态创建任务函数分析

BaseType_t xTaskCreate(	TaskFunction_t pxTaskCode,				//任务函数
					const char * const pcName,				  //任务名字
					const configSTACK_DEPTH_TYPE usStackDepth, //任务堆栈大小
					void * const pvParameters,				  //传递给任务函数的参数
					UBaseType_t uxPriority,					  //任务优先级
					TaskHandle_t * const pxCreatedTask )	   //任务句柄
{
    TCB_t *pxNewTCB;	//创建一个任务控制块
    BaseType_t xReturn;	//定义一个返回值
    //如果堆栈向上增长,先任务控制块,再任务堆栈
    #if( portSTACK_GROWTH > 0 )
    {
        //给任务控制块申请一块内存空间
        pxNewTCB = ( TCB_t * ) pvPortMalloc( sizeof( TCB_t ) );
		//判断是否申请成功
        if( pxNewTCB != NULL )
        {
            //如果申请成功则给任务堆栈申请一块内存空间,大小为 usStackDepth 的4倍
            pxNewTCB->pxStack = ( StackType_t * ) pvPortMalloc( ( ( ( size_t ) usStackDepth ) * sizeof( StackType_t ) ) ); 
		   //判断是否申请成功
            if( pxNewTCB->pxStack == NULL )
            {
                //如果失败则释放掉任务控制块所占用的内存空间
                vPortFree( pxNewTCB );
                pxNewTCB = NULL;
            }
        }
    }
    //如果堆栈向下增长,先任务堆栈,再任务控制块
    #else /* portSTACK_GROWTH */
    {
        StackType_t *pxStack;
		//给任务堆栈申请一块内存空间,大小为 usStackDepth 的4倍
        pxStack = ( StackType_t * ) pvPortMalloc( ( ( ( size_t ) usStackDepth ) * sizeof( StackType_t ) ) ); 
		//判断是否申请成功
        if( pxStack != NULL )
        {
            //如果申请成功则给任务控制块申请一块内存空间
            pxNewTCB = ( TCB_t * ) pvPortMalloc( sizeof( TCB_t ) );
		   //判断是否申请成功
            if( pxNewTCB != NULL )
            {
                //申请成功则让任务控制块的任务堆栈指向这个新开辟的堆栈空间
                pxNewTCB->pxStack = pxStack;
            }
            else
            {
                //如果失败则释放掉任务堆栈所占用的内存空间
                vPortFree( pxStack );
            }
		}
        else
        {
            //如果任务堆栈申请失败,则任务控制块为空
            pxNewTCB = NULL;
        }
    }
	#endif
	//如果任务控制块不为空,说明任务控制块和任务堆栈的内存空间都申请成功,可以存放任务信息了
    if( pxNewTCB != NULL )
    {
        //这里要注意,这句话的意思是要将动态分配和静态分配同时打开才执行
        //( configSUPPORT_STATIC_ALLOCATION == 1 ) && ( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) 
        #if( tskSTATIC_AND_DYNAMIC_ALLOCATION_POSSIBLE != 0 ) 
        {
            pxNewTCB->ucStaticallyAllocated = tskDYNAMICALLY_ALLOCATED_STACK_AND_TCB;
        }
        #endif
        //新创建的任务所需的空间已经申请完毕,任务进入初始化
        prvInitialiseNewTask( pxTaskCode, pcName,
                             ( uint32_t ) usStackDepth, 
                             pvParameters, 										
                             uxPriority, 
                             pxCreatedTask, 
                             pxNewTCB, 
                             NULL );
        //初始化完毕后,将任务添加进就绪列表
        prvAddNewTaskToReadyList( pxNewTCB );
        //任务返回值为pdPASS
        xReturn = pdPASS;
    }
    //否则任务创建失败
    else
    {	//任务返回值为errCOULD_NOT_ALLOCATE_REQUIRED_MEMORY
        xReturn = errCOULD_NOT_ALLOCATE_REQUIRED_MEMORY;
    }
	//返回任务返回值
    return xReturn;
	}

初始化新任务

static void prvInitialiseNewTask( 	TaskFunction_t pxTaskCode,
                                 const char * const pcName,		
                                 const uint32_t ulStackDepth,
                                 void * const pvParameters,
                                 UBaseType_t uxPriority,
                                 TaskHandle_t * const pxCreatedTask,
                                 TCB_t *pxNewTCB,
                                 const MemoryRegion_t * const xRegions )
{
    //创建一个指向栈顶的指针
    StackType_t *pxTopOfStack;
    UBaseType_t x;
	
    //如果使用MPU功能则会执行下列函数,MPU:存储保护单元,暂时先用默认的
    #if( portUSING_MPU_WRAPPERS == 1 )
    BaseType_t xRunPrivileged;
    if( ( uxPriority & portPRIVILEGE_BIT ) != 0U )
    {
        xRunPrivileged = pdTRUE;
    }
    else
    {
        xRunPrivileged = pdFALSE;
    }
    uxPriority &= ~portPRIVILEGE_BIT;
    #endif /* portUSING_MPU_WRAPPERS == 1 */

    /* 避免对函数 memset() 的依赖 */
    #if( tskSET_NEW_STACKS_TO_KNOWN_VALUE == 1 )
    {
        /* Fill the stack with a known value to assist debugging. */
        ( void ) memset( pxNewTCB->pxStack, ( int ) tskSTACK_FILL_BYTE, ( size_t ) ulStackDepth * sizeof( StackType_t ) );
    }
    #endif /* tskSET_NEW_STACKS_TO_KNOWN_VALUE */

    /* 计算栈顶地址,根据堆栈是向上生长还是向下生长来进行不同的计算,portSTACK_GROWTH则是将计算的结果转化为正数或负数 */
    #if( portSTACK_GROWTH < 0 )	//向下生长
    {
        //计算方法
        pxTopOfStack = pxNewTCB->pxStack + ( ulStackDepth - ( uint32_t ) 1 );
        pxTopOfStack = ( StackType_t * ) ( ( ( portPOINTER_SIZE_TYPE ) pxTopOfStack ) & ( ~( ( portPOINTER_SIZE_TYPE ) portBYTE_ALIGNMENT_MASK ) ) ); 

        configASSERT( ( ( ( portPOINTER_SIZE_TYPE ) pxTopOfStack & ( portPOINTER_SIZE_TYPE ) portBYTE_ALIGNMENT_MASK ) == 0UL ) );

        #if( configRECORD_STACK_HIGH_ADDRESS == 1 )
        {
            /* Also record the stack's high address, which may assist
			debugging. */
            pxNewTCB->pxEndOfStack = pxTopOfStack;
        }
        #endif /* configRECORD_STACK_HIGH_ADDRESS */
    }
    #else //向上生长
    {
        pxTopOfStack = pxNewTCB->pxStack;
        
        /* Check the alignment of the stack buffer is correct. */
        configASSERT( ( ( ( portPOINTER_SIZE_TYPE ) pxNewTCB->pxStack & ( portPOINTER_SIZE_TYPE ) portBYTE_ALIGNMENT_MASK ) == 0UL ) );

        /* 检查堆栈,防止出错 */
        pxNewTCB->pxEndOfStack = pxNewTCB->pxStack + ( ulStackDepth - ( uint32_t ) 1 );
    }
    #endif /* portSTACK_GROWTH */

    /* 将任务名称存储在任务控制块中,搬运数组内的数据 */
    for( x = ( UBaseType_t ) 0; x < ( UBaseType_t ) configMAX_TASK_NAME_LEN; x++ )
    {
        pxNewTCB->pcTaskName[ x ] = pcName[ x ];

        /* 如果字符串比configMAX_TASK_NAME_LEN要短,
        则不会复制所有的configMAX_TASK_NAME_LEN字符,以防字符串后面的内存不可访问,节约内存空间 */
        if( pcName[ x ] == 0x00 )
        {
            break;
        }
        else
        {
            mtCOVERAGE_TEST_MARKER();
        }
    }

    /* 确保在字符串长度大于或等于configMAX_TASK_NAME_LEN的情况下终止名称字符串 */
    pxNewTCB->pcTaskName[ configMAX_TASK_NAME_LEN - 1 ] = '\0';

    /* 这是用作数组索引,所以必须确保它不是太大。 如果存在特权位,首先删除特权位 */
    if( uxPriority >= ( UBaseType_t ) configMAX_PRIORITIES )
    {
        uxPriority = ( UBaseType_t ) configMAX_PRIORITIES - ( UBaseType_t ) 1U;
    }
    else
    {
        mtCOVERAGE_TEST_MARKER();
    }
	//新任务的优先级接受调整后的优先级大小
    pxNewTCB->uxPriority = uxPriority;
    #if ( configUSE_MUTEXES == 1 )
    {
        pxNewTCB->uxBasePriority = uxPriority;
        pxNewTCB->uxMutexesHeld = 0;
    }
    #endif /* configUSE_MUTEXES */
    
	//初始化任务状态列表项
    vListInitialiseItem( &( pxNewTCB->xStateListItem ) );
    //初始化任务事件列表项
    vListInitialiseItem( &( pxNewTCB->xEventListItem ) );

    /* 设置任务状态列表项的归属为新任务的任务控制块 */
    listSET_LIST_ITEM_OWNER( &( pxNewTCB->xStateListItem ), pxNewTCB );

    /* 任务事件列表总是按优先级顺序排列
       列表项中的value值存放的是最大优先级减去任务优先级,这里体现出了,数值越大,优先级越小的思想*/
    listSET_LIST_ITEM_VALUE( &( pxNewTCB->xEventListItem ), ( TickType_t ) configMAX_PRIORITIES - ( TickType_t ) uxPriority ); 
    
    /* 设置任务事件列表项的归属为新任务的任务控制块 */
    listSET_LIST_ITEM_OWNER( &( pxNewTCB->xEventListItem ), pxNewTCB );

    //以下是各种不同配置情况下执行的不同操作
  	..............
    //以上省略了不同配置情况下执行的不同操作,需要结合config文件看
        
    //如果任务创建成功
    if( ( void * ) pxCreatedTask != NULL )
    {
        /* 将任务的句柄传递出去,任务句柄可用来更改创建的任务的优先级,删除创建的任务等 */
        *pxCreatedTask = ( TaskHandle_t ) pxNewTCB;
    }
    else
    {
        mtCOVERAGE_TEST_MARKER();
    }
}

将任务添加到就绪列表

static void prvAddNewTaskToReadyList( TCB_t *pxNewTCB )
{
    /* 进入临界段,确保当任务列表正在运行时,中断不会访问该任务列表更新,即关闭中断 */
    taskENTER_CRITICAL();
    {
        //当前任务数量加1
        uxCurrentNumberOfTasks++;
        if( pxCurrentTCB == NULL )
        {
            /* 如果没有没有其他任务,或者所有其他任务都在挂起状态,则使其成为当前任务。 */
            pxCurrentTCB = pxNewTCB;

            if( uxCurrentNumberOfTasks == ( UBaseType_t ) 1 )
            {
                /* 如果当前的这个任务是要创建的第一个任务,则对任务进行初始化 */
                prvInitialiseTaskLists();
            }
            else
            {
                mtCOVERAGE_TEST_MARKER();
            }
        }
        else
        {
            /* 如果还没有开启任务调度器 */
            if( xSchedulerRunning == pdFALSE )
            {
                //并且如果当前任务的优先级小于或等于新创建的任务的优先级
                if( pxCurrentTCB->uxPriority <= pxNewTCB->uxPriority )
                {
                    //就将当前任务设置为新任务
                    pxCurrentTCB = pxNewTCB;
                }
                else
                {
                    mtCOVERAGE_TEST_MARKER();
                }
            }
            else
            {
                mtCOVERAGE_TEST_MARKER();
            }
        }
		//任务数量加1
        uxTaskNumber++;

        #if ( configUSE_TRACE_FACILITY == 1 )
        {
            /* Add a counter into the TCB for tracing only. */
            pxNewTCB->uxTCBNumber = uxTaskNumber;
        }
        #endif /* configUSE_TRACE_FACILITY */
        traceTASK_CREATE( pxNewTCB );
		//将新任务添加到就绪列表中
        prvAddTaskToReadyList( pxNewTCB );

        portSETUP_TCB( pxNewTCB );
    }
    //退出临界段,重新打开中断
    taskEXIT_CRITICAL();
	//任务调度器正在运行
    if( xSchedulerRunning != pdFALSE )
    {
        /* 如果创建的任务的优先级高于当前任务,那么它应该现在运行 */
        if( pxCurrentTCB->uxPriority < pxNewTCB->uxPriority )
        {
            //让新任务进行抢占,即对任务进行抢占式调度
            taskYIELD_IF_USING_PREEMPTION();
        }
        else
        {
            mtCOVERAGE_TEST_MARKER();
        }
    }
    else
    {
        mtCOVERAGE_TEST_MARKER();
    }
}

删除任务

void vTaskDelete( TaskHandle_t xTaskToDelete )
{
    TCB_t *pxTCB;
 	
    /* 进入临界段,确保当任务列表正在运行时,中断不会访问该任务列表更新,即关闭中断 */
    taskENTER_CRITICAL();
    {
        /* 获取要删除的任务的任务控制块 */
        pxTCB = prvGetTCBFromHandle( xTaskToDelete );

        /* 从就绪列表中移除任务 */
        //uxListRemove()会返回删除任务后,列表中的任务数量
        if( uxListRemove( &( pxTCB->xStateListItem ) ) == ( UBaseType_t ) 0 )
        {
            //如果一个任务移除后,任务列表中没有任务了,就复位就绪任务的优先级
            taskRESET_READY_PRIORITY( pxTCB->uxPriority );
        }
        else
        {
            mtCOVERAGE_TEST_MARKER();
        }
		//如果事件列表项所包含的列表不为空
        if( listLIST_ITEM_CONTAINER( &( pxTCB->xEventListItem ) ) != NULL )
        {
            //移除该任务的任务控制块中的事件列表
            ( void ) uxListRemove( &( pxTCB->xEventListItem ) );
        }
        else
        {
            mtCOVERAGE_TEST_MARKER();
        }
		//任务序号加1
        uxTaskNumber++;
		
        //如果TCB结构体是当前任务的TCB结构体
        if( pxTCB == pxCurrentTCB )
        {
            //将要删除的任务放入终止列表中
            vListInsertEnd( &xTasksWaitingTermination, &( pxTCB->xStateListItem ) );
			//被删除并且等待内存释放的任务数量加1
            ++uxDeletedTasksWaitingCleanUp;

            portPRE_TASK_DELETE_HOOK( pxTCB, &xYieldPending );
        }
        else
        {
            //当前任务数减1
            --uxCurrentNumberOfTasks;
            //删除任务的TCB结构体
            prvDeleteTCB( pxTCB );
            prvResetNextTaskUnblockTime();
        }

        traceTASK_DELETE( pxTCB );
    }
    /*退出临界段*/
    taskEXIT_CRITICAL();
	/*如果当前正在运行的任务刚刚被删除了*/
    //任务调度器正在运行
    if( xSchedulerRunning != pdFALSE )
    {
        //任务的TCB是当前运行的任务的TCB
        if( pxTCB == pxCurrentTCB )
        {
            configASSERT( uxSchedulerSuspended == 0 );
            portYIELD_WITHIN_API();
        }
        else
        {
            mtCOVERAGE_TEST_MARKER();
        }
    }
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值