任务挂起的主要工作包括:
将任务从状态列表中移除并挂接到挂起列表中
更新任务唤醒时间
如果挂起当前任务,需要请求切换
/* 挂起任务 */
void vTaskSuspend(TaskHandle_t xTaskToSuspend)
{
TCB_t *pxTCB;
/* 进入临界区 */
taskENTER_CRITICAL();
{
/* 通过任务句柄获取任务TCB */
pxTCB = prvGetTCBFromHandle(xTaskToSuspend);
traceTASK_SUSPEND(pxTCB);
/* 将任务从状态列表中移除,状态列表中没有任何任务 */
if(uxListRemove(&(pxTCB->xStateListItem)) == (UBaseType_t)0)
{
/* 检查该优先级就绪列表中是否有任务,如果没有将该优先级从当前任务优先级记录中清除 */
taskRESET_READY_PRIORITY(pxTCB->uxPriority);
}
else
{
mtCOVERAGE_TEST_MARKER();
}
/* 任务被挂接在事件列表中 */
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)
{
pxTCB->ucNotifyState = taskNOT_WAITING_NOTIFICATION;
}
}
#endif
}
/* 退出临界区 */
taskEXIT_CRITICAL();
/* 当前调度器正在运行 */
if(xSchedulerRunning != pdFALSE)
{
/* 进入临界区 */
taskENTER_CRITICAL();
{
/* 更新下一个要解除阻塞的时间,防止该任务就是最近需要唤醒的任务 */
prvResetNextTaskUnblockTime();
}
/* 退出临界区 */
taskEXIT_CRITICAL();
}
else
{
mtCOVERAGE_TEST_MARKER();
}
/* 该任务为当前任务 */
if(pxTCB == pxCurrentTCB)
{
/* 调度器正在运行 */
if(xSchedulerRunning != pdFALSE)
{
configASSERT(uxSchedulerSuspended == 0);
/* 请求切换任务 */
portYIELD_WITHIN_API();
}
/* 调度器没有正在运行 */
else
{
/* 所有任务都被挂起 */
if(listCURRENT_LIST_LENGTH(&xSuspendedTaskList) == uxCurrentNumberOfTasks)
{
/* 没有当前任务可以运行了 */
pxCurrentTCB = NULL;
}
/* 有部分任务没有被挂起 */
else
{
/* 任务切换上下文 */
vTaskSwitchContext();
}
}
}
else
{
mtCOVERAGE_TEST_MARKER();
}
}
解除任务挂起主要工作包括:
将任务从挂起列表重新加入就绪列表
任务优先级高于当前任务优先级,请求切换
/* 解除任务挂起 */
void vTaskResume(TaskHandle_t xTaskToResume)
{
TCB_t *const pxTCB = xTaskToResume;
configASSERT(xTaskToResume);
/* 当前任务不能被解除挂起,因为当前任务肯定正在运行 */
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();
}
}
带中断的任务挂起解除和不带中断的任务挂起解除之间的差别,在于任务优先级高于当前任务优先级的情况下也不可以立即请求切换任务,而是要等到下一节拍才能切换。
/* 在中断中解除任务挂起 */
BaseType_t xTaskResumeFromISR(TaskHandle_t xTaskToResume)
{
BaseType_t xYieldRequired = pdFALSE;
TCB_t * const pxTCB = xTaskToResume;
UBaseType_t uxSavedInterruptStatus;
configASSERT(xTaskToResume);
portASSERT_IF_INTERRUPT_PRIORITY_INVALID();
/* 进入临界区(意味着不能进入SysTick中断) */
uxSavedInterruptStatus = portSET_INTERRUPT_MASK_FROM_ISR();
{
/* 任务确实被挂起 */
if(prvTaskIsTaskSuspended(pxTCB) != pdFALSE)
{
traceTASK_RESUME_FROM_ISR(pxTCB);
/* 调度器没有被挂起 */
if(uxSchedulerSuspended == (UBaseType_t)pdFALSE)
{
/* 该任务优先级高于当前任务优先级 */
if(pxTCB->uxPriority >= pxCurrentTCB->uxPriority)
{
/* 在下一个节拍时进行任务切换 */
xYieldRequired = pdTRUE;
}
else
{
mtCOVERAGE_TEST_MARKER();
}
/* 将任务从挂起列表中移除 */
(void)uxListRemove(&(pxTCB->xStateListItem));
/* 将任务重新加入就绪列表 */
prvAddTaskToReadyList(pxTCB);
}
/* 调度器被挂起 */
else
{
/* 将任务加入挂起时就绪列表 */
vListInsertEnd(&(xPendingReadyList), &(pxTCB->xEventListItem));
}
}
else
{
mtCOVERAGE_TEST_MARKER();
}
}
/* 退出临界区 */
portCLEAR_INTERRUPT_MASK_FROM_ISR(uxSavedInterruptStatus);
return xYieldRequired;
}