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_DeferredSingleJob( 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_DeferredSingleJob();
\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 TaskHandle_t xTaskToNotify = ( TaskHandle_t ) pUserContext;
\r
187 /* Remove warnings about unused parameters. */
\r
188 ( void ) pTaskPool;
\r
191 /* Notify the task that created this job. */
\r
192 xTaskNotifyGive( xTaskToNotify );
\r
194 /*-----------------------------------------------------------*/
\r
196 static void prvExample_BasicSingleJob( void )
\r
198 IotTaskPoolJobStorage_t xJobStorage;
\r
199 IotTaskPoolJob_t xJob;
\r
200 IotTaskPoolError_t xResult;
\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
207 /* Don't expect any notifications to be pending yet. */
\r
208 configASSERT( ulTaskNotifyTake( pdTRUE, 0 ) == 0 );
\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
217 xResult = IotTaskPool_CreateJob( prvSimpleTaskNotifyCallback, /* Callback function. */
\r
218 ( void * ) xTaskGetCurrentTaskHandle(), /* Job context. */
\r
221 configASSERT( xResult == IOT_TASKPOOL_SUCCESS );
\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
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
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
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
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
251 /*-----------------------------------------------------------*/
\r
253 static void prvExample_DeferredSingleJob( void )
\r
255 IotTaskPoolJobStorage_t xJobStorage;
\r
256 IotTaskPoolJob_t xJob;
\r
257 IotTaskPoolError_t xResult;
\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
265 /* Don't expect any notifications to be pending yet. */
\r
266 configASSERT( ulTaskNotifyTake( pdTRUE, 0 ) == 0 );
\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
276 configASSERT( xResult == IOT_TASKPOOL_SUCCESS );
\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
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
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
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
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
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
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
320 /* A single notification should not have been received... */
\r
321 configASSERT( ulReturn == 1 );
\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
326 xShortDelay_ticks = pdMS_TO_TICKS( ulShortDelay_ms );
\r
327 configASSERT( ( xElapsedTime >= xShortDelay_ticks ) && ( xElapsedTime < ( xShortDelay_ticks + xAllowableMargin ) ) );
\r
329 /*-----------------------------------------------------------*/
\r
331 static void prvExample_BasicRecyclableJob( void )
\r
333 IotTaskPoolJob_t xJob;
\r
334 IotTaskPoolError_t xResult;
\r
336 const uint32_t ulNoFlags = 0UL;
\r
337 const TickType_t xNoDelay = ( TickType_t ) 0;
\r
338 size_t xFreeHeapBeforeCreatingJob = xPortGetFreeHeapSize();
\r
340 /* Don't expect any notifications to be pending yet. */
\r
341 configASSERT( ulTaskNotifyTake( pdTRUE, 0 ) == 0 );
\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
358 configASSERT( xResult == IOT_TASKPOOL_SUCCESS );
\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
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
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
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
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
389 configASSERT( xPortGetFreeHeapSize() == xFreeHeapBeforeCreatingJob );
\r
391 /*-----------------------------------------------------------*/
\r
393 static void prvExample_ReuseRecyclableJobFromLowPriorityTask( void )
\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
402 /* Don't expect any notifications to be pending yet. */
\r
403 configASSERT( ulTaskNotifyTake( pdTRUE, 0 ) == 0 );
\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
418 xResult = IotTaskPool_CreateRecyclableJob( NULL,
\r
419 prvSimpleTaskNotifyCallback,
\r
420 (void * ) xTaskGetCurrentTaskHandle(),
\r
422 configASSERT( xResult == IOT_TASKPOOL_SUCCESS );
\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
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
434 for( x = 0; x < ( tpJOBS_TO_CREATE * 2UL ); x++ )
\r
436 /* Make sure array index does not go out of bounds. */
\r
437 xIndex = x % tpJOBS_TO_CREATE;
\r
439 xResult = IotTaskPool_Schedule( NULL, xJobs[ xIndex ], ulNoFlags );
\r
440 configASSERT( xResult == IOT_TASKPOOL_SUCCESS );
\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
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
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
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
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
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
488 xResult = IotTaskPool_DestroyRecyclableJob( NULL, xJobs[ x ] );
\r
489 configASSERT( xResult == IOT_TASKPOOL_SUCCESS );
\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
495 configASSERT( xPortGetFreeHeapSize() == xFreeHeapBeforeCreatingJob );
\r
497 /*-----------------------------------------------------------*/
\r
499 static void prvExample_ReuseRecyclableJobFromHighPriorityTask( void )
\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
510 /* Don't expect any notifications to be pending yet. */
\r
511 configASSERT( ulTaskNotifyTake( pdTRUE, 0 ) == 0 );
\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
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
529 xResult = IotTaskPool_CreateJob( prvSimpleTaskNotifyCallback, /* Callback function. */
\r
530 ( void * ) xTaskGetCurrentTaskHandle(), /* Job context. */
\r
531 &( xJobStorage[ x ] ),
\r
533 configASSERT( xResult == IOT_TASKPOOL_SUCCESS );
\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
541 for( x = 0; x < tpJOBS_TO_CREATE; x++ )
\r
543 /* Schedule the next job. */
\r
544 xResult = IotTaskPool_Schedule( NULL, xJobs[ x ], ulNoFlags );
\r
545 configASSERT( xResult == IOT_TASKPOOL_SUCCESS );
\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
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
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
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
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
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
587 /* Reset the priority of this task and clear the notifications ready for the
\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
595 /*-----------------------------------------------------------*/
\r