FreeRTOS - 任务创建和删除实现原理

这段代码详细展示了在Cortex-M处理器上创建RTOS任务时的任务控制块(TCB)结构和栈管理。它涉及到栈顶指针、任务状态列表、事件列表、优先级、栈存储分配以及任务初始化。当栈从高地址向低地址增长时,代码会根据这一特性进行栈顶地址的计算和对齐。同时,代码还处理了栈和TCB的内存分配,如果分配失败,会释放已分配的内存。
摘要由CSDN通过智能技术生成

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

栈存储

/* 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. */
        /*根据你使用硬件平台的区别*/
        /*区别在于 硬件平台栈的增长方式*/
        /*分析M3,栈的增长方式*/
        #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 */
        {
        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. */
                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 )
        {
/*以下宏编译暂时不看*/
            //新建任务初始化
            prvInitialiseNewTask( pxTaskCode, pcName, ( uint32_t ) usStackDepth, pvParameters, uxPriority, pxCreatedTask, pxNewTCB, NULL );
            //把任务添加到就绪列表中
            prvAddNewTaskToReadyList( pxNewTCB );
            xReturn = pdPASS;
        }
        else
        {
            xReturn = errCOULD_NOT_ALLOCATE_REQUIRED_MEMORY;
        }

        return xReturn;
    }

Cortex - M处理器使用的栈模型为:“满递减

栈的增长方式

/* Architecture specifics. */
#define portSTACK_GROWTH( -1 )       
#define portTICK_PERIOD_MS( ( TickType_t ) 1000 / configTICK_RATE_HZ )
#define portBYTE_ALIGNMENT8
/* Constants used with memory barrier intrinsics. */
#define portSY_FULL_READ_WRITE( 15 )
static void prvInitialiseNewTask( TaskFunction_t pxTaskCode,
const char * const pcName,/*lint !e971 Unqualified char types are allowed for strings and single characters only. */
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;

计算栈顶地址

/* Calculate the top of stack address.  This depends on whether the stack
    grows from high memory to low (as per the 80x86) or vice versa(反之亦然).
    portSTACK_GROWTH is used to make the result positive or negative as required
    by the port. */
    #if( portSTACK_GROWTH < 0 )
    {
        //栈指针 = 创造栈的地址 + (栈的大小 - 1) 把栈空间的高地址分配给栈顶
        pxTopOfStack = pxNewTCB->pxStack + ( ulStackDepth - ( uint32_t ) 1 );
        //栈的地址对齐
        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. */

        /* Check the alignment of the calculated top of stack is correct. */
        configASSERT( ( ( ( portPOINTER_SIZE_TYPE ) pxTopOfStack & ( portPOINTER_SIZE_TYPE ) portBYTE_ALIGNMENT_MASK ) == 0UL ) );

        #if( configRECORD_STACK_HIGH_ADDRESS == 1 )
        {
            /* Also record the stack's high address, which may assist
            debugging. */
            pxNewTCB->pxEndOfStack = pxTopOfStack;
        }
        #endif /* configRECORD_STACK_HIGH_ADDRESS */
    }
    #else /* portSTACK_GROWTH */
    {
    }
    #endif /* portSTACK_GROWTH */

    /* Store the task name in the TCB. */
    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();
        }
    }
    //补齐字符串
    pxNewTCB->pcTaskName[ configMAX_TASK_NAME_LEN - 1 ] = '\0';
    /* This is used as an array index so must ensure it's not too large.  First
    remove the privilege bit if one is present. */
    //判断任务分配优先级,是否大于最大值,如果超过最大值,则赋值最大值
    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 )
    {
        pxNewTCB->uxBasePriority = uxPriority;
        pxNewTCB->uxMutexesHeld = 0;
    }
    #endif /* configUSE_MUTEXES */
    //任务状态表 任务表初始化
    vListInitialiseItem( &( pxNewTCB->xStateListItem ) );
    vListInitialiseItem( &( pxNewTCB->xEventListItem ) );

    /* Set the pxNewTCB as a link back from the ListItem_t.  This is so we can get
    back to    the containing TCB from a generic item in a list. */
    //任务控制块链接到任务状态表中
    listSET_LIST_ITEM_OWNER( &( pxNewTCB->xStateListItem ), pxNewTCB );

    /* Event lists are always in priority order. */
    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 )
    {
        /* Pass the handle out in an anonymous way.  The handle can be used to
        change the created task's priority, delete the created task, etc.*/
        //赋值任务句柄
        *pxCreatedTask = ( TaskHandle_t ) pxNewTCB;
    }
    else
    {
        mtCOVERAGE_TEST_MARKER();
    }

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值