1.动态创建详细过程
动态创建
1.首先tasks.c中
结构体并给别名,所以初始化可以用TCB_t
typedef struct tskTaskControlBlock
{
…
}tskTCB; typedef tskTCB TCB_t;
2.因此在xTaskCreate()实现中
TCB_t * pxNewTCB;创建了任务控制块
3.任务控制块的结构体中
状态列表 事件列表 优先级 栈指针 任务名

4.回到xTaskCreate
判断生长方向,STM32栈区向下生长
#if ( portSTACK_GROWTH > 0 )
进入的
#else中
其中先定义任务堆栈大小:
StackType_t * pxStack;//这个申请的代表首地址
pxStack = pvPortMallocStack( ( ( ( size_t ) usStackDepth ) * sizeof( StackType_t ) ) );//如128*4字节,128字×每字字节数=字节数
判断是否申请成功任务堆栈,成功则进入
if( pxStack != NULL )
{
pxNewTCB = ( TCB_t * ) pvPortMalloc( sizeof( TCB_t ) ); //任务控制块信息也需要空间,因此申请
if( pxNewTCB != NULL ) //如果申请了一块
{
memset( ( void * ) pxNewTCB, 0x00, sizeof( TCB_t ) );
pxNewTCB->pxStack = pxStack;//然后将首地址给到任务控制块的这个成员变量
}
else
{
vPortFreeStack( pxStack );//否则就释放掉任务堆栈
}
}
else
{
pxNewTCB = NULL;
}
再下面判断是否申请成功任务控制块
prvInitialiseNewTask:这个用来初始化任务控制块中的成员
prvAddNewTaskToReadyList:将任务添加到就绪列表
if( pxNewTCB != NULL )
{
prvInitialiseNewTask( pxTaskCode, pcName, ( uint32_t ) usStackDepth, pvParameters, uxPriority, pxCreatedTask, pxNewTCB, NULL );
prvAddNewTaskToReadyList( pxNewTCB );
xReturn = pdPASS;//就是成功的返回值
}
else
{
xReturn = errCOULD_NOT_ALLOCATE_REQUIRED_MEMORY;
}
5.到prvInitialiseNewTask
( void ) memset( pxNewTCB->pxStack, ( int ) tskSTACK_FILL_BYTE, ( size_t ) ulStackDepth * sizeof( StackType_t ) );
这句pxStack是任务堆栈的首地址,将( size_t ) ulStackDepth * sizeof( StackType_t )大小的地址赋值为( int ) tskSTACK_FILL_BYTE
而这个值是
#define tskSTACK_FILL_BYTE ( 0xa5U )
意思就是整个任务堆栈赋值成a5,那就可以通过判断多少a5被改变,得到剩下的空间
6.判断 #if ( portSTACK_GROWTH < 0 )
是否向下生长?
STM32:是的
//首地址的最低位,取得栈顶
pxTopOfStack = &( pxNewTCB->pxStack[ ulStackDepth - ( uint32_t ) 1 ] );
判断名字是否为空
//pcName是一个入口参数
if( pcName != NULL )
{
for( x = ( UBaseType_t ) 0; x < ( UBaseType_t ) configMAX_TASK_NAME_LEN; x++ )
{
pxNewTCB->pcTaskName[ x ] = pcName[ x ]; //给到任务控制块的这个成员里
if( pcName[ x ] == ( char ) 0x00 )
{
break;
}
else
{
mtCOVERAGE_TEST_MARKER();
}
}
pxNewTCB->pcTaskName[ configMAX_TASK_NAME_LEN - 1 ] = '\0';
}
else
{
mtCOVERAGE_TEST_MARKER();
}
判断优先级
优先级大于最大优先级,就改为最大优先级
if( uxPriority >= ( UBaseType_t ) configMAX_PRIORITIES )
{
uxPriority = ( UBaseType_t ) configMAX_PRIORITIES - ( UBaseType_t ) 1U;
}
pxNewTCB->uxPriority = uxPriority;
然后初始化状态列表项和事件列表项
vListInitialiseItem( &( pxNewTCB->xStateListItem ) ); vListInitialiseItem( &( pxNewTCB->xEventListItem ) );
将状态列表项所有权给到任务控制块,就可以得到任务当前状态
listSET_LIST_ITEM_OWNER( &( pxNewTCB->xStateListItem ), pxNewTCB );
下面是事件列表项
listSET_LIST_ITEM_VALUE( &( pxNewTCB->xEventListItem ), ( TickType_t ) configMAX_PRIORITIES - ( TickType_t ) uxPriority );
listSET_LIST_ITEM_OWNER( &( pxNewTCB->xEventListItem ), pxNewTCB );
下面来到
pxNewTCB->pxTopOfStack = pxPortInitialiseStack( pxTopOfStack, pxTaskCode, pvParameters );
7.进入pxPortInitialiseStack
里面栈顶陆续减,就可以往下陆续给赋值。
StackType_t * pxPortInitialiseStack( StackType_t * pxTopOfStack,
TaskFunction_t pxCode,
void * pvParameters )
{
pxTopOfStack--;
*pxTopOfStack = portINITIAL_XPSR; /* xPSR */
pxTopOfStack--;
*pxTopOfStack = ( ( StackType_t ) pxCode ) & portSTART_ADDRESS_MASK; /* PC */
pxTopOfStack--;
*pxTopOfStack = ( StackType_t ) prvTaskExitError; /* LR */
pxTopOfStack -= 5; /* R12, R3, R2 and R1. */
*pxTopOfStack = ( StackType_t ) pvParameters; /* R0 */
pxTopOfStack -= 8; /* R11, R10, R9, R8, R7, R6, R5 and R4. */
return pxTopOfStack;
}
PC是任务函数指针,切换到A任务时,就通过这个指针切换到任务函数A

这个实际就是最初传入的函数指针

而R0传入的是任务函数参数

程序结束后返回更新后的pxTopOfStack
8.回到prvInitialiseNewTask
将任务句柄给到任务控制块
if( pxCreatedTask != NULL ) { *pxCreatedTask = ( TaskHandle_t ) pxNewTCB; }
9.再到prvAddNewTaskToReadyList()
这是将任务添加到就绪列表
先进入临界区 taskENTER_CRITICAL();
增加任务数量uxCurrentNumberOfTasks++;
如果当前没有任务,这是第一个任务pxCurrentTCB = pxNewTCB;
如果这确实是第一个if( uxCurrentNumberOfTasks == ( UBaseType_t ) 1 )
就初始化任务列表prvInitialiseTaskLists()

10.进入prvInitialiseTaskLists()
初始化32个就绪列表0~31
for( uxPriority = ( UBaseType_t ) 0U; uxPriority < ( UBaseType_t ) configMAX_PRIORITIES; uxPriority++ )
{
vListInitialise( &( pxReadyTasksLists[ uxPriority ] ) );
}
如果使能删除列表,就初始化一个等待删除列表
如果使能挂起列表,就初始化一个挂起列表
#if ( INCLUDE_vTaskDelete == 1 )
{
vListInitialise( &xTasksWaitingTermination );
}
#endif /* INCLUDE_vTaskDelete */
#if ( INCLUDE_vTaskSuspend == 1 )
{
vListInitialise( &xSuspendedTaskList );
}
#endif /* INCLUDE_vTaskSuspend */
11.继续prvAddNewTaskToReadyList()
否则的话,如果当前任务控制块优先级小于新创建的任务控制块
那新创建的就赋给当前
if( xSchedulerRunning == pdFALSE )
{
if( pxCurrentTCB->uxPriority <= pxNewTCB->uxPriority )
{
pxCurrentTCB = pxNewTCB;
}
else
{
mtCOVERAGE_TEST_MARKER();
}
}
下面是任务标号,就可以通过这个查询这是第几个创建的任务

12.进入prvAddTaskToReadyList( pxNewTCB );
进入 taskRECORD_READY_PRIORITY( ( pxTCB )->uxPriority );
进如portRECORD_READY_PRIORITY
得到
#define portRECORD_READY_PRIORITY( uxPriority, uxReadyPriorities ) ( uxReadyPriorities ) |= ( 1UL « ( uxPriority ) )
表示就绪列表,哪个位置一,哪个位就有任务,从上往下读就知道哪个任务优先级最高

13.继续prvAddNewTaskToReadyList()
退出临界区taskEXIT_CRITICAL();
如果任务调度器开启,当前任务优先级,小于新的优先级,执行任务切换,到优先级最高的

2.任务挂起与恢复详细过程
任务挂起
1.进入prvGetTCBFromHandle
如果句柄为NULL,返回当前任务控制块句柄,否则返回传入任务控制块句柄
#define prvGetTCBFromHandle( pxHandle ) ( ( ( pxHandle ) == NULL ) ? pxCurrentTCB : ( pxHandle ) )
2.回到vTaskSuspend
if内是不管当前状态是什么,并移除列表项,移除成功则进入
if( uxListRemove( &( pxTCB->xStateListItem ) ) == ( UBaseType_t ) 0 )
{
taskRESET_READY_PRIORITY( pxTCB->uxPriority );
}
3.进入taskRESET_READY_PRIORITY
if(listCURRENT_LIST_LENGTH(&(pxReadyTasksLists[( uxPriority ) ] ) ) == ( UBaseType_t ) 0 )
{
portRESET_READY_PRIORITY( ( uxPriority ), ( uxTopReadyPriority ) );
}
4.回到vTaskSuspend
移除事件列表项
if( listLIST_ITEM_CONTAINER( &( pxTCB->xEventListItem ) ) != NULL )
{
( void ) uxListRemove( &( pxTCB->xEventListItem ) );
}
插入挂起列表项末尾
vListInsertEnd( &xSuspendedTaskList, &( pxTCB->xStateListItem ) );
如果带挂起的任务控制块在等待消息通知,清除消息通知
for( x = 0; x < configTASK_NOTIFICATION_ARRAY_ENTRIES; x++ )
{
if( pxTCB->ucNotifyState[ x ] == taskWAITING_NOTIFICATION )
{
pxTCB->ucNotifyState[ x ] = taskNOT_WAITING_NOTIFICATION;
}
}
判断调度器是否正在运行
如果正在运行,更新下一个阻塞超时时间
if( xSchedulerRunning != pdFALSE )
{
taskENTER_CRITICAL();
{
prvResetNextTaskUnblockTime();
}
taskEXIT_CRITICAL();
}
判断挂起是否为任务自己,如果挂起的是自己,强制进行任务切换。
如果不是,判断当前挂起的任务总数等于创建的任务总数,表明全部在挂起,则将任务控制块赋值为NULL,
if( pxTCB == pxCurrentTCB )
{
if( xSchedulerRunning != pdFALSE )
{
configASSERT( uxSchedulerSuspended == 0 );
portYIELD_WITHIN_API();
}
else
{
if( listCURRENT_LIST_LENGTH( &xSuspendedTaskList ) == uxCurrentNumberOfTasks )
{
pxCurrentTCB = NULL;
}
else
{
vTaskSwitchContext(); //查找下一个最高优先级任务
}
}
}
任务恢复
任务句柄赋值给任务控制块
TCB_t * const pxTCB = xTaskToResume;
恢复的任务控制块不能等于当前任务和NULL
if( ( pxTCB != pxCurrentTCB ) && ( pxTCB != NULL ) )
如果成立进入,判断任务控制块是否在挂起列表中
if( prvTaskIsTaskSuspended( pxTCB ) != pdFALSE )
如果成立进入,在挂起列表中移除
( void ) uxListRemove( &( pxTCB->xStateListItem ) );
并添加到就绪列表
prvAddTaskToReadyList( pxTCB );
在判断优先级是否大于当前优先级,如果是,则任务切换
taskYIELD_IF_USING_PREEMPTION();
if( ( pxTCB != pxCurrentTCB ) && ( pxTCB != NULL ) )
{
taskENTER_CRITICAL();
{
if( prvTaskIsTaskSuspended( pxTCB ) != pdFALSE )
{
traceTASK_RESUME( pxTCB );
( void ) uxListRemove( &( pxTCB->xStateListItem ) );
prvAddTaskToReadyList( pxTCB );
if( pxTCB->uxPriority >= pxCurrentTCB->uxPriority )
{
taskYIELD_IF_USING_PREEMPTION();
}
else
{
mtCOVERAGE_TEST_MARKER();
}
}
else
{
mtCOVERAGE_TEST_MARKER();
}
}
taskEXIT_CRITICAL();
}
else
{
mtCOVERAGE_TEST_MARKER();
}
3.临界段代码保护
通过++,–实现了嵌套,本质还是基于portDISABLE_INTERRUPTS();和portENABLE_INTERRUPTS();
/*进入临界段*/
#define taskENTER_CRITICAL() portENTER_CRITICAL()
#define portENTER_CRITICAL() vPortEnterCritical()
void vPortEnterCritical( void )
{
portDISABLE_INTERRUPTS();
uxCriticalNesting++;
if( uxCriticalNesting == 1 )
{
configASSERT( ( portNVIC_INT_CTRL_REG & portVECTACTIVE_MASK ) == 0 );
}
}
/*退出临界段*/
void vPortExitCritical( void )
{
configASSERT( uxCriticalNesting );
uxCriticalNesting--;
if( uxCriticalNesting == 0 )
{
portENABLE_INTERRUPTS();
}
}