]> begriffs open source - freertos/blob - FreeRTOS-Plus/Demo/FreeRTOS_IoT_Libraries/task_pool/DemoTasks/SimpleTaskPoolExamples.c
Add MQTT project that builds on the task pool project - currently the library is...
[freertos] / FreeRTOS-Plus / Demo / FreeRTOS_IoT_Libraries / task_pool / DemoTasks / SimpleTaskPoolExamples.c
1 /*\r
2  * FreeRTOS Kernel V10.2.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 //_RB_ Add link to docs here.\r
29 \r
30 /* Kernel includes. */\r
31 #include "FreeRTOS.h"\r
32 #include "task.h"\r
33 \r
34 /* Standard includes. */\r
35 #include <stdio.h>\r
36 \r
37 /* IoT SDK includes. */\r
38 #include "iot_taskpool.h"\r
39 \r
40 /* The priority at which that tasks in the task pool (the worker tasks) get\r
41 created. */\r
42 #define tpTASK_POOL_WORKER_PRIORITY             1\r
43 \r
44 /* The number of jobs created in the example functions that create more than\r
45 one job. */\r
46 #define tpJOBS_TO_CREATE        5\r
47 \r
48 /*\r
49  * Prototypes for the functions that demonstrate the task pool API.\r
50  * See the implementation of the prvTaskPoolDemoTask() function within this file\r
51  * for a description of the individual functions.  A configASSERT() is hit if\r
52  * any of the demos encounter any unexpected behaviour.\r
53  */\r
54 static void prvExample_BasicSingleJob( void );\r
55 static void prvExample_DeferredJobAndCancellingJobs( void );\r
56 static void prvExample_BasicRecyclableJob( void );\r
57 static void prvExample_ReuseRecyclableJobFromLowPriorityTask( void );\r
58 static void prvExample_ReuseRecyclableJobFromHighPriorityTask( void );\r
59 \r
60 /*\r
61  * Prototypes of the callback functions used in the examples.  The callback\r
62  * simply sends a signal (in the form of a direct task notification) to the\r
63  * prvTaskPoolDemoTask() task to let the task know that the callback execute.\r
64  * The handle of the prvTaskPoolDemoTask() task is not accessed directly, but\r
65  * instead passed into the task pool job as the job's context.\r
66  */\r
67 static void prvSimpleTaskNotifyCallback( IotTaskPool_t pTaskPool, IotTaskPoolJob_t pJob, void *pUserContext );\r
68 \r
69 /*\r
70  * The task used to demonstrate the task pool API.  This task just loops through\r
71  * each demo in turn.\r
72  */\r
73 static void prvTaskPoolDemoTask( void *pvParameters );\r
74 \r
75 /*-----------------------------------------------------------*/\r
76 \r
77 /* Parameters used to create the system task pool - see TBD for more information\r
78 as the task pool used in this example is a slimmed down version of the full\r
79 library - the slimmed down version being intended specifically for FreeRTOS\r
80 kernel use cases. */\r
81 static const IotTaskPoolInfo_t xTaskPoolParameters = {\r
82                                                                                                                 /* Minimum number of threads in a task pool.\r
83                                                                                                                 Note the slimmed down version of the task\r
84                                                                                                                 pool used by this library does not autoscale\r
85                                                                                                                 the number of tasks in the pool so in this\r
86                                                                                                                 case this sets the number of tasks in the\r
87                                                                                                                 pool. */\r
88                                                                                                                 2,\r
89                                                                                                                 /* Maximum number of threads in a task pool.\r
90                                                                                                                 Note the slimmed down version of the task\r
91                                                                                                                 pool used by this library does not autoscale\r
92                                                                                                                 the number of tasks in the pool so in this\r
93                                                                                                                 case this parameter is just ignored. */\r
94                                                                                                                 2,\r
95                                                                                                                 /* Stack size for every task pool thread - in\r
96                                                                                                                 bytes, hence multiplying by the number of bytes\r
97                                                                                                                 in a word as configMINIMAL_STACK_SIZE is\r
98                                                                                                                 specified in words. */\r
99                                                                                                                 configMINIMAL_STACK_SIZE * sizeof( portSTACK_TYPE ),\r
100                                                                                                                 /* Priority for every task pool thread. */\r
101                                                                                                                 tpTASK_POOL_WORKER_PRIORITY,\r
102                                                                                                          };\r
103 \r
104 /*-----------------------------------------------------------*/\r
105 \r
106 void vStartSimpleTaskPoolDemo( void )\r
107 {\r
108         /* This example uses a single application task, which in turn is used to\r
109         create and send jobs to task pool tasks. */\r
110         xTaskCreate( prvTaskPoolDemoTask,               /* Function that implements the task. */\r
111                                  "PoolDemo",                            /* Text name for the task - only used for debugging. */\r
112                                  configMINIMAL_STACK_SIZE,      /* Size of stack (in words, not bytes) to allocate for the task. */\r
113                                  NULL,                                          /* Task parameter - not used in this case. */\r
114                                  tskIDLE_PRIORITY,                      /* Task priority, must be between 0 and configMAX_PRIORITIES - 1. */\r
115                                  NULL );                                        /* Used to pass out a handle to the created tsak - not used in this case. */\r
116 }\r
117 /*-----------------------------------------------------------*/\r
118 \r
119 static void prvTaskPoolDemoTask( void *pvParameters )\r
120 {\r
121 IotTaskPoolError_t xResult;\r
122 uint32_t ulLoops = 0;\r
123 \r
124         /* Remove compiler warnings about unused parameters. */\r
125         ( void ) pvParameters;\r
126 \r
127         /* The task pool must be created before it can be used.  The system task\r
128         pool is the task pool managed by the task pool library itself - the storage\r
129         used by the task pool is provided by the library. */\r
130         xResult = IotTaskPool_CreateSystemTaskPool( &xTaskPoolParameters );\r
131         configASSERT( xResult == IOT_TASKPOOL_SUCCESS );\r
132 \r
133         /* Attempting to create the task pool again should then appear to succeed\r
134         (in case it is initialised by more than one library), but have no effect. */\r
135         xResult = IotTaskPool_CreateSystemTaskPool( &xTaskPoolParameters );\r
136         configASSERT( xResult == IOT_TASKPOOL_SUCCESS );\r
137 \r
138         for( ;; )\r
139         {\r
140                 /* Demonstrate the most basic use case where a non persistent job is\r
141                 created and scheduled to run immediately.  The task pool worker tasks\r
142                 (in which the job callback function executes) have a priority above the\r
143                 priority of this task so the job's callback executes as soon as it is\r
144                 scheduled. */\r
145                 prvExample_BasicSingleJob();\r
146 \r
147                 /* Demonstrate a job being scheduled to run at some time in the\r
148                 future, and how a job scheduled to run in the future can be cancelled if\r
149                 it has not yet started executing.  */\r
150                 prvExample_DeferredJobAndCancellingJobs();\r
151 \r
152                 /* Demonstrate the most basic use of a recyclable job.  This is similar\r
153                 to prvExample_BasicSingleJob() but using a recyclable job.  Creating a\r
154                 recyclable job will re-use a previously created and now spare job from\r
155                 the task pool's job cache if one is available, or otherwise dynamically\r
156                 create a new job if a spare job is not available in the cache but space\r
157                 remains in the cache. */\r
158                 prvExample_BasicRecyclableJob();\r
159 \r
160                 /* Demonstrate multiple recyclable jobs being created, used, and then\r
161                 re-used.  In this the task pool worker tasks (in which the job callback\r
162                 functions execute) have a priority above the priority of this task so\r
163                 the job's callback functions execute as soon as they are scheduled. */\r
164                 prvExample_ReuseRecyclableJobFromLowPriorityTask();\r
165 \r
166                 /* Again demonstrate multiple recyclable jobs being used, but this time\r
167                 the priority of the task pool worker tasks (in which the job callback\r
168                 functions execute) are lower than the priority of this task so the job's\r
169                 callback functions don't execute until this task enteres the blocked\r
170                 state. */\r
171                 prvExample_ReuseRecyclableJobFromHighPriorityTask();\r
172 \r
173                 ulLoops++;\r
174                 if( ( ulLoops % 10UL ) == 0 )\r
175                 {\r
176                         printf( "prvTaskPoolDemoTask() performed %u iterations without hitting an assert.\r\n", ulLoops );\r
177                         fflush( stdout );\r
178                 }\r
179         }\r
180 }\r
181 /*-----------------------------------------------------------*/\r
182 \r
183 static void prvSimpleTaskNotifyCallback( IotTaskPool_t pTaskPool, IotTaskPoolJob_t pJob, void *pUserContext )\r
184 {\r
185 /* The jobs context is the handle of the task to which a notification should\r
186 be sent. */\r
187 TaskHandle_t xTaskToNotify = ( TaskHandle_t ) pUserContext;\r
188 \r
189         /* Remove warnings about unused parameters. */\r
190         ( void ) pTaskPool;\r
191         ( void ) pJob;\r
192 \r
193         /* Notify the task that created this job. */\r
194         xTaskNotifyGive( xTaskToNotify );\r
195 }\r
196 /*-----------------------------------------------------------*/\r
197 \r
198 static void prvExample_BasicSingleJob( void )\r
199 {\r
200 IotTaskPoolJobStorage_t xJobStorage;\r
201 IotTaskPoolJob_t xJob;\r
202 IotTaskPoolError_t xResult;\r
203 uint32_t ulReturn;\r
204 const uint32_t ulNoFlags = 0UL;\r
205 const TickType_t xNoDelay = ( TickType_t ) 0;\r
206 size_t xFreeHeapBeforeCreatingJob = xPortGetFreeHeapSize();\r
207 IotTaskPoolJobStatus_t xJobStatus;\r
208 \r
209         /* Don't expect any notifications to be pending yet. */\r
210         configASSERT( ulTaskNotifyTake( pdTRUE, 0 ) == 0 );\r
211 \r
212         /* Create and schedule a job using the handle of this task as the job's\r
213         context and the function that sends a notification to the task handle as\r
214         the jobs callback function.  This is not a recyclable job so the storage\r
215         required to hold information about the job is provided by this task - in\r
216         this case the storage is on the stack of this task so no memory is allocated\r
217         dynamically but the stack frame must remain in scope for the lifetime of\r
218         the job. */\r
219         xResult = IotTaskPool_CreateJob(  prvSimpleTaskNotifyCallback, /* Callback function. */\r
220                                                                           ( void * ) xTaskGetCurrentTaskHandle(), /* Job context. */\r
221                                                                           &xJobStorage,\r
222                                                                           &xJob );\r
223         configASSERT( xResult == IOT_TASKPOOL_SUCCESS );\r
224 \r
225         /* The job has been created but not scheduled so is now ready. */\r
226         IotTaskPool_GetStatus( NULL, xJob, &xJobStatus );\r
227         configASSERT( xJobStatus == IOT_TASKPOOL_STATUS_READY );\r
228 \r
229         /* This is not a persistent (recyclable) job and its storage is on the\r
230         stack of this function, so the amount of heap space available should not\r
231         have chanced since entering this function. */\r
232         configASSERT( xFreeHeapBeforeCreatingJob == xPortGetFreeHeapSize() );\r
233 \r
234         /* In the full task pool implementation the first parameter is used to\r
235         pass the handle of the task pool to schedule.  The lean task pool\r
236         implementation used in this demo only supports a single task pool, which\r
237         is created internally within the library, so the first parameter is NULL. */\r
238         xResult = IotTaskPool_Schedule( NULL, xJob, ulNoFlags );\r
239         configASSERT( xResult == IOT_TASKPOOL_SUCCESS );\r
240 \r
241         /* Look for the notification coming from the job's callback function.  The\r
242         priority of the task pool worker task that executes the callback is higher\r
243         than the priority of this task so a block time is not needed - the task pool\r
244         worker task     pre-empts this task and sends the notification (from the job's\r
245         callback) as soon as the job is scheduled. */\r
246         ulReturn = ulTaskNotifyTake( pdTRUE, xNoDelay );\r
247         configASSERT( ulReturn );\r
248 \r
249         /* The job's callback has executed so the job has now completed. */\r
250         IotTaskPool_GetStatus( NULL, xJob, &xJobStatus );\r
251         configASSERT( xJobStatus == IOT_TASKPOOL_STATUS_COMPLETED );\r
252 }\r
253 /*-----------------------------------------------------------*/\r
254 \r
255 static void prvExample_DeferredJobAndCancellingJobs( void )\r
256 {\r
257 IotTaskPoolJobStorage_t xJobStorage;\r
258 IotTaskPoolJob_t xJob;\r
259 IotTaskPoolError_t xResult;\r
260 uint32_t ulReturn;\r
261 const uint32_t ulShortDelay_ms = 100UL;\r
262 const TickType_t xNoDelay = ( TickType_t ) 0, xAllowableMargin = ( TickType_t ) 5; /* Large margin for Windows port, which is not real time. */\r
263 TickType_t xTimeBefore, xElapsedTime, xShortDelay_ticks;\r
264 size_t xFreeHeapBeforeCreatingJob = xPortGetFreeHeapSize();\r
265 IotTaskPoolJobStatus_t xJobStatus;\r
266 \r
267         /* Don't expect any notifications to be pending yet. */\r
268         configASSERT( ulTaskNotifyTake( pdTRUE, 0 ) == 0 );\r
269 \r
270         /* Create a job using the handle of this task as the job's context and the\r
271         function that sends a notification to the task handle as the jobs callback\r
272         function.  The job is created using storage allocated on the stack of this\r
273         function - so no memory is allocated. */\r
274         xResult = IotTaskPool_CreateJob(  prvSimpleTaskNotifyCallback, /* Callback function. */\r
275                                                                           ( void * ) xTaskGetCurrentTaskHandle(), /* Job context. */\r
276                                                                           &xJobStorage,\r
277                                                                           &xJob );\r
278         configASSERT( xResult == IOT_TASKPOOL_SUCCESS );\r
279 \r
280         /* The job has been created but not scheduled so is now ready. */\r
281         IotTaskPool_GetStatus( NULL, xJob, &xJobStatus );\r
282         configASSERT( xJobStatus == IOT_TASKPOOL_STATUS_READY );\r
283 \r
284         /* This is not a persistent (recyclable) job and its storage is on the\r
285         stack of this function, so the amount of heap space available should not\r
286         have chanced since entering this function. */\r
287         configASSERT( xFreeHeapBeforeCreatingJob == xPortGetFreeHeapSize() );\r
288 \r
289         /* Schedule the job to run its callback in xShortDelay_ms milliseconds time.\r
290         In the full task pool implementation the first parameter is used to     pass the\r
291         handle of the task pool to schedule.  The lean task pool implementation used\r
292         in this demo only supports a single task pool, which is created internally\r
293         within the library, so the first parameter is NULL. */\r
294         xResult = IotTaskPool_ScheduleDeferred( NULL, xJob, ulShortDelay_ms );\r
295         configASSERT( xResult == IOT_TASKPOOL_SUCCESS );\r
296 \r
297         /* The scheduled job should not have executed yet, so don't expect any\r
298         notifications and expect the job's status to be 'deferred'. */\r
299         ulReturn = ulTaskNotifyTake( pdTRUE, xNoDelay );\r
300         configASSERT( ulReturn == 0 );\r
301         IotTaskPool_GetStatus( NULL, xJob, &xJobStatus );\r
302         configASSERT( xJobStatus == IOT_TASKPOOL_STATUS_DEFERRED );\r
303 \r
304         /* As the job has not yet been executed it can be stopped. */\r
305         xResult = IotTaskPool_TryCancel( NULL, xJob, &xJobStatus );\r
306         configASSERT( xResult == IOT_TASKPOOL_SUCCESS );\r
307         IotTaskPool_GetStatus( NULL, xJob, &xJobStatus );\r
308         configASSERT( xJobStatus == IOT_TASKPOOL_STATUS_CANCELED );\r
309 \r
310         /* Schedule the job again, and this time wait until its callback is\r
311         executed (the callback function sends a notification to this task) to see\r
312         that it executes at the right time. */\r
313         xTimeBefore = xTaskGetTickCount();\r
314         xResult = IotTaskPool_ScheduleDeferred( NULL, xJob, ulShortDelay_ms );\r
315         configASSERT( xResult == IOT_TASKPOOL_SUCCESS );\r
316 \r
317         /* Wait twice the deferred execution time to ensure the callback is executed\r
318         before the call below times out. */\r
319         ulReturn = ulTaskNotifyTake( pdTRUE, pdMS_TO_TICKS( ulShortDelay_ms * 2UL ) );\r
320         xElapsedTime = xTaskGetTickCount() - xTimeBefore;\r
321 \r
322         /* A single notification should not have been received... */\r
323         configASSERT( ulReturn == 1 );\r
324 \r
325         /* ...and the time since scheduling the job should be greater than or\r
326         equal to the deferred execution time - which is converted to ticks for\r
327         comparison. */\r
328         xShortDelay_ticks = pdMS_TO_TICKS( ulShortDelay_ms );\r
329         configASSERT( ( xElapsedTime >= xShortDelay_ticks ) && ( xElapsedTime  < ( xShortDelay_ticks + xAllowableMargin ) ) );\r
330 }\r
331 /*-----------------------------------------------------------*/\r
332 \r
333 static void prvExample_BasicRecyclableJob( void )\r
334 {\r
335 IotTaskPoolJob_t xJob;\r
336 IotTaskPoolError_t xResult;\r
337 uint32_t ulReturn;\r
338 const uint32_t ulNoFlags = 0UL;\r
339 const TickType_t xNoDelay = ( TickType_t ) 0;\r
340 size_t xFreeHeapBeforeCreatingJob = xPortGetFreeHeapSize();\r
341 \r
342         /* Don't expect any notifications to be pending yet. */\r
343         configASSERT( ulTaskNotifyTake( pdTRUE, 0 ) == 0 );\r
344 \r
345         /* Create and schedule a job using the handle of this task as the job's\r
346         context and the function that sends a notification to the task handle as\r
347         the jobs callback function.  The job is created as a recyclable job and in\r
348         this case the memory used to hold the job status is allocated inside the\r
349         create function.  As the job is persistent it can be used multiple times,\r
350         as demonstrated in other examples within this demo.  In the full task pool\r
351         implementation the first parameter is used to pass the handle of the task\r
352         pool this recyclable job is to be associated with.  In the lean\r
353         implementation of the task pool used by this demo there is only one task\r
354         pool (the system task pool created within the task pool library) so the\r
355         first parameter is NULL. */\r
356         xResult = IotTaskPool_CreateRecyclableJob( NULL,\r
357                                                                                            prvSimpleTaskNotifyCallback,\r
358                                                                                            (void * ) xTaskGetCurrentTaskHandle(),\r
359                                                                                            &xJob );\r
360         configASSERT( xResult == IOT_TASKPOOL_SUCCESS );\r
361 \r
362         /* This recyclable job is persistent, and in this case created dynamically,\r
363         so expect there to be less heap space then when entering the function. */\r
364         configASSERT( xPortGetFreeHeapSize() < xFreeHeapBeforeCreatingJob );\r
365 \r
366         /* In the full task pool implementation the first parameter is used to\r
367         pass the handle of the task pool to schedule.  The lean task pool\r
368         implementation used in this demo only supports a single task pool, which\r
369         is created internally within the library, so the first parameter is NULL. */\r
370         xResult = IotTaskPool_Schedule( NULL, xJob, ulNoFlags );\r
371         configASSERT( xResult == IOT_TASKPOOL_SUCCESS );\r
372 \r
373         /* Look for the notification coming from the job's callback function.  The\r
374         priority of the task pool worker task that executes the callback is higher\r
375         than the priority of this task so a block time is not needed - the task pool\r
376         worker task     pre-empts this task and sends the notification (from the job's\r
377         callback) as soon as the job is scheduled. */\r
378         ulReturn = ulTaskNotifyTake( pdTRUE, xNoDelay );\r
379         configASSERT( ulReturn );\r
380 \r
381         /* Clean up recyclable job.  In the full implementation of the task pool\r
382         the first parameter is used to pass a handle to the task pool the job is\r
383         associated with.  In the lean implementation of the task pool used by this\r
384         demo there is only one task pool (the system task pool created in the\r
385         task pool library itself) so the first parameter is NULL. */\r
386         IotTaskPool_DestroyRecyclableJob( NULL, xJob );\r
387 \r
388         /* Once the job has been deleted the memory used to hold the job is\r
389         returned, so the available heap should be exactly as when entering this\r
390         function. */\r
391         configASSERT( xPortGetFreeHeapSize() == xFreeHeapBeforeCreatingJob );\r
392 }\r
393 /*-----------------------------------------------------------*/\r
394 \r
395 static void prvExample_ReuseRecyclableJobFromLowPriorityTask( void )\r
396 {\r
397 IotTaskPoolError_t xResult;\r
398 uint32_t x, xIndex, ulNotificationValue;\r
399 const uint32_t ulNoFlags = 0UL;\r
400 IotTaskPoolJob_t xJobs[ tpJOBS_TO_CREATE ];\r
401 size_t xFreeHeapBeforeCreatingJob = xPortGetFreeHeapSize();\r
402 IotTaskPoolJobStatus_t xJobStatus;\r
403 \r
404         /* Don't expect any notifications to be pending yet. */\r
405         configASSERT( ulTaskNotifyTake( pdTRUE, 0 ) == 0 );\r
406 \r
407         /* Create tpJOBS_TO_CREATE jobs using the handle of this task as the job's\r
408         context and the function that sends a notification to the task handle as\r
409         the jobs callback function.  The jobs are created as a recyclable job and\r
410         in this case the memory to store the job information is allocated within\r
411         the create function as at this time there are no recyclable jobs in the\r
412         task pool jobs cache. As the jobs are persistent they can be used multiple\r
413         times.  In the full task pool implementation the first parameter is used to\r
414         pass the handle of the task pool this recyclable job is to be associated\r
415         with.  In the lean implementation of the task pool used by this demo there\r
416         is only one task pool (the system task pool created within the task pool\r
417         library) so the first parameter is NULL. */\r
418         for( x = 0; x < tpJOBS_TO_CREATE; x++ )\r
419         {\r
420                 xResult = IotTaskPool_CreateRecyclableJob( NULL,\r
421                                                                                                    prvSimpleTaskNotifyCallback,\r
422                                                                                                    (void * ) xTaskGetCurrentTaskHandle(),\r
423                                                                                                    &( xJobs[ x ] ) );\r
424                 configASSERT( xResult == IOT_TASKPOOL_SUCCESS );\r
425 \r
426                 /* The job has been created but not scheduled so is now ready. */\r
427                 IotTaskPool_GetStatus( NULL, xJobs[ x ], &xJobStatus );\r
428                 configASSERT( xJobStatus == IOT_TASKPOOL_STATUS_READY );\r
429         }\r
430 \r
431         /* Demonstrate that the jobs can be recycled by performing twice the number\r
432         of iterations of scheduling jobs than there actually are created jobs.  This\r
433         works because the task pool task priorities are above the priority of this\r
434         task, so the tasks that run the jobs pre-empt this task as soon as a job is\r
435         ready. */\r
436         for( x = 0; x < ( tpJOBS_TO_CREATE * 2UL ); x++ )\r
437         {\r
438                 /* Make sure array index does not go out of bounds. */\r
439                 xIndex = x % tpJOBS_TO_CREATE;\r
440 \r
441                 xResult = IotTaskPool_Schedule( NULL, xJobs[ xIndex ], ulNoFlags );\r
442                 configASSERT( xResult == IOT_TASKPOOL_SUCCESS );\r
443 \r
444                 /* The priority of the task pool task(s) is higher than the priority\r
445                 of this task, so the job's callback function should have already\r
446                 executed, sending a notification to this task, and incrementing this\r
447                 task's notification value. */\r
448                 xTaskNotifyWait( 0UL, /* Don't clear any bits on entry. */\r
449                                                  0UL, /* Don't clear any bits on exit. */\r
450                                                  &ulNotificationValue, /* Obtain the notification value. */\r
451                                                  0UL ); /* No block time, return immediately. */\r
452                 configASSERT( ulNotificationValue == ( x + 1 ) );\r
453 \r
454                 /* The job's callback has executed so the job is now completed. */\r
455                 IotTaskPool_GetStatus( NULL, xJobs[ xIndex ], &xJobStatus );\r
456                 configASSERT( xJobStatus == IOT_TASKPOOL_STATUS_COMPLETED );\r
457 \r
458                 /* To leave the list of jobs empty we can stop re-creating jobs half\r
459                 way through iterations of this loop. */\r
460                 if( x < tpJOBS_TO_CREATE )\r
461                 {\r
462                         /* Recycle the job so it can be used again.  In the full task pool\r
463                         implementation the first parameter is used to pass the handle of the\r
464                         task pool this job will be associated with.  In this lean task pool\r
465                         implementation only the system task pool exists (the task pool created\r
466                         internally to the task pool library) so the first parameter is just\r
467                         passed as NULL. *//*_RB_ Why not recycle it automatically? */\r
468                         IotTaskPool_RecycleJob( NULL, xJobs[ xIndex ] );\r
469                         xResult = IotTaskPool_CreateRecyclableJob( NULL,\r
470                                                                                                            prvSimpleTaskNotifyCallback,\r
471                                                                                                            (void * ) xTaskGetCurrentTaskHandle(),\r
472                                                                                                            &( xJobs[ xIndex ] ) );\r
473                         configASSERT( xResult == IOT_TASKPOOL_SUCCESS );\r
474                 }\r
475         }\r
476 \r
477         /* Clear all the notification value bits again. */\r
478         xTaskNotifyWait( portMAX_DELAY, /* Clear all bits on entry - portMAX_DELAY is used as it is a portable way of having all bits set. */\r
479                                          0UL, /* Don't clear any bits on exit. */\r
480                                          NULL, /* Don't need the notification value this time. */\r
481                                          0UL ); /* No block time, return immediately. */\r
482         configASSERT( ulTaskNotifyTake( pdTRUE, 0 ) == 0 );\r
483 \r
484         /* Clean up all the recyclable job.  In the full implementation of the task\r
485         pool the first parameter is used to pass a handle to the task pool the job\r
486         is associated with.  In the lean implementation of the task pool used by\r
487         this demo there is only one task pool (the system task pool created in the\r
488         task pool library itself) so the first parameter is NULL. */\r
489         for( x = 0; x < tpJOBS_TO_CREATE; x++ )\r
490         {\r
491                 xResult = IotTaskPool_DestroyRecyclableJob( NULL, xJobs[ x ] );\r
492                 configASSERT( xResult == IOT_TASKPOOL_SUCCESS );\r
493         }\r
494 \r
495         /* Once the job has been deleted the memory used to hold the job is\r
496         returned, so the available heap should be exactly as when entering this\r
497         function. */\r
498         configASSERT( xPortGetFreeHeapSize() == xFreeHeapBeforeCreatingJob );\r
499 }\r
500 /*-----------------------------------------------------------*/\r
501 \r
502 static void prvExample_ReuseRecyclableJobFromHighPriorityTask( void )\r
503 {\r
504 IotTaskPoolError_t xResult;\r
505 uint32_t x, ulNotificationValue;\r
506 const uint32_t ulNoFlags = 0UL;\r
507 IotTaskPoolJob_t xJobs[ tpJOBS_TO_CREATE ];\r
508 IotTaskPoolJobStorage_t xJobStorage[ tpJOBS_TO_CREATE ];\r
509 size_t xFreeHeapBeforeCreatingJob = xPortGetFreeHeapSize();\r
510 TickType_t xShortDelay = pdMS_TO_TICKS( 150 );\r
511 IotTaskPoolJobStatus_t xJobStatus;\r
512 \r
513         /* Don't expect any notifications to be pending yet. */\r
514         configASSERT( ulTaskNotifyTake( pdTRUE, 0 ) == 0 );\r
515 \r
516         /* prvExample_ReuseRecyclableJobFromLowPriorityTask() executes in a task\r
517         that has a lower [task] priority than the task pool's worker tasks.\r
518         Therefore a talk pool worker preempts the task that calls\r
519         prvExample_ReuseRecyclableJobFromHighPriorityTask() as soon as the job is\r
520         scheduled.  prvExample_ReuseRecyclableJobFromHighPriorityTask() reverses the\r
521         priorities - prvExample_ReuseRecyclableJobFromHighPriorityTask() raises its\r
522         priority to above the task pool's worker tasks, so the worker tasks do not\r
523         execute until the calling task enters the blocked state.  First raise the\r
524         priority - passing NULL means raise the priority of the calling task. */\r
525         vTaskPrioritySet( NULL, tpTASK_POOL_WORKER_PRIORITY + 1 );\r
526 \r
527         /* Create tpJOBS_TO_CREATE jobs using the handle of this task as the job's\r
528         context and the function that sends a notification to the task handle as\r
529         the jobs callback function. */\r
530         for( x = 0; x < tpJOBS_TO_CREATE; x++ )\r
531         {\r
532                 xResult = IotTaskPool_CreateJob(  prvSimpleTaskNotifyCallback, /* Callback function. */\r
533                                                                                   ( void * ) xTaskGetCurrentTaskHandle(), /* Job context. */\r
534                                                                                   &( xJobStorage[ x ] ),\r
535                                                                                   &( xJobs[ x ] ) );\r
536                 configASSERT( xResult == IOT_TASKPOOL_SUCCESS );\r
537 \r
538                 /* This is not a persistent (recyclable) job and its storage is on the\r
539                 stack of this function, so the amount of heap space available should not\r
540                 have chanced since entering this function. */\r
541                 configASSERT( xFreeHeapBeforeCreatingJob == xPortGetFreeHeapSize() );\r
542         }\r
543 \r
544         for( x = 0; x < tpJOBS_TO_CREATE; x++ )\r
545         {\r
546                 /* Schedule the next job. */\r
547                 xResult = IotTaskPool_Schedule( NULL, xJobs[ x ], ulNoFlags );\r
548                 configASSERT( xResult == IOT_TASKPOOL_SUCCESS );\r
549 \r
550                 /* Although scheduled, the job's callback has not executed, so the job\r
551                 reports itself as scheduled. */\r
552                 IotTaskPool_GetStatus( NULL, xJobs[ x ], &xJobStatus );\r
553                 configASSERT( xJobStatus == IOT_TASKPOOL_STATUS_SCHEDULED );\r
554 \r
555                 /* The priority of the task pool task(s) is lower than the priority\r
556                 of this task, so the job's callback function should not have executed\r
557                 yes, so don't expect the notification value for this task to have\r
558                 changed. */\r
559                 xTaskNotifyWait( 0UL, /* Don't clear any bits on entry. */\r
560                                                  0UL, /* Don't clear any bits on exit. */\r
561                                                  &ulNotificationValue, /* Obtain the notification value. */\r
562                                                  0UL ); /* No block time, return immediately. */\r
563                 configASSERT( ulNotificationValue == 0 );\r
564         }\r
565 \r
566         /* At this point there are tpJOBS_TO_CREATE scheduled, but none have executed\r
567         their callbacks because the priority of this task is higher than the\r
568         priority of the task pool worker threads.  When this task blocks to wait for\r
569         a notification a worker thread will be able to executes - but as soon as its\r
570         callback function sends a notification to this task this task will\r
571         preempt it (because it has a higher priority) so this task only expects to\r
572         receive one notification at a time. */\r
573         for( x = 0; x < tpJOBS_TO_CREATE; x++ )\r
574         {\r
575                 xTaskNotifyWait( 0UL, /* Don't clear any bits on entry. */\r
576                                                  0UL, /* Don't clear any bits on exit. */\r
577                                                  &ulNotificationValue, /* Obtain the notification value. */\r
578                                                  xShortDelay ); /* Short delay to allow a task pool worker to execute. */\r
579                 configASSERT( ulNotificationValue == ( x + 1 ) );\r
580         }\r
581 \r
582         /* All the scheduled jobs have now executed, so waiting for another\r
583         notification should timeout without the notification value changing. */\r
584         xTaskNotifyWait( 0UL, /* Don't clear any bits on entry. */\r
585                                          0UL, /* Don't clear any bits on exit. */\r
586                                          &ulNotificationValue, /* Obtain the notification value. */\r
587                                          xShortDelay ); /* Short delay to allow a task pool worker to execute. */\r
588         configASSERT( ulNotificationValue == x );\r
589 \r
590         /* Reset the priority of this task and clear the notifications ready for the\r
591         next example. */\r
592         vTaskPrioritySet( NULL, tskIDLE_PRIORITY );\r
593         xTaskNotifyWait( portMAX_DELAY, /* Clear all bits on entry - portMAX_DELAY is used as it is a portable way of having all bits set. */\r
594                                          0UL, /* Don't clear any bits on exit. */\r
595                                          NULL, /* Don't need the notification value this time. */\r
596                                          0UL ); /* No block time, return immediately. */\r
597 }\r
598 /*-----------------------------------------------------------*/\r
599 \r