本文已参加「新人创造礼」活动,一起敞开创造之路。
在了解了根本的环境和结构之后,对FreeRTOS 的使命,音讯行列,信号量,事情,软件定时器
这些基础的功能部分也得有个知道。
这篇文章首要介绍了一下关于使命的API以及源码的简单剖析。
说明:FreeRTOS 专栏与我的 RT-Thread 专栏不同,我的 RT-Thread 专栏是从理论学习一步一步循序渐进,从 0 起步的 完整教育,而 FreeRTOS 更偏向于 我直接拿来运用,需求用到什么,然后引出知识点,在运用中发现问题,解然后再解决问题。
FreeRTOS 使命API
来知道一下FreeRTOS的常用使命API:
API称号 | CMSIS封装的API | API说明 |
---|---|---|
xTaskCreate | osThreadCreate | 动态创立使命 |
xTaskCreateStatic | osThreadCreate | 静态创立使命 |
vTaskDelete | osThreadTerminate | 删去使命 |
vTaskSuspend | osThreadSuspend | 挂起使命 |
vTaskResume | osThreadResume | 康复使命 |
xTaskResumeFromISR | osThreadResume | 在中止中康复使命 |
uxTaskPriorityGet | osThreadGetPriority | 获取使命优先级 |
vTaskPrioritySet | osThreadSetPriority | 设置使命优先级 |
vTaskDelay | osDelay | 相对延时使命 |
vTaskDelayuntil | osDelayUntil | 肯定延时使命 |
创立使命
使命创立分为动态xTaskCreate
和静态xTaskCreateStatic
,但是在CubeMX中经过封装后统一运用的是osThreadCreate
,可以查看一下osThreadCreate
完成:
/*********************** Thread Management *****************************/
/**
* @brief Create a thread and add it to Active Threads and set it to state READY.
* @param thread_def thread definition referenced with \ref osThread.
* @param argument pointer that is passed to the thread function as start argument.
* @retval thread ID for reference by other functions or NULL in case of error.
* @note MUST REMAIN UNCHANGED: \b osThreadCreate shall be consistent in every CMSIS-RTOS.
*/
osThreadId osThreadCreate (const osThreadDef_t *thread_def, void *argument)
{
TaskHandle_t handle;
#if( configSUPPORT_STATIC_ALLOCATION == 1 ) && ( configSUPPORT_DYNAMIC_ALLOCATION == 1 )
if((thread_def->buffer != NULL) && (thread_def->controlblock != NULL)) {
handle = xTaskCreateStatic((TaskFunction_t)thread_def->pthread,(const portCHAR *)thread_def->name,
thread_def->stacksize, argument, makeFreeRtosPriority(thread_def->tpriority),
thread_def->buffer, thread_def->controlblock);
}
else {
if (xTaskCreate((TaskFunction_t)thread_def->pthread,(const portCHAR *)thread_def->name,
thread_def->stacksize, argument, makeFreeRtosPriority(thread_def->tpriority),
&handle) != pdPASS) {
return NULL;
}
}
#elif( configSUPPORT_STATIC_ALLOCATION == 1 )
handle = xTaskCreateStatic((TaskFunction_t)thread_def->pthread,(const portCHAR *)thread_def->name,
thread_def->stacksize, argument, makeFreeRtosPriority(thread_def->tpriority),
thread_def->buffer, thread_def->controlblock);
#else
if (xTaskCreate((TaskFunction_t)thread_def->pthread,(const portCHAR *)thread_def->name,
thread_def->stacksize, argument, makeFreeRtosPriority(thread_def->tpriority),
&handle) != pdPASS) {
return NULL;
}
#endif
return handle;
}
由上可以得知,CubeMX生成的osThreadCreate
会依据咱们在Config Parameters
中的Memory Allocation
内存分配中挑选的装备结果自动的挑选xTaskCreate
还是xTaskCreateStatic
。
xTaskCreate
xTaskCreateStatic
删去使命
vTaskDelete
封装后是osThreadTerminate
,如下:
osStatus osThreadTerminate (osThreadId thread_id)
{
#if (INCLUDE_vTaskDelete == 1)
vTaskDelete(thread_id);
return osOK;
#else
return osErrorOS;
#endif
}
参数为NULL vTaskDelete(NULL)
是删去使命自己
挂起使命
void vTaskSuspend( TaskHandle_t xTaskToSuspend )
传入的参数是 使命句柄
vTaskSuspend
封装后是osThreadSuspend
,如下:
//
osStatus osThreadSuspend (osThreadId thread_id)
{
#if (INCLUDE_vTaskSuspend == 1)
vTaskSuspend(thread_id);
return osOK;
#else
return osErrorResource;
#endif
}
参数为NULL vTaskSuspend(NULL)
是挂起使命自己
osThreadSuspendAll
挂起一切使命
osStatus osThreadSuspendAll (void)
{
vTaskSuspendAll();
return osOK;
}
康复使命
vTaskResume
在使命中康复使命(将使命从挂起状态康复到安排妥当态)
和xTaskResumeFromISR
在中止中康复使命封装后是osThreadResume
,如下:
osStatus osThreadResume (osThreadId thread_id)
{
#if (INCLUDE_vTaskSuspend == 1)
if(inHandlerMode())
{
if (xTaskResumeFromISR(thread_id) == pdTRUE)
{
portYIELD_FROM_ISR(pdTRUE);
}
}
else
{
vTaskResume(thread_id);
}
return osOK;
#else
return osErrorResource;
#endif
}
osThreadResumeAll
康复一切使命
osStatus osThreadResumeAll (void)
{
if (xTaskResumeAll() == pdTRUE)
return osOK;
else
return osErrorOS;
}
使命优先级
uxTaskPriorityGet
获取使命优先级 封装后是osThreadGetPriority
,还有一个从中止中获取没有写出来,但是经过封装后的函数可以看出来:
osPriority osThreadGetPriority (osThreadId thread_id)
{
#if (INCLUDE_uxTaskPriorityGet == 1)
if (inHandlerMode())
{
return makeCmsisPriority(uxTaskPriorityGetFromISR(thread_id));
}
else
{
return makeCmsisPriority(uxTaskPriorityGet(thread_id));
}
#else
return osPriorityError;
#endif
}
vTaskPrioritySet
设置使命优先级 封装后是osThreadSetPriority
,如下:
osStatus osThreadSetPriority (osThreadId thread_id, osPriority priority)
{
#if (INCLUDE_vTaskPrioritySet == 1)
vTaskPrioritySet(thread_id, makeFreeRtosPriority(priority));
return osOK;
#else
return osErrorOS;
#endif
}
延时使命
vTaskDelay
相对延时封装后osDelay
,如下:
/*********************** Generic Wait Functions *******************************/
/**
* @brief Wait for Timeout (Time Delay)
* @param millisec time delay value
* @retval status code that indicates the execution status of the function.
*/
osStatus osDelay (uint32_t millisec)
{
#if INCLUDE_vTaskDelay
TickType_t ticks = millisec / portTICK_PERIOD_MS;
vTaskDelay(ticks ? ticks : 1); /* Minimum delay = 1 tick */
return osOK;
#else
(void) millisec;
return osErrorResource;
#endif
}
vTaskDelayuntil
肯定延时封装后osDelayUntil
,如下:
/**
* @brief Delay a task until a specified time
* @param PreviousWakeTime Pointer to a variable that holds the time at which the
* task was last unblocked. PreviousWakeTime must be initialised with the current time
* prior to its first use (PreviousWakeTime = osKernelSysTick() )
* @param millisec time delay value
* @retval status code that indicates the execution status of the function.
*/
osStatus osDelayUntil (uint32_t *PreviousWakeTime, uint32_t millisec)
{
#if INCLUDE_vTaskDelayUntil
TickType_t ticks = (millisec / portTICK_PERIOD_MS);
vTaskDelayUntil((TickType_t *) PreviousWakeTime, ticks ? ticks : 1);
return osOK;
#else
(void) millisec;
(void) PreviousWakeTime;
return osErrorResource;
#endif
}
FreeRTOS 使命源码简析
使命状态
在剖析使命源码之前,先得了解一下FreeRTOS中使命的四种根本状态: 运转态,挂起态,堵塞态,安排妥当态。
在官方文档中:
使命操控块
FreeRTOS 的每个使命都有一些特点需求存储,把这些特点调集在一起的结构体叫做使命操控块TCB_t (Task control block),源码如下:
/*
* Task control block. A task control block (TCB) is allocated for each task,
* and stores task state information, including a pointer to the task's context
* (the task's run time environment, including register values)
*/
typedef struct tskTaskControlBlock
{
volatile StackType_t *pxTopOfStack; /*< Points to the location of the last item placed on the tasks stack. THIS MUST BE THE FIRST MEMBER OF THE TCB STRUCT. */
#if ( portUSING_MPU_WRAPPERS == 1 )
xMPU_SETTINGS xMPUSettings; /*< The MPU settings are defined as part of the port layer. THIS MUST BE THE SECOND MEMBER OF THE TCB STRUCT. */
#endif
ListItem_t xStateListItem; /*< The list that the state list item of a task is reference from denotes the state of that task (Ready, Blocked, Suspended ). */
ListItem_t xEventListItem; /*< Used to reference a task from an event list. */
UBaseType_t uxPriority; /*< The priority of the task. 0 is the lowest priority. */
StackType_t *pxStack; /*< Points to the start of the stack. */
char pcTaskName[ configMAX_TASK_NAME_LEN ];/*< Descriptive name given to the task when created. Facilitates debugging only. */ /*lint !e971 Unqualified char types are allowed for strings and single characters only. */
#if ( ( portSTACK_GROWTH > 0 ) || ( configRECORD_STACK_HIGH_ADDRESS == 1 ) )
StackType_t *pxEndOfStack; /*< Points to the highest valid address for the stack. */
#endif
#if ( portCRITICAL_NESTING_IN_TCB == 1 )
UBaseType_t uxCriticalNesting; /*< Holds the critical section nesting depth for ports that do not maintain their own count in the port layer. */
#endif
#if ( configUSE_TRACE_FACILITY == 1 )
UBaseType_t uxTCBNumber; /*< Stores a number that increments each time a TCB is created. It allows debuggers to determine when a task has been deleted and then recreated. */
UBaseType_t uxTaskNumber; /*< Stores a number specifically for use by third party trace code. */
#endif
#if ( configUSE_MUTEXES == 1 )
UBaseType_t uxBasePriority; /*< The priority last assigned to the task - used by the priority inheritance mechanism. */
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; /*< Stores the amount of time the task has spent in the Running state. */
#endif
#if ( configUSE_NEWLIB_REENTRANT == 1 )
/* Allocate a Newlib reent structure that is specific to this task.
Note Newlib support has been included by popular demand, but is not
used by the FreeRTOS maintainers themselves. FreeRTOS is not
responsible for resulting newlib operation. User must be familiar with
newlib and must provide system-wide implementations of the necessary
stubs. Be warned that (at the time of writing) the current newlib design
implements a system-wide malloc() that must be provided with locks. */
struct _reent xNewLib_reent;
#endif
#if( configUSE_TASK_NOTIFICATIONS == 1 )
volatile uint32_t ulNotifiedValue;
volatile uint8_t ucNotifyState;
#endif
/* See the comments above the definition of
tskSTATIC_AND_DYNAMIC_ALLOCATION_POSSIBLE. */
#if( tskSTATIC_AND_DYNAMIC_ALLOCATION_POSSIBLE != 0 ) /*lint !e731 Macro has been consolidated for readability reasons. */
uint8_t ucStaticallyAllocated; /*< Set to pdTRUE if the task is a statically allocated to ensure no attempt is made to free the memory. */
#endif
#if( INCLUDE_xTaskAbortDelay == 1 )
uint8_t ucDelayAborted;
#endif
} tskTCB;
/* The old tskTCB name is maintained above then typedefed to the new TCB_t name
below to enable the use of older kernel aware debuggers. */
typedef tskTCB TCB_t;
pxTopOfStack | 使命仓库栈顶 |
---|---|
xStateListItem | 状态列表项 |
xEventListItem | 事情列表项 |
uxPriority | 使命优先级 |
*pxStack | 使命栈开始地址 |
pcTaskName[16] | 使命称号 |
*pxEndOfStack | 使命仓库栈底 |
状态列表项 : 每个使命都有4种状态,FreeRTOS 运用一种高效的数据结构双向链表保存使命的状态,Linux中也是。
事情列表项 : 信号量,音讯行列,软件定时器等事情的办理
使命创立流程剖析
使命创立流程如下图所示: 在剖析FreeRTOS 使命创立源码之前,咱们得先了解一下栈的不同类型。
栈的四种类型
不同的硬件渠道stack的增加方法不同,总的来说是有4种增加方法:
满减栈、满增栈、空减栈、空增栈。
满减栈:栈指针指向最终压入栈的数据,数据入栈时,sp先减一再入栈。
满增栈:栈指针指向最终压入栈的数据,数据入栈时,sp先加一再入栈。
空减栈:栈指针指向下一个即将放入数据的方位,数据入栈时,先入栈sp再减一。
空增栈:栈指针指向下一个即将放入数据的方位,数据入栈时,先入栈sp再加一。
满栈进栈是先移动指针再存;满栈出栈是先出数据再移动指针;
空栈进栈先存再移动指针;空栈出栈先移动指针再取数据。
ARM M3,M4内核运用的是 满减栈。
使命创立源码剖析
咱们在源码中直接运用注释剖析:
#if( configSUPPORT_DYNAMIC_ALLOCATION == 1 )
BaseType_t xTaskCreate( TaskFunction_t pxTaskCode,
const char * const pcName, /*lint !e971 Unqualified char types are allowed for strings and single characters only. */
const configSTACK_DEPTH_TYPE usStackDepth,
void * const pvParameters,
UBaseType_t uxPriority,
TaskHandle_t * const pxCreatedTask )
{
TCB_t *pxNewTCB;
BaseType_t xReturn;
/* If the stack grows down then allocate the stack then the TCB so the stack
does not grow into the TCB. Likewise if the stack grows up then allocate
the TCB then the stack.
依据自己的硬件渠道仓库增加方法来判别运用那一部分编译,
仓库增加方法:
1、满减栈
2、满增栈
3、空减栈
4、空增栈
#define portSTACK_GROWTH ( -1 )
表明满减栈
*/
#if( portSTACK_GROWTH > 0 )
{
/* Allocate space for the TCB. Where the memory comes from depends on
the implementation of the port malloc function and whether or not static
allocation is being used.
使命栈内存分配
*/
pxNewTCB = ( TCB_t * ) pvPortMalloc( sizeof( TCB_t ) );
if( pxNewTCB != NULL )
{
/* Allocate space for the stack used by the task being created.
The base of the stack memory stored in the TCB so the task can
be deleted later if required.
使命操控块内存分配
*/
pxNewTCB->pxStack = ( StackType_t * ) pvPortMalloc( ( ( ( size_t ) usStackDepth ) * sizeof( StackType_t ) ) ); /*lint !e961 MISRA exception as the casts are only redundant for some ports. */
if( pxNewTCB->pxStack == NULL )
{
/* Could not allocate the stack. Delete the allocated TCB. */
vPortFree( pxNewTCB );
pxNewTCB = NULL;
}
}
}
#else
/* portSTACK_GROWTH */
/*
M3,M4中运用的下面这种
#define portSTACK_TYPE uint32_t
typedef portSTACK_TYPE StackType_t;
每个内存是4个字节(StackType_t),所以创立仓库是依照字来分配的
默许的是128 x 4 = 512字节;
*/
{
StackType_t *pxStack;
/* Allocate space for the stack used by the task being created. */
pxStack = ( StackType_t * ) pvPortMalloc( ( ( ( size_t ) usStackDepth ) * sizeof( StackType_t ) ) ); /*lint !e961 MISRA exception as the casts are only redundant for some ports. */
if( pxStack != NULL )
{
/*
Allocate space for the TCB.
依据TCB的巨细还得分配空间
*/
pxNewTCB = ( TCB_t * ) pvPortMalloc( sizeof( TCB_t ) ); /*lint !e961 MISRA exception as the casts are only redundant for some paths. */
if( pxNewTCB != NULL )
{
/* Store the stack location in the TCB.
赋值栈地址
*/
pxNewTCB->pxStack = pxStack;
}
else
{
/* The stack cannot be used as the TCB was not created. Free
it again.
开释栈空间
*/
vPortFree( pxStack );
}
}
else
{
pxNewTCB = NULL;
}
}
#endif /* portSTACK_GROWTH */
if( pxNewTCB != NULL )
{
#if( tskSTATIC_AND_DYNAMIC_ALLOCATION_POSSIBLE != 0 ) /*lint !e731 Macro has been consolidated for readability reasons. */
{
/* Tasks can be created statically or dynamically, so note this
task was created dynamically in case it is later deleted. */
pxNewTCB->ucStaticallyAllocated = tskDYNAMICALLY_ALLOCATED_STACK_AND_TCB;
}
#endif /* configSUPPORT_STATIC_ALLOCATION */
/*
新建使命初始化
初始化使命操控块
初始化使命仓库
*/
prvInitialiseNewTask( pxTaskCode, pcName, ( uint32_t ) usStackDepth, pvParameters, uxPriority, pxCreatedTask, pxNewTCB, NULL );
/*
把使命添加到安排妥当列表中
*/
prvAddNewTaskToReadyList( pxNewTCB );
xReturn = pdPASS;
}
else
{
xReturn = errCOULD_NOT_ALLOCATE_REQUIRED_MEMORY;
}
return xReturn;
}
#endif /* configSUPPORT_DYNAMIC_ALLOCATION */
使命删去流程剖析
临界段
一种维护机制,代码的临界段也称为临界区,指处理时不可分割的代码区域,一旦这部分代码开始履行,则不允许任何中止打断。为确保临界段代码的履行不被中止,在进入临界段之前须关中止,而临界段代码履行结束后,要当即翻开中止。
在OS中,除了外部中止能将正在运转的代码打断,还有线程的调度——PendSV,体系产生 PendSV中止,在 PendSV Handler 里边完成线程的切换。咱们要将这项东西屏蔽掉,确保当时只有一个线程在运用临界资源。
FreeRTOS对中止的开和关是经过操作 BASEPRI 寄存器来完成的,即大于等于 BASEPRI 的值的中止会被屏蔽,小于 BASEPRI 的值的中止则不会被屏蔽。这样子的好处就是用户可以设置 BASEPRI 的值来挑选性的给一些非常紧迫的中止留一条后路。
FreeRTOS 进入临界段 屏蔽中止:
/*-----------------------------------------------------------*/
portFORCE_INLINE static void vPortRaiseBASEPRI( void )
{
uint32_t ulNewBASEPRI;
__asm volatile
(
" mov %0, %1 \n" \
" msr basepri, %0 \n" \
" isb \n" \
" dsb \n" \
:"=r" (ulNewBASEPRI) : "i" ( configMAX_SYSCALL_INTERRUPT_PRIORITY ) : "memory"
);
}
FreeRTOS 退出临界段 翻开中止:
*-----------------------------------------------------------*/
portFORCE_INLINE static void vPortSetBASEPRI( uint32_t ulNewMaskValue )
{
__asm volatile
(
" msr basepri, %0 " :: "r" ( ulNewMaskValue ) : "memory"
);
}
使命删去源码剖析
咱们在源码中直接运用注释剖析:
#if ( INCLUDE_vTaskDelete == 1 )
void vTaskDelete( TaskHandle_t xTaskToDelete )
{
TCB_t *pxTCB;
/*
进入临界段
*/
taskENTER_CRITICAL();
{
/* If null is passed in here then it is the calling task that is
being deleted.
获取使命操控块 -----参数传入的是使命句柄
判别是使命自身,还是其他使命
*/
pxTCB = prvGetTCBFromHandle( xTaskToDelete );
/*
Remove task from the ready list.
从安排妥当列表中移除
*/
if( uxListRemove( &( pxTCB->xStateListItem ) ) == ( UBaseType_t ) 0 )
{
taskRESET_READY_PRIORITY( pxTCB->uxPriority );
}
else
{
mtCOVERAGE_TEST_MARKER();
}
/*
Is the task waiting on an event also?
从事情列表中移除
*/
if( listLIST_ITEM_CONTAINER( &( pxTCB->xEventListItem ) ) != NULL )
{
( void ) uxListRemove( &( pxTCB->xEventListItem ) );
}
else
{
mtCOVERAGE_TEST_MARKER();
}
/* Increment the uxTaskNumber also so kernel aware debuggers can
detect that the task lists need re-generating. This is done before
portPRE_TASK_DELETE_HOOK() as in the Windows port that macro will
not return. */
uxTaskNumber++;
/*
假如是删去当时使命
*/
if( pxTCB == pxCurrentTCB )
{
/* A task is deleting itself. This cannot complete within the
task itself, as a context switch to another task is required.
Place the task in the termination list. The idle task will
check the termination list and free up any memory allocated by
the scheduler for the TCB and stack of the deleted task.
删去使命自身不能当即删去,在闲暇使命中删去
就把使命添加到等候删去的使命列表中
*/
vListInsertEnd( &xTasksWaitingTermination, &( pxTCB->xStateListItem ) );
/* Increment the ucTasksDeleted variable so the idle task knows
there is a task that has been deleted and that it should therefore
check the xTasksWaitingTermination list.
给空间使命一个标记
*/
++uxDeletedTasksWaitingCleanUp;
/* The pre-delete hook is primarily for the Windows simulator,
in which Windows specific clean up operations are performed,
after which it is not possible to yield away from this task -
hence xYieldPending is used to latch that a context switch is
required.
钩子函数----用户自己完成
*/
portPRE_TASK_DELETE_HOOK( pxTCB, &xYieldPending );
}
else
{
--uxCurrentNumberOfTasks;
prvDeleteTCB( pxTCB );
/* Reset the next expected unblock time in case it referred to
the task that has just been deleted.
复位使命锁定时刻 ----时刻片 操作体系会记载一个最新的时刻,
依据最新的时刻,进行调度,所以删去使命后,要更新锁定时刻
*/
prvResetNextTaskUnblockTime();
}
traceTASK_DELETE( pxTCB );
}
/*退出临界段*/
taskEXIT_CRITICAL();
/* Force a reschedule if it is the currently running task that has just been deleted.
判别调度器是否敞开
*/
if( xSchedulerRunning != pdFALSE )
{
/*
假如是删去使命自身,立刻进行使命调度(开释CPU的运用权)
*/
if( pxTCB == pxCurrentTCB )
{
configASSERT( uxSchedulerSuspended == 0 );
portYIELD_WITHIN_API();
}
else
{
mtCOVERAGE_TEST_MARKER();
}
}
}
#endif /* INCLUDE_vTaskDelete */
使命挂起
咱们在源码中直接运用注释剖析:
#if ( INCLUDE_vTaskSuspend == 1 )
void vTaskSuspend( TaskHandle_t xTaskToSuspend )
{
TCB_t *pxTCB;
/*
进入临界段
*/
taskENTER_CRITICAL();
{
/* If null is passed in here then it is the running task that is
being suspended.
获取使命操控块
*/
pxTCB = prvGetTCBFromHandle( xTaskToSuspend );
traceTASK_SUSPEND( pxTCB );
/* Remove task from the ready/delayed list and place in the
suspended list.
从安排妥当列表中删去
*/
if( uxListRemove( &( pxTCB->xStateListItem ) ) == ( UBaseType_t ) 0 )
{
taskRESET_READY_PRIORITY( pxTCB->uxPriority );
}
else
{
mtCOVERAGE_TEST_MARKER();
}
/* Is the task waiting on an event also?
从事情列表中移除
*/
if( listLIST_ITEM_CONTAINER( &( pxTCB->xEventListItem ) ) != NULL )
{
( void ) uxListRemove( &( pxTCB->xEventListItem ) );
}
else
{
mtCOVERAGE_TEST_MARKER();
}
/*
把使命添加到挂起列表中
*/
vListInsertEnd( &xSuspendedTaskList, &( pxTCB->xStateListItem ) );
#if( configUSE_TASK_NOTIFICATIONS == 1 )
{
if( pxTCB->ucNotifyState == taskWAITING_NOTIFICATION )
{
/* The task was blocked to wait for a notification, but is
now suspended, so no notification was received. */
pxTCB->ucNotifyState = taskNOT_WAITING_NOTIFICATION;
}
}
#endif
}
/*
退出临界段
*/
taskEXIT_CRITICAL();
/*
判别调度器是否开始
看看是否有更高优先级的使命
*/
if( xSchedulerRunning != pdFALSE )
{
/* Reset the next expected unblock time in case it referred to the
task that is now in the Suspended state. */
taskENTER_CRITICAL();
{
prvResetNextTaskUnblockTime();
}
taskEXIT_CRITICAL();
}
else
{
mtCOVERAGE_TEST_MARKER();
}
if( pxTCB == pxCurrentTCB )
{
if( xSchedulerRunning != pdFALSE )
{
/* The current task has just been suspended.
直接进行使命调度,开释CPU
*/
configASSERT( uxSchedulerSuspended == 0 );
portYIELD_WITHIN_API();
}
else
{
/* The scheduler is not running, but the task that was pointed
to by pxCurrentTCB has just been suspended and pxCurrentTCB
must be adjusted to point to a different task.
调度器没有敞开,pxCurrentTCB必须指向别的一个不同的task
由于这个使命被挂起了
*/
if( listCURRENT_LIST_LENGTH( &xSuspendedTaskList ) == uxCurrentNumberOfTasks )
{
/* No other tasks are ready, so set pxCurrentTCB back to
NULL so when the next task is created pxCurrentTCB will
be set to point to it no matter what its relative priority
is.
没有使命预备,把当时的使命操控块复制为NULL
*/
pxCurrentTCB = NULL;
}
else
{
/*手动进行调度,在安排妥当列表中找到优先级最高的使命*/
vTaskSwitchContext();
}
}
}
else
{
mtCOVERAGE_TEST_MARKER();
}
}
#endif /* INCLUDE_vTaskSuspend */
使命康复
咱们在源码中直接运用注释剖析:
#if ( INCLUDE_vTaskSuspend == 1 )
void vTaskResume( TaskHandle_t xTaskToResume )
{
/*获取要康复的使命操控块*/
TCB_t * const pxTCB = ( TCB_t * ) xTaskToResume;
/* It does not make sense to resume the calling task.
检查*/
configASSERT( xTaskToResume );
/* The parameter cannot be NULL as it is impossible to resume the
currently executing task.
康复的话不能是NULL或当时的使命 */
if( ( pxTCB != NULL ) && ( pxTCB != pxCurrentTCB ) )
{
/*进入临界段*/
taskENTER_CRITICAL();
{
/*判别使命是否现已挂起*/
if( prvTaskIsTaskSuspended( pxTCB ) != pdFALSE )
{
traceTASK_RESUME( pxTCB );
/* The ready list can be accessed even if the scheduler is
suspended because this is inside a critical section.
从挂起列表中移除
*/
( void ) uxListRemove( &( pxTCB->xStateListItem ) );
/*添加到安排妥当列表*/
prvAddTaskToReadyList( pxTCB );
/* A higher priority task may have just been resumed.
判别要康复的使命优先级是否大于当时使命的优先级,
假如大于,开释CPU运用权,开始内核调度
*/
if( pxTCB->uxPriority >= pxCurrentTCB->uxPriority )
{
/* This yield may not cause the task just resumed to run,
but will leave the lists in the correct state for the
next yield. */
taskYIELD_IF_USING_PREEMPTION();
}
else
{
mtCOVERAGE_TEST_MARKER();
}
}
else
{
mtCOVERAGE_TEST_MARKER();
}
}
/*退出临界段*/
taskEXIT_CRITICAL();
}
else
{
mtCOVERAGE_TEST_MARKER();
}
}
#endif /* INCLUDE_vTaskSuspend */