2 * FreeRTOS Kernel V10.2.1
\r
3 * Copyright (C) 2017 Amazon.com, Inc. or its affiliates. All Rights Reserved.
\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
12 * The above copyright notice and this permission notice shall be included in all
\r
13 * copies or substantial portions of the Software.
\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
22 * http://www.FreeRTOS.org
\r
23 * http://aws.amazon.com/freertos
\r
25 * 1 tab == 4 spaces!
\r
28 //_RB_ Add link to docs here.
\r
30 /* Kernel includes. */
\r
31 #include "FreeRTOS.h"
\r
34 /* Standard includes. */
\r
37 /* IoT SDK includes. */
\r
38 #include "iot_taskpool.h"
\r
40 /* The priority at which that tasks in the task pool (the worker tasks) get
\r
42 #define tpTASK_POOL_WORKER_PRIORITY 1
\r
44 /* The number of jobs created in the example functions that create more than
\r
46 #define tpJOBS_TO_CREATE 5
\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
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
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
67 static void prvSimpleTaskNotifyCallback( IotTaskPool_t pTaskPool, IotTaskPoolJob_t pJob, void *pUserContext );
\r
70 * The task used to demonstrate the task pool API. This task just loops through
\r
71 * each demo in turn.
\r
73 static void prvTaskPoolDemoTask( void *pvParameters );
\r
75 /*-----------------------------------------------------------*/
\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
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
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
104 /*-----------------------------------------------------------*/
\r
106 void vStartSimpleTaskPoolDemo( void )
\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
117 /*-----------------------------------------------------------*/
\r
119 static void prvTaskPoolDemoTask( void *pvParameters )
\r
121 IotTaskPoolError_t xResult;
\r
122 uint32_t ulLoops = 0;
\r
124 /* Remove compiler warnings about unused parameters. */
\r
125 ( void ) pvParameters;
\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
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
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
145 prvExample_BasicSingleJob();
\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
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
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
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
171 prvExample_ReuseRecyclableJobFromHighPriorityTask();
\r
174 if( ( ulLoops % 10UL ) == 0 )
\r
176 printf( "prvTaskPoolDemoTask() performed %u iterations without hitting an assert.\r\n", ulLoops );
\r
181 /*-----------------------------------------------------------*/
\r
183 static void prvSimpleTaskNotifyCallback( IotTaskPool_t pTaskPool, IotTaskPoolJob_t pJob, void *pUserContext )
\r
185 /* The jobs context is the handle of the task to which a notification should
\r
187 TaskHandle_t xTaskToNotify = ( TaskHandle_t ) pUserContext;
\r
189 /* Remove warnings about unused parameters. */
\r
190 ( void ) pTaskPool;
\r
193 /* Notify the task that created this job. */
\r
194 xTaskNotifyGive( xTaskToNotify );
\r
196 /*-----------------------------------------------------------*/
\r
198 static void prvExample_BasicSingleJob( void )
\r
200 IotTaskPoolJobStorage_t xJobStorage;
\r
201 IotTaskPoolJob_t xJob;
\r
202 IotTaskPoolError_t xResult;
\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
209 /* Don't expect any notifications to be pending yet. */
\r
210 configASSERT( ulTaskNotifyTake( pdTRUE, 0 ) == 0 );
\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
219 xResult = IotTaskPool_CreateJob( prvSimpleTaskNotifyCallback, /* Callback function. */
\r
220 ( void * ) xTaskGetCurrentTaskHandle(), /* Job context. */
\r
223 configASSERT( xResult == IOT_TASKPOOL_SUCCESS );
\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
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
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
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
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
253 /*-----------------------------------------------------------*/
\r
255 static void prvExample_DeferredJobAndCancellingJobs( void )
\r
257 IotTaskPoolJobStorage_t xJobStorage;
\r
258 IotTaskPoolJob_t xJob;
\r
259 IotTaskPoolError_t xResult;
\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
267 /* Don't expect any notifications to be pending yet. */
\r
268 configASSERT( ulTaskNotifyTake( pdTRUE, 0 ) == 0 );
\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
278 configASSERT( xResult == IOT_TASKPOOL_SUCCESS );
\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
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
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
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
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
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
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
322 /* A single notification should not have been received... */
\r
323 configASSERT( ulReturn == 1 );
\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
328 xShortDelay_ticks = pdMS_TO_TICKS( ulShortDelay_ms );
\r
329 configASSERT( ( xElapsedTime >= xShortDelay_ticks ) && ( xElapsedTime < ( xShortDelay_ticks + xAllowableMargin ) ) );
\r
331 /*-----------------------------------------------------------*/
\r
333 static void prvExample_BasicRecyclableJob( void )
\r
335 IotTaskPoolJob_t xJob;
\r
336 IotTaskPoolError_t xResult;
\r
338 const uint32_t ulNoFlags = 0UL;
\r
339 const TickType_t xNoDelay = ( TickType_t ) 0;
\r
340 size_t xFreeHeapBeforeCreatingJob = xPortGetFreeHeapSize();
\r
342 /* Don't expect any notifications to be pending yet. */
\r
343 configASSERT( ulTaskNotifyTake( pdTRUE, 0 ) == 0 );
\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
360 configASSERT( xResult == IOT_TASKPOOL_SUCCESS );
\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
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
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
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
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
391 configASSERT( xPortGetFreeHeapSize() == xFreeHeapBeforeCreatingJob );
\r
393 /*-----------------------------------------------------------*/
\r
395 static void prvExample_ReuseRecyclableJobFromLowPriorityTask( void )
\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
404 /* Don't expect any notifications to be pending yet. */
\r
405 configASSERT( ulTaskNotifyTake( pdTRUE, 0 ) == 0 );
\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
420 xResult = IotTaskPool_CreateRecyclableJob( NULL,
\r
421 prvSimpleTaskNotifyCallback,
\r
422 (void * ) xTaskGetCurrentTaskHandle(),
\r
424 configASSERT( xResult == IOT_TASKPOOL_SUCCESS );
\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
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
436 for( x = 0; x < ( tpJOBS_TO_CREATE * 2UL ); x++ )
\r
438 /* Make sure array index does not go out of bounds. */
\r
439 xIndex = x % tpJOBS_TO_CREATE;
\r
441 xResult = IotTaskPool_Schedule( NULL, xJobs[ xIndex ], ulNoFlags );
\r
442 configASSERT( xResult == IOT_TASKPOOL_SUCCESS );
\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
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
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
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
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
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
491 xResult = IotTaskPool_DestroyRecyclableJob( NULL, xJobs[ x ] );
\r
492 configASSERT( xResult == IOT_TASKPOOL_SUCCESS );
\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
498 configASSERT( xPortGetFreeHeapSize() == xFreeHeapBeforeCreatingJob );
\r
500 /*-----------------------------------------------------------*/
\r
502 static void prvExample_ReuseRecyclableJobFromHighPriorityTask( void )
\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
513 /* Don't expect any notifications to be pending yet. */
\r
514 configASSERT( ulTaskNotifyTake( pdTRUE, 0 ) == 0 );
\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
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
532 xResult = IotTaskPool_CreateJob( prvSimpleTaskNotifyCallback, /* Callback function. */
\r
533 ( void * ) xTaskGetCurrentTaskHandle(), /* Job context. */
\r
534 &( xJobStorage[ x ] ),
\r
536 configASSERT( xResult == IOT_TASKPOOL_SUCCESS );
\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
544 for( x = 0; x < tpJOBS_TO_CREATE; x++ )
\r
546 /* Schedule the next job. */
\r
547 xResult = IotTaskPool_Schedule( NULL, xJobs[ x ], ulNoFlags );
\r
548 configASSERT( xResult == IOT_TASKPOOL_SUCCESS );
\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
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
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
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
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
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
590 /* Reset the priority of this task and clear the notifications ready for the
\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
598 /*-----------------------------------------------------------*/
\r