freeRTOS 队列4 读取消息

出队操作类似于入队的操作。先整明白入队的操作,这个就好说了。

分析:
1. QueueRecv和QueuePeek都是xQueueGenericReceive实现的 2. xQueueReceiveFromISR 3. xQueuePeekFromISR

函数在读取消息的时候是采用拷贝方式的,所以用户需要提供一个数组或缓冲区来保存读取到的数据,

所读取的数据长度是创建队列的时候所设定的每个队列项目的长度

BaseType_t xQueueReceive( QueueHandle_t xQueue,  void * pvBuffer,  TickType_t xTicksToWait );

BaseType_t xQueuePeek     ( QueueHandle_t xQueue,  void * pvBuffer,  TickType_t xTicksToWait );

他们都用函数 

xQueueGenericReceive( ) 来实现。

BaseType_t xQueueReceiveFromISR( QueueHandle_t xQueue,  void * pvBuffer,  BaseType_t * pxTaskWoken );

BaseType_t xQueuePeekFromISR     ( QueueHandle_t xQueue,  void * pvBuffer );

他们是各自实现的。。。

下面先分析xQueueGenericReceive() :

  1 BaseType_t xQueueGenericReceive( QueueHandle_t xQueue, void * const pvBuffer, TickType_t xTicksToWait, const BaseType_t xJustPeeking )
  2 {
  3 BaseType_t xEntryTimeSet = pdFALSE;
  4 TimeOut_t xTimeOut;
  5 int8_t *pcOriginalReadPosition;
  6 Queue_t * const pxQueue = ( Queue_t * ) xQueue;
  7 
  8     configASSERT( pxQueue );
  9     configASSERT( !( ( pvBuffer == NULL ) && ( pxQueue->uxItemSize != ( UBaseType_t ) 0U ) ) );
 10     #if ( ( INCLUDE_xTaskGetSchedulerState == 1 ) || ( configUSE_TIMERS == 1 ) )
 11     {
 12         configASSERT( !( ( xTaskGetSchedulerState() == taskSCHEDULER_SUSPENDED ) && ( xTicksToWait != 0 ) ) );
 13     }
 14     #endif
 15 
 16     /* This function relaxes the coding standard somewhat to allow return
 17     statements within the function itself.  This is done in the interest
 18     of execution time efficiency. 为了效率,直接在函数内返回*/
 20     for( ;; )
 21     {
 22         taskENTER_CRITICAL();
 23         {
 24             const UBaseType_t uxMessagesWaiting = pxQueue->uxMessagesWaiting;  //队列中item个数
 25 
 26             /* Is there data in the queue now?  To be running the calling task
 27             must be the highest priority task wanting to access the queue. */
 28             if( uxMessagesWaiting > ( UBaseType_t ) 0 )  //队列中有item
 29             {
 30                 /* Remember the read position in case the queue is only being
 31                 peeked. */
 32                 pcOriginalReadPosition = pxQueue->u.pcReadFrom;  //记录队列的读指针
 33 
 34                 prvCopyDataFromQueue( pxQueue, pvBuffer );       //<-- 从队列拷贝出数据   ##3 见后
 35 
 36                 if( xJustPeeking == pdFALSE )  【不是peek的方法】
 37                 {
 38                     traceQUEUE_RECEIVE( pxQueue );
 39 
 40                     /* Actually removing data, not just peeking. */
 41                     pxQueue->uxMessagesWaiting = uxMessagesWaiting - 1;  //<-- 队列中item个数 减一
 42 
 43                     #if ( configUSE_MUTEXES == 1 )  //不关注是否是mutex 
56 #endif /* configUSE_MUTEXES */
//有任务在等待发送消息,此时队列有空间了,可以发送 58 if( listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToSend ) ) == pdFALSE ) 59 { 60 if( xTaskRemoveFromEventList( &( pxQueue->xTasksWaitingToSend ) ) != pdFALSE ) 61 { 62 queueYIELD_IF_USING_PREEMPTION(); //置位PendSV 63 } 64 else 65 { 66 mtCOVERAGE_TEST_MARKER(); 67 } 68 } 69 else 70 { 71 mtCOVERAGE_TEST_MARKER(); 72 } 73 } 74 else 【peek】 75 { 76 traceQUEUE_PEEK( pxQueue ); 77 78 /* The data is not being removed, so reset the read 79 pointer. */ 80 pxQueue->u.pcReadFrom = pcOriginalReadPosition; 81 82 /* The data is being left in the queue, so see if there are 83 any other tasks waiting for the data.
peek之后的消息仍在队列中,所以看一下是否有任务在等待接收消息*/ 84 if( listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToReceive ) ) == pdFALSE ) 85 { 86 if( xTaskRemoveFromEventList( &( pxQueue->xTasksWaitingToReceive ) ) != pdFALSE ) 87 { 88 /* The task waiting has a higher priority than this task. */ 89 queueYIELD_IF_USING_PREEMPTION(); //置位PendSV 90 } 91 else 92 { 93 mtCOVERAGE_TEST_MARKER(); 94 } 95 } 96 else 97 { 98 mtCOVERAGE_TEST_MARKER(); 99 } 100 }/* end of peek? */ 101 102 taskEXIT_CRITICAL(); 103 return pdPASS; 104 } 105 else 【queue has no data】 106 { 107 if( xTicksToWait == ( TickType_t ) 0 ) 108 { 109 /* The queue was empty and no block time is specified (or 110 the block time has expired) so leave now. */ 111 taskEXIT_CRITICAL(); 112 traceQUEUE_RECEIVE_FAILED( pxQueue ); 113 return errQUEUE_EMPTY; //直接返回err 114 } 115 else if( xEntryTimeSet == pdFALSE ) 116 { 117 /* The queue was empty and a block time was specified so 118 configure the timeout structure. */ 119 vTaskSetTimeOutState( &xTimeOut ); //初始化时间结构体 120 xEntryTimeSet = pdTRUE; 121 } 122 else 123 { 124 /* Entry time was already set. */ 125 mtCOVERAGE_TEST_MARKER(); 126 } 127 } 128 } 129 taskEXIT_CRITICAL(); 130 131 /* Interrupts and other tasks can send to and receive from the queue 132 now the critical section has been exited. */ 133 134 vTaskSuspendAll(); //调度锁 135 prvLockQueue( pxQueue ); //队列锁 136 137 /* Update the timeout state to see if it has expired yet. */ 138 if( xTaskCheckForTimeOut( &xTimeOut, &xTicksToWait ) == pdFALSE ) 【阻塞时间没到】 139 { 140 if( prvIsQueueEmpty( pxQueue ) != pdFALSE ) 【队列是空的】 141 { 142 traceBLOCKING_ON_QUEUE_RECEIVE( pxQueue ); 143 144 #if ( configUSE_MUTEXES == 1 )
159 #endif

/* 将任务添加到队列的 xTasksWaitingToRCV 列表中 和 延时列表中,
并且将任务从就绪列表中移除。##0 见后
*/
161                 vTaskPlaceOnEventList( &( pxQueue->xTasksWaitingToReceive ), xTicksToWait );
162                 prvUnlockQueue( pxQueue );
163                 if( xTaskResumeAll() == pdFALSE )
164                 {
165                     portYIELD_WITHIN_API();  
166                 }
167                 else
168                 {
169                     mtCOVERAGE_TEST_MARKER();
170                 }
171             }
172             else 【队列不是空的】
173             {
174                 /* Try again. 从for(;;)那里重新来一遍*/
175                 prvUnlockQueue( pxQueue );
176                 ( void ) xTaskResumeAll();
177             }
178         }
179         else  【 timeout 】
180         {
181             prvUnlockQueue( pxQueue );  //队列解锁
182             ( void ) xTaskResumeAll();  //恢复任务调度
183 
184             if( prvIsQueueEmpty( pxQueue ) != pdFALSE )  //队列仍是空的
185             {
186                 traceQUEUE_RECEIVE_FAILED( pxQueue );
187                 return errQUEUE_EMPTY;  //返回错误
188             }
189             else
190             {
191                 mtCOVERAGE_TEST_MARKER();
192             }
193         }
194     }
195 }
196 /*-----------------------------------------------------------*/

下面先分析xQueueGenericReceiveFromISR() :

 1 BaseType_t xQueueReceiveFromISR( QueueHandle_t xQueue, void * const pvBuffer, BaseType_t * const pxHigherPriorityTaskWoken )
 2 {
 3 BaseType_t xReturn;
 4 UBaseType_t uxSavedInterruptStatus;
 5 Queue_t * const pxQueue = ( Queue_t * ) xQueue;
 6 
 7     configASSERT( pxQueue );
 8     configASSERT( !( ( pvBuffer == NULL ) && ( pxQueue->uxItemSize != ( UBaseType_t ) 0U ) ) );
 9 
10     /* RTOS ports that support interrupt nesting have the concept of a maximum
11     system call (or maximum API call) interrupt priority.  Interrupts that are
12     above the maximum system call priority are kept permanently enabled, even
13     when the RTOS kernel is in a critical section, but cannot make any calls to
14     FreeRTOS API functions.  If configASSERT() is defined in FreeRTOSConfig.h
15     then portASSERT_IF_INTERRUPT_PRIORITY_INVALID() will result in an assertion
16     failure if a FreeRTOS API function is called from an interrupt that has been
17     assigned a priority above the configured maximum system call priority.
18     Only FreeRTOS functions that end in FromISR can be called from interrupts
19     that have been assigned a priority at or (logically) below the maximum
20     system call    interrupt priority.  FreeRTOS maintains a separate interrupt
21     safe API to ensure interrupt entry is as fast and as simple as possible.
22     More information (albeit Cortex-M specific) is provided on the following
23     link: http://www.freertos.org/RTOS-Cortex-M3-M4.html */
24     portASSERT_IF_INTERRUPT_PRIORITY_INVALID();
25 
26     uxSavedInterruptStatus = portSET_INTERRUPT_MASK_FROM_ISR();  记录BasePRI值,并屏蔽所有系统可管理的中断
27     {
28         const UBaseType_t uxMessagesWaiting = pxQueue->uxMessagesWaiting;  //队列中item的数量
29 
30         /* Cannot block in an ISR, so check there is data available. */
31         if( uxMessagesWaiting > ( UBaseType_t ) 0 )
32         {
33             const int8_t cRxLock = pxQueue->cRxLock;
34 
35             traceQUEUE_RECEIVE_FROM_ISR( pxQueue );
36 
37             prvCopyDataFromQueue( pxQueue, pvBuffer );           //取item
38             pxQueue->uxMessagesWaiting = uxMessagesWaiting - 1;
39 
40             /* If the queue is locked the event list will not be modified.
41             Instead update the lock count so the task that unlocks the queue
42             will know that an ISR has removed data while the queue was
43             locked. */
44             if( cRxLock == queueUNLOCKED )  【队列没加锁】
45             {
            //这里看一下
// 如果(之前队列满了 && 有任务在等待发送到这个队列的话) -> 则切换任务 46 if( listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToSend ) ) == pdFALSE )
47 { 48 if( xTaskRemoveFromEventList( &( pxQueue->xTasksWaitingToSend ) ) != pdFALSE ) ##1 见后 49 { 50 /* The task waiting has a higher priority than us so 51 force a context switch. */ 52 if( pxHigherPriorityTaskWoken != NULL ) 53 { 54 *pxHigherPriorityTaskWoken = pdTRUE; //置位任务切换标志 55 } 56 else 57 { 58 mtCOVERAGE_TEST_MARKER(); 59 } 60 } 61 else 62 { 63 mtCOVERAGE_TEST_MARKER(); 64 } 65 } 66 else 67 { 68 mtCOVERAGE_TEST_MARKER(); 69 } 70 } 71 else 【队列加锁时,RxLock计数值加一】 ##2 72 { 73 /* Increment the lock count so the task that unlocks the queue 74 knows that data was removed while it was locked. */ 75 pxQueue->cRxLock = ( int8_t ) ( cRxLock + 1 ); 76 } 77 78 xReturn = pdPASS; 79 } 80 else 【队列中没有item】 81 { 82 xReturn = pdFAIL; 83 traceQUEUE_RECEIVE_FROM_ISR_FAILED( pxQueue ); 84 } 85 } 86 portCLEAR_INTERRUPT_MASK_FROM_ISR( uxSavedInterruptStatus ); 87 88 return xReturn; 89 } 90 /*-----------------------------------------------------------*/
 1 BaseType_t xQueuePeekFromISR( QueueHandle_t xQueue,  void * const pvBuffer )
 2 {
 3 BaseType_t xReturn;
 4 UBaseType_t uxSavedInterruptStatus;
 5 int8_t *pcOriginalReadPosition;
 6 Queue_t * const pxQueue = ( Queue_t * ) xQueue;
 7 
 8     configASSERT( pxQueue );
 9     configASSERT( !( ( pvBuffer == NULL ) && ( pxQueue->uxItemSize != ( UBaseType_t ) 0U ) ) );
10     configASSERT( pxQueue->uxItemSize != 0 ); /* Can't peek a semaphore. */
11 
12     /* RTOS ports that support interrupt nesting have the concept of a maximum
13     system call (or maximum API call) interrupt priority.  Interrupts that are
14     above the maximum system call priority are kept permanently enabled, even
15     when the RTOS kernel is in a critical section, but cannot make any calls to
16     FreeRTOS API functions.  If configASSERT() is defined in FreeRTOSConfig.h
17     then portASSERT_IF_INTERRUPT_PRIORITY_INVALID() will result in an assertion
18     failure if a FreeRTOS API function is called from an interrupt that has been
19     assigned a priority above the configured maximum system call priority.
20     Only FreeRTOS functions that end in FromISR can be called from interrupts
21     that have been assigned a priority at or (logically) below the maximum
22     system call    interrupt priority.  FreeRTOS maintains a separate interrupt
23     safe API to ensure interrupt entry is as fast and as simple as possible.
24     More information (albeit Cortex-M specific) is provided on the following
25     link: http://www.freertos.org/RTOS-Cortex-M3-M4.html */
26     portASSERT_IF_INTERRUPT_PRIORITY_INVALID();
27 
28     uxSavedInterruptStatus = portSET_INTERRUPT_MASK_FROM_ISR();
29     {
30         /* Cannot block in an ISR, so check there is data available. */
31         if( pxQueue->uxMessagesWaiting > ( UBaseType_t ) 0 )
32         {
33             traceQUEUE_PEEK_FROM_ISR( pxQueue );
34 
35             /* Remember the read position so it can be reset as nothing is
36             actually being removed from the queue. */
37             pcOriginalReadPosition = pxQueue->u.pcReadFrom;  //记录读指针位置
38             prvCopyDataFromQueue( pxQueue, pvBuffer );       //读取一个item
39             pxQueue->u.pcReadFrom = pcOriginalReadPosition;  //恢复读指针位置
40 
41             xReturn = pdPASS;
42         }
43         else
44         {
45             xReturn = pdFAIL;
46             traceQUEUE_PEEK_FROM_ISR_FAILED( pxQueue );
47         }
48     }
49     portCLEAR_INTERRUPT_MASK_FROM_ISR( uxSavedInterruptStatus );
50 
51     return xReturn;
52 }
53 /*-----------------------------------------------------------*/

##0 注意函数PlaceOnEventList  双加,加入到EventList 和 DelayList。

void vTaskPlaceOnEventList( List_t * const pxEventList, const TickType_t xTicksToWait )
{
    configASSERT( pxEventList );

    /* THIS FUNCTION MUST BE CALLED WITH EITHER INTERRUPTS DISABLED OR THE
    SCHEDULER SUSPENDED AND THE QUEUE BEING ACCESSED LOCKED. */

    /* Place the event list item of the TCB in the appropriate event list.
    This is placed in the list in priority order so the highest priority task
    is the first to be woken by the event.  The queue that contains the event
    list is locked, preventing simultaneous access from interrupts. */
    vListInsert( pxEventList, &( pxCurrentTCB->xEventListItem ) );

    prvAddCurrentTaskToDelayedList( xTicksToWait, pdTRUE );  见时间管理
}
与这个函数操作相反的是, xTaskRemoveFromEventList

##1 xTaskRemoveFromEventList 见队列创建初始化章节。

##2 队列加锁,不能进行入队出队操作。只进行RxLock计数值加一。

           在队列解锁时:判断任务调度与否 、 RxLock减一。

##3 prvCopyDataFromQueue 见信号量章节。

和CopyDataToQueue类似,CopyToQ是指释放信号量。

CopyFromQ是指获取信号量。

留白

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值