typedefstructtskTaskControlBlock /* Theoldnamingconventionisusedtopreventbreakingkernelawaredebuggers. */ { 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
#if ( configUSE_CORE_AFFINITY == 1 ) && ( configNUMBER_OF_CORES > 1 ) UBaseType_t uxCoreAffinityMask; /**< Used to link the task to certain cores. UBaseType_t must have greater than or equal to the number of bits as configNUMBER_OF_CORES. */ #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. */ #if ( configNUMBER_OF_CORES > 1 ) volatile BaseType_t xTaskRunState; /**< Used to identify the core the task is running on, if the task is running. Otherwise, identifies the task's state - not running or yielding. */ UBaseType_t uxTaskAttributes; /**< Task's attributes - currently used to identify the idle tasks. */ #endif char pcTaskName[ configMAX_TASK_NAME_LEN ]; /**< Descriptive name given to the task when created. Facilitates debugging only. */
#if ( configUSE_TASK_PREEMPTION_DISABLE == 1 ) BaseType_t xPreemptionDisable; /**< Used to prevent the task from being preempted. */ #endif
#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 ( configGENERATE_RUN_TIME_STATS == 1 ) configRUN_TIME_COUNTER_TYPE ulRunTimeCounter; /**< Stores the amount of time the task has spent in the Running state. */ #endif
#if ( configUSE_C_RUNTIME_TLS_SUPPORT == 1 ) configTLS_BLOCK_TYPE xTLSBlock; /**< Memory block used as Thread Local Storage (TLS) Block for the task. */ #endif
/* See the comments in FreeRTOS.h with the definition of * tskSTATIC_AND_DYNAMIC_ALLOCATION_POSSIBLE. */ #if ( tskSTATIC_AND_DYNAMIC_ALLOCATION_POSSIBLE != 0 ) uint8_t ucStaticallyAllocated; /**< Set to pdTRUE if the task is a statically allocated to ensure no attempt is made to free the memory. */ #endif
taskENTER_CRITICAL(); //进入临界区 { /* If null is passed in here then it is the calling task that is * being deleted. */ pxTCB = prvGetTCBFromHandle( xTaskToDelete );//获取任务句柄xTaskToDelete所指向的具体的任务, 如果是NULL则代表自己
/* 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++;//系统中任务数+1
/* If the task is running (or yielding), we must add it to the * termination list so that an idle task can delete it when it is * no longer running. */ if( taskTASK_IS_RUNNING_OR_SCHEDULED_TO_YIELD( pxTCB ) != pdFALSE )//判断当前任务是否在运行, 其实就是判断pxTDB是否等于pxCurrentTCB { /* A running task or a task which is scheduled to yield is being * deleted. This cannot complete when the task is still running * on a core, 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;//等待删除的任务数
/* Call the delete hook before portPRE_TASK_DELETE_HOOK() as * portPRE_TASK_DELETE_HOOK() does not return in the Win32 port. */ traceTASK_DELETE( pxTCB );
/* 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. */ #if ( configNUMBER_OF_CORES == 1 ) portPRE_TASK_DELETE_HOOK( pxTCB, &( xYieldPendings[ 0 ] ) ); #else portPRE_TASK_DELETE_HOOK( pxTCB, &( xYieldPendings[ pxTCB->xTaskRunState ] ) ); #endif } else//pxTCB指向的任务不是当前任务 { --uxCurrentNumberOfTasks; traceTASK_DELETE( pxTCB );
/* Reset the next expected unblock time in case it referred to * the task that has just been deleted. */ prvResetNextTaskUnblockTime(); } }
/* If the task is not deleting itself, call prvDeleteTCB from outside of * critical section. If a task deletes itself, prvDeleteTCB is called * from prvCheckTasksWaitingTermination which is called from Idle task. */ if( pxTCB != pxCurrentTCB )//不是当前任务,直接删除 { prvDeleteTCB( pxTCB ); }
/* Force a reschedule if it is the currently running task that has just * been deleted. */ if( xSchedulerRunning != pdFALSE )//调度器在运行 { if( pxTCB == pxCurrentTCB )//指向的任务是当前执行的任务, 则切换任务 { configASSERT( uxSchedulerSuspended == 0 ); portYIELD_WITHIN_API(); } else { mtCOVERAGE_TEST_MARKER(); } } } #else/* #if ( configNUMBER_OF_CORES == 1 ) */ { /* If a running task is not deleting itself, call prvDeleteTCB. If a running * task deletes itself, prvDeleteTCB is called from prvCheckTasksWaitingTermination * which is called from Idle task. */ if( pxTCB->xTaskRunState == taskTASK_NOT_RUNNING ) { prvDeleteTCB( pxTCB ); }
/* Force a reschedule if the task that has just been deleted was running. */ if( ( xSchedulerRunning != pdFALSE ) && ( taskTASK_IS_RUNNING( pxTCB ) == pdTRUE ) ) { if( pxTCB->xTaskRunState == ( BaseType_t ) portGET_CORE_ID() ) { configASSERT( uxSchedulerSuspended == 0 ); vTaskYieldWithinAPI(); } else { prvYieldCore( pxTCB->xTaskRunState ); } }
taskENTER_CRITICAL(); { /* If null is passed in here then it is the running task that is * being suspended. */ pxTCB = prvGetTCBFromHandle( xTaskToSuspend );//简单进行检查, 看xTaskToSuspend是否是NULL
for( x = ( BaseType_t ) 0; x < ( BaseType_t ) configTASK_NOTIFICATION_ARRAY_ENTRIES; x++ ) { if( pxTCB->ucNotifyState[ x ] == taskWAITING_NOTIFICATION ) { /* The task was blocked to wait for a notification, but is * now suspended, so no notification was received. */ pxTCB->ucNotifyState[ x ] = taskNOT_WAITING_NOTIFICATION; } } } #endif/* if ( configUSE_TASK_NOTIFICATIONS == 1 ) */ }
#if ( configNUMBER_OF_CORES == 1 )//只有一个内核 { 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 )//pxTCB指向当前任务 { if( xSchedulerRunning != pdFALSE )//调度器正在执行 { /* The current task has just been suspended. */ configASSERT( uxSchedulerSuspended == 0 );//uxSchedulerSuspended==0表示调度器是否被挂起 portYIELD_WITHIN_API();//进行任务切换 } else//如果没有调度器没有在执行 { /*调度器没有运行, 但是pxCurrentTCB指向的任务正好被挂起了, 所以我们必须要更改pxCurrentTCB*/ 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. */ pxCurrentTCB = NULL; } else { vTaskSwitchContext();//由于不是所有的任务都是挂起状态, 所以转换pxCurrentTCB, 切换上下文 } } } else//pxTCB指向的不是当前任务 { mtCOVERAGE_TEST_MARKER(); } } #else/* #if ( configNUMBER_OF_CORES == 1 ) 不止一个内核时*/ { if( xSchedulerRunning != pdFALSE ) { /* Reset the next expected unblock time in case it referred to the * task that is now in the Suspended state. */ prvResetNextTaskUnblockTime(); } else { mtCOVERAGE_TEST_MARKER(); }
if( taskTASK_IS_RUNNING( pxTCB ) == pdTRUE ) { if( xSchedulerRunning != pdFALSE ) { if( xTaskRunningOnCore == ( BaseType_t ) portGET_CORE_ID() ) { /* The current task has just been suspended. */ configASSERT( uxSchedulerSuspended == 0 ); vTaskYieldWithinAPI(); } else { prvYieldCore( xTaskRunningOnCore ); } } else { /* This code path is not possible because only Idle tasks are * assigned a core before the scheduler is started ( i.e. * taskTASK_IS_RUNNING is only true for idle tasks before * the scheduler is started ) and idle tasks cannot be * suspended. */ mtCOVERAGE_TEST_MARKER(); } } else { mtCOVERAGE_TEST_MARKER(); }
/* It does not make sense to resume the calling task. 恢复调用任务是没有意义的, 意思是xTaskToResume不要是自己*/ configASSERT( xTaskToResume );
#if ( configNUMBER_OF_CORES == 1 )//一核心
/* The parameter cannot be NULL as it is impossible to resume the * currently executing task. */ if( ( pxTCB != pxCurrentTCB ) && ( pxTCB != NULL ) )//恢复调用任务是没有意义的, 意思是xTaskToResume不要是自己和NULL #else
/* The parameter cannot be NULL as it is impossible to resume the * currently executing task. It is also impossible to resume a task * that is actively running on another core but it is not safe * to check their run state here. Therefore, we get into a critical * section and check if the task is actually suspended or not. */ if( pxTCB != NULL ) #endif { taskENTER_CRITICAL();//进入临界区 { if( prvTaskIsTaskSuspended( pxTCB ) != pdFALSE )//pxTCB是挂起状态 { 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 );//添加到就绪表
/* 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_ANY_CORE_IF_USING_PREEMPTION( pxTCB );//如果当前任务的优先级小于pxTCB指向的优先级则进行上下文切换(任务切换) } else//pxTCB不是挂起状态 { mtCOVERAGE_TEST_MARKER(); } } taskEXIT_CRITICAL();//退出临界区 } else { mtCOVERAGE_TEST_MARKER(); }