出队操作类似于入队的操作。先整明白入队的操作,这个就好说了。
分析:
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是指获取信号量。
留白