本文已参加「新人创造礼」活动,一起敞开创造之路。

在了解了根本的环境和结构之后,对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

FreeRTOS记录(二、FreeRTOS任务API认识和源码简析)
xTaskCreateStatic
FreeRTOS记录(二、FreeRTOS任务API认识和源码简析)

删去使命

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记录(二、FreeRTOS任务API认识和源码简析)

使命操控块

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记录(二、FreeRTOS任务API认识和源码简析)
在剖析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 */

使命删去流程剖析

FreeRTOS记录(二、FreeRTOS任务API认识和源码简析)

临界段

一种维护机制,代码的临界段也称为临界区,指处理时不可分割的代码区域,一旦这部分代码开始履行,则不允许任何中止打断。为确保临界段代码的履行不被中止,在进入临界段之前须关中止,而临界段代码履行结束后,要当即翻开中止。

在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 */

使命挂起

FreeRTOS记录(二、FreeRTOS任务API认识和源码简析)
咱们在源码中直接运用注释剖析:

#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 */

使命康复

FreeRTOS记录(二、FreeRTOS任务API认识和源码简析)
咱们在源码中直接运用注释剖析:

#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 */