最近学习白问网韦东山老师在B站开源的freeRTOS课程,网址:韦东山直播公开课:RTOS实战项目之实现多任务系统 第1节:裸机程序框架和缺陷_哔哩哔哩_bilibili和7天物联网训练营【第2期】7天物联网智能家居实战训练营
在学习过程中按照韦老师的方法分析了下freeRTOS源码,如果有不对的地方请指证。
任务创建源码分析:
//任务控制块结构体主要成员
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. */
//状态列表、事件列表
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. */
} tskTCB;
//任务创建函数
BaseType_t xTaskCreate( TaskFunction_t pxTaskCode,
const char * const pcName,
const uint16_t usStackDepth,
void * const pvParameters,
UBaseType_t uxPriority,
TaskHandle_t * const pxCreatedTask ) /*lint !e971 Unqualified char types are allowed for strings and single characters only. */
{
TCB_t *pxNewTCB;
BaseType_t xReturn;
/* 根据你使用的硬件平台的区别*/
这个区别是什么呢?
指的 硬件平台栈增长方式
我们选择M4,分析M4的栈增长方式就可以
在M4的权威指南里 4.4.3-栈存储分析
#define portSTACK_GROWTH ( -1 ) 表示满减栈
*/
#if( portSTACK_GROWTH > 0 )
{
}
#else /* portSTACK_GROWTH */
{
StackType_t *pxStack;
/* 任务栈内存分配*/
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 )
{
/* 任务控制块内存分配 */
pxNewTCB = ( TCB_t * ) pvPortMalloc( sizeof( TCB_t ) ); /*lint !e961 MISRA exception as the casts are only redundant for some paths. */
if( pxNewTCB != NULL )
{
/* 赋值栈地址 */
pxNewTCB->pxStack = pxStack;
}
else
{
/* 释放栈空间 */
vPortFree( pxStack );
}
}
else
{
//没有分配成功
pxNewTCB = NULL;
}
}
#endif /* portSTACK_GROWTH */
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;
}
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 ) /*lint !e971 Unqualified char types are allowed for strings and single characters only. */
{
StackType_t *pxTopOfStack;
UBaseType_t x;
/* 计算栈顶的地址 */
#if( portSTACK_GROWTH < 0 )
{
//把栈空间的高地址分配给栈顶
pxTopOfStack = pxNewTCB->pxStack + ( ulStackDepth - ( uint32_t ) 1 );
//栈对齐---- 栈要8字节对齐
pxTopOfStack = ( StackType_t * ) ( ( ( 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( ( ( ( portPOINTER_SIZE_TYPE ) pxTopOfStack & ( portPOINTER_SIZE_TYPE ) portBYTE_ALIGNMENT_MASK ) == 0UL ) );
}
#else /* portSTACK_GROWTH */
{
}
#endif /* portSTACK_GROWTH */
/* 存储任务名称 */
for( x = ( UBaseType_t ) 0; x < ( UBaseType_t ) configMAX_TASK_NAME_LEN; x++ )
{
pxNewTCB->pcTaskName[ x ] = pcName[ x ];
/* Don't copy all configMAX_TASK_NAME_LEN if the string is shorter than
configMAX_TASK_NAME_LEN characters just in case the memory after the
string is not accessible (extremely unlikely). */
if( pcName[ x ] == 0x00 )
{
break;
}
else
{
mtCOVERAGE_TEST_MARKER();
}
}
/* \0补齐字符串 */
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;
//任务状态表 事件表初始化
vListInitialiseItem( &( pxNewTCB->xStateListItem ) );
vListInitialiseItem( &( pxNewTCB->xEventListItem ) );
/* 任务控制块链接到任务状态表中 */
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 );
/* Initialize the TCB stack to look as if the task was already running,
but had been interrupted by the scheduler. The return address is set
to the start of the task function. Once the stack has been initialised
the top of stack variable is updated. */
#if( portUSING_MPU_WRAPPERS == 1 )
{
}
#else /* portUSING_MPU_WRAPPERS */
{
//任务堆栈初始化,之后返回任务栈顶
pxNewTCB->pxTopOfStack = pxPortInitialiseStack( pxTopOfStack, pxTaskCode, pvParameters );
}
#endif /* portUSING_MPU_WRAPPERS */
if( ( void * ) pxCreatedTask != NULL )
{
/* 赋值任务句柄 */
*pxCreatedTask = ( TaskHandle_t ) pxNewTCB;
}
else
{
mtCOVERAGE_TEST_MARKER();
}
}
//阅读M4权威指南,第八章节,分析异常处理
//为什么分析异常处理----------任务调度其实就是通过CPU内核异常处理实现的
StackType_t *pxPortInitialiseStack( StackType_t *pxTopOfStack, TaskFunction_t pxCode, void *pvParameters )
{
pxTopOfStack--;
//入栈程序状态寄存器
*pxTopOfStack = portINITIAL_XPSR; /* xPSR */
pxTopOfStack--;
//入栈PC指针
*pxTopOfStack = ( ( StackType_t ) pxCode ) & portSTART_ADDRESS_MASK; /* PC */
pxTopOfStack--;
//入栈LR链接寄存器
*pxTopOfStack = ( StackType_t ) prvTaskExitError; /* LR */
/* 不需要初始化 */
pxTopOfStack -= 5; /* R12, R3, R2 and R1. */
//R0作为传参入栈
*pxTopOfStack = ( StackType_t ) pvParameters; /* R0 */
/* 异常返回值入栈 返回值是确定程序使用的栈地址是哪一个 MSP PSP*/
pxTopOfStack--;
*pxTopOfStack = portINITIAL_EXEC_RETURN;
//不初始化
pxTopOfStack -= 8; /* R11, R10, R9, R8, R7, R6, R5 and R4. */
//最终返回栈顶
return pxTopOfStack;
}
任务删除源码分析:
void vTaskDelete( TaskHandle_t xTaskToDelete )
{
TCB_t *pxTCB;
/*
进入临界区
*/
taskENTER_CRITICAL();
{
/*
获取任务控制块
*/
pxTCB = prvGetTCBFromHandle( xTaskToDelete );
/* 从就绪链表中移除待删除的任务 */
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();
}
uxTaskNumber++;
/*
如果要删除的是当前任务
*/
if( pxTCB == pxCurrentTCB )
{
/*不能删除自身,需要把待删除任务添加到等待删除的列表中,由空闲任务删除,并释放任务所占用的资源 */
vListInsertEnd( &xTasksWaitingTermination, &( pxTCB->xStateListItem ) );
/* 给空闲任务一个标记 */
++uxDeletedTasksWaitingCleanUp;
/* 钩子函数,需要用户自己实现 */
portPRE_TASK_DELETE_HOOK( pxTCB, &xYieldPending );
}
/*
如果要删除的是不是任务本身
*/
else
{
//直接删除任务控制块
--uxCurrentNumberOfTasks;
prvDeleteTCB( pxTCB );
/* 更新任务锁定事件,以防止任务锁定事件指向被删除的任务. */
prvResetNextTaskUnblockTime();
}
traceTASK_DELETE( pxTCB );
}
//退出临界段
taskEXIT_CRITICAL();
/* 判断调度器是否开启 */
if( xSchedulerRunning != pdFALSE )
{
/*如果删除的是任务本身,则进行任务调度,释放CPU使用权*/
if( pxTCB == pxCurrentTCB )
{
configASSERT( uxSchedulerSuspended == 0 );
portYIELD_WITHIN_API();
}
else
{
mtCOVERAGE_TEST_MARKER();
}
}
}
任务挂起源码分析:
void vTaskSuspend( TaskHandle_t xTaskToSuspend )
{
TCB_t *pxTCB;
/*进入临界段*/
taskENTER_CRITICAL();
{
/* 获取任务控制块 */
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 ) );
}
/*退出临界段*/
taskEXIT_CRITICAL();
/*判断调度器是否开启*/
if( xSchedulerRunning != pdFALSE )
{
/* 更新下一个任务的锁定事件,以防止指向当前任务. */
taskENTER_CRITICAL();
{
prvResetNextTaskUnblockTime();
}
taskEXIT_CRITICAL();
}
else
{
mtCOVERAGE_TEST_MARKER();
}
/*
如果要被挂起的是任务本身
*/
if( pxTCB == pxCurrentTCB )
{
/*判断调度器是否开启*/
if( xSchedulerRunning != pdFALSE )
{
/* 直接进行任务调度释放CPU使用权 */
configASSERT( uxSchedulerSuspended == 0 );
portYIELD_WITHIN_API();
}
else
{
/* 如果调度器没开启,读取挂起列表的长度 */
if( listCURRENT_LIST_LENGTH( &xSuspendedTaskList ) == uxCurrentNumberOfTasks )
{
/* 当前任务控制块赋值为NULL */
pxCurrentTCB = NULL;
}
else
{
//进行上下文切换
vTaskSwitchContext();
}
}
}
else
{
mtCOVERAGE_TEST_MARKER();
}
}
任务恢复源码分析:
void vTaskResume( TaskHandle_t xTaskToResume )
{
//获取要恢复的任务控制块
TCB_t * const pxTCB = ( TCB_t * ) xTaskToResume;
/*检查 */
configASSERT( xTaskToResume );
/*既然要使用任务控制块,肯定不是为NULL
如果任务控制块,是当前的任务,是错误,是不允许
*/
if( ( pxTCB != NULL ) && ( pxTCB != pxCurrentTCB ) )
{
//进入临街段
taskENTER_CRITICAL();
{
//判断任务是否已经挂起
if( prvTaskIsTaskSuspended( pxTCB ) != pdFALSE )
{
/* 从挂起列表中移除 */
( void ) uxListRemove( &( pxTCB->xStateListItem ) );
//添加任务到就绪列表
prvAddTaskToReadyList( pxTCB );
/* 判断要恢复的任务是否大于当前任务的优先级
如果大于,释放CPU的使用权,开始内核调度
前提条件,是已经使能了 抢占式调度器
*/
if( pxTCB->uxPriority >= pxCurrentTCB->uxPriority )
{
/* */
taskYIELD_IF_USING_PREEMPTION();
}
else
{
mtCOVERAGE_TEST_MARKER();
}
}
else
{
mtCOVERAGE_TEST_MARKER();
}
}
//退出临街段
taskEXIT_CRITICAL();
}
else
{
mtCOVERAGE_TEST_MARKER();
}
}