您的位置:首页 > 其它

FreeRTOS源码解析 -> xTaskCreate()

2014-12-31 15:57 393 查看
 xTaskGenericCreate( pdTASK_CODEpxTaskCode,            /* 指向任务函数的指针*/ 

                                          const signed char *const pcName,          /* 任务的文本名字,只会在调试中用到*/ 

                                          unsigned shortusStackDepth,                  /* 栈深度– 大多数小型微控制器会使用的值会比此值小得多*/ 

                                          void *pvParameters,                                   /* 传入的参数*/

                                          unsigned portBASE_TYPEuxPriority,     /* 任务优先级 */    

                                          xTaskHandle *pxCreatedTask);               /* 任务句柄*/           

signed portBASE_TYPE xTaskGenericCreate( pdTASK_CODE pxTaskCode, const signed char * const pcName, unsigned short usStackDepth, void *pvParameters, unsigned portBASE_TYPE uxPriority, xTaskHandle *pxCreatedTask, portSTACK_TYPE *puxStackBuffer, const xMemoryRegion * const xRegions )
{
signed portBASE_TYPE xReturn;
tskTCB * pxNewTCB; //指向分配的栈空间

configASSERT( pxTaskCode ); //Task函数指针
/*这里要确定uxPriority比设定的最大优先级小*/
configASSERT( ( uxPriority < configMAX_PRIORITIES ) );

/* Allocate the memory required by the TCB and stack for the new task,
checking that the allocation was successful. */
//任务控制块(Task Control Block)和栈 ->分配空间,TCB用来记录现场
pxNewTCB = prvAllocateTCBAndStack( usStackDepth, puxStackBuffer );

if( pxNewTCB != NULL )
{
portSTACK_TYPE *pxTopOfStack;

#if( portUSING_MPU_WRAPPERS == 1 )
/* Should the task be created in privileged mode? */
portBASE_TYPE xRunPrivileged;
if( ( uxPriority & portPRIVILEGE_BIT ) != 0x00 )
{
xRunPrivileged = pdTRUE;
}
else
{
xRunPrivileged = pdFALSE;
}
uxPriority &= ~portPRIVILEGE_BIT;
#endif /* portUSING_MPU_WRAPPERS == 1 */

/* Calculate the top of stack address.  This depends on whether the
stack grows from high memory to low (as per the 80x86) or visa versa.
portSTACK_GROWTH is used to make the result positive or negative as
required by the port. */
//堆栈的生长方向,从高地址到低地址
//根据大小端选择
//根据宏portSTACK_GROWTH设定的值来分配堆栈空间
#if( portSTACK_GROWTH < 0 )
{
pxTopOfStack = pxNewTCB->pxStack + ( usStackDepth - ( unsigned short ) 1 );
pxTopOfStack = ( portSTACK_TYPE * ) ( ( ( unsigned long ) pxTopOfStack ) & ( ( unsigned long ) ~portBYTE_ALIGNMENT_MASK  ) );

/* Check the alignment of the calculated top of stack is correct. */
configASSERT( ( ( ( unsigned long ) pxTopOfStack & ( unsigned long ) portBYTE_ALIGNMENT_MASK ) == 0UL ) );
}
//堆栈的生长方向,从低地址到高地址
#else
{
pxTopOfStack = pxNewTCB->pxStack;

/* Check the alignment of the stack buffer is correct. */
configASSERT( ( ( ( unsigned long ) pxNewTCB->pxStack & ( unsigned long ) portBYTE_ALIGNMENT_MASK ) == 0UL ) );

/* If we want to use stack checking on architectures that use
a positive stack growth direction then we also need to store the
other extreme of the stack space. */
pxNewTCB->pxEndOfStack = pxNewTCB->pxStack + ( usStackDepth - 1 );
}
#endif

/* Setup the newly allocated TCB with the initial state of the task. */
//初始化任务控制块变量
prvInitialiseTCBVariables( pxNewTCB, pcName, uxPriority, xRegions, usStackDepth );

/* Initialize the TCB stack to look as if the task was already running,
but had been interrupted by the scheduler.  The return address is set
to the start of the task function. Once the stack has been initialised
the	top of stack variable is updated. */
#if( portUSING_MPU_WRAPPERS == 1 )
{
pxNewTCB->pxTopOfStack = pxPortInitialiseStack( pxTopOfStack, pxTaskCode, pvParameters, xRunPrivileged );
}
#else
{
//栈内容赋值,将代码保存入栈
pxNewTCB->pxTopOfStack = pxPortInitialiseStack( pxTopOfStack, pxTaskCode, pvParameters );
}
#endif

/* Check the alignment of the initialised stack. */
configASSERT( ( ( ( unsigned long ) pxNewTCB->pxTopOfStack & ( unsigned long ) portBYTE_ALIGNMENT_MASK ) == 0UL ) );

//返回任务的句柄,后面有需要的话可以根据这个句柄来删除task或者改变优先级
if( ( void * ) pxCreatedTask != NULL )
{
/* Pass the TCB out - in an anonymous way.  The calling function/
task can use this as a handle to delete the task later if
required.*/
*pxCreatedTask = ( xTaskHandle ) pxNewTCB;
}

/* We are going to manipulate the task queues to add this task to a
ready list, so must make sure no interrupts occur. */
//现在要将这个task加入ready list,so关闭所有中断
taskENTER_CRITICAL(); //用汇编关闭所有中断!
{
uxCurrentNumberOfTasks++;
if( pxCurrentTCB == NULL )
{
/* There are no other tasks, or all the other tasks are in
the suspended state - make this the current task. */
//当前没有运行其他task或者其他task都处于挂起状态。则这个新的task就是current task
pxCurrentTCB =  pxNewTCB;

//如果这是第一个任务
if( uxCurrentNumberOfTasks == ( unsigned portBASE_TYPE ) 1 )
{
/* This is the first task to be created so do the preliminary
initialisation required.  We will not recover if this call
fails, but we will report the failure. */
//链表的初始化
prvInitialiseTaskLists();
}
}
//当前有任务在运行
else
{
/* If the scheduler is not already running, make this task the
current task if it is the highest priority task to be created
so far. */
//调度器没有工作
if( xSchedulerRunning == pdFALSE )
{
//如果新建的task的优先级比当前任务优先级高,进行抢占。
if( pxCurrentTCB->uxPriority <= uxPriority )
{
pxCurrentTCB = pxNewTCB;
}
}
}

/* Remember the top priority to make context switching faster.  Use
the priority in pxNewTCB as this has been capped to a valid value. */
//记录最高的优先级
if( pxNewTCB->uxPriority > uxTopUsedPriority )
{
uxTopUsedPriority = pxNewTCB->uxPriority;
}

#if ( configUSE_TRACE_FACILITY == 1 )
{
/* Add a counter into the TCB for tracing only. */
pxNewTCB->uxTCBNumber = uxTaskNumber;
}
#endif
uxTaskNumber++;

prvAddTaskToReadyQueue( pxNewTCB ); //pxNewTCB加入ready queue就绪队列

xReturn = pdPASS;
traceTASK_CREATE( pxNewTCB );
}
//新建的task加入ready queue后,开启中断
taskEXIT_CRITICAL();
}

//创建任务失败
else
{
xReturn = errCOULD_NOT_ALLOCATE_REQUIRED_MEMORY;
traceTASK_CREATE_FAILED();
}

//判断创建任务是否成功
if( xReturn == pdPASS )
{
//调度器是否开始了任务调度
if( xSchedulerRunning != pdFALSE )
{
/* If the created task is of a higher priority than the current task
then it should run now. */
//根据优先级判断是否要对任务进行切换
if( pxCurrentTCB->uxPriority < uxPriority )
{
//当前运行任务的优先级小于新建的任务
//切换任务
//SysTick exception is pending
//用在中断环境中的强制上下文切换
portYIELD_WITHIN_API();
}
}
}

return xReturn;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息