]> git.sur5r.net Git - freertos/blob - FreeRTOS/Demo/Common/Minimal/AbortDelay.c
e18259a08a640229b60abfa9cdc7277e1779cde7
[freertos] / FreeRTOS / Demo / Common / Minimal / AbortDelay.c
1 /*\r
2  * FreeRTOS Kernel V10.0.1\r
3  * Copyright (C) 2017 Amazon.com, Inc. or its affiliates.  All Rights Reserved.\r
4  *\r
5  * Permission is hereby granted, free of charge, to any person obtaining a copy of\r
6  * this software and associated documentation files (the "Software"), to deal in\r
7  * the Software without restriction, including without limitation the rights to\r
8  * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of\r
9  * the Software, and to permit persons to whom the Software is furnished to do so,\r
10  * subject to the following conditions:\r
11  *\r
12  * The above copyright notice and this permission notice shall be included in all\r
13  * copies or substantial portions of the Software.\r
14  *\r
15  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\r
16  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS\r
17  * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR\r
18  * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER\r
19  * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r
20  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\r
21  *\r
22  * http://www.FreeRTOS.org\r
23  * http://aws.amazon.com/freertos\r
24  *\r
25  * 1 tab == 4 spaces!\r
26  */\r
27 \r
28 /*\r
29  * This file contains some test scenarios that ensure tasks respond correctly\r
30  * to xTaskAbortDelay() calls.\r
31  */\r
32 \r
33 /* Standard includes. */\r
34 #include "limits.h"\r
35 \r
36 /* Kernel includes. */\r
37 #include "FreeRTOS.h"\r
38 #include "task.h"\r
39 #include "queue.h"\r
40 #include "semphr.h"\r
41 #include "event_groups.h"\r
42 \r
43 /* Demo includes. */\r
44 #include "AbortDelay.h"\r
45 \r
46 /* This file can only be used if the functionality it tests is included in the\r
47 build.  Remove the whole file if this is not the case. */\r
48 #if( INCLUDE_xTaskAbortDelay == 1 )\r
49 \r
50 #if( INCLUDE_xTaskGetHandle != 1 )\r
51         #error This test file uses the xTaskGetHandle() API function so INCLUDE_xTaskGetHandle must be set to 1 in FreeRTOSConfig.h.\r
52 #endif\r
53 \r
54 /* Task priorities.  Allow these to be overridden. */\r
55 #ifndef abtCONTROLLING_PRIORITY\r
56         #define abtCONTROLLING_PRIORITY         ( configMAX_PRIORITIES - 3 )\r
57 #endif\r
58 \r
59 #ifndef abtBLOCKING_PRIORITY\r
60         #define abtBLOCKING_PRIORITY    ( configMAX_PRIORITIES - 2 )\r
61 #endif\r
62 \r
63 /* The tests that are performed. */\r
64 #define abtNOTIFY_WAIT_ABORTS           0\r
65 #define abtNOTIFY_TAKE_ABORTS           1\r
66 #define abtDELAY_ABORTS                         2\r
67 #define abtDELAY_UNTIL_ABORTS           3\r
68 #define abtSEMAPHORE_TAKE_ABORTS        4\r
69 #define abtEVENT_GROUP_ABORTS           5\r
70 #define abtQUEUE_SEND_ABORTS            6\r
71 #define abtMAX_TESTS                            7\r
72 \r
73 /*-----------------------------------------------------------*/\r
74 \r
75 /*\r
76  * The two test tasks.  The controlling task specifies which test to executed.\r
77  * More information is provided in the comments within the tasks.\r
78  */\r
79 static void prvControllingTask( void *pvParameters );\r
80 static void prvBlockingTask( void *pvParameters );\r
81 \r
82 /*\r
83  * Test functions called by the blocking task.  Each function follows the same\r
84  * pattern, but the way the task blocks is different in each case.\r
85  *\r
86  * In each function three blocking calls are made.  The first and third\r
87  * blocking call is expected to time out, while the middle blocking call is\r
88  * expected to be aborted by the controlling task half way through the block\r
89  * time.\r
90  */\r
91 static void prvTestAbortingTaskNotifyWait( void );\r
92 static void prvTestAbortingTaskNotifyTake( void );\r
93 static void prvTestAbortingTaskDelay( void );\r
94 static void prvTestAbortingTaskDelayUntil( void );\r
95 static void prvTestAbortingSemaphoreTake( void );\r
96 static void prvTestAbortingEventGroupWait( void );\r
97 static void prvTestAbortingQueueSend( void );\r
98 \r
99 /*\r
100  * Checks the amount of time a task spent in the Blocked state is within the\r
101  * expected bounds.\r
102  */\r
103 static void prvCheckExpectedTimeIsWithinAnAcceptableMargin( TickType_t xStartTime, TickType_t xExpectedBlockTime );\r
104 \r
105 /*-----------------------------------------------------------*/\r
106 \r
107 /* Used to ensure that tasks are still executing without error. */\r
108 static volatile BaseType_t xControllingCycles = 0, xBlockingCycles = 0;\r
109 static volatile BaseType_t xErrorOccurred = pdFALSE;\r
110 \r
111 /* Each task needs to know the other tasks handle so they can send signals to\r
112 each other.  The handle is obtained from the task's name. */\r
113 static const char *pcControllingTaskName = "AbtCtrl", *pcBlockingTaskName = "AbtBlk";\r
114 \r
115 /* The maximum amount of time a task will block for. */\r
116 const TickType_t xMaxBlockTime = pdMS_TO_TICKS( 100 );\r
117 const TickType_t xHalfMaxBlockTime = pdMS_TO_TICKS( 50 );\r
118 \r
119 /* The actual block time is dependent on the priority of other tasks in the\r
120 system so the actual block time might be greater than that expected, but it\r
121 should be within an acceptable upper bound. */\r
122 const TickType_t xAllowableMargin = pdMS_TO_TICKS( 7 );\r
123 \r
124 /*-----------------------------------------------------------*/\r
125 \r
126 void vCreateAbortDelayTasks( void )\r
127 {\r
128         /* Create the two test tasks described above. */\r
129         xTaskCreate( prvControllingTask, pcControllingTaskName, configMINIMAL_STACK_SIZE, NULL, abtCONTROLLING_PRIORITY, NULL );\r
130         xTaskCreate( prvBlockingTask, pcBlockingTaskName, configMINIMAL_STACK_SIZE, NULL, abtBLOCKING_PRIORITY, NULL );\r
131 }\r
132 /*-----------------------------------------------------------*/\r
133 \r
134 static void prvControllingTask( void *pvParameters )\r
135 {\r
136 TaskHandle_t xBlockingTask;\r
137 uint32_t ulTestToPerform = abtNOTIFY_WAIT_ABORTS;\r
138 TickType_t xTimeAtStart;\r
139 const TickType_t xStartMargin = 2UL;\r
140 \r
141         /* Just to remove compiler warnings. */\r
142         ( void ) pvParameters;\r
143 \r
144         xBlockingTask = xTaskGetHandle( pcBlockingTaskName );\r
145         configASSERT( xBlockingTask );\r
146 \r
147         for( ;; )\r
148         {\r
149                 /* Tell the secondary task to perform the next test. */\r
150                 xTimeAtStart = xTaskGetTickCount();\r
151                 xTaskNotify( xBlockingTask, ulTestToPerform, eSetValueWithOverwrite );\r
152 \r
153                 /* The secondary task has a higher priority, so will now be in the\r
154                 Blocked state to wait for a maximum of xMaxBlockTime.  It expects that\r
155                 period to complete with a timeout.  It will then block for\r
156                 xMaxBlockTimeAgain, but this time it expects to the block time to abort\r
157                 half way through.  Block until it is time to send the abort to the\r
158                 secondary task.  xStartMargin is used because this task takes timing\r
159                 from the beginning of the test, whereas the blocking task takes timing\r
160                 from the entry into the Blocked state - and as the tasks run at\r
161                 different priorities, there may be some discrepancy.  Also, temporarily\r
162                 raise the priority of the controlling task to that of the blocking\r
163                 task to minimise discrepancies. */\r
164                 vTaskPrioritySet( NULL, abtBLOCKING_PRIORITY );\r
165                 vTaskDelay( xMaxBlockTime + xHalfMaxBlockTime + xStartMargin );\r
166                 if( xTaskAbortDelay( xBlockingTask ) != pdPASS )\r
167                 {\r
168                         xErrorOccurred = pdTRUE;\r
169                 }\r
170 \r
171                 /* Reset the priority to the normal controlling priority. */\r
172                 vTaskPrioritySet( NULL, abtCONTROLLING_PRIORITY );\r
173 \r
174                 /* Now wait to be notified that the secondary task has completed its\r
175                 test. */\r
176                 ulTaskNotifyTake( pdTRUE, portMAX_DELAY );\r
177 \r
178                 /* Did the entire test run for the expected time, which is two full\r
179                 block times plus the half block time caused by calling\r
180                 xTaskAbortDelay()? */\r
181                 prvCheckExpectedTimeIsWithinAnAcceptableMargin( xTimeAtStart, ( xMaxBlockTime + xMaxBlockTime + xHalfMaxBlockTime ) );\r
182 \r
183                 /* Move onto the next test. */\r
184                 ulTestToPerform++;\r
185 \r
186                 if( ulTestToPerform >= abtMAX_TESTS )\r
187                 {\r
188                         ulTestToPerform = 0;\r
189                 }\r
190 \r
191                 /* To indicate this task is still executing. */\r
192                 xControllingCycles++;\r
193         }\r
194 }\r
195 /*-----------------------------------------------------------*/\r
196 \r
197 static void prvBlockingTask( void *pvParameters )\r
198 {\r
199 TaskHandle_t xControllingTask;\r
200 uint32_t ulNotificationValue;\r
201 const uint32_t ulMax = 0xffffffffUL;\r
202 \r
203         /* Just to remove compiler warnings. */\r
204         ( void ) pvParameters;\r
205 \r
206         xControllingTask = xTaskGetHandle( pcControllingTaskName );\r
207         configASSERT( xControllingTask );\r
208 \r
209         for( ;; )\r
210         {\r
211                 /* Wait to be notified of the test that is to be performed next. */\r
212                 xTaskNotifyWait( 0, ulMax, &ulNotificationValue, portMAX_DELAY );\r
213 \r
214                 switch( ulNotificationValue )\r
215                 {\r
216                         case abtNOTIFY_WAIT_ABORTS:\r
217                                 prvTestAbortingTaskNotifyWait();\r
218                                 break;\r
219 \r
220                         case abtNOTIFY_TAKE_ABORTS:\r
221                                 prvTestAbortingTaskNotifyTake();\r
222                                 break;\r
223 \r
224                         case abtDELAY_ABORTS:\r
225                                 prvTestAbortingTaskDelay();\r
226                                 break;\r
227 \r
228                         case abtDELAY_UNTIL_ABORTS:\r
229                                 prvTestAbortingTaskDelayUntil();\r
230                                 break;\r
231 \r
232                         case abtSEMAPHORE_TAKE_ABORTS:\r
233                                 prvTestAbortingSemaphoreTake();\r
234                                 break;\r
235 \r
236                         case abtEVENT_GROUP_ABORTS:\r
237                                 prvTestAbortingEventGroupWait();\r
238                                 break;\r
239 \r
240                         case abtQUEUE_SEND_ABORTS:\r
241                                 prvTestAbortingQueueSend();\r
242                                 break;\r
243 \r
244                         default:\r
245                                 /* Should not get here. */\r
246                                 break;\r
247                 }\r
248 \r
249                 /* Let the primary task know the test is complete. */\r
250                 xTaskNotifyGive( xControllingTask );\r
251 \r
252                 /* To indicate this task is still executing. */\r
253                 xBlockingCycles++;\r
254         }\r
255 }\r
256 /*-----------------------------------------------------------*/\r
257 \r
258 static void prvTestAbortingTaskDelayUntil( void )\r
259 {\r
260 TickType_t xTimeAtStart, xLastBlockTime;\r
261 \r
262         /* Note the time before the delay so the length of the delay is known. */\r
263         xTimeAtStart = xTaskGetTickCount();\r
264 \r
265         /* Take a copy of the time as it is updated in the call to\r
266         vTaskDelayUntil() but its original value is needed to determine the actual\r
267         time spend in the Blocked state. */\r
268         xLastBlockTime = xTimeAtStart;\r
269 \r
270         /* This first delay should just time out. */\r
271         vTaskDelayUntil( &xLastBlockTime, xMaxBlockTime );\r
272         prvCheckExpectedTimeIsWithinAnAcceptableMargin( xTimeAtStart, xMaxBlockTime );\r
273 \r
274         /* This second delay should be aborted by the primary task half way\r
275         through.  Again take a copy of the time as it is updated in the call to\r
276         vTaskDelayUntil() buts its original value is needed to determine the amount\r
277         of time actually spent in the Blocked state. */\r
278         xTimeAtStart = xTaskGetTickCount();\r
279         xLastBlockTime = xTimeAtStart;\r
280         vTaskDelayUntil( &xLastBlockTime, xMaxBlockTime );\r
281         prvCheckExpectedTimeIsWithinAnAcceptableMargin( xTimeAtStart, xHalfMaxBlockTime );\r
282 \r
283         /* As with the other tests, the third block period should not time out. */\r
284         xTimeAtStart = xTaskGetTickCount();\r
285         xLastBlockTime = xTimeAtStart;\r
286         vTaskDelayUntil( &xLastBlockTime, xMaxBlockTime );\r
287         prvCheckExpectedTimeIsWithinAnAcceptableMargin( xTimeAtStart, xMaxBlockTime );\r
288 }\r
289 /*-----------------------------------------------------------*/\r
290 \r
291 static void prvTestAbortingTaskDelay( void )\r
292 {\r
293 TickType_t xTimeAtStart;\r
294 \r
295         /* Note the time before the delay so the length of the delay is known. */\r
296         xTimeAtStart = xTaskGetTickCount();\r
297 \r
298         /* This first delay should just time out. */\r
299         vTaskDelay( xMaxBlockTime );\r
300         prvCheckExpectedTimeIsWithinAnAcceptableMargin( xTimeAtStart, xMaxBlockTime );\r
301 \r
302         /* Note the time before the delay so the length of the delay is known. */\r
303         xTimeAtStart = xTaskGetTickCount();\r
304 \r
305         /* This second delay should be aborted by the primary task half way\r
306         through. */\r
307         vTaskDelay( xMaxBlockTime );\r
308         prvCheckExpectedTimeIsWithinAnAcceptableMargin( xTimeAtStart, xHalfMaxBlockTime );\r
309 \r
310         /* Note the time before the delay so the length of the delay is known. */\r
311         xTimeAtStart = xTaskGetTickCount();\r
312 \r
313         /* This third delay should just time out again. */\r
314         vTaskDelay( xMaxBlockTime );\r
315         prvCheckExpectedTimeIsWithinAnAcceptableMargin( xTimeAtStart, xMaxBlockTime );\r
316 }\r
317 /*-----------------------------------------------------------*/\r
318 \r
319 static void prvTestAbortingTaskNotifyTake( void )\r
320 {\r
321 TickType_t xTimeAtStart;\r
322 uint32_t ulReturn;\r
323 \r
324         /* Note the time before the delay so the length of the delay is known. */\r
325         xTimeAtStart = xTaskGetTickCount();\r
326 \r
327         /* This first delay should just time out. */\r
328         ulReturn = ulTaskNotifyTake( pdFALSE, xMaxBlockTime );\r
329         if( ulReturn != 0 )\r
330         {\r
331                 xErrorOccurred = pdTRUE;\r
332         }\r
333         prvCheckExpectedTimeIsWithinAnAcceptableMargin( xTimeAtStart, xMaxBlockTime );\r
334 \r
335         /* Note the time before the delay so the length of the delay is known. */\r
336         xTimeAtStart = xTaskGetTickCount();\r
337 \r
338         /* This second delay should be aborted by the primary task half way\r
339         through. */\r
340         ulReturn = ulTaskNotifyTake( pdFALSE, xMaxBlockTime );\r
341         if( ulReturn != 0 )\r
342         {\r
343                 xErrorOccurred = pdTRUE;\r
344         }\r
345         prvCheckExpectedTimeIsWithinAnAcceptableMargin( xTimeAtStart, xHalfMaxBlockTime );\r
346 \r
347         /* Note the time before the delay so the length of the delay is known. */\r
348         xTimeAtStart = xTaskGetTickCount();\r
349 \r
350         /* This third delay should just time out again. */\r
351         ulReturn = ulTaskNotifyTake( pdFALSE, xMaxBlockTime );\r
352         if( ulReturn != 0 )\r
353         {\r
354                 xErrorOccurred = pdTRUE;\r
355         }\r
356         prvCheckExpectedTimeIsWithinAnAcceptableMargin( xTimeAtStart, xMaxBlockTime );\r
357 }\r
358 /*-----------------------------------------------------------*/\r
359 \r
360 static void prvTestAbortingEventGroupWait( void )\r
361 {\r
362 TickType_t xTimeAtStart;\r
363 EventGroupHandle_t xEventGroup;\r
364 EventBits_t xBitsToWaitFor = ( EventBits_t ) 0x01, xReturn;\r
365 \r
366         #if( configSUPPORT_STATIC_ALLOCATION == 1 )\r
367         {\r
368                 static StaticEventGroup_t xEventGroupBuffer;\r
369 \r
370                 /* Create the event group.  Statically allocated memory is used so the\r
371                 creation cannot fail. */\r
372                 xEventGroup = xEventGroupCreateStatic( &xEventGroupBuffer );\r
373         }\r
374         #else\r
375         {\r
376                 xEventGroup = xEventGroupCreate();\r
377                 configASSERT( xEventGroup );\r
378         }\r
379         #endif\r
380 \r
381         /* Note the time before the delay so the length of the delay is known. */\r
382         xTimeAtStart = xTaskGetTickCount();\r
383 \r
384         /* This first delay should just time out. */\r
385         xReturn = xEventGroupWaitBits( xEventGroup, xBitsToWaitFor, pdTRUE, pdTRUE, xMaxBlockTime );\r
386         if( xReturn != 0x00 )\r
387         {\r
388                 xErrorOccurred = pdTRUE;\r
389         }\r
390         prvCheckExpectedTimeIsWithinAnAcceptableMargin( xTimeAtStart, xMaxBlockTime );\r
391 \r
392         /* Note the time before the delay so the length of the delay is known. */\r
393         xTimeAtStart = xTaskGetTickCount();\r
394 \r
395         /* This second delay should be aborted by the primary task half way\r
396         through. */\r
397         xReturn = xEventGroupWaitBits( xEventGroup, xBitsToWaitFor, pdTRUE, pdTRUE, xMaxBlockTime );\r
398         if( xReturn != 0x00 )\r
399         {\r
400                 xErrorOccurred = pdTRUE;\r
401         }\r
402         prvCheckExpectedTimeIsWithinAnAcceptableMargin( xTimeAtStart, xHalfMaxBlockTime );\r
403 \r
404         /* Note the time before the delay so the length of the delay is known. */\r
405         xTimeAtStart = xTaskGetTickCount();\r
406 \r
407         /* This third delay should just time out again. */\r
408         xReturn = xEventGroupWaitBits( xEventGroup, xBitsToWaitFor, pdTRUE, pdTRUE, xMaxBlockTime );\r
409         if( xReturn != 0x00 )\r
410         {\r
411                 xErrorOccurred = pdTRUE;\r
412         }\r
413         prvCheckExpectedTimeIsWithinAnAcceptableMargin( xTimeAtStart, xMaxBlockTime );\r
414 \r
415         /* Not really necessary in this case, but for completeness. */\r
416         vEventGroupDelete( xEventGroup );\r
417 }\r
418 /*-----------------------------------------------------------*/\r
419 \r
420 static void prvTestAbortingQueueSend( void )\r
421 {\r
422 TickType_t xTimeAtStart;\r
423 BaseType_t xReturn;\r
424 const UBaseType_t xQueueLength = ( UBaseType_t ) 1;\r
425 QueueHandle_t xQueue;\r
426 uint8_t ucItemToQueue;\r
427 \r
428         #if( configSUPPORT_STATIC_ALLOCATION == 1 )\r
429         {\r
430                 static StaticQueue_t xQueueBuffer;\r
431                 static uint8_t ucQueueStorage[ sizeof( uint8_t ) ];\r
432 \r
433                 /* Create the queue.  Statically allocated memory is used so the\r
434                 creation cannot fail. */\r
435                 xQueue = xQueueCreateStatic( xQueueLength, sizeof( uint8_t ), ucQueueStorage, &xQueueBuffer );\r
436         }\r
437         #else\r
438         {\r
439                 xQueue = xQueueCreate( xQueueLength, sizeof( uint8_t ) );\r
440                 configASSERT( xQueue );\r
441         }\r
442         #endif\r
443 \r
444         /* This function tests aborting when in the blocked state waiting to send,\r
445         so the queue must be full.  There is only one space in the queue. */\r
446         xReturn = xQueueSend( xQueue, &ucItemToQueue, xMaxBlockTime );\r
447         if( xReturn != pdPASS )\r
448         {\r
449                 xErrorOccurred = pdTRUE;\r
450         }\r
451 \r
452         /* Note the time before the delay so the length of the delay is known. */\r
453         xTimeAtStart = xTaskGetTickCount();\r
454 \r
455         /* This first delay should just time out. */\r
456         xReturn = xQueueSend( xQueue, &ucItemToQueue, xMaxBlockTime );\r
457         if( xReturn != pdFALSE )\r
458         {\r
459                 xErrorOccurred = pdTRUE;\r
460         }\r
461         prvCheckExpectedTimeIsWithinAnAcceptableMargin( xTimeAtStart, xMaxBlockTime );\r
462 \r
463         /* Note the time before the delay so the length of the delay is known. */\r
464         xTimeAtStart = xTaskGetTickCount();\r
465 \r
466         /* This second delay should be aborted by the primary task half way\r
467         through. */\r
468         xReturn = xQueueSend( xQueue, &ucItemToQueue, xMaxBlockTime );\r
469         if( xReturn != pdFALSE )\r
470         {\r
471                 xErrorOccurred = pdTRUE;\r
472         }\r
473         prvCheckExpectedTimeIsWithinAnAcceptableMargin( xTimeAtStart, xHalfMaxBlockTime );\r
474 \r
475         /* Note the time before the delay so the length of the delay is known. */\r
476         xTimeAtStart = xTaskGetTickCount();\r
477 \r
478         /* This third delay should just time out again. */\r
479         xReturn = xQueueSend( xQueue, &ucItemToQueue, xMaxBlockTime );\r
480         if( xReturn != pdFALSE )\r
481         {\r
482                 xErrorOccurred = pdTRUE;\r
483         }\r
484         prvCheckExpectedTimeIsWithinAnAcceptableMargin( xTimeAtStart, xMaxBlockTime );\r
485 \r
486         /* Not really necessary in this case, but for completeness. */\r
487         vQueueDelete( xQueue );\r
488 }\r
489 /*-----------------------------------------------------------*/\r
490 \r
491 static void prvTestAbortingSemaphoreTake( void )\r
492 {\r
493 TickType_t xTimeAtStart;\r
494 BaseType_t xReturn;\r
495 SemaphoreHandle_t xSemaphore;\r
496 \r
497         #if( configSUPPORT_STATIC_ALLOCATION == 1 )\r
498         {\r
499                 static StaticSemaphore_t xSemaphoreBuffer;\r
500 \r
501                 /* Create the semaphore.  Statically allocated memory is used so the\r
502                 creation cannot fail. */\r
503                 xSemaphore = xSemaphoreCreateBinaryStatic( &xSemaphoreBuffer );\r
504         }\r
505         #else\r
506         {\r
507                 xSemaphore = xSemaphoreCreateBinary();\r
508         }\r
509         #endif\r
510 \r
511         /* Note the time before the delay so the length of the delay is known. */\r
512         xTimeAtStart = xTaskGetTickCount();\r
513 \r
514         /* This first delay should just time out. */\r
515         xReturn = xSemaphoreTake( xSemaphore, xMaxBlockTime );\r
516         if( xReturn != pdFALSE )\r
517         {\r
518                 xErrorOccurred = pdTRUE;\r
519         }\r
520         prvCheckExpectedTimeIsWithinAnAcceptableMargin( xTimeAtStart, xMaxBlockTime );\r
521 \r
522         /* Note the time before the delay so the length of the delay is known. */\r
523         xTimeAtStart = xTaskGetTickCount();\r
524 \r
525         /* This second delay should be aborted by the primary task half way\r
526         through. */\r
527         xReturn = xSemaphoreTake( xSemaphore, xMaxBlockTime );\r
528         if( xReturn != pdFALSE )\r
529         {\r
530                 xErrorOccurred = pdTRUE;\r
531         }\r
532         prvCheckExpectedTimeIsWithinAnAcceptableMargin( xTimeAtStart, xHalfMaxBlockTime );\r
533 \r
534         /* Note the time before the delay so the length of the delay is known. */\r
535         xTimeAtStart = xTaskGetTickCount();\r
536 \r
537         /* This third delay should just time out again. */\r
538         xReturn = xSemaphoreTake( xSemaphore, xMaxBlockTime );\r
539         if( xReturn != pdFALSE )\r
540         {\r
541                 xErrorOccurred = pdTRUE;\r
542         }\r
543         prvCheckExpectedTimeIsWithinAnAcceptableMargin( xTimeAtStart, xMaxBlockTime );\r
544 \r
545         /* Not really necessary in this case, but for completeness. */\r
546         vSemaphoreDelete( xSemaphore );\r
547 }\r
548 /*-----------------------------------------------------------*/\r
549 \r
550 static void prvTestAbortingTaskNotifyWait( void )\r
551 {\r
552 TickType_t xTimeAtStart;\r
553 BaseType_t xReturn;\r
554 \r
555         /* Note the time before the delay so the length of the delay is known. */\r
556         xTimeAtStart = xTaskGetTickCount();\r
557 \r
558         /* This first delay should just time out. */\r
559         xReturn = xTaskNotifyWait( 0, 0, NULL, xMaxBlockTime );\r
560         if( xReturn != pdFALSE )\r
561         {\r
562                 xErrorOccurred = pdTRUE;\r
563         }\r
564         prvCheckExpectedTimeIsWithinAnAcceptableMargin( xTimeAtStart, xMaxBlockTime );\r
565 \r
566         /* Note the time before the delay so the length of the delay is known. */\r
567         xTimeAtStart = xTaskGetTickCount();\r
568 \r
569         /* This second delay should be aborted by the primary task half way\r
570         through. */\r
571         xReturn = xTaskNotifyWait( 0, 0, NULL, xMaxBlockTime );\r
572         if( xReturn != pdFALSE )\r
573         {\r
574                 xErrorOccurred = pdTRUE;\r
575         }\r
576         prvCheckExpectedTimeIsWithinAnAcceptableMargin( xTimeAtStart, xHalfMaxBlockTime );\r
577 \r
578         /* Note the time before the delay so the length of the delay is known. */\r
579         xTimeAtStart = xTaskGetTickCount();\r
580 \r
581         /* This third delay should just time out again. */\r
582         xReturn = xTaskNotifyWait( 0, 0, NULL, xMaxBlockTime );\r
583         if( xReturn != pdFALSE )\r
584         {\r
585                 xErrorOccurred = pdTRUE;\r
586         }\r
587         prvCheckExpectedTimeIsWithinAnAcceptableMargin( xTimeAtStart, xMaxBlockTime );\r
588 }\r
589 /*-----------------------------------------------------------*/\r
590 \r
591 static void prvCheckExpectedTimeIsWithinAnAcceptableMargin( TickType_t xStartTime, TickType_t xExpectedBlockTime )\r
592 {\r
593 TickType_t xTimeNow, xActualBlockTime;\r
594 \r
595         xTimeNow = xTaskGetTickCount();\r
596         xActualBlockTime = xTimeNow - xStartTime;\r
597 \r
598         /* The actual block time should not be less than the expected block time. */\r
599         if( xActualBlockTime < xExpectedBlockTime )\r
600         {\r
601                 xErrorOccurred = pdTRUE;\r
602         }\r
603 \r
604         /* The actual block time can be greater than the expected block time, as it\r
605         depends on the priority of the other tasks, but it should be within an\r
606         acceptable margin. */\r
607         if( xActualBlockTime > ( xExpectedBlockTime + xAllowableMargin ) )\r
608         {\r
609                 xErrorOccurred = pdTRUE;\r
610         }\r
611 }\r
612 /*-----------------------------------------------------------*/\r
613 \r
614 BaseType_t xAreAbortDelayTestTasksStillRunning( void )\r
615 {\r
616 static BaseType_t xLastControllingCycleCount = 0, xLastBlockingCycleCount = 0;\r
617 BaseType_t xReturn = pdPASS;\r
618 \r
619         /* Have both tasks performed at least one cycle since this function was\r
620         last called? */\r
621         if( xControllingCycles == xLastControllingCycleCount )\r
622         {\r
623                 xReturn = pdFAIL;\r
624         }\r
625 \r
626         if( xBlockingCycles == xLastBlockingCycleCount )\r
627         {\r
628                 xReturn = pdFAIL;\r
629         }\r
630 \r
631         if( xErrorOccurred == pdTRUE )\r
632         {\r
633                 xReturn = pdFAIL;\r
634         }\r
635 \r
636         xLastBlockingCycleCount = xBlockingCycles;\r
637         xLastControllingCycleCount = xControllingCycles;\r
638 \r
639         return xReturn;\r
640 }\r
641 \r
642 #endif /* INCLUDE_xTaskAbortDelay == 1 */\r