qpcpp/include/qequeue.hpp

335 lines
13 KiB
C++
Raw Normal View History

2022-08-11 15:36:19 -04:00
//$file${include::qequeue.hpp} vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
//
// Model: qpcpp.qm
// File: ${include::qequeue.hpp}
//
2022-09-22 11:13:20 -04:00
// This code has been generated by QM 5.2.2 <www.state-machine.com/qm>.
2022-08-11 15:36:19 -04:00
// 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) : qpcpp
// 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:
2022-08-11 15:36:19 -04:00
// <www.state-machine.com/licensing>
// <info@state-machine.com>
2022-08-11 15:36:19 -04:00
//
//$endhead${include::qequeue.hpp} ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
//! @file
//! @brief platform-independent fast "raw" thread-safe event queue interface
2022-08-11 15:36:19 -04:00
//!
//! @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
2022-08-11 15:36:19 -04:00
//! 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.
2012-08-14 18:00:48 -04:00
2022-09-22 11:13:20 -04:00
#ifndef QP_INC_QEQUEUE_HPP_
#define QP_INC_QEQUEUE_HPP_
2022-08-11 15:36:19 -04:00
2012-08-14 18:00:48 -04:00
#ifndef QF_EQUEUE_CTR_SIZE
2014-04-13 21:35:34 -04:00
//! The size (in bytes) of the ring-buffer counters used in the
2020-03-17 21:33:58 -04:00
//! native QF event queue implementation. Valid values: 1U, 2U, or 4U;
//! default 1U.
2022-08-11 15:36:19 -04:00
//! @details
//! This macro can be defined in the QF port file (qf_port.hpp) to
//! configure the QP::QEQueueCtr type. Here the macro is not defined
//! so the default of 1 byte is chosen.
2020-03-17 21:33:58 -04:00
#define QF_EQUEUE_CTR_SIZE 1U
2012-08-14 18:00:48 -04:00
#endif
2013-10-10 20:01:51 -04:00
namespace QP {
2012-08-14 18:00:48 -04:00
2020-03-17 21:33:58 -04:00
#if (QF_EQUEUE_CTR_SIZE == 1U)
2022-08-11 15:36:19 -04:00
2014-04-13 21:35:34 -04:00
//! The data type to store the ring-buffer counters based on
//! the macro #QF_EQUEUE_CTR_SIZE.
2022-08-11 15:36:19 -04:00
//! @details
//! The dynamic range of this data type determines the maximum length
//! of the ring buffer managed by the native QF event queue.
2020-03-17 21:33:58 -04:00
using QEQueueCtr = std::uint8_t;
#elif (QF_EQUEUE_CTR_SIZE == 2U)
using QEQueueCtr = std::uint16_t;
#elif (QF_EQUEUE_CTR_SIZE == 4U)
using QEQueueCtr = std::uint32_t;
2012-08-14 18:00:48 -04:00
#else
2020-03-17 21:33:58 -04:00
#error "QF_EQUEUE_CTR_SIZE defined incorrectly, expected 1U, 2U, or 4U"
2012-08-14 18:00:48 -04:00
#endif
2022-08-11 15:36:19 -04:00
} // namespace QP
//============================================================================
2022-08-11 15:36:19 -04:00
//$declare${QF::QEQueue} vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
namespace QP {
//${QF::QEQueue} .............................................................
2014-04-13 21:35:34 -04:00
//! Native QF Event Queue class
2022-08-11 15:36:19 -04:00
//!
//! @details
//! This structure 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,
2022-08-11 15:36:19 -04:00
//! device drivers, or other third-party components.<br>
//!
//! The native QF event queue is configured by defining the macro
2022-08-11 15:36:19 -04:00
//! #QF_EQUEUE_TYPE as QP::QEQueue in the specific QF port header file.<br>
//!
//! The QP::QEQueue class contains only data members for managing an event
//! queue, but does not contain the storage for the queue buffer, which must
2022-08-11 15:36:19 -04:00
//! be provided externally during the queue initialization.<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
2022-08-11 15:36:19 -04:00
//! of empty queue.<br>
//!
//! The QP::QEQueue class is used with two sets of functions. One set is for
//! the active object event queue, which needs to block the active object
//! task when the event queue is empty and unblock it when events are posted
//! to the queue. The interface for the native active object event queue
2022-08-11 15:36:19 -04:00
//! consists of the following functions: QActive::post(), QActive::postLIFO(),
//! and QActive::get_(). Additionally the function QEQueue::init() is used
//! to initialize the queue.<br>
//!
//! The other set of functions, uses this class 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: QP::QEQueue::post(),
//! QP::QEQueue::postLIFO(), and QP::QEQueue::get(). Additionally the
2022-08-11 15:36:19 -04:00
//! function QP::QEQueue::init() is used to initialize the queue.
//!
//! @note
//! 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.
2012-08-14 18:00:48 -04:00
class QEQueue {
private:
2014-04-13 21:35:34 -04:00
//! pointer to event at the front of the queue
2022-08-11 15:36:19 -04:00
//!
//! @details
//! All incoming and outgoing events pass through the m_frontEvt location.
//! When the queue is empty (which is most of the time), the extra
//! m_frontEvt location allows to bypass the ring buffer altogether,
//! greatly optimizing the performance of the queue. Only bursts of events
2022-08-11 15:36:19 -04:00
//! engage the ring buffer.<br>
//!
//! The additional role of this attribute is to indicate the empty status
2022-08-11 15:36:19 -04:00
//! of the queue. The queue is empty if the m_frontEvt location is nullptr.
2013-10-10 20:01:51 -04:00
QEvt const * volatile m_frontEvt;
2012-08-14 18:00:48 -04:00
2014-04-13 21:35:34 -04:00
//! pointer to the start of the ring buffer
2022-08-11 15:36:19 -04:00
QEvt const ** m_ring;
2012-08-14 18:00:48 -04:00
2014-04-13 21:35:34 -04:00
//! offset of the end of the ring buffer from the start of the buffer
2012-08-14 18:00:48 -04:00
QEQueueCtr m_end;
2014-04-13 21:35:34 -04:00
//! offset to where next event will be inserted into the buffer
2013-10-10 20:01:51 -04:00
QEQueueCtr volatile m_head;
2012-08-14 18:00:48 -04:00
2014-04-13 21:35:34 -04:00
//! offset of where next event will be extracted from the buffer
2013-10-10 20:01:51 -04:00
QEQueueCtr volatile m_tail;
2012-08-14 18:00:48 -04:00
2014-04-13 21:35:34 -04:00
//! number of free events in the ring buffer
2013-10-10 20:01:51 -04:00
QEQueueCtr volatile m_nFree;
2012-08-14 18:00:48 -04:00
2014-04-13 21:35:34 -04:00
//! minimum number of free events ever in the ring buffer.
//! @note this attribute remembers the low-watermark of the ring buffer,
//! which provides a valuable information for sizing event queues.
//! @sa QP::QF::getQueueMin().
2012-08-14 18:00:48 -04:00
QEQueueCtr m_nMin;
2022-08-11 15:36:19 -04:00
friend class QActive;
friend class QTicker;
2022-08-28 22:12:27 -04:00
friend class QXMutex;
2022-08-11 15:36:19 -04:00
friend class QXThread;
2012-08-14 18:00:48 -04:00
public:
2022-08-11 15:36:19 -04:00
2014-04-13 21:35:34 -04:00
//! public default constructor
2022-08-11 15:36:19 -04:00
QEQueue() noexcept;
2012-08-14 18:00:48 -04:00
2014-04-13 21:35:34 -04:00
//! Initializes the native QF event queue
//!
2022-08-11 15:36:19 -04:00
//! @details
//! Initialize the event queue by giving it the storage for the
//! ring buffer.
//!
//! @param[in] qSto an array of pointers to QP::QEvt to serve as the
//! ring buffer for the event queue
//! @param[in] qLen the length of the qSto[] buffer (in QP::QEvt pointers)
//!
//! @note
2022-08-11 15:36:19 -04:00
//! The actual capacity of the queue is qLen + 1, because of the extra
//! location forntEvt.
//!
2022-08-11 15:36:19 -04:00
//! @note
//! This function is also used to initialize the event queues of active
//! objects in the built-int QV, QK and QXK kernels, as well as other
//! QP ports to OSes/RTOSes that do provide a suitable message queue.
void init(
QEvt const * qSto[],
std::uint_fast16_t const qLen) noexcept;
2012-08-14 18:00:48 -04:00
2022-08-11 15:36:19 -04:00
//! Posts (FIFO) an event to the "raw" thread-safe QF event queue
//!
//! @details
//! Post an event to the "raw" thread-safe event queue using the
//! First-In-First-Out (FIFO) order.
//!
//! @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
2022-09-22 11:13:20 -04:00
//! QF::NO_MARGIN means that this function will
2022-08-11 15:36:19 -04:00
//! assert if posting
//! @param[in] qs_id QS-id of this state machine (for QS local filter)
//!
//! @note
2022-09-22 11:13:20 -04:00
//! The QF::NO_MARGIN value of the `margin` argument is special and
2022-08-11 15:36:19 -04:00
//! 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 QP::QEQueue::postLIFO(), QP::QEQueue::get()
2022-08-11 15:36:19 -04:00
bool post(
QEvt const * const e,
std::uint_fast16_t const margin,
std::uint_fast8_t const qs_id) noexcept;
2012-08-14 18:00:48 -04:00
2022-08-11 15:36:19 -04:00
//! Posts (LIFO) an event to the "raw" thread-safe QF event queue
//!
//! @details
//! Post an event to the "raw" thread-safe event queue using the
//! Last-In-First-Out (LIFO) order.
//!
//! @param[in] e pointer to the event to be posted to the queue
//! @param[in] qs_id QS-id of this state machine (for QS local filter)
//!
//! @attention
//! The LIFO policy should be used only with great __caution__,
//! because it alters the order of events in the queue.
//!
//! @note
2022-08-11 15:36:19 -04:00
//! This function can be called from any task context or ISR context.
//!
//! @note
2022-08-11 15:36:19 -04:00
//! This function is used for the "raw" thread-safe queues and __not__
//! for the queues of active objects.
//!
2022-08-11 15:36:19 -04:00
//! @sa
//! QEQueue::post(), QEQueue::get(), QActive::defer()
void postLIFO(
QEvt const * const e,
std::uint_fast8_t const qs_id) noexcept;
2012-08-14 18:00:48 -04:00
2022-08-11 15:36:19 -04:00
//! Gets an event from the "raw" thread-safe QF event queue
//!
//! @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] qs_id QS-id of this state machine (for QS local filter)
//!
//! @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 * get(std::uint_fast8_t const qs_id) noexcept;
//! Gets the number of free slots currently in "raw" thread-safe
//! QF event queue
//!
//! @note
//! 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.
//!
//! @sa QP::QMActive::defer(), QP::QMActive::recall()
2022-08-11 15:36:19 -04:00
QEQueueCtr getNFree() const noexcept {
2012-08-14 18:00:48 -04:00
return m_nFree;
}
2017-08-21 18:21:15 -04:00
//! "raw" thread-safe QF event queue operation for obtaining the minimum
//! number of free entries ever in the queue (a.k.a. "low-watermark").
//!
2022-08-11 15:36:19 -04:00
//! @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.
//!
//! @returns the minimum number of free entries ever in the queue
//! since init.
2022-08-11 15:36:19 -04:00
QEQueueCtr getNMin() const noexcept {
2017-08-21 18:21:15 -04:00
return m_nMin;
}
2014-04-13 21:35:34 -04:00
//! "raw" thread-safe QF event queue operation to find out if the queue
//! is empty
//! @note
//! 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.
//!
//! @sa QP::QMActive::defer(), QP::QMActive::recall()
2022-08-11 15:36:19 -04:00
bool isEmpty() const noexcept {
2020-03-17 21:33:58 -04:00
return m_frontEvt == nullptr;
2012-12-10 16:01:54 -05:00
}
2012-08-14 18:00:48 -04:00
private:
2014-04-13 21:35:34 -04:00
2022-08-11 15:36:19 -04:00
//! disallow copying of QP::QEQueue
QEQueue(QEQueue const & other) = delete;
2013-12-30 17:41:15 -05:00
2022-08-11 15:36:19 -04:00
//! disallow copying of QP::QEQueue
QEQueue & operator=(QEQueue const & other) = delete;
}; // class QEQueue
2012-08-14 18:00:48 -04:00
2014-04-13 21:35:34 -04:00
} // namespace QP
2022-08-11 15:36:19 -04:00
//$enddecl${QF::QEQueue} ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
2012-08-14 18:00:48 -04:00
2022-09-22 11:13:20 -04:00
#endif // QP_INC_QEQUEUE_HPP_