blob: 6aa2f78b6d80236f569f82b5004eb15a1c17241a [file] [log] [blame]
brians0ab60bb2013-01-31 02:21:51 +00001/*
2 FreeRTOS V6.0.5 - Copyright (C) 2010 Real Time Engineers Ltd.
3
4 ***************************************************************************
5 * *
6 * If you are: *
7 * *
8 * + New to FreeRTOS, *
9 * + Wanting to learn FreeRTOS or multitasking in general quickly *
10 * + Looking for basic training, *
11 * + Wanting to improve your FreeRTOS skills and productivity *
12 * *
13 * then take a look at the FreeRTOS eBook *
14 * *
15 * "Using the FreeRTOS Real Time Kernel - a Practical Guide" *
16 * http://www.FreeRTOS.org/Documentation *
17 * *
18 * A pdf reference manual is also available. Both are usually delivered *
19 * to your inbox within 20 minutes to two hours when purchased between 8am *
20 * and 8pm GMT (although please allow up to 24 hours in case of *
21 * exceptional circumstances). Thank you for your support! *
22 * *
23 ***************************************************************************
24
25 This file is part of the FreeRTOS distribution.
26
27 FreeRTOS is free software; you can redistribute it and/or modify it under
28 the terms of the GNU General Public License (version 2) as published by the
29 Free Software Foundation AND MODIFIED BY the FreeRTOS exception.
30 ***NOTE*** The exception to the GPL is included to allow you to distribute
31 a combined work that includes FreeRTOS without being obliged to provide the
32 source code for proprietary components outside of the FreeRTOS kernel.
33 FreeRTOS is distributed in the hope that it will be useful, but WITHOUT
34 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
35 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
36 more details. You should have received a copy of the GNU General Public
37 License and the FreeRTOS license exception along with FreeRTOS; if not it
38 can be viewed here: http://www.freertos.org/a00114.html and also obtained
39 by writing to Richard Barry, contact details for whom are available on the
40 FreeRTOS WEB site.
41
42 1 tab == 4 spaces!
43
44 http://www.FreeRTOS.org - Documentation, latest information, license and
45 contact details.
46
47 http://www.SafeRTOS.com - A version that is certified for use in safety
48 critical systems.
49
50 http://www.OpenRTOS.com - Commercial support, development, porting,
51 licensing and training services.
52*/
53
54
55/*
56 * Tests the behaviour when data is peeked from a queue when there are
57 * multiple tasks blocked on the queue.
58 */
59
60
61#include <stdlib.h>
62
63/* Scheduler include files. */
64#include "FreeRTOS.h"
65#include "task.h"
66#include "queue.h"
67#include "semphr.h"
68
69/* Demo program include files. */
70#include "QPeek.h"
71
72#define qpeekQUEUE_LENGTH ( 5 )
73#define qpeekNO_BLOCK ( 0 )
74#define qpeekSHORT_DELAY ( 10 )
75
76#define qpeekLOW_PRIORITY ( tskIDLE_PRIORITY + 0 )
77#define qpeekMEDIUM_PRIORITY ( tskIDLE_PRIORITY + 1 )
78#define qpeekHIGH_PRIORITY ( tskIDLE_PRIORITY + 2 )
79#define qpeekHIGHEST_PRIORITY ( tskIDLE_PRIORITY + 3 )
80
81/*-----------------------------------------------------------*/
82
83/*
84 * The following three tasks are used to demonstrate the peeking behaviour.
85 * Each task is given a different priority to demonstrate the order in which
86 * tasks are woken as data is peeked from a queue.
87 */
88static void prvLowPriorityPeekTask(void *pvParameters);
89static void prvMediumPriorityPeekTask(void *pvParameters);
90static void prvHighPriorityPeekTask(void *pvParameters);
91static void prvHighestPriorityPeekTask(void *pvParameters);
92
93/*-----------------------------------------------------------*/
94
95/* Flag that will be latched to pdTRUE should any unexpected behaviour be
96detected in any of the tasks. */
97static volatile portBASE_TYPE xErrorDetected = pdFALSE;
98
99/* Counter that is incremented on each cycle of a test. This is used to
100detect a stalled task - a test that is no longer running. */
101static volatile unsigned portLONG ulLoopCounter = 0;
102
103/* Handles to the test tasks. */
104xTaskHandle xMediumPriorityTask, xHighPriorityTask, xHighestPriorityTask;
105/*-----------------------------------------------------------*/
106
107void vStartQueuePeekTasks(void)
108{
109 xQueueHandle xQueue;
110
111 /* Create the queue that we are going to use for the test/demo. */
112 xQueue = xQueueCreate(qpeekQUEUE_LENGTH, sizeof(unsigned portLONG));
113
114 /* vQueueAddToRegistry() adds the queue to the queue registry, if one is
115 in use. The queue registry is provided as a means for kernel aware
116 debuggers to locate queues and has no purpose if a kernel aware debugger
117 is not being used. The call to vQueueAddToRegistry() will be removed
118 by the pre-processor if configQUEUE_REGISTRY_SIZE is not defined or is
119 defined to be less than 1. */
120 vQueueAddToRegistry(xQueue, (signed portCHAR *) "QPeek_Test_Queue");
121
122 /* Create the demo tasks and pass it the queue just created. We are
123 passing the queue handle by value so it does not matter that it is declared
124 on the stack here. */
125 xTaskCreate(prvLowPriorityPeekTask, (signed portCHAR *)"PeekL", configMINIMAL_STACK_SIZE, (void *) xQueue, qpeekLOW_PRIORITY, NULL);
126 xTaskCreate(prvMediumPriorityPeekTask, (signed portCHAR *)"PeekM", configMINIMAL_STACK_SIZE, (void *) xQueue, qpeekMEDIUM_PRIORITY, &xMediumPriorityTask);
127 xTaskCreate(prvHighPriorityPeekTask, (signed portCHAR *)"PeekH1", configMINIMAL_STACK_SIZE, (void *) xQueue, qpeekHIGH_PRIORITY, &xHighPriorityTask);
128 xTaskCreate(prvHighestPriorityPeekTask, (signed portCHAR *)"PeekH2", configMINIMAL_STACK_SIZE, (void *) xQueue, qpeekHIGHEST_PRIORITY, &xHighestPriorityTask);
129}
130/*-----------------------------------------------------------*/
131
132static void prvHighestPriorityPeekTask(void *pvParameters)
133{
134 xQueueHandle xQueue = (xQueueHandle) pvParameters;
135 unsigned portLONG ulValue;
136
137#ifdef USE_STDIO
138 {
139 void vPrintDisplayMessage(const portCHAR * const * ppcMessageToSend);
140
141 const portCHAR * const pcTaskStartMsg = "Queue peek test started.\r\n";
142
143 /* Queue a message for printing to say the task has started. */
144 vPrintDisplayMessage(&pcTaskStartMsg);
145 }
146#endif
147
148 for (;;) {
149 /* Try peeking from the queue. The queue should be empty so we will
150 block, allowing the high priority task to execute. */
151 if (xQueuePeek(xQueue, &ulValue, portMAX_DELAY) != pdPASS) {
152 /* We expected to have received something by the time we unblock. */
153 xErrorDetected = pdTRUE;
154 }
155
156 /* When we reach here the high and medium priority tasks should still
157 be blocked on the queue. We unblocked because the low priority task
158 wrote a value to the queue, which we should have peeked. Peeking the
159 data (rather than receiving it) will leave the data on the queue, so
160 the high priority task should then have also been unblocked, but not
161 yet executed. */
162 if (ulValue != 0x11223344) {
163 /* We did not receive the expected value. */
164 xErrorDetected = pdTRUE;
165 }
166
167 if (uxQueueMessagesWaiting(xQueue) != 1) {
168 /* The message should have been left on the queue. */
169 xErrorDetected = pdTRUE;
170 }
171
172 /* Now we are going to actually receive the data, so when the high
173 priority task runs it will find the queue empty and return to the
174 blocked state. */
175 ulValue = 0;
176 if (xQueueReceive(xQueue, &ulValue, qpeekNO_BLOCK) != pdPASS) {
177 /* We expected to receive the value. */
178 xErrorDetected = pdTRUE;
179 }
180
181 if (ulValue != 0x11223344) {
182 /* We did not receive the expected value - which should have been
183 the same value as was peeked. */
184 xErrorDetected = pdTRUE;
185 }
186
187 /* Now we will block again as the queue is once more empty. The low
188 priority task can then execute again. */
189 if (xQueuePeek(xQueue, &ulValue, portMAX_DELAY) != pdPASS) {
190 /* We expected to have received something by the time we unblock. */
191 xErrorDetected = pdTRUE;
192 }
193
194 /* When we get here the low priority task should have again written to the
195 queue. */
196 if (ulValue != 0x01234567) {
197 /* We did not receive the expected value. */
198 xErrorDetected = pdTRUE;
199 }
200
201 if (uxQueueMessagesWaiting(xQueue) != 1) {
202 /* The message should have been left on the queue. */
203 xErrorDetected = pdTRUE;
204 }
205
206 /* We only peeked the data, so suspending ourselves now should enable
207 the high priority task to also peek the data. The high priority task
208 will have been unblocked when we peeked the data as we left the data
209 in the queue. */
210 vTaskSuspend(NULL);
211
212
213
214 /* This time we are going to do the same as the above test, but the
215 high priority task is going to receive the data, rather than peek it.
216 This means that the medium priority task should never peek the value. */
217 if (xQueuePeek(xQueue, &ulValue, portMAX_DELAY) != pdPASS) {
218 xErrorDetected = pdTRUE;
219 }
220
221 if (ulValue != 0xaabbaabb) {
222 xErrorDetected = pdTRUE;
223 }
224
225 vTaskSuspend(NULL);
226 }
227}
228/*-----------------------------------------------------------*/
229
230static void prvHighPriorityPeekTask(void *pvParameters)
231{
232 xQueueHandle xQueue = (xQueueHandle) pvParameters;
233 unsigned portLONG ulValue;
234
235 for (;;) {
236 /* Try peeking from the queue. The queue should be empty so we will
237 block, allowing the medium priority task to execute. Both the high
238 and highest priority tasks will then be blocked on the queue. */
239 if (xQueuePeek(xQueue, &ulValue, portMAX_DELAY) != pdPASS) {
240 /* We expected to have received something by the time we unblock. */
241 xErrorDetected = pdTRUE;
242 }
243
244 /* When we get here the highest priority task should have peeked the data
245 (unblocking this task) then suspended (allowing this task to also peek
246 the data). */
247 if (ulValue != 0x01234567) {
248 /* We did not receive the expected value. */
249 xErrorDetected = pdTRUE;
250 }
251
252 if (uxQueueMessagesWaiting(xQueue) != 1) {
253 /* The message should have been left on the queue. */
254 xErrorDetected = pdTRUE;
255 }
256
257 /* We only peeked the data, so suspending ourselves now should enable
258 the medium priority task to also peek the data. The medium priority task
259 will have been unblocked when we peeked the data as we left the data
260 in the queue. */
261 vTaskSuspend(NULL);
262
263
264 /* This time we are going actually receive the value, so the medium
265 priority task will never peek the data - we removed it from the queue. */
266 if (xQueueReceive(xQueue, &ulValue, portMAX_DELAY) != pdPASS) {
267 xErrorDetected = pdTRUE;
268 }
269
270 if (ulValue != 0xaabbaabb) {
271 xErrorDetected = pdTRUE;
272 }
273
274 vTaskSuspend(NULL);
275 }
276}
277/*-----------------------------------------------------------*/
278
279static void prvMediumPriorityPeekTask(void *pvParameters)
280{
281 xQueueHandle xQueue = (xQueueHandle) pvParameters;
282 unsigned portLONG ulValue;
283
284 for (;;) {
285 /* Try peeking from the queue. The queue should be empty so we will
286 block, allowing the low priority task to execute. The highest, high
287 and medium priority tasks will then all be blocked on the queue. */
288 if (xQueuePeek(xQueue, &ulValue, portMAX_DELAY) != pdPASS) {
289 /* We expected to have received something by the time we unblock. */
290 xErrorDetected = pdTRUE;
291 }
292
293 /* When we get here the high priority task should have peeked the data
294 (unblocking this task) then suspended (allowing this task to also peek
295 the data). */
296 if (ulValue != 0x01234567) {
297 /* We did not receive the expected value. */
298 xErrorDetected = pdTRUE;
299 }
300
301 if (uxQueueMessagesWaiting(xQueue) != 1) {
302 /* The message should have been left on the queue. */
303 xErrorDetected = pdTRUE;
304 }
305
306 /* Just so we know the test is still running. */
307 ulLoopCounter++;
308
309 /* Now we can suspend ourselves so the low priority task can execute
310 again. */
311 vTaskSuspend(NULL);
312 }
313}
314/*-----------------------------------------------------------*/
315
316static void prvLowPriorityPeekTask(void *pvParameters)
317{
318 xQueueHandle xQueue = (xQueueHandle) pvParameters;
319 unsigned portLONG ulValue;
320
321 for (;;) {
322 /* Write some data to the queue. This should unblock the highest
323 priority task that is waiting to peek data from the queue. */
324 ulValue = 0x11223344;
325 if (xQueueSendToBack(xQueue, &ulValue, qpeekNO_BLOCK) != pdPASS) {
326 /* We were expecting the queue to be empty so we should not of
327 had a problem writing to the queue. */
328 xErrorDetected = pdTRUE;
329 }
330
331 /* By the time we get here the data should have been removed from
332 the queue. */
333 if (uxQueueMessagesWaiting(xQueue) != 0) {
334 xErrorDetected = pdTRUE;
335 }
336
337 /* Write another value to the queue, again waking the highest priority
338 task that is blocked on the queue. */
339 ulValue = 0x01234567;
340 if (xQueueSendToBack(xQueue, &ulValue, qpeekNO_BLOCK) != pdPASS) {
341 /* We were expecting the queue to be empty so we should not of
342 had a problem writing to the queue. */
343 xErrorDetected = pdTRUE;
344 }
345
346 /* All the other tasks should now have successfully peeked the data.
347 The data is still in the queue so we should be able to receive it. */
348 ulValue = 0;
349 if (xQueueReceive(xQueue, &ulValue, qpeekNO_BLOCK) != pdPASS) {
350 /* We expected to receive the data. */
351 xErrorDetected = pdTRUE;
352 }
353
354 if (ulValue != 0x01234567) {
355 /* We did not receive the expected value. */
356 }
357
358 /* Lets just delay a while as this is an intensive test as we don't
359 want to starve other tests of processing time. */
360 vTaskDelay(qpeekSHORT_DELAY);
361
362 /* Unsuspend the other tasks so we can repeat the test - this time
363 however not all the other tasks will peek the data as the high
364 priority task is actually going to remove it from the queue. Send
365 to front is used just to be different. As the queue is empty it
366 makes no difference to the result. */
367 vTaskResume(xMediumPriorityTask);
368 vTaskResume(xHighPriorityTask);
369 vTaskResume(xHighestPriorityTask);
370
371 ulValue = 0xaabbaabb;
372 if (xQueueSendToFront(xQueue, &ulValue, qpeekNO_BLOCK) != pdPASS) {
373 /* We were expecting the queue to be empty so we should not of
374 had a problem writing to the queue. */
375 xErrorDetected = pdTRUE;
376 }
377
378 /* This time we should find that the queue is empty. The high priority
379 task actually removed the data rather than just peeking it. */
380 if (xQueuePeek(xQueue, &ulValue, qpeekNO_BLOCK) != errQUEUE_EMPTY) {
381 /* We expected to receive the data. */
382 xErrorDetected = pdTRUE;
383 }
384
385 /* Unsuspend the highest and high priority tasks so we can go back
386 and repeat the whole thing. The medium priority task should not be
387 suspended as it was not able to peek the data in this last case. */
388 vTaskResume(xHighPriorityTask);
389 vTaskResume(xHighestPriorityTask);
390
391 /* Lets just delay a while as this is an intensive test as we don't
392 want to starve other tests of processing time. */
393 vTaskDelay(qpeekSHORT_DELAY);
394 }
395}
396/*-----------------------------------------------------------*/
397
398/* This is called to check that all the created tasks are still running. */
399portBASE_TYPE xAreQueuePeekTasksStillRunning(void)
400{
401 static unsigned portLONG ulLastLoopCounter = 0;
402
403 /* If the demo task is still running then we expect the loopcounter to
404 have incremented since this function was last called. */
405 if (ulLastLoopCounter == ulLoopCounter) {
406 xErrorDetected = pdTRUE;
407 }
408
409 ulLastLoopCounter = ulLoopCounter;
410
411 /* Errors detected in the task itself will have latched xErrorDetected
412 to true. */
413
414 return !xErrorDetected;
415}
416