--- /dev/null
+/*\r
+ * FreeRTOS Kernel V10.2.1\r
+ * Copyright (C) 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.\r
+ *\r
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of\r
+ * this software and associated documentation files (the "Software"), to deal in\r
+ * the Software without restriction, including without limitation the rights to\r
+ * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of\r
+ * the Software, and to permit persons to whom the Software is furnished to do so,\r
+ * subject to the following conditions:\r
+ *\r
+ * The above copyright notice and this permission notice shall be included in all\r
+ * copies or substantial portions of the Software.\r
+ *\r
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\r
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS\r
+ * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR\r
+ * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER\r
+ * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\r
+ *\r
+ * http://www.FreeRTOS.org\r
+ * http://aws.amazon.com/freertos\r
+ *\r
+ * 1 tab == 4 spaces!\r
+ */\r
+\r
+\r
+/* Kernel includes. */\r
+#include "FreeRTOS.h"\r
+#include "task.h"\r
+\r
+/* Standard includes. */\r
+#include <stdio.h>\r
+\r
+/* IoT SDK includes. */\r
+#include "iot_taskpool_freertos.h"\r
+\r
+/* Demo includes. */\r
+#include "demo_config.h"\r
+\r
+/* The priority at which that tasks in the task pool (the worker tasks) get\r
+created. */\r
+#define tpTASK_POOL_WORKER_PRIORITY 1\r
+\r
+/*\r
+ * Prototypes for the functions that demonstrate the task pool API.\r
+ * See the implementation of the prvTaskPoolDemoTask() function within this file\r
+ * for a description of the individual functions. A configASSERT() is hit if\r
+ * any of the demos encounter any unexpected behavior.\r
+ */\r
+static void prvExample_BasicSingleJob( void );\r
+static void prvExample_DeferredJobAndCancellingJobs( void );\r
+\r
+/*\r
+ * Prototypes of the callback functions used in the examples. The callback\r
+ * simply sends a signal (in the form of a direct task notification) to the\r
+ * prvTaskPoolDemoTask() task to let the task know that the callback execute.\r
+ * The handle of the prvTaskPoolDemoTask() task is not accessed directly, but\r
+ * instead passed into the task pool job as the job's context.\r
+ */\r
+static void prvSimpleTaskNotifyCallback( IotTaskPool_t pTaskPool, IotTaskPoolJob_t pJob, void *pUserContext );\r
+\r
+/*\r
+ * The task used to demonstrate the task pool API. This task just loops through\r
+ * each demo in turn.\r
+ */\r
+static void prvTaskPoolDemoTask( void *pvParameters );\r
+\r
+/*-----------------------------------------------------------*/\r
+\r
+/* Parameters used to create the system task pool - see TBD for more information\r
+ * as the task pool used in this example is a slimmed down version of the full\r
+ * library - the slimmed down version being intended specifically for FreeRTOS\r
+ * kernel use cases. */\r
+static const IotTaskPoolInfo_t xTaskPoolParameters = {\r
+ /* minThreads:\r
+ * Minimum number of threads in a task pool.\r
+ * Note the slimmed down version of the task\r
+ * pool used by this library does not auto-scale\r
+ * the number of tasks in the pool so in this\r
+ * case this sets the number of tasks in the\r
+ * pool. */\r
+ IOT_TASKPOOL_NUMBER_OF_WORKERS,\r
+ /* maxThreads:\r
+ * Maximum number of threads in a task pool.\r
+ * Note the slimmed down version of the task\r
+ * pool used by this library does not auto-scale\r
+ * the number of tasks in the pool so in this\r
+ * case this parameter must match minThreads. */\r
+ IOT_TASKPOOL_NUMBER_OF_WORKERS,\r
+ /* Stack size for every task pool thread - in\r
+ * bytes, hence multiplying by the number of bytes\r
+ * in a word as configMINIMAL_STACK_SIZE is\r
+ * specified in words. */\r
+ configMINIMAL_STACK_SIZE * sizeof( portSTACK_TYPE ),\r
+ /* Priority for every task pool thread. */\r
+ tpTASK_POOL_WORKER_PRIORITY,\r
+ };\r
+\r
+/*-----------------------------------------------------------*/\r
+\r
+void vStartSimpleTaskPoolDemo( void )\r
+{\r
+ /* This example uses a single application task, which in turn is used to\r
+ * create and send jobs to task pool tasks. */\r
+ xTaskCreate( prvTaskPoolDemoTask, /* Function that implements the task. */\r
+ "PoolDemo", /* Text name for the task - only used for debugging. */\r
+ democonfigDEMO_STACKSIZE, /* Size of stack (in words, not bytes) to allocate for the task. */\r
+ NULL, /* Task parameter - not used in this case. */\r
+ tskIDLE_PRIORITY, /* Task priority, must be between 0 and configMAX_PRIORITIES - 1. */\r
+ NULL ); /* Used to pass out a handle to the created task - not used in this case. */\r
+}\r
+/*-----------------------------------------------------------*/\r
+\r
+static void prvTaskPoolDemoTask( void *pvParameters )\r
+{\r
+IotTaskPoolError_t xResult;\r
+uint32_t ulLoops = 0;\r
+\r
+ /* Remove compiler warnings about unused parameters. */\r
+ ( void ) pvParameters;\r
+\r
+ configPRINTF( ( "---------STARTING DEMO---------\r\n" ) );\r
+\r
+ /* The task pool must be created before it can be used. The system task\r
+ * pool is the task pool managed by the task pool library itself - the storage\r
+ * used by the task pool is provided by the library. */\r
+ xResult = IotTaskPool_CreateSystemTaskPool( &xTaskPoolParameters );\r
+ configASSERT( xResult == IOT_TASKPOOL_SUCCESS );\r
+\r
+ for( ;; )\r
+ {\r
+ /* Demonstrate the most basic use case where a non persistent job is\r
+ * created and scheduled to run immediately. The task pool worker tasks\r
+ * (in which the job callback function executes) have a priority above the\r
+ * priority of this task so the job's callback executes as soon as it is\r
+ * scheduled. */\r
+ prvExample_BasicSingleJob();\r
+\r
+ /* Demonstrate a job being scheduled to run at some time in the\r
+ * future, and how a job scheduled to run in the future can be canceled\r
+ * if it has not yet started executing. */\r
+ prvExample_DeferredJobAndCancellingJobs();\r
+\r
+ ulLoops++;\r
+ if( ( ulLoops % 10UL ) == 0 )\r
+ {\r
+ configPRINTF( ( "prvTaskPoolDemoTask() performed %u iterations successfully.\r\n", ulLoops ) );\r
+ configPRINTF( ( "Demo completed successfully.\r\n" ) );\r
+ fflush( stdout );\r
+ }\r
+ }\r
+}\r
+/*-----------------------------------------------------------*/\r
+\r
+static void prvSimpleTaskNotifyCallback( IotTaskPool_t pTaskPool, IotTaskPoolJob_t pJob, void *pUserContext )\r
+{\r
+/* The jobs context is the handle of the task to which a notification should\r
+ * be sent. */\r
+TaskHandle_t xTaskToNotify = ( TaskHandle_t ) pUserContext;\r
+\r
+ /* Remove warnings about unused parameters. */\r
+ ( void ) pTaskPool;\r
+ ( void ) pJob;\r
+\r
+ /* Notify the task that created this job. */\r
+ xTaskNotifyGive( xTaskToNotify );\r
+}\r
+/*-----------------------------------------------------------*/\r
+\r
+static void prvExample_BasicSingleJob( void )\r
+{\r
+IotTaskPoolJobStorage_t xJobStorage;\r
+IotTaskPoolJob_t xJob;\r
+IotTaskPoolError_t xResult;\r
+uint32_t ulReturn;\r
+const uint32_t ulNoFlags = 0UL;\r
+const TickType_t xNoDelay = ( TickType_t ) 0;\r
+size_t xFreeHeapBeforeCreatingJob = xPortGetFreeHeapSize();\r
+IotTaskPoolJobStatus_t xJobStatus;\r
+\r
+ /* Direct to task notifications are used to communicate between worker tasks\r
+ and this task. Don't expect any notifications to be pending before commencing. */\r
+ configASSERT( ulTaskNotifyTake( pdTRUE, xNoDelay ) == 0 );\r
+\r
+ /* Create and schedule a job using the handle of this task as the job's\r
+ * context and the function that sends a notification to the task handle as\r
+ * the job's callback function. This is not a recyclable job so the storage\r
+ * required to hold information about the job is provided by this task - in\r
+ * this case the storage is on the stack of this task so no memory is allocated\r
+ * dynamically but the stack frame must remain in scope for the lifetime of\r
+ * the job. */\r
+ xResult = IotTaskPool_CreateJob( prvSimpleTaskNotifyCallback, /* Callback function. */\r
+ ( void * ) xTaskGetCurrentTaskHandle(), /* Job context. */\r
+ &xJobStorage,\r
+ &xJob );\r
+ configASSERT( xResult == IOT_TASKPOOL_SUCCESS );\r
+\r
+ /* The job has been created but not scheduled so is now ready. */\r
+ IotTaskPool_GetStatus( NULL, xJob, &xJobStatus );\r
+ configASSERT( xJobStatus == IOT_TASKPOOL_STATUS_READY );\r
+\r
+ /* This is not a persistent (recyclable) job and its storage is on the\r
+ * stack of this function, so the amount of heap space available should not\r
+ * have changed since entering this function. */\r
+ configASSERT( xFreeHeapBeforeCreatingJob == xPortGetFreeHeapSize() );\r
+\r
+ /* In the full task pool implementation the first parameter is used to\r
+ * pass the handle of the task pool to schedule. The lean task pool\r
+ * implementation used in this demo only supports a single task pool, which\r
+ * is created internally within the library, so the first parameter is NULL. */\r
+ xResult = IotTaskPool_Schedule( NULL, xJob, ulNoFlags );\r
+ configASSERT( xResult == IOT_TASKPOOL_SUCCESS );\r
+\r
+ /* Look for the notification coming from the job's callback function. The\r
+ * priority of the task pool worker task that executes the callback is higher\r
+ * than the priority of this task so a block time is not needed - the task pool\r
+ * worker task preempts this task and sends the notification (from the job's\r
+ * callback) as soon as the job is scheduled. */\r
+ ulReturn = ulTaskNotifyTake( pdTRUE, xNoDelay );\r
+ configASSERT( ulReturn );\r
+\r
+ /* The job's callback has executed so the job has now completed. */\r
+ IotTaskPool_GetStatus( NULL, xJob, &xJobStatus );\r
+ configASSERT( xJobStatus == IOT_TASKPOOL_STATUS_COMPLETED );\r
+}\r
+/*-----------------------------------------------------------*/\r
+\r
+static void prvExample_DeferredJobAndCancellingJobs( void )\r
+{\r
+IotTaskPoolJobStorage_t xJobStorage;\r
+IotTaskPoolJob_t xJob;\r
+IotTaskPoolError_t xResult;\r
+uint32_t ulReturn;\r
+const uint32_t ulShortDelay_ms = 100UL;\r
+const TickType_t xNoDelay = ( TickType_t ) 0, xAllowableMargin = ( TickType_t ) 5; /* Large margin for Windows port, which is not real time. */\r
+TickType_t xTimeBefore, xElapsedTime, xShortDelay_ticks;\r
+size_t xFreeHeapBeforeCreatingJob = xPortGetFreeHeapSize();\r
+IotTaskPoolJobStatus_t xJobStatus;\r
+\r
+ /* Don't expect any notifications to be pending yet. */\r
+ configASSERT( ulTaskNotifyTake( pdTRUE, xNoDelay ) == 0 );\r
+\r
+ /* Create a job using the handle of this task as the job's context and the\r
+ * function that sends a notification to the task handle as the job's callback\r
+ * function. The job is created using storage allocated on the stack of this\r
+ * function - so no memory is allocated. */\r
+ xResult = IotTaskPool_CreateJob( prvSimpleTaskNotifyCallback, /* Callback function. */\r
+ ( void * ) xTaskGetCurrentTaskHandle(), /* Job context. */\r
+ &xJobStorage,\r
+ &xJob );\r
+ configASSERT( xResult == IOT_TASKPOOL_SUCCESS );\r
+\r
+ /* The job has been created but not scheduled so is now ready. */\r
+ IotTaskPool_GetStatus( NULL, xJob, &xJobStatus );\r
+ configASSERT( xJobStatus == IOT_TASKPOOL_STATUS_READY );\r
+\r
+ /* This is not a persistent (recyclable) job and its storage is on the\r
+ * stack of this function, so the amount of heap space available should not\r
+ * have changed since entering this function. */\r
+ configASSERT( xFreeHeapBeforeCreatingJob == xPortGetFreeHeapSize() );\r
+\r
+ /* Schedule the job to run its callback in ulShortDelay_ms milliseconds time.\r
+ * In the full task pool implementation the first parameter is used to pass the\r
+ * handle of the task pool to schedule. The lean task pool implementation used\r
+ * in this demo only supports a single task pool, which is created internally\r
+ * within the library, so the first parameter is NULL. */\r
+ xResult = IotTaskPool_ScheduleDeferred( NULL, xJob, ulShortDelay_ms );\r
+ configASSERT( xResult == IOT_TASKPOOL_SUCCESS );\r
+\r
+ /* The scheduled job should not have executed yet, so don't expect any\r
+ * notifications and expect the job's status to be 'deferred'. */\r
+ ulReturn = ulTaskNotifyTake( pdTRUE, xNoDelay );\r
+ configASSERT( ulReturn == 0 );\r
+ IotTaskPool_GetStatus( NULL, xJob, &xJobStatus );\r
+ configASSERT( xJobStatus == IOT_TASKPOOL_STATUS_DEFERRED );\r
+\r
+ /* As the job has not yet been executed it can be canceled. */\r
+ xResult = IotTaskPool_TryCancel( NULL, xJob, &xJobStatus );\r
+ configASSERT( xResult == IOT_TASKPOOL_SUCCESS );\r
+ IotTaskPool_GetStatus( NULL, xJob, &xJobStatus );\r
+ configASSERT( xJobStatus == IOT_TASKPOOL_STATUS_CANCELED );\r
+\r
+ /* Schedule the job again, and this time wait until its callback is\r
+ * executed (the callback function sends a notification to this task) to see\r
+ * that it executes at the right time. */\r
+ xTimeBefore = xTaskGetTickCount();\r
+ xResult = IotTaskPool_ScheduleDeferred( NULL, xJob, ulShortDelay_ms );\r
+ configASSERT( xResult == IOT_TASKPOOL_SUCCESS );\r
+\r
+ /* Wait twice the deferred execution time to ensure the callback is executed\r
+ * before the call below times out. */\r
+ ulReturn = ulTaskNotifyTake( pdTRUE, pdMS_TO_TICKS( ulShortDelay_ms * 2UL ) );\r
+ xElapsedTime = xTaskGetTickCount() - xTimeBefore;\r
+\r
+ /* A single notification should have been received... */\r
+ configASSERT( ulReturn == 1 );\r
+\r
+ /* ...and the time since scheduling the job should be greater than or\r
+ * equal to the deferred execution time - which is converted to ticks for\r
+ * comparison. */\r
+ xShortDelay_ticks = pdMS_TO_TICKS( ulShortDelay_ms );\r
+ configASSERT( ( xElapsedTime >= xShortDelay_ticks ) && ( xElapsedTime < ( xShortDelay_ticks + xAllowableMargin ) ) );\r
+}\r
+/*-----------------------------------------------------------*/\r