<pre name="code" class="objc">BaseType_t xTaskGenericCreate(
TaskFunction_t pxTaskCode, // 指向任务的入口函数. 任务必须执行并且永不返回 (即:无限循环).
const char * const pcName, //描述任务的名字。主要便于调试。最大长度由configMAX_TASK_NAME_LEN.定义
const uint16_t usStackDepth, //指定任务堆栈的深度
void * const pvParameters, //指针用于作为一个参数传向创建的任务
UBaseType_t uxPriority, //任务运行时的优先级
TaskHandle_t * const pxCreatedTask,
//pxCreatedTask 用于传出任务的句柄。这个句柄将在API 调用中对该创建出来的任务进行引用,比如改变任务优先级,或者删除任务。
//如果应用程序中不会用到这个任务的句柄,则pxCreatedTask 可以被设为NULL
StackType_t * const puxStackBuffer, //堆栈缓冲区
const MemoryRegion_t * const xRegions ) // 缓存区
/*lint !e971 Unqualified char types are allowed for strings and single characters only. */
{
BaseType_t xReturn;
TCB_t * pxNewTCB;
configASSERT( pxTaskCode );
configASSERT( ( ( uxPriority & ( ~portPRIVILEGE_BIT ) ) < configMAX_PRIORITIES ) );
//按照新任务的TCB和堆栈分配存储空间并检查分配是否成功
pxNewTCB = prvAllocateTCBAndStack( usStackDepth, puxStackBuffer );//分配好的空间将填入0x5a数值。
if( pxNewTCB != NULL )//若TCB不为空,即分配成功。
{
StackType_t *pxTopOfStack;//计算堆栈栈顶的位置
#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 */
#if( portSTACK_GROWTH < 0 )// portSTACK_GROWTH = -1 对应倒生堆栈,比如 x86
{
pxTopOfStack = pxNewTCB->pxStack + ( usStackDepth - ( uint16_t ) 1 );//pxStack 指向堆栈的起始地址
pxTopOfStack = ( StackType_t * ) ( ( ( portPOINTER_SIZE_TYPE ) pxTopOfStack ) & ( ( portPOINTER_SIZE_TYPE ) ~portBYTE_ALIGNMENT_MASK ) );
//堆栈有地址对齐的要求
configASSERT( ( ( ( uint32_t ) pxTopOfStack & ( uint32_t ) portBYTE_ALIGNMENT_MASK ) == 0UL ) );
}
#else // 若不是倒生堆栈
{
pxTopOfStack = pxNewTCB->pxStack;//新建的堆栈是空的,所以堆栈的栈顶就在起始地址处(正生堆栈)
configASSERT( ( ( ( uint32_t ) pxNewTCB->pxStack & ( uint32_t ) portBYTE_ALIGNMENT_MASK ) == 0UL ) );
//如果要做堆栈检查,就要知道堆栈的另一端界限在哪里
pxNewTCB->pxEndOfStack = pxNewTCB->pxStack + ( usStackDepth - 1 );
}
#endif
//设置新的TCB,将其置于初始化状态
prvInitialiseTCBVariables( pxNewTCB, pcName, uxPriority, xRegions, usStackDepth );
//初始化堆栈,使得任务好像被中断函数中断了一样,中断返回地址就是任务的首地址,与 uC/OS-II 的方式相同
//依次将xPSR、PC、LR、R12以及R0-R3初始化
#if( portUSING_MPU_WRAPPERS == 1 )
{
pxNewTCB->pxTopOfStack = pxPortInitialiseStack( pxTopOfStack, pxTaskCode, pvParameters, xRunPrivileged );
}
#else
{
pxNewTCB->pxTopOfStack = pxPortInitialiseStack( pxTopOfStack, pxTaskCode, pvParameters );
}
#endif
if( ( void * ) pxCreatedTask != NULL )//若需要返回任务句柄
{
//返回任务的句柄
*pxCreatedTask = ( TaskHandle_t ) pxNewTCB;
}
else
{
mtCOVERAGE_TEST_MARKER();
}
//当正在更新时确保中断不会打断任务链表
taskENTER_CRITICAL();
{
uxCurrentNumberOfTasks++;//系统任务数目加一
if( pxCurrentTCB == NULL )//若当前任务TCB为空,即没有任务
{
//没有其他任务或者其他任务都被挂起,将刚创建的任务变成当前任务
pxCurrentTCB = pxNewTCB;
if( uxCurrentNumberOfTasks == ( UBaseType_t ) 1 )//若系统中任务的数目为1,即这个任务是第一个任务
{
//如果这是第一个任务,就做初始化工作,uC/OS-II 有单独的初始化函数,FreeRTOS 没有,初始化工作放在这里
prvInitialiseTaskLists();
}
else
{
mtCOVERAGE_TEST_MARKER();
}
}
else//若当前任务TCB不为空,即存在相应任务
{
//若调度器已经没有运行,若新建任务的优先级为到目前为止的最高优先级即将其设为当前任务
if( xSchedulerRunning == pdFALSE )//系统调度器没有运行
{
if( pxCurrentTCB->uxPriority <= uxPriority )//若当前任务的优先级不大于新建任务的优先级
{
pxCurrentTCB = pxNewTCB;//将新建任务TCB设为当前任务TCB
}
else
{
mtCOVERAGE_TEST_MARKER();
}
}
else
{
mtCOVERAGE_TEST_MARKER();
}
}
uxTaskNumber++;//任务的数量加1
#if ( configUSE_TRACE_FACILITY == 1 )
{
pxNewTCB->uxTCBNumber = uxTaskNumber;//将任务数量保存到TCB中,主要用以调试。
}
#endif
traceTASK_CREATE( pxNewTCB );
prvAddTaskToReadyList( pxNewTCB );//将新建任务插入到就绪链表中。
xReturn = pdPASS;//返回值为成功
portSETUP_TCB( pxNewTCB );
}
taskEXIT_CRITICAL();
}
else//若TCB为空,即分配不成功
{
xReturn = errCOULD_NOT_ALLOCATE_REQUIRED_MEMORY;//返回值为不能成功分到要求的内存空间
traceTASK_CREATE_FAILED();
}
if( xReturn == pdPASS )//若返回值为成功,即能够创建好任务
{
if( xSchedulerRunning != pdFALSE )//若任务调度器正在运行
{
//若当前任务的优先级小于新建任务的优先级
if( pxCurrentTCB->uxPriority < uxPriority )
{
taskYIELD_IF_USING_PREEMPTION();// 新任务比当前正在运行的任务优先级高,因此要做任务调度
}
else
{
mtCOVERAGE_TEST_MARKER();
}
}
else
{
mtCOVERAGE_TEST_MARKER();
}
}
return xReturn;//将任务的返回值送出。
}
FreeRTOS(V8.0.1)系统之xTaskGenericCreate()
最新推荐文章于 2022-12-30 17:41:51 发布