F´ Flight Software - C/C++ Documentation
A framework for building embedded system applications to NASA flight quality standards.
LocklessPriorityQueue.hpp
Go to the documentation of this file.
1 // ======================================================================
2 // \title Os/Generic/LocklessPriorityQueue.hpp
3 // \brief lockless ISR-safe priority queue implementation for Os::Queue
4 // ======================================================================
5 #ifndef OS_GENERIC_LOCKLESSPRIORITYQUEUE_HPP
6 #define OS_GENERIC_LOCKLESSPRIORITYQUEUE_HPP
7 
8 #include <atomic>
9 #include <limits>
10 #include <type_traits>
11 #include "Fw/FPrimeBasicTypes.hpp"
12 #include "Os/Queue.hpp"
13 #include "config/LocklessQueueCfg.hpp"
14 
15 namespace Os {
16 namespace Generic {
17 
18 static_assert(std::is_integral<LocklessStateTagType>::value && std::is_unsigned<LocklessStateTagType>::value,
19  "LocklessStateTagType must be an unsigned integral type");
20 
29 template <FwSizeType WIDTH>
31  static constexpr bool value = ((sizeof(unsigned char) == WIDTH) && (ATOMIC_CHAR_LOCK_FREE != 0)) ||
32  ((sizeof(unsigned short) == WIDTH) && (ATOMIC_SHORT_LOCK_FREE != 0)) ||
33  ((sizeof(unsigned int) == WIDTH) && (ATOMIC_INT_LOCK_FREE != 0)) ||
34  ((sizeof(unsigned long) == WIDTH) && (ATOMIC_LONG_LOCK_FREE != 0)) ||
35  ((sizeof(unsigned long long) == WIDTH) && (ATOMIC_LLONG_LOCK_FREE != 0));
36 };
37 
38 static_assert(LocklessAtomicLockFree<sizeof(LocklessStateTagType)>::value,
39  "std::atomic<LocklessStateTagType> is never lock-free on this platform; "
40  "configure a narrower type in config/LocklessQueueCfg.hpp");
41 static_assert(LocklessAtomicLockFree<sizeof(U32)>::value, "std::atomic<U32> is never lock-free on this platform");
42 static_assert(LocklessAtomicLockFree<sizeof(FwQueuePriorityType)>::value,
43  "std::atomic<FwQueuePriorityType> is never lock-free on this platform");
44 
45 static_assert(LOCKLESS_QUEUE_MAX_RETRY_PASSES >= 1, "LOCKLESS_QUEUE_MAX_RETRY_PASSES must be at least 1");
46 
47 // A zero backoff could livelock a high-priority blocking caller against a lower-priority
48 // thread on a strict-priority scheduler.
49 static_assert(LOCKLESS_QUEUE_BLOCKING_BACKOFF_US > 0, "LOCKLESS_QUEUE_BLOCKING_BACKOFF_US must be greater than 0");
50 
52  "LOCKLESS_QUEUE_SLOT_ALIGNMENT must be a power of two");
53 
64 };
65 
74 struct alignas(LOCKLESS_QUEUE_SLOT_ALIGNMENT) LocklessSlot {
76  static constexpr U32 STATE_BITS = 2;
78  static constexpr LocklessStateTagType STATE_MASK =
79  (static_cast<LocklessStateTagType>(1) << STATE_BITS) - static_cast<LocklessStateTagType>(1);
81  static constexpr U32 TAG_BITS = static_cast<U32>(std::numeric_limits<LocklessStateTagType>::digits) - STATE_BITS;
82 
88  std::atomic<LocklessStateTagType> m_stateTag;
91  std::atomic<U32> m_sequence;
96  std::atomic<FwQueuePriorityType> m_priority;
97 
99  LocklessSlot();
100 };
101 
119  std::atomic<U32> m_sequence;
121  std::atomic<U32> m_count;
124  std::atomic<U32> m_available;
126  std::atomic<U32> m_highMark;
129 
132 };
133 
171  public:
176  static constexpr FwSizeType MAX_RETRY_PASSES = LOCKLESS_QUEUE_MAX_RETRY_PASSES;
177 
188  static bool isCandidatePreferred(FwQueuePriorityType candidatePriority,
189  U32 candidateSequence,
190  FwQueuePriorityType bestPriority,
191  U32 bestSequence);
192 
194  LocklessPriorityQueue() = default;
195 
204  ~LocklessPriorityQueue() override;
205 
207  LocklessPriorityQueue(const QueueInterface& other) = delete;
208 
210  LocklessPriorityQueue(const QueueInterface* other) = delete;
211 
213  LocklessPriorityQueue& operator=(const QueueInterface& other) override = delete;
214 
227  Status create(FwEnumStoreType id,
228  const Fw::ConstStringBase& name,
229  FwSizeType depth,
230  FwSizeType messageSize) override;
231 
239  void teardown() override;
240 
261  Status send(const U8* buffer, FwSizeType size, FwQueuePriorityType priority, BlockingType blockType) override;
262 
282  Status receive(U8* destination,
283  FwSizeType capacity,
284  BlockingType blockType,
285  FwSizeType& actualSize,
286  FwQueuePriorityType& priority) override;
287 
294  FwSizeType getMessagesAvailable() const override;
295 
299  FwSizeType getMessageHighWaterMark() const override;
300 
302  QueueHandle* getHandle() override;
303 
306 };
307 
308 } // namespace Generic
309 } // namespace Os
310 
311 #endif // OS_GENERIC_LOCKLESSPRIORITYQUEUE_HPP
std::atomic< U32 > m_count
Occupancy count (claimed-or-queued slots) used only for the high-water mark.
PlatformSizeType FwSizeType
I32 FwEnumStoreType
slot contains no data; available to a producer
Status
status returned from the queue send function
Definition: Queue.hpp:30
handle for the lockless priority queue
LocklessSlot * m_slots
Pre-allocated array of m_depth slots, aligned within m_slotsAllocation.
consumer has reserved the slot and is draining it
QueueHandle parent class.
Definition: Queue.hpp:19
constexpr FwSizeType LOCKLESS_QUEUE_SLOT_ALIGNMENT
FwSizeType m_depth
Configured queue depth in messages.
base queue interface
Definition: Queue.hpp:27
constexpr FwSizeType LOCKLESS_QUEUE_MAX_RETRY_PASSES
std::atomic< FwQueuePriorityType > m_priority
Stored message priority. Atomic because consumers read it during the scan phase.
LocklessPriorityQueueHandle m_handle
Persistent queue state.
per-slot data for the lockless priority queue
void * m_slotsAllocation
Raw allocation backing m_slots; retained because allocators may ignore alignment. ...
std::atomic< U32 > m_sequence
Sequence assigned to messages on publication for FIFO tiebreak; may wrap (compared modularly)...
std::atomic< LocklessStateTagType > m_stateTag
LocklessSlotState
slot lifecycle states for the lockless priority queue
uint8_t U8
8-bit unsigned integer
Definition: BasicTypes.h:54
BlockingType
message type
Definition: Queue.hpp:46
producer has reserved the slot and is filling it
PlatformQueuePriorityType FwQueuePriorityType
The type of queue priorities used.
constexpr U32 LOCKLESS_QUEUE_BLOCKING_BACKOFF_US
A read-only abstract superclass for StringBase.
std::atomic< U32 > m_highMark
Maximum value m_count has ever held. Updated by producers via a bounded CAS loop. ...
FwEnumStoreType m_id
Identifier passed to the memory allocator at create() time and reused at teardown().
slot contains a published message available to a consumer
compile-time lock-free possibility for an atomic of unsigned integral width WIDTH ...
U8 * m_data
Pre-allocated array of m_depth * m_messageSize bytes for message payloads.
FwSizeType m_messageSize
Configured maximum size of a single message.
lockless ISR-safe priority queue implementation for Os::QueueInterface