brians | 0ab60bb | 2013-01-31 02:21:51 +0000 | [diff] [blame^] | 1 | /* |
| 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 extra queue functionality introduced in FreeRTOS.org V4.5.0 - |
| 57 | * including xQueueSendToFront(), xQueueSendToBack(), xQueuePeek() and |
| 58 | * mutex behaviour. |
| 59 | * |
| 60 | * See the comments above the prvSendFrontAndBackTest() and |
| 61 | * prvLowPriorityMutexTask() prototypes below for more information. |
| 62 | */ |
| 63 | |
| 64 | |
| 65 | #include <stdlib.h> |
| 66 | |
| 67 | /* Scheduler include files. */ |
| 68 | #include "FreeRTOS.h" |
| 69 | #include "task.h" |
| 70 | #include "queue.h" |
| 71 | #include "semphr.h" |
| 72 | |
| 73 | /* Demo program include files. */ |
| 74 | #include "GenQTest.h" |
| 75 | |
| 76 | #define genqQUEUE_LENGTH ( 5 ) |
| 77 | #define genqNO_BLOCK ( 0 ) |
| 78 | |
| 79 | #define genqMUTEX_LOW_PRIORITY ( tskIDLE_PRIORITY ) |
| 80 | #define genqMUTEX_TEST_PRIORITY ( tskIDLE_PRIORITY + 1 ) |
| 81 | #define genqMUTEX_MEDIUM_PRIORITY ( tskIDLE_PRIORITY + 2 ) |
| 82 | #define genqMUTEX_HIGH_PRIORITY ( tskIDLE_PRIORITY + 3 ) |
| 83 | |
| 84 | /*-----------------------------------------------------------*/ |
| 85 | |
| 86 | /* |
| 87 | * Tests the behaviour of the xQueueSendToFront() and xQueueSendToBack() |
| 88 | * macros by using both to fill a queue, then reading from the queue to |
| 89 | * check the resultant queue order is as expected. Queue data is also |
| 90 | * peeked. |
| 91 | */ |
| 92 | static void prvSendFrontAndBackTest(void *pvParameters); |
| 93 | |
| 94 | /* |
| 95 | * The following three tasks are used to demonstrate the mutex behaviour. |
| 96 | * Each task is given a different priority to demonstrate the priority |
| 97 | * inheritance mechanism. |
| 98 | * |
| 99 | * The low priority task obtains a mutex. After this a high priority task |
| 100 | * attempts to obtain the same mutex, causing its priority to be inherited |
| 101 | * by the low priority task. The task with the inherited high priority then |
| 102 | * resumes a medium priority task to ensure it is not blocked by the medium |
| 103 | * priority task while it holds the inherited high priority. Once the mutex |
| 104 | * is returned the task with the inherited priority returns to its original |
| 105 | * low priority, and is therefore immediately preempted by first the high |
| 106 | * priority task and then the medium prioroity task before it can continue. |
| 107 | */ |
| 108 | static void prvLowPriorityMutexTask(void *pvParameters); |
| 109 | static void prvMediumPriorityMutexTask(void *pvParameters); |
| 110 | static void prvHighPriorityMutexTask(void *pvParameters); |
| 111 | |
| 112 | /*-----------------------------------------------------------*/ |
| 113 | |
| 114 | /* Flag that will be latched to pdTRUE should any unexpected behaviour be |
| 115 | detected in any of the tasks. */ |
| 116 | static portBASE_TYPE xErrorDetected = pdFALSE; |
| 117 | |
| 118 | /* Counters that are incremented on each cycle of a test. This is used to |
| 119 | detect a stalled task - a test that is no longer running. */ |
| 120 | static volatile unsigned portLONG ulLoopCounter = 0; |
| 121 | static volatile unsigned portLONG ulLoopCounter2 = 0; |
| 122 | |
| 123 | /* The variable that is guarded by the mutex in the mutex demo tasks. */ |
| 124 | static volatile unsigned portLONG ulGuardedVariable = 0; |
| 125 | |
| 126 | /* Handles used in the mutext test to suspend and resume the high and medium |
| 127 | priority mutex test tasks. */ |
| 128 | static xTaskHandle xHighPriorityMutexTask, xMediumPriorityMutexTask; |
| 129 | |
| 130 | /*-----------------------------------------------------------*/ |
| 131 | |
| 132 | void vStartGenericQueueTasks(unsigned portBASE_TYPE uxPriority) |
| 133 | { |
| 134 | xQueueHandle xQueue; |
| 135 | xSemaphoreHandle xMutex; |
| 136 | |
| 137 | /* Create the queue that we are going to use for the |
| 138 | prvSendFrontAndBackTest demo. */ |
| 139 | xQueue = xQueueCreate(genqQUEUE_LENGTH, sizeof(unsigned portLONG)); |
| 140 | |
| 141 | /* vQueueAddToRegistry() adds the queue to the queue registry, if one is |
| 142 | in use. The queue registry is provided as a means for kernel aware |
| 143 | debuggers to locate queues and has no purpose if a kernel aware debugger |
| 144 | is not being used. The call to vQueueAddToRegistry() will be removed |
| 145 | by the pre-processor if configQUEUE_REGISTRY_SIZE is not defined or is |
| 146 | defined to be less than 1. */ |
| 147 | vQueueAddToRegistry(xQueue, (signed portCHAR *) "Gen_Queue_Test"); |
| 148 | |
| 149 | /* Create the demo task and pass it the queue just created. We are |
| 150 | passing the queue handle by value so it does not matter that it is |
| 151 | declared on the stack here. */ |
| 152 | xTaskCreate(prvSendFrontAndBackTest, (signed portCHAR *)"GenQ", configMINIMAL_STACK_SIZE, (void *) xQueue, uxPriority, NULL); |
| 153 | |
| 154 | /* Create the mutex used by the prvMutexTest task. */ |
| 155 | xMutex = xSemaphoreCreateMutex(); |
| 156 | |
| 157 | /* vQueueAddToRegistry() adds the mutex to the registry, if one is |
| 158 | in use. The registry is provided as a means for kernel aware |
| 159 | debuggers to locate mutexes and has no purpose if a kernel aware debugger |
| 160 | is not being used. The call to vQueueAddToRegistry() will be removed |
| 161 | by the pre-processor if configQUEUE_REGISTRY_SIZE is not defined or is |
| 162 | defined to be less than 1. */ |
| 163 | vQueueAddToRegistry((xQueueHandle) xMutex, (signed portCHAR *) "Gen_Queue_Mutex"); |
| 164 | |
| 165 | /* Create the mutex demo tasks and pass it the mutex just created. We are |
| 166 | passing the mutex handle by value so it does not matter that it is declared |
| 167 | on the stack here. */ |
| 168 | xTaskCreate(prvLowPriorityMutexTask, (signed portCHAR *)"MuLow", configMINIMAL_STACK_SIZE, (void *) xMutex, genqMUTEX_LOW_PRIORITY, NULL); |
| 169 | xTaskCreate(prvMediumPriorityMutexTask, (signed portCHAR *)"MuMed", configMINIMAL_STACK_SIZE, NULL, genqMUTEX_MEDIUM_PRIORITY, &xMediumPriorityMutexTask); |
| 170 | xTaskCreate(prvHighPriorityMutexTask, (signed portCHAR *)"MuHigh", configMINIMAL_STACK_SIZE, (void *) xMutex, genqMUTEX_HIGH_PRIORITY, &xHighPriorityMutexTask); |
| 171 | } |
| 172 | /*-----------------------------------------------------------*/ |
| 173 | |
| 174 | static void prvSendFrontAndBackTest(void *pvParameters) |
| 175 | { |
| 176 | unsigned portLONG ulData, ulData2; |
| 177 | xQueueHandle xQueue; |
| 178 | |
| 179 | #ifdef USE_STDIO |
| 180 | void vPrintDisplayMessage(const portCHAR * const * ppcMessageToSend); |
| 181 | |
| 182 | const portCHAR * const pcTaskStartMsg = "Queue SendToFront/SendToBack/Peek test started.\r\n"; |
| 183 | |
| 184 | /* Queue a message for printing to say the task has started. */ |
| 185 | vPrintDisplayMessage(&pcTaskStartMsg); |
| 186 | #endif |
| 187 | |
| 188 | xQueue = (xQueueHandle) pvParameters; |
| 189 | |
| 190 | for (;;) { |
| 191 | /* The queue is empty, so sending an item to the back of the queue |
| 192 | should have the same efect as sending it to the front of the queue. |
| 193 | |
| 194 | First send to the front and check everything is as expected. */ |
| 195 | xQueueSendToFront(xQueue, (void *) &ulLoopCounter, genqNO_BLOCK); |
| 196 | |
| 197 | if (uxQueueMessagesWaiting(xQueue) != 1) { |
| 198 | xErrorDetected = pdTRUE; |
| 199 | } |
| 200 | |
| 201 | if (xQueueReceive(xQueue, (void *) &ulData, genqNO_BLOCK) != pdPASS) { |
| 202 | xErrorDetected = pdTRUE; |
| 203 | } |
| 204 | |
| 205 | /* The data we sent to the queue should equal the data we just received |
| 206 | from the queue. */ |
| 207 | if (ulLoopCounter != ulData) { |
| 208 | xErrorDetected = pdTRUE; |
| 209 | } |
| 210 | |
| 211 | /* Then do the same, sending the data to the back, checking everything |
| 212 | is as expected. */ |
| 213 | if (uxQueueMessagesWaiting(xQueue) != 0) { |
| 214 | xErrorDetected = pdTRUE; |
| 215 | } |
| 216 | |
| 217 | xQueueSendToBack(xQueue, (void *) &ulLoopCounter, genqNO_BLOCK); |
| 218 | |
| 219 | if (uxQueueMessagesWaiting(xQueue) != 1) { |
| 220 | xErrorDetected = pdTRUE; |
| 221 | } |
| 222 | |
| 223 | if (xQueueReceive(xQueue, (void *) &ulData, genqNO_BLOCK) != pdPASS) { |
| 224 | xErrorDetected = pdTRUE; |
| 225 | } |
| 226 | |
| 227 | if (uxQueueMessagesWaiting(xQueue) != 0) { |
| 228 | xErrorDetected = pdTRUE; |
| 229 | } |
| 230 | |
| 231 | /* The data we sent to the queue should equal the data we just received |
| 232 | from the queue. */ |
| 233 | if (ulLoopCounter != ulData) { |
| 234 | xErrorDetected = pdTRUE; |
| 235 | } |
| 236 | |
| 237 | #if configUSE_PREEMPTION == 0 |
| 238 | taskYIELD(); |
| 239 | #endif |
| 240 | |
| 241 | |
| 242 | |
| 243 | /* Place 2, 3, 4 into the queue, adding items to the back of the queue. */ |
| 244 | for (ulData = 2; ulData < 5; ulData++) { |
| 245 | xQueueSendToBack(xQueue, (void *) &ulData, genqNO_BLOCK); |
| 246 | } |
| 247 | |
| 248 | /* Now the order in the queue should be 2, 3, 4, with 2 being the first |
| 249 | thing to be read out. Now add 1 then 0 to the front of the queue. */ |
| 250 | if (uxQueueMessagesWaiting(xQueue) != 3) { |
| 251 | xErrorDetected = pdTRUE; |
| 252 | } |
| 253 | ulData = 1; |
| 254 | xQueueSendToFront(xQueue, (void *) &ulData, genqNO_BLOCK); |
| 255 | ulData = 0; |
| 256 | xQueueSendToFront(xQueue, (void *) &ulData, genqNO_BLOCK); |
| 257 | |
| 258 | /* Now the queue should be full, and when we read the data out we |
| 259 | should receive 0, 1, 2, 3, 4. */ |
| 260 | if (uxQueueMessagesWaiting(xQueue) != 5) { |
| 261 | xErrorDetected = pdTRUE; |
| 262 | } |
| 263 | |
| 264 | if (xQueueSendToFront(xQueue, (void *) &ulData, genqNO_BLOCK) != errQUEUE_FULL) { |
| 265 | xErrorDetected = pdTRUE; |
| 266 | } |
| 267 | |
| 268 | if (xQueueSendToBack(xQueue, (void *) &ulData, genqNO_BLOCK) != errQUEUE_FULL) { |
| 269 | xErrorDetected = pdTRUE; |
| 270 | } |
| 271 | |
| 272 | #if configUSE_PREEMPTION == 0 |
| 273 | taskYIELD(); |
| 274 | #endif |
| 275 | |
| 276 | /* Check the data we read out is in the expected order. */ |
| 277 | for (ulData = 0; ulData < genqQUEUE_LENGTH; ulData++) { |
| 278 | /* Try peeking the data first. */ |
| 279 | if (xQueuePeek(xQueue, &ulData2, genqNO_BLOCK) != pdPASS) { |
| 280 | xErrorDetected = pdTRUE; |
| 281 | } |
| 282 | |
| 283 | if (ulData != ulData2) { |
| 284 | xErrorDetected = pdTRUE; |
| 285 | } |
| 286 | |
| 287 | |
| 288 | /* Now try receiving the data for real. The value should be the |
| 289 | same. Clobber the value first so we know we really received it. */ |
| 290 | ulData2 = ~ulData2; |
| 291 | if (xQueueReceive(xQueue, &ulData2, genqNO_BLOCK) != pdPASS) { |
| 292 | xErrorDetected = pdTRUE; |
| 293 | } |
| 294 | |
| 295 | if (ulData != ulData2) { |
| 296 | xErrorDetected = pdTRUE; |
| 297 | } |
| 298 | } |
| 299 | |
| 300 | /* The queue should now be empty again. */ |
| 301 | if (uxQueueMessagesWaiting(xQueue) != 0) { |
| 302 | xErrorDetected = pdTRUE; |
| 303 | } |
| 304 | |
| 305 | #if configUSE_PREEMPTION == 0 |
| 306 | taskYIELD(); |
| 307 | #endif |
| 308 | |
| 309 | |
| 310 | /* Our queue is empty once more, add 10, 11 to the back. */ |
| 311 | ulData = 10; |
| 312 | if (xQueueSend(xQueue, &ulData, genqNO_BLOCK) != pdPASS) { |
| 313 | xErrorDetected = pdTRUE; |
| 314 | } |
| 315 | ulData = 11; |
| 316 | if (xQueueSend(xQueue, &ulData, genqNO_BLOCK) != pdPASS) { |
| 317 | xErrorDetected = pdTRUE; |
| 318 | } |
| 319 | |
| 320 | if (uxQueueMessagesWaiting(xQueue) != 2) { |
| 321 | xErrorDetected = pdTRUE; |
| 322 | } |
| 323 | |
| 324 | /* Now we should have 10, 11 in the queue. Add 7, 8, 9 to the |
| 325 | front. */ |
| 326 | for (ulData = 9; ulData >= 7; ulData--) { |
| 327 | if (xQueueSendToFront(xQueue, (void *) &ulData, genqNO_BLOCK) != pdPASS) { |
| 328 | xErrorDetected = pdTRUE; |
| 329 | } |
| 330 | } |
| 331 | |
| 332 | /* Now check that the queue is full, and that receiving data provides |
| 333 | the expected sequence of 7, 8, 9, 10, 11. */ |
| 334 | if (uxQueueMessagesWaiting(xQueue) != 5) { |
| 335 | xErrorDetected = pdTRUE; |
| 336 | } |
| 337 | |
| 338 | if (xQueueSendToFront(xQueue, (void *) &ulData, genqNO_BLOCK) != errQUEUE_FULL) { |
| 339 | xErrorDetected = pdTRUE; |
| 340 | } |
| 341 | |
| 342 | if (xQueueSendToBack(xQueue, (void *) &ulData, genqNO_BLOCK) != errQUEUE_FULL) { |
| 343 | xErrorDetected = pdTRUE; |
| 344 | } |
| 345 | |
| 346 | #if configUSE_PREEMPTION == 0 |
| 347 | taskYIELD(); |
| 348 | #endif |
| 349 | |
| 350 | /* Check the data we read out is in the expected order. */ |
| 351 | for (ulData = 7; ulData < (7 + genqQUEUE_LENGTH); ulData++) { |
| 352 | if (xQueueReceive(xQueue, &ulData2, genqNO_BLOCK) != pdPASS) { |
| 353 | xErrorDetected = pdTRUE; |
| 354 | } |
| 355 | |
| 356 | if (ulData != ulData2) { |
| 357 | xErrorDetected = pdTRUE; |
| 358 | } |
| 359 | } |
| 360 | |
| 361 | if (uxQueueMessagesWaiting(xQueue) != 0) { |
| 362 | xErrorDetected = pdTRUE; |
| 363 | } |
| 364 | |
| 365 | ulLoopCounter++; |
| 366 | } |
| 367 | } |
| 368 | /*-----------------------------------------------------------*/ |
| 369 | |
| 370 | static void prvLowPriorityMutexTask(void *pvParameters) |
| 371 | { |
| 372 | xSemaphoreHandle xMutex = (xSemaphoreHandle) pvParameters; |
| 373 | |
| 374 | #ifdef USE_STDIO |
| 375 | void vPrintDisplayMessage(const portCHAR * const * ppcMessageToSend); |
| 376 | |
| 377 | const portCHAR * const pcTaskStartMsg = "Mutex with priority inheritance test started.\r\n"; |
| 378 | |
| 379 | /* Queue a message for printing to say the task has started. */ |
| 380 | vPrintDisplayMessage(&pcTaskStartMsg); |
| 381 | #endif |
| 382 | |
| 383 | for (;;) { |
| 384 | /* Take the mutex. It should be available now. */ |
| 385 | if (xSemaphoreTake(xMutex, genqNO_BLOCK) != pdPASS) { |
| 386 | xErrorDetected = pdTRUE; |
| 387 | } |
| 388 | |
| 389 | /* Set our guarded variable to a known start value. */ |
| 390 | ulGuardedVariable = 0; |
| 391 | |
| 392 | /* Our priority should be as per that assigned when the task was |
| 393 | created. */ |
| 394 | if (uxTaskPriorityGet(NULL) != genqMUTEX_LOW_PRIORITY) { |
| 395 | xErrorDetected = pdTRUE; |
| 396 | } |
| 397 | |
| 398 | /* Now unsuspend the high priority task. This will attempt to take the |
| 399 | mutex, and block when it finds it cannot obtain it. */ |
| 400 | vTaskResume(xHighPriorityMutexTask); |
| 401 | |
| 402 | /* We should now have inherited the prioritoy of the high priority task, |
| 403 | as by now it will have attempted to get the mutex. */ |
| 404 | if (uxTaskPriorityGet(NULL) != genqMUTEX_HIGH_PRIORITY) { |
| 405 | xErrorDetected = pdTRUE; |
| 406 | } |
| 407 | |
| 408 | /* We can attempt to set our priority to the test priority - between the |
| 409 | idle priority and the medium/high test priorities, but our actual |
| 410 | prioroity should remain at the high priority. */ |
| 411 | vTaskPrioritySet(NULL, genqMUTEX_TEST_PRIORITY); |
| 412 | if (uxTaskPriorityGet(NULL) != genqMUTEX_HIGH_PRIORITY) { |
| 413 | xErrorDetected = pdTRUE; |
| 414 | } |
| 415 | |
| 416 | /* Now unsuspend the medium priority task. This should not run as our |
| 417 | inherited priority is above that of the medium priority task. */ |
| 418 | vTaskResume(xMediumPriorityMutexTask); |
| 419 | |
| 420 | /* If the did run then it will have incremented our guarded variable. */ |
| 421 | if (ulGuardedVariable != 0) { |
| 422 | xErrorDetected = pdTRUE; |
| 423 | } |
| 424 | |
| 425 | /* When we give back the semaphore our priority should be disinherited |
| 426 | back to the priority to which we attempted to set ourselves. This means |
| 427 | that when the high priority task next blocks, the medium priority task |
| 428 | should execute and increment the guarded variable. When we next run |
| 429 | both the high and medium priority tasks will have been suspended again. */ |
| 430 | if (xSemaphoreGive(xMutex) != pdPASS) { |
| 431 | xErrorDetected = pdTRUE; |
| 432 | } |
| 433 | |
| 434 | /* Check that the guarded variable did indeed increment... */ |
| 435 | if (ulGuardedVariable != 1) { |
| 436 | xErrorDetected = pdTRUE; |
| 437 | } |
| 438 | |
| 439 | /* ... and that our priority has been disinherited to |
| 440 | genqMUTEX_TEST_PRIORITY. */ |
| 441 | if (uxTaskPriorityGet(NULL) != genqMUTEX_TEST_PRIORITY) { |
| 442 | xErrorDetected = pdTRUE; |
| 443 | } |
| 444 | |
| 445 | /* Set our priority back to our original priority ready for the next |
| 446 | loop around this test. */ |
| 447 | vTaskPrioritySet(NULL, genqMUTEX_LOW_PRIORITY); |
| 448 | |
| 449 | /* Just to show we are still running. */ |
| 450 | ulLoopCounter2++; |
| 451 | |
| 452 | #if configUSE_PREEMPTION == 0 |
| 453 | taskYIELD(); |
| 454 | #endif |
| 455 | } |
| 456 | } |
| 457 | /*-----------------------------------------------------------*/ |
| 458 | |
| 459 | static void prvMediumPriorityMutexTask(void *pvParameters) |
| 460 | { |
| 461 | (void) pvParameters; |
| 462 | |
| 463 | for (;;) { |
| 464 | /* The medium priority task starts by suspending itself. The low |
| 465 | priority task will unsuspend this task when required. */ |
| 466 | vTaskSuspend(NULL); |
| 467 | |
| 468 | /* When this task unsuspends all it does is increment the guarded |
| 469 | variable, this is so the low priority task knows that it has |
| 470 | executed. */ |
| 471 | ulGuardedVariable++; |
| 472 | } |
| 473 | } |
| 474 | /*-----------------------------------------------------------*/ |
| 475 | |
| 476 | static void prvHighPriorityMutexTask(void *pvParameters) |
| 477 | { |
| 478 | xSemaphoreHandle xMutex = (xSemaphoreHandle) pvParameters; |
| 479 | |
| 480 | for (;;) { |
| 481 | /* The high priority task starts by suspending itself. The low |
| 482 | priority task will unsuspend this task when required. */ |
| 483 | vTaskSuspend(NULL); |
| 484 | |
| 485 | /* When this task unsuspends all it does is attempt to obtain |
| 486 | the mutex. It should find the mutex is not available so a |
| 487 | block time is specified. */ |
| 488 | if (xSemaphoreTake(xMutex, portMAX_DELAY) != pdPASS) { |
| 489 | xErrorDetected = pdTRUE; |
| 490 | } |
| 491 | |
| 492 | /* When we eventually obtain the mutex we just give it back then |
| 493 | return to suspend ready for the next test. */ |
| 494 | if (xSemaphoreGive(xMutex) != pdPASS) { |
| 495 | xErrorDetected = pdTRUE; |
| 496 | } |
| 497 | } |
| 498 | } |
| 499 | /*-----------------------------------------------------------*/ |
| 500 | |
| 501 | /* This is called to check that all the created tasks are still running. */ |
| 502 | portBASE_TYPE xAreGenericQueueTasksStillRunning(void) |
| 503 | { |
| 504 | static unsigned portLONG ulLastLoopCounter = 0, ulLastLoopCounter2 = 0; |
| 505 | |
| 506 | /* If the demo task is still running then we expect the loopcounters to |
| 507 | have incremented since this function was last called. */ |
| 508 | if (ulLastLoopCounter == ulLoopCounter) { |
| 509 | xErrorDetected = pdTRUE; |
| 510 | } |
| 511 | |
| 512 | if (ulLastLoopCounter2 == ulLoopCounter2) { |
| 513 | xErrorDetected = pdTRUE; |
| 514 | } |
| 515 | |
| 516 | ulLastLoopCounter = ulLoopCounter; |
| 517 | ulLastLoopCounter2 = ulLoopCounter2; |
| 518 | |
| 519 | /* Errors detected in the task itself will have latched xErrorDetected |
| 520 | to true. */ |
| 521 | |
| 522 | return !xErrorDetected; |
| 523 | } |
| 524 | |
| 525 | |