/**
@mainpage
@anchor taskpool
@brief Task pool library.

> A task pool is an adaptive set of threads that can grow and shrink to execute a user-provided callback through a user-defined job that can be scheduled with a non-blocking call. The design principles are to minimize the memory footprint while allowing non-blocking execution. The adaptive behavior allows serving jobs in a timely manner, without allocating system resources for the entire duration of the application, or causing recurring allocation/deallocation patterns. The user does not have to worry about synchronization and thread management other than within its own application.

Features of this library include:
- Non-blocking API functions to schedule immediate and deferred jobs.
- Ability to create statically and dynamically allocated jobs.
- Scalable performance and footprint. The [configuration settings](@ref taskpool_config) allow this library to be tailored to a system's resources.
- Customizable caching for low memory overhead when creating jobs dynamically.

This library uses a user-specified set of threads to process jobs specified by the user as a callback and a context.
Overall, the task pool hinges on two main data structures: the task pool Job (IotTaskPoolJob_t) and the task pool itself (IotTaskPool_t). A task pool job carries the information about the user callback and context, one flag to track the status and a link structure for moving the job in and out of the dispatch queue and cache. User can create two types of jobs: static and recyclable. Static jobs are intended for users that know exactly how many jobs they will schedule (e.g. see Defender scenario above) or for embedding in other data structures. Static jobs need no destruction, and creation simply sets the user callback and context. Recyclable jobs are intended for scenario where user cannot know ahead of time how many jobs she will need. Recyclable jobs are dynamically allocated, and can be either destroyed after use or recycled. If jobs are recycled they are maintained in a cache (IotTaskPoolCache_t) owned by the task pool itself, and re-used when user wants to create more recyclable jobs. The task pool cache has a compile time limit, and can be pre-populated with recyclable jobs by simply creating recyclable jobs and recycling them, in an effort to limit memory allocations at run-time. This is handy for scenarios where user is aware of the steady state requirements for his application.
User jobs are queued through a non-blocking call and processed asynchronously in the order they are received.
- [Task pool API functions](@ref taskpool_functions) Provides a set of functions to queue an asynchronous operation on the <b>Dispatch Queue</b>. API functions are non-blocking and return after successfully queuing an operation.
- <b>Worker threads</b> in the task pool are woken up when operations arrive in the dispatch queue. These threads remove operations from the dispatch queue in FIFO order and execute the user-provided callback. After executing the user callback, the task pool threads try and execute any remaining jobs in the dispatch queue. The task pool tries and execute a user job as soon as it is received and if there are no threads available it will try and create one, up to the maximum number of allowed threads. The user can specify the minimum and maximum number of threads allowed when creating the task pool.
- The user can try and cancel a job after the task has been scheduled. Cancellation is only allowed before the task enters execution.

Threads are created with @ref platform_threads_function_createdetachedthread. Because the platform layer may be re-implemented across systems, threads will be allocated for the task pool library on-the-go on some systems, while other systems may use an always-allocated thread pool.

@dependencies{taskpool,task pool library}
@dot "Task pool direct dependencies"
digraph taskpool_dependencies
{
    node[shape=box, fontname=Helvetica, fontsize=10, style=filled];
    edge[fontname=Helvetica, fontsize=10];
    subgraph
    {
        taskpool[label="Task pool", fillcolor="#cc00ccff"];
    }
    subgraph
    {
        node[fillcolor="#aed8a9ff"];
        rank = same;
        linear_containers[label="List/Queue", URL="@ref linear_containers"];
        logging[label="Logging", URL="@ref logging"];
        static_memory[label="Static memory", URL="@ref static_memory"];
    }
    subgraph
    {
        rank = same;
        platform_threads[label="Thread management", fillcolor="#e89025ff", URL="@ref platform_threads"];
        platform_clock[label="Clock", fillcolor="#e89025ff", URL="@ref platform_clock"];
    }
    taskpool -> linear_containers;
    taskpool -> platform_clock;
    taskpool -> platform_threads;
    taskpool -> static_memory [label=" if static memory only", style="dashed"];
    taskpool -> logging [label=" if logging enabled", style="dashed"];
    logging -> platform_clock;
    logging -> static_memory [label=" if static memory only", style="dashed"];
}
@enddot

Currently, the task pool library has the following dependencies:
- The linear containers (list/queue) library for maintaining the data structures for scheduled and in-progress task pool operations.
- The logging library may be used if @ref IOT_LOG_LEVEL_TASKPOOL is not @ref IOT_LOG_NONE.
- The platform layer provides an interface to the operating system for thread management, timers, clock functions, etc.

In addition to the components above, the task pool library may also depend on C standard library headers.
*/

/**
@page taskpool_design Design
@brief Architecture behind the task pool library.

The sequence diagram below illustrates the workflow described above. The application thread is able to continue executing while the task pool library processes the operation.

@image html taskpool_design_typicaloperation.png width=100%

The state diagrams for statically allocated, non-recyclable jobs with all legal transitions is presented in the diagram below. A static job can be created, schedule and canceled. Cancellation always succeeds, unless the job was already canceled, or completed (i.e. executed). Static jobs cannot be recycled and do no need to be destroyed. Static jobs are suitable for embedding on other data structures that own them.

@image html StaticJobStatus.png width=40%

The state diagram and legal transitions for all recyclable jobs is presented in the diagram below. A recyclable job is dynamically allocated. Just like a static job, a recyclable job can be created, schedule and canceled. Cancellation always succeeds, unless the job was already canceled, or completed (i.e. executed). Unlike static jobs, recyclable jobs can be recycled, or destroyed. Recycling a job effectively pushes a job to the task pool cache, where the task pool manages the lifetime of the job itself. The size of the cache is controlled via a compile time parameter. A user can get rid of a recyclable job by destroying it explicitly. Recyclable jobs should not be embedded in other data structures, but could be referenced from other data structures.

@image html RecyclableJobStatus.png width=50%

*/

/**
@page taskpool_tests Tests
@brief Tests written for the task pool library.

The task pool tests reside in the `tests/common` directory. They are divided into the following subdirectories:
- `system`: task pool system and stress tests. Stress tests may run for a long time, so they are not run unless the `-l` option is passed to the test executable.
- `unit`: task pool unit tests. These tests do not require a network connection.

The current task pool tests use the [Unity test framework](http://www.throwtheswitch.org/unity/).
*/

/**
@configpage{taskpool,task pool library}

@section IOT_TASKPOOL_JOB_WAIT_TIMEOUT_MS
@brief Set this to the desired wait timeout in milliseconds for a worker in the task pool to wait for an incoming job.

If a worker in the task pool wakes up because of a timeout, then the worker will terminate if it exceeds the desired minimum thread quota, which the user can configure via @ref IotTaskPoolInfo_t.minThreads.

@configdefault `1 minute`

@section IOT_TASKPOOL_JOBS_RECYCLE_LIMIT
@brief Set this to the number of recyclable tasks for the task pool to cache.

Caching dynamically allocated tasks (recyclable tasks) helps the application to limit the number of allocations at runtime.
Caching recyclable tasks may help making the application more responsive and predictable, by removing a potential
for memory allocation failures, but it may also have negative repercussions on the amount of memory available at any given time.
It is up to the application developer to strike the correct balance these competing needs.
The task pool will cache when the application calling @ref IotTaskPool_RecycleJob. Any recycled tasks in excess of @ref IOT_TASKPOOL_JOBS_RECYCLE_LIMIT will be destroyed and its memory will be release.

@configdefault `8`

@section IOT_TASKPOOL_ENABLE_ASSERTS
@brief Set this to `1` to perform sanity checks when using the task pool library.

Asserts are useful for debugging, but should be disabled in production code. If this is set to `1`, @ref IotTaskPool_Assert can be defined to set the assertion function; otherwise, the @ref Iot_DefaultAssert will be used.

@configpossible `0` (asserts disabled) or `1` (asserts enabled)<br>
@configrecommended `1` when debugging; `0` in production code.<br>
@configdefault `0`

@section IOT_LOG_LEVEL_TASKPOOL
@brief Set the log level of the task pool library.

Log messages from the task pool library at or below this setting will be printed.

@configpossible One of the @ref logging_constants_levels.<br>
@configdefault @ref IOT_LOG_LEVEL_GLOBAL; if that is undefined, then #IOT_LOG_NONE.
*/

/**
@enums{taskpool,task pool}
@paramstructs{taskpool,task pool}
@functionpointers{taskpool,task pool}
@structs{taskpool,task pool}
@handles{taskpool,task pool}
*/
