]> git.sur5r.net Git - freertos/blob - FreeRTOS-Plus/Demo/FreeRTOS_Plus_IoT_SDK/task_pool/DemoTasks/SimpleTaskPoolExamples.c
Remove any TCP/IP functionality from the task pool demo - the TCP/IP stack is still...
[freertos] / FreeRTOS-Plus / Demo / FreeRTOS_Plus_IoT_SDK / 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_DeferredSingleJob( 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_DeferredSingleJob();\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 TaskHandle_t xTaskToNotify = ( TaskHandle_t ) pUserContext;\r
186 \r
187         /* Remove warnings about unused parameters. */\r
188         ( void ) pTaskPool;\r
189         ( void ) pJob;\r
190 \r
191         /* Notify the task that created this job. */\r
192         xTaskNotifyGive( xTaskToNotify );\r
193 }\r
194 /*-----------------------------------------------------------*/\r
195 \r
196 static void prvExample_BasicSingleJob( void )\r
197 {\r
198 IotTaskPoolJobStorage_t xJobStorage;\r
199 IotTaskPoolJob_t xJob;\r
200 IotTaskPoolError_t xResult;\r
201 uint32_t ulReturn;\r
202 const uint32_t ulNoFlags = 0UL;\r
203 const TickType_t xNoDelay = ( TickType_t ) 0;\r
204 size_t xFreeHeapBeforeCreatingJob = xPortGetFreeHeapSize();\r
205 IotTaskPoolJobStatus_t xJobStatus;\r
206 \r
207         /* Don't expect any notifications to be pending yet. */\r
208         configASSERT( ulTaskNotifyTake( pdTRUE, 0 ) == 0 );\r
209 \r
210         /* Create and schedule a job using the handle of this task as the job's\r
211         context and the function that sends a notification to the task handle as\r
212         the jobs callback function.  This is not a recyclable job so the storage\r
213         required to hold information about the job is provided by this task - in\r
214         this case the storage is on the stack of this task so no memory is allocated\r
215         dynamically but the stack frame must remain in scope for the lifetime of\r
216         the job. */\r
217         xResult = IotTaskPool_CreateJob(  prvSimpleTaskNotifyCallback, /* Callback function. */\r
218                                                                           ( void * ) xTaskGetCurrentTaskHandle(), /* Job context. */\r
219                                                                           &xJobStorage,\r
220                                                                           &xJob );\r
221         configASSERT( xResult == IOT_TASKPOOL_SUCCESS );\r
222 \r
223         /* The job has been created but not scheduled so is now ready. */\r
224         IotTaskPool_GetStatus( NULL, xJob, &xJobStatus );\r
225         configASSERT( xJobStatus == IOT_TASKPOOL_STATUS_READY );\r
226 \r
227         /* This is not a persistent (recyclable) job and its storage is on the\r
228         stack of this function, so the amount of heap space available should not\r
229         have chanced since entering this function. */\r
230         configASSERT( xFreeHeapBeforeCreatingJob == xPortGetFreeHeapSize() );\r
231 \r
232         /* In the full task pool implementation the first parameter is used to\r
233         pass the handle of the task pool to schedule.  The lean task pool\r
234         implementation used in this demo only supports a single task pool, which\r
235         is created internally within the library, so the first parameter is NULL. */\r
236         xResult = IotTaskPool_Schedule( NULL, xJob, ulNoFlags );\r
237         configASSERT( xResult == IOT_TASKPOOL_SUCCESS );\r
238 \r
239         /* Look for the notification coming from the job's callback function.  The\r
240         priority of the task pool worker task that executes the callback is higher\r
241         than the priority of this task so a block time is not needed - the task pool\r
242         worker task     pre-empts this task and sends the notification (from the job's\r
243         callback) as soon as the job is scheduled. */\r
244         ulReturn = ulTaskNotifyTake( pdTRUE, xNoDelay );\r
245         configASSERT( ulReturn );\r
246 \r
247         /* The job's callback has executed so the job has now completed. */\r
248         IotTaskPool_GetStatus( NULL, xJob, &xJobStatus );\r
249         configASSERT( xJobStatus == IOT_TASKPOOL_STATUS_COMPLETED );\r
250 }\r
251 /*-----------------------------------------------------------*/\r
252 \r
253 static void prvExample_DeferredSingleJob( void )\r
254 {\r
255 IotTaskPoolJobStorage_t xJobStorage;\r
256 IotTaskPoolJob_t xJob;\r
257 IotTaskPoolError_t xResult;\r
258 uint32_t ulReturn;\r
259 const uint32_t ulShortDelay_ms = 100UL;\r
260 const TickType_t xNoDelay = ( TickType_t ) 0, xAllowableMargin = ( TickType_t ) 5; /* Large margin for Windows port, which is not real time. */\r
261 TickType_t xTimeBefore, xElapsedTime, xShortDelay_ticks;\r
262 size_t xFreeHeapBeforeCreatingJob = xPortGetFreeHeapSize();\r
263 IotTaskPoolJobStatus_t xJobStatus;\r
264 \r
265         /* Don't expect any notifications to be pending yet. */\r
266         configASSERT( ulTaskNotifyTake( pdTRUE, 0 ) == 0 );\r
267 \r
268         /* Create a job using the handle of this task as the job's context and the\r
269         function that sends a notification to the task handle as the jobs callback\r
270         function.  The job is created using storage allocated on the stack of this\r
271         function - so no memory is allocated. */\r
272         xResult = IotTaskPool_CreateJob(  prvSimpleTaskNotifyCallback, /* Callback function. */\r
273                                                                           ( void * ) xTaskGetCurrentTaskHandle(), /* Job context. */\r
274                                                                           &xJobStorage,\r
275                                                                           &xJob );\r
276         configASSERT( xResult == IOT_TASKPOOL_SUCCESS );\r
277 \r
278         /* The job has been created but not scheduled so is now ready. */\r
279         IotTaskPool_GetStatus( NULL, xJob, &xJobStatus );\r
280         configASSERT( xJobStatus == IOT_TASKPOOL_STATUS_READY );\r
281 \r
282         /* This is not a persistent (recyclable) job and its storage is on the\r
283         stack of this function, so the amount of heap space available should not\r
284         have chanced since entering this function. */\r
285         configASSERT( xFreeHeapBeforeCreatingJob == xPortGetFreeHeapSize() );\r
286 \r
287         /* Schedule the job to run its callback in xShortDelay_ms milliseconds time.\r
288         In the full task pool implementation the first parameter is used to     pass the\r
289         handle of the task pool to schedule.  The lean task pool implementation used\r
290         in this demo only supports a single task pool, which is created internally\r
291         within the library, so the first parameter is NULL. */\r
292         xResult = IotTaskPool_ScheduleDeferred( NULL, xJob, ulShortDelay_ms );\r
293         configASSERT( xResult == IOT_TASKPOOL_SUCCESS );\r
294 \r
295         /* The scheduled job should not have executed yet, so don't expect any\r
296         notifications and expect the job's status to be 'deferred'. */\r
297         ulReturn = ulTaskNotifyTake( pdTRUE, xNoDelay );\r
298         configASSERT( ulReturn == 0 );\r
299         IotTaskPool_GetStatus( NULL, xJob, &xJobStatus );\r
300         configASSERT( xJobStatus == IOT_TASKPOOL_STATUS_DEFERRED );\r
301 \r
302         /* As the job has not yet been executed it can be stopped. */\r
303         xResult = IotTaskPool_TryCancel( NULL, xJob, &xJobStatus );\r
304         configASSERT( xResult == IOT_TASKPOOL_SUCCESS );\r
305         IotTaskPool_GetStatus( NULL, xJob, &xJobStatus );\r
306         configASSERT( xJobStatus == IOT_TASKPOOL_STATUS_CANCELED );\r
307 \r
308         /* Schedule the job again, and this time wait until its callback is\r
309         executed (the callback function sends a notification to this task) to see\r
310         that it executes at the right time. */\r
311         xTimeBefore = xTaskGetTickCount();\r
312         xResult = IotTaskPool_ScheduleDeferred( NULL, xJob, ulShortDelay_ms );\r
313         configASSERT( xResult == IOT_TASKPOOL_SUCCESS );\r
314 \r
315         /* Wait twice the deferred execution time to ensure the callback is executed\r
316         before the call below times out. */\r
317         ulReturn = ulTaskNotifyTake( pdTRUE, pdMS_TO_TICKS( ulShortDelay_ms * 2UL ) );\r
318         xElapsedTime = xTaskGetTickCount() - xTimeBefore;\r
319 \r
320         /* A single notification should not have been received... */\r
321         configASSERT( ulReturn == 1 );\r
322 \r
323         /* ...and the time since scheduling the job should be greater than or\r
324         equal to the deferred execution time - which is converted to ticks for\r
325         comparison. */\r
326         xShortDelay_ticks = pdMS_TO_TICKS( ulShortDelay_ms );\r
327         configASSERT( ( xElapsedTime >= xShortDelay_ticks ) && ( xElapsedTime  < ( xShortDelay_ticks + xAllowableMargin ) ) );\r
328 }\r
329 /*-----------------------------------------------------------*/\r
330 \r
331 static void prvExample_BasicRecyclableJob( void )\r
332 {\r
333 IotTaskPoolJob_t xJob;\r
334 IotTaskPoolError_t xResult;\r
335 uint32_t ulReturn;\r
336 const uint32_t ulNoFlags = 0UL;\r
337 const TickType_t xNoDelay = ( TickType_t ) 0;\r
338 size_t xFreeHeapBeforeCreatingJob = xPortGetFreeHeapSize();\r
339 \r
340         /* Don't expect any notifications to be pending yet. */\r
341         configASSERT( ulTaskNotifyTake( pdTRUE, 0 ) == 0 );\r
342 \r
343         /* Create and schedule a job using the handle of this task as the job's\r
344         context and the function that sends a notification to the task handle as\r
345         the jobs callback function.  The job is created as a recyclable job and in\r
346         this case the memory used to hold the job status is allocated inside the\r
347         create function.  As the job is persistent it can be used multiple times,\r
348         as demonstrated in other examples within this demo.  In the full task pool\r
349         implementation the first parameter is used to pass the handle of the task\r
350         pool this recyclable job is to be associated with.  In the lean\r
351         implementation of the task pool used by this demo there is only one task\r
352         pool (the system task pool created within the task pool library) so the\r
353         first parameter is NULL. */\r
354         xResult = IotTaskPool_CreateRecyclableJob( NULL,\r
355                                                                                            prvSimpleTaskNotifyCallback,\r
356                                                                                            (void * ) xTaskGetCurrentTaskHandle(),\r
357                                                                                            &xJob );\r
358         configASSERT( xResult == IOT_TASKPOOL_SUCCESS );\r
359 \r
360         /* This recyclable job is persistent, and in this case created dynamically,\r
361         so expect there to be less heap space then when entering the function. */\r
362         configASSERT( xPortGetFreeHeapSize() < xFreeHeapBeforeCreatingJob );\r
363 \r
364         /* In the full task pool implementation the first parameter is used to\r
365         pass the handle of the task pool to schedule.  The lean task pool\r
366         implementation used in this demo only supports a single task pool, which\r
367         is created internally within the library, so the first parameter is NULL. */\r
368         xResult = IotTaskPool_Schedule( NULL, xJob, ulNoFlags );\r
369         configASSERT( xResult == IOT_TASKPOOL_SUCCESS );\r
370 \r
371         /* Look for the notification coming from the job's callback function.  The\r
372         priority of the task pool worker task that executes the callback is higher\r
373         than the priority of this task so a block time is not needed - the task pool\r
374         worker task     pre-empts this task and sends the notification (from the job's\r
375         callback) as soon as the job is scheduled. */\r
376         ulReturn = ulTaskNotifyTake( pdTRUE, xNoDelay );\r
377         configASSERT( ulReturn );\r
378 \r
379         /* Clean up recyclable job.  In the full implementation of the task pool\r
380         the first parameter is used to pass a handle to the task pool the job is\r
381         associated with.  In the lean implementation of the task pool used by this\r
382         demo there is only one task pool (the system task pool created in the\r
383         task pool library itself) so the first parameter is NULL. */\r
384         IotTaskPool_DestroyRecyclableJob( NULL, xJob );\r
385 \r
386         /* Once the job has been deleted the memory used to hold the job is\r
387         returned, so the available heap should be exactly as when entering this\r
388         function. */\r
389         configASSERT( xPortGetFreeHeapSize() == xFreeHeapBeforeCreatingJob );\r
390 }\r
391 /*-----------------------------------------------------------*/\r
392 \r
393 static void prvExample_ReuseRecyclableJobFromLowPriorityTask( void )\r
394 {\r
395 IotTaskPoolError_t xResult;\r
396 uint32_t x, xIndex, ulNotificationValue;\r
397 const uint32_t ulNoFlags = 0UL;\r
398 IotTaskPoolJob_t xJobs[ tpJOBS_TO_CREATE ];\r
399 size_t xFreeHeapBeforeCreatingJob = xPortGetFreeHeapSize();\r
400 IotTaskPoolJobStatus_t xJobStatus;\r
401 \r
402         /* Don't expect any notifications to be pending yet. */\r
403         configASSERT( ulTaskNotifyTake( pdTRUE, 0 ) == 0 );\r
404 \r
405         /* Create tpJOBS_TO_CREATE jobs using the handle of this task as the job's\r
406         context and the function that sends a notification to the task handle as\r
407         the jobs callback function.  The jobs are created as a recyclable job and\r
408         in this case the memory to store the job information is allocated within\r
409         the create function as at this time there are no recyclable jobs in the\r
410         task pool jobs cache. As the jobs are persistent they can be used multiple\r
411         times.  In the full task pool implementation the first parameter is used to\r
412         pass the handle of the task pool this recyclable job is to be associated\r
413         with.  In the lean implementation of the task pool used by this demo there\r
414         is only one task pool (the system task pool created within the task pool\r
415         library) so the first parameter is NULL. */\r
416         for( x = 0; x < tpJOBS_TO_CREATE; x++ )\r
417         {\r
418                 xResult = IotTaskPool_CreateRecyclableJob( NULL,\r
419                                                                                                    prvSimpleTaskNotifyCallback,\r
420                                                                                                    (void * ) xTaskGetCurrentTaskHandle(),\r
421                                                                                                    &( xJobs[ x ] ) );\r
422                 configASSERT( xResult == IOT_TASKPOOL_SUCCESS );\r
423 \r
424                 /* The job has been created but not scheduled so is now ready. */\r
425                 IotTaskPool_GetStatus( NULL, xJobs[ x ], &xJobStatus );\r
426                 configASSERT( xJobStatus == IOT_TASKPOOL_STATUS_READY );\r
427         }\r
428 \r
429         /* Demonstrate that the jobs can be recycled by performing twice the number\r
430         of iterations of scheduling jobs than there actually are created jobs.  This\r
431         works because the task pool task priorities are above the priority of this\r
432         task, so the tasks that run the jobs pre-empt this task as soon as a job is\r
433         ready. */\r
434         for( x = 0; x < ( tpJOBS_TO_CREATE * 2UL ); x++ )\r
435         {\r
436                 /* Make sure array index does not go out of bounds. */\r
437                 xIndex = x % tpJOBS_TO_CREATE;\r
438 \r
439                 xResult = IotTaskPool_Schedule( NULL, xJobs[ xIndex ], ulNoFlags );\r
440                 configASSERT( xResult == IOT_TASKPOOL_SUCCESS );\r
441 \r
442                 /* The priority of the task pool task(s) is higher than the priority\r
443                 of this task, so the job's callback function should have already\r
444                 executed, sending a notification to this task, and incrementing this\r
445                 task's notification value. */\r
446                 xTaskNotifyWait( 0UL, /* Don't clear any bits on entry. */\r
447                                                  0UL, /* Don't clear any bits on exit. */\r
448                                                  &ulNotificationValue, /* Obtain the notification value. */\r
449                                                  0UL ); /* No block time, return immediately. */\r
450                 configASSERT( ulNotificationValue == ( x + 1 ) );\r
451 \r
452                 /* The job's callback has executed so the job is now completed. */\r
453                 IotTaskPool_GetStatus( NULL, xJobs[ xIndex ], &xJobStatus );\r
454                 configASSERT( xJobStatus == IOT_TASKPOOL_STATUS_COMPLETED );\r
455 \r
456                 /* To leave the list of jobs empty we can stop re-creating jobs half\r
457                 way through iterations of this loop. */\r
458                 if( x < tpJOBS_TO_CREATE )\r
459                 {\r
460                         /* Recycle the job so it can be used again.  In the full task pool\r
461                         implementation the first parameter is used to pass the handle of the\r
462                         task pool this job will be associated with.  In this lean task pool\r
463                         implementation only the system task pool exists (the task pool created\r
464                         internally to the task pool library) so the first parameter is just\r
465                         passed as NULL. *//*_RB_ Why not recycle it automatically? */\r
466                         IotTaskPool_RecycleJob( NULL, xJobs[ xIndex ] );\r
467                         xResult = IotTaskPool_CreateRecyclableJob( NULL,\r
468                                                                                                            prvSimpleTaskNotifyCallback,\r
469                                                                                                            (void * ) xTaskGetCurrentTaskHandle(),\r
470                                                                                                            &( xJobs[ xIndex ] ) );\r
471                 }\r
472         }\r
473 \r
474         /* Clear all the notification value bits again. */\r
475         xTaskNotifyWait( portMAX_DELAY, /* Clear all bits on entry - portMAX_DELAY is used as it is a portable way of having all bits set. */\r
476                                          0UL, /* Don't clear any bits on exit. */\r
477                                          NULL, /* Don't need the notification value this time. */\r
478                                          0UL ); /* No block time, return immediately. */\r
479         configASSERT( ulTaskNotifyTake( pdTRUE, 0 ) == 0 );\r
480 \r
481         /* Clean up all the recyclable job.  In the full implementation of the task\r
482         pool the first parameter is used to pass a handle to the task pool the job\r
483         is associated with.  In the lean implementation of the task pool used by\r
484         this demo there is only one task pool (the system task pool created in the\r
485         task pool library itself) so the first parameter is NULL. */\r
486         for( x = 0; x < tpJOBS_TO_CREATE; x++ )\r
487         {\r
488                 xResult = IotTaskPool_DestroyRecyclableJob( NULL, xJobs[ x ] );\r
489                 configASSERT( xResult == IOT_TASKPOOL_SUCCESS );\r
490         }\r
491 \r
492         /* Once the job has been deleted the memory used to hold the job is\r
493         returned, so the available heap should be exactly as when entering this\r
494         function. */\r
495         configASSERT( xPortGetFreeHeapSize() == xFreeHeapBeforeCreatingJob );\r
496 }\r
497 /*-----------------------------------------------------------*/\r
498 \r
499 static void prvExample_ReuseRecyclableJobFromHighPriorityTask( void )\r
500 {\r
501 IotTaskPoolError_t xResult;\r
502 uint32_t x, ulNotificationValue;\r
503 const uint32_t ulNoFlags = 0UL;\r
504 IotTaskPoolJob_t xJobs[ tpJOBS_TO_CREATE ];\r
505 IotTaskPoolJobStorage_t xJobStorage[ tpJOBS_TO_CREATE ];\r
506 size_t xFreeHeapBeforeCreatingJob = xPortGetFreeHeapSize();\r
507 TickType_t xShortDelay = pdMS_TO_TICKS( 150 );\r
508 IotTaskPoolJobStatus_t xJobStatus;\r
509 \r
510         /* Don't expect any notifications to be pending yet. */\r
511         configASSERT( ulTaskNotifyTake( pdTRUE, 0 ) == 0 );\r
512 \r
513         /* prvExample_ReuseRecyclableJobFromLowPriorityTask() executes in a task\r
514         that has a lower [task] priority than the task pool's worker tasks.\r
515         Therefore a talk pool worker preempts the task that calls\r
516         prvExample_ReuseRecyclableJobFromHighPriorityTask() as soon as the job is\r
517         scheduled.  prvExample_ReuseRecyclableJobFromHighPriorityTask() reverses the\r
518         priorities - prvExample_ReuseRecyclableJobFromHighPriorityTask() raises its\r
519         priority to above the task pool's worker tasks, so the worker tasks do not\r
520         execute until the calling task enters the blocked state.  First raise the\r
521         priority - passing NULL means raise the priority of the calling task. */\r
522         vTaskPrioritySet( NULL, tpTASK_POOL_WORKER_PRIORITY + 1 );\r
523 \r
524         /* Create tpJOBS_TO_CREATE jobs using the handle of this task as the job's\r
525         context and the function that sends a notification to the task handle as\r
526         the jobs callback function. */\r
527         for( x = 0; x < tpJOBS_TO_CREATE; x++ )\r
528         {\r
529                 xResult = IotTaskPool_CreateJob(  prvSimpleTaskNotifyCallback, /* Callback function. */\r
530                                                                                   ( void * ) xTaskGetCurrentTaskHandle(), /* Job context. */\r
531                                                                                   &( xJobStorage[ x ] ),\r
532                                                                                   &( xJobs[ x ] ) );\r
533                 configASSERT( xResult == IOT_TASKPOOL_SUCCESS );\r
534 \r
535                 /* This is not a persistent (recyclable) job and its storage is on the\r
536                 stack of this function, so the amount of heap space available should not\r
537                 have chanced since entering this function. */\r
538                 configASSERT( xFreeHeapBeforeCreatingJob == xPortGetFreeHeapSize() );\r
539         }\r
540 \r
541         for( x = 0; x < tpJOBS_TO_CREATE; x++ )\r
542         {\r
543                 /* Schedule the next job. */\r
544                 xResult = IotTaskPool_Schedule( NULL, xJobs[ x ], ulNoFlags );\r
545                 configASSERT( xResult == IOT_TASKPOOL_SUCCESS );\r
546 \r
547                 /* Although scheduled, the job's callback has not executed, so the job\r
548                 reports itself as scheduled. */\r
549                 IotTaskPool_GetStatus( NULL, xJobs[ x ], &xJobStatus );\r
550                 configASSERT( xJobStatus == IOT_TASKPOOL_STATUS_SCHEDULED );\r
551 \r
552                 /* The priority of the task pool task(s) is lower than the priority\r
553                 of this task, so the job's callback function should not have executed\r
554                 yes, so don't expect the notification value for this task to have\r
555                 changed. */\r
556                 xTaskNotifyWait( 0UL, /* Don't clear any bits on entry. */\r
557                                                  0UL, /* Don't clear any bits on exit. */\r
558                                                  &ulNotificationValue, /* Obtain the notification value. */\r
559                                                  0UL ); /* No block time, return immediately. */\r
560                 configASSERT( ulNotificationValue == 0 );\r
561         }\r
562 \r
563         /* At this point there are tpJOBS_TO_CREATE scheduled, but none have executed\r
564         their callbacks because the priority of this task is higher than the\r
565         priority of the task pool worker threads.  When this task blocks to wait for\r
566         a notification a worker thread will be able to executes - but as soon as its\r
567         callback function sends a notification to this task this task will\r
568         preempt it (because it has a higher priority) so this task only expects to\r
569         receive one notification at a time. */\r
570         for( x = 0; x < tpJOBS_TO_CREATE; x++ )\r
571         {\r
572                 xTaskNotifyWait( 0UL, /* Don't clear any bits on entry. */\r
573                                                  0UL, /* Don't clear any bits on exit. */\r
574                                                  &ulNotificationValue, /* Obtain the notification value. */\r
575                                                  xShortDelay ); /* Short delay to allow a task pool worker to execute. */\r
576                 configASSERT( ulNotificationValue == ( x + 1 ) );\r
577         }\r
578 \r
579         /* All the scheduled jobs have now executed, so waiting for another\r
580         notification should timeout without the notification value changing. */\r
581         xTaskNotifyWait( 0UL, /* Don't clear any bits on entry. */\r
582                                          0UL, /* Don't clear any bits on exit. */\r
583                                          &ulNotificationValue, /* Obtain the notification value. */\r
584                                          xShortDelay ); /* Short delay to allow a task pool worker to execute. */\r
585         configASSERT( ulNotificationValue == x );\r
586 \r
587         /* Reset the priority of this task and clear the notifications ready for the\r
588         next example. */\r
589         vTaskPrioritySet( NULL, tskIDLE_PRIORITY );\r
590         xTaskNotifyWait( portMAX_DELAY, /* Clear all bits on entry - portMAX_DELAY is used as it is a portable way of having all bits set. */\r
591                                          0UL, /* Don't clear any bits on exit. */\r
592                                          NULL, /* Don't need the notification value this time. */\r
593                                          0UL ); /* No block time, return immediately. */\r
594 }\r
595 /*-----------------------------------------------------------*/\r
596 \r