Back to home page

LXR

 
 

    


File indexing completed on 2025-05-11 08:24:14

0001 /* SPDX-License-Identifier: BSD-2-Clause */
0002 
0003 /**
0004  * @file
0005  *
0006  * @ingroup RegulatorAPI
0007  *
0008  * @brief This header file defines the Regulator API.
0009  *
0010  */
0011 
0012 /*
0013  * Copyright (C) 2023 On-Line Applications Research Corporation (OAR)
0014  *
0015  * Redistribution and use in source and binary forms, with or without
0016  * modification, are permitted provided that the following conditions
0017  * are met:
0018  * 1. Redistributions of source code must retain the above copyright
0019  *    notice, this list of conditions and the following disclaimer.
0020  * 2. Redistributions in binary form must reproduce the above copyright
0021  *    notice, this list of conditions and the following disclaimer in the
0022  *    documentation and/or other materials provided with the distribution.
0023  *
0024  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
0025  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
0026  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
0027  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
0028  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
0029  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
0030  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
0031  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
0032  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
0033  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
0034  * POSSIBILITY OF SUCH DAMAGE.
0035  */
0036 
0037 /**
0038  * @defgroup RegulatorAPI Regulator API
0039  *
0040  * @brief Regulator APIs
0041  *
0042  * The Regulator provides a set of APIs to manage input sources which 
0043  * produces bursts of message traffic.
0044  *
0045  * The regulator is designed to sit logically between two entities -- a
0046  * source and a destination, where it limits the traffic sent to the
0047  * destination to prevent it from being flooded with messages from the
0048  * source. This can be used to accommodate bursts of input from a source
0049  * and meter it out to a destination.  The maximum number of messages
0050  * which can be buffered in the regulator is specified by the
0051  * @a maximum_messages field in the @a rtems_regulator_attributes
0052  * structure passed as an argument to @a rtems_regulator_create().
0053  *
0054  * The regulator library accepts an input stream of messages from a
0055  * source and delivers them to a destination. The regulator assumes that the
0056  * input stream from the source contains sporadic bursts of data which can
0057  * exceed the acceptable rate of the destination. By limiting the message rate,
0058  * the regulator prevents an overflow of messages.
0059  *
0060  * The regulator can be configured for the input buffering required to manage
0061  * the maximum burst and for the metering rate for the output. The output rate
0062  * is in messages per second. If the sender produces data too fast, the
0063  * regulator will buffer the configured number of messages.
0064  *
0065  * A configuration capability is provided to allow for adaptation to different
0066  * message streams. The regulator can also support running multiple instances,
0067  * which could be used on independent message streams.
0068  *
0069  * The regulator provides a simple interface to the application for avoiding
0070  * bursts of input from a fast source overflowing a slower destination.
0071  *
0072  * It is assumed that the application has a design limit on the number of
0073  * messages which may be buffered. All messages accepted by the regulator,
0074  * assuming no overflow on input, will eventually be output by the Delivery
0075  * thread.
0076  *
0077  * A regulator instance is used as follows from the producer/source side:
0078  *
0079  * @code
0080  *   while (1)
0081  *     use rtems_regulator_obtain_buffer to obtain a buffer
0082  *     input operation to fetch data into the buffer
0083  *     rtems_regulator_send(buffer, size of message)
0084  * @endcode
0085  *
0086  * The delivery of message buffers to the Destination and subsequent
0087  * release is performed in the context of the delivery thread by either
0088  * the delivery function or delivery thread. Details are below.
0089  *
0090  * The sequence diagram below shows the interaction between a message Source,
0091  * a Regulator instance, and RTEMS, given the usage described in the above
0092  * paragraphs.
0093  *
0094  * \startuml "Regulator Application Input Source Usage"
0095  *   Source -> Regulator : rtems_regulator_obtain_buffer(regulator, buffer)
0096  *   Regulator -> RTEMS : rtems_partition_get_buffer(id, buffer)
0097  *   RTEMS --> Regulator : rtems_status_code
0098  *   Regulator --> Source : rtems_status_code
0099  *   Source -> Regulator : rtems_regulator_send(regulator, message, length)
0100  *   Regulator -> RTEMS : rtems_message_queue_send(id, message, size)
0101  *   RTEMS --> Regulator : rtems_status_code
0102  *   Regulator --> Source : rtems_status_code
0103  * \enduml
0104  *
0105  * As illustrated in the sequence diagram, the Source usually corresponds
0106  * to application software reading a system input. The Source obtains a
0107  * buffer from the Regulator instance and fills it with incoming data.
0108  * The application explicitly obtaining a buffer and filling it in allows
0109  * for zero copy operations on the Source side.
0110  *
0111  * The Source then sends the buffer to the Regulator instance. The Regulator
0112  * the sends the buffer via a message queue which to the Delivery thread.
0113  * The Delivery thread executes periodically at a rate specified at
0114  * Regulation creation. At each period, the Delivery thread attempts to
0115  * receive up to a configured number of buffers and invoke the Delivery
0116  * function to deliver them to the Destination.
0117  *
0118  * The Delivery function is provided by the application for this
0119  * specific Regulator instance. Depending on the Destination, it may use
0120  * a function which copies the buffer contents (e.g., write()) or which
0121  * operates directly on the buffer contents (e.g. DMA from buffer). In
0122  * the case of a Destination which copies the buffer contents, the buffer
0123  * can be released via @a rtems_regulator_release_buffer() as soon as the
0124  * function or copying completes. In the case where the delivery uses the
0125  * buffer and returns, the call to @a rtems_regulator_release_buffer()
0126  * will occur when the use of the buffer is complete (e.g. completion
0127  * of DMA transfer).  This explicit and deliberate exposure of buffering
0128  * provides the application with the ability to avoid copying the contents.
0129  *
0130  * After the Source has sent the message to the Regulator instance,
0131  * the Source is free to process another input and the Regulator
0132  * instance will ensure that the buffer is delivered to the Delivery
0133  * function and Destination.
0134  *
0135  * The Regulator implementation uses the RTEMS Classic API Partition Manager
0136  * to manage the buffer pool and the RTEMS Classic API Message Queue
0137  * Manager to send the buffer to the Delivery thread.
0138  */
0139 
0140 #ifndef REGULATOR_H
0141 #define REGULATOR_H
0142 
0143 #include <stdlib.h>
0144 
0145 #include <rtems.h>
0146 
0147 /**
0148  * @ingroup RegulatorAPI
0149  *
0150  * @brief Regulator Delivery Function Type
0151  *
0152  * The user provides a function which is invoked to deliver a message
0153  * to the output. It is invoked by the Delivery thread created as part
0154  * of @a rtems_regulator_create(). The priority and stack size of the
0155  * Delivery thread are specified in the regulator attribute set.
0156  *
0157  * It takes three parameters:
0158  *
0159  * @param[in] context is an untyped pointer to a user context
0160  * @param[in] message points to the message
0161  * @param[in] length is the message size
0162  *
0163  * The following is an example deliverer function. It assumes that the
0164  * application has defined the my_context_t structure and it has at least
0165  * the socket field. The @a message passed in originated with an
0166  * application source which obtained the @a message buffer using
0167  * @a rtems_regulator_obtain_buffer(), filled it in with source data,
0168  * and used @a rtems_regulator_send() to hand to the regulator instance
0169  * for later delivery.
0170  *
0171  * @code
0172  *   bool my_deliverer(
0173  *     void     *context,
0174  *     void     *message,
0175  *     size_t    length
0176  *    )
0177  *    {
0178  *       my_context_t *my_context;
0179  *
0180  *       my_context = (my_context_t *)context;
0181  *
0182  *       write(my_context->socket, message, length);
0183  *       rtems_regulator_release_buffer(message);
0184  *       // return false to indicate we released the buffer
0185  *       return false;
0186  *     }
0187  * @endcode
0188  *
0189  * The delivery function returns true to indicate that the delivery thread
0190  * should release the buffer or false to indicate that it released the
0191  * buffer.  If the delivery function invokes a function like @a write()
0192  * to deliver the message to the destination, then the buffer can be
0193  * released immediately after the call. If the delivery function does
0194  * something like setting up a DMA transfer of the buffer, it cannot be
0195  * released until after the DMA is complete.
0196  *
0197  * The following sequence diagram shows the behavior of the Delivery thread
0198  * body and its interaction with the user-supplied deliverer() function.
0199  *
0200  * \startuml "Regulator Delivery Thread Body"
0201  *   loop while (1)
0202  *     "Delivery Thread" -> RTEMS : rtems_rate_monotonic_period(id, delivery_thread_period)
0203  *     loop for 0 : maximum_to_dequeue_per_period
0204  *       "Delivery Thread" -> RTEMS : rtems_message_queue_receive(id, message, size, wait, 0)
0205  *       RTEMS --> "Delivery Thread" : rtems_status_code
0206  *       group if [rtems_status_code != RTEMS_SUCCESSFUL]
0207  *         RTEMS -> "Delivery Thread" : break
0208  *       end
0209  *       "Delivery Thread" -> Application : deliverer(context, buffer, length)
0210  *       "Delivery Thread" -> RTEMS : rtems_partition_return_buffer(id, buffer)
0211  *       RTEMS --> "Delivery Thread" : rtems_status_code
0212  *     end
0213  *   end
0214  * \enduml
0215  *
0216  * In the above sequence diagram, the key points are:
0217  *
0218  *   -# The Delivery Thread Body is periodically executed.
0219  *   -# During each period, up to the instance configuration parameter
0220  *      @a maximum_to_dequeue_per_period may be dequeued and
0221  *      passed the application's delivery function for processing.
0222  *
0223  * Note that the application explicitly obtains buffers from the
0224  * regulator instance but that the release may be done by Delivery
0225  * Thread, the Delivery function, or later when the buffer contents
0226  * are transferred.
0227  */
0228 typedef bool (*rtems_regulator_deliverer)(
0229   void     *context,
0230   void     *message,
0231   size_t    length
0232 );
0233 
0234 /**
0235  * @ingroup RegulatorAPI
0236  *
0237  * @brief Attributes for Regulator Instance
0238  *
0239  * An instance of this structure must be populated by the application
0240  * before creating an instance of the regulator. These settings tailor
0241  * the behavior of the regulator instance.
0242  */
0243 typedef struct {
0244   /** Application function to invoke to output a message to the destination*/
0245   rtems_regulator_deliverer deliverer;
0246 
0247   /** Context pointer to pass to deliver function */
0248   void  *deliverer_context;
0249 
0250   /** Maximum size message to process */
0251   size_t  maximum_message_size;
0252 
0253   /** Maximum number of messages to be able to buffer */
0254   size_t  maximum_messages;
0255 
0256   /** Priority of Delivery thread */
0257   rtems_task_priority delivery_thread_priority;
0258 
0259   /** Stack size of Delivery thread */
0260   size_t delivery_thread_stack_size;
0261 
0262   /** Period (in ticks) of Delivery thread */
0263   rtems_interval delivery_thread_period;
0264 
0265   /** Maximum messages to dequeue per period */
0266   size_t  maximum_to_dequeue_per_period;
0267 
0268 } rtems_regulator_attributes;
0269 
0270 /**
0271  * @ingroup RegulatorAPI
0272  *
0273  * @brief Statistics for Regulator Instance
0274  *
0275  * An instance of this structure is provided to the directive
0276  * @a rtems_regulator_get_statistics and is filled in by that service.
0277  */
0278 typedef struct {
0279   /** Number of successfully obtained buffers. */
0280   size_t    obtained;
0281   
0282   /** Number of successfully released buffers. */
0283   size_t    released;
0284 
0285   /** Number of successfully delivered buffers. */
0286   size_t    delivered;
0287 
0288   /** Rate Monotonic Period statistics for Delivery Thread */
0289   rtems_rate_monotonic_period_statistics period_statistics;
0290 
0291 } rtems_regulator_statistics;
0292 
0293 /**
0294  * @ingroup RegulatorAPI
0295  *
0296  * @brief Regulator Internal Structure
0297  */
0298 struct _Regulator_Control;
0299 
0300 /**
0301  * @ingroup RegulatorAPI
0302  *
0303  * @brief Regulator Instance
0304  *
0305  * This is used by the application as the handle to a Regulator instance.
0306  */
0307 typedef struct _Regulator_Control *rtems_regulator_instance;
0308 
0309 /**
0310  * @ingroup RegulatorAPI
0311  *
0312  * @brief Create a regulator
0313  *
0314  * This function creates an instance of a regulator. It uses the provided
0315  * @a attributes to create the instance return in @a regulator. This instance
0316  * will allocate the buffers associated with the regulator instance as well
0317  * as the Delivery thread.
0318  *
0319  * The @a attributes structure defines the priority and stack size of
0320  * the Delivery thread dedicated to this regulator instance. It also
0321  * defines the period of the Delivery thread and the maximum number of
0322  * messages that may be delivered per period via invocation of the
0323  * delivery function. 
0324  *
0325  * For each regulator instance, the following resources are allocated:
0326  *
0327  * - A memory area for the regulator control block using @a malloc().
0328  * - A RTEMS Classic API Message Queue is constructed with message 
0329  *   buffer memory allocated using @a malloc().  Each message consists
0330  *   of a pointer and a length.
0331  * - A RTEMS Classic API Partition.
0332  * - A RTEMS Classic API Rate Monotonic Period.
0333  *
0334  * @param[in] attributes specify the regulator instance attributes
0335  * @param[inout] regulator will point to the regulator instance
0336  *
0337  * @return an RTEMS status code indicating success or failure.
0338  *
0339  * @note This function allocates memory for the buffers holding messages,
0340  *       an Delivery thread and an RTEMS partition. When it executes, the
0341  *       Delivery thread will create an RTEMS rate monotonic period.
0342  */
0343 rtems_status_code rtems_regulator_create(
0344   rtems_regulator_attributes  *attributes,
0345   rtems_regulator_instance   **regulator
0346 );
0347 
0348 /**
0349  * @ingroup RegulatorAPI
0350  *
0351  * @brief Delete a regulator
0352  *
0353  * This function is used to delete the specified @a regulator instance.
0354  *
0355  * It is the responsibility of the user to ensure that any resources
0356  * such as sockets or open file descriptors used by the delivery
0357  * function are also deleted. It is likely safer to delete those 
0358  * delivery resources after deleting the regulator instance rather than
0359  * before.
0360  *
0361  * @param[in] regulator is the instance to delete
0362  * @param[in] ticks is the maximum number of ticks to wait for
0363  *            the delivery thread to shutdown.
0364  *
0365  * @return an RTEMS status code indicating success or failure.
0366  *
0367  * @note This function deallocates the resources allocated during
0368  *       @a rtems_regulator_create().
0369  */
0370 rtems_status_code rtems_regulator_delete(
0371   rtems_regulator_instance    *regulator,
0372   rtems_interval               ticks
0373 );
0374 
0375 /**
0376  * @ingroup RegulatorAPI
0377  *
0378  * @brief Obtain Buffer from Regulator
0379  *
0380  * This function is used to obtain a buffer from the regulator's pool. The
0381  * @a buffer returned is assumed to be filled in with contents and used
0382  * in a subsequent call to @a rtems_regulator_send(). When the @a buffer is
0383  * delivered, it is expected to be released. If the @a buffer is not
0384  * successfully accepted by this function,  then it should be returned
0385  * using @a rtems_regulator_release_buffer() or used to send another message.
0386  *
0387  * The @a buffer is of the maximum_message_size specified in the attributes
0388  * passed in to @a rtems_regulator_create().
0389  *
0390  * @param[in] regulator is the regulator instance to operate upon
0391  * @param[out] buffer will point to the allocated buffer
0392  *
0393  * @return an RTEMS status code indicating success or failure.
0394  *
0395  * @note This function does not perform dynamic allocation. It obtains a
0396  *       buffer from the pool allocated during @a rtems_regulator_create().
0397  *
0398  * @note Any attempt to write outside the buffer area is undefined.
0399  */
0400 rtems_status_code rtems_regulator_obtain_buffer(
0401   rtems_regulator_instance   *regulator,
0402   void                      **buffer
0403 );
0404 
0405 /**
0406  * @ingroup RegulatorAPI
0407  *
0408  * @brief Release Previously Obtained Regulator Buffer
0409  *
0410  * This function is used to release a buffer to the regulator's pool. It is
0411  * assumed that the @a buffer returned will not be used by the application
0412  * anymore. The @a buffer must have previously been allocated by
0413  * @a rtems_regulator_obtain_buffer() and NOT passed to
0414  * @a rtems_regulator_send().
0415  *
0416  * If a subsequent @a rtems_regulator_send() using this @a buffer is
0417  * successful, the @a buffer will eventually be processed by the delivery
0418  * thread and released.
0419  *
0420  * @param[in] regulator is the regulator instance to operate upon
0421  * @param[out] buffer will point to the buffer to release
0422  *
0423  * @return an RTEMS status code indicating success or failure.
0424  *
0425  * @note This function does not perform dynamic deallocation. It releases a
0426  *       buffer to the pool allocated during @a rtems_regulator_create().
0427  */
0428 rtems_status_code rtems_regulator_release_buffer(
0429   rtems_regulator_instance   *regulator,
0430   void                       *buffer
0431 );
0432 
0433 /**
0434  * @ingroup RegulatorAPI
0435  *
0436  * @brief Send to regulator instance
0437  *
0438  * This function is used by the producer to send a @a message to the
0439  * @a regulator for later delivery by the Delivery thread. The message is
0440  * contained in the memory pointed to by @a message and is @a length
0441  * bytes in length.
0442  *
0443  * It is required that the @a message buffer was obtained via
0444  * @a rtems_regulator_obtain_buffer().
0445  *
0446  * It is assumed that the @a message buffer has been filled in with
0447  * application content to deliver.
0448  *
0449  * If the @a rtems_regulator_send() is successful, the buffer is enqueued
0450  * inside the regulator instance for subsequent delivery. After the
0451  * @a message is delivered, it may be released by either delivery
0452  * function or the application code depending on the implementation.
0453  *
0454  * The status @a RTEMS_TOO_MANY is returned if the regulator's
0455  * internal queue is full. This indicates that the configured
0456  * maximum number of messages was insufficient. It is the
0457  * responsibility of the caller to decide whether to hold messages,
0458  * drop them, or print a message that the maximum number of messages
0459  * should be increased.
0460  *
0461  * If @a rtems_regulator_send() is unsuccessful, it is the application's
0462  * responsibility to release the buffer. If it is successfully sent,
0463  * then it becomes the responsibility of the delivery function to
0464  * release it.
0465  *
0466  * @param[in] regulator is the regulator instance to operate upon
0467  * @param[out] message points to the message to deliver
0468  * @param[out] length is the size of the message in bytes
0469  *
0470  * @return an RTEMS status code indicating success or failure.
0471  *
0472  */
0473 rtems_status_code rtems_regulator_send(
0474   rtems_regulator_instance  *regulator,
0475   void                      *message,
0476   size_t                     length
0477 );
0478 
0479 /**
0480  * @ingroup RegulatorAPI
0481  *
0482  * @brief Obtain statistics for regulator instance
0483  *
0484  * This function is used by the application to obtain statistics
0485  * information about the regulator instance.  
0486  *
0487  * If the @a obtained and @a released fields in the returned 
0488  * @a statistics structure are equal, then there are no buffers
0489  * outstanding from this regulator instance.
0490  *
0491  * @param[in] regulator is the regulator instance to operate upon
0492  * @param[inout] statistics points to the statistics structure to fill in
0493  *
0494  * @return an RTEMS status code indicating success or failure.
0495  *
0496  */
0497 rtems_status_code rtems_regulator_get_statistics(
0498   rtems_regulator_instance   *regulator,
0499   rtems_regulator_statistics *statistics
0500 );
0501 
0502 #endif /* REGULATOR_H */