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