freertos 任務建立 xTaskCreate xTaskGenericCreate 源代碼分析

任務定義
數組

//宏定義 任務建立函數
#define xTaskCreate( pvTaskCode, pcName, usStackDepth, pvParameters, uxPriority, pxCreatedTask ) xTaskGenericCreate( ( pvTaskCode ), ( pcName ), ( usStackDepth ), ( pvParameters ), ( uxPriority ), ( pxCreatedTask ), ( NULL ), ( NULL ) )

 

//任務 建立任務
signed portBASE_TYPE xTaskGenericCreate( pdTASK_CODE pxTaskCode,///指向任務的入口函數. 
     const signed char * const pcName,  //描述任務的名字。主要便於調試
     unsigned short usStackDepth, //指定任務堆棧的深度
      void *pvParameters, //指針用於做爲一個參數傳向建立的任務
      unsigned portBASE_TYPE uxPriority, //任務運行時的優先級
      xTaskHandle *pxCreatedTask, //用於傳出任務的句柄,在API對該建立出來的任務進行引用如改變任務優先級
      portSTACK_TYPE *puxStackBuffer,  //堆棧緩衝區
      const xMemoryRegion * const xRegions /*緩存區*/ )
{
signed portBASE_TYPE xReturn;
tskTCB * pxNewTCB;

	configASSERT( pxTaskCode );
	configASSERT( ( ( uxPriority & ( ~portPRIVILEGE_BIT ) ) < configMAX_PRIORITIES ) );

	/* 爲TCB 和 堆棧分配空間 */ 
	pxNewTCB = prvAllocateTCBAndStack( usStackDepth, puxStackBuffer );

	if( pxNewTCB != NULL )  /* 若是 TCB 空間分配成功 */ 
	{
		portSTACK_TYPE *pxTopOfStack;

		#if( portUSING_MPU_WRAPPERS == 1 )
			/* Should the task be created in privileged mode? 特權模式 */
			portBASE_TYPE xRunPrivileged;
			if( ( uxPriority & portPRIVILEGE_BIT ) != 0U )
			{
				xRunPrivileged = pdTRUE;
			}
			else
			{
				xRunPrivileged = pdFALSE;
			}
			uxPriority &= ~portPRIVILEGE_BIT;
		#endif /* portUSING_MPU_WRAPPERS == 1 */

		
    /* 計算堆棧棧頂的位置 */ 
		#if( portSTACK_GROWTH < 0 )
		{
			pxTopOfStack = pxNewTCB->pxStack + ( usStackDepth - ( unsigned short ) 1 );
			/* pxStack 指向堆棧的起始地址 */
			pxTopOfStack = ( portSTACK_TYPE * ) ( ( ( portPOINTER_SIZE_TYPE ) pxTopOfStack ) & ( ( portPOINTER_SIZE_TYPE ) ~portBYTE_ALIGNMENT_MASK  ) ); /*lint !e923 MISRA exception.  Avoiding casts between pointers and integers is not practical.  Size differences accounted for using portPOINTER_SIZE_TYPE type. */
			/* 堆棧有地址對齊的要求 */
			
			/*內存對齊 */
			configASSERT( ( ( ( unsigned long ) pxTopOfStack & ( unsigned long ) portBYTE_ALIGNMENT_MASK ) == 0UL ) );
		}
		#else /* portSTACK_GROWTH */
		{
			pxTopOfStack = pxNewTCB->pxStack;
			/* 新建的堆棧是空的,因此堆棧的棧頂就在起始地址處(正生堆棧)*/ 

			/* 內存對齊 */
			configASSERT( ( ( ( unsigned long ) pxNewTCB->pxStack & ( unsigned long ) portBYTE_ALIGNMENT_MASK ) == 0UL ) );

			/* If we want to use stack checking on architectures that use
			a positive stack growth direction then we also need to store the
			other extreme of the stack space. */
			
			 /* 若是要作堆棧檢查,就要知道堆棧的另外一端界限在哪裏 */ 
			pxNewTCB->pxEndOfStack = pxNewTCB->pxStack + ( usStackDepth - 1 );
		}
		#endif /* portSTACK_GROWTH */

		 /* 設置 TCB 的各個部分 */ 
		prvInitialiseTCBVariables( pxNewTCB, pcName, uxPriority, xRegions, usStackDepth );
		/* 初始化堆棧,使得任務好像被中斷函數中斷了同樣,中斷返回地址就是任務的首地址 */
		/*一旦被初始化堆棧頂部的堆棧變量將被更新。 */
		
		/* 初始化任務堆棧,並將返回地址保存在tcb中的pxTopOfStack變量*/
		#if( portUSING_MPU_WRAPPERS == 1 )
		{
			pxNewTCB->pxTopOfStack = pxPortInitialiseStack( pxTopOfStack, pxTaskCode, pvParameters, xRunPrivileged );
		}
		#else /* portUSING_MPU_WRAPPERS */
		{
   //彙編語言對堆棧進行初始化
			pxNewTCB->pxTopOfStack = pxPortInitialiseStack( pxTopOfStack, pxTaskCode, pvParameters );
		}
		#endif /* portUSING_MPU_WRAPPERS */

		if( ( void * ) pxCreatedTask != NULL )  //任務句柄
		{
			/* 返回任務的句柄 */ 
			*pxCreatedTask = ( xTaskHandle ) pxNewTCB;
		}

		 /*關中斷*/
		taskENTER_CRITICAL();
		{ /*更新系統的任務數*/
			uxCurrentNumberOfTasks++;
			if( pxCurrentTCB == NULL )
			{
				/* 沒有其餘任務, 或者其餘任務在掛起狀態 設爲當前任務 */
				pxCurrentTCB =  pxNewTCB;

				if( uxCurrentNumberOfTasks == ( unsigned portBASE_TYPE ) 1 )
				{
					//這是第一個任務,初始化任務狀態切換調度時使用的幾個鏈表
					prvInitialiseTaskLists();
				}
			}
			else
			{
				/* 若是調度沒有運行使得當前任務爲最高級任務 */
				if( xSchedulerRunning == pdFALSE )
				{
					if( pxCurrentTCB->uxPriority <= uxPriority )
					{
						pxCurrentTCB = pxNewTCB;
					}
				}
			}
                        if( pxNewTCB->uxPriority > uxTopUsedPriority )
			{
				uxTopUsedPriority = pxNewTCB->uxPriority;
			}
			uxTaskNumber++; 

			#if ( configUSE_TRACE_FACILITY == 1 )
			{
				/* Add a counter into the TCB 僅僅爲了追蹤*/
				pxNewTCB->uxTCBNumber = uxTaskNumber;
			}
			#endif /* configUSE_TRACE_FACILITY */
			traceTASK_CREATE( pxNewTCB );

			prvAddTaskToReadyList( pxNewTCB );  //添加到就緒鏈表中

			xReturn = pdPASS;
			portSETUP_TCB( pxNewTCB );
		}
		taskEXIT_CRITICAL();
	}
	else  //分配失敗
	{
		xReturn = errCOULD_NOT_ALLOCATE_REQUIRED_MEMORY;
		traceTASK_CREATE_FAILED(); //無定義
	}

	if( xReturn == pdPASS )
	{
		if( xSchedulerRunning != pdFALSE )  //切換狀態
		{
			if( pxCurrentTCB->uxPriority < uxPriority )
			{
				portYIELD_WITHIN_API(); //保存現成,而後選擇下一個任務
			}
		}
	}

	return xReturn;
}

進入臨界區

#define taskENTER_CRITICAL()		portENTER_CRITICAL()
#define portENTER_CRITICAL()		vPortEnterCritical()
void vPortEnterCritical( void )
{
	portDISABLE_INTERRUPTS();
	uxCriticalNesting++;
}

#define portDISABLE_INTERRUPTS()	vPortSetInterruptMask() 關中斷
__asm void vPortSetInterruptMask( void )
{
	PRESERVE8

	push { r0 }
	mov r0, #configMAX_SYSCALL_INTERRUPT_PRIORITY
	msr basepri, r0
	pop { r0 }
	bx r14
}
//經過basepri 屏蔽全部中斷

任務鏈表初始化prvInitialiseTaskLists

static void prvInitialiseTaskLists( void )
{
unsigned portBASE_TYPE uxPriority;
 
for( uxPriority = ( unsigned portBASE_TYPE ) 0U; uxPriority < ( unsigned portBASE_TYPE )   configMAX_PRIORITIES; uxPriority++ )
{
vListInitialise( &( pxReadyTasksLists[ uxPriority ] ) );//初始化就緒鏈表數組
}
 
vListInitialise( &xDelayedTaskList1 );//初始化延時鏈表1
vListInitialise( &xDelayedTaskList2 );//初始化延時列表2
vListInitialise( &xPendingReadyList );//初始化調度器掛起時就緒鏈表
 
#if ( INCLUDE_vTaskDelete == 1 )
{
vListInitialise( &xTasksWaitingTermination );//初始化被刪除任務鏈表
}
#endif /* INCLUDE_vTaskDelete */
 
#if ( INCLUDE_vTaskSuspend == 1 )
{
vListInitialise( &xSuspendedTaskList );//初始化
}
#endif /* INCLUDE_vTaskSuspend */
 
/* Start with pxDelayedTaskList using list1 and the pxOverflowDelayedTaskList
using list2. */
pxDelayedTaskList = &xDelayedTaskList1;
pxOverflowDelayedTaskList = &xDelayedTaskList2;
}

鏈表初始化vListInitialise

void vListInitialise( xList * const pxList )
{
/* 列表結構包含了一個列項目 被用來標記一個列表的結尾
 To initialise the list the list end is inserted
做爲惟一列的輸入. */
pxList->pxIndex = ( xListItem * ) &( pxList->xListEnd );   /*lint !e826 !e740 The mini list structure is used as the list end to save RAM.  This is checked and valid. */
 
/* 列結束的值 是列表中可能的最高值 確保他能留在隊列的最後*/
pxList->xListEnd.xItemValue = portMAX_DELAY;
 
/* 列尾的下一個和上一個指針指向他自己,當列是空時 */
pxList->xListEnd.pxNext = ( xListItem * ) &( pxList->xListEnd ); /*lint !e826 !e740 The mini list structure is used as the list end to save RAM.  This is checked and valid. */
pxList->xListEnd.pxPrevious = ( xListItem * ) &( pxList->xListEnd );/*lint !e826 !e740 The mini list structure is used as the list end to save RAM.  This is checked and valid. */
 
pxList->uxNumberOfItems = ( unsigned portBASE_TYPE ) 0U;
}

任務切換函數

#define portYIELD_WITHIN_API portYIELD
#define portYIELD() vPortYieldFromISR()
void vPortYieldFromISR( void )  //請求中斷函數
{
 /* Set a PendSV to request a context switch. */
 *(portNVIC_INT_CTRL) = portNVIC_PENDSVSET;
}

內存分配

static tskTCB *prvAllocateTCBAndStack( unsigned short usStackDepth, portSTACK_TYPE *puxStackBuffer )
{
tskTCB *pxNewTCB;

	/* 分配TCB內存*/
	pxNewTCB = ( tskTCB * ) pvPortMalloc( sizeof( tskTCB ) );

	if( pxNewTCB != NULL )
	{
		/* 分配任務 所須要的內存*/
		pxNewTCB->pxStack = ( portSTACK_TYPE * ) pvPortMallocAligned( ( ( ( size_t )usStackDepth ) * sizeof( portSTACK_TYPE ) ), puxStackBuffer );

		if( pxNewTCB->pxStack == NULL )
		{
			/*任務內存分配失敗,刪掉新分配的TCB內存*/
			vPortFree( pxNewTCB );
			pxNewTCB = NULL;
		}
		else
		{
			/* 爲了調試的*/
			memset( pxNewTCB->pxStack, tskSTACK_FILL_BYTE, usStackDepth * sizeof( portSTACK_TYPE ) );
		}
	}

	return pxNewTCB; //返回新建立的任務
}

任務初始化

static void prvInitialiseTCBVariables( tskTCB *pxTCB, const signed char * const pcName, unsigned portBASE_TYPE uxPriority, const xMemoryRegion * const xRegions, unsigned short usStackDepth )
{
	#if configMAX_TASK_NAME_LEN > 1
	{
		/* Don't bring strncpy into the build unnecessarily. */
		strncpy( ( char * ) pxTCB->pcTaskName, ( const char * ) pcName, ( unsigned short ) configMAX_TASK_NAME_LEN );
	}
	#endif
	pxTCB->pcTaskName[ ( unsigned short ) configMAX_TASK_NAME_LEN - ( unsigned short ) 1 ] = ( signed char ) '\0';

	//確保任務優先級 不超過 定義的最大優先級 
	if( uxPriority >= configMAX_PRIORITIES )
	{
		uxPriority = configMAX_PRIORITIES - ( unsigned portBASE_TYPE ) 1U;
	}

	pxTCB->uxPriority = uxPriority;
	#if ( configUSE_MUTEXES == 1 )
	{
		pxTCB->uxBasePriority = uxPriority;
	}
	#endif
        
	vListInitialiseItem( &( pxTCB->xGenericListItem ) ); //初始化任務鏈表
	vListInitialiseItem( &( pxTCB->xEventListItem ) );   //初始化事件鏈表

	/* Set the pxTCB as a link back from the xListItem.  This is so we can get
	back to	the containing TCB from a generic item in a list. */
	listSET_LIST_ITEM_OWNER( &( pxTCB->xGenericListItem ), pxTCB );

	/* Event lists are always in priority order. */
	listSET_LIST_ITEM_VALUE( &( pxTCB->xEventListItem ), configMAX_PRIORITIES - ( portTickType ) uxPriority );
	listSET_LIST_ITEM_OWNER( &( pxTCB->xEventListItem ), pxTCB );

	#if ( portCRITICAL_NESTING_IN_TCB == 1 )
	{
		pxTCB->uxCriticalNesting = ( unsigned portBASE_TYPE ) 0;
	}
	#endif

	#if ( configUSE_APPLICATION_TASK_TAG == 1 )
	{
		pxTCB->pxTaskTag = NULL;
	}
	#endif

	#if ( configGENERATE_RUN_TIME_STATS == 1 )
	{
		pxTCB->ulRunTimeCounter = 0UL;
	}
	#endif

	#if ( portUSING_MPU_WRAPPERS == 1 )
	{
		vPortStoreTaskMPUSettings( &( pxTCB->xMPUSettings ), xRegions, pxTCB->pxStack, usStackDepth );
	}
	#else
	{
		( void ) xRegions;
		( void ) usStackDepth;
	}
	#endif
}

cpu寄存器初始化

portSTACK_TYPE *pxPortInitialiseStack( portSTACK_TYPE *pxTopOfStack, pdTASK_CODE pxCode, void *pvParameters )
{
	pxTopOfStack--; 
	*pxTopOfStack = portINITIAL_XPSR;	/* xPSR */
	pxTopOfStack--;
	*pxTopOfStack = ( portSTACK_TYPE ) pxCode;	/* PC */
	pxTopOfStack--;
	*pxTopOfStack = 0;	/* LR */
	pxTopOfStack -= 5;	/* R12, R3, R2 and R1. */
	*pxTopOfStack = ( portSTACK_TYPE ) pvParameters;	/* R0 */
	pxTopOfStack -= 8;	/* R11, R10, R9, R8, R7, R6, R5 and R4. */

	return pxTopOfStack;
}

添加任務定義

#define prvAddTaskToReadyQueue( pxTCB )																					\
	if( ( pxTCB )->uxPriority > uxTopReadyPriority )																	\
	{																													\
		uxTopReadyPriority = ( pxTCB )->uxPriority;																		\
	}																													\
	vListInsertEnd( ( xList * ) &( pxReadyTasksLists[ ( pxTCB )->uxPriority ] ), &( ( pxTCB )->xGenericListItem ) )
相關文章
相關標籤/搜索