概览 FreeRTOS的信号量包括二进制信号量、计数信号量、互斥信号量(以后简称互斥量)和递归互斥信号量(以后简称递归互斥量) FreeRTOS的信号量是使用队列机制实现的,数据结构也完全是队列的那一套。 除此之外,还有一种简单的任务间的同步方式: 任务通知 它的数据结构嵌在任务TCB中的,并且数据结构十分简单,涉及到任务TCB的两个字段,我们将它单独列出来:
1 2 1. volatile uint32_t ulNotifiedValue; 2. volatile uint8_t ucNotifyState;
本文只讨论信号量的部分
api 创建队列与其他几个不同,暂且不表
二进制信号量 创建 vSemaphoreCreateBinary xSemaphoreCreateBinary 类型为 queueQUEUE_TYPE_BINARY_SEMAPHORE
1 2 3 4 5 6 7 8 9 10 #define vSemaphoreCreateBinary( xSemaphore ) \ { \ ( xSemaphore ) = xQueueGenericCreate( ( UBaseType_t ) 1, semSEMAPHORE_QUEUE_ITEM_LENGTH, queueQUEUE_TYPE_BINARY_SEMAPHORE ); \ if ( ( xSemaphore ) != NULL ) \ { \ ( void ) xSemaphoreGive( ( xSemaphore ) ); \ } \ } #define xSemaphoreCreateBinary() xQueueGenericCreate( ( UBaseType_t ) 1, semSEMAPHORE_QUEUE_ITEM_LENGTH, queueQUEUE_TYPE_BINARY_SEMAPHORE )
vSemaphoreCreateBinary 使用方式是先创建,再take, 再give, 别的任务再take, 再give。 与xSemaphoreCreateBinary
的使用方式不同,它的处理方式是,创建后,需要先give,才能take到。 其他的计数信号量、互斥量的api与废弃的版本的使用方式都和该api的差不多。
通过这个宏定义我们知道创建二进制信号量实际上是创建了一个队列,队列项有1个,但是队列项的大小为0(宏semSEMAPHORE_QUEUE_ITEM_LENGTH
定义为0)
图1-1:初始化后的二进制信号量对象内存
二进制信号量的释放和获取都是通过操作队列结构体成员uxMessageWaiting来实现的(图1-1红色部分,uxMessageWaiting表示队列中当前队列项的个数)。 经过初始化后,变量uxMessageWaiting为0,这说明队列为空,也就是信号量处于无效状态。 在使用API函数xSemaphoreTake()获取信号之前,需要先释放一个信号量。 释放信号量 give 会将 uxMessageWaiting + 1,这样take才能获取到信号。
计数信号量 创建 创建计数信号量间接使用通用队列创建函数xQueueGenericCreate()。创建计数信号量API接口同样是个宏定义:
1 #define xSemaphoreCreateCounting( uxMaxCount, uxInitialCount ) xQueueCreateCountingSemaphore( ( uxMaxCount ), ( uxInitialCount ) )
创建计数信号量API接口有两个参数,含义如下:
uxMaxCount:最大计数值,当信号到达这个值后,就不再增长了。
uxInitialCount:创建信号量时的初始值。
queueSEMAPHORE_QUEUE_ITEM_LENGTH = 0, 类型为queueQUEUE_TYPE_COUNTING_SEMAPHORE
1 2 3 4 5 6 7 8 9 #if ( ( configUSE_COUNTING_SEMAPHORES == 1 ) && ( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) ) QueueHandle_t xQueueCreateCountingSemaphore ( const UBaseType_t uxMaxCount, const UBaseType_t uxInitialCount ) { xHandle = xQueueGenericCreate( uxMaxCount, queueSEMAPHORE_QUEUE_ITEM_LENGTH, queueQUEUE_TYPE_COUNTING_SEMAPHORE ); ( ( Queue_t * ) xHandle )->uxMessagesWaiting = uxInitialCount; return xHandle; } #endif
-171340877101513.png)
图1-2:初始化后的计数信号量对象内存
互斥量 创建 创建互斥量间接使用通用队列创建函数xQueueGenericCreate()。创建互斥量API接口同样是个宏,定义如下:
1 #define xSemaphoreCreateMutex() xQueueCreateMutex( queueQUEUE_TYPE_MUTEX )
类型为 queueQUEUE_TYPE_MUTEX
, 同样使用xQueueGenericCreate 间接创建。 队列项 item = 0,可以看到信号量的队列项大小全是0
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 QueueHandle_t xQueueCreateMutex ( const uint8_t ucQueueType ) { uxMutexLength = ( UBaseType_t ) 1 ; uxMutexSize = ( UBaseType_t ) 0 ; pxNewQueue = ( Queue_t * ) xQueueGenericCreate( uxMutexLength, uxMutexSize, ucQueueType ); prvInitialiseMutex( pxNewQueue ); return pxNewQueue; } static void prvInitialiseMutex ( Queue_t *pxNewQueue ) { pxNewQueue->pxMutexHolder = NULL ; pxNewQueue->uxQueueType = queueQUEUE_IS_MUTEX; pxNewQueue->u.uxRecursiveCallCount = 0 ; ( void ) xQueueGenericSend( pxNewQueue, NULL , ( TickType_t ) 0U , queueSEND_TO_BACK ); } }
最后调用函数xQueueGenericSend()释放一个互斥量,相当于互斥量创建后是有效的,可以直接使用获取信号量API函数来获取这个互斥量。 如果某资源同时只准一个任务访问,可以用互斥量保护这个资源。这个资源一定是存在的 所以创建互斥量时会先释放一个互斥量,表示这个资源可以使用。
使用方式: 先创建, 然后take, 再give。 sample:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 QueueHandle_t mutexHandle; mutexHandle = xSemaphoreCreateMutex(); void vTaskFunction2 ( void *pvParameters ) { char *pcTaskName; xQueueSemaphoreTake(mutexHandle, 2000 ); info("vTaskFunction2 have take mutex\n" ); pcTaskName = (char *) pvParameters; vTaskDelay(1000 ); info("vTaskFunction2 release mutex\n" ); xSemaphoreGive(mutexHandle); vTaskDelay(1000 ); while (1 ); } void vTaskFunction3 ( void *pvParameters ) { info("vTaskFunction3 taking the mutex\n" ); xQueueSemaphoreTake(mutexHandle, 2000 ); info("vTaskFunction3 have take the mutex\n" ); while (1 ); }
图1-3:初始化后的互斥量对象内存
互斥量和二进制信号量区别:
二进制信号量可以在随便一个任务中获取或释放,然后也可以在任意一个任务中释放或获取。
互斥量具有优先级继承机制,二进制信号量没有
互斥量不可以用于中断服务程序,二进制信号量可以。
递归互斥量 创建递归互斥量间接使用通用队列创建函数xQueueGenericCreate()。创建递归互斥量API接口同样是个宏,定义如下:
1 #define xSemaphoreCreateRecursiveMutex() xQueueCreateMutex( queueQUEUE_TYPE_RECURSIVE_MUTEX )
类型为 queueQUEUE_TYPE_RECURSIVE_MUTEX
创建互斥量和创建递归互斥量是调用的同一个函数xQueueCreateMutex
(),至于参数queueQUEUE_TYPE_RECURSIVE_MUTEX
,我们在FreeRTOS一文中已经知道,它只是用于可视化调试 因此创建互斥量和创建递归互斥量可以看作是一样的,初始化后的递归互斥量对象内存也和互斥量一样,如图1-3所示。
释放信号量 无论二进制信号量、计数信号量还是互斥量,它们都使用相同的获取和释放API函数。释放信号量用于使信号量有效,分为不带中断保护和带中断保护两个版本。
xSemaphoreGive 不带中断保护的版本
1 2 3 #define xSemaphoreGive( xSemaphore ) \ xQueueGenericSend( ( QueueHandle_t ) ( xSemaphore ), NULL , semGIVE_BLOCK_TIME, queueSEND_TO_BACK )
对于二进制信号量和计数信号量, 释放一个信号量的过程实际上可以简化为两种情况:
第一,如果队列未满,队列结构体成员uxMessageWaiting加1,判断xSemaphore上是否有阻塞的任务,有的话解除阻塞,然后返回成功信息(pdPASS);
第二,如果队列满,返回错误代码(err_QUEUE_FULL),表示队列满。
对于互斥量要复杂些,因为互斥量具有优先级继承机制。 释放互斥量可以简化为两种情况:
第一,如果队列未满
队列结构体成员uxMessageWaiting加1
还要判断获取互斥量的任务是否有优先级继承
如果有的话,还要将任务的优先级恢复到原始值。
恢复到原来值也是有条件的,就是该任务必须在没有使用其它互斥量的情况下,才能将继承的优先级恢复到原始值。
然后判断是否有阻塞的任务,有的话解除阻塞,最后返回成功信息(pdPASS);
第二,如果如果队列满,返回错误代码(err_QUEUE_FULL),表示队列满。
优先级继承机制 简单的说: 前提条件: 三个任务 A B C ,优先级 C > B > A , C 与 A 互斥访问同一资源 M: 假设 A (running), A持有资源M, C等待资源M。 来了一个中断,A退出运行态,此时应该切换到C,但是C在等待资源M,所以C 得不到调度 如果按现有的优先级顺序,需要调度到B,再调度到C, 如果C的take的timeout非常大时,可能会阻塞很长事件。 加入优先级继承后, 这样C在take时,会将A的优先级提升到和C一样, 等不到资源调度出去后,会先切到A,A在做完事情后,释放资源M,A在释放时,需要将优先级回到原来的初始值, 再切换到C, C就不需要阻塞那么长的时间。
xSemaphoreGiveFromISR 带中断保护的版本 被释放的信号量可以是二进制信号量和计数信号量。和普通版本的释放信号量API函数不同,它不能释放互斥量,这是因为互斥量不可以在中断中使用 互斥量只能在任务的上下文中使用, take, give 互斥量的优先级继承机制只能在任务中起作用,在中断中毫无意义。 带中断保护的信号量释放其实也是一个宏,真正调用的函数是xQueueGiveFromISR
1 #define xSemaphoreGiveFromISR( xSemaphore, pxHigherPriorityTaskWoken ) xQueueGiveFromISR( ( QueueHandle_t ) ( xSemaphore ), ( pxHigherPriorityTaskWoken ) )
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 BaseType_t xQueueGiveFromISR ( QueueHandle_t xQueue, BaseType_t * const pxHigherPriorityTaskWoken ) { BaseType_t xReturn; UBaseType_t uxSavedInterruptStatus; Queue_t * const pxQueue = ( Queue_t * ) xQueue; portASSERT_IF_INTERRUPT_PRIORITY_INVALID(); uxSavedInterruptStatus = portSET_INTERRUPT_MASK_FROM_ISR(); { const UBaseType_t uxMessagesWaiting = pxQueue->uxMessagesWaiting; if ( uxMessagesWaiting < pxQueue->uxLength ) { traceQUEUE_SEND_FROM_ISR( pxQueue ); pxQueue->uxMessagesWaiting = uxMessagesWaiting + ( UBaseType_t ) 1 ; const int8_t cTxLock = pxQueue->cTxLock; if ( cTxLock == queueUNLOCKED ) { if ( listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToReceive ) ) == pdFALSE ) if ( xTaskRemoveFromEventList( &( pxQueue->xTasksWaitingToReceive ) ) != pdFALSE ) if ( pxHigherPriorityTaskWoken != NULL ) *pxHigherPriorityTaskWoken = pdTRUE; } else { pxQueue->cTxLock = ( int8_t ) ( cTxLock + 1 ); } xReturn = pdPASS; } } portCLEAR_INTERRUPT_MASK_FROM_ISR( uxSavedInterruptStatus ); return xReturn; }
如果队列满,直接返回错误代码(err_QUEUE_FULL);
如果队列未满,则将队列结构体成员uxMessageWaiting加1,然后视队列是否上锁而决定是否解除任务阻塞(如果有得话)
获取信号量 1 #define xSemaphoreTake( xSemaphore, xBlockTime ) xQueueSemaphoreTake( ( xSemaphore ), ( xBlockTime ) )
无论二进制信号量、计数信号量还是互斥量,它们都使用相同的获取和释放API函数。 获取信号量会消耗信号量,如果获取信号量失败,任务可能会阻塞,阻塞时间由函数参数xBlockTime指定,如果为0,则直接返回,不阻塞。 获取信号量分为不带中断保护和带中断保护两个版本。
1 BaseType_t xQueueSemaphoreTake ( QueueHandle_t xQueue, TickType_t xTicksToWait )
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 BaseType_t xQueueSemaphoreTake ( QueueHandle_t xQueue, TickType_t xTicksToWait ) { BaseType_t xEntryTimeSet = pdFALSE; TimeOut_t xTimeOut; Queue_t * const pxQueue = ( Queue_t * ) xQueue; #if ( configUSE_MUTEXES == 1 ) BaseType_t xInheritanceOccurred = pdFALSE; #endif for ( ;; ) { taskENTER_CRITICAL(); { const UBaseType_t uxSemaphoreCount = pxQueue->uxMessagesWaiting; 1. a ----> if ( uxSemaphoreCount > ( UBaseType_t ) 0 ) { 1. a.1 ----> pxQueue->uxMessagesWaiting = uxSemaphoreCount - ( UBaseType_t ) 1 ; #if ( configUSE_MUTEXES == 1 ) { 1. a.2 ----> if ( pxQueue->uxQueueType == queueQUEUE_IS_MUTEX ) { pxQueue->pxMutexHolder = ( int8_t * ) pvTaskIncrementMutexHeldCount(); } } #endif 1. a.3 ----> if ( listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToSend ) ) == pdFALSE ) { if ( xTaskRemoveFromEventList( &( pxQueue->xTasksWaitingToSend ) ) != pdFALSE ) { queueYIELD_IF_USING_PREEMPTION(); } } taskEXIT_CRITICAL(); return pdPASS; } 2. ----> else { 2. a ----> if ( xTicksToWait == ( TickType_t ) 0 ) { taskEXIT_CRITICAL(); traceQUEUE_RECEIVE_FAILED( pxQueue ); return errQUEUE_EMPTY; } 2.b ----> else if ( xEntryTimeSet == pdFALSE ) { vTaskInternalSetTimeOutState( &xTimeOut ); xEntryTimeSet = pdTRUE; } } } taskEXIT_CRITICAL(); 2.b ----> vTaskSuspendAll(); prvLockQueue( pxQueue ); 2.b .1 ----> if ( xTaskCheckForTimeOut( &xTimeOut, &xTicksToWait ) == pdFALSE ) { if ( prvIsQueueEmpty( pxQueue ) != pdFALSE ) { #if ( configUSE_MUTEXES == 1 ) { if ( pxQueue->uxQueueType == queueQUEUE_IS_MUTEX ) { taskENTER_CRITICAL(); { xInheritanceOccurred = xTaskPriorityInherit( ( void * ) pxQueue->pxMutexHolder ); } taskEXIT_CRITICAL(); } } #endif vTaskPlaceOnEventList( &( pxQueue->xTasksWaitingToReceive ), xTicksToWait ); prvUnlockQueue( pxQueue ); if ( xTaskResumeAll() == pdFALSE ) { portYIELD_WITHIN_API(); } } else { prvUnlockQueue( pxQueue ); ( void ) xTaskResumeAll(); } } 2.b .2 ----> else { prvUnlockQueue( pxQueue ); ( void ) xTaskResumeAll(); if ( prvIsQueueEmpty( pxQueue ) != pdFALSE ) { #if ( configUSE_MUTEXES == 1 ) { if ( xInheritanceOccurred != pdFALSE ) { taskENTER_CRITICAL(); { UBaseType_t uxHighestWaitingPriority; uxHighestWaitingPriority = prvGetDisinheritPriorityAfterTimeout( pxQueue ); vTaskPriorityDisinheritAfterTimeout( ( void * ) pxQueue->pxMutexHolder, uxHighestWaitingPriority ); } taskEXIT_CRITICAL(); } } #endif return errQUEUE_EMPTY; } } } }
小结
Queue上有信号量的情况下 a. 出队(出队/入队, 队是指的Queue)
直接拿到了该信号量. 返回true
队列uxMessagesWaiting表示队列上有多少信号量, uxMessagesWaiting-1
Queue的pxMutexHolder更新为当前任务, 同时当前任务的持有mutex数+1
查看是否有等待释放该信号量的任务,如果有, 将等待任务的事件列表项从xTasksWaitingToSend
上删除,并且将任务移动到就绪列表中, 触发pendsv中断
释放信号量的任务为什么会阻塞? Queue满了且不是覆盖式入队且设置了timeout的情况, 参考freertos 队列xQueue分析 , 此时要先将这个释放信号量的任务唤醒. 需要切换上下文.
Queue上没有信号量:
a. 没有信号量,且未设置timeout的情况, 直接返回ERROR_EMPTY b. 设置了timeout, 队列上没有信号量
- 设置了timeout, 队列上没有信号量, timeout未到期
- 如果信号量是mutex, 则需要记录是否发生了或发生过优先级反转, 这个标记在后面timeout到期后会用到,
- 如果此时需要发生优先级继承
- 持有该mutex的任务继承当前任务的优先级
- 如果持有该mutex的任务处于就绪列表中, 需要将其重入readylists, 复位readylists的最高优先级
- 放入等待队列, 即当前任务的事件列表项挂入队列的`xTasksWaitingToReceive`, 同时当前任务的状态列表项挂入延时列表, 更新nextUnblocktime, 由tick中断处理.
- 一是当队列上被释放了信号量时会将`xTasksWaitingToReceive`上的等待的任务唤醒,
- 如果在到期之前没有信号被释放的话, timeout到期后, 该任务才会被唤醒.
-
解锁queue (解锁后才可以操作队列, 这里的操作是专门针对中断服务说的), 恢复调度器, 切换任务, 该任务已经由就绪态转到阻塞态, 调度到就绪列表上最高优先级 - 设置了timeout, 队列上没有信号量, timeout到期了(由tick中断处理delaylist上状态列表项到期时唤醒) - 如果信号量是mutex, 在未到期时发生了或发生过优先级继承, 需要重设持有该mutex的任务的优先级. - 有其他任务在等待take该mutex时, 持有mutex任务初始优先级大于等于其他take该mutex任务的最高优先级时, 重设为这些任务中的最高优先级 - 没有其他任务在等待take该mutex时, 重设优先级为其初始的优先级( base). 或持有mutex任务初始优先级大于等于其他take该mutex任务的最高优先级时, 回到其初始优先级 - 持有该mutex的任务的优先级与将要变动到的优先级如果相同, 则后面什么也不做, 直接返回. 只有发生了变化时, 才进行后面的步骤 - 优先级需要变更的情况下:
持有该mutex的任务如果在就绪列表中, 需要重入readylists, 同时复位readylists的最高优先级
这个需要结合入队(入Queue) (释放信号量的过程)来看
freertos 队列xQueue分析
优先级继承 这里需要特别看下上述过程发生优先级继承时发生了什么? 信号量是mutex
的情况, 才会发生优先级继承. Queue上没有信号量, 该任务要take信号量时, 设置了timeout
timeout未到期, 会调用xTaskPriorityInherit( ( void * ) pxQueue->pxMutexHolder )
见下面的分析, xInheritanceOccurred= true, 表明 a. 当前任务优先级优先级大于持有该任务优先级的任务, 此时发生
优先级继承 1). 如果持有该mutex的任务处于就绪列表中, 需要更新就绪列表, 包括重设优先级等, 持有该mutex的任务需要重入就绪列表. b. 有该mutex的任务优先级比当前任务的优先级低, 但是持有mutex的任务已经发生过
优先级继承时, 也返回true
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 xInheritanceOccurred = xTaskPriorityInherit( ( void * ) pxQueue->pxMutexHolder ) BaseType_t xTaskPriorityInherit( TaskHandle_t const pxMutexHolder ) { TCB_t * const pxMutexHolderTCB = ( TCB_t * ) pxMutexHolder; BaseType_t xReturn = pdFALSE; if ( pxMutexHolder != NULL ) { 1. a ----> if ( pxMutexHolderTCB->uxPriority < pxCurrentTCB->uxPriority ) { if ( ( listGET_LIST_ITEM_VALUE( &( pxMutexHolderTCB->xEventListItem ) ) & taskEVENT_LIST_ITEM_VALUE_IN_USE ) == 0UL ) { listSET_LIST_ITEM_VALUE( &( pxMutexHolderTCB->xEventListItem ), ( TickType_t ) configMAX_PRIORITIES - ( TickType_t ) pxCurrentTCB->uxPriority ); } if ( listIS_CONTAINED_WITHIN( &( pxReadyTasksLists[ pxMutexHolderTCB->uxPriority ] ), &( pxMutexHolderTCB->xStateListItem ) ) != pdFALSE ) { if ( uxListRemove( &( pxMutexHolderTCB->xStateListItem ) ) == ( UBaseType_t ) 0 ) { taskRESET_READY_PRIORITY( pxMutexHolderTCB->uxPriority ); } pxMutexHolderTCB->uxPriority = pxCurrentTCB->uxPriority; prvAddTaskToReadyList( pxMutexHolderTCB ); } else { pxMutexHolderTCB->uxPriority = pxCurrentTCB->uxPriority; } <------ xReturn = pdTRUE; } else { 1.b ----> if ( pxMutexHolderTCB->uxBasePriority < pxCurrentTCB->uxPriority ) { <------- xReturn = pdTRUE; } } } <------- 2. -----> return xReturn; }
timeout到期, 会调用如下过程重设 当初发生 优先级继承的任务
的优先级
持有该mutex的任务的优先级不是回到其初始的优先级, 如果有其他任务仍然在等待该mutex, 则需要从这些任务中找出最高的优先级(listGET_ITEM_VALUE_OF_HEAD_ENTRY( &( pxQueue->xTasksWaitingToReceive ) )
), 然后设置到该最高优先级. 这个优先级被叫做次高优先级. a. 有其他任务在等待take该mutex时, 持有mutex任务初始优先级大于等于其他take该mutex任务的最高优先级时, 重设为这些任务中的最高优先级 b. 没有其他任务在等待take该mutex时, 重设优先级为其初始的优先级( base). 或持有mutex任务初始优先级大于等于其他take该mutex任务的最高优先级时, 回到其初始优先级 持有该mutex的任务的优先级与将要变动到的优先级如果相同, 则后面什么也不做, 直接返回. 只有发生了变化时, 才进行后面的步骤 优先级需要变更的情况下: 持有该mutex的任务如果在就绪列表中, 需要重入readylists, 同时复位readylists的最高优先级
当前take mutex的任务到期后, 如果持有该mutex的任务在当前任务未到期时发生了或发生过优先级继承时, 需要重设持有该mutex的任务优先级. 重设过程只发生在持有该mutex的任务此时只持有了这一个mutex时, 如果持有多个mutex, 则不会进行重设
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 uxHighestWaitingPriority = prvGetDisinheritPriorityAfterTimeout( pxQueue ); static UBaseType_t prvGetDisinheritPriorityAfterTimeout ( const Queue_t * const pxQueue ) { UBaseType_t uxHighestPriorityOfWaitingTasks; if ( listCURRENT_LIST_LENGTH( &( pxQueue->xTasksWaitingToReceive ) ) > 0 ) { uxHighestPriorityOfWaitingTasks = configMAX_PRIORITIES - listGET_ITEM_VALUE_OF_HEAD_ENTRY( &( pxQueue->xTasksWaitingToReceive ) ); } else { uxHighestPriorityOfWaitingTasks = tskIDLE_PRIORITY; } return uxHighestPriorityOfWaitingTasks; } vTaskPriorityDisinheritAfterTimeout( ( void * ) pxQueue->pxMutexHolder, uxHighestWaitingPriority ); void vTaskPriorityDisinheritAfterTimeout ( TaskHandle_t const pxMutexHolder, UBaseType_t uxHighestPriorityWaitingTask ) { TCB_t * const pxTCB = ( TCB_t * ) pxMutexHolder; UBaseType_t uxPriorityUsedOnEntry, uxPriorityToUse; const UBaseType_t uxOnlyOneMutexHeld = ( UBaseType_t ) 1 ; if ( pxMutexHolder != NULL ) { 2. a ----> if ( pxTCB->uxBasePriority < uxHighestPriorityWaitingTask ) { uxPriorityToUse = uxHighestPriorityWaitingTask; } 2.b ----> else { uxPriorityToUse = pxTCB->uxBasePriority; } if ( pxTCB->uxPriority != uxPriorityToUse ) { if ( pxTCB->uxMutexesHeld == 1 ) { uxPriorityUsedOnEntry = pxTCB->uxPriority; pxTCB->uxPriority = uxPriorityToUse; if ( ( listGET_LIST_ITEM_VALUE( &( pxTCB->xEventListItem ) ) & taskEVENT_LIST_ITEM_VALUE_IN_USE ) == 0UL ) { listSET_LIST_ITEM_VALUE( &( pxTCB->xEventListItem ), ( TickType_t ) configMAX_PRIORITIES - ( TickType_t ) uxPriorityToUse ); } if ( listIS_CONTAINED_WITHIN( &( pxReadyTasksLists[ uxPriorityUsedOnEntry ] ), &( pxTCB->xStateListItem ) ) != pdFALSE ) { if ( uxListRemove( &( pxTCB->xStateListItem ) ) == ( UBaseType_t ) 0 ) { taskRESET_READY_PRIORITY( pxTCB->uxPriority ); } prvAddTaskToReadyList( pxTCB ); } } } } }