硬汉嵌入式论坛

 找回密码
 立即注册
查看: 8902|回复: 8
收起左侧

[FreeRTOS] 【ERIC2013原创】FreeRTOS  V7.4.2 详细源码分析之(2)-----------任务

[复制链接]

1万

主题

6万

回帖

10万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
107031
QQ
发表于 2013-6-19 13:53:01 | 显示全部楼层 |阅读模式
任务创建xTaskCreate
/**
* task. h
*<pre>
portBASE_TYPE xTaskCreate(
                              pdTASK_CODE pvTaskCode,
                              const char * const pcName,
                              unsigned short usStackDepth,
                              void *pvParameters,
                              unsigned portBASE_TYPE uxPriority,
                              xTaskHandle *pvCreatedTask
                          );</pre>
*
* Create a new task and add it to the list of tasks that are ready to run.
*
* xTaskCreate() can only be used to create a task that has unrestricted
* access to the entire microcontroller memory map.  Systems that include MPU
* support can alternatively create an MPU constrained task using
* xTaskCreateRestricted().
*
* @param pvTaskCode Pointer to the task entry function.  Tasks
* must be implemented to never return (i.e. continuous loop).
*
* @param pcName A descriptive name for the task.  This is mainly used to
* facilitate debugging.  Max length defined by tskMAX_TASK_NAME_LEN - default
* is 16.
*
* @param usStackDepth The size of the task stack specified as the number of
* variables the stack can hold - not the number of bytes.  For example, if
* the stack is 16 bits wide and usStackDepth is defined as 100, 200 bytes
* will be allocated for stack storage.
*
* @param pvParameters Pointer that will be used as the parameter for the task
* being created.
*
* @param uxPriority The priority at which the task should run.  Systems that
* include MPU support can optionally create tasks in a privileged (system)
* mode by setting bit portPRIVILEGE_BIT of the priority parameter.  For
* example, to create a privileged task at priority 2 the uxPriority parameter
* should be set to ( 2 | portPRIVILEGE_BIT ).
*
* @param pvCreatedTask Used to pass back a handle by which the created task
* can be referenced.
*
* @return pdPASS if the task was successfully created and added to a ready
* list, otherwise an error code defined in the file errors. h
*
* Example usage:
   <pre>
// Task to be created.
void vTaskCode( void * pvParameters )
{
     for( ;; )
     {
         // Task code goes here.
     }
}

// Function that creates a task.
void vOtherFunction( void )
{
static unsigned char ucParameterToPass;
xTaskHandle xHandle;

     // Create the task, storing the handle.  Note that the passed parameter ucParameterToPass
     // must exist for the lifetime of the task, so in this case is declared static.  If it was just an
     // an automatic stack variable it might no longer exist, or at least have been corrupted, by the time
     // the new task attempts to access it.
     xTaskCreate( vTaskCode, "NAME", STACK_SIZE, &ucParameterToPass, tskIDLE_PRIORITY, &xHandle );

     // Use the handle to delete the task.
     vTaskDelete( xHandle );
}

signed portBASE_TYPE xTaskGenericCreate( pdTASK_CODE pxTaskCode,
                                         const signed char * const pcName,
                                         unsigned short usStackDepth,
                                         void *pvParameters,
                                         unsigned portBASE_TYPE uxPriority,
                                         xTaskHandle *pxCreatedTask,
                                         portSTACK_TYPE *puxStackBuffer,
                                         const xMemoryRegion * const xRegions )
{
signed portBASE_TYPE xReturn;
tskTCB * pxNewTCB;

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

    /* Allocate the memory required by the TCB and stack for the new task,
    checking that the allocation was successful. */
    // 为任务分配TCB和堆栈空间
    pxNewTCB = prvAllocateTCBAndStack( usStackDepth, puxStackBuffer );
   
    if( pxNewTCB != NULL )
    {
        portSTACK_TYPE *pxTopOfStack;

        #if( portUSING_MPU_WRAPPERS == 1 )
            /* Should the task be created in privileged mode? */
            //是否将任务设置成特权级模式
            portBASE_TYPE xRunPrivileged;
            if( ( uxPriority & portPRIVILEGE_BIT ) != 0U )
            {
                xRun00000Privileged = pdTRUE;
            }
            else
            {
                xRunPrivileged = pdFALSE;
            }
            uxPriority &= ~portPRIVILEGE_BIT;
        #endif /* portUSING_MPU_WRAPPERS == 1 */
         
        /* Calculate the top of stack address.  This depends on whether the
        stack grows from high memory to low (as per the 80x86) or visa versa.
        portSTACK_GROWTH is used to make the result positive or negative as
        required by the port. */
        //堆栈的生长方向,从高地址到低地址
        #if( portSTACK_GROWTH < 0 )
        {
            //初始化堆栈栈顶位置和堆栈的字节对其方式
            pxTopOfStack = pxNewTCB->pxStack + ( usStackDepth - ( unsigned short ) 1 );
            pxTopOfStack = ( portSTACK_TYPE * ) ( ( ( portPOINTER_SIZE_TYPE ) pxTopOfStack ) & ( ( portPOINTER_SIZE_TYPE ) ~portBYTE_ALIGNMENT_MASK  ) );

            /* Check the alignment of the calculated top of stack is correct. */
            configASSERT( ( ( ( unsigned long ) pxTopOfStack & ( unsigned long ) portBYTE_ALIGNMENT_MASK ) == 0UL ) );
        }
        //堆栈的生长方向,从低地址到高地址
        #else /* portSTACK_GROWTH */
        {
            pxTopOfStack = pxNewTCB->pxStack;

            /* Check the alignment of the stack buffer is correct. */
            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 */

        /* Setup the newly allocated TCB with the initial state of the task. */
        //初始化任务控制块变量
        prvInitialiseTCBVariables( pxNewTCB, pcName, uxPriority, xRegions, usStackDepth );

        /* 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 )
        {
            pxNewTCB->pxTopOfStack = pxPortInitialiseStack( pxTopOfStack, pxTaskCode, pvParameters, xRunPrivileged );
        }
        #else /* portUSING_MPU_WRAPPERS */
        {
            pxNewTCB->pxTopOfStack = pxPortInitialiseStack( pxTopOfStack, pxTaskCode, pvParameters );
        }
        #endif /* portUSING_MPU_WRAPPERS */

        /* Check the alignment of the initialised stack. */
        portALIGNMENT_ASSERT_pxCurrentTCB( ( ( ( unsigned long ) pxNewTCB->pxTopOfStack & ( unsigned long ) portBYTE_ALIGNMENT_MASK ) == 0UL ) );
        
        //返回任务的句柄
        if( ( void * ) pxCreatedTask != NULL )
        {
            /* Pass the TCB out - in an anonymous way.  The calling function/
            task can use this as a handle to delete the task later if
            required.*/
            *pxCreatedTask = ( xTaskHandle ) pxNewTCB;
        }

        /* We are going to manipulate the task queues to add this task to a
        ready list, so must make sure no interrupts occur. */
        //
        taskENTER_CRITICAL();
        {
            uxCurrentNumberOfTasks++;
            if( pxCurrentTCB == NULL )
            {
                /* There are no other tasks, or all the other tasks are in
                the suspended state - make this the current task. */
                //当前没有任务执行
                pxCurrentTCB =  pxNewTCB;
                //如果是第一个任务
                if( uxCurrentNumberOfTasks == ( unsigned portBASE_TYPE ) 1 )
                {
                    /* This is the first task to be created so do the preliminary
                    initialisation required.  We will not recover if this call
                    fails, but we will report the failure. */
                    //初始化任务列表
                    prvInitialiseTaskLists();
                }
            }
            else
            {
                /* If the scheduler is not already running, make this task the
                current task if it is the highest priority task to be created
                so far. */
                if( xSchedulerRunning == pdFALSE )
                {
                    if( pxCurrentTCB->uxPriority <= uxPriority )
                    {
                        pxCurrentTCB = pxNewTCB;
                    }
                }
            }

            /* Remember the top priority to make context switching faster.  Use
            the priority in pxNewTCB as this has been capped to a valid value. */
            if( pxNewTCB->uxPriority > uxTopUsedPriority )
            {
                uxTopUsedPriority = pxNewTCB->uxPriority;
            }

            uxTaskNumber++;

            #if ( configUSE_TRACE_FACILITY == 1 )
            {
                /* Add a counter into the TCB for tracing only. */
                pxNewTCB->uxTCBNumber = uxTaskNumber;
            }
            #endif /* configUSE_TRACE_FACILITY */
            traceTASK_CREATE( pxNewTCB );

            //将任务加入到就绪队列里面
            prvAddTaskToReadyQueue( 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 the created task is of a higher priority than the current task
            then it should run now. */
            //判断是否需要任务切换
            if( pxCurrentTCB->uxPriority < uxPriority )
            {
                portYIELD_WITHIN_API();
            }
        }
    }

    return xReturn;
}
回复

使用道具 举报

1万

主题

6万

回帖

10万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
107031
QQ
 楼主| 发表于 2013-6-19 19:26:45 | 显示全部楼层
任务删除
void vTaskDelete( xTaskHandle xTaskToDelete )
    {
    tskTCB *pxTCB;
        taskENTER_CRITICAL();
        {
            /* Ensure a yield is performed if the current task is being
            deleted. */

            //如果要删除的任务是当前正在执行的任务
            if( xTaskToDelete == pxCurrentTCB )
            {
                xTaskToDelete = NULL;
            }
            /* If null is passed in here then we are deleting ourselves. */
            //得到当前任务控制块的句柄

            pxTCB = prvGetTCBFromHandle( xTaskToDelete );
            /* Remove task from the ready list and place in the    termination list.
            This will stop the task from be scheduled.  The idle task will check
            the termination list and free up any memory allocated by the
            scheduler for the TCB and stack. */

            if( uxListRemove( ( xListItem * ) &( pxTCB->xGenericListItem ) ) == 0 )
            {
                taskRESET_READY_PRIORITY( pxTCB->uxPriority );
            }
            /* Is the task waiting on an event also? */
            if( pxTCB->xEventListItem.pvContainer != NULL )
            {
                uxListRemove( &( pxTCB->xEventListItem ) );
            }
            vListInsertEnd( ( xList * ) &xTasksWaitingTermination, &( pxTCB->xGenericListItem ) );
            /* 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. */

            ++uxTasksDeleted;
            /* Increment the uxTaskNumberVariable also so kernel aware debuggers
            can detect that the task lists need re-generating. */

            uxTaskNumber++;

            traceTASK_DELETE( pxTCB );
        }
        taskEXIT_CRITICAL();
       /* Force a reschedule if we have just deleted the current task. */
       // 如果删除的是当前的任务,那么产生一次调度
        if( xSchedulerRunning != pdFALSE )
        {
            if( ( void * ) xTaskToDelete == NULL )
            {
                portYIELD_WITHIN_API();
            }
        }
    }
回复

使用道具 举报

1万

主题

6万

回帖

10万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
107031
QQ
 楼主| 发表于 2013-6-19 20:16:13 | 显示全部楼层
任务延时
void vTaskDelayUntil( portTickType * const pxPreviousWakeTime, portTickType xTimeIncrement )
    {
    portTickType xTimeToWake;
    portBASE_TYPE xAlreadyYielded, xShouldDelay = pdFALSE;

        configASSERT( pxPreviousWakeTime );
        configASSERT( ( xTimeIncrement > 0U ) );
        vTaskSuspendAll();
        {
            /* Generate the tick time at which the task wants to wake. */
            xTimeToWake = *pxPreviousWakeTime + xTimeIncrement;
            //如果当前计数小于唤醒时间
            if( xTickCount < *pxPreviousWakeTime )
            {
                /* The tick count has overflowed since this function was
                lasted called.  In this case the only time we should ever
                actually delay is if the wake time has also    overflowed,
                and the wake time is greater than the tick time.  When this
                is the case it is as if neither time had overflowed. */
                if( ( xTimeToWake < *pxPreviousWakeTime ) && ( xTimeToWake > xTickCount ) )
                {
                    xShouldDelay = pdTRUE;
                }
            }
            //当前计数大于唤醒时间
            else
            {
                /* The tick time has not overflowed.  In this case we will
                delay if either the wake time has overflowed, and/or the
                tick time is less than the wake time. */
                if( ( xTimeToWake < *pxPreviousWakeTime ) || ( xTimeToWake > xTickCount ) )
                {
                    xShouldDelay = pdTRUE;
                }
            }
            /* Update the wake time ready for the next call. */
            *pxPreviousWakeTime = xTimeToWake;
            if( xShouldDelay != pdFALSE )
            {
                traceTASK_DELAY_UNTIL();

                /* We must remove ourselves from the ready list before adding
                ourselves to the blocked list as the same list item is used for
                both lists. */
                if( uxListRemove( ( xListItem * ) &( pxCurrentTCB->xGenericListItem ) ) == 0 )
                {
                    /* The current task must be in a ready list, so there is
                    no need to check, and the port reset macro can be called
                    directly. */
                    portRESET_READY_PRIORITY( pxCurrentTCB->uxPriority, uxTopReadyPriority );
                }

                prvAddCurrentTaskToDelayedList( xTimeToWake );
            }
        }
        xAlreadyYielded = xTaskResumeAll();
        /* Force a reschedule if xTaskResumeAll has not already done so, we may
        have put ourselves to sleep. */
        if( xAlreadyYielded == pdFALSE )
        {
            portYIELD_WITHIN_API();
        }
    }

void vTaskDelay( portTickType xTicksToDelay )
    {
    portTickType xTimeToWake;
    signed portBASE_TYPE xAlreadyYielded = pdFALSE;

        /* A delay time of zero just forces a reschedule. */
        //
        if( xTicksToDelay > ( portTickType ) 0U )
        {
            vTaskSuspendAll();
            {
                traceTASK_DELAY();

                /* A task that is removed from the event list while the
                scheduler is suspended will not get placed in the ready
                list or removed from the blocked list until the scheduler
                is resumed.

                This task cannot be in an event list as it is the currently
                executing task. */

                /* Calculate the time to wake - this may overflow but this is
                not a problem. */
                xTimeToWake = xTickCount + xTicksToDelay;

                /* We must remove ourselves from the ready list before adding
                ourselves to the blocked list as the same list item is used for
                both lists. */
               //从当前任务就序列表里面删除任务
                if( uxListRemove( ( xListItem * ) &( pxCurrentTCB->xGenericListItem ) ) == 0 )
                {
                    /* The current task must be in a ready list, so there is
                    no need to check, and the port reset macro can be called
                    directly. */
                    portRESET_READY_PRIORITY( pxCurrentTCB->uxPriority, uxTopReadyPriority );
                }
                //将当前任务加入到延迟列表里面
                prvAddCurrentTaskToDelayedList( xTimeToWake );
            }
            xAlreadyYielded = xTaskResumeAll();
        }

        /* Force a reschedule if xTaskResumeAll has not already done so, we may
        have put ourselves to sleep. */
        if( xAlreadyYielded == pdFALSE )
        {
            portYIELD_WITHIN_API();
        }
    }
回复

使用道具 举报

1万

主题

6万

回帖

10万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
107031
QQ
 楼主| 发表于 2013-6-20 19:06:59 | 显示全部楼层
任务挂起
void vTaskSuspend( xTaskHandle xTaskToSuspend )
    {
    tskTCB *pxTCB;

        taskENTER_CRITICAL();
        {
            /* Ensure a yield is performed if the current task is being
            suspended. */
            //如果要挂起的任务是当前正在执行的任务
            if( xTaskToSuspend == ( xTaskHandle ) pxCurrentTCB )
            {
                xTaskToSuspend = NULL;
            }

            /* If null is passed in here then we are suspending ourselves. */
            //得到任务的句柄
            pxTCB = prvGetTCBFromHandle( xTaskToSuspend );

            traceTASK_SUSPEND( pxTCB );

            /* Remove task from the ready/delayed list and place in the    suspended list. */
            //将任务从就绪或延时列表中删除,放到挂起列表中
            if( uxListRemove( ( xListItem * ) &( pxTCB->xGenericListItem ) ) == 0 )
            {
                taskRESET_READY_PRIORITY( pxTCB->uxPriority );
            }

            /* Is the task waiting on an event also? */
            //任务是否在等待其他事件
            if( pxTCB->xEventListItem.pvContainer != NULL )
            {
                uxListRemove( &( pxTCB->xEventListItem ) );
            }

            vListInsertEnd( ( xList * ) &xSuspendedTaskList, &( pxTCB->xGenericListItem ) );
        }
        taskEXIT_CRITICAL();

        //如果要挂起的是当前执行的任务
        if( ( void * ) xTaskToSuspend == NULL )
        {
            //调度器已经开始工作
            if( xSchedulerRunning != pdFALSE )
            {
                /* We have just suspended the current task. */
                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 )
                {
                    /* 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. */
                    pxCurrentTCB = NULL;
                }
                else
                {
                    vTaskSwitchContext();
                }
            }
        }
    }
回复

使用道具 举报

1万

主题

6万

回帖

10万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
107031
QQ
 楼主| 发表于 2013-6-20 19:20:29 | 显示全部楼层
任务恢复
void vTaskResume( xTaskHandle xTaskToResume )
    {
    tskTCB *pxTCB;

        /* It does not make sense to resume the calling task. */
        configASSERT( xTaskToResume );

        /* Remove the task from whichever list it is currently in, and place
        it in the ready list. */

        pxTCB = ( tskTCB * ) xTaskToResume;

        /* The parameter cannot be NULL as it is impossible to resume the
        currently executing task. */

        if( ( pxTCB != NULL ) && ( pxTCB != pxCurrentTCB ) )
        {
            taskENTER_CRITICAL();
            {
                if( xTaskIsTaskSuspended( pxTCB ) == pdTRUE )
                {
                    traceTASK_RESUME( pxTCB );

                    /* As we are in a critical section we can access the ready
                    lists even if the scheduler is suspended. */

                    uxListRemove(  &( pxTCB->xGenericListItem ) );
                    prvAddTaskToReadyQueue( pxTCB );

                    /* We may have just resumed a higher priority task. */
                    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. */

                        portYIELD_WITHIN_API();
                    }
                }
            }
            taskEXIT_CRITICAL();
        }
    }
回复

使用道具 举报

0

主题

4

回帖

0

积分

新手上路

积分
0
发表于 2014-5-8 19:06:06 | 显示全部楼层
写的很好啊,赞~~
回复

使用道具 举报

0

主题

2

回帖

0

积分

新手上路

积分
0
发表于 2014-12-18 16:03:18 | 显示全部楼层
你好,我想问下portYIELD_WITHIN_API();怎么实现的?,我进去后发现他是在中断中将地址改了,对于这里的地址分配我不了解,希望能说下.
    /* Set a PendSV to request a context switch. */
    *(portNVIC_INT_CTRL) = portNVIC_PENDSVSET;


#define portNVIC_SYSTICK_CTRL   ((volatile unsigned long *) 0xe000e010)
#define portNVIC_SYSTICK_LOAD   ((volatile unsigned long *) 0xe000e014)
#define portNVIC_INT_CTRL       ((volatile unsigned long *) 0xe000ed04)
#define portNVIC_SYSPRI2        ((volatile unsigned long *) 0xe000ed20)
#define portNVIC_SYSTICK_CLK    0x00000004
#define portNVIC_SYSTICK_INT    0x00000002
#define portNVIC_SYSTICK_ENABLE 0x00000001
#define portNVIC_PENDSVSET      0x10000000
回复

使用道具 举报

1万

主题

6万

回帖

10万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
107031
QQ
 楼主| 发表于 2014-12-18 16:08:08 | 显示全部楼层

回 aolongzx 的帖子

aolongzx:你好,我想问下portYIELD_WITHIN_API();怎么实现的?,我进去后发现他是在中断中将地址改了,对于这里的地址分配我不了解,希望能说下.
    /* Set a PendSV to request a context switch. */
    *(portNVIC_INT_CTRL) = portNVIC_PENDS .. (2014-12-18 16:03) 
这个很久没有看源码了,待我再看后跟你解答。
回复

使用道具 举报

0

主题

2

回帖

0

积分

新手上路

积分
0
发表于 2014-12-18 16:17:38 | 显示全部楼层
好的,3q,我还发了个消息问了另一个问题
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

QQ|小黑屋|Archiver|手机版|硬汉嵌入式论坛

GMT+8, 2024-5-15 02:16 , Processed in 0.291922 second(s), 31 queries .

Powered by Discuz! X3.4 Licensed

Copyright © 2001-2023, Tencent Cloud.

快速回复 返回顶部 返回列表