/** * \file * \brief RawMessageQueue class header * * \author Copyright (C) 2015 Kamil Szczygiel http://www.distortec.com http://www.freddiechopin.info * * \par License * This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. If a copy of the MPL was not * distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #ifndef INCLUDE_DISTORTOS_RAWMESSAGEQUEUE_HPP_ #define INCLUDE_DISTORTOS_RAWMESSAGEQUEUE_HPP_ #include "distortos/internal/synchronization/MessageQueueBase.hpp" namespace distortos { /** * \brief RawMessageQueue class is very similar to MessageQueue, but optimized for binary serializable types (like POD * types). * * Type \a T can be used with both RawMessageQueue and MessageQueue only when * std::is_trivially_copyable::value == true, otherwise only MessageQueue use is safe, while using * RawMessageQueue results in undefined behavior. * * Similar to POSIX mqd_t - http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/mqueue.h.html * * \ingroup queues */ class RawMessageQueue { public: /// type of uninitialized storage for Entry with link using EntryStorage = internal::MessageQueueBase::EntryStorage; /// import EntryStorageUniquePointer type from internal::MessageQueueBase class using EntryStorageUniquePointer = internal::MessageQueueBase::EntryStorageUniquePointer; /** * type of uninitialized storage for value * * \tparam T is the type of data in queue */ template using ValueStorage = internal::MessageQueueBase::ValueStorage; using ValueStorageUniquePointer = internal::MessageQueueBase::ValueStorageUniquePointer; /** * \brief RawMessageQueue's constructor * * \param [in] entryStorageUniquePointer is a rvalue reference to EntryStorageUniquePointer with storage for queue * entries (sufficiently large for \a maxElements EntryStorage objects) and appropriate deleter * \param [in] valueStorageUniquePointer is a rvalue reference to ValueStorageUniquePointer with storage for queue * elements (sufficiently large for \a maxElements, each \a elementSize bytes long) and appropriate deleter * \param [in] elementSize is the size of single queue element, bytes * \param [in] maxElements is the number of elements in \a entryStorage array and \a valueStorage memory block */ RawMessageQueue(EntryStorageUniquePointer&& entryStorageUniquePointer, ValueStorageUniquePointer&& valueStorageUniquePointer, size_t elementSize, size_t maxElements); /** * \brief Pops oldest element with highest priority from the queue. * * Similar to mq_receive() - http://pubs.opengroup.org/onlinepubs/9699919799/functions/mq_receive.html# * * \param [out] priority is a reference to variable that will be used to return priority of popped value * \param [out] buffer is a pointer to buffer for popped element * \param [in] size is the size of \a buffer, bytes - must be equal to the \a elementSize attribute of * RawMessageQueue * * \return zero if element was popped successfully, error code otherwise: * - EMSGSIZE - \a size doesn't match the \a elementSize attribute of RawMessageQueue; * - error codes returned by Semaphore::wait(); * - error codes returned by Semaphore::post(); */ int pop(uint8_t& priority, void* buffer, size_t size); /** * \brief Pops oldest element with highest priority from the queue. * * Similar to mq_receive() - http://pubs.opengroup.org/onlinepubs/9699919799/functions/mq_receive.html# * * \tparam T is the type of data popped from the queue * * \param [out] priority is a reference to variable that will be used to return priority of popped value * \param [out] buffer is a reference to object that will be used to return popped value * * \return zero if element was popped successfully, error code otherwise: * - EMSGSIZE - sizeof(T) doesn't match the \a elementSize attribute of RawMessageQueue; * - error codes returned by Semaphore::wait(); * - error codes returned by Semaphore::post(); */ template int pop(uint8_t& priority, T& buffer) { return pop(priority, &buffer, sizeof(buffer)); } /** * \brief Pushes the element to the queue. * * Similar to mq_send() - http://pubs.opengroup.org/onlinepubs/9699919799/functions/mq_send.html# * * \param [in] priority is the priority of new element * \param [in] data is a pointer to data that will be pushed to RawMessageQueue * \param [in] size is the size of \a data, bytes - must be equal to the \a elementSize attribute of RawMessageQueue * * \return zero if element was pushed successfully, error code otherwise: * - EMSGSIZE - \a size doesn't match the \a elementSize attribute of RawMessageQueue; * - error codes returned by Semaphore::wait(); * - error codes returned by Semaphore::post(); */ int push(uint8_t priority, const void* data, size_t size); /** * \brief Pushes the element to the queue. * * Similar to mq_send() - http://pubs.opengroup.org/onlinepubs/9699919799/functions/mq_send.html# * * \tparam T is the type of data pushed to the queue * * \param [in] priority is the priority of new element * \param [in] data is a reference to data that will be pushed to RawMessageQueue * * \return zero if element was pushed successfully, error code otherwise: * - EMSGSIZE - sizeof(T) doesn't match the \a elementSize attribute of RawMessageQueue; * - error codes returned by Semaphore::wait(); * - error codes returned by Semaphore::post(); */ template int push(const uint8_t priority, const T& data) { return push(priority, &data, sizeof(data)); } /** * \brief Tries to pop the oldest element with highest priority from the queue. * * Similar to mq_receive() - http://pubs.opengroup.org/onlinepubs/9699919799/functions/mq_receive.html# * * \param [out] priority is a reference to variable that will be used to return priority of popped value * \param [out] buffer is a pointer to buffer for popped element * \param [in] size is the size of \a buffer, bytes - must be equal to the \a elementSize attribute of * RawMessageQueue * * \return zero if element was popped successfully, error code otherwise: * - EMSGSIZE - \a size doesn't match the \a elementSize attribute of RawMessageQueue; * - error codes returned by Semaphore::tryWait(); * - error codes returned by Semaphore::post(); */ int tryPop(uint8_t& priority, void* buffer, size_t size); /** * \brief Tries to pop the oldest element with highest priority from the queue. * * Similar to mq_receive() - http://pubs.opengroup.org/onlinepubs/9699919799/functions/mq_receive.html# * * \tparam T is the type of data popped from the queue * * \param [out] priority is a reference to variable that will be used to return priority of popped value * \param [out] buffer is a reference to object that will be used to return popped value * * \return zero if element was popped successfully, error code otherwise: * - EMSGSIZE - sizeof(T) doesn't match the \a elementSize attribute of RawMessageQueue; * - error codes returned by Semaphore::tryWait(); * - error codes returned by Semaphore::post(); */ template int tryPop(uint8_t& priority, T& buffer) { return tryPop(priority, &buffer, sizeof(buffer)); } /** * \brief Tries to pop the oldest element with highest priority from the queue for a given duration of time. * * Similar to mq_timedreceive() - http://pubs.opengroup.org/onlinepubs/9699919799/functions/mq_receive.html# * * \param [in] duration is the duration after which the call will be terminated without popping the element * \param [out] priority is a reference to variable that will be used to return priority of popped value * \param [out] buffer is a pointer to buffer for popped element * \param [in] size is the size of \a buffer, bytes - must be equal to the \a elementSize attribute of * RawMessageQueue * * \return zero if element was popped successfully, error code otherwise: * - EMSGSIZE - \a size doesn't match the \a elementSize attribute of RawMessageQueue; * - error codes returned by Semaphore::tryWaitFor(); * - error codes returned by Semaphore::post(); */ int tryPopFor(TickClock::duration duration, uint8_t& priority, void* buffer, size_t size); /** * \brief Tries to pop the oldest element with highest priority from the queue for a given duration of time. * * Template variant of tryPopFor(TickClock::duration, uint8_t&, void*, size_t). * * \tparam Rep is type of tick counter * \tparam Period is std::ratio type representing the tick period of the clock, in seconds * * \param [in] duration is the duration after which the call will be terminated without popping the element * \param [out] priority is a reference to variable that will be used to return priority of popped value * \param [out] buffer is a pointer to buffer for popped element * \param [in] size is the size of \a buffer, bytes - must be equal to the \a elementSize attribute of * RawMessageQueue * * \return zero if element was popped successfully, error code otherwise: * - EMSGSIZE - \a size doesn't match the \a elementSize attribute of RawMessageQueue; * - error codes returned by Semaphore::tryWaitFor(); * - error codes returned by Semaphore::post(); */ template int tryPopFor(const std::chrono::duration duration, uint8_t& priority, void* const buffer, const size_t size) { return tryPopFor(std::chrono::duration_cast(duration), priority, buffer, size); } /** * \brief Tries to pop the oldest element with highest priority from the queue for a given duration of time. * * Similar to mq_timedreceive() - http://pubs.opengroup.org/onlinepubs/9699919799/functions/mq_receive.html# * * \tparam Rep is type of tick counter * \tparam Period is std::ratio type representing the tick period of the clock, in seconds * \tparam T is the type of data popped from the queue * * \param [in] duration is the duration after which the call will be terminated without popping the element * \param [out] priority is a reference to variable that will be used to return priority of popped value * \param [out] buffer is a reference to object that will be used to return popped value * * \return zero if element was popped successfully, error code otherwise: * - EMSGSIZE - sizeof(T) doesn't match the \a elementSize attribute of RawMessageQueue; * - error codes returned by Semaphore::tryWaitFor(); * - error codes returned by Semaphore::post(); */ template int tryPopFor(const std::chrono::duration duration, uint8_t& priority, T& buffer) { return tryPopFor(std::chrono::duration_cast(duration), priority, &buffer, sizeof(buffer)); } /** * \brief Tries to pop the oldest element with highest priority from the queue until a given time point. * * Similar to mq_timedreceive() - http://pubs.opengroup.org/onlinepubs/9699919799/functions/mq_receive.html# * * \param [in] timePoint is the time point at which the call will be terminated without popping the element * \param [out] priority is a reference to variable that will be used to return priority of popped value * \param [out] buffer is a pointer to buffer for popped element * \param [in] size is the size of \a buffer, bytes - must be equal to the \a elementSize attribute of * RawMessageQueue * * \return zero if element was popped successfully, error code otherwise: * - EMSGSIZE - \a size doesn't match the \a elementSize attribute of RawMessageQueue; * - error codes returned by Semaphore::tryWaitUntil(); * - error codes returned by Semaphore::post(); */ int tryPopUntil(TickClock::time_point timePoint, uint8_t& priority, void* buffer, size_t size); /** * \brief Tries to pop the oldest element with highest priority from the queue until a given time point. * * Template variant of tryPopUntil(TickClock::time_point, uint8_t&, void*, size_t). * * \tparam Duration is a std::chrono::duration type used to measure duration * * \param [in] timePoint is the time point at which the call will be terminated without popping the element * \param [out] priority is a reference to variable that will be used to return priority of popped value * \param [out] buffer is a pointer to buffer for popped element * \param [in] size is the size of \a buffer, bytes - must be equal to the \a elementSize attribute of * RawMessageQueue * * \return zero if element was popped successfully, error code otherwise: * - EMSGSIZE - \a size doesn't match the \a elementSize attribute of RawMessageQueue; * - error codes returned by Semaphore::tryWaitUntil(); * - error codes returned by Semaphore::post(); */ template int tryPopUntil(const std::chrono::time_point timePoint, uint8_t& priority, void* const buffer, const size_t size) { return tryPopUntil(std::chrono::time_point_cast(timePoint), priority, buffer, size); } /** * \brief Tries to pop the oldest element with highest priority from the queue until a given time point. * * Similar to mq_timedreceive() - http://pubs.opengroup.org/onlinepubs/9699919799/functions/mq_receive.html# * * \tparam Duration is a std::chrono::duration type used to measure duration * \tparam T is the type of data popped from the queue * * \param [in] timePoint is the time point at which the call will be terminated without popping the element * \param [out] priority is a reference to variable that will be used to return priority of popped value * \param [out] buffer is a reference to object that will be used to return popped value * * \return zero if element was popped successfully, error code otherwise: * - EMSGSIZE - sizeof(T) doesn't match the \a elementSize attribute of RawMessageQueue; * - error codes returned by Semaphore::tryWaitUntil(); * - error codes returned by Semaphore::post(); */ template int tryPopUntil(const std::chrono::time_point timePoint, uint8_t& priority, T& buffer) { return tryPopUntil(std::chrono::time_point_cast(timePoint), priority, &buffer, sizeof(buffer)); } /** * \brief Tries to push the element to the queue. * * Similar to mq_send() - http://pubs.opengroup.org/onlinepubs/9699919799/functions/mq_send.html# * * \param [in] priority is the priority of new element * \param [in] data is a pointer to data that will be pushed to RawMessageQueue * \param [in] size is the size of \a data, bytes - must be equal to the \a elementSize attribute of RawMessageQueue * * \return zero if element was pushed successfully, error code otherwise: * - EMSGSIZE - \a size doesn't match the \a elementSize attribute of RawMessageQueue; * - error codes returned by Semaphore::tryWait(); * - error codes returned by Semaphore::post(); */ int tryPush(uint8_t priority, const void* data, size_t size); /** * \brief Tries to push the element to the queue. * * Similar to mq_send() - http://pubs.opengroup.org/onlinepubs/9699919799/functions/mq_send.html# * * \tparam T is the type of data pushed to the queue * * \param [in] priority is the priority of new element * \param [in] data is a reference to data that will be pushed to RawMessageQueue * * \return zero if element was pushed successfully, error code otherwise: * - EMSGSIZE - sizeof(T) doesn't match the \a elementSize attribute of RawMessageQueue; * - error codes returned by Semaphore::tryWait(); * - error codes returned by Semaphore::post(); */ template int tryPush(const uint8_t priority, const T& data) { return tryPush(priority, &data, sizeof(data)); } /** * \brief Tries to push the element to the queue for a given duration of time. * * Similar to mq_timedsend() - http://pubs.opengroup.org/onlinepubs/9699919799/functions/mq_send.html# * * \param [in] duration is the duration after which the wait will be terminated without pushing the element * \param [in] priority is the priority of new element * \param [in] data is a pointer to data that will be pushed to RawMessageQueue * \param [in] size is the size of \a data, bytes - must be equal to the \a elementSize attribute of RawMessageQueue * * \return zero if element was pushed successfully, error code otherwise: * - EMSGSIZE - \a size doesn't match the \a elementSize attribute of RawMessageQueue; * - error codes returned by Semaphore::tryWaitFor(); * - error codes returned by Semaphore::post(); */ int tryPushFor(TickClock::duration duration, uint8_t priority, const void* data, size_t size); /** * \brief Tries to push the element to the queue for a given duration of time. * * Template variant of tryPushFor(TickClock::duration, uint8_t, const void*, size_t). * * \tparam Rep is type of tick counter * \tparam Period is std::ratio type representing the tick period of the clock, in seconds * * \param [in] duration is the duration after which the wait will be terminated without pushing the element * \param [in] priority is the priority of new element * \param [in] data is a pointer to data that will be pushed to RawMessageQueue * \param [in] size is the size of \a data, bytes - must be equal to the \a elementSize attribute of RawMessageQueue * * \return zero if element was pushed successfully, error code otherwise: * - EMSGSIZE - \a size doesn't match the \a elementSize attribute of RawMessageQueue; * - error codes returned by Semaphore::tryWaitFor(); * - error codes returned by Semaphore::post(); */ template int tryPushFor(const std::chrono::duration duration, const uint8_t priority, const void* const data, const size_t size) { return tryPushFor(std::chrono::duration_cast(duration), priority, data, size); } /** * \brief Tries to push the element to the queue for a given duration of time. * * Similar to mq_timedsend() - http://pubs.opengroup.org/onlinepubs/9699919799/functions/mq_send.html# * * \tparam Rep is type of tick counter * \tparam Period is std::ratio type representing the tick period of the clock, in seconds * \tparam T is the type of data pushed to the queue * * \param [in] duration is the duration after which the wait will be terminated without pushing the element * \param [in] priority is the priority of new element * \param [in] data is a reference to data that will be pushed to RawMessageQueue * * \return zero if element was pushed successfully, error code otherwise: * - EMSGSIZE - sizeof(T) doesn't match the \a elementSize attribute of RawMessageQueue; * - error codes returned by Semaphore::tryWaitFor(); * - error codes returned by Semaphore::post(); */ template int tryPushFor(const std::chrono::duration duration, const uint8_t priority, const T& data) { return tryPushFor(std::chrono::duration_cast(duration), priority, &data, sizeof(data)); } /** * \brief Tries to push the element to the queue until a given time point. * * Similar to mq_timedsend() - http://pubs.opengroup.org/onlinepubs/9699919799/functions/mq_send.html# * * \param [in] timePoint is the time point at which the call will be terminated without pushing the element * \param [in] priority is the priority of new element * \param [in] data is a pointer to data that will be pushed to RawMessageQueue * \param [in] size is the size of \a data, bytes - must be equal to the \a elementSize attribute of RawMessageQueue * * \return zero if element was pushed successfully, error code otherwise: * - EMSGSIZE - \a size doesn't match the \a elementSize attribute of RawMessageQueue; * - error codes returned by Semaphore::tryWaitUntil(); * - error codes returned by Semaphore::post(); */ int tryPushUntil(TickClock::time_point timePoint, uint8_t priority, const void* data, size_t size); /** * \brief Tries to push the element to the queue until a given time point. * * Template variant of tryPushUntil(TickClock::time_point, uint8_t, const void*, size_t). * * \tparam Duration is a std::chrono::duration type used to measure duration * * \param [in] timePoint is the time point at which the call will be terminated without pushing the element * \param [in] priority is the priority of new element * \param [in] data is a pointer to data that will be pushed to RawMessageQueue * \param [in] size is the size of \a data, bytes - must be equal to the \a elementSize attribute of RawMessageQueue * * \return zero if element was pushed successfully, error code otherwise: * - EMSGSIZE - \a size doesn't match the \a elementSize attribute of RawMessageQueue; * - error codes returned by Semaphore::tryWaitUntil(); * - error codes returned by Semaphore::post(); */ template int tryPushUntil(const std::chrono::time_point timePoint, const uint8_t priority, const void* const data, const size_t size) { return tryPushUntil(std::chrono::time_point_cast(timePoint), priority, data, size); } /** * \brief Tries to push the element to the queue until a given time point. * * Similar to mq_timedsend() - http://pubs.opengroup.org/onlinepubs/9699919799/functions/mq_send.html# * * \tparam Duration is a std::chrono::duration type used to measure duration * \tparam T is the type of data pushed to the queue * * \param [in] timePoint is the time point at which the call will be terminated without pushing the element * \param [in] priority is the priority of new element * \param [in] data is a reference to data that will be pushed to RawMessageQueue * * \return zero if element was pushed successfully, error code otherwise: * - EMSGSIZE - sizeof(T) doesn't match the \a elementSize attribute of RawMessageQueue; * - error codes returned by Semaphore::tryWaitUntil(); * - error codes returned by Semaphore::post(); */ template int tryPushUntil(const std::chrono::time_point timePoint, const uint8_t priority, const T& data) { return tryPushUntil(std::chrono::time_point_cast(timePoint), priority, &data, sizeof(data)); } private: /** * \brief Pops oldest element with highest priority from the queue. * * Internal version - builds the Functor object. * * \param [in] waitSemaphoreFunctor is a reference to SemaphoreFunctor which will be executed with \a popSemaphore_ * \param [out] priority is a reference to variable that will be used to return priority of popped value * \param [out] buffer is a pointer to buffer for popped element * \param [in] size is the size of \a buffer, bytes - must be equal to the \a elementSize attribute of * RawMessageQueue * * \return zero if element was popped successfully, error code otherwise: * - EMSGSIZE - \a size doesn't match the \a elementSize attribute of RawMessageQueue; * - error codes returned by \a waitSemaphoreFunctor's operator() call; * - error codes returned by Semaphore::post(); */ int popInternal(const internal::SemaphoreFunctor& waitSemaphoreFunctor, uint8_t& priority, void* buffer, size_t size); /** * \brief Pushes the element to the queue. * * Internal version - builds the Functor object. * * \param [in] waitSemaphoreFunctor is a reference to SemaphoreFunctor which will be executed with \a pushSemaphore_ * \param [in] priority is the priority of new element * \param [in] data is a pointer to data that will be pushed to RawMessageQueue * \param [in] size is the size of \a data, bytes - must be equal to the \a elementSize attribute of RawMessageQueue * * \return zero if element was pushed successfully, error code otherwise: * - EMSGSIZE - \a size doesn't match the \a elementSize attribute of RawMessageQueue; * - error codes returned by \a waitSemaphoreFunctor's operator() call; * - error codes returned by Semaphore::post(); */ int pushInternal(const internal::SemaphoreFunctor& waitSemaphoreFunctor, uint8_t priority, const void* data, size_t size); /// contained internal::MessageQueueBase object which implements base functionality internal::MessageQueueBase messageQueueBase_; /// size of single queue element, bytes const size_t elementSize_; }; } // namespace distortos #endif // INCLUDE_DISTORTOS_RAWMESSAGEQUEUE_HPP_