qpcpp/include/qequeue.h

256 lines
11 KiB
C
Raw Normal View History

2015-05-14 16:05:04 -04:00
/// @file
/// @brief platform-independent fast "raw" thread-safe event queue interface
/// @ingroup qf
/// @cond
2014-04-13 21:35:34 -04:00
///***************************************************************************
/// Last updated for version 5.3.0
/// Last updated on 2014-03-08
///
/// Q u a n t u m L e a P s
/// ---------------------------
/// innovating embedded systems
///
/// Copyright (C) Quantum Leaps, www.state-machine.com.
///
/// This program is open source software: you can redistribute it and/or
/// modify it under the terms of the GNU General Public License as published
/// by the Free Software Foundation, either version 3 of the License, or
/// (at your option) any later version.
///
/// Alternatively, this program may be distributed and modified under the
/// terms of Quantum Leaps commercial licenses, which expressly supersede
/// the GNU General Public License and are specifically designed for
/// licensees interested in retaining the proprietary status of their code.
///
/// This program is distributed in the hope that it will be useful,
/// but WITHOUT ANY WARRANTY; without even the implied warranty of
/// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
/// GNU General Public License for more details.
///
/// You should have received a copy of the GNU General Public License
/// along with this program. If not, see <http://www.gnu.org/licenses/>.
///
/// Contact information:
/// Web: www.state-machine.com
/// Email: info@state-machine.com
///***************************************************************************
2015-05-14 16:05:04 -04:00
/// @endcond
2014-04-13 21:35:34 -04:00
2012-08-14 18:00:48 -04:00
#ifndef qequeue_h
#define qequeue_h
2015-05-14 16:05:04 -04:00
/// @description
2012-08-14 18:00:48 -04:00
/// This header file must be included in all QF ports that use native QF
2014-04-13 21:35:34 -04:00
/// event queue for active objects. Also, this file needs to be included
2015-05-14 16:05:04 -04:00
/// in the QP/C++ library when the application uses QP::QMActive::defer() /
/// QP::QMActive::recall(). Finally, this file is also needed when the "raw"
2012-08-14 18:00:48 -04:00
/// thread-safe queues are used for communication between active objects
/// and non-framework entities, such as ISRs, device drivers, or legacy
/// code.
#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
//! native QF event queue implementation. Valid values: 1, 2, or 4;
//! default 1.
2015-05-14 16:05:04 -04:00
/// @description
2012-08-14 18:00:48 -04:00
/// This macro can be defined in the QF port file (qf_port.h) to
2014-04-13 21:35:34 -04:00
/// configure the QP::QEQueueCtr type. Here the macro is not defined
/// so the default of 1 byte is chosen.
2012-08-14 18:00:48 -04:00
#define QF_EQUEUE_CTR_SIZE 1
#endif
2013-10-10 20:01:51 -04:00
namespace QP {
2012-08-14 18:00:48 -04:00
#if (QF_EQUEUE_CTR_SIZE == 1)
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.
2015-05-14 16:05:04 -04:00
/// @description
2012-08-14 18:00:48 -04:00
/// The dynamic range of this data type determines the maximum length
/// of the ring buffer managed by the native QF event queue.
2014-04-13 21:35:34 -04:00
typedef uint_fast8_t QEQueueCtr;
2012-08-14 18:00:48 -04:00
#elif (QF_EQUEUE_CTR_SIZE == 2)
2014-04-13 21:35:34 -04:00
typedef uint_fast16_t QEQueueCtr;
2012-08-14 18:00:48 -04:00
#elif (QF_EQUEUE_CTR_SIZE == 4)
2014-04-13 21:35:34 -04:00
typedef uint_fast32_t QEQueueCtr;
2012-08-14 18:00:48 -04:00
#else
#error "QF_EQUEUE_CTR_SIZE defined incorrectly, expected 1, 2, or 4"
#endif
2013-10-10 20:01:51 -04:00
//****************************************************************************
2014-04-13 21:35:34 -04:00
//! Native QF Event Queue class
2015-05-14 16:05:04 -04:00
/// @description
2012-08-14 18:00:48 -04:00
/// 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,
2015-05-14 16:05:04 -04:00
/// device drivers, or other third-party components.@n
/// @n
2012-08-14 18:00:48 -04:00
/// The native QF event queue is configured by defining the macro
2015-05-14 16:05:04 -04:00
/// #QF_EQUEUE_TYPE as QP::QEQueue in the specific QF port header file.@n
/// @n
2014-04-13 21:35:34 -04:00
/// The QP::QEQueue class contains only data members for managing an event
2012-08-14 18:00:48 -04:00
/// queue, but does not contain the storage for the queue buffer, which must
2015-05-14 16:05:04 -04:00
/// be provided externally during the queue initialization.@n
/// @n
2012-08-14 18:00:48 -04:00
/// 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
2015-05-14 16:05:04 -04:00
/// of empty queue.@n
/// @n
2014-04-13 21:35:34 -04:00
/// The QP::QEQueue class is used with two sets of functions. One set is for
2012-08-14 18:00:48 -04:00
/// 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
2015-05-14 16:05:04 -04:00
/// consists of the following functions: QP::QMActive::post(),
/// QP::QMActive::postLIFO(), and QP::QMActive::get_(). Additionally the
/// function QP::QEQueue::init() is used to initialize the queue.@n
/// @n
2014-04-13 21:35:34 -04:00
/// The other set of functions, uses this class as a simple "raw" event
2012-08-14 18:00:48 -04:00
/// 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
2014-04-13 21:35:34 -04:00
/// consists of the following functions: QP::QEQueue::post(),
/// QP::QEQueue::postLIFO(), and QP::QEQueue::get(). Additionally the
2015-05-14 16:05:04 -04:00
/// function QP::QEQueue::init() is used to initialize the queue.@n
/// @n
/// @note Most event queue operations (both the active object queues and
2012-08-14 18:00:48 -04:00
/// 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.
class QEQueue {
private:
2014-04-13 21:35:34 -04:00
//! pointer to event at the front of the queue
2015-05-14 16:05:04 -04:00
/// @description
2012-08-14 18:00:48 -04:00
/// 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
2015-05-14 16:05:04 -04:00
/// engage the ring buffer.@n
/// @n
2012-08-14 18:00:48 -04:00
/// The additional role of this attribute is to indicate the empty status
/// of the queue. The queue is empty if the m_frontEvt location is NULL.
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
2012-08-14 18:00:48 -04:00
QEvt const **m_ring;
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.
2015-05-14 16:05:04 -04:00
/// @note this attribute remembers the low-watermark of the ring buffer,
2012-08-14 18:00:48 -04:00
/// which provides a valuable information for sizing event queues.
2015-05-14 16:05:04 -04:00
/// @sa QP::QF::getQueueMin().
2012-08-14 18:00:48 -04:00
QEQueueCtr m_nMin;
public:
2014-04-13 21:35:34 -04:00
//! public default constructor
QEQueue(void);
2012-08-14 18:00:48 -04:00
2014-04-13 21:35:34 -04:00
//! Initializes the native QF event queue
2015-05-14 16:05:04 -04:00
/// @description
/// The parameters are as follows: @p qSto[] is the ring buffer storage,
/// @p qLen is the length of the ring buffer in the units of event-
2012-08-14 18:00:48 -04:00
/// pointers.
///
2015-05-14 16:05:04 -04:00
/// @note The actual capacity of the queue is qLen + 1, because of the
2012-08-14 18:00:48 -04:00
/// extra location fornEvt_.
2014-04-13 21:35:34 -04:00
void init(QEvt const *qSto[], uint_fast16_t const qLen);
2012-08-14 18:00:48 -04:00
2014-04-13 21:35:34 -04:00
//! "raw" thread-safe QF event queue implementation for the event
//! posting (FIFO). You can call this function from any task context or
//! ISR context. This function uses internally a critical section.
2015-05-14 16:05:04 -04:00
/// @description
/// The argument @p margin specifies the minimum number of free entries
2013-10-10 20:01:51 -04:00
/// in the queue that must be available for posting to succeed. The
/// function returns true (success) if the posting succeeded (with the
/// provided margin) and false (failure) when the posting fails.
///
2015-05-14 16:05:04 -04:00
/// @note
/// The function raises an assertion if the @p margin is zero and the
2014-04-13 21:35:34 -04:00
/// queue becomes full and cannot accept the event.
2012-08-14 18:00:48 -04:00
///
2015-05-14 16:05:04 -04:00
/// @sa QP::QEQueue::postLIFO(), QP::QEQueue::get()
2014-04-13 21:35:34 -04:00
bool post(QEvt const * const e, uint_fast16_t const margin);
2012-08-14 18:00:48 -04:00
2014-04-13 21:35:34 -04:00
//! "raw" thread-safe QF event queue implementation for the
//! First-In-First-Out (FIFO) event posting. You can call this function
//! from any task context or ISR context. Please note that this function
//! uses internally a critical section.
2015-05-14 16:05:04 -04:00
/// @note The function raises an assertion if the native QF queue becomes
2012-08-14 18:00:48 -04:00
/// full and cannot accept the event.
///
2015-05-14 16:05:04 -04:00
/// @sa QP::QEQueue::postLIFO(), QP::QEQueue::get()
2012-08-14 18:00:48 -04:00
void postLIFO(QEvt const * const e);
2014-04-13 21:35:34 -04:00
//! "raw" thread-safe QF event queue implementation for the
//! Last-In-First-Out (LIFO) event posting.
2015-05-14 16:05:04 -04:00
/// @note
2014-04-13 21:35:34 -04:00
/// The LIFO policy should be used only with great caution because it
/// alters order of events in the queue.
2015-05-14 16:05:04 -04:00
/// @note
2014-04-13 21:35:34 -04:00
/// The function raises an assertion if the native QF queue becomes
2012-08-14 18:00:48 -04:00
/// full and cannot accept the event. You can call this function from
/// any task context or ISR context. Please note that this function uses
/// internally a critical section.
///
2015-05-14 16:05:04 -04:00
/// @sa QP::QEQueue::post(), QP::QEQueue::postLIFO(), QP::QEQueue::get()
2012-08-14 18:00:48 -04:00
QEvt const *get(void);
2014-04-13 21:35:34 -04:00
//! "raw" thread-safe QF event queue operation for obtaining the number
//! of free entries still available in the queue.
2015-05-14 16:05:04 -04:00
/// @note
2014-04-13 21:35:34 -04:00
/// This operation needs to be used with caution because the
2012-08-14 18:00:48 -04:00
/// 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.
///
2015-05-14 16:05:04 -04:00
/// @sa QP::QMActive::defer(), QP::QMActive::recall()
2012-08-14 18:00:48 -04:00
QEQueueCtr getNFree(void) const {
return m_nFree;
}
2014-04-13 21:35:34 -04:00
//! "raw" thread-safe QF event queue operation to find out if the queue
//! is empty
2015-05-14 16:05:04 -04:00
/// @note
2014-04-13 21:35:34 -04:00
/// This operation needs to be used with caution because the
2012-12-10 16:01:54 -05:00
/// queue status can change unexpectedly. The main intent for using
2014-04-13 21:35:34 -04:00
/// this operation is in conjunction with event deferral. In this case
/// the queue is accessed only from a single thread (by a single AO),
2013-02-12 10:02:51 -05:00
/// so no other entity can post events to the queue.
2012-12-10 16:01:54 -05:00
///
2015-05-14 16:05:04 -04:00
/// @sa QP::QMActive::defer(), QP::QMActive::recall()
2012-12-10 16:01:54 -05:00
bool isEmpty(void) const {
return m_frontEvt == static_cast<QEvt const *>(0);
}
2012-08-14 18:00:48 -04:00
private:
2014-04-13 21:35:34 -04:00
//! disallow copying of QEQueue
QEQueue(QEQueue const &);
//! disallow assignment of QEQueue
QEQueue & operator=(QEQueue const &);
2013-12-30 17:41:15 -05:00
2012-08-14 18:00:48 -04:00
friend class QF;
2015-05-14 16:05:04 -04:00
friend class QMActive;
2012-08-14 18:00:48 -04:00
};
2014-04-13 21:35:34 -04:00
} // namespace QP
2012-08-14 18:00:48 -04:00
2014-04-13 21:35:34 -04:00
#endif // qequeue_h
2012-08-14 18:00:48 -04:00