freertos 의 task 에 대한 분석

19958 단어 Freertos
머리말
rtos 스케줄 링 의 기본 단 위 는 task (퀘 스 트) 로 그 중요성 은 두말 할 필요 도 없다. 일반적으로 퀘 스 트 의 생 성, 삭제, 차단, 끊 기, 답장 등 을 포함한다.물론 freertos 도 예 외 는 아니다.일반적인 task 는 세 가지 기본 부분 인 TCB 구조, stack 구조, 작업 코드 를 포함한다.다음은 이 몇 가지 측면 에서 말하자면
task 관련 데이터 구조
TCB 구조 체
typedef struct tskTaskControlBlock
{
	volatile StackType_t	*pxTopOfStack;	//      PSP,            ,  TCB                
	ListItem_t			xStateListItem;	//       
	ListItem_t			xEventListItem;	//       
	UBaseType_t			uxPriority;		//     
	StackType_t			*pxStack;		//    
	char				pcTaskName[ configMAX_TASK_NAME_LEN ];	//    
	#if ( configUSE_TRACE_FACILITY == 1 )	//        
		UBaseType_t		uxTCBNumber;		
		UBaseType_t		uxTaskNumber;
	#endif

	#if ( configUSE_MUTEXES == 1 )			//  mutex  
		UBaseType_t		uxBasePriority;	
		UBaseType_t		uxMutexesHeld;
	#endif

	#if( configUSE_TASK_NOTIFICATIONS == 1 )	//        
		volatile uint32_t ulNotifiedValue;
		volatile uint8_t ucNotifyState;
	#endif

	#if( tskSTATIC_AND_DYNAMIC_ALLOCATION_POSSIBLE != 0 )	//  TCb          
		uint8_t	ucStaticallyAllocated; 		
	#endif

	#if( INCLUDE_xTaskAbortDelay == 1 )	//          
		uint8_t ucDelayAborted;
	#endif
} tskTCB;
typedef tskTCB TCB_t;

작업 과 관련 된 전역 변수
PRIVILEGED_DATA TCB_t * volatile pxCurrentTCB = NULL;	//      TCB      
PRIVILEGED_DATA static List_t pxReadyTasksLists[ configMAX_PRIORITIES ];	//             ,                ,        ;
PRIVILEGED_DATA static List_t xDelayedTaskList1;	//      1				
PRIVILEGED_DATA static List_t xDelayedTaskList2;	//      2	,                  tick     ,        				
PRIVILEGED_DATA static List_t * volatile pxDelayedTaskList;	//          ,                  	
PRIVILEGED_DATA static List_t * volatile pxOverflowDelayedTaskList;	//                 		
/*< Points to the delayed task list currently being used to hold tasks that have overflowed the current tick count. */
PRIVILEGED_DATA static List_t xPendingReadyList;	//        ,   task          ,        ,         			
#if( INCLUDE_vTaskDelete == 1 )
	PRIVILEGED_DATA static List_t xTasksWaitingTermination;	//                    TCB  stack      (       ,           ),              ,                  ram
	PRIVILEGED_DATA static volatile UBaseType_t uxDeletedTasksWaitingCleanUp = ( UBaseType_t ) 0U;	//     01  ,                 ,    0             。
#endif

#if ( INCLUDE_vTaskSuspend == 1 )
	PRIVILEGED_DATA static List_t xSuspendedTaskList;			//        
#endif

PRIVILEGED_DATA static volatile UBaseType_t uxCurrentNumberOfTasks 	= ( UBaseType_t ) 0U;	//      
PRIVILEGED_DATA static volatile TickType_t xTickCount 				= ( TickType_t ) 0U;	//  tick  
PRIVILEGED_DATA static volatile UBaseType_t uxTopReadyPriority 		= tskIDLE_PRIORITY;	//       
PRIVILEGED_DATA static volatile BaseType_t xSchedulerRunning 		= pdFALSE;	//       
PRIVILEGED_DATA static volatile UBaseType_t uxPendedTicks 			= ( UBaseType_t ) 0U;	//suspend     tick 
PRIVILEGED_DATA static volatile BaseType_t xYieldPending 			= pdFALSE;	//
PRIVILEGED_DATA static volatile BaseType_t xNumOfOverflows 			= ( BaseType_t ) 0;	
PRIVILEGED_DATA static UBaseType_t uxTaskNumber 					= ( UBaseType_t ) 0U;	
PRIVILEGED_DATA static volatile TickType_t xNextTaskUnblockTime		= ( TickType_t ) 0U; 	
/* Initialised to portMAX_DELAY before the scheduler starts. */
PRIVILEGED_DATA static TaskHandle_t xIdleTaskHandle					= NULL;			
/*< Holds the handle of the idle task.  The idle task is created

task 관련 코드 분석
작업 생 성
rtos 에서 자원 사용 스케줄 의 최소 단 위 는 보통 task 입 니 다. 작업 생 성 코드 를 먼저 보 세 요.두 가지 로 나 뉘 는데 하 나 는 정적 static 생 성 task (퀘 스 트 stack, tcb 는 모두 미리 정적 신청) 이 고 다른 하 나 는 동적 생 성 (퀘 스 트 stack, tcb 는 모두 생 성 할 때 신청) 입 니 다. 그 중에서 tcb 구조 에 있 는 ucStatically Allocated 요 소 는 이 tcb 를 기록 하 는 방식 으로 만 들 었 습 니 다.코드 보기
/*          ,          tcb、stack   ,        ,     
 pxNewTCB、pxStack   ,    prvInitialiseNewTask   TCB  ,
    prvAddNewTaskToReadyList task   readylist  */
TaskHandle_t xTaskCreateStatic(	TaskFunction_t pxTaskCode,
								const char * const pcName,
								const uint32_t ulStackDepth,
								void * const pvParameters,
								UBaseType_t uxPriority,
								StackType_t * const puxStackBuffer,
								StaticTask_t * const pxTaskBuffer ) {
	TCB_t *pxNewTCB;
	TaskHandle_t xReturn;
	if( ( pxTaskBuffer != NULL ) && ( puxStackBuffer != NULL ) ){
		pxNewTCB = ( TCB_t * ) pxTaskBuffer; /*lint !e740 Unusual cast is ok as the structures are designed to have the same alignment, and the size is checked by an assert. */
		pxNewTCB->pxStack = ( StackType_t * ) puxStackBuffer;
		#if( tskSTATIC_AND_DYNAMIC_ALLOCATION_POSSIBLE != 0 ){
			pxNewTCB->ucStaticallyAllocated = tskSTATICALLY_ALLOCATED_STACK_AND_TCB;
		}
		#endif 

		prvInitialiseNewTask( pxTaskCode, pcName, ulStackDepth, pvParameters, uxPriority, &xReturn, pxNewTCB, NULL );
		prvAddNewTaskToReadyList( pxNewTCB );
	}else{
		xReturn = NULL;
	}
	return xReturn;
}

/*          ,       tcb、stack   ram,
    prvInitialiseNewTask   TCB  ,    prvAddNewTaskToReadyList task   readylist  */
BaseType_t xTaskCreate(	TaskFunction_t pxTaskCode,
						const char * const pcName,
						const uint16_t usStackDepth,
						void * const pvParameters,
						UBaseType_t uxPriority,
						TaskHandle_t * const pxCreatedTask ) 
{
TCB_t *pxNewTCB;
BaseType_t xReturn;

	/*          ,    stack,    TCB,
	    stack  ,    TCb       。。。                */
	/*  TCb    ,       malloc function     */
	pxNewTCB = ( TCB_t * ) pvPortMalloc( sizeof( TCB_t ) );
	if( pxNewTCB != NULL ){
		pxNewTCB->pxStack = ( StackType_t * ) pvPortMalloc( ( ( ( size_t ) usStackDepth ) * sizeof( StackType_t ) ) ); 
		if( pxNewTCB->pxStack == NULL ){
			vPortFree( pxNewTCB );
			pxNewTCB = NULL;
		}
	}
	if( pxNewTCB != NULL ){
		prvInitialiseNewTask( pxTaskCode, pcName, ( uint32_t ) usStackDepth, 
							pvParameters, uxPriority, pxCreatedTask, pxNewTCB, NULL );
		prvAddNewTaskToReadyList( pxNewTCB );
		xReturn = pdPASS;
	}else{
		xReturn = errCOULD_NOT_ALLOCATE_REQUIRED_MEMORY;
	}

	return xReturn;
}


그 중에서 모두 prvInitialiseNewTaskprvAddNewTaskToReadyList 를 호출 했 는데 다음은 이 두 함수 소스 코드 를 보 겠 습 니 다.
/*         task  ,  task    ,   task tcb xStateListItem、xEventListItem     
        (       ,    ),      task        */
static void prvInitialiseNewTask( 	TaskFunction_t pxTaskCode,
									const char * const pcName,
									const uint32_t ulStackDepth,
									void * const pvParameters,
									UBaseType_t uxPriority,
									TaskHandle_t * const pxCreatedTask,
									TCB_t *pxNewTCB,
									const MemoryRegion_t * const xRegions ) {
StackType_t *pxTopOfStack;
UBaseType_t x;

	/*       ;          . */
	#if( portSTACK_GROWTH < 0 ){
		pxTopOfStack = pxNewTCB->pxStack + ( ulStackDepth - ( uint32_t ) 1 );
		pxTopOfStack = ( StackType_t * ) ( ( ( portPOINTER_SIZE_TYPE ) pxTopOfStack ) & ( ~( ( portPOINTER_SIZE_TYPE ) portBYTE_ALIGNMENT_MASK ) ) ); 
		/*         ,         4    8     */
		configASSERT( ( ( ( portPOINTER_SIZE_TYPE ) pxTopOfStack & ( portPOINTER_SIZE_TYPE ) portBYTE_ALIGNMENT_MASK ) == 0UL ) );
	}
	#endif /* portSTACK_GROWTH */

	/*   task   */
	for( x = ( UBaseType_t ) 0; x < ( UBaseType_t ) configMAX_TASK_NAME_LEN; x++ ){
		pxNewTCB->pcTaskName[ x ] = pcName[ x ];
		/*         ,        ram    ,       */
		if( pcName[ x ] == 0x00 ){
			break;
		}else{
			mtCOVERAGE_TEST_MARKER();
		}
	}

	/*          。                           */
	pxNewTCB->pcTaskName[ configMAX_TASK_NAME_LEN - 1 ] = '\0';

	/*                 */
	if( uxPriority >= ( UBaseType_t ) configMAX_PRIORITIES ){
		uxPriority = ( UBaseType_t ) configMAX_PRIORITIES - ( UBaseType_t ) 1U;
	}else{
		mtCOVERAGE_TEST_MARKER();
	}

	pxNewTCB->uxPriority = uxPriority;
	#if ( configUSE_MUTEXES == 1 ){//  mutex  ,         
		pxNewTCB->uxBasePriority = uxPriority;
		pxNewTCB->uxMutexesHeld = 0;
	}
	#endif /* configUSE_MUTEXES */

	/*   tcb xStateListItem   xEventListItem                 list  */
	vListInitialiseItem( &( pxNewTCB->xStateListItem ) );
	vListInitialiseItem( &( pxNewTCB->xEventListItem ) );

	/*       owner */
	listSET_LIST_ITEM_OWNER( &( pxNewTCB->xStateListItem ), pxNewTCB );

	/*                */
	listSET_LIST_ITEM_VALUE( &( pxNewTCB->xEventListItem ), ( TickType_t ) configMAX_PRIORITIES - ( TickType_t ) uxPriority ); /*lint !e961 MISRA exception as the casts are only redundant for some ports. */
	listSET_LIST_ITEM_OWNER( &( pxNewTCB->xEventListItem ), pxNewTCB );

	/*   TCB  ,              ,          。
	               。                  。 
	            ,               */
	pxNewTCB->pxTopOfStack = pxPortInitialiseStack( pxTopOfStack, pxTaskCode, pvParameters );

	if( ( void * ) pxCreatedTask != NULL ){
		/*         ,      (      tcb   )            */
		*pxCreatedTask = ( TaskHandle_t ) pxNewTCB;
	}else{
		mtCOVERAGE_TEST_MARKER();
	}
}

/*     NEW task                
1.            ,             (     pxCurrentTCB   NEW tcb),  prvInitialiseTaskLists            
2.             ,         ,  pxCurrentTCB   pxNewTCB    ,  pxNewTCB      ,       TCB
3.            ,              ,        task pxCurrentTCB   pxNewTCB        ,  pxNewTCB     ,            ,  case1 \ 2           ,   pxCurrentTCB            。

     case ,    prvAddTaskToReadyList task   readylist  */
static void prvAddNewTaskToReadyList( TCB_t *pxNewTCB )
{
	/*                     。 */
	taskENTER_CRITICAL();{
		uxCurrentNumberOfTasks++;
		if( pxCurrentTCB == NULL ){
		/*     task,    task      、      ,      NEW     */
			pxCurrentTCB = pxNewTCB;
			if( uxCurrentNumberOfTasks == ( UBaseType_t ) 1 ){
				/*            ,             。
				        ,       ,        。*/
				prvInitialiseTaskLists();
			}else{
				mtCOVERAGE_TEST_MARKER();
			}
		}else{//             
		/*          ,            ,
		                    。*/
			if( xSchedulerRunning == pdFALSE ){
				if( pxCurrentTCB->uxPriority <= pxNewTCB->uxPriority ){
					pxCurrentTCB = pxNewTCB;
				}else{
					mtCOVERAGE_TEST_MARKER();
				}
			}else{
				mtCOVERAGE_TEST_MARKER();
			}
		}

		uxTaskNumber++;
		prvAddTaskToReadyList( pxNewTCB );
		portSETUP_TCB( pxNewTCB );
	}
	taskEXIT_CRITICAL();

	if( xSchedulerRunning != pdFALSE ){//        
	/*                                    ,         */
		if( pxCurrentTCB->uxPriority < pxNewTCB->uxPriority ){
			taskYIELD_IF_USING_PREEMPTION();
		}else{
			mtCOVERAGE_TEST_MARKER();
		}
	}else{
		mtCOVERAGE_TEST_MARKER();
	}
}
prvAddNewTaskToReadyList 에서 prvAddTaskToReadyList 이 매크로 와 관련 되 었 습 니 다. 다음 과 같이 준 비 된 최고 우선 순위 작업 을 업데이트 한 다음 에 이 task 를 우선 순위 목록 에 대응 하 는 readylist 목록 끝 에 삽입 합 니 다. 주로 시간 편 순환 스케줄 링 을 실현 합 니 다.
#define prvAddTaskToReadyList( pxTCB )													\
	taskRECORD_READY_PRIORITY( ( pxTCB )->uxPriority );								\
	vListInsertEnd( &( pxReadyTasksLists[ ( pxTCB )->uxPriority ] ), &( ( pxTCB )->xStateListItem ) ); 	\

작업 삭제
작업 생 성 이 있 으 면 작업 이 삭 제 됩 니 다. 동적 작업 은 삭제 할 수 있 을 뿐만 아니 라 정적 작업 도 삭제 할 수 있 습 니 다. 동적 작업 은 더욱 철저하게 삭제 되 고 TCB, stack 도 삭 제 됩 니 다. 정적 작업 은 삭제 할 때 TCB, stack 이 정적 으로 분배 되 어 삭제 할 수 없습니다.소스 코드
/*      ,                  ,       
1.          ,  TCB、stack              
2.          ,prvDeleteTCB     tcb、stack  
             ,          ,          。*/
void vTaskDelete( TaskHandle_t xTaskToDelete )
{
TCB_t *pxTCB;

	taskENTER_CRITICAL();{
		/*      xTaskToDelete NULL,         ,pxTCB = pxCurrentTCB,
		   pxTCB = xTaskToDelete*/
		pxTCB = prvGetTCBFromHandle( xTaskToDelete );

		/*           ,              ,    
		      ,            0 ,                  */
		if( uxListRemove( &( pxTCB->xStateListItem ) ) == ( UBaseType_t ) 0 )
			taskRESET_READY_PRIORITY( pxTCB->uxPriority );

		/*           ,                   (             ) */
		if( listLIST_ITEM_CONTAINER( &( pxTCB->xEventListItem ) ) != NULL )
			( void ) uxListRemove( &( pxTCB->xEventListItem ) );

		/*   uxTaskNumber,                          。
		       portPRE_TASK_DELETE_HOOK()    Windows          
		    。*/
		uxTaskNumber++;//           。。。。。

		if( pxTCB == pxCurrentTCB ){//      
		/*            。           ,                 。
		         xTasksWaitingTermination 。
		                            TCB       。*/
			vListInsertEnd( &xTasksWaitingTermination, &( pxTCB->xStateListItem ) );

		/*  uxDeletedTasksWaitingCleanUp  ,                  ,
		          xTasksWaitingTermination  。               */
			++uxDeletedTasksWaitingCleanUp;

		/*         Windows   ,     Windows       ,
		    ,             ,xYieldPending            。*/
			portPRE_TASK_DELETE_HOOK( pxTCB, &xYieldPending );
		}else{//           
			--uxCurrentNumberOfTasks;	//      ,
			prvDeleteTCB( pxTCB );		//    TCB、Stack   ,            
			/*             ,               task。*/
			prvResetNextTaskUnblockTime();
		}
	}
	taskEXIT_CRITICAL();
	/* Force a reschedule if it is the currently running task that has just been deleted. */
	if( xSchedulerRunning != pdFALSE ){//                     
		if( pxTCB == pxCurrentTCB )
			portYIELD_WITHIN_API();		//          ,  pxCurrentTCB      
	}
}

그 중에서 prvDeleteTCBprvResetNextTaskUnblockTime 를 호출 하여 소스 코드 를 보 았 다.
/*    tcb、stack   。    ram            ,     。。。*/
static void prvDeleteTCB( TCB_t *pxTCB ){
	#if( ( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) && ( configSUPPORT_STATIC_ALLOCATION == 0 ) && ( portUSING_MPU_WRAPPERS == 0 ) ){
		/* The task can only have been allocated dynamically - free both
		the stack and TCB. */
		vPortFree( pxTCB->pxStack );
		vPortFree( pxTCB );
	}
	#elif( tskSTATIC_AND_DYNAMIC_ALLOCATION_POSSIBLE == 1 ){
		/* The task could have been allocated statically or dynamically, so
		check what was statically allocated before trying to free the
		memory. */
		if( pxTCB->ucStaticallyAllocated == tskDYNAMICALLY_ALLOCATED_STACK_AND_TCB ){
			/* Both the stack and TCB were allocated dynamically, so both
			must be freed. */
			vPortFree( pxTCB->pxStack );
			vPortFree( pxTCB );
		}else if( pxTCB->ucStaticallyAllocated == tskSTATICALLY_ALLOCATED_STACK_ONLY ){
			/* Only the stack was statically allocated, so the TCB is theonly memory that must be freed. */
			vPortFree( pxTCB );
		}else{
			/* Neither the stack nor the TCB were allocated dynamically, so
			nothing needs to be freed. */
			configASSERT( pxTCB->ucStaticallyAllocated == tskSTATICALLY_ALLOCATED_STACK_AND_TCB	)
			mtCOVERAGE_TEST_MARKER();
		}
	}
	#endif /* configSUPPORT_DYNAMIC_ALLOCATION */
}

/*       unblock tine,    tick      delaylist             ,   */
static void prvResetNextTaskUnblockTime( void ){
TCB_t *pxTCB;
	if( listLIST_IS_EMPTY( pxDelayedTaskList ) != pdFALSE ){
		/*           。xNextTaskUnblockTime         ,          
		if(xTickCount >= xNextTaskUnblockTime)     ,          。*/
		xNextTaskUnblockTime = portMAX_DELAY;
	}else{
		/*           ,               。    
		                    。      */
		( pxTCB ) = ( TCB_t * ) listGET_OWNER_OF_HEAD_ENTRY( pxDelayedTaskList );
		xNextTaskUnblockTime = listGET_LIST_ITEM_VALUE( &( ( pxTCB )->xStateListItem ) );
	}
}

작업 지연
누 드 컴퓨터 프로 그래 밍 에서 우 리 는 일반적으로 시간 을 지연 시 키 는 것 은 CPU 를 공전 시 키 는 것 이다. 그러면 자원 을 크게 낭비 하 게 된다. OS 에서 이런 상황 이 발생 하 는 것 을 기본적으로 허용 하지 않 기 때문에 OS 는 사용자 가 OS 에서 사용 할 수 있 도록 두 개의 함 수 를 제공 했다. vTaskDelayUntilvTaskDelay.두 함수 에 경미 한 차이 가 있 으 니, 상세 하 게 분석 하면 코드 를 볼 수 있다.
/*       delay tick   ,  task  delaylist  xTicksToDelay tick*/
void vTaskDelay( const TickType_t xTicksToDelay ){
BaseType_t xAlreadyYielded = pdFALSE;
	/*   tick 0  ,        */
	if( xTicksToDelay > ( TickType_t ) 0U ){
		configASSERT( uxSchedulerSuspended == 0 );
		vTaskSuspendAll();{
			traceTASK_DELAY();
			/*                            
			           ,         。
			           ,           。*/
			prvAddCurrentTaskToDelayedList( xTicksToDelay, pdFALSE );
		}
		xAlreadyYielded = xTaskResumeAll();
	}
	/*   xTaskResumeAll     ,          ,      slepp */
	if( xAlreadyYielded == pdFALSE )
		portYIELD_WITHIN_API();
}

/*          pxPreviousWakeTime,      xTimeIncrement 。      ,                    ,          ,                   vTaskDelayUntil */
void vTaskDelayUntil( TickType_t * const pxPreviousWakeTime, const TickType_t xTimeIncrement )
{
TickType_t xTimeToWake;
BaseType_t xAlreadyYielded, xShouldDelay = pdFALSE;

	vTaskSuspendAll();{//      
		const TickType_t xConstTickCount = xTickCount;

		/*           tick */
		xTimeToWake = *pxPreviousWakeTime + xTimeIncrement;

		if( xConstTickCount < *pxPreviousWakeTime )
		{//    tick        tick  ,          
			/*       ,     */
			if( ( xTimeToWake < *pxPreviousWakeTime ) && ( xTimeToWake > xConstTickCount ) )
			{
				xShouldDelay = pdTRUE;
			}else{
				mtCOVERAGE_TEST_MARKER();
			}
		}else{
			/* tick      。    ,            、   tick wake time  ,
			        delay*/
			if( ( xTimeToWake < *pxPreviousWakeTime ) || ( xTimeToWake > xConstTickCount ) ){
				xShouldDelay = pdTRUE;
			}else{
				mtCOVERAGE_TEST_MARKER();
			}
		}

		/*       ,        */
		*pxPreviousWakeTime = xTimeToWake;

		if( xShouldDelay != pdFALSE )
			/* prvAddCurrentTaskToDelayedList()            ,       ,    tick */
			prvAddCurrentTaskToDelayedList( xTimeToWake - xConstTickCount, pdFALSE );
	}
	xAlreadyYielded = xTaskResumeAll();//        

	/*   xTaskResumeAll     ,          ,      slepp*/
	if( xAlreadyYielded == pdFALSE )
		portYIELD_WITHIN_API();
}

태 스 크 걸 기
이 부분 코드 는 주로 작업 연결, 작업 해제 등 을 포함한다.
void vTaskSuspend( TaskHandle_t xTaskToSuspend )
{
TCB_t *pxTCB;

	taskENTER_CRITICAL();{
		/*          ,      */
		pxTCB = prvGetTCBFromHandle( xTaskToSuspend );
		/*      ready delayed list   ,       xSuspendedTaskList  */
		if( uxListRemove( &( pxTCB->xStateListItem ) ) == ( UBaseType_t ) 0 ){
			taskRESET_READY_PRIORITY( pxTCB->uxPriority );
		}
		/*              ,   ,            */
		if( listLIST_ITEM_CONTAINER( &( pxTCB->xEventListItem ) ) != NULL ){
			( void ) uxListRemove( &( pxTCB->xEventListItem ) );
		}
		/*  task   xSuspendedTaskList  。(       )*/
		vListInsertEnd( &xSuspendedTaskList, &( pxTCB->xStateListItem ) );
	}
	taskEXIT_CRITICAL();

	if( xSchedulerRunning != pdFALSE ){
	/*   xNextTaskUnblockTime ,             xNextTaskUnblockTime     (           )*/
		taskENTER_CRITICAL();{
			prvResetNextTaskUnblockTime();
		}
		taskEXIT_CRITICAL();
	}

	if( pxTCB == pxCurrentTCB ){//           
		if( xSchedulerRunning != pdFALSE )
		{//         ,            
			/* The current task has just been suspended. */
			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. */
			if( listCURRENT_LIST_LENGTH( &xSuspendedTaskList ) == uxCurrentNumberOfTasks )
			{//           ,             ,               
			//pxCurrentTCB  NULL。         
				pxCurrentTCB = NULL;
			}else{//    。。      
				vTaskSwitchContext();
			}
		}
	}
}

void vTaskResume( TaskHandle_t xTaskToResume )
{
TCB_t * const pxTCB = ( TCB_t * ) xTaskToResume;
	/*              NULL,pxCurrentTCB */
	if( ( pxTCB != NULL ) && ( pxTCB != pxCurrentTCB ) ){
		taskENTER_CRITICAL();{
			if( prvTaskIsTaskSuspended( pxTCB ) != pdFALSE )
			{//  pxTCB         
				/*         ,        ,  xSuspendedTaskList 
				  task  ,    readylist */
				( void ) uxListRemove(  &( pxTCB->xStateListItem ) );
				prvAddTaskToReadyList( pxTCB );
				/*    pxTCB     pxCurrentTCB  ,                */
				if( pxTCB->uxPriority >= pxCurrentTCB->uxPriority ){
				
					taskYIELD_IF_USING_PREEMPTION();
				}
				
			}
		}
		taskEXIT_CRITICAL();
	}
}

좋은 웹페이지 즐겨찾기