Embedded Template Library 1.0
queue_mpmc_mutex.h
Go to the documentation of this file.
1
2
3/******************************************************************************
4The MIT License(MIT)
5
6Embedded Template Library.
7https://github.com/ETLCPP/etl
8https://www.etlcpp.com
9
10Copyright(c) 2018 John Wellbelove
11
12Permission is hereby granted, free of charge, to any person obtaining a copy
13of this software and associated documentation files(the "Software"), to deal
14in the Software without restriction, including without limitation the rights
15to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
16copies of the Software, and to permit persons to whom the Software is
17furnished to do so, subject to the following conditions :
18
19The above copyright notice and this permission notice shall be included in all
20copies or substantial portions of the Software.
21
22THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
23IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
24FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
25AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
26LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
27OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
28SOFTWARE.
29******************************************************************************/
30
31#ifndef ETL_MPMC_QUEUE_MUTEX_INCLUDED
32#define ETL_MPMC_QUEUE_MUTEX_INCLUDED
33
34#include "platform.h"
35#include "mutex.h"
36
37#if ETL_HAS_MUTEX
38
39#include "alignment.h"
40#include "parameter_type.h"
41#include "memory_model.h"
42#include "integral_limits.h"
43#include "utility.h"
44#include "placement_new.h"
45
46#include <stddef.h>
47#include <stdint.h>
48
49namespace etl
50{
51 template <size_t MEMORY_MODEL = etl::memory_model::MEMORY_MODEL_LARGE>
52 class queue_mpmc_mutex_base
53 {
54 public:
55
57 typedef typename etl::size_type_lookup<MEMORY_MODEL>::type size_type;
58
59 //*************************************************************************
61 //*************************************************************************
62 size_type capacity() const
63 {
64 return MAX_SIZE;
65 }
66
67 //*************************************************************************
69 //*************************************************************************
70 size_type max_size() const
71 {
72 return MAX_SIZE;
73 }
74
75 protected:
76
77 queue_mpmc_mutex_base(size_type max_size_)
78 : write_index(0),
79 read_index(0),
80 current_size(0),
81 MAX_SIZE(max_size_)
82 {
83 }
84
85 //*************************************************************************
87 //*************************************************************************
88 static size_type get_next_index(size_type index, size_type maximum)
89 {
90 ++index;
91
92 if (index == maximum) ETL_UNLIKELY
93 {
94 index = 0;
95 }
96
97 return index;
98 }
99
100 size_type write_index;
101 size_type read_index;
102 size_type current_size;
103 const size_type MAX_SIZE;
104
105 //*************************************************************************
107 //*************************************************************************
108#if defined(ETL_POLYMORPHIC_MPMC_QUEUE_MUTEX) || defined(ETL_POLYMORPHIC_CONTAINERS)
109 public:
110 virtual ~queue_mpmc_mutex_base()
111 {
112 }
113#else
114 protected:
115 ~queue_mpmc_mutex_base()
116 {
117 }
118#endif
119 };
120
121 //***************************************************************************
131 //***************************************************************************
132 template <typename T, const size_t MEMORY_MODEL = etl::memory_model::MEMORY_MODEL_LARGE>
133 class iqueue_mpmc_mutex : public queue_mpmc_mutex_base<MEMORY_MODEL>
134 {
135 private:
136
137 typedef etl::queue_mpmc_mutex_base<MEMORY_MODEL> base_t;
138
139 public:
140
141 typedef T value_type;
142 typedef T& reference;
143 typedef const T& const_reference;
144#if ETL_USING_CPP11
145 typedef T&& rvalue_reference;
146#endif
147 typedef typename base_t::size_type size_type;
148
149 using base_t::write_index;
150 using base_t::read_index;
151 using base_t::current_size;
152 using base_t::MAX_SIZE;
153 using base_t::get_next_index;
154
155 //*************************************************************************
157 //*************************************************************************
158 bool push(const_reference value)
159 {
160 access.lock();
161
162 bool result = push_implementation(value);
163
164 access.unlock();
165
166 return result;
167 }
168
169#if ETL_USING_CPP11
170 //*************************************************************************
172 //*************************************************************************
173 bool push(rvalue_reference value)
174 {
175 access.lock();
176
177 bool result = push_implementation(etl::move(value));
178
179 access.unlock();
180
181 return result;
182 }
183#endif
184
185#if ETL_USING_CPP11 && ETL_NOT_USING_STLPORT && !defined(ETL_QUEUE_MPMC_MUTEX_FORCE_CPP03_IMPLEMENTATION)
186 //*************************************************************************
189 //*************************************************************************
190 template <typename ... Args>
191 bool emplace(Args&&... args)
192 {
193 access.lock();
194
195 bool result = emplace_implementation(etl::forward<Args>(args)...);
196
197 access.unlock();
198
199 return result;
200 }
201#else
202 //*************************************************************************
205 //*************************************************************************
206 template <typename T1>
207 bool emplace(const T1& value1)
208 {
209 access.lock();
210
211 bool result = emplace_implementation(value1);
212
213 access.unlock();
214
215 return result;
216 }
217
218 //*************************************************************************
221 //*************************************************************************
222 template <typename T1, typename T2>
223 bool emplace(const T1& value1, const T2& value2)
224 {
225 access.lock();
226
227 bool result = emplace_implementation(value1, value2);
228
229 access.unlock();
230
231 return result;
232 }
233
234 //*************************************************************************
237 //*************************************************************************
238 template <typename T1, typename T2, typename T3>
239 bool emplace(const T1& value1, const T2& value2, const T3& value3)
240 {
241 access.lock();
242
243 bool result = emplace_implementation(value1, value2, value3);
244
245 access.unlock();
246
247 return result;
248 }
249
250 //*************************************************************************
253 //*************************************************************************
254 template <typename T1, typename T2, typename T3, typename T4>
255 bool emplace(const T1& value1, const T2& value2, const T3& value3, const T4& value4)
256 {
257 access.lock();
258
259 bool result = emplace_implementation(value1, value2, value3, value4);
260
261 access.unlock();
262
263 return result;
264 }
265#endif
266
267 //*************************************************************************
269 //*************************************************************************
270 bool pop(reference value)
271 {
272 access.lock();
273
274 bool result = pop_implementation(value);
275
276 access.unlock();
277
278 return result;
279 }
280
281 //*************************************************************************
283 //*************************************************************************
284 bool pop()
285 {
286 access.lock();
287
288 bool result = pop_implementation();
289
290 access.unlock();
291
292 return result;
293 }
294
295 //*************************************************************************
297 //*************************************************************************
298 reference front()
299 {
300 access.lock();
301
302 reference result = front_implementation();
303
304 access.unlock();
305
306 return result;
307 }
308
309 //*************************************************************************
311 //*************************************************************************
312 const_reference front() const
313 {
314 access.lock();
315
316 const_reference result = front_implementation();
317
318 access.unlock();
319
320 return result;
321 }
322
323 //*************************************************************************
325 //*************************************************************************
326 void clear()
327 {
328 access.lock();
329
330 while (pop_implementation())
331 {
332 // Do nothing.
333 }
334
335 access.unlock();
336 }
337
338 //*************************************************************************
340 //*************************************************************************
341 bool empty() const
342 {
343 access.lock();
344
345 size_type result = (current_size == 0);
346
347 access.unlock();
348
349 return result;
350 }
351
352 //*************************************************************************
354 //*************************************************************************
355 bool full() const
356 {
357 access.lock();
358
359 size_type result = (current_size == MAX_SIZE);
360
361 access.unlock();
362
363 return result;
364 }
365
366 //*************************************************************************
368 //*************************************************************************
369 size_type size() const
370 {
371 access.lock();
372
373 size_type result = current_size;
374
375 access.unlock();
376
377 return result;
378 }
379
380 //*************************************************************************
382 //*************************************************************************
383 size_type available() const
384 {
385 access.lock();
386
387 size_type result = MAX_SIZE - current_size;
388
389 access.unlock();
390
391 return result;
392 }
393
394 protected:
395
396 //*************************************************************************
398 //*************************************************************************
399 iqueue_mpmc_mutex(T* p_buffer_, size_type max_size_)
400 : base_t(max_size_),
401 p_buffer(p_buffer_)
402 {
403 }
404
405 private:
406
407 //*************************************************************************
409 //*************************************************************************
410 bool push_implementation(const_reference value)
411 {
412 if (current_size != MAX_SIZE)
413 {
414 ::new (&p_buffer[write_index]) T(value);
415
416 write_index = get_next_index(write_index, MAX_SIZE);
417
418 ++current_size;
419
420 return true;
421 }
422
423 // Queue is full.
424 return false;
425 }
426
427#if ETL_USING_CPP11 && ETL_NOT_USING_STLPORT && !defined(ETL_QUEUE_MPMC_MUTEX_FORCE_CPP03_IMPLEMENTATION)
428 //*************************************************************************
430 //*************************************************************************
431 bool push_implementation(rvalue_reference value)
432 {
433 if (current_size != MAX_SIZE)
434 {
435 ::new (&p_buffer[write_index]) T(etl::move(value));
436
437 write_index = get_next_index(write_index, MAX_SIZE);
438
439 ++current_size;
440
441 return true;
442 }
443
444 // Queue is full.
445 return false;
446 }
447#endif
448
449#if ETL_USING_CPP11 && ETL_NOT_USING_STLPORT && !defined(ETL_QUEUE_MPMC_MUTEX_FORCE_CPP03_IMPLEMENTATION)
450 //*************************************************************************
452 //*************************************************************************
453 template <typename ... Args>
454 bool emplace_implementation(Args&&... args)
455 {
456 if (current_size != MAX_SIZE)
457 {
458 ::new (&p_buffer[write_index]) T(etl::forward<Args>(args)...);
459
460 write_index = get_next_index(write_index, MAX_SIZE);
461
462 ++current_size;
463
464 return true;
465 }
466
467 // Queue is full.
468 return false;
469 }
470#else
471 //*************************************************************************
473 //*************************************************************************
474 template <typename T1>
475 bool emplace_implementation(const T1& value1)
476 {
477 if (current_size != MAX_SIZE)
478 {
479 ::new (&p_buffer[write_index]) T(value1);
480
481 write_index = get_next_index(write_index, MAX_SIZE);
482
483 ++current_size;
484
485 return true;
486 }
487
488 // Queue is full.
489 return false;
490 }
491
492 //*************************************************************************
494 //*************************************************************************
495 template <typename T1, typename T2>
496 bool emplace_implementation(const T1& value1, const T2& value2)
497 {
498 if (current_size != MAX_SIZE)
499 {
500 ::new (&p_buffer[write_index]) T(value1, value2);
501
502 write_index = get_next_index(write_index, MAX_SIZE);
503
504 ++current_size;
505
506 return true;
507 }
508
509 // Queue is full.
510 return false;
511 }
512
513 //*************************************************************************
515 //*************************************************************************
516 template <typename T1, typename T2, typename T3>
517 bool emplace_implementation(const T1& value1, const T2& value2, const T3& value3)
518 {
519 if (current_size != MAX_SIZE)
520 {
521 ::new (&p_buffer[write_index]) T(value1, value2, value3);
522
523 write_index = get_next_index(write_index, MAX_SIZE);
524
525 ++current_size;
526
527 return true;
528 }
529
530 // Queue is full.
531 return false;
532 }
533
534 //*************************************************************************
536 //*************************************************************************
537 template <typename T1, typename T2, typename T3, typename T4>
538 bool emplace_implementation(const T1& value1, const T2& value2, const T3& value3, const T4& value4)
539 {
540 if (current_size != MAX_SIZE)
541 {
542 ::new (&p_buffer[write_index]) T(value1, value2, value3, value4);
543
544 write_index = get_next_index(write_index, MAX_SIZE);
545
546 ++current_size;
547
548 return true;
549 }
550
551 // Queue is full.
552 return false;
553 }
554#endif
555
556 //*************************************************************************
558 //*************************************************************************
559 bool pop_implementation(reference value)
560 {
561 if (current_size == 0)
562 {
563 // Queue is empty
564 return false;
565 }
566
567#if ETL_USING_CPP11 && ETL_NOT_USING_STLPORT && !defined(ETL_QUEUE_LOCKABLE_FORCE_CPP03_IMPLEMENTATION)
568 value = etl::move(p_buffer[read_index]);
569#else
570 value = p_buffer[read_index];
571#endif
572
573 p_buffer[read_index].~T();
574
575 read_index = get_next_index(read_index, MAX_SIZE);
576
577 --current_size;
578
579 return true;
580 }
581
582 //*************************************************************************
584 //*************************************************************************
585 bool pop_implementation()
586 {
587 if (current_size == 0)
588 {
589 // Queue is empty
590 return false;
591 }
592
593 p_buffer[read_index].~T();
594
595 read_index = get_next_index(read_index, MAX_SIZE);
596
597 --current_size;
598
599 return true;
600 }
601
602 //*************************************************************************
604 //*************************************************************************
605 reference front_implementation()
606 {
607 return p_buffer[read_index];
608 }
609
610 //*************************************************************************
612 //*************************************************************************
613 const_reference front_implementation() const
614 {
615 return p_buffer[read_index];
616 }
617
618 // Disable copy construction and assignment.
619 iqueue_mpmc_mutex(const iqueue_mpmc_mutex&);
620 iqueue_mpmc_mutex& operator =(const iqueue_mpmc_mutex&);
621
622 T* p_buffer;
623
624 mutable etl::mutex access;
625 };
626
627 //***************************************************************************
634 //***************************************************************************
635 template <typename T, size_t SIZE, const size_t MEMORY_MODEL = etl::memory_model::MEMORY_MODEL_LARGE>
636 class queue_mpmc_mutex : public etl::iqueue_mpmc_mutex<T, MEMORY_MODEL>
637 {
638 private:
639
640 typedef etl::iqueue_mpmc_mutex<T, MEMORY_MODEL> base_t;
641
642 public:
643
644 typedef typename base_t::size_type size_type;
645
646 ETL_STATIC_ASSERT((SIZE <= etl::integral_limits<size_type>::max), "Size too large for memory model");
647
648 static ETL_CONSTANT size_type MAX_SIZE = size_type(SIZE);
649
650 //*************************************************************************
652 //*************************************************************************
653 queue_mpmc_mutex()
654 : base_t(reinterpret_cast<T*>(&buffer[0]), MAX_SIZE)
655 {
656 }
657
658 //*************************************************************************
660 //*************************************************************************
661 ~queue_mpmc_mutex()
662 {
663 base_t::clear();
664 }
665
666 private:
667
668 queue_mpmc_mutex(const queue_mpmc_mutex&) ETL_DELETE;
669 queue_mpmc_mutex& operator = (const queue_mpmc_mutex&) ETL_DELETE;
670
671#if ETL_USING_CPP11
672 queue_mpmc_mutex(queue_mpmc_mutex&&) = delete;
673 queue_mpmc_mutex& operator = (queue_mpmc_mutex&&) = delete;
674#endif
675
677 typename etl::aligned_storage<sizeof(T), etl::alignment_of<T>::value>::type buffer[MAX_SIZE];
678 };
679
680 template <typename T, size_t SIZE, const size_t MEMORY_MODEL>
681 ETL_CONSTANT typename queue_mpmc_mutex<T, SIZE, MEMORY_MODEL>::size_type queue_mpmc_mutex<T, SIZE, MEMORY_MODEL>::MAX_SIZE;
682}
683
684#endif
685#endif
This mutex class is implemented using CMSIS's RTOS2 mutexes.
Definition: mutex_cmsis_os2.h:43
Definition: alignment.h:221
Definition: integral_limits.h:468
add_rvalue_reference
Definition: type_traits_generator.h:1327
bitset_ext
Definition: absolute.h:38
size_t max_size() const
Returns the maximum number of items in the variant_pool.
Definition: variant_pool_generator.h:281
Definition: memory_model.h:50