【freertos-kernel】queue(发送)

news2025/6/3 7:14:02

文章目录

  • 补充
    • 各种yeild
    • TCB的xStateListItem和xEventListItem
  • xQueueGenericSend
    • prvCopyDataToQueue
    • prvNotifyQueueSetContainer
    • vTaskInternalSetTimeOutState
    • vTaskSuspendAll
    • xTaskResumeAll
    • prvLockQueue
    • prvUnlockQueue
    • prvIncrementQueueTxLock
    • vTaskPlaceOnEventList
      • prvAddCurrentTaskToDelayedList
  • xQueueGenericSendFromISR

补充

各种yeild

各种 yield 宏和函数的作用都是为了让系统知道“现在应该检查是否需要切换到更高优先级任务”,它们的区别在于使用的上下文和条件不同。

名称含义使用场景
portYIELD_WITHIN_API()强制进行一次任务调度在非中断上下文中调用,比如队列操作后
taskYIELD()同上,是 portYIELD_WITHIN_API() 的别名同上
portEND_SWITCHING_ISR(xHigherPriorityTaskWoken)在中断中唤醒任务后使用ISR 中调用 xQueueSendFromISR() 等函数后
vTaskMissedYield()标记需要调度,但不在当前上下文立即执行在调度器被挂起期间唤醒任务时使用
queueYIELD_IF_USING_PREEMPTION()如果启用抢占式调度,就 yield多用于队列、信号量内部逻辑中

TCB的xStateListItem和xEventListItem

xStateListItem用于任务状态切换,它决定了任务处于哪个系统级(全局)链表中(如就绪、延时、挂起等)。
xEventListItem用于将任务加入到某个特定事件的等待列表中(例如队列的发送/接收等待列表、信号量的等待列表等)。

xQueueGenericSend

实现了将数据放入队列、唤醒等待任务、以及在队列满时让任务进入阻塞状态等核心功能。
过程挺啰嗦的,简单来说就是xCopyPosition 确定新数据pvItemToQueue写入队列数据缓存区的位置,如果队列没满,就复制数据进队列,唤醒该队列的接受等待任务链表xTasksWaitingToReceive 中的任务;如果满了,等待xTicksToWait。
流程如图

xQueueGenericSend

BaseType_t xQueueGenericSend( QueueHandle_t xQueue,
                              const void * const pvItemToQueue,
                              TickType_t xTicksToWait,
                              const BaseType_t xCopyPosition )

初始化参数和断言检查

BaseType_t xEntryTimeSet = pdFALSE, xYieldRequired;
TimeOut_t xTimeOut;
Queue_t * const pxQueue = xQueue;
traceENTER_xQueueGenericSend( xQueue, pvItemToQueue, xTicksToWait, xCopyPosition );
//检查 pxQueue 是否合法。
configASSERT( pxQueue );
//确保传入的 pvItemToQueue 非空且队列项大小不为零。
configASSERT( !( ( pvItemToQueue == NULL ) && ( pxQueue->uxItemSize != ( UBaseType_t ) 0U ) ) );
//如果使用 queueOVERWRITE 模式,则确保队列长度为1(因为只能覆盖已有的一项)。
configASSERT( !( ( xCopyPosition == queueOVERWRITE ) && ( pxQueue->uxLength != 1 ) ) );
#if ( ( INCLUDE_xTaskGetSchedulerState == 1 ) || ( configUSE_TIMERS == 1 ) )
{
	//若调度器被挂起且需要等待时间,触发断言失败(调度器挂起时不能阻塞等待)。
    configASSERT( !( ( xTaskGetSchedulerState() == taskSCHEDULER_SUSPENDED ) && ( xTicksToWait != 0 ) ) );
}
#endif

进入循环尝试发送数据

for( ; ; )
{
    taskENTER_CRITICAL();
    {
    	//如果当前消息数小于最大容量,或使用的是覆盖写,则可以继续发送
        if( ( pxQueue->uxMessagesWaiting < pxQueue->uxLength ) || ( xCopyPosition == queueOVERWRITE ) )
        {
            traceQUEUE_SEND( pxQueue );
            #if ( configUSE_QUEUE_SETS == 1 )//如果启用了 configUSE_QUEUE_SETS
            {
                const UBaseType_t uxPreviousMessagesWaiting = pxQueue->uxMessagesWaiting;
                //将数据拷贝进队列缓冲区
                xYieldRequired = prvCopyDataToQueue( pxQueue, pvItemToQueue, xCopyPosition );
                if( pxQueue->pxQueueSetContainer != NULL )//如果这个队列属于某个队列集合
                {
                	//覆盖写并且之前有数据,只是替换已有数据,不需要再通知队列集合
                    if( ( xCopyPosition == queueOVERWRITE ) && ( uxPreviousMessagesWaiting != ( UBaseType_t ) 0 ) )
                    {
                        mtCOVERAGE_TEST_MARKER();
                    }
                    //通知队列集合
                    else if( prvNotifyQueueSetContainer( pxQueue ) != pdFALSE )
                    {
                        queueYIELD_IF_USING_PREEMPTION();
                    }
                    ...
                }
                else//如果这个队列不属于某个队列集合
                {
                	//如果有任务在等待从队列接收数据(即 xTasksWaitingToReceive 不为空),唤醒一个任务
                    if( listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToReceive ) ) == pdFALSE )
                    {
                        if( xTaskRemoveFromEventList( &( pxQueue->xTasksWaitingToReceive ) ) != pdFALSE )
                        {
                            queueYIELD_IF_USING_PREEMPTION();
                        }
                       	...
                    }
                    else if( xYieldRequired != pdFALSE )
                    {
                        queueYIELD_IF_USING_PREEMPTION();
                    }
                   ...
                }
            }
            #else /* configUSE_QUEUE_SETS */
            {
            	//拷贝数据
                xYieldRequired = prvCopyDataToQueue( pxQueue, pvItemToQueue, xCopyPosition );
                //如果有任务等待该队列消息,就唤醒该任务
                if( listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToReceive ) ) == pdFALSE )
                {
                    if( xTaskRemoveFromEventList( &( pxQueue->xTasksWaitingToReceive ) ) != pdFALSE )
                    {
                        queueYIELD_IF_USING_PREEMPTION();
                    }
                   	...
                }
                else if( xYieldRequired != pdFALSE )
                {
                    queueYIELD_IF_USING_PREEMPTION();
                }
               	...
            }
            #endif /* configUSE_QUEUE_SETS */
            taskEXIT_CRITICAL();	//退出临界区
            traceRETURN_xQueueGenericSend( pdPASS );
            return pdPASS;
        }
        else//消息数量满了
        {
            if( xTicksToWait == ( TickType_t ) 0 )//不允许等
            {
                taskEXIT_CRITICAL();
                traceQUEUE_SEND_FAILED( pxQueue );
                traceRETURN_xQueueGenericSend( errQUEUE_FULL );
                return errQUEUE_FULL;
            }
            else if( xEntryTimeSet == pdFALSE )//允许等待
            {
            	//初始化超时
                vTaskInternalSetTimeOutState( &xTimeOut );
                xEntryTimeSet = pdTRUE;
            }
            else
            {
                mtCOVERAGE_TEST_MARKER();
            }
        }
    }
    taskEXIT_CRITICAL();
    //挂起调度器并锁定队列
    vTaskSuspendAll();
    prvLockQueue( pxQueue );
    //检查是否超时
    if( xTaskCheckForTimeOut( &xTimeOut, &xTicksToWait ) == pdFALSE )
    {
        if( prvIsQueueFull( pxQueue ) != pdFALSE )
        {	//如果未超时且仍满,则将当前任务加入发送等待列表
            traceBLOCKING_ON_QUEUE_SEND( pxQueue );
            vTaskPlaceOnEventList( &( pxQueue->xTasksWaitingToSend ), xTicksToWait );
            prvUnlockQueue( pxQueue );
            if( xTaskResumeAll() == pdFALSE )
            {
                taskYIELD_WITHIN_API();
            }
        }
        else//未超时队列未满
        {
            prvUnlockQueue( pxQueue );//解锁队列
            ( void ) xTaskResumeAll();//恢复调度器
        }
    }
    else //超时了
    {
        prvUnlockQueue( pxQueue );//解锁队列
        ( void ) xTaskResumeAll();//恢复调度器
        traceQUEUE_SEND_FAILED( pxQueue );
        traceRETURN_xQueueGenericSend( errQUEUE_FULL );
        return errQUEUE_FULL;
    }
}

prvCopyDataToQueue

指定位置拷贝数据进队列缓存区。

static BaseType_t prvCopyDataToQueue( Queue_t * const pxQueue,
                                      const void * pvItemToQueue,//要入队的数据
                                      const BaseType_t xPosition )//插入位置
{
    BaseType_t xReturn = pdFALSE;
    UBaseType_t uxMessagesWaiting;
    uxMessagesWaiting = pxQueue->uxMessagesWaiting;
    if( pxQueue->uxItemSize == ( UBaseType_t ) 0 )//判断是否是空队列(uxItemSize == 0)
    {
        #if ( configUSE_MUTEXES == 1 )
        {
            if( pxQueue->uxQueueType == queueQUEUE_IS_MUTEX )//如果是互斥锁
            {
                xReturn = xTaskPriorityDisinherit( pxQueue->u.xSemaphore.xMutexHolder );//解除优先级继承
                pxQueue->u.xSemaphore.xMutexHolder = NULL;//清除当前持有者
            }
            ...
        }
        #endif /* configUSE_MUTEXES */
    }
    else if( xPosition == queueSEND_TO_BACK )//uxItemSize不为0,发送到队列尾部
    {
    	//将数据从 pvItemToQueue 拷贝到队列的写入位置 pcWriteTo
        ( void ) memcpy( ( void * ) pxQueue->pcWriteTo, pvItemToQueue, ( size_t ) pxQueue->uxItemSize );
        pxQueue->pcWriteTo += pxQueue->uxItemSize;//写完后,pcWriteTo 指针偏移uxItemSize
        if( pxQueue->pcWriteTo >= pxQueue->u.xQueue.pcTail )
        {
            pxQueue->pcWriteTo = pxQueue->pcHead;//如果写到了队列末尾,则绕回到队列头部(循环队列)
        }
        ...
    }
    else //uxItemSize不为0,发送到队列头部 或 覆盖写
    {
    	//数据被拷贝到 pcReadFrom 的当前位置(即下一个读取位置)
        ( void ) memcpy( ( void * ) pxQueue->u.xQueue.pcReadFrom, pvItemToQueue, ( size_t ) pxQueue->uxItemSize );
        pxQueue->u.xQueue.pcReadFrom -= pxQueue->uxItemSize;//将 pcReadFrom 指针向前偏移uxItemSize
        if( pxQueue->u.xQueue.pcReadFrom < pxQueue->pcHead )
        {	//如果指针小于队列头部,则绕回队列末尾
            pxQueue->u.xQueue.pcReadFrom = ( pxQueue->u.xQueue.pcTail - pxQueue->uxItemSize );
        }
        ...
        if( xPosition == queueOVERWRITE )
        {
            if( uxMessagesWaiting > ( UBaseType_t ) 0 )
            {
            	//如果是 queueOVERWRITE 模式,表示这是替换已有元素,所以减少当前等待的消息数 uxMessagesWaiting(如果之前有数据的话)
                --uxMessagesWaiting;
            }
            ...
        }
        ...
    }
    //更新队列当前消息数
    pxQueue->uxMessagesWaiting = ( UBaseType_t ) ( uxMessagesWaiting + ( UBaseType_t ) 1 );
    return xReturn;
}

prvNotifyQueueSetContainer

static BaseType_t prvNotifyQueueSetContainer( const Queue_t * const pxQueue )
{
    Queue_t * pxQueueSetContainer = pxQueue->pxQueueSetContainer;//获取队列集合指针
    BaseType_t xReturn = pdFALSE;
    configASSERT( pxQueueSetContainer ); //确保集合存在
    configASSERT( pxQueueSetContainer->uxMessagesWaiting < pxQueueSetContainer->uxLength );//确保集合没满
    if( pxQueueSetContainer->uxMessagesWaiting < pxQueueSetContainer->uxLength )
    {
        const int8_t cTxLock = pxQueueSetContainer->cTxLock;//记录当前集合的发送锁状态
        traceQUEUE_SET_SEND( pxQueueSetContainer );
        xReturn = prvCopyDataToQueue( pxQueueSetContainer, &pxQueue, queueSEND_TO_BACK );//将当前队列加入集合
        if( cTxLock == queueUNLOCKED )//如果集合没有被锁定
        {	//检查是否要唤醒等待接收的任务
            if( listLIST_IS_EMPTY( &( pxQueueSetContainer->xTasksWaitingToReceive ) ) == pdFALSE )
            {
                if( xTaskRemoveFromEventList( &( pxQueueSetContainer->xTasksWaitingToReceive ) ) != pdFALSE )
                {
                    xReturn = pdTRUE;
                }
                ...
            }
            ...
        }
        else
        {
            prvIncrementQueueTxLock( pxQueueSetContainer, cTxLock );//增加集合的锁计数器(防止并发访问冲突)
        }
    }
    ...
    return xReturn;
}

vTaskInternalSetTimeOutState

void vTaskInternalSetTimeOutState( TimeOut_t * const pxTimeOut )
{
    traceENTER_vTaskInternalSetTimeOutState( pxTimeOut );
    pxTimeOut->xOverflowCount = xNumOfOverflows;// 溢出计数器(记录 tick 计数器回绕次数)
    pxTimeOut->xTimeOnEntering = xTickCount;	// 开始等待的时间点(tick 值)
    traceRETURN_vTaskInternalSetTimeOutState();
}

关于定时器详细的信息后面再看。

vTaskSuspendAll

暂停调度器,防止任务切换 ,以确保在执行某些关键操作期间,系统状态不会被其他任务修改。
使用一个全局变量 uxSchedulerSuspended 来记录调度器被挂起的次数。

//gcc/arm-cm3
#define portASSERT_IF_IN_ISR() configASSERT( uxInterruptNesting == 0 )
#define portMEMORY_BARRIER()    __asm volatile ( "" ::: "memory" )

"memory":告诉编译器这行代码会读写内存,不能对内存操作进行重排序

void vTaskSuspendAll( void )
{
    traceENTER_vTaskSuspendAll();
    #if ( configNUMBER_OF_CORES == 1 )
    {
        portSOFTWARE_BARRIER();//在某些模拟/仿真平台中,用来模拟“内存屏障”行为,防止编译器优化导致的指令重排序问题。
        uxSchedulerSuspended = ( UBaseType_t ) ( uxSchedulerSuspended + 1U );
        portMEMORY_BARRIER();
    }
    #else /* #if ( configNUMBER_OF_CORES == 1 ) */
    {
        UBaseType_t ulState;
        portASSERT_IF_IN_ISR();				// 确保不在中断中调用
        if( xSchedulerRunning != pdFALSE )
        {
            ulState = portSET_INTERRUPT_MASK();	// 关中断
            configASSERT( portGET_CRITICAL_NESTING_COUNT() == 0 );	// 确保不在临界区
            portSOFTWARE_BARRIER();
            portGET_TASK_LOCK();	// 获取任务锁(多核同步)
            if( uxSchedulerSuspended == 0U )
            {
                prvCheckForRunStateChange();	// 第一次挂起时可能要做一些检查
            }
            ...
            portGET_ISR_LOCK();// 获取 ISR 锁
            ++uxSchedulerSuspended;// 增加挂起计数
            portRELEASE_ISR_LOCK();// 释放 ISR 锁
            portCLEAR_INTERRUPT_MASK( ulState ); // 开中断
        }
        ...
    }
    #endif /* #if ( configNUMBER_OF_CORES == 1 ) */
    traceRETURN_vTaskSuspendAll();
}

xTaskResumeAll

恢复任务调度器,唤醒等待中的任务,并处理挂起期间积压的 tick 和待调度任务

BaseType_t xTaskResumeAll( void )
{
    TCB_t * pxTCB = NULL;
    BaseType_t xAlreadyYielded = pdFALSE;
    traceENTER_xTaskResumeAll();
    #if ( configNUMBER_OF_CORES > 1 )
        if( xSchedulerRunning != pdFALSE )
    #endif
    {
        taskENTER_CRITICAL();
        {
            BaseType_t xCoreID;
            xCoreID = ( BaseType_t ) portGET_CORE_ID();
            configASSERT( uxSchedulerSuspended != 0U );
            uxSchedulerSuspended = ( UBaseType_t ) ( uxSchedulerSuspended - 1U );
            portRELEASE_TASK_LOCK();
            if( uxSchedulerSuspended == ( UBaseType_t ) 0U )
            {
                if( uxCurrentNumberOfTasks > ( UBaseType_t ) 0U )
                {	//处理挂起期间加入就绪列表的任务
                    while( listLIST_IS_EMPTY( &xPendingReadyList ) == pdFALSE )
                    {
                        pxTCB = listGET_OWNER_OF_HEAD_ENTRY( ( &xPendingReadyList ) );
                        listREMOVE_ITEM( &( pxTCB->xEventListItem ) );
                        portMEMORY_BARRIER();
                        listREMOVE_ITEM( &( pxTCB->xStateListItem ) );
                        prvAddTaskToReadyList( pxTCB );
                        #if ( configNUMBER_OF_CORES == 1 )
                        {
                            if( pxTCB->uxPriority > pxCurrentTCB->uxPriority )
                            {
                                xYieldPendings[ xCoreID ] = pdTRUE;
                            }
                        }
                    }

                    if( pxTCB != NULL )
                    {	//更新下一个要解除阻塞的任务时间
                        prvResetNextTaskUnblockTime();
                    }
                    {
                    	//处理挂起期间积累的 tick 数量
                        TickType_t xPendedCounts = xPendedTicks; /* Non-volatile copy. */
                        if( xPendedCounts > ( TickType_t ) 0U )
                        {
                            do
                            {
                            	//每处理一个 tick,调用 xTaskIncrementTick() 检查是否有任务超时或就绪;
								//如果有高优先级任务就绪,标记调度需求
                                if( xTaskIncrementTick() != pdFALSE )
                                {
                                    xYieldPendings[ xCoreID ] = pdTRUE;
                                }
                                --xPendedCounts;
                            } while( xPendedCounts > ( TickType_t ) 0U );
                            xPendedTicks = 0;
                        }
                    }
                    if( xYieldPendings[ xCoreID ] != pdFALSE )
                    {	//如果需要调度,执行一次上下文切换
                        #if ( configUSE_PREEMPTION != 0 )
                        {
                            xAlreadyYielded = pdTRUE;
                        }
                        #endif /* #if ( configUSE_PREEMPTION != 0 ) */
                        #if ( configNUMBER_OF_CORES == 1 )
                        {
                            taskYIELD_TASK_CORE_IF_USING_PREEMPTION( pxCurrentTCB );
                        }
                        #endif /* #if ( configNUMBER_OF_CORES == 1 ) */
                    }
                }
            }
        }
        taskEXIT_CRITICAL();
    }
    traceRETURN_xTaskResumeAll( xAlreadyYielded );
    return xAlreadyYielded;
}

prvLockQueue

进入临界区并标记队列为“已锁定”,确保当前上下文独占访问队列,防止其他任务或中断修改队列状态。

#define prvLockQueue( pxQueue )                            \
    taskENTER_CRITICAL();                                  \
    {                                                      \
        if( ( pxQueue )->cRxLock == queueUNLOCKED )        \
        {                                                  \
            ( pxQueue )->cRxLock = queueLOCKED_UNMODIFIED; \
        }                                                  \
        if( ( pxQueue )->cTxLock == queueUNLOCKED )        \
        {                                                  \
            ( pxQueue )->cTxLock = queueLOCKED_UNMODIFIED; \
        }                                                  \
    }                                                      \
    taskEXIT_CRITICAL()

prvUnlockQueue

释放队列的发送锁 (cTxLock) 和接收锁 (cRxLock),并唤醒等待在该队列上的任务(如果有)。

void vTaskMissedYield( void )
{
    traceENTER_vTaskMissedYield();
    xYieldPendings[ portGET_CORE_ID() ] = pdTRUE;
    traceRETURN_vTaskMissedYield();
}

static void prvUnlockQueue( Queue_t * const pxQueue )
{
    taskENTER_CRITICAL();
    {
        int8_t cTxLock = pxQueue->cTxLock;
        while( cTxLock > queueLOCKED_UNMODIFIED )//在此期间有嵌套操作(比如中断中再次写入队列),循环处理这些嵌套操作,直到减到 queueLOCKED_UNMODIFIED;
        {
            #if ( configUSE_QUEUE_SETS == 1 )
            {
                if( pxQueue->pxQueueSetContainer != NULL )
                {
                	//通知集合
					//集合可能会唤醒等待它的任务
                    if( prvNotifyQueueSetContainer( pxQueue ) != pdFALSE )
                    {
                        vTaskMissedYield();
                    }
                    ...
                }
                else
                {
                    if( listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToReceive ) ) == pdFALSE )
                    {
                        if( xTaskRemoveFromEventList( &( pxQueue->xTasksWaitingToReceive ) ) != pdFALSE )
                        {
                            vTaskMissedYield();//如果唤醒的是优先级更高的任务,标记需要调度
                        }
                        ...
                    }
                    else
                    {
                        break;
                    }
                }
            }
            #else /* configUSE_QUEUE_SETS */
            {
                //不为空的话,唤醒任务,vTaskMissedYield
            }
            #endif /* configUSE_QUEUE_SETS */
            --cTxLock;
        }

        pxQueue->cTxLock = queueUNLOCKED;
    }
    taskEXIT_CRITICAL();
	//对cRxLock 做同样的操作
}

prvIncrementQueueTxLock

没啥好说的,递增队列的发送锁

#define prvIncrementQueueTxLock( pxQueue, cTxLock )                           \
    do {                                                                      \
        const UBaseType_t uxNumberOfTasks = uxTaskGetNumberOfTasks();         \
        if( ( UBaseType_t ) ( cTxLock ) < uxNumberOfTasks )                   \
        {                                                                     \
            configASSERT( ( cTxLock ) != queueINT8_MAX );                     \
            ( pxQueue )->cTxLock = ( int8_t ) ( ( cTxLock ) + ( int8_t ) 1 ); \
        }                                                                     \
    } while( 0 )

vTaskPlaceOnEventList

将当前任务加入指定的事件列表(如 xTasksWaitingToReceive 或 xTasksWaitingToSend),并把它添加到延时列表中,使其进入阻塞状态。

void vTaskPlaceOnEventList( List_t * const pxEventList,
                            const TickType_t xTicksToWait )
{
    traceENTER_vTaskPlaceOnEventList( pxEventList, xTicksToWait );
    configASSERT( pxEventList );
    vListInsert( pxEventList, &( pxCurrentTCB->xEventListItem ) );//插入后,任务会进入阻塞状态,不再参与调度
    prvAddCurrentTaskToDelayedList( xTicksToWait, pdTRUE );//会把当前任务加入系统延时列表
    traceRETURN_vTaskPlaceOnEventList();
}

prvAddCurrentTaskToDelayedList

当前任务从就绪列表中移除,并根据设定的等待时间,将其插入到延时列表中,从而让任务进入阻塞状态。

static void prvAddCurrentTaskToDelayedList( TickType_t xTicksToWait,
                                            const BaseType_t xCanBlockIndefinitely )
{
    TickType_t xTimeToWake;
    const TickType_t xConstTickCount = xTickCount;
    List_t * const pxDelayedList = pxDelayedTaskList;
    List_t * const pxOverflowDelayedList = pxOverflowDelayedTaskList;
    #if ( INCLUDE_xTaskAbortDelay == 1 )
    {	//清除“延迟被中断”标志
        pxCurrentTCB->ucDelayAborted = ( uint8_t ) pdFALSE;
    }
    #endif
    //从就绪列表中移除当前任务
    if( uxListRemove( &( pxCurrentTCB->xStateListItem ) ) == ( UBaseType_t ) 0 )
    {	//如果这个优先级上没有其他任务了(即返回值为 0),就更新最高就绪优先级
        portRESET_READY_PRIORITY( pxCurrentTCB->uxPriority, uxTopReadyPriority );
    }
    #if ( INCLUDE_vTaskSuspend == 1 )
    {
        if( ( xTicksToWait == portMAX_DELAY ) && ( xCanBlockIndefinitely != pdFALSE ) )//无限期等待
        {	//将任务加入 挂起任务列表
            listINSERT_END( &xSuspendedTaskList, &( pxCurrentTCB->xStateListItem ) );
        }
        else
        {
            xTimeToWake = xConstTickCount + xTicksToWait;//计算唤醒时间点
            listSET_LIST_ITEM_VALUE( &( pxCurrentTCB->xStateListItem ), xTimeToWake );//设置任务状态项的值为唤醒时间
            if( xTimeToWake < xConstTickCount )//判断是否发生 tick 溢出
            {	//如果溢出就插入 pxOverflowDelayedList
                traceMOVED_TASK_TO_OVERFLOW_DELAYED_LIST();
                vListInsert( pxOverflowDelayedList, &( pxCurrentTCB->xStateListItem ) );
            }
            else
            {
            	//插入正常的 pxDelayedList
                traceMOVED_TASK_TO_DELAYED_LIST();
                vListInsert( pxDelayedList, &( pxCurrentTCB->xStateListItem ) );
                //如果该任务是下一个要解除阻塞的任务,更新全局变量 xNextTaskUnblockTime
                if( xTimeToWake < xNextTaskUnblockTime )
                {
                    xNextTaskUnblockTime = xTimeToWake;
                }
            }
        }
    }
    #else /* INCLUDE_vTaskSuspend */
    {
        xTimeToWake = xConstTickCount + xTicksToWait;计算唤醒时间点
        listSET_LIST_ITEM_VALUE( &( pxCurrentTCB->xStateListItem ), xTimeToWake );//设置任务状态项的值为唤醒时间
        //检查xTimeToWake 是否溢出
        if( xTimeToWake < xConstTickCount )
        {
            traceMOVED_TASK_TO_OVERFLOW_DELAYED_LIST();
            vListInsert( pxOverflowDelayedList, &( pxCurrentTCB->xStateListItem ) );
        }
        else
        {
            traceMOVED_TASK_TO_DELAYED_LIST();
            vListInsert( pxDelayedList, &( pxCurrentTCB->xStateListItem ) );
            if( xTimeToWake < xNextTaskUnblockTime )
            {
                xNextTaskUnblockTime = xTimeToWake;
            }
        }
        ( void ) xCanBlockIndefinitely;
    }
    #endif /* INCLUDE_vTaskSuspend */
}

xQueueGenericSendFromISR

与xQueueGenericSend的区别:

  • 不可阻塞
  • 需要手动处理调度请求

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2395082.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

破解高原运维难题:分布式光伏智能监控系统的应用研究

安科瑞刘鸿鹏 摘要 高原地区光照资源丰富&#xff0c;具有发展分布式光伏发电的巨大潜力。然而&#xff0c;该地区复杂的气候环境、地形地貌和运维条件对光伏电站的运行与维护带来严峻挑战。本文结合Acrel1000DP分布式光伏监控系统的技术特点和典型应用案例&#xff0c;探讨其…

图标变白,开始菜单栏无法打开程序(以jupyter为例)

不知道是本人删了一些东西导致的还是什么原因&#xff0c;总之现在本人的jupyter只能通过命令行打开&#xff0c;以往我是从开始菜单栏打开。琢磨了一段时间&#xff0c;发现是.ico文件没有了。重新在网上下载图片&#xff0c;用网站图片转 ico 图标 - 锤子在线工具 转换一下格…

大语言模型(LLM)入门 - (1) 相关概念

文章来自&#xff1a;大语言模型(LLM)小白入门自学项目-TiaoYu-1 GitHub - tiaoyu1122/TiaoYu-1: For People! For Freedom!For People! For Freedom! Contribute to tiaoyu1122/TiaoYu-1 development by creating an account on GitHub.https://github.com/tiaoyu1122/TiaoYu…

行为型:访问者模式

目录 1、核心思想 2、实现方式 2.1 模式结构 2.2 实现案例 3、优缺点分析 4、适用场景 1、核心思想 目的&#xff1a;数据结构稳定的情况下&#xff0c;解决数据与算法的耦合问题。适用于对象结构稳定但需频繁扩展操作的场景。 实现&#xff1a;在访问数据时根据数据类…

C++数据结构 : 哈希表的实现

C数据结构 &#xff1a; 哈希表的实现 目录 C数据结构 &#xff1a; 哈希表的实现引言1. 哈希概念1.1 直接定址法1.2 哈希冲突1.3 负载因子 2. 哈希函数2.1 除法散列法/除留余数法2.2 乘法散列法&#xff08;了解&#xff09;2.3 全域散列法&#xff08;了解&#xff09; 3. 处…

AD9268、AD9643调试过程中遇到的问题

Ad9268芯片 AD9268是一款双通道、16位、80 MSPS/105 MSPS/125 MSPS模数转换器(ADC)。AD9268旨在支持要求高性能、低成本、小尺寸和多功能的通信应用。双通道ADC内核采用多级差分流水线架构&#xff0c;集成输出纠错逻辑。每个ADC都具有宽带宽、差分采样保持模拟输入放大器&…

webpack CDN打包优化

CDN网络分发服务 请求资源时最近的服务器将缓存内容交给用户 体积较大且变动不多的文件存在CDN文件中 react react-dom资源 // 添加自定义对于webpack的配置const path require(path) const { whenProd, getPlugin, pluginByName } require(craco/craco)module.exports {//…

ARM内核一览

经常看介绍某某牛批芯片用的又是ARM什么核&#xff0c;看的云里雾里&#xff0c;所以简单整理整理。&#xff08;内容来自官网和GPT&#xff09; 1 ARM 内核总体分类 系列特点应用场景Cortex-M超低功耗、低成本、实时性嵌入式系统、微控制器、IoTCortex-R高可靠性、硬实时汽车…

Rust 和 Python 如何混合使用

Rust 与 Python 可以通过多种方式混合使用&#xff0c;如 FFI 接口、PyO3 库、CFFI、CPython API、wasm 模块嵌入等。这种混合开发模式可结合 Rust 的性能优势与 Python 的开发效率。其中&#xff0c;PyO3 是目前最受欢迎的桥接工具&#xff0c;它允许使用 Rust 编写 Python 扩…

台式电脑CPU天梯图_2025年台式电脑CPU天梯图

CPU的选择绝对是重中之重,它关乎了一台电脑性能好坏。相信不少用户,在挑选CPU的时候不知道谁强谁弱,尤其是intel和AMD两款CPU之间。下面通过2025年台式电脑CPU天梯图来了解下这两款cpu. 2025年台式电脑CPU天梯图 2025年台式电脑CPU天梯图包含了老旧型号以及12代、13代、14代…

2025年渗透测试面试题总结-匿名[校招]安全服务工程师(题目+回答)

安全领域各种资源&#xff0c;学习文档&#xff0c;以及工具分享、前沿信息分享、POC、EXP分享。不定期分享各种好玩的项目及好用的工具&#xff0c;欢迎关注。 目录 匿名[校招]安全服务工程师 一面问题与完整回答 1. 学校、专业、成绩与排名 2. 学习安全时长 3. 当前学习…

Deseq2:MAG相对丰度差异检验

首先使用代码将contigs和MAG联系起来 https://github.com/MrOlm/drep/blob/master/helper_scripts/parse_stb.py ~/parse_stb.py --reverse -f ~/bin_dir/* -o ~/bin_dir/genomes.stb # 查看第一列的contigs有没有重复&#xff08;重复的话会影响后续比对&#xff09; awk {p…

CTFHub-RCE 命令注入-过滤目录分隔符

观察源代码 代码里面可以发现过滤了目录分隔符\和/ 判断是Windows还是Linux 源代码中有 ping -c 4 说明是Linux 查看有哪些文件 127.0.0.1|ls 打开flag文件 发现存在一个flag_is_here的文件夹&#xff0c;我们需要打开这个文件夹找到目标文件我们尝试分步&#xff0c;先利…

CentOS-stream-9 Zabbix的安装与配置

一、Web环境搭建部署Zabbix时&#xff0c;选择合适的MariaDB、PHP和Nginx版本非常重要&#xff0c;以确保兼容性和最佳性能。以下是建议版本&#xff1a;Zabbix 6.4 MariaDB&#xff1a;官方文档推荐使用MariaDB 10.3或更高版本。对于CentOS Stream 9&#xff0c;建议使用Maria…

开源是什么?我们为什么要开源?

本片为故事类文章推荐听音频哦 软件自由运动的背景 梦开始的地方 20世纪70年代&#xff0c;软件行业处于早期发展阶段&#xff0c;软件通常与硬件捆绑销售&#xff0c;用户对软件的使用、修改和分发权利非常有限。随着计算机技术的发展和互联网的普及&#xff0c;越来越多的开…

【unity游戏开发——编辑器扩展】EditorApplication公共类处理编辑器生命周期事件、播放模式控制以及各种编辑器状态查询

注意&#xff1a;考虑到编辑器扩展的内容比较多&#xff0c;我将编辑器扩展的内容分开&#xff0c;并全部整合放在【unity游戏开发——编辑器扩展】专栏里&#xff0c;感兴趣的小伙伴可以前往逐一查看学习。 文章目录 前言一、监听编辑器事件1、常用编辑器事件2、示例监听播放模…

React---day3

React 2.5 jsx的本质 jsx 仅仅只是 React.createElement(component, props, …children) 函数的语法糖。所有的jsx最终都会被转换成React.createElement的函数调用。 createElement需要传递三个参数&#xff1a; 参数一&#xff1a;type 当前ReactElement的类型&#xff1b;…

PyCharm接入DeepSeek,实现高效AI编程

介绍本土AI工具DeepSeek如何结合PyCharm同样实现该功能。 一 DeepSeek API申请 首先进入DeepSeek官网&#xff1a;DeepSeek 官网 接着点击右上角的 “API 开放平台“ 然后点击API keys 创建好的API key&#xff0c;记得复制保存好 二 pycharm 接入deepseek 首先打开PyCh…

CTFSHOW-WEB-36D杯

给你shell 这道题对我这个新手还是有难度的&#xff0c;花了不少时间。首先f12看源码&#xff0c;看到?view_source&#xff0c;点进去看源码 <?php //Its no need to use scanner. Of course if you want, but u will find nothing. error_reporting(0); include "…

RabbitMQ vs MQTT:深入比较与最新发展

RabbitMQ vs MQTT&#xff1a;深入比较与最新发展 引言 在消息队列和物联网&#xff08;IoT&#xff09;通信领域&#xff0c;RabbitMQ 和 MQTT 是两种备受瞩目的技术&#xff0c;各自针对不同的需求和场景提供了强大的解决方案。随着 2025 年的到来&#xff0c;这两项技术都…