函数原型:
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 )
1.根据usStackDepth计算出任务堆栈大小并malloc相应的堆栈和tcb控制块变量空间(TCB_t)
TCB_t *pxNewTCB;
pxNewTCB = ( TCB_t * ) pvPortMalloc( sizeof( TCB_t ) );
pxNewTCB->pxStack = ( StackType_t * ) pvPortMalloc( ( ( ( size_t ) usStackDepth ) * sizeof( StackType_t ) ) );
2.宏定义判断是否动态和静态内存分配,如果都支持,则设定任务堆栈和tcb均为动态分配产生的。
pxNewTCB->ucStaticallyAllocated = tskDYNAMICALLY_ALLOCATED_STACK_AND_TCB;
3.初始化新任务的tcb结构体
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 )
3.1如果内核设定支持堆栈溢出检测,则设定任务tcb结构体的堆栈的最大上边界地址
pxTopOfStack = pxNewTCB->pxStack;
pxNewTCB->pxEndOfStack = pxNewTCB->pxStack + ( ulStackDepth - ( uint32_t ) 1 );
3.2根据设定的名称最大长度configMAX_TASK_NAME_LEN和'\0'字符,初始化任务名称pcName
3.3设定任务优先级--为什么要减1???
uxPriority = ( UBaseType_t ) configMAX_PRIORITIES - ( UBaseType_t ) 1U;
pxNewTCB->uxPriority = uxPriority;
3.4初始化tcb结构体的状态列表项和事件列表项,
//初始化
vListInitialiseItem( &( pxNewTCB->xStateListItem ) );
vListInitialiseItem( &( pxNewTCB->xEventListItem ) );
//指定列表项所属tcb
listSET_LIST_ITEM_OWNER( &( pxNewTCB->xStateListItem ), pxNewTCB );
listSET_LIST_ITEM_OWNER( &( pxNewTCB->xEventListItem ), pxNewTCB );
//设定事件列表项xEventListItem的值
listSET_LIST_ITEM_VALUE( &( pxNewTCB->xEventListItem ), ( TickType_t ) configMAX_PRIORITIES - ( TickType_t ) uxPriority );
3.5如果支持边界嵌套计数,则初始化
pxNewTCB->uxCriticalNesting = ( UBaseType_t ) 0U;
3.6如果支持任务事件统计,则初始化
pxNewTCB->ulRunTimeCounter = 0UL;
3.7如果tcb存在本地数据存储指针,则初始化
for( x = 0; x < ( UBaseType_t ) configNUM_THREAD_LOCAL_STORAGE_POINTERS; x++ )
{
pxNewTCB->pvThreadLocalStoragePointers[ x ] = NULL;
}
//执行的判断条件是#if( configNUM_THREAD_LOCAL_STORAGE_POINTERS != 0 ),
个人认为应该修改为#if( configNUM_THREAD_LOCAL_STORAGE_POINTERS > 0 ),这样程序可能会更好吧
//configNUM_THREAD_LOCAL_STORAGE_POINTERS的值设定为负数,会导致编译报错
3.8如果内核配置支持消息通知,则初始化
pxNewTCB->ulNotifiedValue = 0;
pxNewTCB->ucNotifyState = taskNOT_WAITING_NOTIFICATION;
3.9如果内核支持INCLUDE_xTaskAbortDelay(即xTaskAbortDelay函数),则初始化
pxNewTCB->ucDelayAborted = pdFALSE;
3.10初始化任务堆栈
pxNewTCB->pxTopOfStack = pxPortInitialiseStack( pxTopOfStack, pxTaskCode, pvParameters );
3.11设定返回任务句柄(实际上就是tcb指针)
*pxCreatedTask = ( TaskHandle_t ) pxNewTCB;
4.将新建的任务添加到任务就绪列表中
static void prvAddNewTaskToReadyList( TCB_t *pxNewTCB )
4.1 任务总量计数++
uxCurrentNumberOfTasks++; //uxCurrentNumberOfTasks全局变量,对所有任务计数
4.2 如果当前无任务在运行,猜测应该是当前是第一次创建任务pxCurrentTCB == NULL //pxCurrentTCB用于指定当前在运行的任务tcb
4.2.1 将新创建的任务tcb复制给pxCurrentTCB
pxCurrentTCB = pxNewTCB;
4.2.2 判断如果当前是第一次创建任务(任务计数为1)uxCurrentNumberOfTasks == 1,就需要做以下全局任务列表的初始化,主要有以下列表
PRIVILEGED_DATA static List_t pxReadyTasksLists[ configMAX_PRIORITIES ]; //就绪任务列表数组,不同的优先级分成不同的列表
PRIVILEGED_DATA static List_t xDelayedTaskList1; //阻塞任务列表1
PRIVILEGED_DATA static List_t xDelayedTaskList2; //阻塞任务列表2
PRIVILEGED_DATA static List_t * volatile pxDelayedTaskList;
PRIVILEGED_DATA static List_t * volatile pxOverflowDelayedTaskList;
PRIVILEGED_DATA static List_t xPendingReadyList;
4.3 如果任务当前有任务在运行
4.3.1判断任务调度器是否在运行且新任务的优先级是否比当前运行的任务优先级高,将当前任务tcb指针指向新任务
pxCurrentTCB = pxNewTCB;
4.4 创建的任务总数计数++
uxTaskNumber++; //全局变量,创建的任务总数计数
//uxTaskNumber与uxCurrentNumberOfTasks的区别
//首先是uxCurrentNumberOfTasks,代表当前系统中存在的任务数目,创建任务时++,删除任务时--
//uxTaskNumber系统从运行到结束的创建任务总数,虽然会在创建任务时++,但删除任务时不做--操作
4.5初始化tcb的任务控制块编号,系统会将创建任务计数赋值给uxTCBNumber
pxNewTCB->uxTCBNumber = uxTaskNumber;
4.6将任务添加到指定的任务优先级的就绪列表中
prvAddTaskToReadyList( pxNewTCB );
4.7 如果新任务比正在运行的任务优先级高,发起任务切换
taskYIELD_IF_USING_PREEMPTION(); //内部调用portYIELD_WITHIN_API()--->portYIELD()
5.返回创建结果