From a2a2fffed9a528da0b7d9bb9c0c88ac9c827fd8c Mon Sep 17 00:00:00 2001 From: rtel Date: Wed, 19 Jun 2019 18:41:21 +0000 Subject: [PATCH] Bring in a minimum subset of the IoT SDK - at this time just a subset of the library dependencies rather than the libraries themselves. git-svn-id: https://svn.code.sf.net/p/freertos/code/trunk@2665 1d2547de-c912-0410-9cb9-b8ca96c0e9e2 --- .../include/platform/iot_platform_types_afr.h | 84 + .../platform/include/platform/iot_clock.h | 216 +++ .../platform/include/platform/iot_metrics.h | 103 ++ .../platform/include/platform/iot_network.h | 294 ++++ .../platform/include/platform/iot_threads.h | 355 ++++ .../include/types/iot_platform_types.h | 158 ++ .../standard/common/include/iot_atomic.h | 39 + .../c_sdk/standard/common/include/iot_init.h | 67 + .../common/include/iot_linear_containers.h | 956 +++++++++++ .../common/include/iot_logging_setup.h | 223 +++ .../standard/common/include/iot_taskpool.h | 558 ++++++ .../common/include/private/iot_error.h | 117 ++ .../common/include/private/iot_logging.h | 229 +++ .../include/private/iot_static_memory.h | 250 +++ .../include/private/iot_taskpool_internal.h | 294 ++++ .../common/include/types/iot_taskpool_types.h | 362 ++++ .../standard/common/taskpool/iot_taskpool.c | 1497 +++++++++++++++++ .../taskpool/iot_taskpool_static_memory.c | 175 ++ 18 files changed, 5977 insertions(+) create mode 100644 FreeRTOS-Plus/Source/FreeRTOS-Plus-IoT-SDK/abstractions/platform/freertos/include/platform/iot_platform_types_afr.h create mode 100644 FreeRTOS-Plus/Source/FreeRTOS-Plus-IoT-SDK/abstractions/platform/include/platform/iot_clock.h create mode 100644 FreeRTOS-Plus/Source/FreeRTOS-Plus-IoT-SDK/abstractions/platform/include/platform/iot_metrics.h create mode 100644 FreeRTOS-Plus/Source/FreeRTOS-Plus-IoT-SDK/abstractions/platform/include/platform/iot_network.h create mode 100644 FreeRTOS-Plus/Source/FreeRTOS-Plus-IoT-SDK/abstractions/platform/include/platform/iot_threads.h create mode 100644 FreeRTOS-Plus/Source/FreeRTOS-Plus-IoT-SDK/abstractions/platform/include/types/iot_platform_types.h create mode 100644 FreeRTOS-Plus/Source/FreeRTOS-Plus-IoT-SDK/c_sdk/standard/common/include/iot_atomic.h create mode 100644 FreeRTOS-Plus/Source/FreeRTOS-Plus-IoT-SDK/c_sdk/standard/common/include/iot_init.h create mode 100644 FreeRTOS-Plus/Source/FreeRTOS-Plus-IoT-SDK/c_sdk/standard/common/include/iot_linear_containers.h create mode 100644 FreeRTOS-Plus/Source/FreeRTOS-Plus-IoT-SDK/c_sdk/standard/common/include/iot_logging_setup.h create mode 100644 FreeRTOS-Plus/Source/FreeRTOS-Plus-IoT-SDK/c_sdk/standard/common/include/iot_taskpool.h create mode 100644 FreeRTOS-Plus/Source/FreeRTOS-Plus-IoT-SDK/c_sdk/standard/common/include/private/iot_error.h create mode 100644 FreeRTOS-Plus/Source/FreeRTOS-Plus-IoT-SDK/c_sdk/standard/common/include/private/iot_logging.h create mode 100644 FreeRTOS-Plus/Source/FreeRTOS-Plus-IoT-SDK/c_sdk/standard/common/include/private/iot_static_memory.h create mode 100644 FreeRTOS-Plus/Source/FreeRTOS-Plus-IoT-SDK/c_sdk/standard/common/include/private/iot_taskpool_internal.h create mode 100644 FreeRTOS-Plus/Source/FreeRTOS-Plus-IoT-SDK/c_sdk/standard/common/include/types/iot_taskpool_types.h create mode 100644 FreeRTOS-Plus/Source/FreeRTOS-Plus-IoT-SDK/c_sdk/standard/common/taskpool/iot_taskpool.c create mode 100644 FreeRTOS-Plus/Source/FreeRTOS-Plus-IoT-SDK/c_sdk/standard/common/taskpool/iot_taskpool_static_memory.c diff --git a/FreeRTOS-Plus/Source/FreeRTOS-Plus-IoT-SDK/abstractions/platform/freertos/include/platform/iot_platform_types_afr.h b/FreeRTOS-Plus/Source/FreeRTOS-Plus-IoT-SDK/abstractions/platform/freertos/include/platform/iot_platform_types_afr.h new file mode 100644 index 000000000..e85534381 --- /dev/null +++ b/FreeRTOS-Plus/Source/FreeRTOS-Plus-IoT-SDK/abstractions/platform/freertos/include/platform/iot_platform_types_afr.h @@ -0,0 +1,84 @@ +/* + * Amazon FreeRTOS Platform V1.0.0 + * Copyright (C) 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to + * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of + * the Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * http://aws.amazon.com/freertos + * http://www.FreeRTOS.org + */ + +/** + * @file iot_platform_types_posix.h + * @brief Definitions of platform layer types on POSIX systems. + */ + +#ifndef _IOT_PLATFORM_TYPES_AFR_H_ +#define _IOT_PLATFORM_TYPES_AFR_H_ + +#include "timers.h" + +typedef struct iot_mutex_internal +{ + StaticSemaphore_t xMutex; /**< FreeRTOS mutex. */ + BaseType_t recursive; /**< Type; used for indicating if this is reentrant or normal. */ +} iot_mutex_internal_t; + +/** + * @brief The native mutex type on AFR systems. + */ +typedef iot_mutex_internal_t _IotSystemMutex_t; + +typedef struct iot_sem_internal +{ + StaticSemaphore_t xSemaphore; /**< FreeRTOS semaphore. */ +} iot_sem_internal_t; + +/** + * @brief The native semaphore type on AFR systems. + */ +typedef iot_sem_internal_t _IotSystemSemaphore_t; + +/** + * @brief Holds information about an active detached thread so that we can + * delete the FreeRTOS task when it completes + */ +typedef struct threadInfo +{ + void * pArgument; /**< @brief Argument to `threadRoutine`. */ + void ( *threadRoutine )( void * );/**< @brief Thread function to run. */ +} threadInfo_t; + +/** + * @brief Holds information about an active timer. + */ +typedef struct timerInfo +{ + TimerHandle_t timer; /**< @brief Underlying timer. */ + void ( *threadRoutine )( void * ); /**< @brief Thread function to run on timer expiration. */ + void * pArgument; /**< @brief First argument to threadRoutine. */ + StaticTimer_t xTimerBuffer; /**< Memory that holds the FreeRTOS timer. */ + TickType_t xTimerPeriod; /**< Period of this timer. */ +} timerInfo_t; + +/** + * @brief Represents an #IotTimer_t on AFR systems. + */ +typedef timerInfo_t _IotSystemTimer_t; + +#endif /* ifndef _IOT_PLATFORM_TYPES_POSIX_H_ */ diff --git a/FreeRTOS-Plus/Source/FreeRTOS-Plus-IoT-SDK/abstractions/platform/include/platform/iot_clock.h b/FreeRTOS-Plus/Source/FreeRTOS-Plus-IoT-SDK/abstractions/platform/include/platform/iot_clock.h new file mode 100644 index 000000000..93c7dcb54 --- /dev/null +++ b/FreeRTOS-Plus/Source/FreeRTOS-Plus-IoT-SDK/abstractions/platform/include/platform/iot_clock.h @@ -0,0 +1,216 @@ +/* + * Amazon FreeRTOS Platform V1.0.0 + * Copyright (C) 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to + * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of + * the Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * http://aws.amazon.com/freertos + * http://www.FreeRTOS.org + */ + +/** + * @file iot_clock.h + * @brief Time-related functions used by libraries in this SDK. + */ + +#ifndef IOT_CLOCK_H_ +#define IOT_CLOCK_H_ + +/* The config header is always included first. */ +#include "iot_config.h" + +/* Standard includes. */ +#include +#include +#include + +/* Platform layer types include. */ +#include "types/iot_platform_types.h" + +/** + * @functionspage{platform_clock,platform clock component,Clock} + * - @functionname{platform_clock_function_gettimestring} + * - @functionname{platform_clock_function_gettimems} + * - @functionname{platform_clock_function_sleepms} + * - @functionname{platform_clock_function_timercreate} + * - @functionname{platform_clock_function_timerdestroy} + * - @functionname{platform_clock_function_timerarm} + */ + +/** + * @functionpage{IotClock_GetTimestring,platform_clock,gettimestring} + * @functionpage{IotClock_GetTimeMs,platform_clock,gettimems} + * @functionpage{IotClock_SleepMs,platform_clock,sleepms} + * @functionpage{IotClock_TimerCreate,platform_clock,timercreate} + * @functionpage{IotClock_TimerDestroy,platform_clock,timerdestroy} + * @functionpage{IotClock_TimerArm,platform_clock,timerarm} + */ + +/** + * @brief Generates a human-readable timestring, such as "01 Jan 2018 12:00". + * + * This function uses the system clock to generate a human-readable timestring. + * This timestring is printed by the [logging functions](@ref logging_functions). + * + * @param[out] pBuffer A buffer to store the timestring in. + * @param[in] bufferSize The size of `pBuffer`. + * @param[out] pTimestringLength The actual length of the timestring stored in + * `pBuffer`. + * + * @return `true` if a timestring was successfully generated; `false` otherwise. + * + * @warning The implementation of this function must not call any [logging functions] + * (@ref logging_functions). + * + * Example + * @code{c} + * char timestring[ 32 ]; + * size_t timestringLength = 0; + * + * if( IotClock_GetTimestring( timestring, 32, ×tringLength ) == true ) + * { + * printf( "Timestring: %.*s", timestringLength, timestring ); + * } + * @endcode + */ +/* @[declare_platform_clock_gettimestring] */ +bool IotClock_GetTimestring( char * pBuffer, + size_t bufferSize, + size_t * pTimestringLength ); +/* @[declare_platform_clock_gettimestring] */ + +/** + * @brief Returns a nonzero, monotonically-increasing system time in milliseconds. + * + * This function reads a millisecond-resolution system clock. The clock should + * always be monotonically-increasing; therefore, real-time clocks that may be + * set by another process are not suitable for this function's implementation. + * + * @return The value of the system clock. This function is not expected to fail. + * + * Example + * @code{c} + * // Get current time. + * uint64_t currentTime = IotClock_GetTimeMs(); + * @endcode + */ +/* @[declare_platform_clock_gettimems] */ +uint64_t IotClock_GetTimeMs( void ); +/* @[declare_platform_clock_gettimems] */ + +/** + * @brief Delay for the given number of milliseconds. + * + * This function suspends its calling thread for at least `sleepTimeMs` milliseconds. + * + * @param[in] sleepTimeMs Sleep time (in milliseconds). + */ +/* @[declare_platform_clock_sleepms] */ +void IotClock_SleepMs( uint32_t sleepTimeMs ); +/* @[declare_platform_clock_sleepms] */ + +/** + * @brief Create a new timer. + * + * This function creates a new, unarmed timer. It must be called on an uninitialized + * #IotTimer_t. This function must not be called on an already-initialized #IotTimer_t. + * + * @param[out] pNewTimer Set to a new timer handle on success. + * @param[in] expirationRoutine The function to run when this timer expires. This + * function should be called in its own detached thread. + * @param[in] pArgument The argument to pass to `expirationRoutine`. + * + * @return `true` if the timer is successfully created; `false` otherwise. + * + * @see @ref platform_clock_function_timerdestroy, @ref platform_clock_function_timerarm + */ +/* @[declare_platform_clock_timercreate] */ +bool IotClock_TimerCreate( IotTimer_t * pNewTimer, + IotThreadRoutine_t expirationRoutine, + void * pArgument ); +/* @[declare_platform_clock_timercreate] */ + +/** + * @brief Free resources used by a timer. + * + * This function frees resources used by a timer. It must be called on an initialized + * #IotTimer_t. No other timer functions should be called on `pTimer` after calling + * this function (unless the timer is re-created). + * + * This function will stop the `pTimer` if it is armed. + * + * @param[in] pTimer The timer to destroy. + * + * @see @ref platform_clock_function_timercreate, @ref platform_clock_function_timerarm + */ +/* @[declare_platform_clock_timerdestroy] */ +void IotClock_TimerDestroy( IotTimer_t * pTimer ); +/* @[declare_platform_clock_timerdestroy] */ + +/** + * @brief Arm a timer to expire at the given relative timeout. + * + * This function arms a timer to run its expiration routine at the given time. + * + * If `periodMs` is nonzero, the timer should expire periodically at intervals + * such as: + * - `relativeTimeoutMs` + * - `relativeTimeoutMs + periodMs` + * - `relativeTimeoutMs + 2 * periodMs` + * - Etc. (subject to some jitter). + * + * Setting `periodMs` to `0` arms a one-shot, non-periodic timer. + * + * @param[in] pTimer The timer to arm. + * @param[in] relativeTimeoutMs When the timer should expire, relative to the time + * this function is called. + * @param[in] periodMs How often the timer should expire again after `relativeTimerMs`. + * + * @return `true` if the timer was successfully armed; `false` otherwise. + * + * @see @ref platform_clock_function_timercreate, @ref platform_clock_function_timerdestroy + * + * Example + * @code{c} + * + * void timerExpirationRoutine( void * pArgument ); + * + * void timerExample( void ) + * { + * IotTimer_t timer; + * + * if( IotClock_TimerCreate( &timer, timerExpirationRoutine, NULL ) == true ) + * { + * // Set the timer to periodically expire every 10 seconds. + * if( IotClock_TimerArm( &timer, 10000, 10000 ) == true ) + * { + * // Wait for timer to expire. + * } + * + * IotClock_TimerDestroy( &timer ); + * } + * } + * @endcode + */ +/* @[declare_platform_clock_timerarm] */ +bool IotClock_TimerArm( IotTimer_t * pTimer, + uint32_t relativeTimeoutMs, + uint32_t periodMs ); +/* @[declare_platform_clock_timerarm] */ + +#endif /* ifndef IOT_CLOCK_H_ */ diff --git a/FreeRTOS-Plus/Source/FreeRTOS-Plus-IoT-SDK/abstractions/platform/include/platform/iot_metrics.h b/FreeRTOS-Plus/Source/FreeRTOS-Plus-IoT-SDK/abstractions/platform/include/platform/iot_metrics.h new file mode 100644 index 000000000..74eb4f626 --- /dev/null +++ b/FreeRTOS-Plus/Source/FreeRTOS-Plus-IoT-SDK/abstractions/platform/include/platform/iot_metrics.h @@ -0,0 +1,103 @@ +/* + * Amazon FreeRTOS Platform V1.0.0 + * Copyright (C) 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to + * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of + * the Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * http://aws.amazon.com/freertos + * http://www.FreeRTOS.org + */ + +/** + * @file iot_metrics.h + * @brief Functions for retrieving [Device Defender](@ref defender) metrics. + * + * The functions in this header are only required by Device Defender. They do not + * need to be implemented if Device Defender is not used. + */ + +#ifndef IOT_METRICS_H_ +#define IOT_METRICS_H_ + +/* The config header is always included first. */ +#include "iot_config.h" + +/* Standard includes. */ +#include + +/* Linear containers (lists and queues) include. */ +#include "iot_linear_containers.h" + +/** + * @functionspage{platform_metrics,platform metrics component,Metrics} + * - @functionname{platform_metrics_function_init} + * - @functionname{platform_metrics_function_cleanup} + * - @functionname{platform_metrics_function_gettcpconnections} + */ + +/** + * @functionpage{IotMetrics_Init,platform_metrics,init} + * @functionpage{IotMetrics_Cleanup,platform_metrics,cleanup} + * @functionpage{IotMetrics_GetTcpConnections,platform_metrics,gettcpconnections} + */ + +/** + * @brief One-time initialization function for the platform metrics component. + * + * This function initializes the platform metrics component. It must be called + * once (and only once) before calling any other metrics or [Device Defender function] + * (@ref defender_functions). Calling this function more than once without first + * calling @ref platform_metrics_function_cleanup may result in a crash. + * + * @return `true` is initialization succeeded; `false` otherwise. + * + * @warning No thread-safety guarantees are provided for this function. + */ +/* @[declare_platform_metrics_init] */ +bool IotMetrics_Init( void ); +/* @[declare_platform_metrics_init] */ + +/** + * @brief One-time deinitialization function for the platform metrics component. + * + * This function frees resources taken in @ref platform_metrics_function_init. + * No other metrics or [Device Defender functions](@ref defender_functions) may + * be called unless @ref platform_metrics_function_init is called again. + * + * @warning No thread-safety guarantees are provided for this function. + */ +/* @[declare_platform_metrics_cleanup] */ +void IotMetrics_Cleanup( void ); +/* @[declare_platform_metrics_cleanup] */ + +/** + * @brief Retrieve a list of active TCP connections from the system. + * + * The provided connections are reported by Device Defender. + * + * @param[in] pContext Context passed as the first parameter of `metricsCallback`. + * @param[in] metricsCallback Called by this function to provide the list of TCP + * connections. The list given by this function is should not be used after the + * callback returns. + */ +/* @[declare_platform_metrics_gettcpconnections] */ +void IotMetrics_GetTcpConnections( void * pContext, + void ( * metricsCallback )( void *, const IotListDouble_t * ) ); +/* @[declare_platform_metrics_gettcpconnections] */ + +#endif /* ifndef IOT_METRICS_H_ */ diff --git a/FreeRTOS-Plus/Source/FreeRTOS-Plus-IoT-SDK/abstractions/platform/include/platform/iot_network.h b/FreeRTOS-Plus/Source/FreeRTOS-Plus-IoT-SDK/abstractions/platform/include/platform/iot_network.h new file mode 100644 index 000000000..f52e4bb06 --- /dev/null +++ b/FreeRTOS-Plus/Source/FreeRTOS-Plus-IoT-SDK/abstractions/platform/include/platform/iot_network.h @@ -0,0 +1,294 @@ +/* + * Amazon FreeRTOS Platform V1.0.0 + * Copyright (C) 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to + * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of + * the Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * http://aws.amazon.com/freertos + * http://www.FreeRTOS.org + */ + +/** + * @file iot_network.h + * @brief Abstraction of network functions used by libraries in this SDK. + */ + +#ifndef IOT_NETWORK_H_ +#define IOT_NETWORK_H_ + +/* Standard includes. */ +#include +#include +#include + +/** + * @ingroup platform_datatypes_enums + * @brief Return codes for [network functions](@ref platform_network_functions). + */ +typedef enum IotNetworkError +{ + IOT_NETWORK_SUCCESS = 0, /**< Function successfully completed. */ + IOT_NETWORK_FAILURE, /**< Generic failure not covered by other values. */ + IOT_NETWORK_BAD_PARAMETER, /**< At least one parameter was invalid. */ + IOT_NETWORK_NO_MEMORY, /**< Memory allocation failed. */ + IOT_NETWORK_SYSTEM_ERROR /**< An error occurred when calling a system API. */ +} IotNetworkError_t; + +/** + * @page platform_network_functions Networking + * @brief Functions of the network abstraction component. + * + * The network abstraction component does not declare functions, but uses function + * pointers instead. This allows multiple network stacks to be used at the same time. + * Libraries that require the network will request an #IotNetworkInterface_t + * parameter. The members of the #IotNetworkInterface_t will be called whenever + * the library interacts with the network. + * + * The following function pointers are associated with an #IotNetworkInterface_t. + * Together, they represent a network stack. + * - @functionname{platform_network_function_create} + * - @functionname{platform_network_function_setreceivecallback} + * - @functionname{platform_network_function_send} + * - @functionname{platform_network_function_receive} + * - @functionname{platform_network_function_close} + * - @functionname{platform_network_function_destroy} + * - @functionname{platform_network_function_receivecallback} + */ + +/** + * @functionpage{IotNetworkInterface_t::create,platform_network,create} + * @functionpage{IotNetworkInterface_t::setReceiveCallback,platform_network,setreceivecallback} + * @functionpage{IotNetworkInterface_t::send,platform_network,send} + * @functionpage{IotNetworkInterface_t::receive,platform_network,receive} + * @functionpage{IotNetworkInterface_t::close,platform_network,close} + * @functionpage{IotNetworkInterface_t::destroy,platform_network,destroy} + * @functionpage{IotNetworkReceiveCallback_t,platform_network,receivecallback} + */ + +/** + * @brief Provide an asynchronous notification of incoming network data. + * + * A function with this signature may be set with @ref platform_network_function_setreceivecallback + * to be invoked when data is available on the network. + * + * @param[in] pConnection The connection on which data is available, defined by + * the network stack. + * @param[in] pContext The third argument passed to @ref platform_network_function_setreceivecallback. + */ +/* @[declare_platform_network_receivecallback] */ +typedef void ( * IotNetworkReceiveCallback_t )( void * pConnection, + void * pContext ); +/* @[declare_platform_network_receivecallback] */ + +/** + * @ingroup platform_datatypes_paramstructs + * @brief Represents the functions of a network stack. + * + * Functions that match these signatures should be implemented against a system's + * network stack. See the `platform` directory for existing implementations. + */ +typedef struct IotNetworkInterface +{ + /** + * @brief Create a new network connection. + * + * This function allocates resources and establishes a new network connection. + * @param[in] pConnectionInfo Represents information needed to set up the + * new connection, defined by the network stack. + * @param[in] pCredentialInfo Represents information needed to secure the + * new connection, defined by the network stack. + * @param[out] pConnection Set to represent a new connection, defined by the + * network stack. + * + * @return Any #IotNetworkError_t, as defined by the network stack. + */ + /* @[declare_platform_network_create] */ + IotNetworkError_t ( * create )( void * pConnectionInfo, + void * pCredentialInfo, + void ** pConnection ); + /* @[declare_platform_network_create] */ + + /** + * @brief Register an @ref platform_network_function_receivecallback. + * + * Sets an @ref platform_network_function_receivecallback to be called + * asynchronously when data arrives on the network. The network stack + * should invoke this function "as if" it were the thread routine of a + * detached thread. + * + * Each network connection may only have one receive callback at any time. + * @ref platform_network_function_close is expected to remove any active + * receive callbacks. + * + * @param[in] pConnection The connection to associate with the receive callback. + * @param[in] receiveCallback The function to invoke for incoming network data. + * @param[in] pContext A value to pass as the first parameter to the receive callback. + * + * @return Any #IotNetworkError_t, as defined by the network stack. + * + * @see platform_network_function_receivecallback + */ + /* @[declare_platform_network_setreceivecallback] */ + IotNetworkError_t ( * setReceiveCallback )( void * pConnection, + IotNetworkReceiveCallback_t receiveCallback, + void * pContext ); + /* @[declare_platform_network_setreceivecallback] */ + + /** + * @brief Send data over a return connection. + * + * Attempts to transmit `messageLength` bytes of `pMessage` across the + * connection represented by `pConnection`. Returns the number of bytes + * actually sent, `0` on failure. + * + * @param[in] pConnection The connection used to send data, defined by the + * network stack. + * @param[in] pMessage The message to send. + * @param[in] messageLength The length of `pMessage`. + * + * @return The number of bytes successfully sent, `0` on failure. + */ + /* @[declare_platform_network_send] */ + size_t ( * send )( void * pConnection, + const uint8_t * pMessage, + size_t messageLength ); + /* @[declare_platform_network_send] */ + + /** + * @brief Block and wait for incoming network data. + * + * Wait for a message of size `bytesRequested` to arrive on the network and + * place it in `pBuffer`. + * + * @param[in] pConnection The connection to wait on, defined by the network + * stack. + * @param[out] pBuffer Where to place the incoming network data. This buffer + * must be at least `bytesRequested` in size. + * @param[in] bytesRequested How many bytes to wait for. `pBuffer` must be at + * least this size. + * + * @return The number of bytes successfully received. This should be + * `bytesRequested` when successful. Any other value may indicate an error. + */ + /* @[declare_platform_network_receive] */ + size_t ( * receive )( void * pConnection, + uint8_t * pBuffer, + size_t bytesRequested ); + /* @[declare_platform_network_receive] */ + + /** + * @brief Close a network connection. + * + * This function closes the connection, but does not release the resources + * used by the connection. This allows calls to other networking functions + * to return an error and handle a closed connection without the risk of + * crashing. Once it can be guaranteed that `pConnection` will no longer be + * used, the connection can be destroyed with @ref platform_network_function_destroy. + * + * In addition to closing the connection, this function should also remove + * any active [receive callback](@ref platform_network_function_receivecallback). + * + * @param[in] pConnection The network connection to close, defined by the + * network stack. + * + * @return Any #IotNetworkError_t, as defined by the network stack. + * + * @note It must be safe to call this function on an already-closed connection. + */ + /* @[declare_platform_network_close] */ + IotNetworkError_t ( * close )( void * pConnection ); + /* @[declare_platform_network_close] */ + + /** + * @brief Free resources used by a network connection. + * + * This function releases the resources of a closed connection. It should be + * called after @ref platform_network_function_close. + * + * @param[in] pConnection The network connection to destroy, defined by + * the network stack. + * + * @return Any #IotNetworkError_t, as defined by the network stack. + * + * @attention No function should be called on the network connection after + * calling this function. This function must be safe to call from a + * [receive callback](@ref platform_network_function_receivecallback). + */ + /* @[declare_platform_network_destroy] */ + IotNetworkError_t ( * destroy )( void * pConnection ); + /* @[declare_platform_network_destroy] */ +} IotNetworkInterface_t; + +/** + * @ingroup platform_datatypes_paramstructs + * @brief Information on the remote server for connection setup. + * + * May be passed to #IotNetworkInterface_t.create as `pConnectionInfo`. This + * structure contains commonly-used parameters, but may be replaced with an + * alternative. + */ +typedef struct IotNetworkServerInfo +{ + const char * pHostName; /**< @brief Server host name. Must be NULL-terminated. */ + uint16_t port; /**< @brief Server port in host-order. */ +} IotNetworkServerInfo_t; + +/** + * @ingroup platform_datatypes_paramstructs + * @brief Contains the credentials necessary for connection setup. + * + * May be passed to #IotNetworkInterface_t.create as `pCredentialInfo`. This + * structure contains commonly-used parameters, but may be replaced with an + * alternative. + */ +typedef struct IotNetworkCredentials +{ + /** + * @brief Set this to a non-NULL value to use ALPN. + * + * This string must be NULL-terminated. + * + * See [this link] + * (https://aws.amazon.com/blogs/iot/mqtt-with-tls-client-authentication-on-port-443-why-it-is-useful-and-how-it-works/) + * for more information. + */ + const char * pAlpnProtos; + + /** + * @brief Set this to a non-zero value to use TLS max fragment length + * negotiation (TLS MFLN). + * + * @note The network stack may have a minimum value for this parameter and + * may return an error if this parameter is too small. + */ + size_t maxFragmentLength; + + /** + * @brief Disable server name indication (SNI) for a TLS session. + */ + bool disableSni; + + const char * pRootCa; /**< @brief String representing a trusted server root certificate. */ + size_t rootCaSize; /**< @brief Size associated with #IotNetworkCredentials_t.pRootCa. */ + const char * pClientCert; /**< @brief String representing the client certificate. */ + size_t clientCertSize; /**< @brief Size associated with #IotNetworkCredentials_t.pClientCert. */ + const char * pPrivateKey; /**< @brief String representing the client certificate's private key. */ + size_t privateKeySize; /**< @brief Size associated with #IotNetworkCredentials_t.pPrivateKey. */ +} IotNetworkCredentials_t; + +#endif /* ifndef IOT_NETWORK_H_ */ diff --git a/FreeRTOS-Plus/Source/FreeRTOS-Plus-IoT-SDK/abstractions/platform/include/platform/iot_threads.h b/FreeRTOS-Plus/Source/FreeRTOS-Plus-IoT-SDK/abstractions/platform/include/platform/iot_threads.h new file mode 100644 index 000000000..58571d840 --- /dev/null +++ b/FreeRTOS-Plus/Source/FreeRTOS-Plus-IoT-SDK/abstractions/platform/include/platform/iot_threads.h @@ -0,0 +1,355 @@ +/* + * Amazon FreeRTOS Platform V1.0.0 + * Copyright (C) 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to + * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of + * the Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * http://aws.amazon.com/freertos + * http://www.FreeRTOS.org + */ + +/** + * @file iot_threads.h + * @brief Threading and synchronization functions used by libraries in this SDK. + */ + +#ifndef IOT_THREADS_H_ +#define IOT_THREADS_H_ + +/* The config header is always included first. */ +#include "iot_config.h" + +/* Standard includes. */ +#include +#include + +/* Platform layer types include. */ +#include "types/iot_platform_types.h" + +/** + * @functionspage{platform_threads,platform thread management,Thread Management} + * - @functionname{platform_threads_function_createdetachedthread} + * - @functionname{platform_threads_function_mutexcreate} + * - @functionname{platform_threads_function_mutexdestroy} + * - @functionname{platform_threads_function_mutexlock} + * - @functionname{platform_threads_function_mutextrylock} + * - @functionname{platform_threads_function_mutexunlock} + * - @functionname{platform_threads_function_semaphorecreate} + * - @functionname{platform_threads_function_semaphoredestroy} + * - @functionname{platform_threads_function_semaphoregetcount} + * - @functionname{platform_threads_function_semaphorewait} + * - @functionname{platform_threads_function_semaphoretrywait} + * - @functionname{platform_threads_function_semaphoretimedwait} + * - @functionname{platform_threads_function_semaphorepost} + */ + +/** + * @functionpage{Iot_CreateDetachedThread,platform_threads,createdetachedthread} + * @functionpage{IotMutex_Create,platform_threads,mutexcreate} + * @functionpage{IotMutex_Destroy,platform_threads,mutexdestroy} + * @functionpage{IotMutex_Lock,platform_threads,mutexlock} + * @functionpage{IotMutex_TryLock,platform_threads,mutextrylock} + * @functionpage{IotMutex_Unlock,platform_threads,mutexunlock} + * @functionpage{IotSemaphore_Create,platform_threads,semaphorecreate} + * @functionpage{IotSemaphore_Destroy,platform_threads,semaphoredestroy} + * @functionpage{IotSemaphore_GetCount,platform_threads,semaphoregetcount} + * @functionpage{IotSemaphore_Wait,platform_threads,semaphorewait} + * @functionpage{IotSemaphore_TryWait,platform_threads,semaphoretrywait} + * @functionpage{IotSemaphore_TimedWait,platform_threads,semaphoretimedwait} + * @functionpage{IotSemaphore_Post,platform_threads,semaphorepost} + */ + +/** + * @brief Create a new detached thread, i.e. a thread that cleans up after itself. + * + * This function creates a new thread. Threads created by this function exit + * upon returning from the thread routine. Any resources taken must be freed + * by the exiting thread. + * + * @param[in] threadRoutine The function this thread should run. + * @param[in] pArgument The argument passed to `threadRoutine`. + * @param[in] priority Represents the priority of the new thread, as defined by + * the system. The value #IOT_THREAD_DEFAULT_PRIORITY (i.e. `0`) must be used to + * represent the system default for thread priority. + * @param[in] stackSize Represents the stack size of the new thread, as defined + * by the system. The value #IOT_THREAD_DEFAULT_STACK_SIZE (i.e. `0`) must be used + * to represent the system default for stack size. + * + * @return `true` if the new thread was successfully created; `false` otherwise. + * + * @code{c} + * // Thread routine. + * void threadRoutine( void * pArgument ); + * + * // Run threadRoutine in a detached thread, using default priority and stack size. + * if( Iot_CreateDetachedThread( threadRoutine, + * NULL, + * IOT_THREAD_DEFAULT_PRIORITY, + * IOT_THREAD_DEFAULT_STACK_SIZE ) == true ) + * { + * // Success + * } + * else + * { + * // Failure, no thread was created. + * } + * @endcode + */ +/* @[declare_platform_threads_createdetachedthread] */ +bool Iot_CreateDetachedThread( IotThreadRoutine_t threadRoutine, + void * pArgument, + int32_t priority, + size_t stackSize ); +/* @[declare_platform_threads_createdetachedthread] */ + +/** + * @brief Create a new mutex. + * + * This function creates a new, unlocked mutex. It must be called on an uninitialized + * #IotMutex_t. This function must not be called on an already-initialized #IotMutex_t. + * + * @param[in] pNewMutex Pointer to the memory that will hold the new mutex. + * @param[in] recursive Set to `true` to create a recursive mutex, i.e. a mutex that + * may be locked multiple times by the same thread. If the system does not support + * recursive mutexes, this function should do nothing and return `false`. + * + * @return `true` if mutex creation succeeds; `false` otherwise. + * + * @see @ref platform_threads_function_mutexdestroy + * + * Example + * @code{c} + * IotMutex_t mutex; + * + * // Create non-recursive mutex. + * if( IotMutex_Create( &mutex, false ) == true ) + * { + * // Lock and unlock the mutex... + * + * // Destroy the mutex when it's no longer needed. + * IotMutex_Destroy( &mutex ); + * } + * @endcode + */ +/* @[declare_platform_threads_mutexcreate] */ +bool IotMutex_Create( IotMutex_t * pNewMutex, bool recursive ); +/* @[declare_platform_threads_mutexcreate] */ + +/** + * @brief Free resources used by a mutex. + * + * This function frees resources used by a mutex. It must be called on an initialized + * #IotMutex_t. No other mutex functions should be called on `pMutex` after calling + * this function (unless the mutex is re-created). + * + * @param[in] pMutex The mutex to destroy. + * + * @warning This function must not be called on a locked mutex. + * @see @ref platform_threads_function_mutexcreate + */ +/* @[declare_platform_threads_mutexdestroy] */ +void IotMutex_Destroy( IotMutex_t * pMutex ); +/* @[declare_platform_threads_mutexdestroy] */ + +/** + * @brief Lock a mutex. This function should only return when the mutex is locked; + * it is not expected to fail. + * + * This function blocks and waits until a mutex is available. It waits forever + * (deadlocks) if `pMutex` is already locked and never unlocked. + * + * @param[in] pMutex The mutex to lock. + * + * @see @ref platform_threads_function_mutextrylock for a nonblocking lock. + */ +/* @[declare_platform_threads_mutexlock] */ +void IotMutex_Lock( IotMutex_t * pMutex ); +/* @[declare_platform_threads_mutexlock] */ + +/** + * @brief Attempt to lock a mutex. Return immediately if the mutex is not available. + * + * If `pMutex` is available, this function immediately locks it and returns. + * Otherwise, this function returns without locking `pMutex`. + * + * @param[in] pMutex The mutex to lock. + * + * @return `true` if the mutex was successfully locked; `false` if the mutex was + * not available. + * + * @see @ref platform_threads_function_mutexlock for a blocking lock. + */ +/* @[declare_platform_threads_mutextrylock] */ +bool IotMutex_TryLock( IotMutex_t * pMutex ); +/* @[declare_platform_threads_mutextrylock] */ + +/** + * @brief Unlock a mutex. This function should only return when the mutex is unlocked; + * it is not expected to fail. + * + * Unlocks a locked mutex. `pMutex` must have been locked by the thread calling + * this function. + * + * @param[in] pMutex The mutex to unlock. + * + * @note This function should not be called on a mutex that is already unlocked. + */ +/* @[declare_platform_threads_mutexunlock] */ +void IotMutex_Unlock( IotMutex_t * pMutex ); +/* @[declare_platform_threads_mutexunlock] */ + +/** + * @brief Create a new counting semaphore. + * + * This function creates a new counting semaphore with a given intial and + * maximum value. It must be called on an uninitialized #IotSemaphore_t. + * This function must not be called on an already-initialized #IotSemaphore_t. + * + * @param[in] pNewSemaphore Pointer to the memory that will hold the new semaphore. + * @param[in] initialValue The semaphore should be initialized with this value. + * @param[in] maxValue The maximum value the semaphore will reach. + * + * @return `true` if semaphore creation succeeds; `false` otherwise. + * + * @see @ref platform_threads_function_semaphoredestroy + * + * Example + * @code{c} + * IotSemaphore_t sem; + * + * // Create a locked binary semaphore. + * if( IotSemaphore_Create( &sem, 0, 1 ) == true ) + * { + * // Unlock the semaphore. + * IotSemaphore_Post( &sem ); + * + * // Destroy the semaphore when it's no longer needed. + * IotSemaphore_Destroy( &sem ); + * } + * @endcode + */ +/* @[declare_platform_threads_semaphorecreate] */ +bool IotSemaphore_Create( IotSemaphore_t * pNewSemaphore, + uint32_t initialValue, + uint32_t maxValue ); +/* @[declare_platform_threads_semaphorecreate] */ + +/** + * @brief Free resources used by a semaphore. + * + * This function frees resources used by a semaphore. It must be called on an initialized + * #IotSemaphore_t. No other semaphore functions should be called on `pSemaphore` after + * calling this function (unless the semaphore is re-created). + * + * @param[in] pSemaphore The semaphore to destroy. + * + * @warning This function must not be called on a semaphore with waiting threads. + * @see @ref platform_threads_function_semaphorecreate + */ +/* @[declare_platform_threads_semaphoredestroy] */ +void IotSemaphore_Destroy( IotSemaphore_t * pSemaphore ); +/* @[declare_platform_threads_semaphoredestroy] */ + +/** + * @brief Query the current count of the semaphore. + * + * This function queries a counting semaphore for its current value. A counting + * semaphore's value is always 0 or positive. + * + * @param[in] pSemaphore The semaphore to query. + * + * @return The current count of the semaphore. This function should not fail. + */ +/* @[declare_platform_threads_semaphoregetcount] */ +uint32_t IotSemaphore_GetCount( IotSemaphore_t * pSemaphore ); +/* @[declare_platform_threads_semaphoregetcount] */ + +/** + * @brief Wait on (lock) a semaphore. This function should only return when the + * semaphore wait succeeds; it is not expected to fail. + * + * This function blocks and waits until a counting semaphore is positive. It + * waits forever (deadlocks) if `pSemaphore` has a count `0` that is never + * [incremented](@ref platform_threads_function_semaphorepost). + * + * @param[in] pSemaphore The semaphore to lock. + * + * @see @ref platform_threads_function_semaphoretrywait for a nonblocking wait; + * @ref platform_threads_function_semaphoretimedwait for a wait with timeout. + */ +/* @[declare_platform_threads_semaphorewait] */ +void IotSemaphore_Wait( IotSemaphore_t * pSemaphore ); +/* @[declare_platform_threads_semaphorewait] */ + +/** + * @brief Attempt to wait on (lock) a semaphore. Return immediately if the semaphore + * is not available. + * + * If the count of `pSemaphore` is positive, this function immediately decrements + * the semaphore and returns. Otherwise, this function returns without decrementing + * `pSemaphore`. + * + * @param[in] pSemaphore The semaphore to lock. + * + * @return `true` if the semaphore wait succeeded; `false` if the semaphore has + * a count of `0`. + * + * @see @ref platform_threads_function_semaphorewait for a blocking wait; + * @ref platform_threads_function_semaphoretimedwait for a wait with timeout. + */ +/* @[declare_platform_threads_semaphoretrywait] */ +bool IotSemaphore_TryWait( IotSemaphore_t * pSemaphore ); +/* @[declare_platform_threads_semaphoretrywait] */ + +/** + * @brief Attempt to wait on (lock) a semaphore with a timeout. + * + * This function blocks and waits until a counting semaphore is positive + * or its timeout expires (whichever is sooner). It decrements + * `pSemaphore` and returns `true` if the semaphore is positive at some + * time during the wait. If `pSemaphore` is always `0` during the wait, + * this function returns `false`. + * + * @param[in] pSemaphore The semaphore to lock. + * @param[in] timeoutMs Relative timeout of semaphore lock. This function returns + * false if the semaphore couldn't be locked within this timeout. + * + * @return `true` if the semaphore wait succeeded; `false` if it timed out. + * + * @see @ref platform_threads_function_semaphoretrywait for a nonblocking wait; + * @ref platform_threads_function_semaphorewait for a blocking wait. + */ +/* @[declare_platform_threads_semaphoretimedwait] */ +bool IotSemaphore_TimedWait( IotSemaphore_t * pSemaphore, + uint32_t timeoutMs ); +/* @[declare_platform_threads_semaphoretimedwait] */ + +/** + * @brief Post to (unlock) a semaphore. This function should only return when the + * semaphore post succeeds; it is not expected to fail. + * + * This function increments the count of a semaphore. Any thread may call this + * function to increment a semaphore's count. + * + * @param[in] pSemaphore The semaphore to unlock. + */ +/* @[declare_platform_threads_semaphorepost] */ +void IotSemaphore_Post( IotSemaphore_t * pSemaphore ); +/* @[declare_platform_threads_semaphorepost] */ + +#endif /* ifndef IOT_THREADS_H_ */ diff --git a/FreeRTOS-Plus/Source/FreeRTOS-Plus-IoT-SDK/abstractions/platform/include/types/iot_platform_types.h b/FreeRTOS-Plus/Source/FreeRTOS-Plus-IoT-SDK/abstractions/platform/include/types/iot_platform_types.h new file mode 100644 index 000000000..e9fc7851c --- /dev/null +++ b/FreeRTOS-Plus/Source/FreeRTOS-Plus-IoT-SDK/abstractions/platform/include/types/iot_platform_types.h @@ -0,0 +1,158 @@ +/* + * Amazon FreeRTOS Platform V1.0.0 + * Copyright (C) 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to + * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of + * the Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * http://aws.amazon.com/freertos + * http://www.FreeRTOS.org + */ + +/** + * @file iot_platform_types.h + * @brief Types of the platform layer. + */ + +#ifndef IOT_PLATFORM_TYPES_H_ +#define IOT_PLATFORM_TYPES_H_ + +/* The config header is always included first. */ +#include "iot_config.h" + +/* Linear containers (lists and queues) include for metrics types. */ +#include "iot_linear_containers.h" + +/*------------------------- Thread management types -------------------------*/ + +/** + * @brief A value representing the system default for new thread priority. + */ +#ifndef IOT_THREAD_DEFAULT_PRIORITY + #define IOT_THREAD_DEFAULT_PRIORITY 0 +#endif + +/** + * @brief A value representhing the system default for new thread stack size. + */ +#ifndef IOT_THREAD_DEFAULT_STACK_SIZE + #define IOT_THREAD_DEFAULT_STACK_SIZE 0 +#endif + +/** + * @ingroup platform_datatypes_handles + * @brief The type used to represent mutexes, configured with the type + * `_IotSystemMutex_t`. + * + * + * `_IotSystemMutex_t` will be automatically configured during build and generally + * does not need to be defined. + * + * + * Mutexes should only be released by the threads that take them. + * + * Example
+ * To change the type of #IotMutex_t to `long`: + * @code{c} + * typedef long _IotSystemMutex_t; + * #include "iot_threads.h" + * @endcode + */ +typedef _IotSystemMutex_t IotMutex_t; + +/** + * @ingroup platform_datatypes_handles + * @brief The type used to represent semaphores, configured with the type + * `_IotSystemSemaphore_t`. + * + * + * `_IotSystemSemaphore_t` will be automatically configured during build and + * generally does not need to be defined. + * + * + * Semaphores must be counting, and any thread may take (wait on) or release + * (post to) a semaphore. + * + * Example
+ * To change the type of #IotSemaphore_t to `long`: + * @code{c} + * typedef long _IotSystemSemaphore_t; + * #include "iot_threads.h" + * @endcode + */ +typedef _IotSystemSemaphore_t IotSemaphore_t; + +/** + * @brief Thread routine function. + * + * @param[in] void * The argument passed to the @ref + * platform_threads_function_createdetachedthread. For application use. + */ +typedef void ( * IotThreadRoutine_t )( void * ); + +/*-------------------------- Clock and timer types --------------------------*/ + +/** + * @ingroup platform_datatypes_handles + * @brief The type used to represent timers, configured with the type + * `_IotSystemTimer_t`. + * + * + * `_IotSystemTimer_t` will be automatically configured during build and generally + * does not need to be defined. + * + * + * Example
+ * To change the type of #IotTimer_t to `long`: + * @code{c} + * typedef long _IotSystemTimer_t; + * #include "iot_clock.h" + * @endcode + */ +typedef _IotSystemTimer_t IotTimer_t; + +/*------------------------------ Metrics types ------------------------------*/ + +/** + * @brief The length of the buffer used to store IP addresses for metrics. + * + * This is the length of the longest IPv6 address plus space for the port number + * and NULL terminator. + */ +#define IOT_METRICS_IP_ADDRESS_LENGTH 54 + +/** + * @brief Represents a TCP connection to a remote IPv4 server. + * + * A list of these is provided by @ref platform_metrics_function_gettcpconnections. + */ +typedef struct IotMetricsTcpConnection +{ + IotLink_t link; /**< @brief List link member. */ + void * pNetworkContext; /**< @brief Context that may be used by metrics or Defender. */ + size_t addressLength; /**< @brief The length of the address stored in #IotMetricsTcpConnection_t.pRemoteAddress. */ + + /** + * @brief NULL-terminated IP address and port in text format. + * + * IPv4 addresses will be in the format `xxx.xxx.xxx.xxx:port`. + * IPv6 addresses will be in the format `[xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx]:port`. + */ + char pRemoteAddress[ IOT_METRICS_IP_ADDRESS_LENGTH ]; +} IotMetricsTcpConnection_t; + +#endif /* ifndef IOT_PLATFORM_TYPES_H_ */ diff --git a/FreeRTOS-Plus/Source/FreeRTOS-Plus-IoT-SDK/c_sdk/standard/common/include/iot_atomic.h b/FreeRTOS-Plus/Source/FreeRTOS-Plus-IoT-SDK/c_sdk/standard/common/include/iot_atomic.h new file mode 100644 index 000000000..ff2a21972 --- /dev/null +++ b/FreeRTOS-Plus/Source/FreeRTOS-Plus-IoT-SDK/c_sdk/standard/common/include/iot_atomic.h @@ -0,0 +1,39 @@ +/* + * Amazon FreeRTOS Common V1.0.0 + * Copyright (C) 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to + * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of + * the Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * http://aws.amazon.com/freertos + * http://www.FreeRTOS.org + */ + +/** + * @file iot_atomic.h + * @brief Chooses the appropriate atomic operations header. + * + * On FreeRTOS, this file chooses the atomic header provided with the FreeRTOS + * kernel. + */ + +#ifndef IOT_ATOMIC_H_ +#define IOT_ATOMIC_H_ + +#include "atomic.h" + +#endif /* ifndef IOT_ATOMIC_H_ */ diff --git a/FreeRTOS-Plus/Source/FreeRTOS-Plus-IoT-SDK/c_sdk/standard/common/include/iot_init.h b/FreeRTOS-Plus/Source/FreeRTOS-Plus-IoT-SDK/c_sdk/standard/common/include/iot_init.h new file mode 100644 index 000000000..fe1ffb40e --- /dev/null +++ b/FreeRTOS-Plus/Source/FreeRTOS-Plus-IoT-SDK/c_sdk/standard/common/include/iot_init.h @@ -0,0 +1,67 @@ +/* + * Amazon FreeRTOS Common V1.0.0 + * Copyright (C) 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to + * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of + * the Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * http://aws.amazon.com/freertos + * http://www.FreeRTOS.org + */ + +/** + * @file iot_init.h + * @brief Provides function signatures for common intialization and cleanup of + * this SDK. + */ + +#ifndef IOT_INIT_H_ +#define IOT_INIT_H_ + +/* The config header is always included first. */ +#include "iot_config.h" + +/* Standard includes. */ +#include + +/** + * @brief One-time initialization function for this SDK. + * + * This function initializes common libraries, such as static memory and task + * pool. It must be called once (and only once) before calling any other + * function in this SDK. Calling this function more than once without first + * calling `IotSdk_Cleanup` may result in a crash. + * + * @return `true` if initialization succeeded; `false` otherwise. Logs may be + * printed in case of failure. + * + * @warning No thread-safety guarantees are provided for this function. + */ +bool IotSdk_Init( void ); + +/** + * @brief One-time deinitialization function for all common libraries. + * + * This function frees resources taken in `IotSdk_Init`. No other function + * in this SDK may be called after calling this function unless `IotSdk_Init` + * is called again. + * + * @warning No thread-safety guarantees are provided for this function. + */ +void IotSdk_Cleanup( void ); + +#endif /* IOT_INIT_H_ */ diff --git a/FreeRTOS-Plus/Source/FreeRTOS-Plus-IoT-SDK/c_sdk/standard/common/include/iot_linear_containers.h b/FreeRTOS-Plus/Source/FreeRTOS-Plus-IoT-SDK/c_sdk/standard/common/include/iot_linear_containers.h new file mode 100644 index 000000000..dc5ac252c --- /dev/null +++ b/FreeRTOS-Plus/Source/FreeRTOS-Plus-IoT-SDK/c_sdk/standard/common/include/iot_linear_containers.h @@ -0,0 +1,956 @@ +/* + * Amazon FreeRTOS Common V1.0.0 + * Copyright (C) 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to + * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of + * the Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * http://aws.amazon.com/freertos + * http://www.FreeRTOS.org + */ + +/** + * @file iot_linear_containers.h + * @brief Declares and implements doubly-linked lists and queues. + */ + +#ifndef IOT_LINEAR_CONTAINERS_H_ +#define IOT_LINEAR_CONTAINERS_H_ + +/* The config header is always included first. */ +#include "iot_config.h" + +/* Standard includes. */ +#include +#include +#include + +/** + * @defgroup linear_containers_datatypes_listqueue List and queue + * @brief Structures that represent a list or queue. + */ + +/** + * @ingroup linear_containers_datatypes_listqueue + * @brief Link member placed in structs of a list or queue. + * + * All elements in a list or queue must contain one of these members. The macro + * #IotLink_Container can be used to calculate the starting address of the + * link's container. + */ +typedef struct IotLink +{ + struct IotLink * pPrevious; /**< @brief Pointer to the previous element. */ + struct IotLink * pNext; /**< @brief Pointer to the next element. */ +} IotLink_t; + +/** + * @ingroup linear_containers_datatypes_listqueue + * @brief Represents a doubly-linked list. + */ +typedef IotLink_t IotListDouble_t; + +/** + * @ingroup linear_containers_datatypes_listqueue + * @brief Represents a queue. + */ +typedef IotLink_t IotDeQueue_t; + +/** + * @constantspage{linear_containers,linear containers library} + * + * @section linear_containers_constants_initializers Linear Containers Initializers + * @brief Provides default values for initializing the linear containers data types. + * + * @snippet this define_linear_containers_initializers + * + * All user-facing data types of the linear containers library should be initialized + * using one of the following. + * + * @warning Failure to initialize a linear containers data type with the appropriate + * initializer may result in a runtime error! + * @note The initializers may change at any time in future versions, but their + * names will remain the same. + */ +/* @[define_linear_containers_initializers] */ +#define IOT_LINK_INITIALIZER { 0 } /**< @brief Initializer for an #IotLink_t. */ +#define IOT_LIST_DOUBLE_INITIALIZER IOT_LINK_INITIALIZER /**< @brief Initializer for an #IotListDouble_t. */ +#define IOT_DEQUEUE_INITIALIZER IOT_LINK_INITIALIZER /**< @brief Initializer for an #IotDeQueue_t. */ +/* @[define_linear_containers_initializers] */ + +/** + * @def IotContainers_Assert( expression ) + * @brief Assertion macro for the linear containers library. + * + * Set @ref IOT_CONTAINERS_ENABLE_ASSERTS to `1` to enable assertions in the linear + * containers library. + * + * @param[in] expression Expression to be evaluated. + */ +#if IOT_CONTAINERS_ENABLE_ASSERTS == 1 + #ifndef IotContainers_Assert + #include + #define IotContainers_Assert( expression ) assert( expression ) + #endif +#else + #define IotContainers_Assert( expression ) +#endif + +/** + * @brief Calculates the starting address of a containing struct. + * + * @param[in] type Type of the containing struct. + * @param[in] pLink Pointer to a link member. + * @param[in] linkName Name of the #IotLink_t in the containing struct. + */ +#define IotLink_Container( type, pLink, linkName ) \ + ( ( type * ) ( void * ) ( ( ( uint8_t * ) ( pLink ) ) - offsetof( type, linkName ) ) ) + +/** + * @brief Iterates through all elements of a linear container. + * + * Container elements must not be freed or removed while iterating. + * + * @param[in] pStart The first element to iterate from. + * @param[out] pLink Pointer to a container element. + */ +#define IotContainers_ForEach( pStart, pLink ) \ + for( ( pLink ) = ( pStart )->pNext; \ + ( pLink ) != ( pStart ); \ + ( pLink ) = ( pLink )->pNext ) + +/** + * @functionspage{linear_containers,linear containers library} + * - @functionname{linear_containers_function_link_islinked} + * - @functionname{linear_containers_function_list_double_create} + * - @functionname{linear_containers_function_list_double_count} + * - @functionname{linear_containers_function_list_double_isempty} + * - @functionname{linear_containers_function_list_double_peekhead} + * - @functionname{linear_containers_function_list_double_peektail} + * - @functionname{linear_containers_function_list_double_inserthead} + * - @functionname{linear_containers_function_list_double_inserttail} + * - @functionname{linear_containers_function_list_double_insertbefore} + * - @functionname{linear_containers_function_list_double_insertafter} + * - @functionname{linear_containers_function_list_double_insertsorted} + * - @functionname{linear_containers_function_list_double_remove} + * - @functionname{linear_containers_function_list_double_removehead} + * - @functionname{linear_containers_function_list_double_removetail} + * - @functionname{linear_containers_function_list_double_removeall} + * - @functionname{linear_containers_function_list_double_findfirstmatch} + * - @functionname{linear_containers_function_list_double_removefirstmatch} + * - @functionname{linear_containers_function_list_double_removeallmatches} + * - @functionname{linear_containers_function_queue_create} + * - @functionname{linear_containers_function_queue_count} + * - @functionname{linear_containers_function_queue_isempty} + * - @functionname{linear_containers_function_queue_peekhead} + * - @functionname{linear_containers_function_queue_peektail} + * - @functionname{linear_containers_function_queue_enqueuehead} + * - @functionname{linear_containers_function_queue_dequeuehead} + * - @functionname{linear_containers_function_queue_enqueuetail} + * - @functionname{linear_containers_function_queue_dequeuetail} + * - @functionname{linear_containers_function_queue_remove} + * - @functionname{linear_containers_function_queue_removeall} + * - @functionname{linear_containers_function_queue_removeallmatches} + */ + +/** + * @functionpage{IotLink_IsLinked,linear_containers,link_islinked} + * @functionpage{IotListDouble_Create,linear_containers,list_double_create} + * @functionpage{IotListDouble_Count,linear_containers,list_double_count} + * @functionpage{IotListDouble_IsEmpty,linear_containers,list_double_isempty} + * @functionpage{IotListDouble_PeekHead,linear_containers,list_double_peekhead} + * @functionpage{IotListDouble_PeekTail,linear_containers,list_double_peektail} + * @functionpage{IotListDouble_InsertHead,linear_containers,list_double_inserthead} + * @functionpage{IotListDouble_InsertTail,linear_containers,list_double_inserttail} + * @functionpage{IotListDouble_InsertBefore,linear_containers,list_double_insertbefore} + * @functionpage{IotListDouble_InsertAfter,linear_containers,list_double_insertafter} + * @functionpage{IotListDouble_InsertSorted,linear_containers,list_double_insertsorted} + * @functionpage{IotListDouble_Remove,linear_containers,list_double_remove} + * @functionpage{IotListDouble_RemoveHead,linear_containers,list_double_removehead} + * @functionpage{IotListDouble_RemoveTail,linear_containers,list_double_removetail} + * @functionpage{IotListDouble_RemoveAll,linear_containers,list_double_removeall} + * @functionpage{IotListDouble_FindFirstMatch,linear_containers,list_double_findfirstmatch} + * @functionpage{IotListDouble_RemoveFirstMatch,linear_containers,list_double_removefirstmatch} + * @functionpage{IotListDouble_RemoveAllMatches,linear_containers,list_double_removeallmatches} + * @functionpage{IotDeQueue_Create,linear_containers,queue_create} + * @functionpage{IotDeQueue_Count,linear_containers,queue_count} + * @functionpage{IotDeQueue_IsEmpty,linear_containers,queue_isempty} + * @functionpage{IotDeQueue_PeekHead,linear_containers,queue_peekhead} + * @functionpage{IotDeQueue_PeekTail,linear_containers,queue_peektail} + * @functionpage{IotDeQueue_EnqueueHead,linear_containers,queue_enqueuehead} + * @functionpage{IotDeQueue_DequeueHead,linear_containers,queue_dequeuehead} + * @functionpage{IotDeQueue_EnqueueTail,linear_containers,queue_enqueuetail} + * @functionpage{IotDeQueue_DequeueTail,linear_containers,queue_dequeuetail} + * @functionpage{IotDeQueue_Remove,linear_containers,queue_remove} + * @functionpage{IotDeQueue_RemoveAll,linear_containers,queue_removeall} + * @functionpage{IotDeQueue_RemoveAllMatches,linear_containers,queue_removeallmatches} + */ + +/** + * @brief Check if an #IotLink_t is linked in a list or queue. + * + * @param[in] pLink The link to check. + * + * @return `true` if `pCurrent` is linked in a list or queue; `false` otherwise. + */ +/* @[declare_linear_containers_link_islinked] */ +static inline bool IotLink_IsLinked( const IotLink_t * const pLink ) +/* @[declare_linear_containers_link_islinked] */ +{ + bool isLinked = false; + + if( pLink != NULL ) + { + isLinked = ( pLink->pNext != NULL ) && ( pLink->pPrevious != NULL ); + } + + return isLinked; +} + +/** + * @brief Create a new doubly-linked list. + * + * This function initializes a new doubly-linked list. It must be called on an + * uninitialized #IotListDouble_t before calling any other doubly-linked list + * function. This function must not be called on an already-initialized + * #IotListDouble_t. + * + * This function will not fail. The function @ref linear_containers_function_list_double_removeall + * may be called to destroy a list. + * + * @param[in] pList Pointer to the memory that will hold the new doubly-linked list. + */ +/* @[declare_linear_containers_list_double_create] */ +static inline void IotListDouble_Create( IotListDouble_t * const pList ) +/* @[declare_linear_containers_list_double_create] */ +{ + /* This function must not be called with a NULL parameter. */ + IotContainers_Assert( pList != NULL ); + + /* An empty list is a link pointing to itself. */ + pList->pPrevious = pList; + pList->pNext = pList; +} + +/** + * @brief Return the number of elements contained in an #IotListDouble_t. + * + * @param[in] pList The doubly-linked list with the elements to count. + * + * @return The number of elements in the doubly-linked list. + */ +/* @[declare_linear_containers_list_double_count] */ +static inline size_t IotListDouble_Count( const IotListDouble_t * const pList ) +/* @[declare_linear_containers_list_double_count] */ +{ + size_t count = 0; + + if( pList != NULL ) + { + /* Get the list head. */ + const IotLink_t * pCurrent = pList->pNext; + + /* Iterate through the list to count the elements. */ + while( pCurrent != pList ) + { + count++; + pCurrent = pCurrent->pNext; + } + } + + return count; +} + +/** + * @brief Check if a doubly-linked list is empty. + * + * @param[in] pList The doubly-linked list to check. + * + * @return `true` if the list is empty; `false` otherwise. + */ +/* @[declare_linear_containers_list_double_isempty] */ +static inline bool IotListDouble_IsEmpty( const IotListDouble_t * const pList ) +/* @[declare_linear_containers_list_double_isempty] */ +{ + /* An empty list is NULL link, or a link pointing to itself. */ + return( ( pList == NULL ) || ( pList->pNext == pList ) ); +} + +/** + * @brief Return an #IotLink_t representing the first element in a doubly-linked list + * without removing it. + * + * @param[in] pList The list to peek. + * + * @return Pointer to an #IotLink_t representing the element at the head of the + * list; `NULL` if the list is empty. The macro #IotLink_Container may be used to + * determine the address of the link's container. + */ +/* @[declare_linear_containers_list_double_peekhead] */ +static inline IotLink_t * IotListDouble_PeekHead( const IotListDouble_t * const pList ) +/* @[declare_linear_containers_list_double_peekhead] */ +{ + IotLink_t * pHead = NULL; + + if( pList != NULL ) + { + if( IotListDouble_IsEmpty( pList ) == false ) + { + pHead = pList->pNext; + } + } + + return pHead; +} + +/** + * @brief Return an #IotLink_t representing the last element in a doubly-linked + * list without removing it. + * + * @param[in] pList The list to peek. + * + * @return Pointer to an #IotLink_t representing the element at the tail of the + * list; `NULL` if the list is empty. The macro #IotLink_Container may be used to + * determine the address of the link's container. + */ +/* @[declare_linear_containers_list_double_peektail] */ +static inline IotLink_t * IotListDouble_PeekTail( const IotListDouble_t * const pList ) +/* @[declare_linear_containers_list_double_peektail] */ +{ + IotLink_t * pTail = NULL; + + if( pList != NULL ) + { + if( IotListDouble_IsEmpty( pList ) == false ) + { + pTail = pList->pPrevious; + } + } + + return pTail; +} + +/** + * @brief Insert an element at the head of a doubly-linked list. + * + * @param[in] pList The doubly-linked list that will hold the new element. + * @param[in] pLink Pointer to the new element's link member. + */ +/* @[declare_linear_containers_list_double_inserthead] */ +static inline void IotListDouble_InsertHead( IotListDouble_t * const pList, + IotLink_t * const pLink ) +/* @[declare_linear_containers_list_double_inserthead] */ +{ + /* This function must not be called with NULL parameters. */ + IotContainers_Assert( pList != NULL ); + IotContainers_Assert( pLink != NULL ); + + /* Save current list head. */ + IotLink_t * pHead = pList->pNext; + + /* Place new element before list head. */ + pLink->pNext = pHead; + pLink->pPrevious = pList; + + /* Assign new list head. */ + pHead->pPrevious = pLink; + pList->pNext = pLink; +} + +/** + * @brief Insert an element at the tail of a doubly-linked list. + * + * @param[in] pList The double-linked list that will hold the new element. + * @param[in] pLink Pointer to the new element's link member. + */ +/* @[declare_linear_containers_list_double_inserttail] */ +static inline void IotListDouble_InsertTail( IotListDouble_t * const pList, + IotLink_t * const pLink ) +/* @[declare_linear_containers_list_double_inserttail] */ +{ + /* This function must not be called with NULL parameters. */ + IotContainers_Assert( pList != NULL ); + IotContainers_Assert( pLink != NULL ); + + /* Save current list tail. */ + IotLink_t * pTail = pList->pPrevious; + + pLink->pNext = pList; + pLink->pPrevious = pTail; + + pList->pPrevious = pLink; + pTail->pNext = pLink; +} + +/** + * @brief Insert an element before another element in a doubly-linked list. + * + * @param[in] pElement The new element will be placed before this element. + * @param[in] pLink Pointer to the new element's link member. + */ +/* @[declare_linear_containers_list_double_insertbefore] */ +static inline void IotListDouble_InsertBefore( IotLink_t * const pElement, + IotLink_t * const pLink ) +/* @[declare_linear_containers_list_double_insertbefore] */ +{ + IotListDouble_InsertTail( pElement, pLink ); +} + +/** + * @brief Insert an element after another element in a doubly-linked list. + * + * @param[in] pElement The new element will be placed after this element. + * @param[in] pLink Pointer to the new element's link member. + */ +/* @[declare_linear_containers_list_double_insertafter] */ +static inline void IotListDouble_InsertAfter( IotLink_t * const pElement, + IotLink_t * const pLink ) +/* @[declare_linear_containers_list_double_insertafter] */ +{ + IotListDouble_InsertHead( pElement, pLink ); +} + +/** + * @brief Insert an element in a sorted doubly-linked list. + * + * Places an element into a list by sorting it into order. The function + * `compare` is used to determine where to place the new element. + * + * @param[in] pList The list that will hold the new element. + * @param[in] pLink Pointer to the new element's link member. + * @param[in] compare Determines the order of the list. Returns a negative + * value if its first argument is less than its second argument; returns + * zero if its first argument is equal to its second argument; returns a + * positive value if its first argument is greater than its second argument. + * The parameters to this function are #IotLink_t, so the macro #IotLink_Container + * may be used to determine the address of the link's container. + */ +/* @[declare_linear_containers_list_double_insertsorted] */ +static inline void IotListDouble_InsertSorted( IotListDouble_t * const pList, + IotLink_t * const pLink, + int32_t ( *compare )( const IotLink_t * const, const IotLink_t * const ) ) +/* @[declare_linear_containers_list_double_insertsorted] */ +{ + /* This function must not be called with NULL parameters. */ + IotContainers_Assert( pList != NULL ); + IotContainers_Assert( pLink != NULL ); + IotContainers_Assert( compare != NULL ); + + /* Insert at head for empty list. */ + if( IotListDouble_IsEmpty( pList ) == true ) + { + IotListDouble_InsertHead( pList, pLink ); + } + else + { + bool inserted = false; + IotLink_t * pCurrent = pList->pNext; + + /* Iterate through the list to find the correct position. */ + while( pCurrent != pList ) + { + /* Comparing for '<' preserves the order of insertion. */ + if( compare( pLink, pCurrent ) < 0 ) + { + IotListDouble_InsertBefore( pCurrent, pLink ); + inserted = true; + + break; + } + + pCurrent = pCurrent->pNext; + } + + /* New element is greater than all elements in list. Insert at tail. */ + if( inserted == false ) + { + IotListDouble_InsertTail( pList, pLink ); + } + } +} + +/** + * @brief Remove a single element from a doubly-linked list. + * + * @param[in] pLink The element to remove. + */ +/* @[declare_linear_containers_list_double_remove] */ +static inline void IotListDouble_Remove( IotLink_t * const pLink ) +/* @[declare_linear_containers_list_double_remove] */ +{ + /* This function must not be called with a NULL parameter. */ + IotContainers_Assert( pLink != NULL ); + + /* This function must be called on a linked element. */ + IotContainers_Assert( IotLink_IsLinked( pLink ) == true ); + + pLink->pPrevious->pNext = pLink->pNext; + pLink->pNext->pPrevious = pLink->pPrevious; + pLink->pPrevious = NULL; + pLink->pNext = NULL; +} + +/** + * @brief Remove the element at the head of a doubly-linked list. + * + * @param[in] pList The doubly-linked list that holds the element to remove. + * + * @return Pointer to an #IotLink_t representing the removed list head; `NULL` + * if the list is empty. The macro #IotLink_Container may be used to determine + * the address of the link's container. + */ +/* @[declare_linear_containers_list_double_removehead] */ +static inline IotLink_t * IotListDouble_RemoveHead( IotListDouble_t * const pList ) +/* @[declare_linear_containers_list_double_removehead] */ +{ + IotLink_t * pHead = NULL; + + if( IotListDouble_IsEmpty( pList ) == false ) + { + pHead = pList->pNext; + IotListDouble_Remove( pHead ); + } + + return pHead; +} + +/** + * @brief Remove the element at the tail of a doubly-linked list. + * + * @param[in] pList The doubly-linked list that holds the element to remove. + * + * @return Pointer to an #IotLink_t representing the removed list tail; `NULL` + * if the list is empty. The macro #IotLink_Container may be used to determine + * the address of the link's container. + */ +/* @[declare_linear_containers_list_double_removetail] */ +static inline IotLink_t * IotListDouble_RemoveTail( IotListDouble_t * const pList ) +/* @[declare_linear_containers_list_double_removetail] */ +{ + IotLink_t * pTail = NULL; + + if( IotListDouble_IsEmpty( pList ) == false ) + { + pTail = pList->pPrevious; + IotListDouble_Remove( pTail ); + } + + return pTail; +} + +/** + * @brief Remove all elements in a doubly-linked list. + * + * @param[in] pList The list to empty. + * @param[in] freeElement A function to free memory used by each removed list + * element. Optional; pass `NULL` to ignore. + * @param[in] linkOffset Offset in bytes of a link member in its container, used + * to calculate the pointer to pass to `freeElement`. This value should be calculated + * with the C `offsetof` macro. This parameter is ignored if `freeElement` is `NULL` + * or its value is `0`. + */ +/* @[declare_linear_containers_list_double_removeall] */ +static inline void IotListDouble_RemoveAll( IotListDouble_t * const pList, + void ( *freeElement )( void * ), + size_t linkOffset ) +/* @[declare_linear_containers_list_double_removeall] */ +{ + /* This function must not be called with a NULL pList parameter. */ + IotContainers_Assert( pList != NULL ); + + /* Get the list head. */ + IotLink_t * pCurrent = pList->pNext; + + /* Iterate through the list and remove all elements. */ + while( pCurrent != pList ) + { + /* Save a pointer to the next list element. */ + IotLink_t * pNext = pCurrent->pNext; + + /* Remove and free the current list element. */ + IotListDouble_Remove( pCurrent ); + + if( freeElement != NULL ) + { + freeElement( ( ( uint8_t * ) pCurrent ) - linkOffset ); + } + + /* Move the iterating pointer to the next list element. */ + pCurrent = pNext; + } +} + +/** + * @brief Search a doubly-linked list for the first matching element. + * + * If a match is found, the matching element is not removed from the list. + * See @ref linear_containers_function_list_double_removefirstmatch for the function + * that searches and removes. + * + * @param[in] pList The doubly-linked list to search. + * @param[in] pStartPoint An element in `pList`. Only elements between this one and + * the list tail are checked. Pass `NULL` to search from the beginning of the list. + * @param[in] isMatch Function to determine if an element matches. Pass `NULL` to + * search using the address `pMatch`, i.e. `element == pMatch`. + * @param[in] pMatch If `isMatch` is `NULL`, each element in the list is compared + * to this address to find a match. Otherwise, it is passed as the second argument + * to `isMatch`. + * + * @return Pointer to an #IotLink_t representing the first matched element; `NULL` + * if no match is found. The macro #IotLink_Container may be used to determine the + * address of the link's container. + */ +/* @[declare_linear_containers_list_double_findfirstmatch] */ +static inline IotLink_t * IotListDouble_FindFirstMatch( const IotListDouble_t * const pList, + const IotLink_t * const pStartPoint, + bool ( *isMatch )( const IotLink_t * const, void * ), + void * pMatch ) +/* @[declare_linear_containers_list_double_findfirstmatch] */ +{ + /* The const must be cast away to match this function's return value. Nevertheless, + * this function will respect the const-ness of pStartPoint. */ + IotLink_t * pCurrent = ( IotLink_t * ) pStartPoint; + + /* This function must not be called with a NULL pList parameter. */ + IotContainers_Assert( pList != NULL ); + + /* Search starting from list head if no start point is given. */ + if( pStartPoint == NULL ) + { + pCurrent = pList->pNext; + } + + /* Iterate through the list to search for matches. */ + while( pCurrent != pList ) + { + /* Call isMatch if provided. Otherwise, compare pointers. */ + if( isMatch != NULL ) + { + if( isMatch( pCurrent, pMatch ) == true ) + { + return pCurrent; + } + } + else + { + if( pCurrent == pMatch ) + { + return pCurrent; + } + } + + pCurrent = pCurrent->pNext; + } + + /* No match found, return NULL. */ + return NULL; +} + +/** + * @brief Search a doubly-linked list for the first matching element and remove + * it. + * + * An #IotLink_t may be passed as `pList` to start searching after the head of a + * doubly-linked list. + * + * @param[in] pList The doubly-linked list to search. + * @param[in] pStartPoint An element in `pList`. Only elements between this one and + * the list tail are checked. Pass `NULL` to search from the beginning of the list. + * @param[in] isMatch Function to determine if an element matches. Pass `NULL` to + * search using the address `pMatch`, i.e. `element == pMatch`. + * @param[in] pMatch If `isMatch` is `NULL`, each element in the list is compared + * to this address to find a match. Otherwise, it is passed as the second argument + * to `isMatch`. + * + * @return Pointer to an #IotLink_t representing the matched and removed element; + * `NULL` if no match is found. The macro #IotLink_Container may be used to determine + * the address of the link's container. + */ +/* @[declare_linear_containers_list_double_removefirstmatch] */ +static inline IotLink_t * IotListDouble_RemoveFirstMatch( IotListDouble_t * const pList, + const IotLink_t * const pStartPoint, + bool ( *isMatch )( const IotLink_t *, void * ), + void * pMatch ) +/* @[declare_linear_containers_list_double_removefirstmatch] */ +{ + IotLink_t * pMatchedElement = IotListDouble_FindFirstMatch( pList, + pStartPoint, + isMatch, + pMatch ); + + if( pMatchedElement != NULL ) + { + IotListDouble_Remove( pMatchedElement ); + } + + return pMatchedElement; +} + +/** + * @brief Remove all matching elements from a doubly-linked list. + * + * @param[in] pList The doubly-linked list to search. + * @param[in] isMatch Function to determine if an element matches. Pass `NULL` to + * search using the address `pMatch`, i.e. `element == pMatch`. + * @param[in] pMatch If `isMatch` is `NULL`, each element in the list is compared + * to this address to find a match. Otherwise, it is passed as the second argument + * to `isMatch`. + * @param[in] freeElement A function to free memory used by each removed list + * element. Optional; pass `NULL` to ignore. + * @param[in] linkOffset Offset in bytes of a link member in its container, used + * to calculate the pointer to pass to `freeElement`. This value should be calculated + * with the C `offsetof` macro. This parameter is ignored if `freeElement` is `NULL` + * or its value is `0`. + */ +/* @[declare_linear_containers_list_double_removeallmatches] */ +static inline void IotListDouble_RemoveAllMatches( IotListDouble_t * const pList, + bool ( *isMatch )( const IotLink_t *, void * ), + void * pMatch, + void ( *freeElement )( void * ), + size_t linkOffset ) +/* @[declare_linear_containers_list_double_removeallmatches] */ +{ + IotLink_t * pMatchedElement = NULL, * pNextElement = NULL; + + /* Search the list for all matching elements. */ + do + { + pMatchedElement = IotListDouble_FindFirstMatch( pList, + pMatchedElement, + isMatch, + pMatch ); + + if( pMatchedElement != NULL ) + { + /* Save pointer to next element. */ + pNextElement = pMatchedElement->pNext; + + /* Match found; remove and free. */ + IotListDouble_Remove( pMatchedElement ); + + if( freeElement != NULL ) + { + freeElement( ( ( uint8_t * ) pMatchedElement ) - linkOffset ); + } + + /* Continue search from next element. */ + pMatchedElement = pNextElement; + } + } while( pMatchedElement != NULL ); +} + +/** + * @brief Create a new queue. + * + * This function initializes a new double-ended queue. It must be called on an uninitialized + * #IotDeQueue_t before calling any other queue function. This function must not be + * called on an already-initialized #IotDeQueue_t. + * + * This function will not fail. + * + * @param[in] pQueue Pointer to the memory that will hold the new queue. + */ +/* @[declare_linear_containers_queue_create] */ +static inline void IotDeQueue_Create( IotDeQueue_t * const pQueue ) +/* @[declare_linear_containers_queue_create] */ +{ + IotListDouble_Create( pQueue ); +} + +/** + * @brief Return the number of elements contained in an #IotDeQueue_t. + * + * @param[in] pQueue The queue with the elements to count. + * + * @return The number of items elements in the queue. + */ +/* @[declare_linear_containers_queue_count] */ +static inline size_t IotDeQueue_Count( const IotDeQueue_t * const pQueue ) +/* @[declare_linear_containers_queue_count] */ +{ + return IotListDouble_Count( pQueue ); +} + +/** + * @brief Check if a queue is empty. + * + * @param[in] pQueue The queue to check. + * + * @return `true` if the queue is empty; `false` otherwise. + * + */ +/* @[declare_linear_containers_queue_isempty] */ +static inline bool IotDeQueue_IsEmpty( const IotDeQueue_t * const pQueue ) +/* @[declare_linear_containers_queue_isempty] */ +{ + return IotListDouble_IsEmpty( pQueue ); +} + +/** + * @brief Return an #IotLink_t representing the element at the front of the queue + * without removing it. + * + * @param[in] pQueue The queue to peek. + * + * @return Pointer to an #IotLink_t representing the element at the head of the + * queue; `NULL` if the queue is empty. The macro #IotLink_Container may be used + * to determine the address of the link's container. + */ +/* @[declare_linear_containers_queue_peekhead] */ +static inline IotLink_t * IotDeQueue_PeekHead( const IotDeQueue_t * const pQueue ) +/* @[declare_linear_containers_queue_peekhead] */ +{ + return IotListDouble_PeekHead( pQueue ); +} + +/** + * @brief Return an #IotLink_t representing the element at the back of the queue + * without removing it. + * + * @param[in] pQueue The queue to peek. + * + * @return Pointer to an #IotLink_t representing the element at the head of the + * queue; `NULL` if the queue is empty. The macro #IotLink_Container may be used + * to determine the address of the link's container. + */ +/* @[declare_linear_containers_queue_peektail] */ +static inline IotLink_t * IotDeQueue_PeekTail( const IotDeQueue_t * const pQueue ) +/* @[declare_linear_containers_queue_peektail] */ +{ + return IotListDouble_PeekTail( pQueue ); +} + +/** + * @brief Add an element at the head of the queue. + * + * @param[in] pQueue The queue that will hold the new element. + * @param[in] pLink Pointer to the new element's link member. + */ +/* @[declare_linear_containers_queue_enqueuehead] */ +static inline void IotDeQueue_EnqueueHead( IotDeQueue_t * const pQueue, + IotLink_t * const pLink ) +/* @[declare_linear_containers_queue_enqueuehead] */ +{ + IotListDouble_InsertHead( pQueue, pLink ); +} + +/** + * @brief Remove an element at the head of the queue. + * + * @param[in] pQueue The queue that holds the element to remove. + * + * @return Pointer to an #IotLink_t representing the removed queue element; `NULL` + * if the queue is empty. The macro #IotLink_Container may be used to determine + * the address of the link's container. + */ +/* @[declare_linear_containers_queue_dequeuehead] */ +static inline IotLink_t * IotDeQueue_DequeueHead( IotDeQueue_t * const pQueue ) +/* @[declare_linear_containers_queue_dequeuehead] */ +{ + return IotListDouble_RemoveHead( pQueue ); +} + +/** + * @brief Add an element at the tail of the queue. + * + * @param[in] pQueue The queue that will hold the new element. + * @param[in] pLink Pointer to the new element's link member. + */ +/* @[declare_linear_containers_queue_enqueuetail] */ +static inline void IotDeQueue_EnqueueTail( IotDeQueue_t * const pQueue, + IotLink_t * const pLink ) +/* @[declare_linear_containers_queue_enqueuetail] */ +{ + IotListDouble_InsertTail( pQueue, pLink ); +} + +/** + * @brief Remove an element at the tail of the queue. + * + * @param[in] pQueue The queue that holds the element to remove. + * + * @return Pointer to an #IotLink_t representing the removed queue element; `NULL` + * if the queue is empty. The macro #IotLink_Container may be used to determine + * the address of the link's container. + */ +/* @[declare_linear_containers_queue_dequeuetail] */ +static inline IotLink_t * IotDeQueue_DequeueTail( IotDeQueue_t * const pQueue ) +/* @[declare_linear_containers_queue_dequeuetail] */ +{ + return IotListDouble_RemoveTail( pQueue ); +} + +/** + * @brief Remove a single element from a queue. + * + * @param[in] pLink The element to remove. + */ +/* @[declare_linear_containers_queue_remove] */ +static inline void IotDeQueue_Remove( IotLink_t * const pLink ) +/* @[declare_linear_containers_queue_remove] */ +{ + IotListDouble_Remove( pLink ); +} + +/** + * @brief Remove all elements in a queue. + * + * @param[in] pQueue The queue to empty. + * @param[in] freeElement A function to free memory used by each removed queue + * element. Optional; pass `NULL` to ignore. + * @param[in] linkOffset Offset in bytes of a link member in its container, used + * to calculate the pointer to pass to `freeElement`. This value should be calculated + * with the C `offsetof` macro. This parameter is ignored if `freeElement` is `NULL` + * or its value is `0`. + */ +/* @[declare_linear_containers_queue_removeall] */ +static inline void IotDeQueue_RemoveAll( IotDeQueue_t * const pQueue, + void ( * freeElement )( void * ), + size_t linkOffset ) +/* @[declare_linear_containers_queue_removeall] */ +{ + IotListDouble_RemoveAll( pQueue, freeElement, linkOffset ); +} + +/** + * @brief Remove all matching elements from a queue. + * + * @param[in] pQueue The queue to search. + * @param[in] isMatch Function to determine if an element matches. Pass `NULL` to + * search using the address `pMatch`, i.e. `element == pMatch`. + * @param[in] pMatch If `isMatch` is `NULL`, each element in the queue is compared + * to this address to find a match. Otherwise, it is passed as the second argument + * to `isMatch`. + * @param[in] freeElement A function to free memory used by each removed queue + * element. Optional; pass `NULL` to ignore. + * @param[in] linkOffset Offset in bytes of a link member in its container, used + * to calculate the pointer to pass to `freeElement`. This value should be calculated + * with the C `offsetof` macro. This parameter is ignored if `freeElement` is `NULL` + * or its value is `0`. + */ +/* @[declare_linear_containers_queue_removeallmatches] */ +static inline void IotDeQueue_RemoveAllMatches( IotDeQueue_t * const pQueue, + bool ( * isMatch )( const IotLink_t *, void * ), + void * pMatch, + void ( * freeElement )( void * ), + size_t linkOffset ) +/* @[declare_linear_containers_queue_removeallmatches] */ +{ + IotListDouble_RemoveAllMatches( pQueue, isMatch, pMatch, freeElement, linkOffset ); +} + +#endif /* IOT_LINEAR_CONTAINERS_H_ */ diff --git a/FreeRTOS-Plus/Source/FreeRTOS-Plus-IoT-SDK/c_sdk/standard/common/include/iot_logging_setup.h b/FreeRTOS-Plus/Source/FreeRTOS-Plus-IoT-SDK/c_sdk/standard/common/include/iot_logging_setup.h new file mode 100644 index 000000000..ec3d6d164 --- /dev/null +++ b/FreeRTOS-Plus/Source/FreeRTOS-Plus-IoT-SDK/c_sdk/standard/common/include/iot_logging_setup.h @@ -0,0 +1,223 @@ +/* + * Amazon FreeRTOS Common V1.0.0 + * Copyright (C) 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to + * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of + * the Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * http://aws.amazon.com/freertos + * http://www.FreeRTOS.org + */ + +/** + * @file iot_logging_setup.h + * @brief Defines the logging macro #IotLog. + */ + +#ifndef IOT_LOGGING_SETUP_H_ +#define IOT_LOGGING_SETUP_H_ + +/* The config header is always included first. */ +#include "iot_config.h" + +/* Logging include. Because it's included here, iot_logging.h never needs + * to be included in source. */ +#include "private/iot_logging.h" + +/** + * @functionpage{IotLog,logging,log} + * @functionpage{IotLog_PrintBuffer,logging,printbuffer} + */ + +/** + * @def IotLog( messageLevel, pLogConfig, ... ) + * @brief Logging function for a specific library. In most cases, this is the + * logging function to call. + * + * This function prints a single log message. It is available when @ref + * LIBRARY_LOG_LEVEL is not #IOT_LOG_NONE. Log messages automatically + * include the [log level](@ref logging_constants_levels), [library name] + * (@ref LIBRARY_LOG_NAME), and time. An optional @ref IotLogConfig_t may + * be passed to this function to hide information for a single log message. + * + * The logging library must be set up before this function may be called. See + * @ref logging_setup_use for more information. + * + * This logging function also has the following abbreviated forms that can be used + * when an #IotLogConfig_t isn't needed. + * + * Name | Equivalent to + * ---- | ------------- + * #IotLogError | @code{c} IotLog( IOT_LOG_ERROR, NULL, ... ) @endcode + * #IotLogWarn | @code{c} IotLog( IOT_LOG_WARN, NULL, ... ) @endcode + * #IotLogInfo | @code{c} IotLog( IOT_LOG_INFO, NULL, ... ) @endcode + * #IotLogDebug | @code{c} IotLog( IOT_LOG_DEBUG, NULL, ... ) @endcode + * + * @param[in] messageLevel Log level of this message. Must be one of the + * @ref logging_constants_levels. + * @param[in] pLogConfig Pointer to an #IotLogConfig_t. Optional; pass `NULL` + * to ignore. + * @param[in] ... Message and format specification. + * + * @return No return value. On errors, it prints nothing. + * + * @note This function may be implemented as a macro. + * @see @ref logging_function_generic for the generic (not library-specific) + * logging function. + */ + +/** + * @def IotLog_PrintBuffer( pHeader, pBuffer, bufferSize ) + * @brief Log the contents of buffer as bytes. Only available when @ref + * LIBRARY_LOG_LEVEL is #IOT_LOG_DEBUG. + * + * This function prints the bytes located at a given memory address. It is + * intended for debugging only, and is therefore only available when @ref + * LIBRARY_LOG_LEVEL is #IOT_LOG_DEBUG. + * + * Log messages printed by this function always include the [log level] + * (@ref logging_constants_levels), [library name](@ref LIBRARY_LOG_NAME), + * and time. In addition, this function may print an optional header `pHeader` + * before it prints the contents of the buffer. This function does not have an + * #IotLogConfig_t parameter. + * + * The logging library must be set up before this function may be called. See + * @ref logging_setup_use for more information. + * + * @param[in] pHeader A message to log before the buffer. Optional; pass `NULL` + * to ignore. + * @param[in] pBuffer Pointer to start of buffer. + * @param[in] bufferSize Size of `pBuffer`. + * + * @return No return value. On errors, it prints nothing. + * + * @note This function may be implemented as a macro. + * @note To conserve memory, @ref logging_function_genericprintbuffer (the underlying + * implementation) only allocates enough memory for a single line of output. Therefore, + * in multithreaded systems, its output may appear "fragmented" if other threads are + * logging simultaneously. + * @see @ref logging_function_genericprintbuffer for the generic (not library-specific) + * buffer logging function. + * + * Example + * @code{c} + * const uint8_t pBuffer[] = { 0x00, 0x01, 0x02, 0x03 }; + * + * IotLog_PrintBuffer( "This buffer contains:", + * pBuffer, + * 4 ); + * @endcode + * The code above prints something like the following: + * @code{c} + * [DEBUG][LIB_NAME][2018-01-01 12:00:00] This buffer contains: + * 00 01 02 03 + * @endcode + */ + +/** + * @def IotLogError( ... ) + * @brief Abbreviated logging macro for level #IOT_LOG_ERROR. + * + * Equivalent to: + * @code{c} + * IotLog( IOT_LOG_ERROR, NULL, ... ) + * @endcode + */ + +/** + * @def IotLogWarn( ... ) + * @brief Abbreviated logging macro for level #IOT_LOG_WARN. + * + * Equivalent to: + * @code{c} + * IotLog( IOT_LOG_WARN, NULL, ... ) + * @endcode + */ + +/** + * @def IotLogInfo( ... ) + * @brief Abbreviated logging macro for level #IOT_LOG_INFO. + * + * Equivalent to: + * @code{c} + * IotLog( IOT_LOG_INFO, NULL, ... ) + * @endcode + */ + +/** + * @def IotLogDebug( ... ) + * @brief Abbreviated logging macro for level #IOT_LOG_DEBUG. + * + * Equivalent to: + * @code{c} + * IotLog( IOT_LOG_DEBUG, NULL, ... ) + * @endcode + */ + +/* Check that LIBRARY_LOG_LEVEL is defined and has a valid value. */ +#if !defined( LIBRARY_LOG_LEVEL ) || \ + ( LIBRARY_LOG_LEVEL != IOT_LOG_NONE && \ + LIBRARY_LOG_LEVEL != IOT_LOG_ERROR && \ + LIBRARY_LOG_LEVEL != IOT_LOG_WARN && \ + LIBRARY_LOG_LEVEL != IOT_LOG_INFO && \ + LIBRARY_LOG_LEVEL != IOT_LOG_DEBUG ) + #error "Please define LIBRARY_LOG_LEVEL as either IOT_LOG_NONE, IOT_LOG_ERROR, IOT_LOG_WARN, IOT_LOG_INFO, or IOT_LOG_DEBUG." +/* Check that LIBRARY_LOG_NAME is defined and has a valid value. */ +#elif !defined( LIBRARY_LOG_NAME ) + #error "Please define LIBRARY_LOG_NAME." +#else + /* Define IotLog if the log level is greater than "none". */ + #if LIBRARY_LOG_LEVEL > IOT_LOG_NONE + #define IotLog( messageLevel, pLogConfig, ... ) \ + IotLog_Generic( LIBRARY_LOG_LEVEL, \ + LIBRARY_LOG_NAME, \ + messageLevel, \ + pLogConfig, \ + __VA_ARGS__ ) + + /* Define the abbreviated logging macros. */ + #define IotLogError( ... ) IotLog( IOT_LOG_ERROR, NULL, __VA_ARGS__ ) + #define IotLogWarn( ... ) IotLog( IOT_LOG_WARN, NULL, __VA_ARGS__ ) + #define IotLogInfo( ... ) IotLog( IOT_LOG_INFO, NULL, __VA_ARGS__ ) + #define IotLogDebug( ... ) IotLog( IOT_LOG_DEBUG, NULL, __VA_ARGS__ ) + + /* If log level is DEBUG, enable the function to print buffers. */ + #if LIBRARY_LOG_LEVEL >= IOT_LOG_DEBUG + #define IotLog_PrintBuffer( pHeader, pBuffer, bufferSize ) \ + IotLog_GenericPrintBuffer( LIBRARY_LOG_NAME, \ + pHeader, \ + pBuffer, \ + bufferSize ) + #else + #define IotLog_PrintBuffer( pHeader, pBuffer, bufferSize ) + #endif + /* Remove references to IotLog from the source code if logging is disabled. */ + #else + /* @[declare_logging_log] */ + #define IotLog( messageLevel, pLogConfig, ... ) + /* @[declare_logging_log] */ + /* @[declare_logging_printbuffer] */ + #define IotLog_PrintBuffer( pHeader, pBuffer, bufferSize ) + /* @[declare_logging_printbuffer] */ + #define IotLogError( ... ) + #define IotLogWarn( ... ) + #define IotLogInfo( ... ) + #define IotLogDebug( ... ) + #endif +#endif + +#endif /* ifndef IOT_LOGGING_SETUP_H_ */ diff --git a/FreeRTOS-Plus/Source/FreeRTOS-Plus-IoT-SDK/c_sdk/standard/common/include/iot_taskpool.h b/FreeRTOS-Plus/Source/FreeRTOS-Plus-IoT-SDK/c_sdk/standard/common/include/iot_taskpool.h new file mode 100644 index 000000000..081e968dc --- /dev/null +++ b/FreeRTOS-Plus/Source/FreeRTOS-Plus-IoT-SDK/c_sdk/standard/common/include/iot_taskpool.h @@ -0,0 +1,558 @@ +/* + * Amazon FreeRTOS Common V1.0.0 + * Copyright (C) 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to + * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of + * the Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * http://aws.amazon.com/freertos + * http://www.FreeRTOS.org + */ + +/** + * @file iot_taskpool.h + * @brief User-facing functions of the task pool library. + */ + +#ifndef IOT_TASKPOOL_H_ +#define IOT_TASKPOOL_H_ + +/* The config header is always included first. */ +#include "iot_config.h" + +/* Standard includes. */ +#include +#include +#include + +/* Task pool types. */ +#include "types/iot_taskpool_types.h" + +/*------------------------- Task Pool library functions --------------------------*/ + +/** + * @functionspage{taskpool,task pool library} + * - @functionname{taskpool_function_createsystemtaskpool} + * - @functionname{taskpool_function_getsystemtaskpool} + * - @functionname{taskpool_function_create} + * - @functionname{taskpool_function_destroy} + * - @functionname{taskpool_function_setmaxthreads} + * - @functionname{taskpool_function_createjob} + * - @functionname{taskpool_function_createrecyclablejob} + * - @functionname{taskpool_function_destroyrecyclablejob} + * - @functionname{taskpool_function_recyclejob} + * - @functionname{taskpool_function_schedule} + * - @functionname{taskpool_function_scheduledeferred} + * - @functionname{taskpool_function_getstatus} + * - @functionname{taskpool_function_trycancel} + * - @functionname{taskpool_function_getjobstoragefromhandle} + * - @functionname{taskpool_function_strerror} + */ + +/** + * @functionpage{IotTaskPool_CreateSystemTaskPool,taskpool,createsystemtaskpool} + * @functionpage{IotTaskPool_GetSystemTaskPool,taskpool,getsystemtaskpool} + * @functionpage{IotTaskPool_Create,taskpool,create} + * @functionpage{IotTaskPool_Destroy,taskpool,destroy} + * @functionpage{IotTaskPool_SetMaxThreads,taskpool,setmaxthreads} + * @functionpage{IotTaskPool_CreateJob,taskpool,createjob} + * @functionpage{IotTaskPool_CreateRecyclableJob,taskpool,createrecyclablejob} + * @functionpage{IotTaskPool_DestroyRecyclableJob,taskpool,destroyrecyclablejob} + * @functionpage{IotTaskPool_RecycleJob,taskpool,recyclejob} + * @functionpage{IotTaskPool_Schedule,taskpool,schedule} + * @functionpage{IotTaskPool_ScheduleDeferred,taskpool,scheduledeferred} + * @functionpage{IotTaskPool_GetStatus,taskpool,getstatus} + * @functionpage{IotTaskPool_TryCancel,taskpool,trycancel} + * @functionpage{IotTaskPool_GetJobStorageFromHandle,taskpool,getjobstoragefromhandle} + * @functionpage{IotTaskPool_strerror,taskpool,strerror} + */ + +/** + * @brief Creates the one single instance of the system task pool. + * + * This function should be called once by the application to initialize the one single instance of the system task pool. + * An application should initialize the system task pool early in the boot sequence, before initializing any other library + * and before posting any jobs. Early initialization it typically easy to accomplish by creating the system task pool + * before starting the scheduler. + * + * This function does not allocate memory to hold the task pool data structures and state, but it + * may allocate memory to hold the dependent entities and data structures, e.g. the threads of the task + * pool. The system task pool handle is recoverable for later use by calling @ref IotTaskPool_GetSystemTaskPool or + * the shortcut @ref IOT_SYSTEM_TASKPOOL. + * + * @param[in] pInfo A pointer to the task pool initialization data. + * + * @return One of the following: + * - #IOT_TASKPOOL_SUCCESS + * - #IOT_TASKPOOL_BAD_PARAMETER + * - #IOT_TASKPOOL_NO_MEMORY + * + * @warning This function should be called only once. Calling this function more that once will result in + * undefined behavior. + * + */ +/* @[declare_taskpool_createsystemtaskpool] */ +IotTaskPoolError_t IotTaskPool_CreateSystemTaskPool( const IotTaskPoolInfo_t * const pInfo ); +/* @[declare_taskpool_createsystemtaskpool] */ + +/** + * @brief Retrieves the one and only instance of a system task pool + * + * This function retrieves the system task pool created with @ref IotTaskPool_CreateSystemTaskPool, and it is functionally + * equivalent to using the shortcut @ref IOT_SYSTEM_TASKPOOL. + * + * @return The system task pool handle. + * + * @warning This function should be called after creating the system task pool with @ref IotTaskPool_CreateSystemTaskPool. + * Calling this function before creating the system task pool may return a pointer to an uninitialized task pool, NULL, or otherwise + * fail with undefined behaviour. + * + */ +/* @[declare_taskpool_getsystemtaskpool] */ +IotTaskPool_t IotTaskPool_GetSystemTaskPool( void ); +/* @[declare_taskpool_getsystemtaskpool] */ + +/** + * @brief Creates one instance of a task pool. + * + * This function should be called by the user to initialize one instance of a task + * pool. The task pool instance will be created around the storage pointed to by the `pTaskPool` + * parameter. This function will create the minimum number of threads requested by the user + * through an instance of the #IotTaskPoolInfo_t type specified with the `pInfo` parameter. + * This function does not allocate memory to hold the task pool data structures and state, but it + * may allocates memory to hold the dependent data structures, e.g. the threads of the task + * pool. + * + * @param[in] pInfo A pointer to the task pool initialization data. + * @param[out] pTaskPool A pointer to the task pool handle to be used after initialization. + * The pointer `pTaskPool` will hold a valid handle only if (@ref IotTaskPool_Create) + * completes successfully. + * + * @return One of the following: + * - #IOT_TASKPOOL_SUCCESS + * - #IOT_TASKPOOL_BAD_PARAMETER + * - #IOT_TASKPOOL_NO_MEMORY + * + */ +/* @[declare_taskpool_create] */ +IotTaskPoolError_t IotTaskPool_Create( const IotTaskPoolInfo_t * const pInfo, + IotTaskPool_t * const pTaskPool ); +/* @[declare_taskpool_create] */ + +/** + * @brief Destroys a task pool instance and collects all memory associated with a task pool and its + * satellite data structures. + * + * This function should be called to destroy one instance of a task pool previously created with a call + * to @ref IotTaskPool_Create or @ref IotTaskPool_CreateSystemTaskPool. + * Calling this fuction release all underlying resources. After calling this function, any job scheduled but not yet executed + * will be cancelled and destroyed. + * The `taskPool` instance will no longer be valid after this function returns. + * + * @param[in] taskPool A handle to the task pool, e.g. as returned by a call to @ref IotTaskPool_Create or + * @ref IotTaskPool_CreateSystemTaskPool. The `taskPool` instance will no longer be valid after this function returns. + * + * @return One of the following: + * - #IOT_TASKPOOL_SUCCESS + * - #IOT_TASKPOOL_BAD_PARAMETER + * + */ +/* @[declare_taskpool_destroy] */ +IotTaskPoolError_t IotTaskPool_Destroy( IotTaskPool_t taskPool ); +/* @[declare_taskpool_destroy] */ + +/** + * @brief Sets the maximum number of threads for one instance of a task pool. + * + * This function sets the maximum number of threads for the task pool + * pointed to by `taskPool`. + * + * If the number of currently active threads in the task pool is greater than `maxThreads`, this + * function causes the task pool to shrink the number of active threads. + * + * @param[in] taskPool A handle to the task pool that must have been previously initialized with + * a call to @ref IotTaskPool_Create or @ref IotTaskPool_CreateSystemTaskPool. + * @param[in] maxThreads The maximum number of threads for the task pool. + * + * @return One of the following: + * - #IOT_TASKPOOL_SUCCESS + * - #IOT_TASKPOOL_BAD_PARAMETER + * - #IOT_TASKPOOL_SHUTDOWN_IN_PROGRESS + * + */ +/* @[declare_taskpool_setmaxthreads] */ +IotTaskPoolError_t IotTaskPool_SetMaxThreads( IotTaskPool_t taskPool, + uint32_t maxThreads ); +/* @[declare_taskpool_setmaxthreads] */ + +/** + * @brief Creates a job for the task pool around a user-provided storage. + * + * This function may allocate memory to hold the state for a job. + * + * @param[in] userCallback A user-specified callback for the job. + * @param[in] pUserContext A user-specified context for the callback. + * @param[in] pJobStorage The storage for the job data structure. + * @param[out] pJob A pointer to an instance of @ref IotTaskPoolJob_t that will be initialized when this + * function returns successfully. This handle can be used to inspect the job status with + * @ref IotTaskPool_GetStatus or cancel the job with @ref IotTaskPool_TryCancel, etc.... + * + * @return One of the following: + * - #IOT_TASKPOOL_SUCCESS + * - #IOT_TASKPOOL_BAD_PARAMETER + * + * + */ +/* @[declare_taskpool_createjob] */ +IotTaskPoolError_t IotTaskPool_CreateJob( IotTaskPoolRoutine_t userCallback, + void * pUserContext, + IotTaskPoolJobStorage_t * const pJobStorage, + IotTaskPoolJob_t * const pJob ); +/* @[declare_taskpool_createjob] */ + +/** + * brief Creates a job for the task pool by allocating the job dynamically. + * + * A recyclable job does not need to be allocated twice, but it can rather be reused through + * subsequent calls to @ref IotTaskPool_CreateRecyclableJob. + * + * @param[in] taskPool A handle to the task pool for which to create a recyclable job. + * @param[in] userCallback A user-specified callback for the job. + * @param[in] pUserContext A user-specified context for the callback. + * @param[out] pJob A pointer to an instance of @ref IotTaskPoolJob_t that will be initialized when this + * function returns successfully. This handle can be used to inspect the job status with + * @ref IotTaskPool_GetStatus or cancel the job with @ref IotTaskPool_TryCancel, etc.... + * + * @return One of the following: + * - #IOT_TASKPOOL_SUCCESS + * - #IOT_TASKPOOL_BAD_PARAMETER + * - #IOT_TASKPOOL_NO_MEMORY + * - #IOT_TASKPOOL_SHUTDOWN_IN_PROGRESS + * + * @note This function will not allocate memory. + * + * @warning A recyclable job should be recycled with a call to @ref IotTaskPool_RecycleJob rather than destroyed. + * + */ +/* @[declare_taskpool_createrecyclablejob] */ +IotTaskPoolError_t IotTaskPool_CreateRecyclableJob( IotTaskPool_t taskPool, + IotTaskPoolRoutine_t userCallback, + void * pUserContext, + IotTaskPoolJob_t * const pJob ); +/* @[declare_taskpool_createrecyclablejob] */ + +/** + * @brief This function un-initializes a job. + * + * This function will destroy a job created with @ref IotTaskPool_CreateRecyclableJob. + * A job should not be destroyed twice. A job that was previously scheduled but has not completed yet should not be destroyed, + * but rather the application should attempt to cancel it first by calling @ref IotTaskPool_TryCancel. + * An attempt to destroy a job that was scheduled but not yet executed or canceled, may result in a + * @ref IOT_TASKPOOL_ILLEGAL_OPERATION error. + * + * @param[in] taskPool A handle to the task pool, e.g. as returned by a call to @ref IotTaskPool_Create or @ref IotTaskPool_CreateSystemTaskPool. + * @param[in] job A handle to a job that was create with a call to @ref IotTaskPool_CreateJob. + * + * @return One of the following: + * - #IOT_TASKPOOL_SUCCESS + * - #IOT_TASKPOOL_BAD_PARAMETER + * - #IOT_TASKPOOL_ILLEGAL_OPERATION + * - #IOT_TASKPOOL_SHUTDOWN_IN_PROGRESS + * + * @warning The task pool will try and prevent destroying jobs that are currently queued for execution, but does + * not enforce strict ordering of operations. It is up to the user to make sure @ref IotTaskPool_DestroyRecyclableJob is not called + * our of order. + * + * @warning Calling this function on job that was not previously created with @ref IotTaskPool_CreateRecyclableJob + * will result in a @ref IOT_TASKPOOL_ILLEGAL_OPERATION error. + * + */ +/* @[declare_taskpool_destroyrecyclablejob] */ +IotTaskPoolError_t IotTaskPool_DestroyRecyclableJob( IotTaskPool_t taskPool, + IotTaskPoolJob_t job ); +/* @[declare_taskpool_destroyrecyclablejob] */ + +/** + * @brief Recycles a job into the task pool job cache. + * + * This function will try and recycle the job into the task pool cache. If the cache is full, + * the job memory is destroyed as if the user called @ref IotTaskPool_DestroyRecyclableJob. The job should be recycled into + * the task pool instance from where it was allocated. + * Failure to do so will yield undefined results. A job should not be recycled twice. A job + * that was previously scheduled but not completed or canceled cannot be safely recycled. An attempt to do so will result + * in an @ref IOT_TASKPOOL_ILLEGAL_OPERATION error. + * + * @param[in] taskPool A handle to the task pool, e.g. as returned by a call to @ref IotTaskPool_Create. + * @param[out] job A pointer to a job that was create with a call to @ref IotTaskPool_CreateJob. + * + * @return One of the following: + * - #IOT_TASKPOOL_SUCCESS + * - #IOT_TASKPOOL_BAD_PARAMETER + * - #IOT_TASKPOOL_ILLEGAL_OPERATION + * - #IOT_TASKPOOL_SHUTDOWN_IN_PROGRESS + * + * @warning The `taskPool` used in this function should be the same + * used to create the job pointed to by `job`, or the results will be undefined. + * + * @warning Attempting to call this function on a statically allocated job will result in @ref IOT_TASKPOOL_ILLEGAL_OPERATION + * error. + * + * @warning This function should be used to recycle a job in the task pool cache when after the job executed. + * Failing to call either this function or @ref IotTaskPool_DestroyRecyclableJob will result is a memory leak. Statically + * allocated jobs do not need to be recycled or destroyed. + * + */ +/* @[declare_taskpool_recyclejob] */ +IotTaskPoolError_t IotTaskPool_RecycleJob( IotTaskPool_t taskPool, + IotTaskPoolJob_t job ); +/* @[declare_taskpool_recyclejob] */ + +/** + * @brief This function schedules a job created with @ref IotTaskPool_CreateJob or @ref IotTaskPool_CreateRecyclableJob + * against the task pool pointed to by `taskPool`. + * + * See @ref taskpool_design for a description of the jobs lifetime and interaction with the threads used in the task pool + * library. + * + * @param[in] taskPool A handle to the task pool that must have been previously initialized with. + * a call to @ref IotTaskPool_Create. + * @param[in] job A job to schedule for execution. This must be first initialized with a call to @ref IotTaskPool_CreateJob. + * @param[in] flags Flags to be passed by the user, e.g. to identify the job as high priority by specifying #IOT_TASKPOOL_JOB_HIGH_PRIORITY. + * + * @return One of the following: + * - #IOT_TASKPOOL_SUCCESS + * - #IOT_TASKPOOL_BAD_PARAMETER + * - #IOT_TASKPOOL_ILLEGAL_OPERATION + * - #IOT_TASKPOOL_NO_MEMORY + * - #IOT_TASKPOOL_SHUTDOWN_IN_PROGRESS + * + * + * @note This function will not allocate memory, so it is guaranteed to succeed if the paramters are correct and the task pool + * was correctly initialized, and not yet destroyed. + * + * @warning The `taskPool` used in this function should be the same used to create the job pointed to by `job`, or the + * results will be undefined. + * + * Example + * @code{c} + * // An example of a user context to pass to a callback through a task pool thread. + * typedef struct JobUserContext + * { + * uint32_t counter; + * } JobUserContext_t; + * + * // An example of a user callback to invoke through a task pool thread. + * static void ExecutionCb( IotTaskPool_t taskPool, IotTaskPoolJob_t job, void * context ) + * { + * ( void )taskPool; + * ( void )job; + * + * JobUserContext_t * pUserContext = ( JobUserContext_t * )context; + * + * pUserContext->counter++; + * } + * + * void TaskPoolExample( ) + * { + * JobUserContext_t userContext = { 0 }; + * IotTaskPoolJob_t job; + * IotTaskPool_t taskPool; + * + * // Configure the task pool to hold at least two threads and three at the maximum. + * // Provide proper stack size and priority per the application needs. + * + * const IotTaskPoolInfo_t tpInfo = { .minThreads = 2, .maxThreads = 3, .stackSize = 512, .priority = 0 }; + * + * // Create a task pool. + * IotTaskPool_Create( &tpInfo, &taskPool ); + * + * // Statically allocate one job, schedule it. + * IotTaskPool_CreateJob( &ExecutionCb, &userContext, &job ); + * + * IotTaskPoolError_t errorSchedule = IotTaskPool_Schedule( taskPool, &job, 0 ); + * + * switch ( errorSchedule ) + * { + * case IOT_TASKPOOL_SUCCESS: + * break; + * case IOT_TASKPOOL_BAD_PARAMETER: // Invalid parameters, such as a NULL handle, can trigger this error. + * case IOT_TASKPOOL_ILLEGAL_OPERATION: // Scheduling a job that was previously scheduled or destroyed could trigger this error. + * case IOT_TASKPOOL_NO_MEMORY: // Scheduling a with flag #IOT_TASKPOOL_JOB_HIGH_PRIORITY could trigger this error. + * case IOT_TASKPOOL_SHUTDOWN_IN_PROGRESS: // Scheduling a job after trying to destroy the task pool could trigger this error. + * // ASSERT + * break; + * default: + * // ASSERT + * } + * + * // + * // ... Perform other operations ... + * // + * + * IotTaskPool_Destroy( taskPool ); + * } + * @endcode + */ +/* @[declare_taskpool_schedule] */ +IotTaskPoolError_t IotTaskPool_Schedule( IotTaskPool_t taskPool, + IotTaskPoolJob_t job, + uint32_t flags ); +/* @[declare_taskpool_schedule] */ + +/** + * @brief This function schedules a job created with @ref IotTaskPool_CreateJob against the task pool + * pointed to by `taskPool` to be executed after a user-defined time interval. + * + * See @ref taskpool_design for a description of the jobs lifetime and interaction with the threads used in the task pool + * library. + * + * @param[in] taskPool A handle to the task pool that must have been previously initialized with. + * a call to @ref IotTaskPool_Create. + * @param[in] job A job to schedule for execution. This must be first initialized with a call to @ref IotTaskPool_CreateJob. + * @param[in] timeMs The time in milliseconds to wait before scheduling the job. + * + * @return One of the following: + * - #IOT_TASKPOOL_SUCCESS + * - #IOT_TASKPOOL_BAD_PARAMETER + * - #IOT_TASKPOOL_ILLEGAL_OPERATION + * - #IOT_TASKPOOL_SHUTDOWN_IN_PROGRESS + * + * + * @note This function will not allocate memory. + * + * @warning The `taskPool` used in this function should be the same + * used to create the job pointed to by `job`, or the results will be undefined. + * + */ +/* @[declare_taskpool_scheduledeferred] */ +IotTaskPoolError_t IotTaskPool_ScheduleDeferred( IotTaskPool_t taskPool, + IotTaskPoolJob_t job, + uint32_t timeMs ); +/* @[declare_taskpool_scheduledeferred] */ + +/** + * @brief This function retrieves the current status of a job. + * + * @param[in] taskPool A handle to the task pool that must have been previously initialized with + * a call to @ref IotTaskPool_Create or @ref IotTaskPool_CreateSystemTaskPool. + * @param[in] job The job to cancel. + * @param[out] pStatus The status of the job at the time of cancellation. + * + * @return One of the following: + * - #IOT_TASKPOOL_SUCCESS + * - #IOT_TASKPOOL_BAD_PARAMETER + * - #IOT_TASKPOOL_SHUTDOWN_IN_PROGRESS + * + * @warning This function is not thread safe and the job status returned in `pStatus` may be invalid by the time + * the calling thread has a chance to inspect it. + */ +/* @[declare_taskpool_getstatus] */ +IotTaskPoolError_t IotTaskPool_GetStatus( IotTaskPool_t taskPool, + IotTaskPoolJob_t job, + IotTaskPoolJobStatus_t * const pStatus ); +/* @[declare_taskpool_getstatus] */ + +/** + * @brief This function tries to cancel a job that was previously scheduled with @ref IotTaskPool_Schedule. + * + * A job can be canceled only if it is not yet executing, i.e. if its status is + * @ref IOT_TASKPOOL_STATUS_READY or @ref IOT_TASKPOOL_STATUS_SCHEDULED. Calling + * @ref IotTaskPool_TryCancel on a job whose status is @ref IOT_TASKPOOL_STATUS_COMPLETED, + * or #IOT_TASKPOOL_STATUS_CANCELED will yield a #IOT_TASKPOOL_CANCEL_FAILED return result. + * + * @param[in] taskPool A handle to the task pool that must have been previously initialized with + * a call to @ref IotTaskPool_Create. + * @param[in] job The job to cancel. + * @param[out] pStatus The status of the job at the time of cancellation. + * + * @return One of the following: + * - #IOT_TASKPOOL_SUCCESS + * - #IOT_TASKPOOL_BAD_PARAMETER + * - #IOT_TASKPOOL_SHUTDOWN_IN_PROGRESS + * - #IOT_TASKPOOL_CANCEL_FAILED + * + * @warning The `taskPool` used in this function should be the same + * used to create the job pointed to by `job`, or the results will be undefined. + * + */ +/* @[declare_taskpool_trycancel] */ +IotTaskPoolError_t IotTaskPool_TryCancel( IotTaskPool_t taskPool, + IotTaskPoolJob_t job, + IotTaskPoolJobStatus_t * const pStatus ); +/* @[declare_taskpool_trycancel] */ + +/** + * @brief Returns a pointer to the job storage from an instance of a job handle + * of type @ref IotTaskPoolJob_t. This function is guaranteed to succeed for a + * valid job handle. + * + * @param[in] job The job handle. + * + * @return A pointer to the storage associated with the job handle `job`. + * + * @warning If the `job` handle used is invalid, the results will be undefined. + */ +/* @[declare_taskpool_getjobstoragefromhandle] */ +IotTaskPoolJobStorage_t * IotTaskPool_GetJobStorageFromHandle( IotTaskPoolJob_t job ); +/* @[declare_taskpool_getjobstoragefromhandle] */ + +/** + * @brief Returns a string that describes an @ref IotTaskPoolError_t. + * + * Like the POSIX's `strerror`, this function returns a string describing a + * return code. In this case, the return code is a task pool library error code, + * `status`. + * + * The string returned by this function MUST be treated as read-only: any + * attempt to modify its contents may result in a crash. Therefore, this function + * is limited to usage in logging. + * + * @param[in] status The status to describe. + * + * @return A read-only string that describes `status`. + * + * @warning The string returned by this function must never be modified. + */ +/* @[declare_taskpool_strerror] */ +const char * IotTaskPool_strerror( IotTaskPoolError_t status ); +/* @[declare_taskpool_strerror] */ + +/** + * @brief The maximum number of task pools to be created when using + * a memory pool. + */ +#ifndef IOT_TASKPOOLS +#define IOT_TASKPOOLS ( 4 ) +#endif + +/** + * @brief The maximum number of jobs to cache. + */ +#ifndef IOT_TASKPOOL_JOBS_RECYCLE_LIMIT + #define IOT_TASKPOOL_JOBS_RECYCLE_LIMIT ( 8UL ) +#endif + +/** + * @brief The maximum timeout in milliseconds to wait for a job to be scheduled before waking up a worker thread. + * A worker thread that wakes up as a result of a timeout may exit to allow the task pool to fold back to its + * minimum number of threads. + */ +#ifndef IOT_TASKPOOL_JOB_WAIT_TIMEOUT_MS + #define IOT_TASKPOOL_JOB_WAIT_TIMEOUT_MS ( 60 * 1000UL ) +#endif + +#endif /* ifndef IOT_TASKPOOL_H_ */ diff --git a/FreeRTOS-Plus/Source/FreeRTOS-Plus-IoT-SDK/c_sdk/standard/common/include/private/iot_error.h b/FreeRTOS-Plus/Source/FreeRTOS-Plus-IoT-SDK/c_sdk/standard/common/include/private/iot_error.h new file mode 100644 index 000000000..805039001 --- /dev/null +++ b/FreeRTOS-Plus/Source/FreeRTOS-Plus-IoT-SDK/c_sdk/standard/common/include/private/iot_error.h @@ -0,0 +1,117 @@ +/* + * Amazon FreeRTOS Common V1.0.0 + * Copyright (C) 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to + * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of + * the Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * http://aws.amazon.com/freertos + * http://www.FreeRTOS.org + */ + +/** + * @file iot_error.h + * @brief Provides macros for error checking and function cleanup. + * + * The macros in this file are generic. They may be customized by each library + * by setting the library prefix. + */ + +#ifndef IOT_ERROR_H_ +#define IOT_ERROR_H_ + +/* The config header is always included first. */ +#include "iot_config.h" + +/** + * @brief Declare the status variable and an initial value. + * + * This macro should be at the beginning of any functions that use cleanup sections. + * + * @param[in] statusType The type of the status variable for this function. + * @param[in] initialValue The initial value to assign to the status variable. + */ +#define IOT_FUNCTION_ENTRY( statusType, initialValue ) statusType status = initialValue + +/** + * @brief Declares the label that begins a cleanup section. + * + * This macro should be placed at the end of a function and followed by + * #IOT_FUNCTION_CLEANUP_END. + */ +#define IOT_FUNCTION_CLEANUP_BEGIN() iotCleanup: + +/** + * @brief Declares the end of a cleanup section. + * + * This macro should be placed at the end of a function and preceded by + * #IOT_FUNCTION_CLEANUP_BEGIN. + */ +#define IOT_FUNCTION_CLEANUP_END() return status + +/** + * @brief Declares an empty cleanup section. + * + * This macro should be placed at the end of a function to exit on error if no + * cleanup is required. + */ +#define IOT_FUNCTION_EXIT_NO_CLEANUP() IOT_FUNCTION_CLEANUP_BEGIN(); IOT_FUNCTION_CLEANUP_END() + +/** + * @brief Jump to the cleanup section. + */ +#define IOT_GOTO_CLEANUP() goto iotCleanup + +/** + * @brief Assign a value to the status variable and jump to the cleanup section. + * + * @param[in] statusValue The value to assign to the status variable. + */ +#define IOT_SET_AND_GOTO_CLEANUP( statusValue ) { status = ( statusValue ); IOT_GOTO_CLEANUP(); } + +/** + * @brief Jump to the cleanup section if a condition is `false`. + * + * This macro may be used in place of `assert` to exit a function is a condition + * is `false`. + * + * @param[in] condition The condition to check. + */ +#define IOT_GOTO_CLEANUP_IF_FALSE( condition ) { if( ( condition ) == false ) { IOT_GOTO_CLEANUP(); } } + +/** + * @brief Assign a value to the status variable and jump to the cleanup section + * if a condition is `false`. + * + * @param[in] statusValue The value to assign to the status variable. + * @param[in] condition The condition to check. + */ +#define IOT_SET_AND_GOTO_CLEANUP_IF_FALSE( statusValue, condition ) \ + if( ( condition ) == false ) \ + IOT_SET_AND_GOTO_CLEANUP( statusValue ) + +/** + * @brief Check a condition; if `false`, assign the "Bad parameter" status value + * and jump to the cleanup section. + * + * @param[in] libraryPrefix The library prefix of the status variable. + * @param[in] condition The condition to check. + */ +#define IOT_VALIDATE_PARAMETER( libraryPrefix, condition ) \ + IOT_SET_AND_GOTO_CLEANUP_IF_FALSE( libraryPrefix ## _BAD_PARAMETER, condition ) + +#endif /* ifndef IOT_ERROR_H_ */ diff --git a/FreeRTOS-Plus/Source/FreeRTOS-Plus-IoT-SDK/c_sdk/standard/common/include/private/iot_logging.h b/FreeRTOS-Plus/Source/FreeRTOS-Plus-IoT-SDK/c_sdk/standard/common/include/private/iot_logging.h new file mode 100644 index 000000000..377dd6985 --- /dev/null +++ b/FreeRTOS-Plus/Source/FreeRTOS-Plus-IoT-SDK/c_sdk/standard/common/include/private/iot_logging.h @@ -0,0 +1,229 @@ +/* + * Amazon FreeRTOS Common V1.0.0 + * Copyright (C) 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to + * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of + * the Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * http://aws.amazon.com/freertos + * http://www.FreeRTOS.org + */ + +/** + * @file iot_logging.h + * @brief Generic logging function header file. + * + * Declares the generic logging function and the log levels. This file never + * needs to be included in source code. The header iot_logging_setup.h should + * be included instead. + * + * @see iot_logging_setup.h + */ + +#ifndef IOT_LOGGING_H_ +#define IOT_LOGGING_H_ + +/* The config header is always included first. */ +#include "iot_config.h" + +/* Standard includes. */ +#include +#include +#include + +/** + * @constantspage{logging,logging library} + * + * @section logging_constants_levels Log levels + * @brief Log levels for the libraries in this SDK. + * + * Each library should specify a log level by setting @ref LIBRARY_LOG_LEVEL. + * All log messages with a level at or below the specified level will be printed + * for that library. + * + * Currently, there are 4 log levels. In the order of lowest to highest, they are: + * - #IOT_LOG_NONE
+ * @copybrief IOT_LOG_NONE + * - #IOT_LOG_ERROR
+ * @copybrief IOT_LOG_ERROR + * - #IOT_LOG_WARN
+ * @copybrief IOT_LOG_WARN + * - #IOT_LOG_INFO
+ * @copybrief IOT_LOG_INFO + * - #IOT_LOG_DEBUG
+ * @copybrief IOT_LOG_DEBUG + */ + +/** + * @brief No log messages. + * + * Log messages with this level will be silently discarded. When @ref + * LIBRARY_LOG_LEVEL is #IOT_LOG_NONE, logging is disabled and no [logging functions] + * (@ref logging_functions) can be called. + */ +#define IOT_LOG_NONE 0 + +/** + * @brief Only critical, unrecoverable errors. + * + * Log messages with this level will be printed when a library encounters an + * error from which it cannot easily recover. + */ +#define IOT_LOG_ERROR 1 + +/** + * @brief Message about an abnormal but recoverable event. + * + * Log messages with this level will be printed when a library encounters an + * abnormal event that may be indicative of an error. Libraries should continue + * execution after logging a warning. + */ +#define IOT_LOG_WARN 2 + +/** + * @brief A helpful, informational message. + * + * Log messages with this level may indicate the normal status of a library + * function. They should be used to track how far a program has executed. + */ +#define IOT_LOG_INFO 3 + +/** + * @brief Detailed and excessive debug information. + * + * Log messages with this level are intended for developers. They may contain + * excessive information such as internal variables, buffers, or other specific + * information. + */ +#define IOT_LOG_DEBUG 4 + +/** + * @paramstructs{logging,logging} + */ + +/** + * @ingroup logging_datatypes_paramstructs + * @brief Log message configuration struct. + * + * @paramfor @ref logging_function_log, @ref logging_function_generic + * + * By default, log messages print the library name, log level, and a timestring. + * This struct can be passed to @ref logging_function_generic to disable one of + * the above components in the log message. + * + * Example: + * + * @code{c} + * IotLog_Generic( IOT_LOG_DEBUG, "SAMPLE", IOT_LOG_DEBUG, NULL, "Hello world!" ); + * @endcode + * The code above prints the following message: + * @code + * [DEBUG][SAMPLE][2018-01-01 12:00:00] Hello world! + * @endcode + * + * The timestring can be disabled as follows: + * @code + * IotLogConfig_t logConfig = { .hideLogLevel = false, .hideLibraryName = false, .hideTimestring = true}; + * IotLog_Generic( IOT_LOG_DEBUG, "SAMPLE", IOT_LOG_DEBUG, &logConfig, "Hello world!" ); + * @endcode + * The resulting log message will be: + * @code + * [DEBUG][SAMPLE] Hello world! + * @endcode + */ +typedef struct IotLogConfig +{ + bool hideLogLevel; /**< @brief Don't print the log level string for this message. */ + bool hideLibraryName; /**< @brief Don't print the library name for this message. */ + bool hideTimestring; /**< @brief Don't print the timestring for this message. */ +} IotLogConfig_t; + +/** + * @functionspage{logging,logging library} + * + * - @functionname{logging_function_log} + * - @functionname{logging_function_printbuffer} + * - @functionname{logging_function_generic} + * - @functionname{logging_function_genericprintbuffer} + */ + +/** + * @functionpage{IotLog_Generic,logging,generic} + * @functionpage{IotLog_PrintBuffer,logging,genericprintbuffer} + */ + +/** + * @brief Generic logging function that prints a single message. + * + * This function is the generic logging function shared across all libraries. + * The library-specific logging function @ref logging_function_log is implemented + * using this function. Like @ref logging_function_log, this function is only + * available when @ref LIBRARY_LOG_LEVEL is #IOT_LOG_NONE. + * + * In most cases, the library-specific logging function @ref logging_function_log + * should be called instead of this function. + * + * @param[in] libraryLogSetting The log level setting of the library, used to + * determine if the log message should be printed. Must be one of the @ref + * logging_constants_levels. + * @param[in] pLibraryName The library name to print. See @ref LIBRARY_LOG_NAME. + * @param[in] messageLevel The log level of the this message. See @ref LIBRARY_LOG_LEVEL. + * @param[in] pLogConfig Pointer to a #IotLogConfig_t. Optional; pass `NULL` to ignore. + * @param[in] pFormat Format string for the log message. + * @param[in] ... Arguments for format specification. + * + * @return No return value. On errors, it prints nothing. + */ +/* @[declare_logging_generic] */ +void IotLog_Generic( int libraryLogSetting, + const char * const pLibraryName, + int messageLevel, + const IotLogConfig_t * const pLogConfig, + const char * const pFormat, + ... ); +/* @[declare_logging_generic] */ + +/** + * @brief Generic function to log the contents of a buffer as bytes. + * + * This function is the generic buffer logging function shared across all libraries. + * The library-specific buffer logging function @ref logging_function_printbuffer is + * implemented using this function. Like @ref logging_function_printbuffer, this + * function is only available when @ref LIBRARY_LOG_LEVEL is #IOT_LOG_DEBUG. + * + * In most cases, the library-specific buffer logging function @ref + * logging_function_printbuffer should be called instead of this function. + * + * @param[in] pLibraryName The library name to print with the log. See @ref LIBRARY_LOG_NAME. + * @param[in] pHeader A message to print before printing the buffer. + * @param[in] pBuffer The buffer to print. + * @param[in] bufferSize The number of bytes in `pBuffer` to print. + * + * @return No return value. On errors, it prints nothing. + * + * @note To conserve memory, this function only allocates enough memory for a + * single line of output. Therefore, in multithreaded systems, its output may + * appear "fragmented" if other threads are logging simultaneously. + */ +/* @[declare_logging_genericprintbuffer] */ +void IotLog_GenericPrintBuffer( const char * const pLibraryName, + const char * const pHeader, + const uint8_t * const pBuffer, + size_t bufferSize ); +/* @[declare_logging_genericprintbuffer] */ + +#endif /* ifndef IOT_LOGGING_H_ */ diff --git a/FreeRTOS-Plus/Source/FreeRTOS-Plus-IoT-SDK/c_sdk/standard/common/include/private/iot_static_memory.h b/FreeRTOS-Plus/Source/FreeRTOS-Plus-IoT-SDK/c_sdk/standard/common/include/private/iot_static_memory.h new file mode 100644 index 000000000..76fe2b36d --- /dev/null +++ b/FreeRTOS-Plus/Source/FreeRTOS-Plus-IoT-SDK/c_sdk/standard/common/include/private/iot_static_memory.h @@ -0,0 +1,250 @@ +/* + * Amazon FreeRTOS Common V1.0.0 + * Copyright (C) 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to + * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of + * the Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * http://aws.amazon.com/freertos + * http://www.FreeRTOS.org + */ + +/** + * @file iot_static_memory.h + * @brief Common functions for managing static buffers. Only used when + * @ref IOT_STATIC_MEMORY_ONLY is `1`. + */ + +/* The config header is always included first. */ +#include "iot_config.h" + +/* The functions in this file should only exist in static memory only mode, hence + * the check for IOT_STATIC_MEMORY_ONLY in the double inclusion guard. */ +#if !defined( IOT_STATIC_MEMORY_H_ ) && ( IOT_STATIC_MEMORY_ONLY == 1 ) +#define IOT_STATIC_MEMORY_H_ + +/* Standard includes. */ +#include +#include +#include + +/** + * @functionspage{static_memory,static memory component} + * - @functionname{static_memory_function_init} + * - @functionname{static_memory_function_cleanup} + * - @functionname{static_memory_function_findfree} + * - @functionname{static_memory_function_returninuse} + * - @functionname{static_memory_function_messagebuffersize} + * - @functionname{static_memory_function_mallocmessagebuffer} + * - @functionname{static_memory_function_freemessagebuffer} + */ + +/*----------------------- Initialization and cleanup ------------------------*/ + +/** + * @functionpage{IotStaticMemory_Init,static_memory,init} + * @functionpage{IotStaticMemory_Cleanup,static_memory,cleanup} + */ + +/** + * @brief One-time initialization function for static memory. + * + * This function performs internal setup of static memory. It must be called + * once (and only once) before calling any other static memory function. + * Calling this function more than once without first calling + * @ref static_memory_function_cleanup may result in a crash. + * + * @return `true` if initialization succeeded; `false` otherwise. + * + * @attention This function is called by `IotSdk_Init` and does not need to be + * called by itself. + * + * @warning No thread-safety guarantees are provided for this function. + * + * @see static_memory_function_cleanup + */ +/* @[declare_static_memory_init] */ +bool IotStaticMemory_Init( void ); +/* @[declare_static_memory_init] */ + +/** + * @brief One-time deinitialization function for static memory. + * + * This function frees resources taken in @ref static_memory_function_init. + * It should be called after to clean up static memory. After this function + * returns, @ref static_memory_function_init must be called again before + * calling any other static memory function. + * + * @attention This function is called by `IotSdk_Cleanup` and does not need + * to be called by itself. + * + * @warning No thread-safety guarantees are provided for this function. + * + * @see static_memory_function_init + */ +/* @[declare_static_memory_cleanup] */ +void IotStaticMemory_Cleanup( void ); +/* @[declare_static_memory_cleanup] */ + +/*------------------------- Buffer allocation and free ----------------------*/ + +/** + * @functionpage{IotStaticMemory_FindFree,static_memory,findfree} + * @functionpage{IotStaticMemory_ReturnInUse,static_memory,returninuse} + */ + +/** + * @brief Find a free buffer using the "in-use" flags. + * + * If a free buffer is found, this function marks the buffer in-use. This function + * is common to the static memory implementation. + * + * @param[in] pInUse The "in-use" flags to search. + * @param[in] limit How many flags to check, i.e. the size of `pInUse`. + * + * @return The index of a free buffer; `-1` if no free buffers are available. + * + * Example: + * @code{c} + * // To use this function, first declare two arrays. One provides the statically-allocated + * // objects, the other provides flags to determine which objects are in-use. + * #define NUMBER_OF_OBJECTS ... + * #define OBJECT_SIZE ... + * static bool _pInUseObjects[ NUMBER_OF_OBJECTS ] = { 0 }; + * static uint8_t _pObjects[ NUMBER_OF_OBJECTS ][ OBJECT_SIZE ] = { { 0 } }; // Placeholder for objects. + * + * // The function to statically allocate objects. Must have the same signature + * // as malloc(). + * void * Iot_MallocObject( size_t size ) + * { + * int32_t freeIndex = -1; + * void * pNewObject = NULL; + * + * // Check that sizes match. + * if( size != OBJECT_SIZE ) + * { + * // Get the index of a free object. + * freeIndex = IotStaticMemory_FindFree( _pInUseMessageBuffers, + * IOT_MESSAGE_BUFFERS ); + * + * if( freeIndex != -1 ) + * { + * pNewBuffer = &( _pMessageBuffers[ freeIndex ][ 0 ] ); + * } + * } + * + * return pNewBuffer; + * } + * @endcode + */ +/* @[declare_static_memory_findfree] */ +int32_t IotStaticMemory_FindFree( bool * pInUse, + size_t limit ); +/* @[declare_static_memory_findfree] */ + +/** + * @brief Return an "in-use" buffer. + * + * This function is common to the static memory implementation. + * + * @param[in] ptr Pointer to the buffer to return. + * @param[in] pPool The pool of buffers that the in-use buffer was allocated from. + * @param[in] pInUse The "in-use" flags for pPool. + * @param[in] limit How many buffers (and flags) to check while searching for ptr. + * @param[in] elementSize The size of a single element in pPool. + * + * Example: + * @code{c} + * // To use this function, first declare two arrays. One provides the statically-allocated + * // objects, the other provides flags to determine which objects are in-use. + * #define NUMBER_OF_OBJECTS ... + * #define OBJECT_SIZE ... + * static bool _pInUseObjects[ NUMBER_OF_OBJECTS ] = { 0 }; + * static uint8_t _pObjects[ NUMBER_OF_OBJECTS ][ OBJECT_SIZE ] = { { 0 } }; // Placeholder for objects. + * + * // The function to free statically-allocated objects. Must have the same signature + * // as free(). + * void Iot_FreeObject( void * ptr ) + * { + * IotStaticMemory_ReturnInUse( ptr, + * _pObjects, + * _pInUseObjects, + * NUMBER_OF_OBJECTS, + * OBJECT_SIZE ); + * } + * @endcode + */ +/* @[declare_static_memory_returninuse] */ +void IotStaticMemory_ReturnInUse( void * ptr, + void * pPool, + bool * pInUse, + size_t limit, + size_t elementSize ); +/* @[declare_static_memory_returninuse] */ + +/*------------------------ Message buffer management ------------------------*/ + +/** + * @functionpage{Iot_MessageBufferSize,static_memory,messagebuffersize} + * @functionpage{Iot_MallocMessageBuffer,static_memory,mallocmessagebuffer} + * @functionpage{Iot_FreeMessageBuffer,static_memory,freemessagebuffer} + */ + +/** + * @brief Get the fixed size of a message buffer. + * + * The size of the message buffers are known at compile time, but it is a [constant] + * (@ref IOT_MESSAGE_BUFFER_SIZE) that may not be visible to all source files. + * This function allows other source files to know the size of a message buffer. + * + * @return The size, in bytes, of a single message buffer. + */ +/* @[declare_static_memory_messagebuffersize] */ +size_t Iot_MessageBufferSize( void ); +/* @[declare_static_memory_messagebuffersize] */ + +/** + * @brief Get an empty message buffer. + * + * This function is the analog of [malloc] + * (http://pubs.opengroup.org/onlinepubs/9699919799/functions/malloc.html) + * for message buffers. + * + * @param[in] size Requested size for a message buffer. + * + * @return Pointer to the start of a message buffer. If the `size` argument is larger + * than the [fixed size of a message buffer](@ref IOT_MESSAGE_BUFFER_SIZE) + * or no message buffers are available, `NULL` is returned. + */ +/* @[declare_static_memory_mallocmessagebuffer] */ +void * Iot_MallocMessageBuffer( size_t size ); +/* @[declare_static_memory_mallocmessagebuffer] */ + +/** + * @brief Free an in-use message buffer. + * + * This function is the analog of [free] + * (http://pubs.opengroup.org/onlinepubs/9699919799/functions/free.html) + * for message buffers. + * + * @param[in] ptr Pointer to the message buffer to free. + */ +/* @[declare_static_memory_freemessagebuffer] */ +void Iot_FreeMessageBuffer( void * ptr ); +/* @[declare_static_memory_freemessagebuffer] */ + +#endif /* if !defined( IOT_STATIC_MEMORY_H_ ) && ( IOT_STATIC_MEMORY_ONLY == 1 ) */ diff --git a/FreeRTOS-Plus/Source/FreeRTOS-Plus-IoT-SDK/c_sdk/standard/common/include/private/iot_taskpool_internal.h b/FreeRTOS-Plus/Source/FreeRTOS-Plus-IoT-SDK/c_sdk/standard/common/include/private/iot_taskpool_internal.h new file mode 100644 index 000000000..b989c586c --- /dev/null +++ b/FreeRTOS-Plus/Source/FreeRTOS-Plus-IoT-SDK/c_sdk/standard/common/include/private/iot_taskpool_internal.h @@ -0,0 +1,294 @@ +/* + * Amazon FreeRTOS Common V1.0.0 + * Copyright (C) 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to + * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of + * the Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * http://aws.amazon.com/freertos + * http://www.FreeRTOS.org + */ + +/** + * @file iot_taskpool_internal.h + * @brief Internal header of task pool library. This header should not be included in + * typical application code. + */ + +#ifndef IOT_TASKPOOL_INTERNAL_H_ +#define IOT_TASKPOOL_INTERNAL_H_ + +/* The config header is always included first. */ +#include "iot_config.h" + +/* Task pool include. */ +#include "private/iot_error.h" +#include "iot_taskpool.h" + +/* FreeRTOS includes. */ +#include "FreeRTOS.h" +#include "semphr.h" +#include "timers.h" + +/* Establish a few convenience macros to handle errors in a standard way. */ + +/** + * @brief Every public API return an enumeration value with an undelying value of 0 in case of success. + */ +#define TASKPOOL_SUCCEEDED( x ) ( ( x ) == IOT_TASKPOOL_SUCCESS ) + +/** + * @brief Every public API returns an enumeration value with an undelying value different than 0 in case of success. + */ +#define TASKPOOL_FAILED( x ) ( ( x ) != IOT_TASKPOOL_SUCCESS ) + +/** + * @brief Jump to the cleanup area. + */ +#define TASKPOOL_GOTO_CLEANUP() IOT_GOTO_CLEANUP() + +/** + * @brief Declare the storage for the error status variable. + */ +#define TASKPOOL_FUNCTION_ENTRY( result ) IOT_FUNCTION_ENTRY( IotTaskPoolError_t, result ) + +/** + * @brief Check error and leave in case of failure. + */ +#define TASKPOOL_ON_ERROR_GOTO_CLEANUP( expr ) \ + { if( TASKPOOL_FAILED( status = ( expr ) ) ) { IOT_GOTO_CLEANUP(); } \ + } + +/** + * @brief Exit if an argument is NULL. + */ +#define TASKPOOL_ON_NULL_ARG_GOTO_CLEANUP( ptr ) IOT_VALIDATE_PARAMETER( IOT_TASKPOOL, ( ptr != NULL ) ) + +/** + * @brief Exit if an argument is NULL. + */ +#define TASKPOOL_ON_ARG_ERROR_GOTO_CLEANUP( expr ) IOT_VALIDATE_PARAMETER( IOT_TASKPOOL, ( ( expr ) == false ) ) + +/** + * @brief Set error and leave. + */ +#define TASKPOOL_SET_AND_GOTO_CLEANUP( expr ) IOT_SET_AND_GOTO_CLEANUP( expr ) + +/** + * @brief Initialize error and declare start of cleanup area. + */ +#define TASKPOOL_FUNCTION_CLEANUP() IOT_FUNCTION_CLEANUP_BEGIN() + +/** + * @brief Initialize error and declare end of cleanup area. + */ +#define TASKPOOL_FUNCTION_CLEANUP_END() IOT_FUNCTION_CLEANUP_END() + +/** + * @brief Create an empty cleanup area. + */ +#define TASKPOOL_NO_FUNCTION_CLEANUP() IOT_FUNCTION_EXIT_NO_CLEANUP() + +/** + * @brief Does not create a cleanup area. + */ +#define TASKPOOL_NO_FUNCTION_CLEANUP_NOLABEL() return status + +/** + * @def IotTaskPool_Assert( expression ) + * @brief Assertion macro for the Task pool library. + * + * Set @ref IOT_TASKPOOL_ENABLE_ASSERTS to `1` to enable assertions in the Task pool + * library. + * + * @param[in] expression Expression to be evaluated. + */ +#if IOT_TASKPOOL_ENABLE_ASSERTS == 1 + #ifndef IotTaskPool_Assert + #include + #define IotTaskPool_Assert( expression ) assert( expression ) + #endif +#else + #define IotTaskPool_Assert( expression ) +#endif + +/* Configure logs for TASKPOOL functions. */ +#ifdef IOT_LOG_LEVEL_TASKPOOL + #define LIBRARY_LOG_LEVEL IOT_LOG_LEVEL_TASKPOOL +#else + #ifdef IOT_LOG_LEVEL_GLOBAL + #define LIBRARY_LOG_LEVEL IOT_LOG_LEVEL_GLOBAL + #else + #define LIBRARY_LOG_LEVEL IOT_LOG_NONE + #endif +#endif + +#define LIBRARY_LOG_NAME ( "TASKPOOL" ) +#include "iot_logging_setup.h" + +/* + * Provide default values for undefined memory allocation functions based on + * the usage of dynamic memory allocation. + */ +#if IOT_STATIC_MEMORY_ONLY == 1 + #include "private/iot_static_memory.h" + +/** + * @brief Allocate an #_taskPool_t. This function should have the + * same signature as [malloc]. + */ + void * IotTaskPool_MallocTaskPool( size_t size ); + +/** + * @brief Free an #_taskPool_t. This function should have the + * same signature as [malloc]. + */ + void IotTaskPool_FreeTaskPool( void * ptr ); + +/** + * @brief Allocate an #IotTaskPoolJob_t. This function should have the + * same signature as [malloc]. + */ + void * IotTaskPool_MallocJob( size_t size ); + +/** + * @brief Free an #IotTaskPoolJob_t. This function should have the same + * same signature as [malloc]. + * (http://pubs.opengroup.org/onlinepubs/9699919799/functions/malloc.html). + */ + void IotTaskPool_FreeJob( void * ptr ); + +/** + * @brief Allocate an #_taskPoolTimerEvent_t. This function should have the + * same signature as [malloc]. + */ + void * IotTaskPool_MallocTimerEvent( size_t size ); + +/** + * @brief Free an #_taskPoolTimerEvent_t. This function should have the + * same signature as[ free ]. + */ + void IotTaskPool_FreeTimerEvent( void * ptr ); + +#else /* if IOT_STATIC_MEMORY_ONLY == 1 */ + #include + + #ifndef IotTaskPool_MallocTaskPool + #define IotTaskPool_MallocTaskPool malloc + #endif + + #ifndef IotTaskPool_FreeTaskPool + #define IotTaskPool_FreeTaskPool free + #endif + + #ifndef IotTaskPool_MallocJob + #define IotTaskPool_MallocJob malloc + #endif + + #ifndef IotTaskPool_FreeJob + #define IotTaskPool_FreeJob free + #endif + + #ifndef IotTaskPool_MallocTimerEvent + #define IotTaskPool_MallocTimerEvent malloc + #endif + + #ifndef IotTaskPool_FreeTimerEvent + #define IotTaskPool_FreeTimerEvent free + #endif + +#endif /* if IOT_STATIC_MEMORY_ONLY == 1 */ + +/* ---------------------------------------------------------------------------------------------- */ + +/** + * @cond DOXYGEN_IGNORE + * Doxygen should ignore this section. + * + * A macros to manage task pool memory allocation. + */ +#define IOT_TASK_POOL_INTERNAL_STATIC ( ( uint32_t ) 0x00000001 ) /* Flag to mark a job as user-allocated. */ +/** @endcond */ + +/** + * @brief Task pool jobs cache. + * + * @warning This is a system-level data type that should not be modified or used directly in any application. + * @warning This is a system-level data type that can and will change across different versions of the platform, with no regards for backward compatibility. + * + */ +typedef struct _taskPoolCache +{ + IotListDouble_t freeList; /**< @brief A list ot hold cached jobs. */ + + uint32_t freeCount; /**< @brief A counter to track the number of jobs in the cache. */ +} _taskPoolCache_t; + +/** + * @brief The task pool data structure keeps track of the internal state and the signals for the dispatcher threads. + * The task pool is a thread safe data structure. + * + * @warning This is a system-level data type that should not be modified or used directly in any application. + * @warning This is a system-level data type that can and will change across different versions of the platform, with no regards for backward compatibility. + * + */ +typedef struct _taskPool +{ + IotDeQueue_t dispatchQueue; /**< @brief The queue for the jobs waiting to be executed. */ + IotListDouble_t timerEventsList; /**< @brief The timeouts queue for all deferred jobs waiting to be executed. */ + _taskPoolCache_t jobsCache; /**< @brief A cache to re-use jobs in order to limit memory allocations. */ + uint32_t activeThreads; /**< @brief The number of threads in the task pool at any given time. */ + int32_t priority; /**< @brief The priority for all task pool threads. */ + SemaphoreHandle_t dispatchSignal; /**< @brief The synchronization object on which threads are waiting for incoming jobs. */ + StaticSemaphore_t dispatchSignalBuffer; /**< @brief The semaphore buffer. */ + SemaphoreHandle_t startStopSignal; /**< @brief The synchronization object for threads to signal start and stop condition. */ + StaticSemaphore_t startStopSignalBuffer; /**< @brief The semaphore buffer. */ + TimerHandle_t timer; /**< @brief The timer for deferred jobs. */ + StaticTimer_t timerBuffer; /**< @brief The timer buffer. */ + bool running; /**< @brief A flag to track whether the task pool is operational or should shut down. */ +} _taskPool_t; + +/** + * @brief The job data structure keeps track of the user callback and context, as well as the status of the job. + * + * @warning This is a system-level data type that should not be modified or used directly in any application. + * @warning This is a system-level data type that can and will change across different versions of the platform, with no regards for backward compatibility. + * + */ +typedef struct _taskPoolJob +{ + IotLink_t link; /**< @brief The link to insert the job in the dispatch queue. */ + IotTaskPoolRoutine_t userCallback; /**< @brief The user provided callback. */ + void * pUserContext; /**< @brief The user provided context. */ + uint32_t flags; /**< @brief Internal flags. */ + IotTaskPoolJobStatus_t status; /**< @brief The status for the job. */ +} _taskPoolJob_t; + +/** + * @brief Represents an operation that is subject to a timer. + * + * These events are queued per MQTT connection. They are sorted by their + * expiration time. + */ +typedef struct _taskPoolTimerEvent +{ + IotLink_t link; /**< @brief List link member. */ + TickType_t expirationTime; /**< @brief When this event should be processed. */ + IotTaskPoolJob_t job; /**< @brief The task pool job associated with this event. */ +} _taskPoolTimerEvent_t; + +#endif /* ifndef IOT_TASKPOOL_INTERNAL_H_ */ \ No newline at end of file diff --git a/FreeRTOS-Plus/Source/FreeRTOS-Plus-IoT-SDK/c_sdk/standard/common/include/types/iot_taskpool_types.h b/FreeRTOS-Plus/Source/FreeRTOS-Plus-IoT-SDK/c_sdk/standard/common/include/types/iot_taskpool_types.h new file mode 100644 index 000000000..ea53dba71 --- /dev/null +++ b/FreeRTOS-Plus/Source/FreeRTOS-Plus-IoT-SDK/c_sdk/standard/common/include/types/iot_taskpool_types.h @@ -0,0 +1,362 @@ +/* + * Amazon FreeRTOS Common V1.0.0 + * Copyright (C) 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to + * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of + * the Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * http://aws.amazon.com/freertos + * http://www.FreeRTOS.org + */ + +/** + * @file iot_taskpool_types.h + * @brief Types of the task pool. + */ + +#ifndef IOT_TASKPOOL_TYPES_H_ +#define IOT_TASKPOOL_TYPES_H_ + +/* The config header is always included first. */ +#include "iot_config.h" + +/* Standard includes. */ +#include +#include + +/* Platform types includes. */ +#include "types/iot_platform_types.h" + +/* Linear containers (lists and queues) include. */ +#include "iot_linear_containers.h" + +/*-------------------------- Task pool enumerated types --------------------------*/ + +/** + * @ingroup taskpool_datatypes_enums + * @brief Return codes of [task pool functions](@ref taskpool_functions). + */ +typedef enum IotTaskPoolError +{ + /** + * @brief Task pool operation completed successfully. + * + * Functions that may return this value: + * - @ref taskpool_function_createsystemtaskpool + * - @ref taskpool_function_create + * - @ref taskpool_function_destroy + * - @ref taskpool_function_setmaxthreads + * - @ref taskpool_function_createjob + * - @ref taskpool_function_createrecyclablejob + * - @ref taskpool_function_destroyrecyclablejob + * - @ref taskpool_function_recyclejob + * - @ref taskpool_function_schedule + * - @ref taskpool_function_scheduledeferred + * - @ref taskpool_function_getstatus + * - @ref taskpool_function_trycancel + * + */ + IOT_TASKPOOL_SUCCESS = 0, + + /** + * @brief Task pool operation failed because at laest one parameter is invalid. + * + * Functions that may return this value: + * - @ref taskpool_function_createsystemtaskpool + * - @ref taskpool_function_create + * - @ref taskpool_function_destroy + * - @ref taskpool_function_setmaxthreads + * - @ref taskpool_function_createjob + * - @ref taskpool_function_createrecyclablejob + * - @ref taskpool_function_destroyrecyclablejob + * - @ref taskpool_function_recyclejob + * - @ref taskpool_function_schedule + * - @ref taskpool_function_scheduledeferred + * - @ref taskpool_function_getstatus + * - @ref taskpool_function_trycancel + * + */ + IOT_TASKPOOL_BAD_PARAMETER, + + /** + * @brief Task pool operation failed because it is illegal. + * + * Functions that may return this value: + * - @ref taskpool_function_createjob + * - @ref taskpool_function_createrecyclablejob + * - @ref taskpool_function_destroyrecyclablejob + * - @ref taskpool_function_recyclejob + * - @ref taskpool_function_schedule + * - @ref taskpool_function_scheduledeferred + * - @ref taskpool_function_trycancel + * + */ + IOT_TASKPOOL_ILLEGAL_OPERATION, + + /** + * @brief Task pool operation failed because allocating memory failed. + * + * Functions that may return this value: + * - @ref taskpool_function_createsystemtaskpool + * - @ref taskpool_function_create + * - @ref taskpool_function_setmaxthreads + * - @ref taskpool_function_createrecyclablejob + * - @ref taskpool_function_scheduledeferred + * - @ref taskpool_function_getstatus + * + */ + IOT_TASKPOOL_NO_MEMORY, + + /** + * @brief Task pool operation failed because of an invalid parameter. + * + * Functions that may return this value: + * - @ref taskpool_function_setmaxthreads + * - @ref taskpool_function_createrecyclablejob + * - @ref taskpool_function_destroyrecyclablejob + * - @ref taskpool_function_recyclejob + * - @ref taskpool_function_schedule + * - @ref taskpool_function_scheduledeferred + * - @ref taskpool_function_getstatus + * - @ref taskpool_function_trycancel + * + */ + IOT_TASKPOOL_SHUTDOWN_IN_PROGRESS, + + /** + * @brief Task pool cancellation failed. + * + * Functions that may return this value: + * - @ref taskpool_function_trycancel + * + */ + IOT_TASKPOOL_CANCEL_FAILED, +} IotTaskPoolError_t; + +/** + * @enums{taskpool,Task pool library} + */ + +/** + * @ingroup taskpool_datatypes_enums + * @brief Status codes of [task pool Job](@ref IotTaskPoolJob_t). + * + */ +typedef enum IotTaskPoolJobStatus +{ + /** + * @brief Job is ready to be scheduled. + * + */ + IOT_TASKPOOL_STATUS_READY = 0, + + /** + * @brief Job has been queued for execution. + * + */ + IOT_TASKPOOL_STATUS_SCHEDULED, + + /** + * @brief Job has been scheduled for deferred execution. + * + */ + IOT_TASKPOOL_STATUS_DEFERRED, + + /** + * @brief Job is executing. + * + */ + IOT_TASKPOOL_STATUS_COMPLETED, + + /** + * @brief Job has been canceled before executing. + * + */ + IOT_TASKPOOL_STATUS_CANCELED, + + /** + * @brief Job status is undefined. + * + */ + IOT_TASKPOOL_STATUS_UNDEFINED, +} IotTaskPoolJobStatus_t; + +/*------------------------- Task pool types and handles --------------------------*/ + +/** + * @ingroup taskpool_datatypes_handles + * @brief Opaque handle of a Task Pool instance. + * + * This type identifies a Task Pool instance, which is valid after a successful call + * to @ref taskpool_function_createsystemtaskpool or @ref taskpool_function_create. A + * variable of this type is passed as the first + * argument to [Task Pool library functions](@ref taskpool_functions) to identify which + * task pool that function acts on. + * + * A call to @ref taskpool_function_destroy makes a task pool handle invalid. Once + * @ref taskpool_function_destroy returns, the task handle should no longer + * be used. + * + * @initializer{IotTaskPool_t,IOT_TASKPOOL_INITIALIZER} + */ +typedef struct _taskPool * IotTaskPool_t; + +/** + * @ingroup taskpool_datatypes_structs + * @brief The job storage data structure provides the storage for a statically allocated Task Pool Job instance. + * + * @warning This is a system-level data type that should not be modified or used directly in any application. + * @warning This is a system-level data type that can and will change across different versions of the platform, with no regards for backward compatibility. + * + */ +typedef struct IotTaskPoolJobStorage +{ + IotLink_t link; /**< @brief Placeholder. */ + void * dummy2; /**< @brief Placeholder. */ + void * dummy3; /**< @brief Placeholder. */ + uint32_t dummy4; /**< @brief Placeholder. */ + IotTaskPoolJobStatus_t status; /**< @brief Placeholder. */ +} IotTaskPoolJobStorage_t; + +/** + * @ingroup taskpool_datatypes_handles + * @brief Opaque handle of a Task Pool Job. + * + * This type identifies a Task Pool Job instance, which is valid after a successful call + * to @ref taskpool_function_createjob or @ref taskpool_function_createrecyclablejob. + * + * A call to @ref taskpool_function_recyclejob or @ref taskpool_function_destroyrecyclablejob makes a + * task pool job handle invalid. Once @ref taskpool_function_recyclejob or + * @ref taskpool_function_destroyrecyclablejob returns, the task job handle should no longer be used. + * + * @initializer{IotTaskPoolJob_t,IOT_TASKPOOL_JOB_INITIALIZER} + * + */ +typedef struct _taskPoolJob * IotTaskPoolJob_t; + +/*------------------------- Task pool parameter structs --------------------------*/ + +/** + * @ingroup taskpool_datatypes_functionpointers + * @brief Callback type for a user callback. + * + * This type identifies the user callback signature to execute a task pool job. This callback will be invoked + * by the task pool threads with the `pUserContext` parameter, as specified by the user when + * calling @ref IotTaskPool_Schedule. + * + */ +typedef void ( * IotTaskPoolRoutine_t )( IotTaskPool_t pTaskPool, + IotTaskPoolJob_t pJob, + void * pUserContext ); + +/** + * @ingroup taskpool_datatypes_paramstructs + * @brief Initialization information to create one task pool instance. + * + * @paramfor @ref taskpool_function_createsystemtaskpool @ref taskpool_function_create. + * + * Passed as an argument to @ref taskpool_function_create. + * + * @initializer{IotTaskPoolInfo_t,IOT_TASKPOOL_INFO_INITIALIZER} + */ +typedef struct IotTaskPoolInfo +{ + /** + * @brief Specifies the operating parameters for a task pool. + * + * @attention #IotTaskPoolInfo_t.minThreads MUST be at least 1. + * #IotTaskPoolInfo_t.maxThreads MUST be greater or equal to #IotTaskPoolInfo_t.minThreads. + * If the minimum number of threads is same as the maximum, then the task pool will not try and grow the + * number of worker threads at run time. + */ + + uint32_t minThreads; /**< @brief Minimum number of threads in a task pool. These threads will be created when the task pool is first created with @ref taskpool_function_create. */ + uint32_t maxThreads; /**< @brief Maximum number of threads in a task pool. A task pool may try and grow the number of active threads up to #IotTaskPoolInfo_t.maxThreads. */ + uint32_t stackSize; /**< @brief Stack size for every task pool thread. The stack size for each thread is fixed after the task pool is created and cannot be changed. */ + int32_t priority; /**< @brief priority for every task pool thread. The priority for each thread is fixed after the task pool is created and cannot be changed. */ +} IotTaskPoolInfo_t; + +/*------------------------- TASKPOOL defined constants --------------------------*/ + +/** + * @constantspage{taskpool,task pool library} + * + * @section taskpool_constants_initializers Task pool Initializers + * @brief Provides default values for initializing the data types of the task pool library. + * + * @snippet this define_taskpool_initializers + * + * All user-facing data types of the task pool library can be initialized using + * one of the following. + * + * @warning Failure to initialize a task pool data type with the appropriate initializer + * may result in a runtime error! + * @note The initializers may change at any time in future versions, but their + * names will remain the same. + * + * Example + * @code{c} + * + * IotTaskPool_t * pTaskPool; + * + * const IotTaskPoolInfo_t tpInfo = IOT_TASKPOOL_INFO_INITIALIZER_LARGE; + * + * IotTaskPoolError_t error = IotTaskPool_Create( &tpInfo, &pTaskPool ); + * + * // Use the task pool + * // ... + * + * @endcode + * + */ +/* @[define_taskpool_initializers] */ +/** @brief Initializer for a small #IotTaskPoolInfo_t. */ +#define IOT_TASKPOOL_INFO_INITIALIZER_SMALL { .minThreads = 1, .maxThreads = 1, .stackSize = IOT_THREAD_DEFAULT_STACK_SIZE, .priority = IOT_THREAD_DEFAULT_PRIORITY } +/** @brief Initializer for a medium #IotTaskPoolInfo_t. */ +#define IOT_TASKPOOL_INFO_INITIALIZER_MEDIUM { .minThreads = 1, .maxThreads = 2, .stackSize = IOT_THREAD_DEFAULT_STACK_SIZE, .priority = IOT_THREAD_DEFAULT_PRIORITY } +/** @brief Initializer for a large #IotTaskPoolInfo_t. */ +#define IOT_TASKPOOL_INFO_INITIALIZER_LARGE { .minThreads = 2, .maxThreads = 3, .stackSize = IOT_THREAD_DEFAULT_STACK_SIZE, .priority = IOT_THREAD_DEFAULT_PRIORITY } +/** @brief Initializer for a very large #IotTaskPoolInfo_t. */ +#define IOT_TASKPOOL_INFO_INITIALIZER_XLARGE { .minThreads = 2, .maxThreads = 4, .stackSize = IOT_THREAD_DEFAULT_STACK_SIZE, .priority = IOT_THREAD_DEFAULT_PRIORITY } +/** @brief Initializer for a typical #IotTaskPoolInfo_t. */ +#define IOT_TASKPOOL_INFO_INITIALIZER IOT_TASKPOOL_INFO_INITIALIZER_MEDIUM +/** @brief Initializer for a #IotTaskPool_t. */ +#define IOT_TASKPOOL_INITIALIZER NULL +/** @brief Initializer for a #IotTaskPoolJobStorage_t. */ +#define IOT_TASKPOOL_JOB_STORAGE_INITIALIZER { { NULL, NULL }, NULL, NULL, 0, IOT_TASKPOOL_STATUS_UNDEFINED } +/** @brief Initializer for a #IotTaskPoolJob_t. */ +#define IOT_TASKPOOL_JOB_INITIALIZER NULL +/* @[define_taskpool_initializers] */ + +/** + * @brief Flag for scheduling a job to execute immediately, even if the maximum number of threads in the + * task pool was reached already. + * + * @warning This flag may cause the task pool to create a worker to serve the job immediately, and + * therefore using this flag may incur in additional memory usage and potentially fail scheduling the job. + */ +#define IOT_TASKPOOL_JOB_HIGH_PRIORITY ( ( uint32_t ) 0x00000001 ) + +/** + * @brief Allows the use of the handle to the system task pool. + * + * @warning The task pool handle is not valid unless @ref IotTaskPool_CreateSystemTaskPool is + * called before the handle is used. + */ +#define IOT_SYSTEM_TASKPOOL ( IotTaskPool_GetSystemTaskPool() ) + +#endif /* ifndef IOT_TASKPOOL_TYPES_H_ */ diff --git a/FreeRTOS-Plus/Source/FreeRTOS-Plus-IoT-SDK/c_sdk/standard/common/taskpool/iot_taskpool.c b/FreeRTOS-Plus/Source/FreeRTOS-Plus-IoT-SDK/c_sdk/standard/common/taskpool/iot_taskpool.c new file mode 100644 index 000000000..214bffb0e --- /dev/null +++ b/FreeRTOS-Plus/Source/FreeRTOS-Plus-IoT-SDK/c_sdk/standard/common/taskpool/iot_taskpool.c @@ -0,0 +1,1497 @@ +/* + * Amazon FreeRTOS Common V1.0.0 + * Copyright (C) 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to + * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of + * the Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * http://aws.amazon.com/freertos + * http://www.FreeRTOS.org + */ +/** + * @file iot_taskpool.c + * @brief Implements the task pool functions in iot_taskpool.h + */ + +/* The config header is always included first. */ +#include "iot_config.h" + +/* Standard includes. */ +#include +#include +#include +#include + +/* Platform layer includes. */ +#include "platform/iot_threads.h" +#include "platform/iot_clock.h" + +/* Task pool internal include. */ +#include "private/iot_taskpool_internal.h" + +/** + * @brief Enter a critical section by disabling interrupts. + * + */ +#define TASKPOOL_ENTER_CRITICAL() taskENTER_CRITICAL() + +/** + * @brief Enter a critical section by disabling interrupts. + * + */ +#define TASKPOOL_ENTER_CRITICAL_FROM_ISR() taskENTER_CRITICAL_FROM_ISR() + +/** + * @brief Exit a critical section by re-enabling interrupts. + * + */ +#define TASKPOOL_EXIT_CRITICAL() taskEXIT_CRITICAL() + +/** + * @brief Exit a critical section by re-enabling interrupts. + * + */ +#define TASKPOOL_EXIT_CRITICAL_FROM_ISR( x ) taskEXIT_CRITICAL_FROM_ISR( x ) + +/** + * @brief Maximum semaphore value for wait operations. + */ +#define TASKPOOL_MAX_SEM_VALUE 0xFFFF + +/** + * @brief Reschedule delay in milliseconds for deferred jobs. + */ +#define TASKPOOL_JOB_RESCHEDULE_DELAY_MS ( 10ULL ) + +/* ---------------------------------------------------------------------------------- */ + +/** + * Doxygen should ignore this section. + * + * @brief The system task pool handle for all libraries to use. + * User application can use the system task pool as well knowing that the usage will be shared with + * the system libraries as well. The system task pool needs to be initialized before any library is used or + * before any code that posts jobs to the task pool runs. + */ +_taskPool_t _IotSystemTaskPool = { .dispatchQueue = IOT_DEQUEUE_INITIALIZER }; + +/* -------------- Convenience functions to create/recycle/destroy jobs -------------- */ + +/** + * @brief Initializes one instance of a Task pool cache. + * + * @param[in] pCache The pre-allocated instance of the cache to initialize. + */ +static void _initJobsCache( _taskPoolCache_t * const pCache ); + +/** + * @brief Initialize a job. + * + * @param[in] pJob The job to initialize. + * @param[in] userCallback The user callback for the job. + * @param[in] pUserContext The context tp be passed to the callback. + * @param[in] isStatic A flag to indicate whether the job is statically or synamically allocated. + */ +static void _initializeJob( _taskPoolJob_t * const pJob, + IotTaskPoolRoutine_t userCallback, + void * pUserContext, + bool isStatic ); + +/** + * @brief Extracts and initializes one instance of a job from the cache or, if there is none available, it allocates and initialized a new one. + * + * @param[in] pCache The instance of the cache to extract the job from. + */ +static _taskPoolJob_t * _fetchOrAllocateJob( _taskPoolCache_t * const pCache ); + +/** + * Recycles one instance of a job into the cache or, if the cache is full, it destroys it. + * + * @param[in] pCache The instance of the cache to recycle the job into. + * @param[in] pJob The job to recycle. + * + */ +static void _recycleJob( _taskPoolCache_t * const pCache, + _taskPoolJob_t * const pJob ); + +/** + * Destroys one instance of a job. + * + * @param[in] pJob The job to destroy. + * + */ +static void _destroyJob( _taskPoolJob_t * const pJob ); + +/* -------------- The worker thread procedure for a task pool thread -------------- */ + +/** + * The procedure for a task pool worker thread. + * + * @param[in] pUserContext The user context. + * + */ +static void _taskPoolWorker( void * pUserContext ); + +/* -------------- Convenience functions to handle timer events -------------- */ + +/** + * Comparer for the time list. + * + * param[in] pTimerEventLink1 The link to the first timer event. + * param[in] pTimerEventLink1 The link to the first timer event. + */ +static int32_t _timerEventCompare( const IotLink_t * const pTimerEventLink1, + const IotLink_t * const pTimerEventLink2 ); + +/** + * Reschedules the timer for handling deferred jobs to the next timeout. + * + * param[in] timer The timer to reschedule. + * param[in] pFirstTimerEvent The timer event that carries the timeout and job inforamtion. + */ +static void _rescheduleDeferredJobsTimer( TimerHandle_t const timer, + _taskPoolTimerEvent_t * const pFirstTimerEvent ); + +/** + * The task pool timer procedure for scheduling deferred jobs. + * + * param[in] timer The timer to handle. + */ +static void _timerThread( TimerHandle_t xTimer ); + +/* -------------- Convenience functions to create/initialize/destroy the task pool -------------- */ + +/** + * Parameter validation for a task pool initialization. + * + * @param[in] pInfo The initialization information for the task pool. + * + */ +static IotTaskPoolError_t _performTaskPoolParameterValidation( const IotTaskPoolInfo_t * const pInfo ); + +/** + * Initializes a pre-allocated instance of a task pool. + * + * @param[in] pInfo The initialization information for the task pool. + * @param[in] pTaskPool The pre-allocated instance of the task pool to initialize. + * + */ +static IotTaskPoolError_t _initTaskPoolControlStructures( const IotTaskPoolInfo_t * const pInfo, + _taskPool_t * const pTaskPool ); + +/** + * Initializes a pre-allocated instance of a task pool. + * + * @param[in] pInfo The initialization information for the task pool. + * @param[out] pTaskPool A pointer to the task pool data structure to initialize. + * + */ +static IotTaskPoolError_t _createTaskPool( const IotTaskPoolInfo_t * const pInfo, + _taskPool_t * const pTaskPool ); + +/** + * Destroys one instance of a task pool. + * + * @param[in] pTaskPool The task pool to destroy. + * + */ +static void _destroyTaskPool( _taskPool_t * const pTaskPool ); + +/** + * Check for the exit condition. + * + * @param[in] pTaskPool The task pool to destroy. + * + */ +static bool _IsShutdownStarted( const _taskPool_t * const pTaskPool ); + +/** + * Set the exit condition. + * + * @param[in] pTaskPool The task pool to destroy. + * @param[in] threads The number of threads active in the task pool at shutdown time. + * + */ +static void _signalShutdown( _taskPool_t * const pTaskPool, + uint32_t threads ); + +/** + * Places a job in the dispatch queue. + * + * @param[in] pTaskPool The task pool to scheduel the job with. + * @param[in] pJob The job to schedule. + * @param[in] flags The job flags. + * + */ +static IotTaskPoolError_t _scheduleInternal( _taskPool_t * const pTaskPool, + _taskPoolJob_t * const pJob, + uint32_t flags ); + +/** + * Matches a deferred job in the timer queue with its timer event wrapper. + * + * @param[in] pLink A pointer to the timer event link in the timer queue. + * @param[in] pMatch A pointer to the job to match. + * + */ +static bool _matchJobByPointer( const IotLink_t * const pLink, + void * pMatch ); + +/** + * Tries to cancel a job. + * + * @param[in] pTaskPool The task pool to cancel an operation against. + * @param[in] pJob The job to cancel. + * @param[out] pStatus The status of the job at the time of cancellation. + * + */ +static IotTaskPoolError_t _tryCancelInternal( _taskPool_t * const pTaskPool, + _taskPoolJob_t * const pJob, + IotTaskPoolJobStatus_t * const pStatus ); + +/* ---------------------------------------------------------------------------------------------- */ + +IotTaskPool_t IotTaskPool_GetSystemTaskPool( void ) +{ + return &_IotSystemTaskPool; +} + +/*-----------------------------------------------------------*/ + +IotTaskPoolError_t IotTaskPool_CreateSystemTaskPool( const IotTaskPoolInfo_t * const pInfo ) +{ + TASKPOOL_FUNCTION_ENTRY( IOT_TASKPOOL_SUCCESS ); + + /* Parameter checking. */ + TASKPOOL_ON_ERROR_GOTO_CLEANUP( _performTaskPoolParameterValidation( pInfo ) ); + + /* Create the system task pool pool. */ + TASKPOOL_SET_AND_GOTO_CLEANUP( _createTaskPool( pInfo, &_IotSystemTaskPool ) ); + + TASKPOOL_NO_FUNCTION_CLEANUP(); +} + +/*-----------------------------------------------------------*/ + +IotTaskPoolError_t IotTaskPool_Create( const IotTaskPoolInfo_t * const pInfo, + IotTaskPool_t * const pTaskPool ) +{ + TASKPOOL_FUNCTION_ENTRY( IOT_TASKPOOL_SUCCESS ); + + _taskPool_t * pTempTaskPool = NULL; + + /* Verify that the task pool storage is valid. */ + TASKPOOL_ON_NULL_ARG_GOTO_CLEANUP( pTaskPool ); + + /* Parameter checking. */ + TASKPOOL_ON_ERROR_GOTO_CLEANUP( _performTaskPoolParameterValidation( pInfo ) ); + + /* Allocate the memory for the task pool */ + pTempTaskPool = ( _taskPool_t * ) IotTaskPool_MallocTaskPool( sizeof( _taskPool_t ) ); + + if( pTempTaskPool == NULL ) + { + TASKPOOL_SET_AND_GOTO_CLEANUP( IOT_TASKPOOL_NO_MEMORY ); + } + + memset( pTempTaskPool, 0x00, sizeof( _taskPool_t ) ); + + TASKPOOL_SET_AND_GOTO_CLEANUP( _createTaskPool( pInfo, pTempTaskPool ) ); + + TASKPOOL_FUNCTION_CLEANUP(); + + if( TASKPOOL_FAILED( status ) ) + { + if( pTempTaskPool != NULL ) + { + IotTaskPool_FreeTaskPool( pTempTaskPool ); + } + } + else + { + *pTaskPool = pTempTaskPool; + } + + TASKPOOL_FUNCTION_CLEANUP_END(); +} + +/*-----------------------------------------------------------*/ + +IotTaskPoolError_t IotTaskPool_Destroy( IotTaskPool_t taskPoolHandle ) +{ + TASKPOOL_FUNCTION_ENTRY( IOT_TASKPOOL_SUCCESS ); + + uint32_t count; + bool completeShutdown = true; + + _taskPool_t * pTaskPool = ( _taskPool_t * ) taskPoolHandle; + + /* Track how many threads the task pool owns. */ + uint32_t activeThreads; + + /* Parameter checking. */ + TASKPOOL_ON_NULL_ARG_GOTO_CLEANUP( pTaskPool ); + + /* Destroying the task pool should be safe, and therefore we will grab the task pool lock. + * No worker thread or application thread should access any data structure + * in the task pool while the task pool is being destroyed. */ + TASKPOOL_ENTER_CRITICAL(); + { + IotLink_t * pItemLink; + + /* Record how many active threads in the task pool. */ + activeThreads = pTaskPool->activeThreads; + + /* Destroying a Task pool happens in six (6) stages: First, (1) we clear the job queue and (2) the timer queue. + * Then (3) we clear the jobs cache. We will then (4) wait for all worker threads to signal exit, + * before (5) setting the exit condition and wake up all active worker threads. Finally (6) destroying + * all task pool data structures and release the associated memory. + */ + + /* (1) Clear the job queue. */ + do + { + pItemLink = NULL; + + pItemLink = IotDeQueue_DequeueHead( &pTaskPool->dispatchQueue ); + + if( pItemLink != NULL ) + { + _taskPoolJob_t * pJob = IotLink_Container( _taskPoolJob_t, pItemLink, link ); + + _destroyJob( pJob ); + } + } while( pItemLink ); + + /* (2) Clear the timer queue. */ + { + _taskPoolTimerEvent_t * pTimerEvent; + + /* A deferred job may have fired already. Since deferred jobs will go through the same mutex + * the shutdown sequence is holding at this stage, there is no risk for race conditions. Yet, we + * need to let the deferred job to destroy the task pool. */ + + pItemLink = IotListDouble_PeekHead( &pTaskPool->timerEventsList ); + + if( pItemLink != NULL ) + { + TickType_t now = xTaskGetTickCount(); + + pTimerEvent = IotLink_Container( _taskPoolTimerEvent_t, pItemLink, link ); + + if( pTimerEvent->expirationTime <= now ) + { + IotLogDebug( "Shutdown will be deferred to the timer thread" ); + + /* Timer may have fired already! Let the timer thread destroy + * complete the taskpool destruction sequence. */ + completeShutdown = false; + } + + /* Remove all timers from the timeout list. */ + for( ; ; ) + { + pItemLink = IotListDouble_RemoveHead( &pTaskPool->timerEventsList ); + + if( pItemLink == NULL ) + { + break; + } + + pTimerEvent = IotLink_Container( _taskPoolTimerEvent_t, pItemLink, link ); + + _destroyJob( pTimerEvent->job ); + + IotTaskPool_FreeTimerEvent( pTimerEvent ); + } + } + } + + /* (3) Clear the job cache. */ + do + { + pItemLink = NULL; + + pItemLink = IotListDouble_RemoveHead( &pTaskPool->jobsCache.freeList ); + + if( pItemLink != NULL ) + { + _taskPoolJob_t * pJob = IotLink_Container( _taskPoolJob_t, pItemLink, link ); + + _destroyJob( pJob ); + } + } while( pItemLink ); + + /* (4) Set the exit condition. */ + _signalShutdown( pTaskPool, activeThreads ); + } + TASKPOOL_EXIT_CRITICAL(); + + /* (5) Wait for all active threads to reach the end of their life-span. */ + for( count = 0; count < activeThreads; ++count ) + { + xSemaphoreTake( pTaskPool->startStopSignal, portMAX_DELAY ); + } + + IotTaskPool_Assert( uxSemaphoreGetCount( pTaskPool->startStopSignal ) == 0 ); + IotTaskPool_Assert( pTaskPool->activeThreads == 0 ); + + /* (6) Destroy all signaling objects. */ + if( completeShutdown == true ) + { + _destroyTaskPool( pTaskPool ); + + /* Do not free the system task pool which is statically allocated. */ + if( pTaskPool != &_IotSystemTaskPool ) + { + IotTaskPool_FreeTaskPool( pTaskPool ); + } + } + + TASKPOOL_NO_FUNCTION_CLEANUP(); +} + +/*-----------------------------------------------------------*/ + +IotTaskPoolError_t IotTaskPool_SetMaxThreads( IotTaskPool_t taskPoolHandle, + uint32_t maxThreads ) +{ + TASKPOOL_FUNCTION_ENTRY( IOT_TASKPOOL_SUCCESS ); + + _taskPool_t * pTaskPool = ( _taskPool_t * ) taskPoolHandle; + + /* Parameter checking. */ + TASKPOOL_ON_NULL_ARG_GOTO_CLEANUP( pTaskPool ); + TASKPOOL_ON_ARG_ERROR_GOTO_CLEANUP( maxThreads < 1UL ); + + TASKPOOL_NO_FUNCTION_CLEANUP(); +} + +/*-----------------------------------------------------------*/ + +IotTaskPoolError_t IotTaskPool_CreateJob( IotTaskPoolRoutine_t userCallback, + void * pUserContext, + IotTaskPoolJobStorage_t * const pJobStorage, + IotTaskPoolJob_t * const ppJob ) +{ + TASKPOOL_FUNCTION_ENTRY( IOT_TASKPOOL_SUCCESS ); + + /* Parameter checking. */ + TASKPOOL_ON_NULL_ARG_GOTO_CLEANUP( userCallback ); + TASKPOOL_ON_NULL_ARG_GOTO_CLEANUP( pJobStorage ); + TASKPOOL_ON_NULL_ARG_GOTO_CLEANUP( ppJob ); + + /* Build a job around the user-provided storage. */ + _initializeJob( ( _taskPoolJob_t * ) pJobStorage, userCallback, pUserContext, true ); + + *ppJob = ( IotTaskPoolJob_t ) pJobStorage; + + TASKPOOL_NO_FUNCTION_CLEANUP(); +} + +/*-----------------------------------------------------------*/ + +IotTaskPoolError_t IotTaskPool_CreateRecyclableJob( IotTaskPool_t taskPoolHandle, + IotTaskPoolRoutine_t userCallback, + void * pUserContext, + IotTaskPoolJob_t * const ppJob ) +{ + TASKPOOL_FUNCTION_ENTRY( IOT_TASKPOOL_SUCCESS ); + + _taskPool_t * pTaskPool = ( _taskPool_t * ) taskPoolHandle; + _taskPoolJob_t * pTempJob = NULL; + + /* Parameter checking. */ + TASKPOOL_ON_NULL_ARG_GOTO_CLEANUP( taskPoolHandle ); + TASKPOOL_ON_NULL_ARG_GOTO_CLEANUP( userCallback ); + TASKPOOL_ON_NULL_ARG_GOTO_CLEANUP( ppJob ); + + TASKPOOL_ENTER_CRITICAL(); + { + /* Bail out early if this task pool is shutting down. */ + pTempJob = _fetchOrAllocateJob( &pTaskPool->jobsCache ); + } + TASKPOOL_EXIT_CRITICAL(); + + if( pTempJob == NULL ) + { + IotLogInfo( "Failed to allocate a job." ); + + TASKPOOL_SET_AND_GOTO_CLEANUP( IOT_TASKPOOL_NO_MEMORY ); + } + + _initializeJob( pTempJob, userCallback, pUserContext, false ); + + *ppJob = pTempJob; + + TASKPOOL_NO_FUNCTION_CLEANUP(); +} + +/*-----------------------------------------------------------*/ + +IotTaskPoolError_t IotTaskPool_DestroyRecyclableJob( IotTaskPool_t taskPoolHandle, + IotTaskPoolJob_t pJobHandle ) +{ + TASKPOOL_FUNCTION_ENTRY( IOT_TASKPOOL_SUCCESS ); + + _taskPool_t * pTaskPool = ( _taskPool_t * ) taskPoolHandle; + _taskPoolJob_t * pJob = ( _taskPoolJob_t * ) pJobHandle; + + /* Parameter checking. */ + TASKPOOL_ON_NULL_ARG_GOTO_CLEANUP( taskPoolHandle ); + TASKPOOL_ON_NULL_ARG_GOTO_CLEANUP( pJobHandle ); + + IotTaskPool_Assert( IotLink_IsLinked( &pJob->link ) == false ); + + _destroyJob( pJob ); + + TASKPOOL_NO_FUNCTION_CLEANUP(); +} + +/*-----------------------------------------------------------*/ + +IotTaskPoolError_t IotTaskPool_RecycleJob( IotTaskPool_t taskPoolHandle, + IotTaskPoolJob_t pJob ) +{ + TASKPOOL_FUNCTION_ENTRY( IOT_TASKPOOL_SUCCESS ); + + _taskPool_t * pTaskPool = ( _taskPool_t * ) taskPoolHandle; + + /* Parameter checking. */ + TASKPOOL_ON_NULL_ARG_GOTO_CLEANUP( taskPoolHandle ); + TASKPOOL_ON_NULL_ARG_GOTO_CLEANUP( pJob ); + + TASKPOOL_ENTER_CRITICAL(); + { + IotTaskPool_Assert( IotLink_IsLinked( &pJob->link ) == false ); + + _recycleJob( &pTaskPool->jobsCache, pJob ); + } + TASKPOOL_EXIT_CRITICAL(); + + TASKPOOL_NO_FUNCTION_CLEANUP(); +} + +/*-----------------------------------------------------------*/ + +IotTaskPoolError_t IotTaskPool_Schedule( IotTaskPool_t taskPoolHandle, + IotTaskPoolJob_t pJob, + uint32_t flags ) +{ + TASKPOOL_FUNCTION_ENTRY( IOT_TASKPOOL_SUCCESS ); + + _taskPool_t * pTaskPool = ( _taskPool_t * ) taskPoolHandle; + + /* Parameter checking. */ + TASKPOOL_ON_NULL_ARG_GOTO_CLEANUP( taskPoolHandle ); + TASKPOOL_ON_NULL_ARG_GOTO_CLEANUP( pJob ); + TASKPOOL_ON_ARG_ERROR_GOTO_CLEANUP( ( flags != 0UL ) && ( flags != IOT_TASKPOOL_JOB_HIGH_PRIORITY ) ); + + TASKPOOL_ENTER_CRITICAL(); + { + _scheduleInternal( pTaskPool, pJob, flags ); + } + TASKPOOL_EXIT_CRITICAL(); + + TASKPOOL_NO_FUNCTION_CLEANUP(); +} + +/*-----------------------------------------------------------*/ + +IotTaskPoolError_t IotTaskPool_ScheduleDeferred( IotTaskPool_t taskPoolHandle, + IotTaskPoolJob_t job, + uint32_t timeMs ) +{ + TASKPOOL_FUNCTION_ENTRY( IOT_TASKPOOL_SUCCESS ); + + _taskPool_t * pTaskPool = ( _taskPool_t * ) taskPoolHandle; + + /* Parameter checking. */ + TASKPOOL_ON_NULL_ARG_GOTO_CLEANUP( taskPoolHandle ); + TASKPOOL_ON_NULL_ARG_GOTO_CLEANUP( job ); + + if( timeMs == 0UL ) + { + TASKPOOL_SET_AND_GOTO_CLEANUP( IotTaskPool_Schedule( pTaskPool, job, 0 ) ); + } + + TASKPOOL_ENTER_CRITICAL(); + { + _taskPoolTimerEvent_t * pTimerEvent = IotTaskPool_MallocTimerEvent( sizeof( _taskPoolTimerEvent_t ) ); + + if( pTimerEvent == NULL ) + { + TASKPOOL_EXIT_CRITICAL(); + + TASKPOOL_SET_AND_GOTO_CLEANUP( IOT_TASKPOOL_NO_MEMORY ); + } + + IotLink_t * pTimerEventLink; + + TickType_t now = xTaskGetTickCount(); + + pTimerEvent->link.pNext = NULL; + pTimerEvent->link.pPrevious = NULL; + pTimerEvent->expirationTime = now + pdMS_TO_TICKS( timeMs ); + pTimerEvent->job = job; + + /* Append the timer event to the timer list. */ + IotListDouble_InsertSorted( &pTaskPool->timerEventsList, &pTimerEvent->link, _timerEventCompare ); + + /* Update the job status to 'scheduled'. */ + job->status = IOT_TASKPOOL_STATUS_DEFERRED; + + /* Peek the first event in the timer event list. There must be at least one, + * since we just inserted it. */ + pTimerEventLink = IotListDouble_PeekHead( &pTaskPool->timerEventsList ); + IotTaskPool_Assert( pTimerEventLink != NULL ); + + /* If the event we inserted is at the front of the queue, then + * we need to reschedule the underlying timer. */ + if( pTimerEventLink == &pTimerEvent->link ) + { + pTimerEvent = IotLink_Container( _taskPoolTimerEvent_t, pTimerEventLink, link ); + + _rescheduleDeferredJobsTimer( pTaskPool->timer, pTimerEvent ); + } + } + TASKPOOL_EXIT_CRITICAL(); + + TASKPOOL_NO_FUNCTION_CLEANUP(); +} + +/*-----------------------------------------------------------*/ + +IotTaskPoolError_t IotTaskPool_GetStatus( IotTaskPool_t taskPoolHandle, + IotTaskPoolJob_t job, + IotTaskPoolJobStatus_t * const pStatus ) +{ + TASKPOOL_FUNCTION_ENTRY( IOT_TASKPOOL_SUCCESS ); + + _taskPool_t * pTaskPool = ( _taskPool_t * ) taskPoolHandle; + + /* Parameter checking. */ + TASKPOOL_ON_NULL_ARG_GOTO_CLEANUP( taskPoolHandle ); + TASKPOOL_ON_NULL_ARG_GOTO_CLEANUP( job ); + TASKPOOL_ON_NULL_ARG_GOTO_CLEANUP( pStatus ); + *pStatus = IOT_TASKPOOL_STATUS_UNDEFINED; + + TASKPOOL_ENTER_CRITICAL(); + { + *pStatus = job->status; + } + TASKPOOL_EXIT_CRITICAL(); + + TASKPOOL_NO_FUNCTION_CLEANUP(); +} + +/*-----------------------------------------------------------*/ + +IotTaskPoolError_t IotTaskPool_TryCancel( IotTaskPool_t taskPoolHandle, + IotTaskPoolJob_t job, + IotTaskPoolJobStatus_t * const pStatus ) +{ + TASKPOOL_FUNCTION_ENTRY( IOT_TASKPOOL_SUCCESS ); + + _taskPool_t * pTaskPool = ( _taskPool_t * ) taskPoolHandle; + + /* Parameter checking. */ + TASKPOOL_ON_NULL_ARG_GOTO_CLEANUP( taskPoolHandle ); + TASKPOOL_ON_NULL_ARG_GOTO_CLEANUP( job ); + + if( pStatus != NULL ) + { + *pStatus = IOT_TASKPOOL_STATUS_UNDEFINED; + } + + TASKPOOL_ENTER_CRITICAL(); + { + status = _tryCancelInternal( pTaskPool, job, pStatus ); + } + TASKPOOL_EXIT_CRITICAL(); + + TASKPOOL_NO_FUNCTION_CLEANUP(); +} + +/*-----------------------------------------------------------*/ + +IotTaskPoolJobStorage_t * IotTaskPool_GetJobStorageFromHandle( IotTaskPoolJob_t pJob ) +{ + return ( IotTaskPoolJobStorage_t * ) pJob; +} + +/*-----------------------------------------------------------*/ + +const char * IotTaskPool_strerror( IotTaskPoolError_t status ) +{ + const char * pMessage = NULL; + + switch( status ) + { + case IOT_TASKPOOL_SUCCESS: + pMessage = "SUCCESS"; + break; + + case IOT_TASKPOOL_BAD_PARAMETER: + pMessage = "BAD PARAMETER"; + break; + + case IOT_TASKPOOL_ILLEGAL_OPERATION: + pMessage = "ILLEGAL OPERATION"; + break; + + case IOT_TASKPOOL_NO_MEMORY: + pMessage = "NO MEMORY"; + break; + + case IOT_TASKPOOL_SHUTDOWN_IN_PROGRESS: + pMessage = "SHUTDOWN IN PROGRESS"; + break; + + case IOT_TASKPOOL_CANCEL_FAILED: + pMessage = "CANCEL FAILED"; + break; + + default: + pMessage = "INVALID STATUS"; + break; + } + + return pMessage; +} + +/* ---------------------------------------------------------------------------------------------- */ +/* ---------------------------------------------------------------------------------------------- */ +/* ---------------------------------------------------------------------------------------------- */ + +static IotTaskPoolError_t _performTaskPoolParameterValidation( const IotTaskPoolInfo_t * const pInfo ) +{ + TASKPOOL_FUNCTION_ENTRY( IOT_TASKPOOL_SUCCESS ); + + /* Check input values for consistency. */ + TASKPOOL_ON_NULL_ARG_GOTO_CLEANUP( pInfo ); + TASKPOOL_ON_ARG_ERROR_GOTO_CLEANUP( pInfo->minThreads > pInfo->maxThreads ); + TASKPOOL_ON_ARG_ERROR_GOTO_CLEANUP( pInfo->minThreads < 1UL ); + TASKPOOL_ON_ARG_ERROR_GOTO_CLEANUP( pInfo->maxThreads < 1UL ); + + TASKPOOL_NO_FUNCTION_CLEANUP(); +} + +static IotTaskPoolError_t _initTaskPoolControlStructures( const IotTaskPoolInfo_t * const pInfo, + _taskPool_t * const pTaskPool ) +{ + TASKPOOL_FUNCTION_ENTRY( IOT_TASKPOOL_SUCCESS ); + + bool semStartStopInit = false; + bool semDispatchInit = false; + + /* Initialize a job data structures that require no de-initialization. + * All other data structures carry a value of 'NULL' before initailization. + */ + IotDeQueue_Create( &pTaskPool->dispatchQueue ); + IotListDouble_Create( &pTaskPool->timerEventsList ); + + _initJobsCache( &pTaskPool->jobsCache ); + + /* Initialize the semaphore to ensure all threads have started. */ + pTaskPool->startStopSignal = xSemaphoreCreateCountingStatic( pInfo->minThreads, 0, &pTaskPool->startStopSignalBuffer ); + + if( pTaskPool->startStopSignal != NULL ) + { + semStartStopInit = true; + + /* Initialize the semaphore for waiting for incoming work. */ + pTaskPool->dispatchSignal = xSemaphoreCreateCountingStatic( TASKPOOL_MAX_SEM_VALUE, 0, &pTaskPool->dispatchSignalBuffer ); + + if( pTaskPool->dispatchSignal != NULL ) + { + semDispatchInit = true; + } + else + { + TASKPOOL_SET_AND_GOTO_CLEANUP( IOT_TASKPOOL_NO_MEMORY ); + } + } + else + { + TASKPOOL_SET_AND_GOTO_CLEANUP( IOT_TASKPOOL_NO_MEMORY ); + } + + TASKPOOL_FUNCTION_CLEANUP(); + + if( TASKPOOL_FAILED( status ) ) + { + if( semStartStopInit ) + { + vSemaphoreDelete( &pTaskPool->startStopSignal ); + } + + if( semDispatchInit ) + { + vSemaphoreDelete( &pTaskPool->dispatchSignal ); + } + } + + TASKPOOL_FUNCTION_CLEANUP_END(); +} + +static IotTaskPoolError_t _createTaskPool( const IotTaskPoolInfo_t * const pInfo, + _taskPool_t * const pTaskPool ) +{ + TASKPOOL_FUNCTION_ENTRY( IOT_TASKPOOL_SUCCESS ); + + uint32_t count; + uint32_t threadsCreated = 0; + + /* Check input values for consistency. */ + TASKPOOL_ON_NULL_ARG_GOTO_CLEANUP( pTaskPool ); + + /* Zero out all data structures. */ + memset( ( void * ) pTaskPool, 0x00, sizeof( _taskPool_t ) ); + + /* Initialize all internal data structure prior to creating all threads. */ + TASKPOOL_ON_ERROR_GOTO_CLEANUP( _initTaskPoolControlStructures( pInfo, pTaskPool ) ); + + /* Create the timer mutex for a new connection. */ + pTaskPool->timer = xTimerCreate( NULL, portMAX_DELAY, pdFALSE, ( void * ) pTaskPool, _timerThread ); + + if( pTaskPool->timer == NULL ) + { + IotLogError( "Failed to create timer for task pool." ); + + TASKPOOL_SET_AND_GOTO_CLEANUP( IOT_TASKPOOL_NO_MEMORY ); + } + + /* The task pool will initialize the minimum number of threads reqeusted by the user upon start. */ + /* When a thread is created, it will signal a semaphore to signify that it is about to wait on incoming */ + /* jobs. A thread can be woken up for exit or for new jobs only at that point in time. */ + /* The exit condition is setting the maximum number of threads to 0. */ + + /* Create the minimum number of threads specified by the user, and if one fails shutdown and return error. */ + for( ; threadsCreated < pInfo->minThreads; ) + { + TaskHandle_t task = NULL; + + BaseType_t res = xTaskCreate( _taskPoolWorker, + NULL, + pInfo->stackSize, + pTaskPool, + pInfo->priority, + &task ); + + /* Create one thread. */ + if( res == pdFALSE ) + { + IotLogError( "Could not create worker thread! Exiting..." ); + + /* If creating one thread fails, set error condition and exit the loop. */ + TASKPOOL_SET_AND_GOTO_CLEANUP( IOT_TASKPOOL_NO_MEMORY ); + } + + /* Upon successful thread creation, increase the number of active threads. */ + pTaskPool->activeThreads++; + IotTaskPool_Assert( task != NULL ); + + ++threadsCreated; + } + + TASKPOOL_FUNCTION_CLEANUP(); + + /* Wait for threads to be ready to wait on the condition, so that threads are actually able to receive messages. */ + for( count = 0; count < threadsCreated; ++count ) + { + xSemaphoreTake( pTaskPool->startStopSignal, portMAX_DELAY ); + } + + /* In case of failure, wait on the created threads to exit. */ + if( TASKPOOL_FAILED( status ) ) + { + /* Set the exit condition for the newly created threads. */ + _signalShutdown( pTaskPool, threadsCreated ); + + /* Signal all threads to exit. */ + for( count = 0; count < threadsCreated; ++count ) + { + xSemaphoreTake( pTaskPool->startStopSignal, portMAX_DELAY ); + } + + _destroyTaskPool( pTaskPool ); + } + + pTaskPool->running = true; + + TASKPOOL_FUNCTION_CLEANUP_END(); +} + +/*-----------------------------------------------------------*/ + +static void _destroyTaskPool( _taskPool_t * const pTaskPool ) +{ + if( pTaskPool->timer != NULL ) + { + xTimerDelete( pTaskPool->timer, 0 ); + } + + if( pTaskPool->dispatchSignal != NULL ) + { + vSemaphoreDelete( pTaskPool->dispatchSignal ); + } + + if( pTaskPool->startStopSignal != NULL ) + { + vSemaphoreDelete( pTaskPool->startStopSignal ); + } +} + +/* ---------------------------------------------------------------------------------------------- */ + +static void _taskPoolWorker( void * pUserContext ) +{ + IotTaskPool_Assert( pUserContext != NULL ); + + IotTaskPoolRoutine_t userCallback = NULL; + bool running = true; + + /* Extract pTaskPool pointer from context. */ + _taskPool_t * pTaskPool = ( _taskPool_t * ) pUserContext; + + /* Signal that this worker completed initialization and it is ready to receive notifications. */ + ( void ) xSemaphoreGive( pTaskPool->startStopSignal ); + + /* OUTER LOOP: it controls the lifetiem of the worker thread: exit condition for a worker thread + * is setting maxThreads to zero. A worker thread is running until the maximum number of allowed + * threads is not zero and the active threads are less than the maximum number of allowed threads. + */ + do + { + IotLink_t * pFirst = NULL; + _taskPoolJob_t * pJob = NULL; + + /* Wait on incoming notifications... */ + xSemaphoreTake( pTaskPool->dispatchSignal, portMAX_DELAY ); + + /* Acquire the lock to check the exit condition, and release the lock if the exit condition is verified, + * or before waiting for incoming notifications. + */ + TASKPOOL_ENTER_CRITICAL(); + { + /* If the exit condition is verified, update the number of active threads and exit the loop. */ + if( _IsShutdownStarted( pTaskPool ) ) + { + IotLogDebug( "Worker thread exiting because exit condition was set." ); + + /* Decrease the number of active threads. */ + pTaskPool->activeThreads--; + + TASKPOOL_EXIT_CRITICAL(); + + /* Signal that this worker is exiting. */ + xSemaphoreGive( pTaskPool->startStopSignal ); + + /* On shutdown, abandon the OUTER LOOP immediately. */ + break; + } + + /* Dequeue the first job in FIFO order. */ + pFirst = IotDeQueue_DequeueHead( &pTaskPool->dispatchQueue ); + + /* If there is indeed a job, then update status under lock, and release the lock before processing the job. */ + if( pFirst != NULL ) + { + /* Extract the job from its link. */ + pJob = IotLink_Container( _taskPoolJob_t, pFirst, link ); + + /* Update status to 'executing'. */ + pJob->status = IOT_TASKPOOL_STATUS_COMPLETED; + userCallback = pJob->userCallback; + } + } + TASKPOOL_EXIT_CRITICAL(); + + /* INNER LOOP: it controls the execution of jobs: the exit condition is the lack of a job to execute. */ + while( pJob != NULL ) + { + /* Process the job by invoking the associated callback with the user context. + * This task pool thread will not be available until the user callback returns. + */ + { + IotTaskPool_Assert( IotLink_IsLinked( &pJob->link ) == false ); + IotTaskPool_Assert( userCallback != NULL ); + + userCallback( pTaskPool, pJob, pJob->pUserContext ); + + /* This job is finished, clear its pointer. */ + pJob = NULL; + userCallback = NULL; + + /* If this thread exceeded the quota, then let it terminate. */ + if( running == false ) + { + /* Abandon the INNER LOOP. Execution will tranfer back to the OUTER LOOP condition. */ + break; + } + } + + /* Acquire the lock before updating the job status. */ + TASKPOOL_ENTER_CRITICAL(); + { + /* Try and dequeue the next job in the dispatch queue. */ + IotLink_t * pItem = NULL; + + /* Dequeue the next job from the dispatch queue. */ + pItem = IotDeQueue_DequeueHead( &pTaskPool->dispatchQueue ); + + /* If there is no job left in the dispatch queue, update the worker status and leave. */ + if( pItem == NULL ) + { + TASKPOOL_EXIT_CRITICAL(); + + /* Abandon the INNER LOOP. Execution will tranfer back to the OUTER LOOP condition. */ + break; + } + else + { + pJob = IotLink_Container( _taskPoolJob_t, pItem, link ); + + userCallback = pJob->userCallback; + } + + pJob->status = IOT_TASKPOOL_STATUS_COMPLETED; + } + TASKPOOL_EXIT_CRITICAL(); + } + } while( running == true ); + + vTaskDelete( NULL ); +} + +/* ---------------------------------------------------------------------------------------------- */ + +static void _initJobsCache( _taskPoolCache_t * const pCache ) +{ + IotDeQueue_Create( &pCache->freeList ); + + pCache->freeCount = 0; +} + +/*-----------------------------------------------------------*/ + +static void _initializeJob( _taskPoolJob_t * const pJob, + IotTaskPoolRoutine_t userCallback, + void * pUserContext, + bool isStatic ) +{ + pJob->link.pNext = NULL; + pJob->link.pPrevious = NULL; + pJob->userCallback = userCallback; + pJob->pUserContext = pUserContext; + + if( isStatic ) + { + pJob->flags = IOT_TASK_POOL_INTERNAL_STATIC; + pJob->status = IOT_TASKPOOL_STATUS_READY; + } + else + { + pJob->status = IOT_TASKPOOL_STATUS_READY; + } +} + +static _taskPoolJob_t * _fetchOrAllocateJob( _taskPoolCache_t * const pCache ) +{ + _taskPoolJob_t * pJob = NULL; + IotLink_t * pLink = IotListDouble_RemoveHead( &( pCache->freeList ) ); + + if( pLink != NULL ) + { + pJob = IotLink_Container( _taskPoolJob_t, pLink, link ); + } + + /* If there is no available job in the cache, then allocate one. */ + if( pJob == NULL ) + { + pJob = ( _taskPoolJob_t * ) IotTaskPool_MallocJob( sizeof( _taskPoolJob_t ) ); + + if( pJob != NULL ) + { + memset( pJob, 0x00, sizeof( _taskPoolJob_t ) ); + } + else + { + /* Log alocation failure for troubleshooting purposes. */ + IotLogInfo( "Failed to allocate job." ); + } + } + /* If there was a job in the cache, then make sure we keep the counters up-to-date. */ + else + { + IotTaskPool_Assert( pCache->freeCount > 0 ); + + pCache->freeCount--; + } + + return pJob; +} + +/*-----------------------------------------------------------*/ + +static void _recycleJob( _taskPoolCache_t * const pCache, + _taskPoolJob_t * const pJob ) +{ + /* We should never try and recycling a job that is linked into some queue. */ + IotTaskPool_Assert( IotLink_IsLinked( &pJob->link ) == false ); + + /* We will recycle the job if there is space in the cache. */ + if( pCache->freeCount < IOT_TASKPOOL_JOBS_RECYCLE_LIMIT ) + { + /* Destroy user data, for added safety&security. */ + pJob->userCallback = NULL; + pJob->pUserContext = NULL; + + /* Reset the status for added debuggability. */ + pJob->status = IOT_TASKPOOL_STATUS_UNDEFINED; + + IotListDouble_InsertTail( &pCache->freeList, &pJob->link ); + + pCache->freeCount++; + + IotTaskPool_Assert( pCache->freeCount >= 1 ); + } + else + { + _destroyJob( pJob ); + } +} + +/*-----------------------------------------------------------*/ + +static void _destroyJob( _taskPoolJob_t * const pJob ) +{ + /* Destroy user data, for added safety & security. */ + pJob->userCallback = NULL; + pJob->pUserContext = NULL; + + /* Reset the status for added debuggability. */ + pJob->status = IOT_TASKPOOL_STATUS_UNDEFINED; + + /* Only dispose of dynamically allocated jobs. */ + if( ( pJob->flags & IOT_TASK_POOL_INTERNAL_STATIC ) == 0UL ) + { + IotTaskPool_FreeJob( pJob ); + } +} + +/* ---------------------------------------------------------------------------------------------- */ + +static bool _IsShutdownStarted( const _taskPool_t * const pTaskPool ) +{ + return( pTaskPool->running == false ); +} + +/*-----------------------------------------------------------*/ + +static void _signalShutdown( _taskPool_t * const pTaskPool, + uint32_t threads ) +{ + uint32_t count; + + /* Set the exit condition. */ + pTaskPool->running = false; + + /* Broadcast to all active threads to wake-up. Active threads do check the exit condition right after wakein up. */ + for( count = 0; count < threads; ++count ) + { + ( void ) xSemaphoreGive( pTaskPool->dispatchSignal ); + } +} + +/* ---------------------------------------------------------------------------------------------- */ + +static IotTaskPoolError_t _scheduleInternal( _taskPool_t * const pTaskPool, + _taskPoolJob_t * const pJob, + uint32_t flags ) +{ + TASKPOOL_FUNCTION_ENTRY( IOT_TASKPOOL_SUCCESS ); + + /* Update the job status to 'scheduled'. */ + pJob->status = IOT_TASKPOOL_STATUS_SCHEDULED; + + BaseType_t higherPriorityTaskWoken; + + /* Append the job to the dispatch queue. */ + IotDeQueue_EnqueueTail( &pTaskPool->dispatchQueue, &pJob->link ); + + /* Signal a worker to pick up the job. */ + ( void ) xSemaphoreGiveFromISR( pTaskPool->dispatchSignal, &higherPriorityTaskWoken ); + + portYIELD_FROM_ISR( higherPriorityTaskWoken ); + + TASKPOOL_NO_FUNCTION_CLEANUP_NOLABEL(); +} + +/*-----------------------------------------------------------*/ + +static bool _matchJobByPointer( const IotLink_t * const pLink, + void * pMatch ) +{ + const _taskPoolJob_t * const pJob = ( _taskPoolJob_t * ) pMatch; + + const _taskPoolTimerEvent_t * const pTimerEvent = IotLink_Container( _taskPoolTimerEvent_t, pLink, link ); + + if( pJob == pTimerEvent->job ) + { + return true; + } + + return false; +} + +/*-----------------------------------------------------------*/ + +static IotTaskPoolError_t _tryCancelInternal( _taskPool_t * const pTaskPool, + _taskPoolJob_t * const pJob, + IotTaskPoolJobStatus_t * const pStatus ) +{ + TASKPOOL_FUNCTION_ENTRY( IOT_TASKPOOL_SUCCESS ); + + bool cancelable = false; + + /* We can only cancel jobs that are either 'ready' (waiting to be scheduled). 'deferred', or 'scheduled'. */ + + IotTaskPoolJobStatus_t currentStatus = pJob->status; + + switch( currentStatus ) + { + case IOT_TASKPOOL_STATUS_READY: + case IOT_TASKPOOL_STATUS_DEFERRED: + case IOT_TASKPOOL_STATUS_SCHEDULED: + case IOT_TASKPOOL_STATUS_CANCELED: + cancelable = true; + break; + + case IOT_TASKPOOL_STATUS_COMPLETED: + /* Log mesggesong purposes. */ + IotLogWarn( "Attempt to cancel a job that is already executing, or canceled." ); + break; + + default: + /* Log mesggesong purposes. */ + IotLogError( "Attempt to cancel a job with an undefined state." ); + break; + } + + /* Update the returned status to the current status of the job. */ + if( pStatus != NULL ) + { + *pStatus = currentStatus; + } + + if( cancelable == false ) + { + TASKPOOL_SET_AND_GOTO_CLEANUP( IOT_TASKPOOL_CANCEL_FAILED ); + } + else + { + /* Update the status of the job. */ + pJob->status = IOT_TASKPOOL_STATUS_CANCELED; + + /* If the job is cancelable and its current status is 'scheduled' then unlink it from the dispatch + * queue and signal any waiting threads. */ + if( currentStatus == IOT_TASKPOOL_STATUS_SCHEDULED ) + { + /* A scheduled work items must be in the dispatch queue. */ + IotTaskPool_Assert( IotLink_IsLinked( &pJob->link ) ); + + IotDeQueue_Remove( &pJob->link ); + } + + /* If the job current status is 'deferred' then the job has to be pending + * in the timeouts queue. */ + else if( currentStatus == IOT_TASKPOOL_STATUS_DEFERRED ) + { + /* Find the timer event associated with the current job. There MUST be one, hence assert if not. */ + IotLink_t * pTimerEventLink = IotListDouble_FindFirstMatch( &pTaskPool->timerEventsList, NULL, _matchJobByPointer, pJob ); + IotTaskPool_Assert( pTimerEventLink != NULL ); + + if( pTimerEventLink != NULL ) + { + bool shouldReschedule = false; + + /* If the job being cancelled was at the head of the timeouts queue, then we need to reschedule the timer + * with the next job timeout */ + IotLink_t * pHeadLink = IotListDouble_PeekHead( &pTaskPool->timerEventsList ); + + if( pHeadLink == pTimerEventLink ) + { + shouldReschedule = true; + } + + /* Remove the timer event associated with the canceled job and free the associated memory. */ + IotListDouble_Remove( pTimerEventLink ); + IotTaskPool_FreeTimerEvent( IotLink_Container( _taskPoolTimerEvent_t, pTimerEventLink, link ) ); + + if( shouldReschedule ) + { + IotLink_t * pNextTimerEventLink = IotListDouble_PeekHead( &pTaskPool->timerEventsList ); + + if( pNextTimerEventLink != NULL ) + { + _rescheduleDeferredJobsTimer( pTaskPool->timer, IotLink_Container( _taskPoolTimerEvent_t, pNextTimerEventLink, link ) ); + } + } + } + } + else + { + /* A cancelable job status should be either 'scheduled' or 'deferrred'. */ + IotTaskPool_Assert( ( currentStatus == IOT_TASKPOOL_STATUS_READY ) || ( currentStatus == IOT_TASKPOOL_STATUS_CANCELED ) ); + } + } + + TASKPOOL_NO_FUNCTION_CLEANUP(); +} + +/*-----------------------------------------------------------*/ + +static int32_t _timerEventCompare( const IotLink_t * const pTimerEventLink1, + const IotLink_t * const pTimerEventLink2 ) +{ + const _taskPoolTimerEvent_t * const pTimerEvent1 = IotLink_Container( _taskPoolTimerEvent_t, + pTimerEventLink1, + link ); + const _taskPoolTimerEvent_t * const pTimerEvent2 = IotLink_Container( _taskPoolTimerEvent_t, + pTimerEventLink2, + link ); + + if( pTimerEvent1->expirationTime < pTimerEvent2->expirationTime ) + { + return -1; + } + + if( pTimerEvent1->expirationTime > pTimerEvent2->expirationTime ) + { + return 1; + } + + return 0; +} + +/*-----------------------------------------------------------*/ + +static void _rescheduleDeferredJobsTimer( TimerHandle_t const timer, + _taskPoolTimerEvent_t * const pFirstTimerEvent ) +{ + uint64_t delta = 0; + TickType_t now = xTaskGetTickCount(); + + if( pFirstTimerEvent->expirationTime > now ) + { + delta = pFirstTimerEvent->expirationTime - now; + } + + if( delta < TASKPOOL_JOB_RESCHEDULE_DELAY_MS ) + { + delta = TASKPOOL_JOB_RESCHEDULE_DELAY_MS; /* The job will be late... */ + } + + IotTaskPool_Assert( delta > 0 ); + + if( xTimerChangePeriod( timer, ( uint32_t ) delta, portMAX_DELAY ) == pdFAIL ) + { + IotLogWarn( "Failed to re-arm timer for task pool" ); + } +} + +/*-----------------------------------------------------------*/ + +static void _timerThread( TimerHandle_t xTimer ) +{ + _taskPool_t * pTaskPool = pvTimerGetTimerID( xTimer ); + + IotTaskPool_Assert( pTaskPool ); + + _taskPoolTimerEvent_t * pTimerEvent = NULL; + + IotLogDebug( "Timer thread started for task pool %p.", pTaskPool ); + + /* Attempt to lock the timer mutex. Return immediately if the mutex cannot be locked. + * If this mutex cannot be locked it means that another thread is manipulating the + * timeouts list, and will reset the timer to fire again, although it will be late. + */ + TASKPOOL_ENTER_CRITICAL(); + { + /* Check again for shutdown and bail out early in case. */ + if( _IsShutdownStarted( pTaskPool ) ) + { + TASKPOOL_EXIT_CRITICAL(); + + /* Complete the shutdown sequence. */ + _destroyTaskPool( pTaskPool ); + + return; + } + + /* Dispatch all deferred job whose timer expired, then reset the timer for the next + * job down the line. */ + for( ; ; ) + { + /* Peek the first event in the timer event list. */ + IotLink_t * pLink = IotListDouble_PeekHead( &pTaskPool->timerEventsList ); + + /* Check if the timer misfired for any reason. */ + if( pLink != NULL ) + { + /* Record the current time. */ + TickType_t now = xTaskGetTickCount(); + + /* Extract the job from its envelope. */ + pTimerEvent = IotLink_Container( _taskPoolTimerEvent_t, pLink, link ); + + /* Check if the first event should be processed now. */ + if( pTimerEvent->expirationTime <= now ) + { + /* Remove the timer event for immediate processing. */ + IotListDouble_Remove( &( pTimerEvent->link ) ); + } + else + { + /* The first element in the timer queue shouldn't be processed yet. + * Arm the timer for when it should be processed and leave altogether. */ + _rescheduleDeferredJobsTimer( pTaskPool->timer, pTimerEvent ); + + break; + } + } + /* If there are no timer events to process, terminate this thread. */ + else + { + IotLogDebug( "No further timer events to process. Exiting timer thread." ); + + break; + } + + IotLogDebug( "Scheduling job from timer event." ); + + /* Queue the job associated with the received timer event. */ + ( void ) _scheduleInternal( pTaskPool, pTimerEvent->job, 0 ); + + /* Free the timer event. */ + IotTaskPool_FreeTimerEvent( pTimerEvent ); + } + } + TASKPOOL_EXIT_CRITICAL(); +} diff --git a/FreeRTOS-Plus/Source/FreeRTOS-Plus-IoT-SDK/c_sdk/standard/common/taskpool/iot_taskpool_static_memory.c b/FreeRTOS-Plus/Source/FreeRTOS-Plus-IoT-SDK/c_sdk/standard/common/taskpool/iot_taskpool_static_memory.c new file mode 100644 index 000000000..8de4f6e27 --- /dev/null +++ b/FreeRTOS-Plus/Source/FreeRTOS-Plus-IoT-SDK/c_sdk/standard/common/taskpool/iot_taskpool_static_memory.c @@ -0,0 +1,175 @@ +/* + * Amazon FreeRTOS Common V1.0.0 + * Copyright (C) 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to + * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of + * the Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * http://aws.amazon.com/freertos + * http://www.FreeRTOS.org + */ + +/** + * @file iot_taskpool_static_memory.c + * @brief Implementation of task pool static memory functions. + */ + +/* The config header is always included first. */ +#include "iot_config.h" + +/* This file should only be compiled if dynamic memory allocation is forbidden. */ +#if IOT_STATIC_MEMORY_ONLY == 1 + +/* Standard includes. */ +#include +#include +#include + +/* Static memory include. */ +#include "private/iot_static_memory.h" + +/* Task pool internal include. */ +#include "private/iot_taskpool_internal.h" + +/*-----------------------------------------------------------*/ + +/* Validate static memory configuration settings. */ +#if IOT_TASKPOOL_JOBS_RECYCLE_LIMIT <= 0 + #error "IOT_TASKPOOL_JOBS_RECYCLE_LIMIT cannot be 0 or negative." +#endif + +/*-----------------------------------------------------------*/ + +/* + * Static memory buffers and flags, allocated and zeroed at compile-time. + */ +static bool _pInUseTaskPools[ IOT_TASKPOOLS ] = { 0 }; /**< @brief Task pools in-use flags. */ +static _taskPool_t _pTaskPools[ IOT_TASKPOOLS ] = { { .dispatchQueue = IOT_DEQUEUE_INITIALIZER } }; /**< @brief Task pools. */ + +static bool _pInUseTaskPoolJobs[ IOT_TASKPOOL_JOBS_RECYCLE_LIMIT ] = { 0 }; /**< @brief Task pool jobs in-use flags. */ +static _taskPoolJob_t _pTaskPoolJobs[ IOT_TASKPOOL_JOBS_RECYCLE_LIMIT ] = { { .link = IOT_LINK_INITIALIZER } }; /**< @brief Task pool jobs. */ + +static bool _pInUseTaskPoolTimerEvents[ IOT_TASKPOOL_JOBS_RECYCLE_LIMIT ] = { 0 }; /**< @brief Task pool timer event in-use flags. */ +static _taskPoolTimerEvent_t _pTaskPoolTimerEvents[ IOT_TASKPOOL_JOBS_RECYCLE_LIMIT ] = { { .link = { 0 } } }; /**< @brief Task pool timer events. */ + +/*-----------------------------------------------------------*/ + +void * IotTaskPool_MallocTaskPool( size_t size ) +{ + int freeIndex = -1; + void * pNewTaskPool = NULL; + + /* Check size argument. */ + if( size == sizeof( _taskPool_t ) ) + { + /* Find a free task pool job. */ + freeIndex = IotStaticMemory_FindFree( _pInUseTaskPools, IOT_TASKPOOLS ); + + if( freeIndex != -1 ) + { + pNewTaskPool = &( _pTaskPools[ freeIndex ] ); + } + } + + return pNewTaskPool; +} + +/*-----------------------------------------------------------*/ + +void IotTaskPool_FreeTaskPool( void * ptr ) +{ + /* Return the in-use task pool job. */ + IotStaticMemory_ReturnInUse( ptr, + _pTaskPools, + _pInUseTaskPools, + IOT_TASKPOOLS, + sizeof( _taskPool_t ) ); +} + +/*-----------------------------------------------------------*/ + +void * IotTaskPool_MallocJob( size_t size ) +{ + int32_t freeIndex = -1; + void * pNewJob = NULL; + + /* Check size argument. */ + if( size == sizeof( _taskPoolJob_t ) ) + { + /* Find a free task pool job. */ + freeIndex = IotStaticMemory_FindFree( _pInUseTaskPoolJobs, + IOT_TASKPOOL_JOBS_RECYCLE_LIMIT ); + + if( freeIndex != -1 ) + { + pNewJob = &( _pTaskPoolJobs[ freeIndex ] ); + } + } + + return pNewJob; +} + +/*-----------------------------------------------------------*/ + +void IotTaskPool_FreeJob( void * ptr ) +{ + /* Return the in-use task pool job. */ + IotStaticMemory_ReturnInUse( ptr, + _pTaskPoolJobs, + _pInUseTaskPoolJobs, + IOT_TASKPOOL_JOBS_RECYCLE_LIMIT, + sizeof( _taskPoolJob_t ) ); +} + +/*-----------------------------------------------------------*/ + +void * IotTaskPool_MallocTimerEvent( size_t size ) +{ + int32_t freeIndex = -1; + void * pNewTimerEvent = NULL; + + /* Check size argument. */ + if( size == sizeof( _taskPoolTimerEvent_t ) ) + { + /* Find a free task pool timer event. */ + freeIndex = IotStaticMemory_FindFree( _pInUseTaskPoolTimerEvents, + IOT_TASKPOOL_JOBS_RECYCLE_LIMIT ); + + if( freeIndex != -1 ) + { + pNewTimerEvent = &( _pTaskPoolTimerEvents[ freeIndex ] ); + } + } + + return pNewTimerEvent; +} + +/*-----------------------------------------------------------*/ + +void IotTaskPool_FreeTimerEvent( void * ptr ) +{ + /* Return the in-use task pool timer event. */ + IotStaticMemory_ReturnInUse( ptr, + _pTaskPoolTimerEvents, + _pInUseTaskPoolTimerEvents, + IOT_TASKPOOL_JOBS_RECYCLE_LIMIT, + sizeof( _taskPoolTimerEvent_t ) ); +} + +/*-----------------------------------------------------------*/ + +#endif -- 2.39.2