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