FreeRTOS任务挂起以及延时部分源码分析


layout: post
title: “任务状态”
date: 2023-7-19 15:39:08 +0800
tags: FreeRTOS


任务状态

fireRTOS代码分析

任务挂起

//把一个任务挂起
void vTaskSuspend( TaskHandle_t xTaskToSuspend )
{
    TCB_t *pxTCB;

    taskENTER_CRITICAL();//进入临界区
    {
        /* 参数是NULL的时候设置为当前任务, 否则返回这一个参数的TCB */
        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 ) );
        }
		//插入挂起的队列
        vListInsertEnd( &xSuspendedTaskList, &( pxTCB->xStateListItem ) );
	
        #if( configUSE_TASK_NOTIFICATIONS == 1 )
        {
            if( pxTCB->ucNotifyState == taskWAITING_NOTIFICATION )
            {
                /* The task was blocked to wait for a 通知, but is
					now suspended, so no notification was received. */
                pxTCB->ucNotifyState = taskNOT_WAITING_NOTIFICATION;
            }
        }
        #endif
    }
    taskEXIT_CRITICAL();

    if( xSchedulerRunning != pdFALSE )
    {
        /* 重新设置一下下一个软件时钟的时间(一般用于Delay以及等待事件) */
        taskENTER_CRITICAL();
        {
            prvResetNextTaskUnblockTime();
        }
        taskEXIT_CRITICAL();
    }

    if( pxTCB == pxCurrentTCB )
    {
        if( xSchedulerRunning != pdFALSE )
        {
            /* 调度器在运行 */
            configASSERT( uxSchedulerSuspended == 0 );
            //切换任务
            portYIELD_WITHIN_API();
        }
        else
        {
            /* 调度器没有运行(不能进行任务切换) */
            if( listCURRENT_LIST_LENGTH( &xSuspendedTaskList ) == uxCurrentNumberOfTasks )
            {
                /* 没有其他的任务了 */
                pxCurrentTCB = NULL;
            }
            else
            {
                //把记录当前任务的全局变量改为优先级最高的一个任务
                vTaskSwitchContext();
            }
        }
    }
    else
    {
        mtCOVERAGE_TEST_MARKER();
    }
}

恢复挂起的任务

//恢复挂起的任务
void vTaskResume( TaskHandle_t xTaskToResume )
{
    TCB_t * const pxTCB = ( TCB_t * ) xTaskToResume;

    /* 同上 */
    if( ( pxTCB != NULL ) && ( pxTCB != pxCurrentTCB ) )
    {
        taskENTER_CRITICAL();
        {
            //检测是不是真的被挂起了
            if( prvTaskIsTaskSuspended( pxTCB ) != pdFALSE )
            {
                traceTASK_RESUME( pxTCB );

                /* 从挂起的链表里面移除 */
                ( void ) uxListRemove(  &( pxTCB->xStateListItem ) );
                //加入就绪列表
                prvAddTaskToReadyList( pxTCB );

                /* A higher priority task may have just been resumed. */
                if( pxTCB->uxPriority >= pxCurrentTCB->uxPriority )
                {
                    /* 优先级比较当前任务高, 进行一次任务切换 */
                    taskYIELD_IF_USING_PREEMPTION();
                }
            }
        }
        taskEXIT_CRITICAL();
    }
}
//恢复所有挂起的任务
BaseType_t xTaskResumeAll( void )
{
TCB_t *pxTCB = NULL;
BaseType_t xAlreadyYielded = pdFALSE;

	/* If uxSchedulerSuspended is zero then this function does not match a
	previous call to vTaskSuspendAll(). */
	configASSERT( uxSchedulerSuspended );

	/* It is possible that an ISR caused a task to be removed from an event
	list while the scheduler was suspended.  If this was the case then the
	removed task will have been added to the xPendingReadyList.  Once the
	scheduler has been resumed it is safe to move all the pending ready
	tasks from this list into their appropriate ready list. 
	如果之前的任务有在ISR中并且任务调度实现的时候被从事件List里面移除, 需要处理 */
	taskENTER_CRITICAL();
	{
        //任务切换挂起的记录减一
		--uxSchedulerSuspended;

		if( uxSchedulerSuspended == ( UBaseType_t ) pdFALSE )
		{
			if( uxCurrentNumberOfTasks > ( UBaseType_t ) 0U )
			{
				/* Move any readied tasks from the pending list into the
				appropriate ready list. 这是一个等待恢复的队列, 一般是在时钟挂起的时候转为ready的任务 */
				while( listLIST_IS_EMPTY( &xPendingReadyList ) == pdFALSE )
				{
                    //处理待处理的任务
					pxTCB = ( TCB_t * ) listGET_OWNER_OF_HEAD_ENTRY( ( &xPendingReadyList ) );
					( void ) uxListRemove( &( pxTCB->xEventListItem ) );
					( void ) uxListRemove( &( pxTCB->xStateListItem ) );
					prvAddTaskToReadyList( pxTCB );

					/* If the moved task has a priority higher than the current
					task then a yield must be performed. */
					if( pxTCB->uxPriority >= pxCurrentTCB->uxPriority )
					{
                        //需要优先级切换
						xYieldPending = pdTRUE;
					}
					else
					{
						mtCOVERAGE_TEST_MARKER();
					}
				}

				if( pxTCB != NULL )
				{
					/* A task was unblocked while the scheduler was suspended,
					which may have prevented the next unblock time from being
					re-calculated, in which case re-calculate it now.  Mainly
					important for low power tickless implementations, where
					this can prevent an unnecessary exit from low power
					state. 更新一下下一个需要处理的Delay时钟的值 */
					prvResetNextTaskUnblockTime();
				}

				/* If any ticks occurred while the scheduler was suspended then
				they should be processed now.  This ensures the tick count does
				not	slip, and that any delayed tasks are resumed at the correct
				time. 
				处理挂期间任务的待处理事项*/
				{
					UBaseType_t uxPendedCounts = uxPendedTicks; /* Non-volatile copy. */

					if( uxPendedCounts > ( UBaseType_t ) 0U )
					{
						do
						{
                            //调用时钟处理函数, 更新一下时钟值
							if( xTaskIncrementTick() != pdFALSE )
							{
								xYieldPending = pdTRUE;
							}
							else
							{
								mtCOVERAGE_TEST_MARKER();
							}
							--uxPendedCounts;//记录挂起的时钟数
						} while( uxPendedCounts > ( UBaseType_t ) 0U );

						uxPendedTicks = 0;
					}
					else
					{
						mtCOVERAGE_TEST_MARKER();
					}
				}

				if( xYieldPending != pdFALSE )
				{
					#if( configUSE_PREEMPTION != 0 )
					{
						xAlreadyYielded = pdTRUE;
					}
					#endif
                    //任务切换
					taskYIELD_IF_USING_PREEMPTION();
				}
			}
	}
	taskEXIT_CRITICAL();

	return xAlreadyYielded;
}

延时函数

void vTaskDelay( const TickType_t xTicksToDelay )
{
    BaseType_t xAlreadyYielded = pdFALSE;

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

            /* 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. 把这一个任务插入Delay队列里面 */
            prvAddCurrentTaskToDelayedList( xTicksToDelay, pdFALSE );
        }
        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();
    }
    else
    {
        mtCOVERAGE_TEST_MARKER();
    }
}
static void prvAddCurrentTaskToDelayedList( TickType_t xTicksToWait, const BaseType_t xCanBlockIndefinitely )
{
TickType_t xTimeToWake;
const TickType_t xConstTickCount = xTickCount;

	/* 把当前的任务从运行的任务里面删除 */
	if( uxListRemove( &( pxCurrentTCB->xStateListItem ) ) == ( UBaseType_t ) 0 )
	{
		/* 这个优先级没有任务了, 清除标志位 */
		portRESET_READY_PRIORITY( pxCurrentTCB->uxPriority, uxTopReadyPriority );
	}
	else
	{
		mtCOVERAGE_TEST_MARKER();
	}

    if( ( xTicksToWait == portMAX_DELAY ) && ( xCanBlockIndefinitely != pdFALSE ) )
    {
        /* 设置的时间是无限, 直接挂起. */
        vListInsertEnd( &xSuspendedTaskList, &( pxCurrentTCB->xStateListItem ) );
    }
    else
    {
        /* 计算唤醒的时间 */
        xTimeToWake = xConstTickCount + xTicksToWait;

        /* 设置时钟 */
        listSET_LIST_ITEM_VALUE( &( pxCurrentTCB->xStateListItem ), xTimeToWake );

        if( xTimeToWake < xConstTickCount )
        {
            /* 溢出列表. */
            vListInsert( pxOverflowDelayedTaskList, &( pxCurrentTCB->xStateListItem ) );
        }
        else
        {
            /* 不是溢出 */
            vListInsert( pxDelayedTaskList, &( pxCurrentTCB->xStateListItem ) );

            /* 设置下一次的唤醒时间 */
            if( xTimeToWake < xNextTaskUnblockTime )
            {
                xNextTaskUnblockTime = xTimeToWake;
            }
            else
            {
                mtCOVERAGE_TEST_MARKER();
            }
        }
    }
	
}
void vTaskDelayUntil( TickType_t * const pxPreviousWakeTime, const TickType_t xTimeIncrement )
{
    TickType_t xTimeToWake;
    BaseType_t xAlreadyYielded, xShouldDelay = pdFALSE;

    configASSERT( pxPreviousWakeTime );
    configASSERT( ( xTimeIncrement > 0U ) );
    configASSERT( uxSchedulerSuspended == 0 );

    vTaskSuspendAll();
    {
        /* Minor optimisation.  The tick count cannot change in this
			block. */
        const TickType_t xConstTickCount = xTickCount;

        /* Generate the tick time at which the task wants to wake. */
        xTimeToWake = *pxPreviousWakeTime + xTimeIncrement;
		//节拍器溢出
        if( xConstTickCount < *pxPreviousWakeTime )
        {
            /* 唤醒时间和现在的时间都已经溢出过了 */
            if( ( xTimeToWake < *pxPreviousWakeTime ) && ( xTimeToWake > xConstTickCount ) )
            {
                xShouldDelay = pdTRUE;
            }
            else
            {
                mtCOVERAGE_TEST_MARKER();
            }
        }
        else
        {
            /* 只有溢出时间溢出了, 或者都没有溢出 */
            if( ( xTimeToWake < *pxPreviousWakeTime ) || ( xTimeToWake > xConstTickCount ) )
            {
                xShouldDelay = pdTRUE;
            }
            else
            {
                mtCOVERAGE_TEST_MARKER();
            }
        }

        /* Update the wake time ready for the next call. */
        *pxPreviousWakeTime = xTimeToWake;

        if( xShouldDelay != pdFALSE )
        {
            traceTASK_DELAY_UNTIL( xTimeToWake );

				/* 插入到延时链表里面 */
				prvAddCurrentTaskToDelayedList( xTimeToWake - xConstTickCount, pdFALSE );
			}
			else
			{
				mtCOVERAGE_TEST_MARKER();
			}
		}
		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();
    }
    else
    {
        mtCOVERAGE_TEST_MARKER();
    }
}

你可能感兴趣的:(FreRTOS笔记,stm32,单片机,mcu,c语言)