[PATCH rtems v1] Add the Regulator Interface and test
Joel Sherrill
joel at rtems.org
Fri Jul 14 16:00:43 UTC 2023
Comments embedded. V2 coming. If your comments arrive in time, I might get
them in without a V3.
On Sun, Jul 9, 2023 at 7:48 PM Chris Johns <chrisj at rtems.org> wrote:
> Hi,
>
> Thanks for posting this code. My comments are below and I hope they help.
>
> Thanks
> Chris
>
> On 8/7/2023 6:55 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 | 360 +++++
> > cpukit/include/rtems/regulatorimpl.h | 100 ++
> > cpukit/regulator/regulator.c | 487 +++++++
>
> I prefer we do not add pieces of functionality to cpukit at this level. You
> mention this is application support so would `libapp` work? It would allow
> for
> growth, eg logging. We have separate libraries for libdl etc so should
> this be
> separate or placed in libcpu? We also have libmisc and it could live there?
>
Showing your age. libcpu is gone. :)
I will move it under libmisc for now. libapp would just be another dumping
ground. I wonder why shell is under libmisc other than history. lol
>
> FYI and unrelated I also think moving dtc, ftpd, mghttpd, compression and
> telnetd somewhere would be good.
>
Compression is better than the hodge podge of locations that that code was
in before. :)
The network libraries should be on a path to move to rtems-net-services.
But dtc is core functionality for some BSPs so I'm not sure what to do with
it.
My main concern in this area has not been to push things into external
repos or libraries as much as make sure the directory organization of
what we have makes sense. Top of my list is a few things in score/ that
I think don't belong.
But you are right. This is a topic for another thread.
>
> > spec/build/cpukit/librtemscpu.yml | 3 +
> > spec/build/testsuites/libtests/grp.yml | 2 +
> > .../build/testsuites/libtests/regulator01.yml | 21 +
> > testsuites/libtests/regulator01/regulator01.c | 1156 +++++++++++++++++
> > .../libtests/regulator01/regulator01.doc | 37 +
> > .../libtests/regulator01/rtems_config.c | 59 +
> > 9 files changed, 2225 insertions(+)
> > create mode 100644 cpukit/include/rtems/regulator.h
> > create mode 100644 cpukit/include/rtems/regulatorimpl.h
> > create mode 100644 cpukit/regulator/regulator.c
> > 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..7344ced2ae
> > --- /dev/null
> > +++ b/cpukit/include/rtems/regulator.h
> > @@ -0,0 +1,360 @@
> > +/* SPDX-License-Identifier: BSD-2-Clause */
> > +
> > +/**
> > + * @defgroup RegulatorAPI Regulator API
> > + *
> > + * @brief Regulator APIs
> > + *
> > + * The Regulator provides a set of APIs to manage bursty 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 bursty input from a source
>
> ... bursts of input ...
>
Changed in three places
>
> > + * and meter it out to a destination.
> > + *
> > + * 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
>
> How is the maximum burst defined?
>
I updated the main page description. The regulator buffers maximum_messages
which is the amount of buffering the delivery thread is allowed to get
behind. This
could be one burst or multiple as they are delivered.
I think it was covered but later. I also added more to
rtems_regulator_create()
about the attributes structure.
> > + * is in messages per second. If the sender produces data too fast, the
> > + * regulator will buffer the configured number of messages.
>
> What happens to the input data when the "configured number of messages"
> limit is
> reached?
>
The rtems_regulator_send() returns RTEMS_TOO_MANY which is from the
underlying
rtems_message_queue_send().
I will be submitting a Classic API Guide chapter for the regulator after
the code is merged. Each error code will be listed as is practice. The
Doxygen
doesn't list every error code.
> There is no discussion about error, error responiblity and recovery.
>
I added some to rtems_regulator_send() but my recommendation to User #1
was to do a systems analysis on the source and sink and ensure the maximum
number of messages buffered was sufficient.
FWIW this is just a message queue under the hood and I don't think we
have guidance for sizing that. :)
>
> > + * 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
> > + * bursty input from a fast source overflowing a slower output sink.
> > + *
> > + * It is assumed that the application has a design limit on the number
> of
> > + * messages which may be buffered. All messages will eventually be
> output.
>
> Does the regulator provide any stats, latched states or alarms to help a
> user
> integrate and prove the data flows are operating as designed? I have
> successfully used high or low water marks as a way to help audit this type
> of
> functionality in systems. The marks are set at the system level and can be
> manually checked or monitored to make sure no system limits are beached.
> Slient
> drops or overflows can be difficult to resolve.
>
User #1 had no requirements for any of that. We can discuss adding that as
user
requirements arise. At this point, I wouldn't know what would be
interesting for
statistics. I have a few ideas -- like maximum messages queued (0 would be
the
low mark), reflecting the period statistics, and perhaps tracking number of
messages
delivered per period.
Message queues do not track the high water mark or if they returned too
many.
It would seem that a lot of what would be interesting could be information
from the
underlying RTEMS objects.
Can we file a ticket for this as an enhancement? I can assure you that it
won't happen
on this round of submission but it is an interesting thing to consider
adding.
>
> > + *
> > + * A regulator instance is used as follows:
> > + *
> > + * @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)
> > + * // rtems_regulator_send() will release the buffer
> automatically when done
> > + * @endcode
> > + *
> > + * 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 Source then sends the buffer to the Regulator instance. 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.
> > + *
> > + * 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 ultimate
> > + * Destination by the internal Delivery thread.
> > + */
> > +
> > +/**
> > + * @addtogroup RegulatorAPI
> > + *
> > + * @file
> > + *
> > + * @brief This header file defines the Regulator API.
> > + *
> > + */
> > +
> > +/*
> > + * 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.
> > + */
> > +
> > +#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.
>
> What is the context this handler is called in? Are there any contriants,
> eg tack
> size, performance side effects, ...?
>
Added. There is a dedicated thread whose stack size, period, and priority
are specified as part of the attributes passed to rtems_regulator_create().
I added some here and tidied up the information with
rtems_regulator_create().
> > 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.
> > + *
> > + * @code
> > + * void 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);
> > + * regulator release(message);
>
> What is `regulator release()`?
>
Should have been rtems_regulator_release_buffer(). Looks like I tried
to write English rather than the method name for some reason.
>
> > + * }
> > + * @endcode
> > + *
> > + * The following sequence diagram shows the behavior of the Delivery
> thread
>
> behaviour
>
I thought we preferred US spellings but were not particularly picky. As
long as the
flavor and color are correct. :)
>
> > + * 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,
> output_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 that the Delivery
> Thread
> > + * Body is periodically executed and that during each up to the instance
> > + * configuration parameter maximum_to_dequeue_per_period can be
> dequeued and
> > + * given to the application's deliverer method for processing.
>
> Could this paragraph be worded in a simpler way? It has `are that` and
> `and that
> during each up to the instance...`.
>
I changed it to a lead-in and numbered bullets.
>
> > + * Note that the application explicitly obtains buffers from the
> regulator
> > + * instance but that the Delivery Thread implicitly releases them to the
> > + * internal pool when delivered.
>
> What can a user do with a message pointer? Can they hold it, queue it or
> take
> any references to it? The example is not clear because a socket write is a
> copy
> by value and a release implies a separate action is required and the
> implemention automatically returns the buffer to the parition?
>
The regulator is designed to not add copies of buffers. They obtain buffers,
fill them in, feed them to the regulator, and eventually process each via a
delivery function.
The use of a partition and a message queue which is only ptr/length is
intentional
to avoid message buffer copies. My thinking was that the input device
would directly
fill in the buffer and it would not be copied until the delivery function
handed it to
the sink.
I've added Doxygen comments on the lifespan and ownership of the buffer.
There was already some in a couple of places and I added to it.
> > + */
> > +typedef void (*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 method to invoke to output a message to the
> destination*/
> > + rtems_regulator_deliverer deliverer;
> > +
> > + /** Context pointer to pass to deliver method */
> > + 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 output thread */
> > + rtems_task_priority output_thread_priority;
> > +
> > + /** Stack size of output thread */
> > + size_t output_thread_stack_size;
> > +
> > + /** Period (in ticks) of output thread */
>
> What happens if set to 0 or 1?
>
1 is legal per RTEMS.
Good catch on 0. That is actually period status. I added a check to
rtems_regulator_create() for this and return RTEMS_INVALID_NUMBER.
> > + rtems_interval output_thread_period;
> > +
> > + /** Maximum messages to dequeue per period */
> > + size_t maximum_to_dequeue_per_period;
> > +
> > +} rtems_regulator_attributes;
> > +
> > +/**
> > + * @ingroup RegulatorAPI
> > + *
> > + * @brief 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 output task.
> > + *
> > + * @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 method allocates memory for the buffers holding messages,
> > + * an output task and an RTEMS partition. When it executes, the
> > + * output task will create an RTEMS rate monotonic period.
>
> I see a message queue create in the code?
>
> Is the memory worksapce of heap?
>
Currently workspace. Do you think it should be changed to construct
and allocate this memory from the heap? That would be V3. :)
I added documentation to rtems_regulator_create() to list all the resources
it allocates.
>
> > + */
> > +rtems_status_code rtems_regulator_create(
> > + rtems_regulator_attributes *attributes,
> > + rtems_regulator_instance **regulator
> > +);
> > +
> > +/**
> > + * @ingroup RegulatorAPI
> > + *
> > + * @brief Delete a regulator
> > + *
> > + * This method is used to delete an instance of a @a regulator.
> > + *
> > + * @param[in] regulator is the instance to delete
> > + *
> > + * @return an RTEMS status code indicating success or failure.
> > + *
> > + * @note This method deallocates the resources allocated during
> > + * rtems_regulator_create().
> > + */
> > +rtems_status_code rtems_regulator_delete(
> > + rtems_regulator_instance *regulator
> > +);
> > +
> > +/**
> > + * @ingroup RegulatorAPI
> > + *
> > + * @brief Obtain Buffer from Regulator
> > + *
> > + * This method 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 rtems_regulator_send(). If the @a buffer is
> not sent,
> > + * then it should be returned using rtems_regulator_release_buffer().
> > + *
> > + * The buffer is of the maximum_message_size specified in the attributes
> > + * passed in to 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 method does not perform dynamic allocation. It obtains a
> > + * buffer from the pool allocated during 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 method is used to release a buffer from 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
> > + * rtems_regulator_obtain_buffer().
> > + *
> > + * If the rtems_regulator_send() is successful, the buffer is
> automatically
> > + * released to the pool. If unsuccessful or the application decides not
> > + * to send the message, it is the application's responsibility to
> > + * release the buffer.
> > + *
> > + * @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 method does not perform dynamic deallocation. It releases
> a
> > + * buffer to the pool allocated during rtems_regulator_create().
> > + */
> > +rtems_status_code rtems_regulator_release_buffer(
> > + rtems_regulator_instance *regulator,
> > + void *buffer
> > +);
> > +
> > +/**
> > + * @ingroup RegulatorAPI
> > + *
> > + * @brief Send to regulator instance
> > + *
> > + * This method is used by the producer to send a @a message to the
> > + * @a regulator for later delivery by the output task. The message is
> > + * contained in the memory pointed to by @a message and is @a length
> > + * bytes in length.
> > + *
> > + * It is assumed that the @a message buffer has been filled in with
> > + * application content to deliver and that the @a message buffer was
> > + * obtained via rtems_regulator_obtain_buffer().
>
> It is a requirement the send call only passes memory from the
> rtems_regulator_obtain_buffer() call. Maybe the wording should clearly
> state this.
>
Strengthened and split into two paragraphs.
>
> > + * If the rtems_regulator_send() is successful, the buffer is
> automatically
> > + * released to the pool. If unsuccessful or the application decides not
> > + * to send the message, it is the application's responsibility to
> > + * release the buffer.
>
> This is not true. The memory is not automatically returned to the pool by
> the
> send call. If the send is successful it is placed in an internal handle and
> queued on a message queue (I assume is sized to hold all buffers) and it
> is only
> released after the message has be read from the message queue and the
> delivery
> handler has returned.
>
I've cleaned up the description.
>
> I find the automatic and manual interactions of the API confusing. I see a
> number of places a user can step on their own toes. It seems this code as
> evolved because the example shows a release call in delivery handler and
> yet
> there is an automatic release. I wonder if the automatic release is a good
> idea
> as the user needs to handle a few other cases manually? The automatic
> release
> also implies the handling of the buffer in the delivery handler is
> sychronous
> and that may not suite all applications requiring buffer buffering and
> copies.
>
The API did not evolve other than to add rtems_ naming conventions when
User #1 asked for it to be submitted. It was conceived to not introduce yet
another
buffer copy. Yes, that puts some responsibility on the user but that's the
cost of
not copying. I thought I kept it pretty simple to use. User #1 didn't have
any issues
incorporating it into their application.
The automatic release does assume that the delivery to the sink is by value
and
the buffer is safe to release back to the regulator.
Do you think the delivery function should return a bool to indicate if the
release
should happen or not? If it returns say false, the delivery code for the
user would
have to release it on its own.
> > + *
> > + * @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
> > +);
> > +
> > +#endif /* REGULATOR_H */
> > diff --git a/cpukit/include/rtems/regulatorimpl.h
> b/cpukit/include/rtems/regulatorimpl.h
> > new file mode 100644
> > index 0000000000..dfbcb04214
> > --- /dev/null
> > +++ b/cpukit/include/rtems/regulatorimpl.h
> > @@ -0,0 +1,100 @@
> > +/* 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) 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.
> > + */
> > +
> > +#ifndef RTEMS_REGULATORIMPL_H
> > +#define RTEMS_REGULATORIMPL_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 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;
> > +
> > + /** Pool of unused messages */
> > + rtems_id messages_partition_id;
> > +
> > + /** Message queue of pending outgoing messages */
> > + rtems_id queue_id;
> > +
> > + /** Id of thread performing output */
> > + rtems_id output_thread_id;
> > +
> > + /** Id of period used by output thread */
> > + rtems_id output_thread_period_id;
> > +
> > +} _Regulator_Control;
> > +
> > +#endif /* RTEMS_REGULATORIMPL_H */
> > diff --git a/cpukit/regulator/regulator.c b/cpukit/regulator/regulator.c
> > new file mode 100644
> > index 0000000000..33a6b33950
> > --- /dev/null
> > +++ b/cpukit/regulator/regulator.c
> > @@ -0,0 +1,487 @@
> > +/* 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/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;
> > +
> > + /*
> > + * The argument passed in cannot be NULL if the regulator_create
> worked.
> > + */
> > + the_regulator = (_Regulator_Control *) arg;
> > +
> > + /**
> > + * 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->output_thread_period_id
> > + );
> > + if (sc != RTEMS_SUCCESSFUL) {
> > + rtems_task_exit();
> > + }
> > +
> > + /**
> > + * Loop on the rate_monotonic_period() based on the specified period.
> > + */
> > + while (1) {
> > + sc = rtems_rate_monotonic_period(
> > + the_regulator->output_thread_period_id,
> > + the_regulator->Attributes.output_thread_period
> > + );
> > + (void) sc;
> > +
> > + /**
> > + * 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
> > + );
> > + if (sc != RTEMS_SUCCESSFUL) {
> > + break;
> > + }
> > +
> > + the_regulator->Attributes.deliverer(
> > + the_regulator->Attributes.deliverer_context,
> > + regulator_message.buffer,
> > + regulator_message.length
> > + );
> > +
> > + /**
> > + * The message was successfully delivered so return the buffer to
> the pool.
> > + */
> > + sc = rtems_partition_return_buffer(
> > + the_regulator->messages_partition_id,
> > + regulator_message.buffer
> > + );
> > + (void) sc;
>
> I am confused because the example has:
>
> regulator release(message);
>
Changed to rtems_regulator_release_buffer() where that occurred.
>
> and I do not know what that is doing and yet here the buffer is being
> automatically released?
>
Hopefully clearer now. Buffers are managed by a partition. I added some to
the comment to help tie it together.
>
> There is no explanation on why the return status of the partition return
> call
> can be ignored?
>
I have no idea what to do with a non-successful status. I suppose the user
could provide a function to call back but generically we have no way to
do anything.
>
> > + }
> > + }
> > +
> > +}
> > +
> > +/**
> > + * @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 rtems_regulator_create()
> and in
> > + * rtems_regulator_delete().
> > + *
> > + * @param[in] the_regulator is the instance to operate upon
> > + */
> > +static void _Regulator_Free_helper(
> > + _Regulator_Control *the_regulator
> > +)
> > +{
> > + (void)
> rtems_rate_monotonic_delete(the_regulator->output_thread_period_id);
> > +
> > + (void) rtems_task_delete(the_regulator->output_thread_id);
>
> The task holds and uses output_thread_period_id. Is this OK? Could the
> task end
> up spinning, locking things up?
>
Periods have to be used by the creating thread. My experience using them is
that this ends up being the create/use pattern.
>
> I think it is wrong to delete the task like this. What if the deliver
> function
> is being called and that code in turn has called a socket write and with
> that a
> bunch of states are being held when the task context is killed?
>
The user has to know it is safe to delete the instance. They likely need to
close
the socket before deleting the regulator. I added a bit to
rtems_regulator_delete()
to note that the user has to clean up for resources used by the delivery
thread and
may need to delete them before calling this.
>
> > +
> > + (void) rtems_message_queue_delete(the_regulator->queue_id);
> > +
> > + (void) rtems_partition_delete(the_regulator->messages_partition_id);
> > +
> > + if (the_regulator->message_memory) {
> > + free(the_regulator->message_memory);
> > + }
> > +
> > + the_regulator->initialized = 0;
>
> Not needed if you free the memory.
>
The regulator instance is in the user's space. We don't free it.
I will consider adding a RTEMS_REGULATOR_INITIALIZER.
> > + free(the_regulator);
> > +}
> > +
> > +/**
> > + * @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:
> > + *
> > + * - output_thread_priority by rtems_task_create()
> > + * - output_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;
> > + }
> > +
> > + /**
> > + * 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 output_thread_id field to be initialized to 0.
> If the
> > + * 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->output_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);
> > + 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);
> > + return sc;
> > + }
> > +
> > + /**
> > + * Create the message queue between the sender and output thread
> > + */
> > + sc = rtems_message_queue_create(
> > + rtems_build_name('S', 'N', 'D', 'Q'),
> > + attributes->maximum_messages,
> > + sizeof(_Regulator_Message_t),
> > + RTEMS_DEFAULT_ATTRIBUTES,
> > + &the_regulator->queue_id
> > + );
> > + if (sc != RTEMS_SUCCESSFUL) {
> > + _Regulator_Free_helper(the_regulator);
> > + 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->output_thread_priority,
> > + attributes->output_thread_stack_size,
> > + RTEMS_DEFAULT_MODES,
> > + RTEMS_DEFAULT_ATTRIBUTES,
> > + &the_regulator->output_thread_id
> > + );
> > + if (sc != RTEMS_SUCCESSFUL) {
> > + _Regulator_Free_helper(the_regulator);
> > + 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.
> > + */
> > + sc = rtems_task_start(
> > + the_regulator->output_thread_id,
> > + _Regulator_Output_task_body,
> > + (rtems_task_argument) the_regulator
> > + );
> > + (void) sc;
>
> Huh?
>
How would it fail? I can add a check and return it but it can't fail if the
code is correct.
>
> > + /**
> > + * The regulator is successfully initialized. Set the initialized
> field
> > + * to reflect this and return the instance pointer.
> > + */
> > + the_regulator->initialized = REGULATOR_INITIALIZED;
>
> I am a bit lost on the value of this variable and state?
>
regulator instance is memory allocated by the called. Just making sure it
has been through create.
>
> > +
> > + *regulator = (void *)the_regulator;
> > +
> > + return RTEMS_SUCCESSFUL;
> > +}
> > +
> > +/**
> > + * @ingroup RegulatorInternalAPI
> > + */
> > +rtems_status_code rtems_regulator_delete(
> > + rtems_regulator_instance *regulator
> > +)
> > +{
> > + _Regulator_Control *the_regulator;
> > +
> > + the_regulator = (_Regulator_Control *) regulator;
> > +
> > + /**
> > + * Validate the arguments and ensure the regulator was successfully
> > + * initialized.
> > + */
> > + if (!the_regulator) {
> > + return RTEMS_INVALID_ADDRESS;
> > + }
> > +
> > + if (the_regulator->initialized != REGULATOR_INITIALIZED) {
> > + return RTEMS_INCORRECT_STATE;
> > + }
> > +
> > + /**
> > + * Free the resources associated with this regulator instance.
> > + */
> > + _Regulator_Free_helper(the_regulator);
> > +
> > + 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 sc;
> > +
> > + the_regulator = (_Regulator_Control *) regulator;
> > +
> > + /**
> > + * Validate the arguments and ensure the regulator was successfully
> > + * initialized.
> > + */
> > + if (!the_regulator) {
> > + return RTEMS_INVALID_ADDRESS;
> > + }
> > +
> > + if (the_regulator->initialized != REGULATOR_INITIALIZED) {
> > + return RTEMS_INCORRECT_STATE;
>
> These repeasted checks calls could be a single check type function.
>
Maybe. Not sure it is worth it. The test had 100% statement and branch
coverage.
>
> > + }
> > +
> > + /**
> > + * Allocate a buffer for the user application from the buffer pool
> managed
> > + * by an Classic API partition.
> > + */
> > + sc = rtems_partition_get_buffer(
> > + the_regulator->messages_partition_id,
> > + buffer
> > + );
> > +
> > + return sc;
> > +}
> > +
> > +/**
> > + * @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 sc;
> > +
> > + the_regulator = (_Regulator_Control *) regulator;
> > +
> > + /**
> > + * Validate the arguments and ensure the regulator was successfully
> > + * initialized.
> > + */
> > + if (!the_regulator) {
> > + return RTEMS_INVALID_ADDRESS;
> > + }
> > +
> > + if (the_regulator->initialized != REGULATOR_INITIALIZED) {
> > + return RTEMS_INCORRECT_STATE;
> > + }
> > +
> > + /**
> > + * Deallocate the buffer to the buffer pool managed by a Classic
> > + * API partition.
> > + */
> > + sc = rtems_partition_return_buffer(
> > + the_regulator->messages_partition_id,
> > + buffer
> > + );
> > +
> > + return sc;
> > +}
> > +
> > +/**
> > + * @ingroup RegulatorInternalAPI
> > + */
> > +rtems_status_code rtems_regulator_send(
> > + rtems_regulator_instance *regulator,
> > + void *message,
> > + size_t length
> > +)
> > +{
> > + _Regulator_Control *the_regulator;
> > + rtems_status_code sc;
> > + _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;
> > + }
> > +
> > + if (!the_regulator) {
> > + return RTEMS_INVALID_ADDRESS;
> > + }
> > +
> > + if (the_regulator->initialized != REGULATOR_INITIALIZED) {
> > + return RTEMS_INCORRECT_STATE;
> > + }
> > +
> > + /**
> > + * 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;
>
> I would consider making this a handle the user also need to use. I would
> allocate a handle per buffer and change send, deliver etc to use handles.
> I have
> found the message pointer confusing to follow in each interface.
>
Handle to what? They obtain a buffer of a known maximum size. Providing the
size is just to support cases where the entire buffer isn't needed.
>
> > +
> > + /**
> > + * Send the application message to the output thread for delivery
> using
> > + * a Classic API message queue.
> > + */
> > + sc = rtems_message_queue_send(
> > + the_regulator->queue_id,
> > + ®ulator_message,
> > + sizeof(_Regulator_Message_t)
> > + );
> > + if (sc != RTEMS_SUCCESSFUL) {
> > + return sc;
> > + }
> > +
> > + return sc;
> > +}
> > diff --git a/spec/build/cpukit/librtemscpu.yml
> b/spec/build/cpukit/librtemscpu.yml
> > index 3654e7f94a..670c3cd479 100644
> > --- a/spec/build/cpukit/librtemscpu.yml
> > +++ b/spec/build/cpukit/librtemscpu.yml
> > @@ -150,6 +150,8 @@ install:
> > - cpukit/include/rtems/pty.h
> > - cpukit/include/rtems/qreslib.h
> > - cpukit/include/rtems/ramdisk.h
> > + - cpukit/include/rtems/regulator.h
> > + - cpukit/include/rtems/regulatorimpl.h
> > - cpukit/include/rtems/rbheap.h
> > - cpukit/include/rtems/rbtree.h
> > - cpukit/include/rtems/record.h
> > @@ -1183,6 +1185,7 @@ source:
> > - cpukit/posix/src/vfork.c
> > - cpukit/posix/src/wait.c
> > - cpukit/posix/src/waitpid.c
> > +- cpukit/regulator/regulator.c
> > - cpukit/rtems/src/barrier.c
> > - cpukit/rtems/src/barriercreate.c
> > - cpukit/rtems/src/barrierdelete.c
> > diff --git a/spec/build/testsuites/libtests/grp.yml
> b/spec/build/testsuites/libtests/grp.yml
> > index be340c8ab6..7ca0f7dfa1 100644
> > --- a/spec/build/testsuites/libtests/grp.yml
> > +++ b/spec/build/testsuites/libtests/grp.yml
> > @@ -230,6 +230,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..408a22dd48
> > --- /dev/null
> > +++ b/testsuites/libtests/regulator01/regulator01.c
> > @@ -0,0 +1,1156 @@
> > +/* 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);
> > +}
> > +
> > +/**
> > + * @ingroup RegulatorTests
> > + * @brief Empty Deliver Method for Testing
> > + */
> > +static void test_regulator_deliverer(
> > + void *context,
> > + void *message,
> > + size_t length
> > +)
> > +{
> > + (void) context;
> > + (void) message;
> > + (void) length;
> > +}
> > +
> > +/**
> > + * @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));
> > +}
> > +
> > +/**
> > + * @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 void test_regulator_deliverer_logger(
> > + void *context,
> > + void *message,
> > + size_t length
> > +)
> > +{
> > + (void) context;
> > +
> > + size_t len;
> > + rtems_interval ticks;
> > +
> > + 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++;
> > +}
> > +
> > +
> > +/**
> > + * @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,
> > + .output_thread_priority = 16,
> > + .output_thread_stack_size = 0,
> > + .output_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,
> > + .output_thread_priority = 16,
> > + .output_thread_stack_size = 0,
> > + .output_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.output_thread_priority = 32;
> > + attributes.maximum_to_dequeue_per_period = 1;
> > + attributes.output_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.output_thread_priority = 32;
> > + attributes.maximum_to_dequeue_per_period = 1;
> > + attributes.output_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 output_thread_priority field is 0.
> > + */
> > +static void test_regulator_create_output_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.output_thread_priority = 0;
> > + attributes.maximum_to_dequeue_per_period = 1;
> > + attributes.output_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.output_thread_priority = 8;
> > + attributes.maximum_to_dequeue_per_period = 1;
> > + attributes.output_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.output_thread_priority = 8;
> > + attributes.maximum_to_dequeue_per_period = 1;
> > + attributes.output_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.output_thread_priority = 8;
> > + attributes.maximum_to_dequeue_per_period = 1;
> > + attributes.output_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.output_thread_priority = 8;
> > + attributes.maximum_to_dequeue_per_period = 1;
> > + attributes.output_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);
> > + 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);
> > + 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);
> > + 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);
> > + 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);
> > + 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);
> > + 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 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 = NULL,
> > + .maximum_message_size = 16,
> > + .maximum_messages = 10,
> > + .output_thread_priority = 16,
> > + .output_thread_stack_size = 0,
> > + .output_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);
> > +
> > + 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);
> > + rtems_test_assert(sc == RTEMS_SUCCESSFUL);
> > +}
> > +
> > +/**
> > + * @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 = NULL,
> > + .maximum_message_size = MAXIMUM_MESSAGE_LENGTH,
> > + .maximum_messages = 10,
> > + .output_thread_priority = 16,
> > + .output_thread_stack_size = 0,
> > + .output_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);
> > +
> > + /*
> > + * 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);
> > + rtems_test_assert(sc == RTEMS_SUCCESSFUL);
> > +}
> > +
> > +/* 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_output_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_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..7c266dc406
> > --- /dev/null
> > +++ b/testsuites/libtests/regulator01/regulator01.doc
> > @@ -0,0 +1,37 @@
> > +# SPDX-License-Identifier: BSD-2-Clause
> > +
> > +# Copyright (c) 2013 Daniel Ramirez <javamonn at gmail.com>
> > +#
> > +# 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: uid01
> > +
> > +directives:
> > + + uid_read_message
> > +
> > +concepts:
> > + + Tests that uid_read_message when called with a timeout greater than
> 0
> > + ticks but less than 1 tick will correctly round this up to a 1 tick
> > + timeout.
>
This file was a bogus copy of another test. Fixed.
> > 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>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.rtems.org/pipermail/devel/attachments/20230714/2b9484d2/attachment-0001.htm>
More information about the devel
mailing list