Hi Joel, This looks good.
A minor nit relates to pointer checks. We have: https://docs.rtems.org/branches/master/eng/coding-conventions.html#language-and-compiler I do not know how well enforced the pointer check for NULL in `if` is? Chris On 10/8/2023 1:42 am, Joel Sherrill wrote: > Updates #4924. > > The Regulator is an application support class which is used to > deal with the scenario where there is a bursty input source > which needs to be metered out to a destination sink. The maximum > size of bursts needs to be known and the delivery method must > be configured to deliver messages at a rate that allows the > traffic to not overflow. > --- > cpukit/include/rtems/regulator.h | 499 +++++++ > cpukit/include/rtems/regulatorimpl.h | 135 ++ > cpukit/libmisc/regulator/regulator.c | 683 +++++++++ > spec/build/cpukit/librtemscpu.yml | 2 + > spec/build/cpukit/objregulator.yml | 18 + > spec/build/testsuites/libtests/grp.yml | 2 + > .../build/testsuites/libtests/regulator01.yml | 21 + > testsuites/libtests/regulator01/regulator01.c | 1310 +++++++++++++++++ > .../libtests/regulator01/regulator01.doc | 67 + > .../libtests/regulator01/rtems_config.c | 59 + > 10 files changed, 2796 insertions(+) > create mode 100644 cpukit/include/rtems/regulator.h > create mode 100644 cpukit/include/rtems/regulatorimpl.h > create mode 100644 cpukit/libmisc/regulator/regulator.c > create mode 100644 spec/build/cpukit/objregulator.yml > create mode 100644 spec/build/testsuites/libtests/regulator01.yml > create mode 100644 testsuites/libtests/regulator01/regulator01.c > create mode 100644 testsuites/libtests/regulator01/regulator01.doc > create mode 100644 testsuites/libtests/regulator01/rtems_config.c > > diff --git a/cpukit/include/rtems/regulator.h > b/cpukit/include/rtems/regulator.h > new file mode 100644 > index 0000000000..362a99f6bc > --- /dev/null > +++ b/cpukit/include/rtems/regulator.h > @@ -0,0 +1,499 @@ > +/* SPDX-License-Identifier: BSD-2-Clause */ > + > +/** > + * @defgroup RegulatorAPI Regulator API > + * > + * @brief Regulator APIs > + * > + * The Regulator provides a set of APIs to manage input sources which > + * produces bursts of message traffic. > + */ > + > +/** > + * @mainpage > + * > + * The regulator is designed to sit logically between two entities -- a > + * source and a destination, where it limits the traffic sent to the > + * destination to prevent it from being flooded with messages from the > + * source. This can be used to accommodate bursts of input from a source > + * and meter it out to a destination. The maximum number of messages > + * which can be buffered in the regulator is specified by the > + * @a maximum_messages field in the @a rtems_regulator_attributes > + * structure passed as an argument to @a rtems_regulator_create(). > + * > + * The regulator library accepts an input stream of messages from a > + * source and delivers them to a destination. The regulator assumes that the > + * input stream from the source contains sporadic bursts of data which can > + * exceed the acceptable rate of the destination. By limiting the message > rate, > + * the regulator prevents an overflow of messages. > + * > + * The regulator can be configured for the input buffering required to manage > + * the maximum burst and for the metering rate for the output. The output > rate > + * is in messages per second. If the sender produces data too fast, the > + * regulator will buffer the configured number of messages. > + * > + * A configuration capability is provided to allow for adaptation to > different > + * message streams. The regulator can also support running multiple > instances, > + * which could be used on independent message streams. > + * > + * The regulator provides a simple interface to the application for avoiding > + * bursts of input from a fast source overflowing a slower destination. > + * > + * It is assumed that the application has a design limit on the number of > + * messages which may be buffered. All messages accepted by the regulator, > + * assuming no overflow on input, will eventually be output by the Delivery > + * thread. > + * > + * A regulator instance is used as follows from the producer/source side: > + * > + * @code > + * while (1) > + * use rtems_regulator_obtain_buffer to obtain a buffer > + * input operation to fetch data into the buffer > + * rtems_regulator_send(buffer, size of message) > + * @endcode > + * > + * The delivery of message buffers to the Destination and subsequent > + * release is performed in the context of the delivery thread by either > + * the delivery function or delivery thread. Details are below. > + * > + * The sequence diagram below shows the interaction between a message Source, > + * a Regulator instance, and RTEMS, given the usage described in the above > + * paragraphs. > + * > + * \startuml "Regulator Application Input Source Usage" > + * Source -> Regulator : rtems_regulator_obtain_buffer(regulator, buffer) > + * Regulator -> RTEMS : rtems_partition_get_buffer(id, buffer) > + * RTEMS --> Regulator : rtems_status_code > + * Regulator --> Source : rtems_status_code > + * Source -> Regulator : rtems_regulator_send(regulator, message, length) > + * Regulator -> RTEMS : rtems_message_queue_send(id, message, size) > + * RTEMS --> Regulator : rtems_status_code > + * Regulator --> Source : rtems_status_code > + * \enduml > + * > + * As illustrated in the sequence diagram, the Source usually corresponds > + * to application software reading a system input. The Source obtains a > + * buffer from the Regulator instance and fills it with incoming data. > + * The application explicitly obtaining a buffer and filling it in allows > + * for zero copy operations on the Source side. > + * > + * The Source then sends the buffer to the Regulator instance. The Regulator > + * the sends the buffer via a message queue which to the Delivery thread. > + * The Delivery thread executes periodically at a rate specified at > + * Regulation creation. At each period, the Delivery thread attempts to > + * receive up to a configured number of buffers and invoke the Delivery > + * function to deliver them to the Destination. > + * > + * The Delivery function is provided by the application for this > + * specific Regulator instance. Depending on the Destination, it may use > + * a function which copies the buffer contents (e.g., write()) or which > + * operates directly on the buffer contents (e.g. DMA from buffer). In > + * the case of a Destination which copies the buffer contents, the buffer > + * can be released via @a rtems_regulator_release_buffer() as soon as the > + * function or copying completes. In the case where the delivery uses the > + * buffer and returns, the call to @a rtems_regulator_release_buffer() > + * will occur when the use of the buffer is complete (e.g. completion > + * of DMA transfer). This explicit and deliberate exposure of buffering > + * provides the application with the ability to avoid copying the contents. > + * > + * After the Source has sent the message to the Regulator instance, > + * the Source is free to process another input and the Regulator > + * instance will ensure that the buffer is delivered to the Delivery > + * function and Destination. > + * > + * The Regulator implementation uses the RTEMS Classic API Partition Manager > + * to manage the buffer pool and the RTEMS Classic API Message Queue > + * Manager to send the buffer to the Delivery thread. > + */ > + > +/** > + * @addtogroup RegulatorAPI > + * > + * @file > + * > + * @brief This header file defines the Regulator API. > + * > + */ > + > +/* > + * Copyright (C) 2023 On-Line Applications Research Corporation (OAR) > + * > + * Redistribution and use in source and binary forms, with or without > + * modification, are permitted provided that the following conditions > + * are met: > + * 1. Redistributions of source code must retain the above copyright > + * notice, this list of conditions and the following disclaimer. > + * 2. Redistributions in binary form must reproduce the above copyright > + * notice, this list of conditions and the following disclaimer in the > + * documentation and/or other materials provided with the distribution. > + * > + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS > IS" > + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE > + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE > + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE > + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR > + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF > + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS > + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN > + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) > + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE > + * POSSIBILITY OF SUCH DAMAGE. > + */ > + > +#ifndef REGULATOR_H > +#define REGULATOR_H > + > +#include <stdlib.h> > + > +#include <rtems.h> > + > +/** > + * @ingroup RegulatorAPI > + * > + * @brief Regulator Delivery Function Type > + * > + * The user provides a function which is invoked to deliver a message > + * to the output. It is invoked by the Delivery thread created as part > + * of @a rtems_regulator_create(). The priority and stack size of the > + * Delivery thread are specified in the regulator attribute set. > + * > + * It takes three parameters: > + * > + * @param[in] context is an untyped pointer to a user context > + * @param[in] message points to the message > + * @param[in] length is the message size > + * > + * The following is an example deliverer function. It assumes that the > + * application has defined the my_context_t structure and it has at least > + * the socket field. The @a message passed in originated with an > + * application source which obtained the @a message buffer using > + * @a rtems_regulator_obtain_buffer(), filled it in with source data, > + * and used @a rtems_regulator_send() to hand to the regulator instance > + * for later delivery. > + * > + * @code > + * bool my_deliverer( > + * void *context, > + * void *message, > + * size_t length > + * ) > + * { > + * my_context_t *my_context; > + * > + * my_context = (my_context_t *)context; > + * > + * write(my_context->socket, message, length); > + * rtems_regulator_release_buffer(message); > + * // return false to indicate we released the buffer > + * return false; > + * } > + * @endcode > + * > + * The delivery function returns true to indicate that the delivery thread > + * should release the buffer or false to indicate that it released the > + * buffer. If the delivery function invokes a function like @a write() > + * to deliver the message to the destination, then the buffer can be > + * released immediately after the call. If the delivery function does > + * something like setting up a DMA transfer of the buffer, it cannot be > + * released until after the DMA is complete. > + * > + * The following sequence diagram shows the behavior of the Delivery thread > + * body and its interaction with the user-supplied deliverer() function. > + * > + * \startuml "Regulator Delivery Thread Body" > + * loop while (1) > + * "Delivery Thread" -> RTEMS : rtems_rate_monotonic_period(id, > delivery_thread_period) > + * loop for 0 : maximum_to_dequeue_per_period > + * "Delivery Thread" -> RTEMS : rtems_message_queue_receive(id, > message, size, wait, 0) > + * RTEMS --> "Delivery Thread" : rtems_status_code > + * group if [rtems_status_code != RTEMS_SUCCESSFUL] > + * RTEMS -> "Delivery Thread" : break > + * end > + * "Delivery Thread" -> Application : deliverer(context, buffer, > length) > + * "Delivery Thread" -> RTEMS : rtems_partition_return_buffer(id, > buffer) > + * RTEMS --> "Delivery Thread" : rtems_status_code > + * end > + * end > + * \enduml > + * > + * In the above sequence diagram, the key points are: > + * > + * -# The Delivery Thread Body is periodically executed. > + * -# During each period, up to the instance configuration parameter > + * @a maximum_to_dequeue_per_period may be dequeued and > + * passed the application's delivery function for processing. > + * > + * Note that the application explicitly obtains buffers from the > + * regulator instance but that the release may be done by Delivery > + * Thread, the Delivery function, or later when the buffer contents > + * are transferred. > + */ > +typedef bool (*rtems_regulator_deliverer)( > + void *context, > + void *message, > + size_t length > +); > + > +/** > + * @ingroup RegulatorAPI > + * > + * @brief Attributes for Regulator Instance > + * > + * An instance of this structure must be populated by the application > + * before creating an instance of the regulator. These settings tailor > + * the behavior of the regulator instance. > + */ > +typedef struct { > + /** Application function to invoke to output a message to the destination*/ > + rtems_regulator_deliverer deliverer; > + > + /** Context pointer to pass to deliver function */ > + void *deliverer_context; > + > + /** Maximum size message to process */ > + size_t maximum_message_size; > + > + /** Maximum number of messages to be able to buffer */ > + size_t maximum_messages; > + > + /** Priority of Delivery thread */ > + rtems_task_priority delivery_thread_priority; > + > + /** Stack size of Delivery thread */ > + size_t delivery_thread_stack_size; > + > + /** Period (in ticks) of Delivery thread */ > + rtems_interval delivery_thread_period; > + > + /** Maximum messages to dequeue per period */ > + size_t maximum_to_dequeue_per_period; > + > +} rtems_regulator_attributes; > + > +/** > + * @ingroup RegulatorAPI > + * > + * @brief Statistics for Regulator Instance > + * > + * An instance of this structure is provided to the directive > + * @a rtems_regulator_get_statistics and is filled in by that service. > + */ > +typedef struct { > + /** Number of successfully obtained buffers. */ > + size_t obtained; > + > + /** Number of successfully released buffers. */ > + size_t released; > + > + /** Number of successfully delivered buffers. */ > + size_t delivered; > + > + /** Rate Monotonic Period statistics for Delivery Thread */ > + rtems_rate_monotonic_period_statistics period_statistics; > + > +} rtems_regulator_statistics; > + > +/** > + * @ingroup RegulatorAPI > + * > + * @brief Regulator Instance > + * > + * This is used by the application as the handle to a Regulator instance. > + */ > +typedef void *rtems_regulator_instance; > + > +/** > + * @ingroup RegulatorAPI > + * > + * @brief Create a regulator > + * > + * This function creates an instance of a regulator. It uses the provided > + * @a attributes to create the instance return in @a regulator. This instance > + * will allocate the buffers associated with the regulator instance as well > + * as the Delivery thread. > + * > + * The @a attributes structure defines the priority and stack size of > + * the Delivery thread dedicated to this regulator instance. It also > + * defines the period of the Delivery thread and the maximum number of > + * messages that may be delivered per period via invocation of the > + * delivery function. > + * > + * For each regulator instance, the following resources are allocated: > + * > + * - A memory area for the regulator control block using @a malloc(). > + * - A RTEMS Classic API Message Queue is constructed with message > + * buffer memory allocated using @a malloc(). Each message consists > + * of a pointer and a length. > + * - A RTEMS Classic API Partition. > + * - A RTEMS Classic API Rate Monotonic Period. > + * > + * @param[in] attributes specify the regulator instance attributes > + * @param[inout] regulator will point to the regulator instance > + * > + * @return an RTEMS status code indicating success or failure. > + * > + * @note This function allocates memory for the buffers holding messages, > + * an Delivery thread and an RTEMS partition. When it executes, the > + * Delivery thread will create an RTEMS rate monotonic period. > + */ > +rtems_status_code rtems_regulator_create( > + rtems_regulator_attributes *attributes, > + rtems_regulator_instance **regulator > +); > + > +/** > + * @ingroup RegulatorAPI > + * > + * @brief Delete a regulator > + * > + * This function is used to delete the specified @a regulator instance. > + * > + * It is the responsibility of the user to ensure that any resources > + * such as sockets or open file descriptors used by the delivery > + * function are also deleted. It is likely safer to delete those > + * delivery resources after deleting the regulator instance rather than > + * before. > + * > + * @param[in] regulator is the instance to delete > + * @param[in] ticks is the maximum number of ticks to wait for > + * the delivery thread to shutdown. > + * > + * @return an RTEMS status code indicating success or failure. > + * > + * @note This function deallocates the resources allocated during > + * @a rtems_regulator_create(). > + */ > +rtems_status_code rtems_regulator_delete( > + rtems_regulator_instance *regulator, > + rtems_interval ticks > +); > + > +/** > + * @ingroup RegulatorAPI > + * > + * @brief Obtain Buffer from Regulator > + * > + * This function is used to obtain a buffer from the regulator's pool. The > + * @a buffer returned is assumed to be filled in with contents and used > + * in a subsequent call to @a rtems_regulator_send(). When the @a buffer is > + * delivered, it is expected to be released. If the @a buffer is not > + * successfully accepted by this function, then it should be returned > + * using @a rtems_regulator_release_buffer() or used to send another message. > + * > + * The @a buffer is of the maximum_message_size specified in the attributes > + * passed in to @a rtems_regulator_create(). > + * > + * @param[in] regulator is the regulator instance to operate upon > + * @param[out] buffer will point to the allocated buffer > + * > + * @return an RTEMS status code indicating success or failure. > + * > + * @note This function does not perform dynamic allocation. It obtains a > + * buffer from the pool allocated during @a rtems_regulator_create(). > + * > + * @note Any attempt to write outside the buffer area is undefined. > + */ > +rtems_status_code rtems_regulator_obtain_buffer( > + rtems_regulator_instance *regulator, > + void **buffer > +); > + > +/** > + * @ingroup RegulatorAPI > + * > + * @brief Release Previously Obtained Regulator Buffer > + * > + * This function is used to release a buffer to the regulator's pool. It is > + * assumed that the @a buffer returned will not be used by the application > + * anymore. The @a buffer must have previously been allocated by > + * @a rtems_regulator_obtain_buffer() and NOT passed to > + * @a rtems_regulator_send(). > + * > + * If a subsequent @a rtems_regulator_send() using this @a buffer is > + * successful, the @a buffer will eventually be processed by the delivery > + * thread and released. > + * > + * @param[in] regulator is the regulator instance to operate upon > + * @param[out] buffer will point to the buffer to release > + * > + * @return an RTEMS status code indicating success or failure. > + * > + * @note This function does not perform dynamic deallocation. It releases a > + * buffer to the pool allocated during @a rtems_regulator_create(). > + */ > +rtems_status_code rtems_regulator_release_buffer( > + rtems_regulator_instance *regulator, > + void *buffer > +); > + > +/** > + * @ingroup RegulatorAPI > + * > + * @brief Send to regulator instance > + * > + * This function is used by the producer to send a @a message to the > + * @a regulator for later delivery by the Delivery thread. The message is > + * contained in the memory pointed to by @a message and is @a length > + * bytes in length. > + * > + * It is required that the @a message buffer was obtained via > + * @a rtems_regulator_obtain_buffer(). > + * > + * It is assumed that the @a message buffer has been filled in with > + * application content to deliver. > + * > + * If the @a rtems_regulator_send() is successful, the buffer is enqueued > + * inside the regulator instance for subsequent delivery. After the > + * @a message is delivered, it may be released by either delivery > + * function or the application code depending on the implementation. > + * > + * The status @a RTEMS_TOO_MANY is returned if the regulator's > + * internal queue is full. This indicates that the configured > + * maximum number of messages was insufficient. It is the > + * responsibility of the caller to decide whether to hold messages, > + * drop them, or print a message that the maximum number of messages > + * should be increased. > + * > + * If @a rtems_regulator_send() is unsuccessful, it is the application's > + * responsibility to release the buffer. If it is successfully sent, > + * then it becomes the responsibility of the delivery function to > + * release it. > + * > + * @param[in] regulator is the regulator instance to operate upon > + * @param[out] message points to the message to deliver > + * @param[out] length is the size of the message in bytes > + * > + * @return an RTEMS status code indicating success or failure. > + * > + */ > +rtems_status_code rtems_regulator_send( > + rtems_regulator_instance *regulator, > + void *message, > + size_t length > +); > + > +/** > + * @ingroup RegulatorAPI > + * > + * @brief Obtain statistics for regulator instance > + * > + * This function is used by the application to obtain statistics > + * information about the regulator instance. > + * > + * If the @a obtained and @a released fields in the returned > + * @a statistics structure are equal, then there are no buffers > + * outstanding from this regulator instance. > + * > + * @param[in] regulator is the regulator instance to operate upon > + * @param[inout] statistics points to the statistics structure to fill in > + * > + * @return an RTEMS status code indicating success or failure. > + * > + */ > +rtems_status_code rtems_regulator_get_statistics( > + rtems_regulator_instance *regulator, > + rtems_regulator_statistics *statistics > +); > + > +#endif /* REGULATOR_H */ > diff --git a/cpukit/include/rtems/regulatorimpl.h > b/cpukit/include/rtems/regulatorimpl.h > new file mode 100644 > index 0000000000..ef1334c332 > --- /dev/null > +++ b/cpukit/include/rtems/regulatorimpl.h > @@ -0,0 +1,135 @@ > +/* SPDX-License-Identifier: BSD-2-Clause */ > + > +/** > + * @defgroup RegulatorInternalAPI Regulator API Internals > + * > + * @brief Regulator Internal Information > + * > + * This concerns implementation information about the Regulator. > + */ > + > +/** > + * @ingroup RegulatorInternalAPI > + * > + * @file > + * > + * @brief Regulator Library Implementation Support > + */ > + > +/* > + * Copyright (C) 2023 On-Line Applications Research Corporation (OAR) > + * > + * Redistribution and use in source and binary forms, with or without > + * modification, are permitted provided that the following conditions > + * are met: > + * 1. Redistributions of source code must retain the above copyright > + * notice, this list of conditions and the following disclaimer. > + * 2. Redistributions in binary form must reproduce the above copyright > + * notice, this list of conditions and the following disclaimer in the > + * documentation and/or other materials provided with the distribution. > + * > + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS > IS" > + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE > + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE > + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE > + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR > + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF > + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS > + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN > + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) > + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE > + * POSSIBILITY OF SUCH DAMAGE. > + */ > + > +#ifndef RTEMS_REGULATORIMPL_H > +#define RTEMS_REGULATORIMPL_H > + > +#include <stdatomic.h> > + > +#include <rtems/chain.h> > + > + > +/** > + * @ingroup RegulatorInternalAPI > + * > + * This constant is used to indicate the regulator instance is initialized. > + */ > +#define REGULATOR_INITIALIZED 0xDeadF00d > + > +/** > + * @ingroup RegulatorInternalAPI > + * > + * @brief Regulator Message Instance Management Structure > + */ > +typedef struct { > + /** This points to the message contents. */ > + void *buffer; > + /** This is the length of the message. */ > + size_t length; > +} _Regulator_Message_t; > + > +/** > + * @ingroup RegulatorInternalAPI > + * > + * @brief Regulator Statistics Private Structure > + * > + * An instance of this structure is allocated per regulator instance. > + */ > +typedef struct { > + /** Number of successfully obtained buffers. */ > + atomic_size_t obtained; > + > + /** Number of successfully released buffers. */ > + atomic_size_t released; > + > + /** Number of successfully delivered buffers. */ > + atomic_size_t delivered; > +} _Regulator_Statistics; > + > +/** > + * @ingroup RegulatorInternalAPI > + * > + * @brief Regulator Instance Private Structure > + * > + * An instance of this structure is allocated per regulator instance. > + */ > +typedef struct { > + /** Has magic value when instance is usable */ > + uint32_t initialized; > + > + /** Attributes for this instance -- copied from user */ > + rtems_regulator_attributes Attributes; > + > + /** Pointer to allocated message memory */ > + void *message_memory; > + > + /** Pointer to allocated memory for RTEMS Message Queue for pending > buffers*/ > + void *message_queue_storage; > + > + /** RTEMS Message Queue of pending outgoing messages */ > + rtems_id queue_id; > + > + /** RTEMS Partition for pool of unused messages */ > + rtems_id messages_partition_id; > + > + /** RTEMS Task for performing output */ > + rtems_id delivery_thread_id; > + > + /** Id of period used by output thread */ > + rtems_id delivery_thread_period_id; > + > + /** Indicates Delivery thread is running */ > + bool delivery_thread_is_running; > + > + /** Indicates Delivery thread has been requested to exit */ > + bool delivery_thread_request_exit; > + > + /** Indicates Delivery thread has exited */ > + bool delivery_thread_has_exited; > + > + /** Internal Statistics */ > + _Regulator_Statistics Statistics; > + > +} _Regulator_Control; > + > +#endif /* RTEMS_REGULATORIMPL_H */ > diff --git a/cpukit/libmisc/regulator/regulator.c > b/cpukit/libmisc/regulator/regulator.c > new file mode 100644 > index 0000000000..2337fdaf77 > --- /dev/null > +++ b/cpukit/libmisc/regulator/regulator.c > @@ -0,0 +1,683 @@ > +/* SPDX-License-Identifier: BSD-2-Clause */ > + > +/** > + * @file > + * > + * @brief Regulator Library Implementation > + */ > + > +/* > + * Copyright (C) 2022 On-Line Applications Research Corporation (OAR) > + * > + * Redistribution and use in source and binary forms, with or without > + * modification, are permitted provided that the following conditions > + * are met: > + * 1. Redistributions of source code must retain the above copyright > + * notice, this list of conditions and the following disclaimer. > + * 2. Redistributions in binary form must reproduce the above copyright > + * notice, this list of conditions and the following disclaimer in the > + * documentation and/or other materials provided with the distribution. > + * > + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS > IS" > + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE > + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE > + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE > + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR > + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF > + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS > + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN > + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) > + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE > + * POSSIBILITY OF SUCH DAMAGE. > + */ > + > +#include <stdlib.h> > + > +#include <rtems.h> > +#include <rtems/regulator.h> > + > +#include <rtems/regulatorimpl.h> > + > +/** > + * @ingroup RegulatorInternalAPI > + * > + * This method is the body for the task which delivers the output for > + * this regulator instance at the configured rate. > + * > + * @param[in] arg points to the regulator instance this thread > + * is associated with > + */ > +static rtems_task _Regulator_Output_task_body( > + rtems_task_argument arg > +) > +{ > + _Regulator_Control *the_regulator; > + rtems_status_code sc; > + size_t to_dequeue; > + _Regulator_Message_t regulator_message; > + size_t regulator_message_size; > + bool release_it; > + > + /* > + * The argument passed in cannot be NULL if the regulator_create worked. > + */ > + the_regulator = (_Regulator_Control *) arg; > + > + the_regulator->delivery_thread_is_running = true; > + > + /** > + * This thread uses a rate monotonic period object instance. A rate > + * monotonic period object must be created by the thread using it. > + * It can be deleted by any thread which simplifies clean up. > + * > + * The rate_monotonic_create() call can fail if the application > + * is incorrectly configured. This thread has no way to report the > + * failure. If it continues with an invalid id, then the thread will > + * not block on the period and spin continuously consuming CPU. The only > + * alternatives are to invoke rtems_fatal_error_occurred() or silently > + * exit the thread. > + */ > + sc = rtems_rate_monotonic_create( > + rtems_build_name('P', 'E', 'R', 'D'), > + &the_regulator->delivery_thread_period_id > + ); > + if (sc != RTEMS_SUCCESSFUL) { > + goto exit_delivery_thread; > + } > + > + /** > + * Loop on the rate_monotonic_period() based on the specified period. > + */ > + while (1) { > + sc = rtems_rate_monotonic_period( > + the_regulator->delivery_thread_period_id, > + the_regulator->Attributes.delivery_thread_period > + ); > + _Assert_Unused_variable_equals(sc, RTEMS_SUCCESSFUL); > + > + /** > + * If the delivery thread has been requested to exit, then > + * quit processing messages, break out of this loop, and exit > + * this thread. > + */ > + if (the_regulator->delivery_thread_request_exit) { > + break; > + } > + > + /** > + * Loop for the configured number of messages to deliver per period. > + * If we reach the point, there are no more messages, block for the > + * rest of this period. If there are messages, deliver them. > + */ > + for (to_dequeue = 0; > + to_dequeue < > the_regulator->Attributes.maximum_to_dequeue_per_period; > + to_dequeue++) { > + regulator_message_size = sizeof(_Regulator_Message_t); > + sc = rtems_message_queue_receive( > + the_regulator->queue_id, > + ®ulator_message, > + ®ulator_message_size, > + RTEMS_NO_WAIT, > + 0 > + ); > + _Assert_Unused_variable_equals(sc, RTEMS_SUCCESSFUL); > + if (sc != RTEMS_SUCCESSFUL) { > + break; > + } > + > + release_it = the_regulator->Attributes.deliverer( > + the_regulator->Attributes.deliverer_context, > + regulator_message.buffer, > + regulator_message.length > + ); > + > + the_regulator->Statistics.delivered++; > + > + /** > + * The message was successfully delivered. If the delivery function > + * wants the buffer returned, do it now. The delivery to the > Destination > + * may involve handing the buffer off to something like DMA > + * and need to wait for it to complete before releasing the buffer. > + * > + * Note that this is the underlying RTEMS service > + * used by @a rtems_regulator_obtain_buffer() and @a > + * rtems_regulator_release_buffer(). > + */ > + if (release_it == true) { > + the_regulator->Statistics.released++; > + sc = rtems_partition_return_buffer( > + the_regulator->messages_partition_id, > + regulator_message.buffer > + ); > + _Assert_Unused_variable_equals(sc, RTEMS_SUCCESSFUL); > + } > + } > + } > + > + /** > + * This thread was requested to exit. Do so. > + */ > +exit_delivery_thread: > + the_regulator->delivery_thread_is_running = false; > + the_regulator->delivery_thread_has_exited = true; > + > + (void) > rtems_rate_monotonic_delete(the_regulator->delivery_thread_period_id); > + > + rtems_task_exit(); > +} > + > +/** > + * @ingroup RegulatorInternalAPI > + * > + * This method frees the resources associated with a regulator instance. > + * The resources are freed in the opposite of the order in which they are > + * allocated. This is used on error cases in @a rtems_regulator_create() and > in > + * @a rtems_regulator_delete(). > + * > + * @param[in] the_regulator is the instance to operate upon > + * @param[in] ticks is the length of time to wait for the delivery thread > + * to exit > + * > + * @return This method returns true is successful and false on timeout. > + */ > +static bool _Regulator_Free_helper( > + _Regulator_Control *the_regulator, > + rtems_interval ticks > +) > +{ > + rtems_status_code sc; > + > + > + /* > + * If the output thread has not started running, then we can just delete > it. > + */ > + > + if (ticks == 0 || the_regulator->delivery_thread_is_running == false) { > + sc = rtems_task_delete(the_regulator->delivery_thread_id); > + _Assert_Unused_variable_equals(sc, RTEMS_SUCCESSFUL); > + } else { > + rtems_interval remaining = ticks; > + > + the_regulator->delivery_thread_request_exit = true; > + > + while (1) { > + if (the_regulator->delivery_thread_has_exited) { > + break; > + } > + > + if (remaining == 0) { > + return false; > + } > + > + (void) rtems_task_wake_after(1); > + remaining--; > + } > + } > + > + /* > + * The output thread deletes the rate monotonic period that it created. > + */ > + > + /* > + * The regulator's message_queue_storage is implicitly freed by this call. > + */ > + sc = rtems_message_queue_delete(the_regulator->queue_id); > + _Assert_Unused_variable_equals(sc, RTEMS_SUCCESSFUL); > + > + sc = rtems_partition_delete(the_regulator->messages_partition_id); > + _Assert_Unused_variable_equals(sc, RTEMS_SUCCESSFUL); > + > + if (the_regulator->message_memory) { > + free(the_regulator->message_memory); > + } > + > + the_regulator->initialized = 0; > + free(the_regulator); > + return true; > +} > + > +/** > + * @ingroup RegulatorInternalAPI > + */ > +rtems_status_code rtems_regulator_create( > + rtems_regulator_attributes *attributes, > + rtems_regulator_instance **regulator > +) > +{ > + _Regulator_Control *the_regulator; > + rtems_status_code sc; > + size_t alloc_size; > + > + /** > + * Perform basic validation of parameters > + */ > + if (!attributes) { > + return RTEMS_INVALID_ADDRESS; > + } > + > + if (!regulator) { > + return RTEMS_INVALID_ADDRESS; > + } > + > + /** > + * Verify attributes are OK. Some are checked by calls to object create > + * methods. Specifically the following are not checked: > + * > + * - delivery_thread_priority by rtems_task_create() > + * - delivery_thread_stack_size can be any value > + */ > + if (attributes->deliverer == NULL) { > + return RTEMS_INVALID_ADDRESS; > + } > + > + if (attributes->maximum_messages == 0) { > + return RTEMS_INVALID_NUMBER; > + } > + > + if (attributes->maximum_message_size == 0) { > + return RTEMS_INVALID_SIZE; > + } > + > + if (attributes->maximum_to_dequeue_per_period == 0) { > + return RTEMS_INVALID_NUMBER; > + } > + > + if (attributes->delivery_thread_period == 0) { > + return RTEMS_INVALID_NUMBER; > + } > + > + /** > + * Allocate memory for regulator instance > + */ > + the_regulator = (_Regulator_Control *) calloc(sizeof(_Regulator_Control), > 1); > + if (!the_regulator) { > + return RTEMS_NO_MEMORY; > + } > + > + /** > + * We do NOT want the delivery_thread_id field to be initialized to 0. If > the > + * @a rtems_task_create() fails, then the field will not be overwritten. > + * This results in an attempt to rtems_task_delete(0) during clean > + * up. The thread ID of 0 is self which results in the calling thread > + * accidentally deleting itself. > + */ > + the_regulator->delivery_thread_id = (rtems_id) -1; > + > + /** > + * Copy the attributes to an internal area for later use > + */ > + the_regulator->Attributes = *attributes; > + > + /** > + * Allocate memory for the messages. There is no need to zero out the > + * message memory because the user should fill that in. > + */ > + alloc_size = attributes->maximum_message_size * > attributes->maximum_messages; > + the_regulator->message_memory = calloc(alloc_size, 1); > + if (!the_regulator->message_memory) { > + _Regulator_Free_helper(the_regulator, 0); > + return RTEMS_NO_MEMORY; > + } > + > + /** > + * Associate message memory with a partition so allocations are atomic > + */ > + sc = rtems_partition_create( > + rtems_build_name('P', 'O', 'O', 'L'), > + the_regulator->message_memory, > + alloc_size, > + attributes->maximum_message_size, > + RTEMS_DEFAULT_ATTRIBUTES, > + &the_regulator->messages_partition_id > + ); > + if (sc != RTEMS_SUCCESSFUL) { > + _Regulator_Free_helper(the_regulator, 0); > + return sc; > + } > + > + /** > + * Create the message queue between the sender and output thread > + */ > + RTEMS_MESSAGE_QUEUE_BUFFER(sizeof(_Regulator_Message_t)) > regulator_message_t; > + > + size_t storage_size = sizeof(regulator_message_t) * > attributes->maximum_messages; > + > + the_regulator->message_queue_storage = malloc(storage_size); > + if (the_regulator->message_queue_storage == NULL) { > + _Regulator_Free_helper(the_regulator, 0); > + return RTEMS_NO_MEMORY; > + } > + > + rtems_message_queue_config mq_config = { > + .name = rtems_build_name('S', 'N', 'D', 'Q'), > + .maximum_pending_messages = attributes->maximum_messages, > + .maximum_message_size = sizeof(_Regulator_Message_t), > + .storage_area = the_regulator->message_queue_storage, > + .storage_size = storage_size, > + .storage_free = free, > + .attributes = RTEMS_DEFAULT_ATTRIBUTES > + }; > + sc = rtems_message_queue_construct( > + &mq_config, > + &the_regulator->queue_id > + ); > + if (sc != RTEMS_SUCCESSFUL) { > + _Regulator_Free_helper(the_regulator, 0); > + return sc; > + } > + > + /** > + * @note A rate monotonic period object must be created by the thread > + * using it. Thus that specific create operation is not included > + * in this method. All other resources are allocated here. > + */ > + > + /** > + * Create the output thread Using the priority and stack size attributes > + * specified by the user. > + */ > + sc = rtems_task_create( > + rtems_build_name('R', 'E', 'G', 'U'), > + attributes->delivery_thread_priority, > + attributes->delivery_thread_stack_size, > + RTEMS_DEFAULT_MODES, > + RTEMS_DEFAULT_ATTRIBUTES, > + &the_regulator->delivery_thread_id > + ); > + if (sc != RTEMS_SUCCESSFUL) { > + _Regulator_Free_helper(the_regulator, 0); > + return sc; > + } > + > + /** > + * Start the output thread. > + * > + * @note There should be no way this call can fail. The task id is valid, > + * the regulator output thread entry point is valid, and the argument > + * is valid. > + */ > + the_regulator->delivery_thread_is_running = true; > + the_regulator->delivery_thread_request_exit = false; > + the_regulator->delivery_thread_has_exited = false; > + > + sc = rtems_task_start( > + the_regulator->delivery_thread_id, > + _Regulator_Output_task_body, > + (rtems_task_argument) the_regulator > + ); > + _Assert_Unused_variable_equals(sc, RTEMS_SUCCESSFUL); > + > + /** > + * The regulator is successfully initialized. Set the initialized field > + * to reflect this and return the instance pointer. > + */ > + the_regulator->initialized = REGULATOR_INITIALIZED; > + > + *regulator = (void *)the_regulator; > + > + return RTEMS_SUCCESSFUL; > +} > + > +/** > + * @brief Validate the regulator instance provided by the user > + * > + * Validate the regulator instance provided by the user > + * > + * @param[in] regulator is the instance provided by the user > + * @param[inout] status will contain the RTEMS status for this check > + * > + * @return This method returns a @a _Regulator_Control instance pointer > + * which is NULL if invalid or points to the internal regulator > + * control structure if valid. > + */ > +static inline _Regulator_Control *_Regulator_Get( > + rtems_regulator_instance *regulator, > + rtems_status_code *status > +) > +{ > + _Regulator_Control *the_regulator = (_Regulator_Control *) regulator; > + > + if (!the_regulator) { > + *status = RTEMS_INVALID_ADDRESS; > + return NULL; > + } > + > + if (the_regulator->initialized != REGULATOR_INITIALIZED) { > + *status = RTEMS_INCORRECT_STATE; > + return NULL; > + } > + > + status = RTEMS_SUCCESSFUL; > + return the_regulator; > +} > + > +/** > + * @ingroup RegulatorInternalAPI > + */ > +rtems_status_code rtems_regulator_delete( > + rtems_regulator_instance *regulator, > + rtems_interval ticks > +) > +{ > + _Regulator_Control *the_regulator; > + rtems_status_code status; > + > + /** > + * Convert external handle to internal instance pointer > + */ > + the_regulator = _Regulator_Get(regulator, &status); > + if (the_regulator == NULL) { > + return status; > + } > + > + /** > + * There can be no buffers outstanding > + */ > + _Regulator_Statistics *stats = &the_regulator->Statistics; > + > + if (stats->obtained != stats->released ) { > + return RTEMS_RESOURCE_IN_USE; > + } > + > + /** > + * Free the resources associated with this regulator instance. > + */ > + bool bc; > + bc = _Regulator_Free_helper(the_regulator, ticks); > + if (bc == false) { > + return RTEMS_TIMEOUT; > + } > + > + return RTEMS_SUCCESSFUL; > +} > + > +/** > + * @ingroup RegulatorInternalAPI > + * > + * Allocate a buffer for the caller using the internal partition. > + */ > +rtems_status_code rtems_regulator_obtain_buffer( > + rtems_regulator_instance *regulator, > + void **buffer > +) > +{ > + _Regulator_Control *the_regulator; > + rtems_status_code status; > + > + /** > + * Convert external handle to internal instance pointer > + */ > + the_regulator = _Regulator_Get(regulator, &status); > + if (the_regulator == NULL) { > + return status; > + } > + > + /** > + * Allocate a buffer for the user application from the buffer pool managed > + * by an Classic API partition. > + */ > + status = rtems_partition_get_buffer( > + the_regulator->messages_partition_id, > + buffer > + ); > + > + if (status == RTEMS_SUCCESSFUL) { > + the_regulator->Statistics.obtained++; > + } > + > + return status; > +} > + > +/** > + * @ingroup RegulatorInternalAPI > + * > + * Allocate a buffer for the caller using the internal partition. > + */ > +rtems_status_code rtems_regulator_release_buffer( > + rtems_regulator_instance *regulator, > + void *buffer > +) > +{ > + _Regulator_Control *the_regulator; > + rtems_status_code status; > + > + /** > + * Convert external handle to internal instance pointer > + */ > + the_regulator = _Regulator_Get(regulator, &status); > + if (the_regulator == NULL) { > + return status; > + } > + > + /** > + * Deallocate the buffer to the buffer pool managed by a Classic > + * API partition. > + */ > + status = rtems_partition_return_buffer( > + the_regulator->messages_partition_id, > + buffer > + ); > + > + if (status == RTEMS_SUCCESSFUL) { > + the_regulator->Statistics.released++; > + } > + > + return status; > +} > + > +/** > + * @ingroup RegulatorInternalAPI > + */ > +rtems_status_code rtems_regulator_send( > + rtems_regulator_instance *regulator, > + void *message, > + size_t length > +) > +{ > + _Regulator_Control *the_regulator; > + rtems_status_code status; > + _Regulator_Message_t regulator_message; > + > + the_regulator = (_Regulator_Control *) regulator; > + > + /** > + * Validate the arguments and ensure the regulator was successfully > + * initialized. > + */ > + if (!message) { > + return RTEMS_INVALID_ADDRESS; > + } > + > + if (length == 0) { > + return RTEMS_INVALID_NUMBER; > + } > + > + /** > + * Convert external handle to internal instance pointer > + */ > + the_regulator = _Regulator_Get(regulator, &status); > + if (the_regulator == NULL) { > + return status; > + } > + > + /** > + * Place the message pointer and length into a temporary structure. This > + * lets the implementation internally send the message by reference and > + * have a zero-copy implementation. > + */ > + regulator_message.buffer = message; > + regulator_message.length = length; > + > + /** > + * Send the application message to the output thread for delivery using > + * a Classic API message queue. > + */ > + status = rtems_message_queue_send( > + the_regulator->queue_id, > + ®ulator_message, > + sizeof(_Regulator_Message_t) > + ); > + if (status != RTEMS_SUCCESSFUL) { > + return status; > + } > + > + return status; > +} > + > +/** > + * @ingroup RegulatorInternalAPI > + */ > +rtems_status_code rtems_regulator_get_statistics( > + rtems_regulator_instance *regulator, > + rtems_regulator_statistics *statistics > +) > +{ > + _Regulator_Control *the_regulator; > + rtems_status_code status; > + > + the_regulator = (_Regulator_Control *) regulator; > + > + /** > + * Validate the arguments and ensure the regulator was successfully > + * initialized. > + */ > + if (!statistics) { > + return RTEMS_INVALID_ADDRESS; > + } > + > + /** > + * Convert external handle to internal instance pointer > + */ > + the_regulator = _Regulator_Get(regulator, &status); > + if (the_regulator == NULL) { > + return status; > + } > + > + /** > + * Zero out the statistics structure in case the get period statistics > + * fails below. > + */ > + memset(statistics, 0, sizeof(rtems_regulator_statistics)); > + > + /** > + * Fill in the caller's statistics structure from information > + * maintained by the regulator instance about buffers processed. > + */ > + statistics->obtained = the_regulator->Statistics.obtained; > + statistics->released = the_regulator->Statistics.released; > + statistics->delivered = the_regulator->Statistics.delivered; > + > + /** > + * Attempt to retrieve the delivery thread's period's statistics. > + * > + * NOTE; If the Delivery Thread has not run yet, the period will not > + * exist yet. We should not fail for this reason but it is why > + * we zeroed out the entire structure above. > + */ > + (void) rtems_rate_monotonic_get_statistics( > + the_regulator->delivery_thread_period_id, > + &statistics->period_statistics > + ); > + > + return RTEMS_SUCCESSFUL; > +} > diff --git a/spec/build/cpukit/librtemscpu.yml > b/spec/build/cpukit/librtemscpu.yml > index ff4ac8e944..e7ee9cf581 100644 > --- a/spec/build/cpukit/librtemscpu.yml > +++ b/spec/build/cpukit/librtemscpu.yml > @@ -507,6 +507,8 @@ links: > uid: objmpci > - role: build-dependency > uid: objpci > +- role: build-dependency > + uid: objregulator > - role: build-dependency > uid: objpsxsgnl > - role: build-dependency > diff --git a/spec/build/cpukit/objregulator.yml > b/spec/build/cpukit/objregulator.yml > new file mode 100644 > index 0000000000..56d6154de9 > --- /dev/null > +++ b/spec/build/cpukit/objregulator.yml > @@ -0,0 +1,18 @@ > +SPDX-License-Identifier: CC-BY-SA-4.0 OR BSD-2-Clause > +build-type: objects > +cflags: [] > +copyrights: > +- Copyright (C) 2023 OAR Corporatoin > +cppflags: [] > +cxxflags: [] > +enabled-by: true > +includes: [] > +install: > +- destination: ${BSP_INCLUDEDIR}/rtems > + source: > + - cpukit/include/rtems/regulator.h > + - cpukit/include/rtems/regulatorimpl.h > +links: [] > +source: > +- cpukit/libmisc/regulator/regulator.c > +type: build > diff --git a/spec/build/testsuites/libtests/grp.yml > b/spec/build/testsuites/libtests/grp.yml > index addcb286ad..c1a6209e99 100644 > --- a/spec/build/testsuites/libtests/grp.yml > +++ b/spec/build/testsuites/libtests/grp.yml > @@ -228,6 +228,8 @@ links: > uid: record01 > - role: build-dependency > uid: record02 > +- role: build-dependency > + uid: regulator01 > - role: build-dependency > uid: rtmonuse > - role: build-dependency > diff --git a/spec/build/testsuites/libtests/regulator01.yml > b/spec/build/testsuites/libtests/regulator01.yml > new file mode 100644 > index 0000000000..776d0ae34b > --- /dev/null > +++ b/spec/build/testsuites/libtests/regulator01.yml > @@ -0,0 +1,21 @@ > +SPDX-License-Identifier: CC-BY-SA-4.0 OR BSD-2-Clause > +build-type: test-program > +cflags: [] > +copyrights: > +- Copyright (C) 2023 OAR Corporation > +cppflags: [] > +cxxflags: [] > +enabled-by: true > +features: c cprogram > +includes: [] > +ldflags: > +- -Wl,--wrap=malloc > +links: [] > +source: > +- testsuites/libtests/regulator01/regulator01.c > +- testsuites/libtests/regulator01/rtems_config.c > +stlib: [] > +target: testsuites/libtests/regulator01.exe > +type: build > +use-after: [] > +use-before: [] > diff --git a/testsuites/libtests/regulator01/regulator01.c > b/testsuites/libtests/regulator01/regulator01.c > new file mode 100644 > index 0000000000..cc5af01223 > --- /dev/null > +++ b/testsuites/libtests/regulator01/regulator01.c > @@ -0,0 +1,1310 @@ > +/* SPDX-License-Identifier: BSD-2-Clause */ > + > +/** > + * @defgroup RegulatorTests Regulator Test Cases > + * > + * @brief Unit test cases for the Regulator > + * > + * This is a set of unit test cases for the regulator. > + */ > + > +/** > + * @ingroup RegulatorTests > + * > + * @file > + * > + * @brief Test 01 for Regulator Library > + */ > + > +/* > + * Copyright (C) 2022 On-Line Applications Research Corporation (OAR) > + * > + * Redistribution and use in source and binary forms, with or without > + * modification, are permitted provided that the following conditions > + * are met: > + * 1. Redistributions of source code must retain the above copyright > + * notice, this list of conditions and the following disclaimer. > + * 2. Redistributions in binary form must reproduce the above copyright > + * notice, this list of conditions and the following disclaimer in the > + * documentation and/or other materials provided with the distribution. > + * > + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS > IS" > + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE > + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE > + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE > + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR > + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF > + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS > + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN > + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) > + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE > + * POSSIBILITY OF SUCH DAMAGE. > + */ > + > +#include <stdio.h> > +#include <string.h> > +#include <unistd.h> > + > +#include <rtems.h> > +#include <rtems/test-info.h> > +#include <tmacros.h> > + > +#include <rtems/regulator.h> > + > +/** > + * @brief Regulator Test Name > + */ > +const char rtems_test_name[] = "Regulator 1"; > + > +/* > + * Prototypes for wrapped functions > + */ > +void *__wrap_malloc(size_t size); > +void *__real_malloc(size_t size); > + > +/** > + * @ingroup RegulatorTests > + * @brief Calloc Wrapper Trigger Count > + */ > +static int malloc_trigger_count; > + > +/** > + * @ingroup RegulatorTests > + * @brief Calloc Wrapper Call Count > + */ > +static int malloc_call_count; > + > +/** > + * @ingroup RegulatorTests > + * @brief Calloc Wrapper Trigger enable > + */ > +static bool malloc_trigger_enabled; > + > +/** > + * @ingroup RegulatorTests > + * @brief Enable Calloc Wrapper Trigger > + */ > +static void malloc_trigger_enable( > + int trigger_count > +) > +{ > + malloc_trigger_enabled = true; > + malloc_trigger_count = trigger_count; > + malloc_call_count = 0; > +} > +/** > + * @ingroup RegulatorTests > + * @brief Reset Calloc Wrapper Trigger and Count > + */ > +static void malloc_trigger_reset(void) > +{ > + malloc_trigger_enabled = 0; > + malloc_trigger_count = 0; > + malloc_call_count = 0; > +} > +/** > + * @ingroup RegulatorTests > + * @brief Calloc Wrapper to Trigger Allocation Errors > + */ > +void *__wrap_malloc(size_t size) > +{ > + if (malloc_trigger_enabled) { > + malloc_call_count++; > + if (malloc_call_count == malloc_trigger_count) { > + return NULL; > + } > + } > + > + return __real_malloc(size); > +} > + > +/** > + * @brief Constant to simpify code > + */ > +#define FIVE_SECONDS (5 * rtems_clock_get_ticks_per_second()) > + > +/** > + * @ingroup RegulatorTests > + * @brief Empty Deliver Method for Testing > + */ > +static bool test_regulator_deliverer( > + void *context, > + void *message, > + size_t length > +) > +{ > + (void) context; > + (void) message; > + (void) length; > + > + return true; > +} > + > +/** > + * @ingroup RegulatorTests > + * @brief Maximum length of a test message that is delivered > + */ > +#define MAXIMUM_MESSAGE_LENGTH 32 > + > +/** > + * @ingroup RegulatorTests > + * @brief Maximum number of test messages to buffer > + */ > +#define MAXIMUM_MESSAGES_TO_BUFFER 10 > + > +/** > + * @ingroup RegulatorTests > + * @brief Structure for capturing messages as delivered > + */ > +typedef struct { > + rtems_interval processed; > + char message[MAXIMUM_MESSAGE_LENGTH]; > +} message_log_t; > + > +/** > + * @ingroup RegulatorTests > + * @brief Set of Delivered messages > + */ > +message_log_t delivered_messages[MAXIMUM_MESSAGES_TO_BUFFER]; > + > +/** > + * @ingroup RegulatorTests > + * @brief Count of Delivered messages > + */ > +int delivered_message_count; > + > +/** > + * @ingroup RegulatorTests > + * @brief Reset Delivered Message Set > + * > + * This is used at the beginning of a test case which is going to > + * check that message contents and delivery times were as expected. > + */ > +static void delivered_messages_reset(void) > +{ > + delivered_message_count = 0; > + memset(delivered_messages, 0xc5, sizeof(delivered_messages)); > +} > + > +/** > + * @brief Context for Logger Delivery Function > + */ > +typedef struct { > + /** Regulator instance being operated on */ > + rtems_regulator_instance *regulator; > +} deliverer_logger_context_t; > + > +/** > + * @brief Context Instance for Logger Delivery Function > + */ > +static deliverer_logger_context_t deliverer_logger_context; > + > +/** > + * @ingroup RegulatorTests > + * @brief Empty Deliver Method for Testing > + * > + * This deliverer method implementation logs the messages along with > + * their time of arrival. This is used by the test cases to verify > + * proper delivery. > + */ > +static bool test_regulator_deliverer_logger( > + void *context, > + void *message, > + size_t length > +) > +{ > + deliverer_logger_context_t *the_context; > + > + the_context = (deliverer_logger_context_t *)context; > + > + static bool caller_releases_buffer = true; > + > + size_t len; > + rtems_interval ticks; > + rtems_status_code sc; > + > + len = strnlen(message, MAXIMUM_MESSAGE_LENGTH) + 1; > + rtems_test_assert(len = length); > + > + ticks = rtems_clock_get_ticks_since_boot(); > + > + delivered_messages[delivered_message_count].processed = ticks; > + > + strcpy(delivered_messages[delivered_message_count].message, message); > + > + delivered_message_count++; > + > + /* > + * Alternate releasing the buffer here and allowing the calling Delivery > + * Thread to do it. This increases coverage of that logic. > + */ > + if (caller_releases_buffer == true) { > + caller_releases_buffer = false; > + return true; > + } > + > + sc = rtems_regulator_release_buffer(the_context->regulator, message); > + rtems_test_assert(sc == RTEMS_SUCCESSFUL); > + > + return false; > +} > + > + > +/** > + * @ingroup RegulatorTests > + * @brief Helper to create a Regulator instance > + * > + * This helper creates a regulator instance with some arbitrary attributes. > + * This is used in multiple test cases to have a valie regulator instance to > + * trigger error cases. > + */ > +static rtems_regulator_instance *test_regulator_create_regulator_OK(void) > +{ > + rtems_status_code sc; > + rtems_regulator_attributes attributes = { > + .deliverer = test_regulator_deliverer, > + .deliverer_context = NULL, > + .maximum_message_size = 16, > + .maximum_messages = 10, > + .delivery_thread_priority = 16, > + .delivery_thread_stack_size = 0, > + .delivery_thread_period = RTEMS_MILLISECONDS_TO_TICKS(1000), > + .maximum_to_dequeue_per_period = 3 > + }; > + rtems_regulator_instance *regulator; > + > + regulator = NULL; > + > + sc = rtems_regulator_create(&attributes, ®ulator); > + rtems_test_assert(sc == RTEMS_SUCCESSFUL); > + rtems_test_assert(regulator != NULL); > + > + return regulator; > +} > + > +/** > + * @ingroup RegulatorTests > + * @brief Verify rtems_regulator_create() maximum_to_dequeue_per_period > + * attributes error > + * > + * This unit test verifies that rtems_regulator_create() returns an error > when > + * the maximum_to_dequeue_per_period attribute is zero. > + */ > +static void test_regulator_create_max_dequeue_zero(void) > +{ > + rtems_status_code sc; > + rtems_regulator_attributes attributes = { > + .deliverer = test_regulator_deliverer, > + .deliverer_context = NULL, > + .maximum_message_size = 16, > + .maximum_messages = 10, > + .delivery_thread_priority = 16, > + .delivery_thread_stack_size = 0, > + .delivery_thread_period = RTEMS_MILLISECONDS_TO_TICKS(1000), > + .maximum_to_dequeue_per_period = 0 > + }; > + rtems_regulator_instance *regulator; > + > + regulator = NULL; > + > + sc = rtems_regulator_create(&attributes, ®ulator); > + rtems_test_assert(sc == RTEMS_INVALID_NUMBER); > +} > + > +/** > + * @ingroup RegulatorTests > + * @brief Verify rtems_regulator_create() NULL attributes error > + * > + * This unit test verifies that rtems_regulator_create() returns an error > when > + * the attributes argument is NULL. > + */ > +static void test_regulator_create_null_attributes(void) > +{ > + rtems_status_code sc; > + rtems_regulator_instance *regulator; > + > + sc = rtems_regulator_create(NULL, ®ulator); > + rtems_test_assert(sc == RTEMS_INVALID_ADDRESS); > +} > + > +/** > + * @ingroup RegulatorTests > + * @brief Verify rtems_regulator_create NULL regulator error > + * > + * This unit test verifies that rtems_regulator_create() returns an error > when > + * the regulator argument is NULL. > + */ > +static void test_regulator_create_null_regulator(void) > +{ > + rtems_status_code sc; > + rtems_regulator_attributes attributes; > + > + sc = rtems_regulator_create(&attributes, NULL); > + rtems_test_assert(sc == RTEMS_INVALID_ADDRESS); > +} > + > +/** > + * @ingroup RegulatorTests > + * @brief Verify rtems_regulator_create deliverer is NULL > + * > + * This unit test verifies that rtems_regulator_create() returns an error > when > + * the the attributes deliverer field is NULL. > + */ > +static void test_regulator_create_deliverer_is_null(void) > +{ > + rtems_status_code sc; > + rtems_regulator_attributes attributes; > + rtems_regulator_instance *regulator; > + > + (void) memset(&attributes, 0, sizeof(rtems_regulator_attributes)); > + > + attributes.deliverer = NULL; > + attributes.maximum_messages = 0; > + attributes.maximum_message_size = 16; > + attributes.maximum_to_dequeue_per_period = 1; > + > + sc = rtems_regulator_create(&attributes, ®ulator); > + rtems_test_assert(sc == RTEMS_INVALID_ADDRESS); > +} > + > +/** > + * @ingroup RegulatorTests > + * @brief Verify rtems_regulator_create maximum_messages is 0 error > + * > + * This unit test verifies that rtems_regulator_create() returns an error > when > + * the the attributes maximum_messages field is 0. > + */ > +static void test_regulator_create_maximum_messages_is_zero(void) > +{ > + rtems_status_code sc; > + rtems_regulator_attributes attributes; > + rtems_regulator_instance *regulator; > + > + (void) memset(&attributes, 0, sizeof(rtems_regulator_attributes)); > + > + attributes.deliverer = test_regulator_deliverer; > + attributes.maximum_messages = 0; > + attributes.maximum_message_size = 16; > + attributes.maximum_to_dequeue_per_period = 1; > + > + sc = rtems_regulator_create(&attributes, ®ulator); > + rtems_test_assert(sc == RTEMS_INVALID_NUMBER); > +} > + > +/** > + * @ingroup RegulatorTests > + * @brief Verify rtems_regulator_create maximum_message_size is 0 error > + * > + * This unit test verifies that rtems_regulator_create() returns an error > when > + * the the attributes maximum_message_size field is 0. > + */ > +static void test_regulator_create_maximum_message_size_is_zero(void) > +{ > + rtems_status_code sc; > + rtems_regulator_attributes attributes; > + rtems_regulator_instance *regulator; > + > + (void) memset(&attributes, 0, sizeof(rtems_regulator_attributes)); > + > + attributes.deliverer = test_regulator_deliverer; > + attributes.maximum_messages = 10; > + attributes.maximum_message_size = 0; > + attributes.maximum_to_dequeue_per_period = 1; > + > + sc = rtems_regulator_create(&attributes, ®ulator); > + rtems_test_assert(sc == RTEMS_INVALID_SIZE); > +} > + > +/** > + * @ingroup RegulatorTests > + * @brief Verify rtems_regulator_create maximum_to_dequeue_per_period is 0 > error > + * > + * This unit test verifies that rtems_regulator_create() returns an error > when > + * the the attributes maximum_to_dequeue_per_period field is 0. > + */ > +static void test_regulator_create_maximum_to_dequeue_per_period_is_zero(void) > +{ > + rtems_status_code sc; > + rtems_regulator_attributes attributes; > + rtems_regulator_instance *regulator; > + > + (void) memset(&attributes, 0, sizeof(rtems_regulator_attributes)); > + > + attributes.deliverer = test_regulator_deliverer; > + attributes.maximum_messages = 10; > + attributes.maximum_message_size = 0; > + > + sc = rtems_regulator_create(&attributes, ®ulator); > + rtems_test_assert(sc == RTEMS_INVALID_SIZE); > +} > + > +/** > + * @ingroup RegulatorTests > + * @brief Verify rtems_regulator_create returns error on failure to allocate > regulator > + * > + * This unit test verifies that rtems_regulator_create() returns an error > when > + * it is unable to allocate the mmemory for the regulator instance. > + */ > +static void test_regulator_create_malloc_regulator_fails(void) > +{ > + rtems_status_code sc; > + rtems_regulator_attributes attributes; > + rtems_regulator_instance *regulator; > + > + (void) memset(&attributes, 0, sizeof(rtems_regulator_attributes)); > + > + attributes.deliverer = test_regulator_deliverer; > + attributes.maximum_messages = 10; > + attributes.maximum_message_size = 16; > + attributes.delivery_thread_priority = 32; > + attributes.maximum_to_dequeue_per_period = 1; > + attributes.delivery_thread_period = > RTEMS_MILLISECONDS_TO_TICKS(1000); > + > + malloc_trigger_enable(1); > + > + sc = rtems_regulator_create(&attributes, ®ulator); > + rtems_test_assert(sc == RTEMS_NO_MEMORY); > + > + malloc_trigger_reset(); > +} > + > +/** > + * @ingroup RegulatorTests > + * @brief Verify rtems_regulator_create returns error on failure to allocate > buffers > + * > + * This unit test verifies that rtems_regulator_create() returns an error > when > + * it is unable to allocate the mmemory for the regulator buffers. > + */ > +static void test_regulator_create_malloc_buffers_fails(void) > +{ > + rtems_status_code sc; > + rtems_regulator_attributes attributes; > + rtems_regulator_instance *regulator; > + > + (void) memset(&attributes, 0, sizeof(rtems_regulator_attributes)); > + > + attributes.deliverer = test_regulator_deliverer; > + attributes.maximum_messages = 10; > + attributes.maximum_message_size = 16; > + attributes.delivery_thread_priority = 32; > + attributes.maximum_to_dequeue_per_period = 1; > + attributes.delivery_thread_period = > RTEMS_MILLISECONDS_TO_TICKS(1000); > + > + malloc_trigger_enable(2); > + > + sc = rtems_regulator_create(&attributes, ®ulator); > + rtems_test_assert(sc == RTEMS_NO_MEMORY); > + > + malloc_trigger_reset(); > +} > + > +/** > + * @ingroup RegulatorTests > + * @brief Verify rtems_regulator_create and delete work > + * > + * This unit test verifies that rtems_regulator_create() can successfully > create > + * the the attributes delivery_thread_priority field is 0. > + */ > +static void test_regulator_create_delivery_thread_priority_is_zero(void) > +{ > + rtems_status_code sc; > + rtems_regulator_attributes attributes; > + rtems_regulator_instance *regulator; > + > + (void) memset(&attributes, 0, sizeof(rtems_regulator_attributes)); > + > + attributes.deliverer = test_regulator_deliverer; > + attributes.maximum_messages = 10; > + attributes.maximum_message_size = 16; > + attributes.delivery_thread_priority = 0; > + attributes.maximum_to_dequeue_per_period = 1; > + attributes.delivery_thread_period = > RTEMS_MILLISECONDS_TO_TICKS(1000); > + > + sc = rtems_regulator_create(&attributes, ®ulator); > + rtems_test_assert(sc == RTEMS_INVALID_PRIORITY); > +} > + > +/** > + * @ingroup RegulatorTests > + * @brief Verify rtems_regulator_create rtems_partition_create error > + * > + * This unit test verifies that rtems_regulator_create() correctly returns an > + * error when the call to rtems_partition_create() fails. > + */ > +static void test_regulator_create_partition_create_fails(void) > +{ > + rtems_status_code sc; > + rtems_id partition_id; > + unsigned long partition_area[16]; > + rtems_regulator_attributes attributes; > + rtems_regulator_instance *regulator; > + > + sc = rtems_partition_create( > + rtems_build_name('T', 'P', 'T', 'P'), > + partition_area, > + 16 * sizeof(unsigned long), > + 2 * sizeof(unsigned long), > + RTEMS_DEFAULT_ATTRIBUTES, > + &partition_id > + ); > + rtems_test_assert(sc == RTEMS_SUCCESSFUL); > + > + (void) memset(&attributes, 0, sizeof(rtems_regulator_attributes)); > + > + attributes.deliverer = test_regulator_deliverer; > + attributes.maximum_messages = 10; > + attributes.maximum_message_size = 16; > + attributes.delivery_thread_priority = 8; > + attributes.maximum_to_dequeue_per_period = 1; > + attributes.delivery_thread_period = > RTEMS_MILLISECONDS_TO_TICKS(1000); > + > + sc = rtems_regulator_create(&attributes, ®ulator); > + rtems_test_assert(sc == RTEMS_TOO_MANY); > + > + sc = rtems_partition_delete(partition_id); > + rtems_test_assert(sc == RTEMS_SUCCESSFUL); > +} > + > +/** > + * @ingroup RegulatorTests > + * @brief Verify rtems_regulator_create rtems_message_queue_create error > + * > + * This unit test verifies that rtems_regulator_create() correctly returns an > + * error when the call to rtems_message_queue_create() fails. > + */ > +static void test_regulator_create_message_queue_create_fails(void) > +{ > + rtems_status_code sc; > + rtems_id queue_id; > + rtems_regulator_attributes attributes; > + rtems_regulator_instance *regulator; > + > + sc = rtems_message_queue_create( > + rtems_build_name('T', 'Q', 'T', 'Q'), > + 4, > + sizeof(unsigned long), > + RTEMS_DEFAULT_ATTRIBUTES, > + &queue_id > + ); > + rtems_test_assert(sc == RTEMS_SUCCESSFUL); > + > + (void) memset(&attributes, 0, sizeof(rtems_regulator_attributes)); > + > + attributes.deliverer = test_regulator_deliverer; > + attributes.maximum_messages = 10; > + attributes.maximum_message_size = 16; > + attributes.delivery_thread_priority = 8; > + attributes.maximum_to_dequeue_per_period = 1; > + attributes.delivery_thread_period = > RTEMS_MILLISECONDS_TO_TICKS(1000); > + > + sc = rtems_regulator_create(&attributes, ®ulator); > + rtems_test_assert(sc == RTEMS_TOO_MANY); > + > + sc = rtems_message_queue_delete(queue_id); > + rtems_test_assert(sc == RTEMS_SUCCESSFUL); > +} > + > +/** > + * @ingroup RegulatorTests > + * @brief Verify rtems_regulator_create rtems_task_create error > + * > + * This unit test verifies that rtems_regulator_create() correctly returns an > + * error when the call to rtems_task_create() fails. > + */ > +static void test_regulator_create_task_create_fails(void) > +{ > + rtems_status_code sc; > + rtems_id task_id; > + rtems_regulator_attributes attributes; > + rtems_regulator_instance *regulator; > + > + sc = rtems_task_create( > + rtems_build_name('T', 'T', 'T', 'T'), > + 80, > + 0, > + RTEMS_DEFAULT_MODES, > + RTEMS_DEFAULT_ATTRIBUTES, > + &task_id > + ); > + rtems_test_assert(sc == RTEMS_SUCCESSFUL); > + > + (void) memset(&attributes, 0, sizeof(rtems_regulator_attributes)); > + > + attributes.deliverer = test_regulator_deliverer; > + attributes.maximum_messages = 10; > + attributes.maximum_message_size = 16; > + attributes.delivery_thread_priority = 8; > + attributes.maximum_to_dequeue_per_period = 1; > + attributes.delivery_thread_period = > RTEMS_MILLISECONDS_TO_TICKS(1000); > + > + sc = rtems_regulator_create(&attributes, ®ulator); > + rtems_test_assert(sc == RTEMS_TOO_MANY); > + > + sc = rtems_task_delete(task_id); > + rtems_test_assert(sc == RTEMS_SUCCESSFUL); > +} > + > +/** > + * @ingroup RegulatorTests > + * @brief Verify Regulator Output Thread Handles Error on Period Create > + * > + * This unit test verifies that regulator output thread correctly exits > + * when the call to rtems_rate_monotonic_create() fails. > + * > + * This error condition/path cannot be directly detected via a return code, > + * It is verified via a debugger or code coverage reports. > + */ > +static void test_regulator_create_rate_monotonic_create_fails(void) > +{ > + rtems_status_code sc; > + rtems_id period_id; > + rtems_regulator_attributes attributes; > + rtems_regulator_instance *regulator; > + > + sc = rtems_rate_monotonic_create( > + rtems_build_name('T', 'S', 'T', 'P'), > + &period_id > + ); > + rtems_test_assert(sc == RTEMS_SUCCESSFUL); > + > + (void) memset(&attributes, 0, sizeof(rtems_regulator_attributes)); > + > + attributes.deliverer = test_regulator_deliverer; > + attributes.maximum_messages = 10; > + attributes.maximum_message_size = 16; > + attributes.delivery_thread_priority = 8; > + attributes.maximum_to_dequeue_per_period = 1; > + attributes.delivery_thread_period = > RTEMS_MILLISECONDS_TO_TICKS(1000); > + > + sc = rtems_regulator_create(&attributes, ®ulator); > + rtems_test_assert(sc == RTEMS_SUCCESSFUL); > + > + /* > + * Let the output thread execute and encounter the create error. > + */ > + > + sleep(1); > + > + /* > + * Now deallocate the resources allocated earlier > + */ > + sc = rtems_regulator_delete(regulator, FIVE_SECONDS); > + rtems_test_assert(sc == RTEMS_SUCCESSFUL); > + > + sc = rtems_rate_monotonic_delete(period_id); > + rtems_test_assert(sc == RTEMS_SUCCESSFUL); > +} > + > +/** > + * @ingroup RegulatorTests > + * @brief Verify rtems_regulator_delete NULL regulator error > + * > + * This unit test verifies that rtems_regulator_delete() returns an error > when > + * the regulator argument is NULL. > + */ > +static void test_regulator_delete_null_regulator(void) > +{ > + rtems_status_code sc; > + > + sc = rtems_regulator_delete(NULL, FIVE_SECONDS); > + rtems_test_assert(sc == RTEMS_INVALID_ADDRESS); > +} > + > +/** > + * @ingroup RegulatorTests > + * @brief Verify rtems_regulator_delete uninitialized regulator error > + * > + * This unit test verifies that rtems_regulator_delete() returns an error > when > + * the regulator argument is uninitialized. > + */ > +static void test_regulator_delete_uninitialized_regulator(void) > +{ > + rtems_status_code sc; > + rtems_regulator_instance regulator; > + > + (void) memset(®ulator, 0, sizeof(regulator)); > + > + sc = rtems_regulator_delete(®ulator, 0); > + rtems_test_assert(sc == RTEMS_INCORRECT_STATE); > +} > + > +/** > + * @ingroup RegulatorTests > + * @brief Verify rtems_regulator_delete successful case > + * > + * This unit test verifies that rtems_regulator_delete() can be successfully > + * deleted. > + */ > +static void test_regulator_delete_OK(void) > +{ > + rtems_status_code sc; > + rtems_regulator_instance *regulator; > + > + regulator = test_regulator_create_regulator_OK(); > + rtems_test_assert(regulator != NULL); > + > + sc = rtems_regulator_delete(regulator, FIVE_SECONDS); > + rtems_test_assert(sc == RTEMS_SUCCESSFUL); > +} > + > +/** > + * @ingroup RegulatorTests > + * @brief Verify rtems_regulator_obtain_buffer NULL regulator error > + * > + * This unit test verifies that rtems_regulator_obtain_buffer() returns an > error when > + * the regulator argument is NULL. > + */ > +static void test_regulator_obtain_buffer_null_regulator(void) > +{ > + rtems_status_code sc; > + void *buffer; > + > + sc = rtems_regulator_obtain_buffer(NULL, &buffer); > + rtems_test_assert(sc == RTEMS_INVALID_ADDRESS); > +} > + > +/** > + * @ingroup RegulatorTests > + * @brief Verify rtems_regulator_obtain_buffer uninitialized regulator error > + * > + * This unit test verifies that rtems_regulator_obtain_buffer() returns an > error when > + * the regulator argument is uninitialized. > + */ > +static void test_regulator_obtain_buffer_uninitialized_regulator(void) > +{ > + rtems_status_code sc; > + rtems_regulator_instance regulator; > + void *buffer; > + > + (void) memset(®ulator, 0, sizeof(regulator)); > + > + sc = rtems_regulator_obtain_buffer(®ulator, &buffer); > + rtems_test_assert(sc == RTEMS_INCORRECT_STATE); > +} > + > +/** > + * @ingroup RegulatorTests > + * @brief Verify rtems_regulator_obtain_buffer successful case > + * > + * This unit test verifies that rtems_regulator_obtain_buffer() can be > successfully > + * obtained from an initialized regulator. > + */ > +static void test_regulator_obtain_buffer_OK(void) > +{ > + rtems_status_code sc; > + rtems_regulator_instance *regulator; > + void *buffer; > + > + regulator = test_regulator_create_regulator_OK(); > + rtems_test_assert(regulator != NULL); > + > + sc = rtems_regulator_obtain_buffer(regulator, &buffer); > + rtems_test_assert(sc == RTEMS_SUCCESSFUL); > + rtems_test_assert(buffer != NULL); > + > + /* > + * Not really testing this here but cannot delete underlying partition > + * if there are buffers outstanding. > + */ > + sc = rtems_regulator_release_buffer(regulator, buffer); > + rtems_test_assert(sc == RTEMS_SUCCESSFUL); > + rtems_test_assert(buffer != NULL); > + > + sc = rtems_regulator_delete(regulator, FIVE_SECONDS); > + rtems_test_assert(sc == RTEMS_SUCCESSFUL); > +} > + > +/** > + * @ingroup RegulatorTests > + * @brief Verify rtems_regulator_release_buffer NULL regulator error > + * > + * This unit test verifies that rtems_regulator_release_buffer() returns an > error when > + * the regulator argument is NULL. > + */ > +static void test_regulator_release_buffer_null_regulator(void) > +{ > + rtems_status_code sc; > + void *buffer; > + > + sc = rtems_regulator_release_buffer(NULL, &buffer); > + rtems_test_assert(sc == RTEMS_INVALID_ADDRESS); > +} > + > +/** > + * @ingroup RegulatorTests > + * @brief Verify rtems_regulator_release_buffer uninitialized regulator error > + * > + * This unit test verifies that rtems_regulator_release_buffer() returns an > + * error when the regulator argument is uninitialized. > + */ > +static void test_regulator_release_buffer_uninitialized_regulator(void) > +{ > + rtems_status_code sc; > + rtems_regulator_instance regulator; > + void *buffer; > + > + (void) memset(®ulator, 0, sizeof(regulator)); > + > + sc = rtems_regulator_release_buffer(®ulator, &buffer); > + rtems_test_assert(sc == RTEMS_INCORRECT_STATE); > +} > + > +/** > + * @ingroup RegulatorTests > + * @brief Verify rtems_regulator_release_buffer successful case > + * > + * This unit test verifies that rtems_regulator_release_buffer() can be > successfully > + * invoked with a buffer previously allocated by > rtems_regulator_obtain_buffer(). > + */ > +static void test_regulator_release_buffer_OK(void) > +{ > + rtems_status_code sc; > + rtems_regulator_instance *regulator; > + void *buffer; > + > + regulator = test_regulator_create_regulator_OK(); > + rtems_test_assert(regulator != NULL); > + > + sc = rtems_regulator_obtain_buffer(regulator, &buffer); > + rtems_test_assert(sc == RTEMS_SUCCESSFUL); > + rtems_test_assert(buffer != NULL); > + > + sc = rtems_regulator_release_buffer(regulator, buffer); > + rtems_test_assert(sc == RTEMS_SUCCESSFUL); > + > + sc = rtems_regulator_delete(regulator, FIVE_SECONDS); > + rtems_test_assert(sc == RTEMS_SUCCESSFUL); > +} > + > +/** > + * @ingroup RegulatorTests > + * @brief Verify rtems_regulator_send NULL regulator error > + * > + * This unit test verifies that rtems_regulator_send() returns an error when > + * the regulator argument is NULL. > + */ > +static void test_regulator_send_null_regulator(void) > +{ > + rtems_status_code sc; > + void *buffer; > + size_t length; > + > + buffer = &length; > + length = sizeof(size_t); > + > + sc = rtems_regulator_send(NULL, buffer, length); > + rtems_test_assert(sc == RTEMS_INVALID_ADDRESS); > +} > + > +/** > + * @ingroup RegulatorTests > + * @brief Verify rtems_regulator_send NULL message error > + * > + * This unit test verifies that rtems_regulator_send() returns an error when > + * the message argument is NULL. > + */ > +static void test_regulator_send_null_message(void) > +{ > + rtems_status_code sc; > + size_t length; > + rtems_regulator_instance regulator; > + > + length = sizeof(size_t); > + > + sc = rtems_regulator_send(®ulator, NULL, length); > + rtems_test_assert(sc == RTEMS_INVALID_ADDRESS); > +} > + > +/** > + * @ingroup RegulatorTests > + * @brief Verify rtems_regulator_send zero length message error > + * > + * This unit test verifies that rtems_regulator_send() returns an > + * error when the message length is 0. > + */ > +static void test_regulator_send_length_is_zero(void) > +{ > + rtems_status_code sc; > + rtems_regulator_instance regulator; > + void *buffer; > + size_t length; > + > + buffer = &length; > + length = 0; > + > + sc = rtems_regulator_send(®ulator, buffer, length); > + rtems_test_assert(sc == RTEMS_INVALID_NUMBER); > +} > + > +/** > + * @ingroup RegulatorTests > + * @brief Verify rtems_regulator_send uninitialized regulator error > + * > + * This unit test verifies that rtems_regulator_send() returns an > + * error when the regulator argument is uninitialized. > + */ > +static void test_regulator_send_uninitialized_regulator(void) > +{ > + rtems_status_code sc; > + rtems_regulator_instance regulator; > + void *buffer; > + size_t length; > + > + buffer = &length; > + length = sizeof(size_t); > + > + (void) memset(®ulator, 0, sizeof(regulator)); > + > + sc = rtems_regulator_send(®ulator, buffer, length); > + rtems_test_assert(sc == RTEMS_INCORRECT_STATE); > +} > + > +/** > + * @ingroup RegulatorTests > + * @brief Verify Cannot Delete with Message Outstanding > + * > + * This unit test verifies that when the regulator is successfully > + * initialized, that it cannot be deleted with an undelivered message. > + * It also verifies some basic statistics are working. > + */ > +static void test_regulator_cannot_delete_with_outstanding(void) > +{ > + rtems_status_code sc; > + rtems_regulator_instance *regulator; > + char message[MAXIMUM_MESSAGE_LENGTH]; > + void *buffer; > + size_t length; > + int match; > + rtems_regulator_attributes attributes = { > + .deliverer = test_regulator_deliverer_logger, > + .deliverer_context = &deliverer_logger_context, > + .maximum_message_size = 16, > + .maximum_messages = 10, > + .delivery_thread_priority = 16, > + .delivery_thread_stack_size = 0, > + .delivery_thread_period = RTEMS_MILLISECONDS_TO_TICKS(250), > + .maximum_to_dequeue_per_period = 3 > + }; > + rtems_regulator_statistics stats; > + > + sc = rtems_regulator_create(&attributes, ®ulator); > + rtems_test_assert(sc == RTEMS_SUCCESSFUL); > + rtems_test_assert(regulator != NULL); > + > + deliverer_logger_context.regulator = regulator; > + > + delivered_messages_reset(); > + > + // Ensure statistics show no buffers obtained or processed > + sc = rtems_regulator_get_statistics(regulator, &stats); > + rtems_test_assert(sc == RTEMS_SUCCESSFUL); > + rtems_test_assert(stats.obtained == 0); > + rtems_test_assert(stats.released == 0); > + rtems_test_assert(stats.delivered == 0); > + rtems_test_assert(stats.period_statistics.count == 0); > + rtems_test_assert(stats.period_statistics.missed_count == 0); > + > + // Obtain a buffer which should change the statistics > + sc = rtems_regulator_obtain_buffer(regulator, &buffer); > + rtems_test_assert(sc == RTEMS_SUCCESSFUL); > + rtems_test_assert(buffer != NULL); > + > + // Ensure statistics show one buffer obtained > + sc = rtems_regulator_get_statistics(regulator, &stats); > + rtems_test_assert(sc == RTEMS_SUCCESSFUL); > + rtems_test_assert(stats.obtained == 1); > + rtems_test_assert(stats.released == 0); > + rtems_test_assert(stats.delivered == 0); > + rtems_test_assert(stats.period_statistics.count == 0); > + rtems_test_assert(stats.period_statistics.missed_count == 0); > + > + > + // Format and send the message -- statistics do not change > + length = snprintf(message, MAXIMUM_MESSAGE_LENGTH, "message %d", 1024) + 1; > + strcpy(buffer, message); > + > + sc = rtems_regulator_send(regulator, buffer, length); > + rtems_test_assert(sc == RTEMS_SUCCESSFUL); > + > + // Ensure statistics show one buffer obtained > + sc = rtems_regulator_get_statistics(regulator, &stats); > + rtems_test_assert(sc == RTEMS_SUCCESSFUL); > + rtems_test_assert(stats.obtained == 1); > + rtems_test_assert(stats.released == 0); > + rtems_test_assert(stats.delivered == 0); > + rtems_test_assert(stats.period_statistics.count == 0); > + rtems_test_assert(stats.period_statistics.missed_count == 0); > + > + // This is the actual failing case -- cannot delete w/outstanding > + sc = rtems_regulator_delete(regulator, FIVE_SECONDS); > + rtems_test_assert(sc == RTEMS_RESOURCE_IN_USE); > + > + // Now let the deliveries happen > + sleep(1); > + > + // Ensure statistics show all buffers released > + sc = rtems_regulator_get_statistics(regulator, &stats); > + rtems_test_assert(sc == RTEMS_SUCCESSFUL); > + rtems_test_assert(stats.obtained == 1); > + rtems_test_assert(stats.released == 1); > + rtems_test_assert(stats.delivered == 1); > + rtems_test_assert(stats.period_statistics.count != 0); > + rtems_test_assert(stats.period_statistics.missed_count == 0); > + > + rtems_test_assert(delivered_message_count == 1); > + match = strncmp( > + delivered_messages[0].message, > + message, > + MAXIMUM_MESSAGE_LENGTH > + ); > + rtems_test_assert(match == 0); > + > + sc = rtems_regulator_delete(regulator, FIVE_SECONDS); > + rtems_test_assert(sc == RTEMS_SUCCESSFUL); > + > + deliverer_logger_context.regulator = NULL; > +} > + > +/** > + * @ingroup RegulatorTests > + * @brief Verify rtems_regulator_send and output thread delivers message > + * > + * This unit test verifies that when the regulator is > + * successfully initialized and used as expected, a message sent via > + * rtems_regulator_send() is delivered as expected. > + */ > +static void test_regulator_send_one_message_OK(void) > +{ > + rtems_status_code sc; > + rtems_regulator_instance *regulator; > + char message[MAXIMUM_MESSAGE_LENGTH]; > + void *buffer; > + size_t length; > + int match; > + rtems_regulator_attributes attributes = { > + .deliverer = test_regulator_deliverer_logger, > + .deliverer_context = &deliverer_logger_context, > + .maximum_message_size = 16, > + .maximum_messages = 10, > + .delivery_thread_priority = 16, > + .delivery_thread_stack_size = 0, > + .delivery_thread_period = RTEMS_MILLISECONDS_TO_TICKS(250), > + .maximum_to_dequeue_per_period = 3 > + }; > + > + sc = rtems_regulator_create(&attributes, ®ulator); > + rtems_test_assert(sc == RTEMS_SUCCESSFUL); > + rtems_test_assert(regulator != NULL); > + > + deliverer_logger_context.regulator = regulator; > + > + delivered_messages_reset(); > + > + sc = rtems_regulator_obtain_buffer(regulator, &buffer); > + rtems_test_assert(sc == RTEMS_SUCCESSFUL); > + rtems_test_assert(buffer != NULL); > + > + length = snprintf(message, MAXIMUM_MESSAGE_LENGTH, "message %d", 1024) + 1; > + strcpy(buffer, message); > + > + sc = rtems_regulator_send(regulator, buffer, length); > + rtems_test_assert(sc == RTEMS_SUCCESSFUL); > + > + sleep(1); > + > + rtems_test_assert(delivered_message_count == 1); > + match = strncmp( > + delivered_messages[0].message, > + message, > + MAXIMUM_MESSAGE_LENGTH > + ); > + rtems_test_assert(match == 0); > + > + sc = rtems_regulator_delete(regulator, FIVE_SECONDS); > + rtems_test_assert(sc == RTEMS_SUCCESSFUL); > + > + deliverer_logger_context.regulator = NULL; > +} > + > +/** > + * @ingroup RegulatorTests > + * @brief Verify rtems_regulator_send and output thread delivers messages > + * > + * This unit test verifies that when the regulator is successfully > initialized > + * and used as expected, and multiple messages are sent via > rtems_regulator_send() > + * that they are delivered as expected. > + */ > +#include <stdio.h> > +static void test_regulator_send_multiple_messages_OK(void) > +{ > + rtems_status_code sc; > + rtems_regulator_instance *regulator; > + char message[MAXIMUM_MESSAGE_LENGTH]; > + void *buffer; > + size_t length; > + int match; > + int i; > + time_t base_time; > + time_t tmp_time; > + rtems_interval base_ticks; > + rtems_interval ticks; > + rtems_interval ticks_per_second; > + > + rtems_regulator_attributes attributes = { > + .deliverer = test_regulator_deliverer_logger, > + .deliverer_context = &deliverer_logger_context, > + .maximum_message_size = MAXIMUM_MESSAGE_LENGTH, > + .maximum_messages = 10, > + .delivery_thread_priority = 16, > + .delivery_thread_stack_size = 0, > + .delivery_thread_period = RTEMS_MILLISECONDS_TO_TICKS(1000), > + .maximum_to_dequeue_per_period = 2 > + }; > + > + delivered_messages_reset(); > + > + sc = rtems_regulator_create(&attributes, ®ulator); > + rtems_test_assert(sc == RTEMS_SUCCESSFUL); > + rtems_test_assert(regulator != NULL); > + > + deliverer_logger_context.regulator = regulator; > + > + /* > + * Ensure the messages are sent on a second boundary to ensure the > + * output thread will process them as expected. > + */ > + tmp_time = time(NULL); > + do { > + base_time = time(NULL); > + } while (tmp_time == base_time); > + > + /** > + * Send five messages as a burst which will need to be smoothly sent at > + * the configured rate. > + */ > + for (i=1 ; i <= 5 ; i++) { > + sc = rtems_regulator_obtain_buffer(regulator, &buffer); > + rtems_test_assert(sc == RTEMS_SUCCESSFUL); > + rtems_test_assert(buffer != NULL); > + > + length = snprintf(message, MAXIMUM_MESSAGE_LENGTH, "message %d", i); > + strcpy(buffer, message); > + > + sc = rtems_regulator_send(regulator, buffer, length); > + rtems_test_assert(sc == RTEMS_SUCCESSFUL); > + } > + > + /* > + * Let the output thread executed and deliver the messages. > + */ > + sleep(5); > + > + /** > + * Ensure the five messages were delivered as follows: > + * > + * - deliver all 5 > + * - contents are "message N" where N is 1 to 5 > + * - message 1 and 2 delivered during the first second > + * - message 3 and 4 delivered during the second second > + * - message 5 delivered during the third second > + * - no further messages delivered > + */ > + > + rtems_test_assert(delivered_message_count == 5); > + > + for (i=0 ; i < 5 ; i++) { > + (void) snprintf(message, MAXIMUM_MESSAGE_LENGTH, "message %d", i+1); > +// printf("%d %s\n", i, delivered_messages[i].message); > + match = strncmp( > + delivered_messages[i].message, > + message, > + MAXIMUM_MESSAGE_LENGTH > + ); > + rtems_test_assert(match == 0); > + } > + > + /** > + * Verify that messages were delivered in the proper groups. Check that > + * the delivery time matches expectations. > + */ > + rtems_test_assert(delivered_messages[0].processed == > delivered_messages[1].processed); > + rtems_test_assert(delivered_messages[1].processed != > delivered_messages[2].processed); > + rtems_test_assert(delivered_messages[2].processed == > delivered_messages[3].processed); > + rtems_test_assert(delivered_messages[3].processed != > delivered_messages[4].processed); > + > + /** > + * Verify that the message groups were properly spaced temporally. They > + * should be one second apart. > + */ > + ticks_per_second = rtems_clock_get_ticks_per_second(); > + > + base_ticks = delivered_messages[1].processed; > + ticks = delivered_messages[2].processed; > + rtems_test_assert(ticks_per_second == ticks - base_ticks); > + > + base_ticks = delivered_messages[3].processed; > + ticks = delivered_messages[4].processed; > + rtems_test_assert(ticks_per_second == ticks - base_ticks); > + > + sc = rtems_regulator_delete(regulator, FIVE_SECONDS); > + rtems_test_assert(sc == RTEMS_SUCCESSFUL); > + > + deliverer_logger_context.regulator = NULL; > +} > + > +/* Necessary prototype */ > +rtems_task test_regulator(rtems_task_argument); > + > +/** > + * @ingroup RegulatorTestshttps://devel.rtems.org/milestone/6.1 > + * @brief Test entry task which invokes test cases > + */ > +rtems_task test_regulator(rtems_task_argument arg) > +{ > + (void) arg; > + > + TEST_BEGIN(); > + > + malloc_trigger_reset(); > + > + test_regulator_create_max_dequeue_zero(); > + test_regulator_create_null_attributes(); > + test_regulator_create_null_regulator(); > + test_regulator_create_deliverer_is_null(); > + test_regulator_create_maximum_messages_is_zero(); > + test_regulator_create_maximum_message_size_is_zero(); > + test_regulator_create_maximum_to_dequeue_per_period_is_zero(); > + test_regulator_create_malloc_regulator_fails(); > + test_regulator_create_malloc_buffers_fails(); > + test_regulator_create_delivery_thread_priority_is_zero(); > + test_regulator_create_partition_create_fails(); > + test_regulator_create_message_queue_create_fails(); > + test_regulator_create_task_create_fails(); > + test_regulator_create_rate_monotonic_create_fails(); > + > + test_regulator_delete_null_regulator(); > + test_regulator_delete_uninitialized_regulator(); > + test_regulator_delete_OK(); > + > + test_regulator_obtain_buffer_null_regulator(); > + test_regulator_obtain_buffer_uninitialized_regulator(); > + test_regulator_obtain_buffer_OK(); > + > + test_regulator_release_buffer_null_regulator(); > + test_regulator_release_buffer_uninitialized_regulator(); > + test_regulator_release_buffer_OK(); > + > + test_regulator_send_null_regulator(); > + test_regulator_send_null_message(); > + test_regulator_send_length_is_zero(); > + test_regulator_send_uninitialized_regulator(); > + > + test_regulator_send_one_message_OK(); > + test_regulator_cannot_delete_with_outstanding(); > + > + test_regulator_send_multiple_messages_OK(); > + > + TEST_END(); > + > + rtems_test_exit(0); > +} > diff --git a/testsuites/libtests/regulator01/regulator01.doc > b/testsuites/libtests/regulator01/regulator01.doc > new file mode 100644 > index 0000000000..ff4e8005ec > --- /dev/null > +++ b/testsuites/libtests/regulator01/regulator01.doc > @@ -0,0 +1,67 @@ > +# SPDX-License-Identifier: BSD-2-Clause > + > +# Copyright (c) 2023 OAR Corporation > +# > +# Redistribution and use in source and binary forms, with or without > +# modification, are permitted provided that the following conditions > +# are met: > +# 1. Redistributions of source code must retain the above copyright > +# notice, this list of conditions and the following disclaimer. > +# 2. Redistributions in binary form must reproduce the above copyright > +# notice, this list of conditions and the following disclaimer in the > +# documentation and/or other materials provided with the distribution. > +# > +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" > +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE > +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE > +# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE > +# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR > +# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF > +# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS > +# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN > +# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) > +# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE > +# POSSIBILITY OF SUCH DAMAGE. > +# > + > +This file describes the directives and concepts tested by this test set. > + > +test set name: regulator01 > + > +directives: > + + rtems_regulator_create > + + rtems_regulator_delete > + + rtems_regulator_obtain_buffer > + + rtems_regulator_release_buffer > + + rtems_regulator_send > + > +concepts > + + Verify rtems_regulator_create() maximum_to_dequeue_per_period > + + Verify rtems_regulator_create() NULL attributes error > + + Verify rtems_regulator_create NULL regulator error > + + Verify rtems_regulator_create deliverer is NULL > + + Verify rtems_regulator_create maximum_messages is 0 error > + + Verify rtems_regulator_create maximum_message_size is 0 error > + + Verify rtems_regulator_create maximum_to_dequeue_per_period is 0 error > + + Verify rtems_regulator_create returns error on failure to allocate > regulator > + + Verify rtems_regulator_create returns error on failure to allocate > buffers > + + Verify rtems_regulator_create and delete work > + + Verify rtems_regulator_create rtems_partition_create error > + + Verify rtems_regulator_create rtems_message_queue_create error > + + Verify rtems_regulator_create rtems_task_create error > + + Verify Regulator Output Thread Handles Error on Period Create > + + Verify rtems_regulator_delete NULL regulator error > + + Verify rtems_regulator_delete uninitialized regulator error > + + Verify rtems_regulator_delete successful case > + + Verify rtems_regulator_obtain_buffer NULL regulator error > + + Verify rtems_regulator_obtain_buffer uninitialized regulator error > + + Verify rtems_regulator_obtain_buffer successful case > + + Verify rtems_regulator_release_buffer NULL regulator error > + + Verify rtems_regulator_release_buffer uninitialized regulator error > + + Verify rtems_regulator_release_buffer successful case > + + Verify rtems_regulator_send NULL regulator error > + + Verify rtems_regulator_send NULL message error > + + Verify rtems_regulator_send zero length message error > + + Verify rtems_regulator_send uninitialized regulator error > + + Verify rtems_regulator_send and output thread delivers message > + + Verify rtems_regulator_send and cannot delete with outstanding messages > diff --git a/testsuites/libtests/regulator01/rtems_config.c > b/testsuites/libtests/regulator01/rtems_config.c > new file mode 100644 > index 0000000000..ca96e1b1dd > --- /dev/null > +++ b/testsuites/libtests/regulator01/rtems_config.c > @@ -0,0 +1,59 @@ > +/* SPDX-License-Identifier: BSD-2-Clause */ > + > +/** > + * @file > + * > + * @brief RTEMS Configuration for regulator tests > + */ > + > +/* > + * COPYRIGHT (c) 2022. * On-Line Applications Research Corporation (OAR). > + * > + * Redistribution and use in source and binary forms, with or without > + * modification, are permitted provided that the following conditions > + * are met: > + * 1. Redistributions of source code must retain the above copyright > + * notice, this list of conditions and the following disclaimer. > + * 2. Redistributions in binary form must reproduce the above copyright > + * notice, this list of conditions and the following disclaimer in the > + * documentation and/or other materials provided with the distribution. > + * > + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS > IS" > + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE > + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE > + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE > + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR > + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF > + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS > + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN > + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) > + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE > + * POSSIBILITY OF SUCH DAMAGE. > + */ > + > + > +#include <rtems.h> > + > +rtems_task test_regulator(rtems_task_argument); > + > +#include <bsp.h> /* for device driver prototypes */ > + > +/* NOTICE: the clock driver is explicitly disabled */ > +#define CONFIGURE_APPLICATION_NEEDS_CLOCK_DRIVER > +#define CONFIGURE_APPLICATION_NEEDS_CONSOLE_DRIVER > + > +#define CONFIGURE_RTEMS_INIT_TASKS_TABLE > +#define CONFIGURE_INIT_TASK_ENTRY_POINT test_regulator > +#define CONFIGURE_INIT_TASK_ATTRIBUTES RTEMS_FLOATING_POINT > + > +/* Use hard limits to make it easier to trip object creation errors */ > +#define CONFIGURE_MAXIMUM_TASKS 2 > +#define CONFIGURE_MAXIMUM_MESSAGE_QUEUES 1 > +#define CONFIGURE_MAXIMUM_PARTITIONS 1 > +#define CONFIGURE_MAXIMUM_PERIODS 1 > + > +#define CONFIGURE_UNIFIED_WORK_AREAS > +#define CONFIGURE_MINIMUM_TASK_STACK_SIZE (8 * 1024) > + > +#define CONFIGURE_INIT > +#include <rtems/confdefs.h> _______________________________________________ devel mailing list devel@rtems.org http://lists.rtems.org/mailman/listinfo/devel