4.2.14 退出阻塞--xTaskAbortDelay
接口:
BaseType_t xTaskAbortDelay( TaskHandle_t xTask )
形参1:xTask ,想要退出阻塞态的任务;
返回:pdPASS:退出成功;pdFAIL:退出失败。
- 1 BaseType_t xTaskAbortDelay( TaskHandle_t xTask )
- 2 {
- 3 TCB_t * pxTCB = xTask;
- 4 BaseType_t xReturn;
- 5
- 6 configASSERT( pxTCB );
- 7
- 8 vTaskSuspendAll();
- 9 {
- 10 /* A task can only be prematurely removed from the Blocked state if
- 11 * it is actually in the Blocked state. */
- 12 /* 任务只有真的在阻塞态才能提前移出阻塞态 */
- 13 if( eTaskGetState( xTask ) == eBlocked )
- 14 {
- 15 xReturn = pdPASS;
- 16
- 17 /* Remove the reference to the task from the blocked list. An
- 18 * interrupt won't touch the xStateListItem because the
- 19 * scheduler is suspended. */
- 20 ( void ) uxListRemove( &( pxTCB->xStateListItem ) );
- 21
- 22 /* Is the task waiting on an event also? If so remove it from
- 23 * the event list too. Interrupts can touch the event list item,
- 24 * even though the scheduler is suspended, so a critical section
- 25 * is used. */
- 26 /* 如果任务在等待事件, 则移出事件列表, 因为调度器暂停时, 中断仍
- 27 * 能访问事件列表, 所以需要进入临界区 */
- 28 taskENTER_CRITICAL();
- 29 {
- 30 if( listLIST_ITEM_CONTAINER( &( pxTCB->xEventListItem ) ) != NULL )
- 31 {
- 32 ( void ) uxListRemove( &( pxTCB->xEventListItem ) );
- 33
- 34 /* This lets the task know it was forcibly removed from the
- 35 * blocked state so it should not re-evaluate its block time and
- 36 * then block again. */
- 37 /* 让任务知道是被强制移出阻塞态的, 防止被重新计算阻塞时间再次进入
- 38 * 阻塞态 */
- 39 pxTCB->ucDelayAborted = ( uint8_t ) pdTRUE;
- 40 }
- 41 else
- 42 {
- 43 mtCOVERAGE_TEST_MARKER();
- 44 }
- 45 }
- 46 taskEXIT_CRITICAL();
- 47
- 48 /* Place the unblocked task into the appropriate ready list. */
- 49 prvAddTaskToReadyList( pxTCB );
- 50
- 51 /* A task being unblocked cannot cause an immediate context
- 52 * switch if preemption is turned off. */
- 53 #if ( configUSE_PREEMPTION == 1 )
- 54 {
- 55 #if ( configNUMBER_OF_CORES == 1 )
- 56 {
- 57 /* Preemption is on, but a context switch should only be
- 58 * performed if the unblocked task has a priority that is
- 59 * higher than the currently executing task. */
- 60 /* 比当前任务优先级高, 等调度器运行后, 需要进行yield */
- 61 if( pxTCB->uxPriority > pxCurrentTCB->uxPriority )
- 62 {
- 63 /* Pend the yield to be performed when the scheduler
- 64 * is unsuspended. */
- 65 xYieldPendings[ 0 ] = pdTRUE;
- 66 }
- 67 else
- 68 {
- 69 mtCOVERAGE_TEST_MARKER();
- 70 }
- 71 }
- 72 #endif /* #if ( configNUMBER_OF_CORES == 1 ) */
- 73 }
- 74 #endif /* #if ( configUSE_PREEMPTION == 1 ) */
- 75 }
- 76 else
- 77 {
- 78 xReturn = pdFAIL;
- 79 }
- 80 }
- 81 ( void ) xTaskResumeAll();
- 82
- 83 return xReturn;
- 84 }
复制代码 xTaskAbortDelay 这个接口主要就是强制将在阻塞态的任务变成就绪态。
4.2.15 系统滴答时钟处理--xTaskIncrementTick
接口:
BaseType_t xTaskIncrementTick( void )
返回:pdPASS:需要切换上下文;pdFAIL:不需要切换上下文。
接口代码如下:
- 1 BaseType_t xTaskIncrementTick( void )
- 2 {
- 3 TCB_t * pxTCB;
- 4 TickType_t xItemValue;
- 5 BaseType_t xSwitchRequired = pdFALSE;
- 6
- 7 /* Tick increment should occur on every kernel timer event. Core 0 has the
- 8 * responsibility to increment the tick, or increment the pended ticks if the
- 9 * scheduler is suspended. If pended ticks is greater than zero, the core that
- 10 * calls xTaskResumeAll has the responsibility to increment the tick. */
- 11 if( uxSchedulerSuspended == ( UBaseType_t ) 0U )
- 12 {
- 13 /* Minor optimisation. The tick count cannot change in this
- 14 * block. */
- 15 const TickType_t xConstTickCount = xTickCount + ( TickType_t ) 1;
- 16
- 17 /* Increment the RTOS tick, switching the delayed and overflowed
- 18 * delayed lists if it wraps to 0. */
- 19 xTickCount = xConstTickCount;
- 20
- 21 /* tick溢出了, 交换下delay列表 */
- 22 if( xConstTickCount == ( TickType_t ) 0U )
- 23 {
- 24 taskSWITCH_DELAYED_LISTS();
- 25 }
- 26 else
- 27 {
- 28 mtCOVERAGE_TEST_MARKER();
- 29 }
- 30
- 31 /* See if this tick has made a timeout expire. Tasks are stored in
- 32 * the queue in the order of their wake time - meaning once one task
- 33 * has been found whose block time has not expired there is no need to
- 34 * look any further down the list. */
- 35 /* 因为delay列表的项是按唤醒时间从小到大排序的, 所以遍历过程中一旦发现
- 36 * 任务唤醒时间没到, 就可以停止了 */
- 37 if( xConstTickCount >= xNextTaskUnblockTime )
- 38 {
- 39 for( ; ; )
- 40 {
- 41 if( listLIST_IS_EMPTY( pxDelayedTaskList ) != pdFALSE )
- 42 {
- 43 /* The delayed list is empty. Set xNextTaskUnblockTime
- 44 * to the maximum possible value so it is extremely
- 45 * unlikely that the
- 46 * if( xTickCount >= xNextTaskUnblockTime ) test will pass
- 47 * next time through. */
- 48 xNextTaskUnblockTime = portMAX_DELAY;
- 49 break;
- 50 }
- 51 else
- 52 {
- 53 /* The delayed list is not empty, get the value of the
- 54 * item at the head of the delayed list. This is the time
- 55 * at which the task at the head of the delayed list must
- 56 * be removed from the Blocked state. */
- 57 /* MISRA Ref 11.5.3 [Void pointer assignment] */
- 58 /* More details at: https://github.com/FreeRTOS/FreeRTOS-Kernel/blob/main/MISRA.md#rule-115 */
- 59 /* coverity[misra_c_2012_rule_11_5_violation] */
- 60 pxTCB = listGET_OWNER_OF_HEAD_ENTRY( pxDelayedTaskList );
- 61 xItemValue = listGET_LIST_ITEM_VALUE( &( pxTCB->xStateListItem ) );
- 62
- 63 if( xConstTickCount < xItemValue )
- 64 {
- 65 /* It is not time to unblock this item yet, but the
- 66 * item value is the time at which the task at the head
- 67 * of the blocked list must be removed from the Blocked
- 68 * state - so record the item value in
- 69 * xNextTaskUnblockTime. */
- 70 /* 这个任务未到唤醒时间, 但因为前面的都移出了, 所以这一定
- 71 * 是下次最近唤醒的时间, 记录下来 */
- 72 xNextTaskUnblockTime = xItemValue;
- 73 break;
- 74 }
- 75 else
- 76 {
- 77 mtCOVERAGE_TEST_MARKER();
- 78 }
- 79
- 80 /* It is time to remove the item from the Blocked state. */
- 81 listREMOVE_ITEM( &( pxTCB->xStateListItem ) );
- 82
- 83 /* Is the task waiting on an event also? If so remove
- 84 * it from the event list. */
- 85 /* 等待事件的话, 移出事件列表 */
- 86 if( listLIST_ITEM_CONTAINER( &( pxTCB->xEventListItem ) ) != NULL )
- 87 {
- 88 listREMOVE_ITEM( &( pxTCB->xEventListItem ) );
- 89 }
- 90 else
- 91 {
- 92 mtCOVERAGE_TEST_MARKER();
- 93 }
- 94
- 95 /* Place the unblocked task into the appropriate ready
- 96 * list. */
- 97 prvAddTaskToReadyList( pxTCB );
- 98
- 99 /* A task being unblocked cannot cause an immediate
- 100 * context switch if preemption is turned off. */
- 101 #if ( configUSE_PREEMPTION == 1 )
- 102 {
- 103 #if ( configNUMBER_OF_CORES == 1 )
- 104 {
- 105 /* Preemption is on, but a context switch should
- 106 * only be performed if the unblocked task's
- 107 * priority is higher than the currently executing
- 108 * task.
- 109 * The case of equal priority tasks sharing
- 110 * processing time (which happens when both
- 111 * preemption and time slicing are on) is
- 112 * handled below.*/
- 113 /* 移出的任务优先级比当前运行的任务高, 需要上下文切换 */
- 114 if( pxTCB->uxPriority > pxCurrentTCB->uxPriority )
- 115 {
- 116 xSwitchRequired = pdTRUE;
- 117 }
- 118 else
- 119 {
- 120 mtCOVERAGE_TEST_MARKER();
- 121 }
- 122 }
- 123 #endif /* #if( configNUMBER_OF_CORES == 1 ) */
- 124 }
- 125 #endif /* #if ( configUSE_PREEMPTION == 1 ) */
- 126 }
- 127 }
- 128 }
- 129
- 130 /* Tasks of equal priority to the currently running task will share
- 131 * processing time (time slice) if preemption is on, and the application
- 132 * writer has not explicitly turned time slicing off. */
- 133 /* 相同优先级的任务用时间片运行, 每个时间片长是一个tick. 这里不用管更高
- 134 * 优先级的任务是否唤醒, 一是上面已经判断过了, 二是只是需要知道是否要上
- 135 * 下文切换, 这样判断就足够了, 在上下文切换的时候自然会选择合适的任务运行 */
- 136 #if ( ( configUSE_PREEMPTION == 1 ) && ( configUSE_TIME_SLICING == 1 ) )
- 137 {
- 138 #if ( configNUMBER_OF_CORES == 1 )
- 139 {
- 140 if( listCURRENT_LIST_LENGTH( &( pxReadyTasksLists[ pxCurrentTCB->uxPriority ] ) ) > 1U )
- 141 {
- 142 xSwitchRequired = pdTRUE;
- 143 }
- 144 else
- 145 {
- 146 mtCOVERAGE_TEST_MARKER();
- 147 }
- 148 }
- 149 #endif /* #if ( configNUMBER_OF_CORES == 1 ) */
- 150 }
- 151 #endif /* #if ( ( configUSE_PREEMPTION == 1 ) && ( configUSE_TIME_SLICING == 1 ) ) */
- 152
- 153 #if ( configUSE_TICK_HOOK == 1 )
- 154 {
- 155 /* Guard against the tick hook being called when the pended tick
- 156 * count is being unwound (when the scheduler is being unlocked). */
- 157 if( xPendedTicks == ( TickType_t ) 0 )
- 158 {
- 159 vApplicationTickHook();
- 160 }
- 161 else
- 162 {
- 163 mtCOVERAGE_TEST_MARKER();
- 164 }
- 165 }
- 166 #endif /* configUSE_TICK_HOOK */
- 167
- 168 #if ( configUSE_PREEMPTION == 1 )
- 169 {
- 170 #if ( configNUMBER_OF_CORES == 1 )
- 171 {
- 172 /* For single core the core ID is always 0. */
- 173 if( xYieldPendings[ 0 ] != pdFALSE )
- 174 {
- 175 xSwitchRequired = pdTRUE;
- 176 }
- 177 else
- 178 {
- 179 mtCOVERAGE_TEST_MARKER();
- 180 }
- 181 }
- 182 #endif /* #if ( configNUMBER_OF_CORES == 1 ) */
- 183 }
- 184 #endif /* #if ( configUSE_PREEMPTION == 1 ) */
- 185 }
- 186 else
- 187 {
- 188 /* 调度器处于暂停中, 在xTaskResumeAll接口中检查xPendedTicks的值,
- 189 * 并调用本接口处理tick值. */
- 190 xPendedTicks += 1U;
- 191
- 192 /* The tick hook gets called at regular intervals, even if the
- 193 * scheduler is locked. */
- 194 #if ( configUSE_TICK_HOOK == 1 )
- 195 {
- 196 vApplicationTickHook();
- 197 }
- 198 #endif
- 199 }
- 200
- 201 return xSwitchRequired;
- 202 }
复制代码 xTaskIncrementTick 接口比较复杂,流程图就不贴了,太长。这个接口简单来讲就是如果调度器未停止,就检查每个阻塞的任务是否到了等待时间,包括本身延迟的时间和等待事件的超时时间,并加入到就绪列表中。
4.2.16 切换上下文--vTaskSwitchContext
切换上下文,主要作用是挑选出需要切换过去的任务。
接口:
void vTaskSwitchContext( void )
接口代码如下:
- 1 void vTaskSwitchContext( void )
- 2 {
- 3 if( uxSchedulerSuspended != ( UBaseType_t ) 0U )
- 4 {
- 5 /* The scheduler is currently suspended - do not allow a context
- 6 * switch. */
- 7 /* 调度器暂停时, 不允许上下文切换 */
- 8 xYieldPendings[ 0 ] = pdTRUE;
- 9 }
- 10 else
- 11 {
- 12 xYieldPendings[ 0 ] = pdFALSE;
- 13
- 14 /* Check for stack overflow, if configured. */
- 15 /* 就是检查当前栈的位置有没有超过栈顶位置 */
- 16 taskCHECK_FOR_STACK_OVERFLOW();
- 17
- 18 /* Before the currently running task is switched out, save its errno. */
- 19 #if ( configUSE_POSIX_ERRNO == 1 )
- 20 {
- 21 pxCurrentTCB->iTaskErrno = FreeRTOS_errno;
- 22 }
- 23 #endif
- 24
- 25 /* Select a new task to run using either the generic C or port
- 26 * optimised asm code. */
- 27 /* MISRA Ref 11.5.3 [Void pointer assignment] */
- 28 /* More details at: https://github.com/FreeRTOS/FreeRTOS-Kernel/blob/main/MISRA.md#rule-115 */
- 29 /* coverity[misra_c_2012_rule_11_5_violation] */
- 30 /* 选择就绪列表中优先级最高的任务 */
- 31 taskSELECT_HIGHEST_PRIORITY_TASK();
- 32
- 33 /* Macro to inject port specific behaviour immediately after
- 34 * switching tasks, such as setting an end of stack watchpoint
- 35 * or reconfiguring the MPU. */
- 36 portTASK_SWITCH_HOOK( pxCurrentTCB );
- 37
- 38 /* After the new task is switched in, update the global errno. */
- 39 #if ( configUSE_POSIX_ERRNO == 1 )
- 40 {
- 41 FreeRTOS_errno = pxCurrentTCB->iTaskErrno;
- 42 }
- 43 #endif
- 44 }
- 45 }
复制代码 vTaskSwitchContext 最核心的就是“taskSELECT_HIGHEST_PRIORITY_TASK();”调用。
4.2.17 加入到事件列表--vTaskPlaceOnEventList
把当前任务放到事件列表中,主要用于队列的实现。
接口:
void vTaskPlaceOnEventList( List_t * const pxEventList, const TickType_t xTicksToWait )
形参1:pxEventList,事件列表;
形参2:xTicksToWait ,最长等待时间。
接口代码如下:
- 1 void vTaskPlaceOnEventList( List_t * const pxEventList,
- 2 const TickType_t xTicksToWait )
- 3 {
- 4 configASSERT( pxEventList );
- 5
- 6 /* THIS FUNCTION MUST BE CALLED WITH THE
- 7 * SCHEDULER SUSPENDED AND THE QUEUE BEING ACCESSED LOCKED. */
- 8
- 9 /* Place the event list item of the TCB in the appropriate event list.
- 10 * This is placed in the list in priority order so the highest priority task
- 11 * is the first to be woken by the event.
- 12 *
- 13 * Note: Lists are sorted in ascending order by ListItem_t.xItemValue.
- 14 * Normally, the xItemValue of a TCB's ListItem_t members is:
- 15 * xItemValue = ( configMAX_PRIORITIES - uxPriority )
- 16 * Therefore, the event list is sorted in descending priority order.
- 17 *
- 18 * The queue that contains the event list is locked, preventing
- 19 * simultaneous access from interrupts. */
- 20 /* 将当前任务加入到事件列表, 列表是按升序存放的, 而一般情况下, 任务的
- 21 * xEventListItem的值是xItemValue=(configMAX_PRIORITIES-uxPriority),
- 22 * 所以事件列表是按优先级降序排列的 */
- 23 vListInsert( pxEventList, &( pxCurrentTCB->xEventListItem ) );
- 24
- 25 /* 还需要放到延迟列表中, 用于最大延迟时间的唤醒 */
- 26 prvAddCurrentTaskToDelayedList( xTicksToWait, pdTRUE );
- 27 }
复制代码 vTaskPlaceOnEventList 4.2.18 加入到无序事件列表--vTaskPlaceOnUnorderedEventList
把当前任务放到无序的事件列表中,主要用于事件组。
接口:
void vTaskPlaceOnUnorderedEventList( List_t * pxEventList,const TickType_t xItemValue, const TickType_t xTicksToWait )
形参1:pxEventList,事件列表;
形参2:xItemValue,设置的值
形参3:xTicksToWait ,最长等待时间。
接口代码如下:
- 1 void vTaskPlaceOnUnorderedEventList( List_t * pxEventList,
- 2 const TickType_t xItemValue,
- 3 const TickType_t xTicksToWait )
- 4 {
- 5 configASSERT( pxEventList );
- 6
- 7 /* THIS FUNCTION MUST BE CALLED WITH THE SCHEDULER SUSPENDED. It is used by
- 8 * the event groups implementation. */
- 9 configASSERT( uxSchedulerSuspended != ( UBaseType_t ) 0U );
- 10
- 11 /* Store the item value in the event list item. It is safe to access the
- 12 * event list item here as interrupts won't access the event list item of a
- 13 * task that is not in the Blocked state. */
- 14 /* 中断只会访问处于Blocked态的事件列表项, 这里当前任务明显还未进入Blocked态 */
- 15 listSET_LIST_ITEM_VALUE( &( pxCurrentTCB->xEventListItem ), xItemValue | taskEVENT_LIST_ITEM_VALUE_IN_USE );
- 16
- 17 /* Place the event list item of the TCB at the end of the appropriate event
- 18 * list. It is safe to access the event list here because it is part of an
- 19 * event group implementation - and interrupts don't access event groups
- 20 * directly (instead they access them indirectly by pending function calls to
- 21 * the task level). */
- 22 /* 主要是用于事件组的实现, 中断不会直接访问. 无序存放, 所以直接放在最后 */
- 23 listINSERT_END( pxEventList, &( pxCurrentTCB->xEventListItem ) );
- 24
- 25 prvAddCurrentTaskToDelayedList( xTicksToWait, pdTRUE );
- 26 }
复制代码 vTaskPlaceOnUnorderedEventList 4.2.19 移出事件列表--xTaskRemoveFromEventList
将当前任务从事件列表中移出,主要用于队列的实现。
接口:
BaseType_t xTaskRemoveFromEventList( const List_t * const pxEventList )
形参1:pxEventList,事件列表;
返回值:pdTRUE:需要进行上下文切换;pdFALSE:不需要。
接口代码如下:
- 1 BaseType_t xTaskRemoveFromEventList( const List_t * const pxEventList )
- 2 {
- 3 TCB_t * pxUnblockedTCB;
- 4 BaseType_t xReturn;
- 5
- 6 /* THIS FUNCTION MUST BE CALLED FROM A CRITICAL SECTION. It can also be
- 7 * called from a critical section within an ISR. */
- 8
- 9 /* The event list is sorted in priority order, so the first in the list can
- 10 * be removed as it is known to be the highest priority. Remove the TCB from
- 11 * the delayed list, and add it to the ready list.
- 12 *
- 13 * If an event is for a queue that is locked then this function will never
- 14 * get called - the lock count on the queue will get modified instead. This
- 15 * means exclusive access to the event list is guaranteed here.
- 16 *
- 17 * This function assumes that a check has already been made to ensure that
- 18 * pxEventList is not empty. */
- 19 /* MISRA Ref 11.5.3 [Void pointer assignment] */
- 20 /* More details at: https://github.com/FreeRTOS/FreeRTOS-Kernel/blob/main/MISRA.md#rule-115 */
- 21 /* coverity[misra_c_2012_rule_11_5_violation] */
- 22 /* 按优先级降序存放的, 所以头部是优先级最高的任务 */
- 23 pxUnblockedTCB = listGET_OWNER_OF_HEAD_ENTRY( pxEventList );
- 24 configASSERT( pxUnblockedTCB );
- 25 listREMOVE_ITEM( &( pxUnblockedTCB->xEventListItem ) );
- 26
- 27 if( uxSchedulerSuspended == ( UBaseType_t ) 0U )
- 28 {
- 29 listREMOVE_ITEM( &( pxUnblockedTCB->xStateListItem ) );
- 30 prvAddTaskToReadyList( pxUnblockedTCB );
- 31
- 32 #if ( configUSE_TICKLESS_IDLE != 0 )
- 33 {
- 34 /* If a task is blocked on a kernel object then xNextTaskUnblockTime
- 35 * might be set to the blocked task's time out time. If the task is
- 36 * unblocked for a reason other than a timeout xNextTaskUnblockTime is
- 37 * normally left unchanged, because it is automatically reset to a new
- 38 * value when the tick count equals xNextTaskUnblockTime. However if
- 39 * tickless idling is used it might be more important to enter sleep mode
- 40 * at the earliest possible time - so reset xNextTaskUnblockTime here to
- 41 * ensure it is updated at the earliest possible time. */
- 42 /* 重置最近唤醒时间 */
- 43 prvResetNextTaskUnblockTime();
- 44 }
- 45 #endif
- 46 }
- 47 else
- 48 {
- 49 /* The delayed and ready lists cannot be accessed, so hold this task
- 50 * pending until the scheduler is resumed. */
- 51 /* 调度器暂停, 不能访问延迟和就绪列表, 需要放到pend列表里 */
- 52 listINSERT_END( &( xPendingReadyList ), &( pxUnblockedTCB->xEventListItem ) );
- 53 }
- 54
- 55 #if ( configNUMBER_OF_CORES == 1 )
- 56 {
- 57 if( pxUnblockedTCB->uxPriority > pxCurrentTCB->uxPriority )
- 58 {
- 59 /* Return true if the task removed from the event list has a higher
- 60 * priority than the calling task. This allows the calling task to know if
- 61 * it should force a context switch now. */
- 62 /* 取出任务的优先级更高, 需要进行上下文切换 */
- 63 xReturn = pdTRUE;
- 64
- 65 /* Mark that a yield is pending in case the user is not using the
- 66 * "xHigherPriorityTaskWoken" parameter to an ISR safe FreeRTOS function. */
- 67 xYieldPendings[ 0 ] = pdTRUE;
- 68 }
- 69 else
- 70 {
- 71 xReturn = pdFALSE;
- 72 }
- 73 }
- 74 #endif /* #if ( configNUMBER_OF_CORES == 1 ) */
- 75
- 76 return xReturn;
- 77 }
复制代码 xTaskRemoveFromEventList
16~19都比较简单,这里就简单过一下,下一篇学习空闲任务究竟做了什么事情以及它调用的几个小接口。
下篇再见。
来源:程序园用户自行投稿发布,如果侵权,请联系站长删除
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作! |