1+ #ifndef KLIB_RTOS_QUEUE_HPP
2+ #define KLIB_RTOS_QUEUE_HPP
3+
4+ #include < atomic>
5+
6+ #include < klib/ringbuffer.hpp>
7+
8+ #include " waitable.hpp"
9+ #include " mutex.hpp"
10+
11+ namespace klib ::rtos {
12+ /* *
13+ * @brief Queue class for RTOS usage implemented using a ringbuffer
14+ *
15+ * @tparam Size
16+ */
17+ template <typename T, size_t MaxSize>
18+ class queue : public waitable {
19+ protected:
20+ std::atomic_bool waiting;
21+
22+ // mutex to protect access to the queue
23+ rtos::mutex mutex;
24+
25+ // ringbuffer to store the data
26+ klib::ringbuffer<T, MaxSize> buffer;
27+
28+ public:
29+ /* *
30+ * @brief Add an item to the queue.
31+ *
32+ * @param val
33+ */
34+ constexpr void push (const T &val) {
35+ mutex.lock ();
36+
37+ // wait until we have space in the buffer
38+ while (buffer.full ()) {
39+ // mark as waiting
40+ waiting.store (true );
41+
42+ // unlock the mutex while waiting
43+ mutex.unlock ();
44+
45+ // yield to other tasks
46+ rtos::syscall::yield (*this );
47+
48+ // lock the mutex again
49+ mutex.lock ();
50+ }
51+
52+ // push the item to the buffer
53+ buffer.push (val);
54+
55+ // clear the waiting flag for the other side if it was waiting
56+ // on data to be available in the buffer
57+ waiting.store (false );
58+
59+ // unlock the mutex
60+ mutex.unlock ();
61+ }
62+
63+ /* *
64+ * @brief Copy the last item from the buffer and pop.
65+ *
66+ * @return
67+ */
68+ constexpr T copy_and_pop () {
69+ // lock the mutex while accessing the buffer
70+ mutex.lock ();
71+
72+ // wait until we have data in the buffer
73+ while (buffer.empty ()) {
74+ // mark as waiting
75+ waiting.store (true );
76+
77+ // unlock the mutex while waiting
78+ mutex.unlock ();
79+
80+ // yield to other tasks
81+ rtos::syscall::yield (*this );
82+
83+ // lock the mutex again
84+ mutex.lock ();
85+ }
86+
87+ // copy and pop the item
88+ T item = buffer.copy_and_pop ();
89+
90+ // clear the waiting flag for the other side if it was waiting
91+ // on space in the buffer
92+ waiting.store (false );
93+
94+ // unlock the mutex
95+ mutex.unlock ();
96+
97+ // return the item
98+ return item;
99+ }
100+
101+ /* *
102+ * @brief clear the queue.
103+ *
104+ * @return
105+ */
106+ constexpr void clear () {
107+ // lock the mutex while clearing the buffer
108+ mutex.lock ();
109+
110+ // clear the buffer
111+ buffer.clear ();
112+
113+ // unlock the mutex
114+ mutex.unlock ();
115+ }
116+
117+ /* *
118+ * @brief Return whether the queue is empty.
119+ *
120+ * @return
121+ */
122+ constexpr bool empty () {
123+ // lock the mutex while accessing the buffer
124+ mutex.lock ();
125+
126+ // check if the buffer is empty
127+ const bool is_empty = buffer.empty ();
128+
129+ // unlock the mutex
130+ mutex.unlock ();
131+
132+ return is_empty;
133+ }
134+
135+ /* *
136+ * @brief Return whether the queue is full.
137+ *
138+ * @return
139+ */
140+ constexpr bool full () {
141+ // lock the mutex while accessing the buffer
142+ mutex.lock ();
143+
144+ // check if the buffer is full
145+ const bool is_full = buffer.full ();
146+
147+ // unlock the mutex
148+ mutex.unlock ();
149+
150+ return is_full;
151+ }
152+
153+ /* *
154+ * @brief Get the current size of the queue.
155+ *
156+ * @return
157+ */
158+ constexpr size_t size () {
159+ // lock the mutex while accessing the buffer
160+ mutex.lock ();
161+
162+ // get the size of the buffer
163+ const size_t current_size = buffer.size ();
164+
165+ // unlock the mutex
166+ mutex.unlock ();
167+
168+ return current_size;
169+ }
170+
171+ /* *
172+ * @brief Get the maximum size of the queue.
173+ *
174+ * @return
175+ */
176+ constexpr size_t max_size () const {
177+ return MaxSize;
178+ }
179+
180+ /* *
181+ * @brief
182+ *
183+ * @return true
184+ * @return false
185+ */
186+ virtual bool is_waiting () const override {
187+ return waiting.load ();
188+ }
189+ };
190+ }
191+
192+ #endif
0 commit comments