configMAX_PRIORITIES
,该数量受MCU内存限制,数量越多,占用内存越高void StartDefaultTask(void const * argument) { for(;;) { osDelay(1); } }
任务堆栈信息数据结构
任务调度信息app
任务建立信息less
任务通知信息ide
任务互斥信息函数
任务调试信息源码分析
选项 | 解释 |
---|---|
*pxTopOfStack | 任务堆栈栈顶 |
xStateListltem | 状态列表项 |
xEventListltem | 事件列表项 |
uxPriority | 任务优先级 |
*pxStack | 任务栈起始地址 |
pcTaskName[] | 任务名称 |
*pxEndOfStack | 任务堆栈栈底 |
#if( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) BaseType_t xTaskCreate( TaskFunction_t pxTaskCode, const char * const pcName, /*lint !e971 Unqualified char types are allowed for strings and single characters only. */ const configSTACK_DEPTH_TYPE usStackDepth, void * const pvParameters, UBaseType_t uxPriority, TaskHandle_t * const pxCreatedTask ) { TCB_t *pxNewTCB; BaseType_t xReturn; /* 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. */ #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 ) { #if( tskSTATIC_AND_DYNAMIC_ALLOCATION_POSSIBLE != 0 ) /*lint !e731 Macro has been consolidated for readability reasons. */ { /* Tasks can be created statically or dynamically, so note this task was created dynamically in case it is later deleted. */ pxNewTCB->ucStaticallyAllocated = tskDYNAMICALLY_ALLOCATED_STACK_AND_TCB; } #endif /* configSUPPORT_STATIC_ALLOCATION */ /*初始化任务控制块与堆栈*/ prvInitialiseNewTask( pxTaskCode, pcName, ( uint32_t ) usStackDepth, pvParameters, uxPriority, pxCreatedTask, pxNewTCB, NULL ); /*添加任务到就绪列表中*/ prvAddNewTaskToReadyList( pxNewTCB ); xReturn = pdPASS; } else { xReturn = errCOULD_NOT_ALLOCATE_REQUIRED_MEMORY; } return xReturn; } #endif /* configSUPPORT_DYNAMIC_ALLOCATION */
void vTaskDelete( TaskHandle_t xTaskToDelete ) { TCB_t *pxTCB; taskENTER_CRITICAL(); { /* If null is passed in here then it is the calling task that is being deleted. */ pxTCB = prvGetTCBFromHandle( xTaskToDelete ); /* Remove task from the ready list. */ if( uxListRemove( &( pxTCB->xStateListItem ) ) == ( UBaseType_t ) 0 ) { taskRESET_READY_PRIORITY( pxTCB->uxPriority ); } else { mtCOVERAGE_TEST_MARKER(); } /* Is the task waiting on an event also? */ if( listLIST_ITEM_CONTAINER( &( pxTCB->xEventListItem ) ) != NULL ) { ( void ) uxListRemove( &( pxTCB->xEventListItem ) ); } else { mtCOVERAGE_TEST_MARKER(); } /* Increment the uxTaskNumber also so kernel aware debuggers can detect that the task lists need re-generating. This is done before portPRE_TASK_DELETE_HOOK() as in the Windows port that macro will not return. */ uxTaskNumber++; if( pxTCB == pxCurrentTCB ) { /* A task is deleting itself. This cannot complete within the task itself, as a context switch to another task is required. Place the task in the termination list. The idle task will check the termination list and free up any memory allocated by the scheduler for the TCB and stack of the deleted task. */ vListInsertEnd( &xTasksWaitingTermination, &( pxTCB->xStateListItem ) ); /* 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. */ ++uxDeletedTasksWaitingCleanUp; /* The pre-delete hook is primarily for the Windows simulator, in which Windows specific clean up operations are performed, after which it is not possible to yield away from this task - hence xYieldPending is used to latch that a context switch is required. */ portPRE_TASK_DELETE_HOOK( pxTCB, &xYieldPending ); } else { --uxCurrentNumberOfTasks; prvDeleteTCB( pxTCB ); /* Reset the next expected unblock time in case it referred to the task that has just been deleted. */ prvResetNextTaskUnblockTime(); } traceTASK_DELETE( pxTCB ); } taskEXIT_CRITICAL(); /* Force a reschedule if it is the currently running task that has just been deleted. */ if( xSchedulerRunning != pdFALSE ) { if( pxTCB == pxCurrentTCB ) { configASSERT( uxSchedulerSuspended == 0 ); portYIELD_WITHIN_API(); } else { mtCOVERAGE_TEST_MARKER(); } } }
void vTaskSuspend( TaskHandle_t xTaskToSuspend ) { TCB_t *pxTCB; taskENTER_CRITICAL(); { /* If null is passed in here then it is the running task that is being suspended. */ pxTCB = prvGetTCBFromHandle( xTaskToSuspend ); traceTASK_SUSPEND( pxTCB ); /* Remove task from the ready/delayed list and place in the suspended list. */ if( uxListRemove( &( pxTCB->xStateListItem ) ) == ( UBaseType_t ) 0 ) { taskRESET_READY_PRIORITY( pxTCB->uxPriority ); } else { mtCOVERAGE_TEST_MARKER(); } /* Is the task waiting on an event also? */ if( listLIST_ITEM_CONTAINER( &( pxTCB->xEventListItem ) ) != NULL ) { ( void ) uxListRemove( &( pxTCB->xEventListItem ) ); } else { mtCOVERAGE_TEST_MARKER(); } vListInsertEnd( &xSuspendedTaskList, &( pxTCB->xStateListItem ) ); #if( configUSE_TASK_NOTIFICATIONS == 1 ) { if( pxTCB->ucNotifyState == taskWAITING_NOTIFICATION ) { /* The task was blocked to wait for a notification, but is now suspended, so no notification was received. */ pxTCB->ucNotifyState = taskNOT_WAITING_NOTIFICATION; } } #endif } taskEXIT_CRITICAL(); if( xSchedulerRunning != pdFALSE ) { /* Reset the next expected unblock time in case it referred to the task that is now in the Suspended state. */ taskENTER_CRITICAL(); { prvResetNextTaskUnblockTime(); } taskEXIT_CRITICAL(); } else { mtCOVERAGE_TEST_MARKER(); } if( pxTCB == pxCurrentTCB ) { if( xSchedulerRunning != pdFALSE ) { /* The current task has just been suspended. */ configASSERT( uxSchedulerSuspended == 0 ); 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(); } } } else { mtCOVERAGE_TEST_MARKER(); } }
void vTaskResume( TaskHandle_t xTaskToResume ) { TCB_t * const pxTCB = ( TCB_t * ) xTaskToResume; /* It does not make sense to resume the calling task. */ configASSERT( xTaskToResume ); /* The parameter cannot be NULL as it is impossible to resume the currently executing task. */ if( ( pxTCB != NULL ) && ( pxTCB != pxCurrentTCB ) ) { taskENTER_CRITICAL(); { if( prvTaskIsTaskSuspended( pxTCB ) != pdFALSE ) { traceTASK_RESUME( pxTCB ); /* The ready list can be accessed even if the scheduler is suspended because this is inside a critical section. */ ( void ) uxListRemove( &( pxTCB->xStateListItem ) ); prvAddTaskToReadyList( pxTCB ); /* A higher priority task may have just been resumed. */ 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. */ taskYIELD_IF_USING_PREEMPTION(); } else { mtCOVERAGE_TEST_MARKER(); } } else { mtCOVERAGE_TEST_MARKER(); } } taskEXIT_CRITICAL(); } else { mtCOVERAGE_TEST_MARKER(); } }
void vTaskStartScheduler( void ) { BaseType_t xReturn; /* Add the idle task at the lowest priority. */ #if( configSUPPORT_STATIC_ALLOCATION == 1 ) { StaticTask_t *pxIdleTaskTCBBuffer = NULL; StackType_t *pxIdleTaskStackBuffer = NULL; uint32_t ulIdleTaskStackSize; /* The Idle task is created using user provided RAM - obtain the address of the RAM then create the idle task. */ vApplicationGetIdleTaskMemory( &pxIdleTaskTCBBuffer, &pxIdleTaskStackBuffer, &ulIdleTaskStackSize ); /*静态建立空闲任务,此处配置任务控制块*/ xIdleTaskHandle = xTaskCreateStatic( prvIdleTask, configIDLE_TASK_NAME, ulIdleTaskStackSize, ( void * ) NULL, /*lint !e961. The cast is not redundant for all compilers. */ ( tskIDLE_PRIORITY | portPRIVILEGE_BIT ), pxIdleTaskStackBuffer, pxIdleTaskTCBBuffer ); /*lint !e961 MISRA exception, justified as it is not a redundant explicit cast to all supported compilers. */ /*判断任务是否建立成功*/ if( xIdleTaskHandle != NULL ) { xReturn = pdPASS; } else { xReturn = pdFAIL; } } #else { /* The Idle task is being created using dynamically allocated RAM. */ xReturn = xTaskCreate( prvIdleTask, configIDLE_TASK_NAME, configMINIMAL_STACK_SIZE, ( void * ) NULL, ( tskIDLE_PRIORITY | portPRIVILEGE_BIT ), &xIdleTaskHandle ); /*lint !e961 MISRA exception, justified as it is not a redundant explicit cast to all supported compilers. */ } #endif /* configSUPPORT_STATIC_ALLOCATION */ /*是否建立软件定时器*/ #if ( configUSE_TIMERS == 1 ) { if( xReturn == pdPASS ) { xReturn = xTimerCreateTimerTask(); } else { mtCOVERAGE_TEST_MARKER(); } } #endif /* configUSE_TIMERS */ if( xReturn == pdPASS ) { /* freertos_tasks_c_additions_init() should only be called if the user definable macro FREERTOS_TASKS_C_ADDITIONS_INIT() is defined, as that is the only macro called by the function. */ #ifdef FREERTOS_TASKS_C_ADDITIONS_INIT { freertos_tasks_c_additions_init(); } #endif /* Interrupts are turned off here, to ensure a tick does not occur before or during the call to xPortStartScheduler(). The stacks of the created tasks contain a status word with interrupts switched on so interrupts will automatically get re-enabled when the first task starts to run. */ portDISABLE_INTERRUPTS(); #if ( configUSE_NEWLIB_REENTRANT == 1 ) { /* Switch Newlib's _impure_ptr variable to point to the _reent structure specific to the task that will run first. */ _impure_ptr = &( pxCurrentTCB->xNewLib_reent ); } #endif /* configUSE_NEWLIB_REENTRANT */ xNextTaskUnblockTime = portMAX_DELAY; /*开启任务调度*/ xSchedulerRunning = pdTRUE; /*Systick计数器置0*/ xTickCount = ( TickType_t ) 0U; /* If configGENERATE_RUN_TIME_STATS is defined then the following macro must be defined to configure the timer/counter used to generate the run time counter time base. NOTE: If configGENERATE_RUN_TIME_STATS is set to 0 and the following line fails to build then ensure you do not have portCONFIGURE_TIMER_FOR_RUN_TIME_STATS() defined in your FreeRTOSConfig.h file. */ portCONFIGURE_TIMER_FOR_RUN_TIME_STATS(); /* Setting up the timer tick is hardware specific and thus in the portable interface. */ if( xPortStartScheduler() != pdFALSE ) { /* Should not reach here as if the scheduler is running the function will not return. */ } else { /* Should only reach here if a task calls xTaskEndScheduler(). */ } } else { /* This line will only be reached if the kernel could not be started, because there was not enough FreeRTOS heap to create the idle task or the timer task. */ configASSERT( xReturn != errCOULD_NOT_ALLOCATE_REQUIRED_MEMORY ); } /* Prevent compiler warnings if INCLUDE_xTaskGetIdleTaskHandle is set to 0, meaning xIdleTaskHandle is not used anywhere else. */ ( void ) xIdleTaskHandle; } BaseType_t xPortStartScheduler( void ) { #if( configASSERT_DEFINED == 1 ) { volatile uint32_t ulOriginalPriority; volatile uint8_t * const pucFirstUserPriorityRegister = ( uint8_t * ) ( portNVIC_IP_REGISTERS_OFFSET_16 + portFIRST_USER_INTERRUPT_NUMBER ); volatile uint8_t ucMaxPriorityValue; /* Determine the maximum priority from which ISR safe FreeRTOS API functions can be called. ISR safe functions are those that end in "FromISR". FreeRTOS maintains separate thread and ISR API functions to ensure interrupt entry is as fast and simple as possible. Save the interrupt priority value that is about to be clobbered. */ ulOriginalPriority = *pucFirstUserPriorityRegister; /* Determine the number of priority bits available. First write to all possible bits. */ *pucFirstUserPriorityRegister = portMAX_8_BIT_VALUE; /* Read the value back to see how many bits stuck. */ ucMaxPriorityValue = *pucFirstUserPriorityRegister; /* The kernel interrupt priority should be set to the lowest priority. */ configASSERT( ucMaxPriorityValue == ( configKERNEL_INTERRUPT_PRIORITY & ucMaxPriorityValue ) ); /* Use the same mask on the maximum system call priority. */ ucMaxSysCallPriority = configMAX_SYSCALL_INTERRUPT_PRIORITY & ucMaxPriorityValue; /* Calculate the maximum acceptable priority group value for the number of bits read back. */ ulMaxPRIGROUPValue = portMAX_PRIGROUP_BITS; while( ( ucMaxPriorityValue & portTOP_BIT_OF_BYTE ) == portTOP_BIT_OF_BYTE ) { ulMaxPRIGROUPValue--; ucMaxPriorityValue <<= ( uint8_t ) 0x01; } #ifdef __NVIC_PRIO_BITS { /* Check the CMSIS configuration that defines the number of priority bits matches the number of priority bits actually queried from the hardware. */ configASSERT( ( portMAX_PRIGROUP_BITS - ulMaxPRIGROUPValue ) == __NVIC_PRIO_BITS ); } #endif #ifdef configPRIO_BITS { /* Check the FreeRTOS configuration that defines the number of priority bits matches the number of priority bits actually queried from the hardware. */ configASSERT( ( portMAX_PRIGROUP_BITS - ulMaxPRIGROUPValue ) == configPRIO_BITS ); } #endif /* Shift the priority group value back to its position within the AIRCR register. */ ulMaxPRIGROUPValue <<= portPRIGROUP_SHIFT; ulMaxPRIGROUPValue &= portPRIORITY_GROUP_MASK; /* Restore the clobbered interrupt priority register to its original value. */ *pucFirstUserPriorityRegister = ulOriginalPriority; } #endif /* conifgASSERT_DEFINED */ /* Make PendSV and SysTick the lowest priority interrupts. */ portNVIC_SYSPRI2_REG |= portNVIC_PENDSV_PRI; portNVIC_SYSPRI2_REG |= portNVIC_SYSTICK_PRI; /* Start the timer that generates the tick ISR. Interrupts are disabled here already. */ vPortSetupTimerInterrupt(); /* Initialise the critical nesting count ready for the first task. */ uxCriticalNesting = 0; /* Start the first task. */ prvStartFirstTask(); /* Should not get here! */ return 0; } /*初始化Systick值,即将其置0,系统上电的时候Systick的值并非0*/ void vPortSetupTimerInterrupt( void ) { /* Calculate the constants required to configure the tick interrupt. */ #if( configUSE_TICKLESS_IDLE == 1 ) { ulTimerCountsForOneTick = ( configSYSTICK_CLOCK_HZ / configTICK_RATE_HZ ); xMaximumPossibleSuppressedTicks = portMAX_24_BIT_NUMBER / ulTimerCountsForOneTick; ulStoppedTimerCompensation = portMISSED_COUNTS_FACTOR / ( configCPU_CLOCK_HZ / configSYSTICK_CLOCK_HZ ); } #endif /* configUSE_TICKLESS_IDLE */ /* Stop and clear the SysTick. */ portNVIC_SYSTICK_CTRL_REG = 0UL; portNVIC_SYSTICK_CURRENT_VALUE_REG = 0UL; /* Configure SysTick to interrupt at the requested rate. */ portNVIC_SYSTICK_LOAD_REG = ( configSYSTICK_CLOCK_HZ / configTICK_RATE_HZ ) - 1UL; portNVIC_SYSTICK_CTRL_REG = ( portNVIC_SYSTICK_CLK_BIT | portNVIC_SYSTICK_INT_BIT | portNVIC_SYSTICK_ENABLE_BIT ); }
void vTaskDelay( const TickType_t xTicksToDelay ) { BaseType_t xAlreadyYielded = pdFALSE; /* A delay time of zero just forces a reschedule. */ /*判断延时时间是否大于0*/ if( xTicksToDelay > ( TickType_t ) 0U ) { /*断言*/ configASSERT( uxSchedulerSuspended == 0 ); /*挂起调度器*/ 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. */ prvAddCurrentTaskToDelayedList( xTicksToDelay, pdFALSE ); } xAlreadyYielded = xTaskResumeAll(); } else { mtCOVERAGE_TEST_MARKER(); } /* 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(); } }
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 ) { /* 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 > xConstTickCount ) ) { xShouldDelay = pdTRUE; } else { mtCOVERAGE_TEST_MARKER(); } } 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 > 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() needs the block time, not the time to wake, so subtract the current tick count. */ 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(); } }
void vTaskSuspendAll( void ) { /* A critical section is not required as the variable is of type BaseType_t. Please read Richard Barry's reply in the following link to a post in the FreeRTOS support forum before reporting this as a bug! - http://goo.gl/wu4acr */ ++uxSchedulerSuspended; }
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. */ /*进入临界区*/ taskENTER_CRITICAL(); { /*uxSchedulerSuspended--*/ --uxSchedulerSuspended; if( uxSchedulerSuspended == ( UBaseType_t ) pdFALSE ) { if( uxCurrentNumberOfTasks > ( UBaseType_t ) 0U ) { /* Move any readied tasks from the pending list into the appropriate ready list. */ 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. */ 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(); } else { mtCOVERAGE_TEST_MARKER(); } } } else { mtCOVERAGE_TEST_MARKER(); } } taskEXIT_CRITICAL(); return xAlreadyYielded; }
/*消息队列可做为信号量使用,故此处作了类型转换*/ #define xQueueCreate( uxQueueLength, uxItemSize ) xQueueGenericCreate( ( uxQueueLength ), ( uxItemSize ), ( queueQUEUE_TYPE_BASE ) ) QueueHandle_t xQueueGenericCreate( const UBaseType_t uxQueueLength, const UBaseType_t uxItemSize, const uint8_t ucQueueType ) { Queue_t *pxNewQueue; size_t xQueueSizeInBytes; uint8_t *pucQueueStorage; configASSERT( uxQueueLength > ( UBaseType_t ) 0 ); if( uxItemSize == ( UBaseType_t ) 0 ) { /* There is not going to be a queue storage area. */ xQueueSizeInBytes = ( size_t ) 0; } else { /* Allocate enough space to hold the maximum number of items that can be in the queue at any time. */ xQueueSizeInBytes = ( size_t ) ( uxQueueLength * uxItemSize ); /*lint !e961 MISRA exception as the casts are only redundant for some ports. */ } /*分配空间*/ pxNewQueue = ( Queue_t * ) pvPortMalloc( sizeof( Queue_t ) + xQueueSizeInBytes ); if( pxNewQueue != NULL ) { /* Jump past the queue structure to find the location of the queue storage area. */ pucQueueStorage = ( ( uint8_t * ) pxNewQueue ) + sizeof( Queue_t ); #if( configSUPPORT_STATIC_ALLOCATION == 1 ) { /* Queues can be created either statically or dynamically, so note this task was created dynamically in case it is later deleted. */ pxNewQueue->ucStaticallyAllocated = pdFALSE; } #endif /* configSUPPORT_STATIC_ALLOCATION */ /*队列初始化*/ prvInitialiseNewQueue( uxQueueLength, uxItemSize, pucQueueStorage, ucQueueType, pxNewQueue ); } else { traceQUEUE_CREATE_FAILED( ucQueueType ); } return pxNewQueue; } /*队列初始化*/ static void prvInitialiseNewQueue( const UBaseType_t uxQueueLength, const UBaseType_t uxItemSize, uint8_t *pucQueueStorage, const uint8_t ucQueueType, Queue_t *pxNewQueue ) { /* Remove compiler warnings about unused parameters should configUSE_TRACE_FACILITY not be set to 1. */ ( void ) ucQueueType; if( uxItemSize == ( UBaseType_t ) 0 ) { /* No RAM was allocated for the queue storage area, but PC head cannot be set to NULL because NULL is used as a key to say the queue is used as a mutex. Therefore just set pcHead to point to the queue as a benign value that is known to be within the memory map. */ pxNewQueue->pcHead = ( int8_t * ) pxNewQueue; } else { /* Set the head to the start of the queue storage area. */ pxNewQueue->pcHead = ( int8_t * ) pucQueueStorage; } /* Initialise the queue members as described where the queue type is defined. */ pxNewQueue->uxLength = uxQueueLength; pxNewQueue->uxItemSize = uxItemSize; /*重置队列*/ ( void ) xQueueGenericReset( pxNewQueue, pdTRUE ); #if ( configUSE_TRACE_FACILITY == 1 ) { pxNewQueue->ucQueueType = ucQueueType; } #endif /* configUSE_TRACE_FACILITY */ #if( configUSE_QUEUE_SETS == 1 ) { pxNewQueue->pxQueueSetContainer = NULL; } #endif /* configUSE_QUEUE_SETS */ traceQUEUE_CREATE( pxNewQueue ); } /*重置队列*/ BaseType_t xQueueGenericReset( QueueHandle_t xQueue, BaseType_t xNewQueue ) { Queue_t * const pxQueue = ( Queue_t * ) xQueue; configASSERT( pxQueue ); /*进入临界区*/ taskENTER_CRITICAL(); { /*队尾指针 = 队头指针 + 队列程序控制块大小*/ pxQueue->pcTail = pxQueue->pcHead + ( pxQueue->uxLength * pxQueue->uxItemSize ); /*置零*/ pxQueue->uxMessagesWaiting = ( UBaseType_t ) 0U; /*将要操做的指针对象指向队头*/ pxQueue->pcWriteTo = pxQueue->pcHead; /*将要读取的地址指向队尾*/ pxQueue->u.pcReadFrom = pxQueue->pcHead + ( ( pxQueue->uxLength - ( UBaseType_t ) 1U ) * pxQueue->uxItemSize ); pxQueue->cRxLock = queueUNLOCKED; pxQueue->cTxLock = queueUNLOCKED; if( xNewQueue == pdFALSE ) { /* If there are tasks blocked waiting to read from the queue, then the tasks will remain blocked as after this function exits the queue will still be empty. If there are tasks blocked waiting to write to the queue, then one should be unblocked as after this function exits it will be possible to write to it. */ if( listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToSend ) ) == pdFALSE ) { if( xTaskRemoveFromEventList( &( pxQueue->xTasksWaitingToSend ) ) != pdFALSE ) { queueYIELD_IF_USING_PREEMPTION(); } else { mtCOVERAGE_TEST_MARKER(); } } else { mtCOVERAGE_TEST_MARKER(); } } else { /* Ensure the event queues start in the correct state. */ /*建立发送与接收节点*/ vListInitialise( &( pxQueue->xTasksWaitingToSend ) ); vListInitialise( &( pxQueue->xTasksWaitingToReceive ) ); } } /*退出临界区*/ taskEXIT_CRITICAL(); /* A value is returned for calling semantic consistency with previous versions. */ return pdPASS; }
void vQueueDelete( QueueHandle_t xQueue ) { Queue_t * const pxQueue = ( Queue_t * ) xQueue; configASSERT( pxQueue ); traceQUEUE_DELETE( pxQueue ); #if ( configQUEUE_REGISTRY_SIZE > 0 ) { vQueueUnregisterQueue( pxQueue ); } #endif #if( ( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) && ( configSUPPORT_STATIC_ALLOCATION == 0 ) ) { /* The queue can only have been allocated dynamically - free it again. */ /*直接释放内存空间*/ vPortFree( pxQueue ); } #elif( ( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) && ( configSUPPORT_STATIC_ALLOCATION == 1 ) ) { /* The queue could have been allocated statically or dynamically, so check before attempting to free the memory. */ if( pxQueue->ucStaticallyAllocated == ( uint8_t ) pdFALSE ) { /*直接释放内存空间*/ vPortFree( pxQueue ); } else { mtCOVERAGE_TEST_MARKER(); } } #else { /* The queue must have been statically allocated, so is not going to be deleted. Avoid compiler warnings about the unused parameter. */ ( void ) pxQueue; } #endif /* configSUPPORT_DYNAMIC_ALLOCATION */ }