qpc/include/qequeue.h
2023-01-06 12:57:26 -05:00

348 lines
12 KiB
C

/*$file${include::qequeue.h} vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv*/
/*
* Model: qpc.qm
* File: ${include::qequeue.h}
*
* This code has been generated by QM 5.2.4 <www.state-machine.com/qm>.
* DO NOT EDIT THIS FILE MANUALLY. All your changes will be lost.
*
* This code is covered by the following QP license:
* License # : LicenseRef-QL-dual
* Issued to : Any user of the QP/C real-time embedded framework
* Framework(s) : qpc
* Support ends : 2023-12-31
* License scope:
*
* Copyright (C) 2005 Quantum Leaps, LLC <state-machine.com>.
*
* SPDX-License-Identifier: GPL-3.0-or-later OR LicenseRef-QL-commercial
*
* This software is dual-licensed under the terms of the open source GNU
* General Public License version 3 (or any later version), or alternatively,
* under the terms of one of the closed source Quantum Leaps commercial
* licenses.
*
* The terms of the open source GNU General Public License version 3
* can be found at: <www.gnu.org/licenses/gpl-3.0>
*
* The terms of the closed source Quantum Leaps commercial licenses
* can be found at: <www.state-machine.com/licensing>
*
* Redistributions in source code must retain this top-level comment block.
* Plagiarizing this software to sidestep the license obligations is illegal.
*
* Contact information:
* <www.state-machine.com/licensing>
* <info@state-machine.com>
*/
/*$endhead${include::qequeue.h} ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^*/
/*! @file
* @brief QP natvie, platform-independent, thread-safe event queue interface
* @details
* This header file must be included in all QF ports that use native QF
* event queue for active objects. Also, this file needs to be included
* in the QP/C library when the application uses QActive_defer()/
* QActive_recall(). Finally, this file is also needed when the "raw"
* thread-safe queues are used for communication between active objects
* and non-framework entities, such as ISRs, device drivers, or legacy
* code.
*/
#ifndef QP_INC_QEQUEUE_H_
#define QP_INC_QEQUEUE_H_
#ifndef QF_EQUEUE_CTR_SIZE
/*! The size [bytes] of the ring-buffer counters used in the
* native QF event queue implementation. Valid values: 1U, 2U, or 4U;
* default 1U.
* @details
* This macro can be defined in the QF port file (qf_port.h) to
* configure the ::QEQueueCtr type. Here the macro is not defined so the
* default of 1 byte is chosen.
*/
#define QF_EQUEUE_CTR_SIZE 1U
#endif
#if (QF_EQUEUE_CTR_SIZE == 1U)
/*! The data type to store the ring-buffer counters based on
* the macro #QF_EQUEUE_CTR_SIZE.
* @details
* The dynamic range of this data type determines the maximum length
* of the ring buffer managed by the native QF event queue.
*/
typedef uint8_t QEQueueCtr;
#elif (QF_EQUEUE_CTR_SIZE == 2U)
typedef uint16_t QEQueueCtr;
#elif (QF_EQUEUE_CTR_SIZE == 4U)
typedef uint32_t QEQueueCtr;
#else
#error "QF_EQUEUE_CTR_SIZE defined incorrectly, expected 1U, 2U, or 4U"
#endif
/*==========================================================================*/
/*$declare${QF::QEQueue} vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv*/
/*${QF::QEQueue} ...........................................................*/
/*! @brief Native QF Event Queue
* @class QEQueue
*
* @details
* This class describes the native QF event queue, which can be used as
* the event queue for active objects, or as a simple "raw" event queue for
* thread-safe event passing among non-framework entities, such as ISRs,
* device drivers, or other third-party components.<br>
*
* The native QF event queue is configured by defining the macro
* #QF_EQUEUE_TYPE as ::QEQueue in the specific QF port header file.<br>
* <br>
* The ::QEQueue structure contains only data members for managing an event
* queue, but does not contain the storage for the queue buffer, which must
* be provided externally during the queue initialization.<br>
* <br>
* The event queue can store only event pointers, not the whole events. The
* internal implementation uses the standard ring-buffer plus one external
* location that optimizes the queue operation for the most frequent case
* of empty queue.<br>
* <br>
* The ::QEQueue structure is used with two sets of functions. One set is for
* the active object event queue, which might need to block the active object
* task when the event queue is empty and might need to unblock it when
* events are posted to the queue. The interface for the native active object
* event queue consists of the following functions: QActive_post(),
* QActive_postLIFO(), and QActive_get_(). Additionally the function
* QEQueue_init() is used to initialize the queue.<br>
* <br>
* The other set of functions, uses ::QEQueue as a simple "raw" event
* queue to pass events between entities other than active objects, such as
* ISRs. The "raw" event queue is not capable of blocking on the get()
* operation, but is still thread-safe because it uses QF critical section
* to protect its integrity. The interface for the "raw" thread-safe queue
* consists of the following functions: QEQueue_post(),
* QEQueue_postLIFO(), and QEQueue_get(). Additionally the function
* QEQueue_init() is used to initialize the queue.
*
* <br>ote Most event queue operations (both the active object queues and
* the "raw" queues) internally use the QF critical section. You should be
* careful not to invoke those operations from other critical sections when
* nesting of critical sections is not supported.
*
* @sa ::QEQueue for the description of the data members
*/
typedef struct {
/* private: */
/*! pointer to event at the front of the queue.
* @private @memberof QEQueue
*
* @details
* All incoming and outgoing events pass through the frontEvt location.
* When the queue is empty (which is most of the time), the extra
* frontEvt location allows to bypass the ring buffer altogether,
* greatly optimizing the performance of the queue. Only bursts of events
* engage the ring buffer.
*
* <br>ote The additional role of this attribute is to indicate the empty
* status of the queue. The queue is empty when frontEvt is NULL.
*/
QEvt const * volatile frontEvt;
/*! pointer to the start of the ring buffer
* @private @memberof QEQueue
*/
QEvt const ** ring;
/*! offset of the end of the ring buffer from the start of the buffer
* @private @memberof QEQueue
*/
QEQueueCtr end;
/*! offset to where next event will be inserted into the buffer
* @private @memberof QEQueue
*/
QEQueueCtr volatile head;
/*! offset of where next event will be extracted from the buffer
* @private @memberof QEQueue
*/
QEQueueCtr volatile tail;
/*! number of free events in the ring buffer
* @private @memberof QEQueue
*/
QEQueueCtr volatile nFree;
/*! Minimum number of free events ever in the ring buffer.
* @private @memberof QEQueue
*
* @details
* This attribute remembers the low-watermark of the ring buffer,
* which provides a valuable information for sizing event queues.
* @sa QF_getQueueMargin().
*/
QEQueueCtr nMin;
} QEQueue;
/* public: */
/*! Initialize the native QF event queue.
* @public @memberof QEQueue
*
* @details
* Initialize the event queue by giving it the storage for the ring buffer.
*
* @param[in,out] me current instance pointer (see @ref oop)
* @param[in] qSto an array of pointers to ::QEvt to sereve as the
* ring buffer for the event queue
* @param[in] qLen the length of the `qSto` buffer (in ::QEvt pointers)
*
* @note The actual capacity of the queue is qLen + 1, because of the extra
* location forntEvt.
*
* @note
* This function is also used to initialize the event queues of active
* objects in the built-int QV and QK kernels, as well as other
* QP ports to OSes/RTOSes that do provide a suitable message queue.
*/
void QEQueue_init(QEQueue * const me,
QEvt const ** const qSto,
uint_fast16_t const qLen);
/*! Post an event to the "raw" thread-safe event queue (FIFO).
* @public @memberof QEQueue
*
* @details
* Post an event to the "raw" thread-safe event queue using the
* First-In-First-Out (FIFO) order.
*
* @param[in,out] me current instance pointer (see @ref oop)
* @param[in] e pointer to the event to be posted to the queue
* @param[in] margin number of required free slots in the queue after
* posting the event. The special value #QF_NO_MARGIN
* means that this function will assert if posting
* @note
* The #QF_NO_MARGIN value of the `margin` parameter is special and
* denotes situation when the post() operation is assumed to succeed (event
* delivery guarantee). An assertion fires, when the event cannot be
* delivered in this case.
*
* @returns 'true' (success) when the posting succeeded with the provided
* margin and 'false' (failure) when the posting fails.
*
* @note This function can be called from any task context or ISR context.
*
* @sa QEQueue_postLIFO(), QEQueue_get()
*/
bool QEQueue_post(QEQueue * const me,
QEvt const * const e,
uint_fast16_t const margin,
uint_fast8_t const qs_id);
/*! Post an event to the "raw" thread-safe event queue (LIFO).
* @public @memberof QEQueue
*
* @details
* Post an event to the "raw" thread-safe event queue using the
* Last-In-First-Out (LIFO) order.
*
* @param[in,out] me current instance pointer (see @ref oop)
* @param[in] e pointer to the event to be posted to the queue
*
* @attention
* The LIFO policy should be used only with great __caution__, because
* it alters the order of events in the queue.
*
* @note
* This function can be called from any task context or ISR context.
*
* @note
* this function is used for the "raw" thread-safe queues and __not__
* for the queues of active objects.
*
* @sa
* QEQueue_post(), QEQueue_get(), QActive_defer()
*/
void QEQueue_postLIFO(QEQueue * const me,
QEvt const * const e,
uint_fast8_t const qs_id);
/*! Obtain an event from the "raw" thread-safe queue.
* @public @memberof QEQueue
*
* @details
* Retrieves an event from the front of the "raw" thread-safe queue and
* returns a pointer to this event to the caller.
*
* @param[in,out] me current instance pointer (see @ref oop)
*
* @returns
* pointer to event at the front of the queue, if the queue is
* not empty and NULL if the queue is empty.
*
* @note
* this function is used for the "raw" thread-safe queues and __not__
* for the queues of active objects.
*
* @sa
* QEQueue_post(), QEQueue_postLIFO(), QActive_recall()
*/
QEvt const * QEQueue_get(QEQueue * const me,
uint_fast8_t const qs_id);
/*! "raw" thread-safe QF event queue operation for obtaining the number
* of free entries still available in the queue.
* @public @memberof QEQueue
*
* @details
* This operation needs to be used with caution because the number of free
* entries can change unexpectedly. The main intent for using this operation
* is in conjunction with event deferral. In this case the queue is accessed
* only from a single thread (by a single AO), so the number of free
* entries cannot change unexpectedly.
*
* @param[in] me current instance pointer (see @ref oop)
*
* @returns the current number of free slots in the queue.
*/
static inline QEQueueCtr QEQueue_getNFree(QEQueue const * const me) {
return me->nFree;
}
/*! "raw" thread-safe QF event queue operation for obtaining the minimum
* number of free entries ever in the queue (a.k.a. "low-watermark").
* @public @memberof QEQueue
*
* @details
* This operation needs to be used with caution because the "low-watermark"
* can change unexpectedly. The main intent for using this operation is to
* get an idea of queue usage to size the queue adequately.
*
* @param[in] me current instance pointer (see @ref oop)
*
* @returns the minimum number of free entries ever in the queue since init.
*/
static inline QEQueueCtr QEQueue_getNMin(QEQueue const * const me) {
return me->nMin;
}
/*! "raw" thread-safe QF event queue operation to find out if the queue
* is empty.
* @public @memberof QEQueue
*
* @details
* This operation needs to be used with caution because the queue status
* can change unexpectedly. The main intent for using this operation is in
* conjunction with event deferral. In this case the queue is accessed only
* from a single thread (by a single AO), so no other entity can post
* events to the queue.
*
* @param[in] me_ current instance pointer (see @ref oop)
*
* @returns 'true' if the queue is current empty and 'false' otherwise.
*/
static inline bool QEQueue_isEmpty(QEQueue const * const me) {
return me->frontEvt == (QEvt *)0;
}
/*$enddecl${QF::QEQueue} ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^*/
#endif /* QP_INC_QEQUEUE_H_ */