Embedded Template Library 1.0
Loading...
Searching...
No Matches
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 "integral_limits.h"
41 #include "memory_model.h"
42 #include "parameter_type.h"
43 #include "placement_new.h"
44 #include "utility.h"
45
46 #include <stddef.h>
47 #include <stdint.h>
48
49namespace etl
50{
51 //***************************************************************************
54 //***************************************************************************
55 class queue_mpmc_exception : public exception
56 {
57 public:
58
59 queue_mpmc_exception(string_type reason_, string_type file_name_, numeric_type line_number_)
60 : exception(reason_, file_name_, line_number_)
61 {
62 }
63 };
64
65 //***************************************************************************
68 //***************************************************************************
69 class queue_mpmc_empty : public queue_mpmc_exception
70 {
71 public:
72
73 queue_mpmc_empty(string_type file_name_, numeric_type line_number_)
74 : queue_mpmc_exception(ETL_ERROR_TEXT("queue_mpmc_mutex:empty", ETL_QUEUE_MPMC_MUTEX_FILE_ID"A"), file_name_, line_number_)
75 {
76 }
77 };
78
79 template <size_t MEMORY_MODEL = etl::memory_model::MEMORY_MODEL_LARGE>
80 class queue_mpmc_mutex_base
81 {
82 public:
83
85 typedef typename etl::size_type_lookup<MEMORY_MODEL>::type size_type;
86
87 //*************************************************************************
89 //*************************************************************************
90 size_type capacity() const
91 {
92 return MAX_SIZE;
93 }
94
95 //*************************************************************************
97 //*************************************************************************
98 size_type max_size() const
99 {
100 return MAX_SIZE;
101 }
102
103 protected:
104
105 queue_mpmc_mutex_base(size_type max_size_)
106 : write_index(0)
107 , read_index(0)
108 , current_size(0)
109 , MAX_SIZE(max_size_)
110 {
111 }
112
113 //*************************************************************************
115 //*************************************************************************
116 static size_type get_next_index(size_type index, size_type maximum)
117 {
118 ++index;
119
120 if (index == maximum) ETL_UNLIKELY
121 {
122 index = 0;
123 }
124
125 return index;
126 }
127
128 size_type write_index;
129 size_type read_index;
130 size_type current_size;
131 const size_type MAX_SIZE;
132
133 //*************************************************************************
135 //*************************************************************************
136 #if defined(ETL_POLYMORPHIC_MPMC_QUEUE_MUTEX) || defined(ETL_POLYMORPHIC_CONTAINERS)
137
138 public:
139
140 virtual ~queue_mpmc_mutex_base() {}
141 #else
142
143 protected:
144
145 ~queue_mpmc_mutex_base() {}
146 #endif
147 };
148
149 //***************************************************************************
159 //***************************************************************************
160 template <typename T, const size_t MEMORY_MODEL = etl::memory_model::MEMORY_MODEL_LARGE>
161 class iqueue_mpmc_mutex : public queue_mpmc_mutex_base<MEMORY_MODEL>
162 {
163 private:
164
165 typedef etl::queue_mpmc_mutex_base<MEMORY_MODEL> base_t;
166
167 public:
168
169 typedef T value_type;
170 typedef T& reference;
171 typedef const T& const_reference;
172 #if ETL_USING_CPP11
173 typedef T&& rvalue_reference;
174 #endif
175 typedef typename base_t::size_type size_type;
176
177 using base_t::current_size;
178 using base_t::get_next_index;
179 using base_t::MAX_SIZE;
180 using base_t::read_index;
181 using base_t::write_index;
182
183 //*************************************************************************
185 //*************************************************************************
186 bool push(const_reference value)
187 {
188 access.lock();
189
190 bool result = push_implementation(value);
191
192 access.unlock();
193
194 return result;
195 }
196
197 #if ETL_USING_CPP11
198 //*************************************************************************
200 //*************************************************************************
201 bool push(rvalue_reference value)
202 {
203 access.lock();
204
205 bool result = push_implementation(etl::move(value));
206
207 access.unlock();
208
209 return result;
210 }
211 #endif
212
213 #if ETL_USING_CPP11 && ETL_NOT_USING_STLPORT && !defined(ETL_QUEUE_MPMC_MUTEX_FORCE_CPP03_IMPLEMENTATION)
214 //*************************************************************************
218 //*************************************************************************
219 template <typename... Args>
220 bool emplace(Args&&... args)
221 {
222 access.lock();
223
224 bool result = emplace_implementation(etl::forward<Args>(args)...);
225
226 access.unlock();
227
228 return result;
229 }
230 #else
231 //*************************************************************************
235 //*************************************************************************
236 bool emplace()
237 {
238 access.lock();
239
240 bool result = emplace_implementation();
241
242 access.unlock();
243
244 return result;
245 }
246
247 //*************************************************************************
251 //*************************************************************************
252 template <typename T1>
253 bool emplace(const T1& value1)
254 {
255 access.lock();
256
257 bool result = emplace_implementation(value1);
258
259 access.unlock();
260
261 return result;
262 }
263
264 //*************************************************************************
268 //*************************************************************************
269 template <typename T1, typename T2>
270 bool emplace(const T1& value1, const T2& value2)
271 {
272 access.lock();
273
274 bool result = emplace_implementation(value1, value2);
275
276 access.unlock();
277
278 return result;
279 }
280
281 //*************************************************************************
285 //*************************************************************************
286 template <typename T1, typename T2, typename T3>
287 bool emplace(const T1& value1, const T2& value2, const T3& value3)
288 {
289 access.lock();
290
291 bool result = emplace_implementation(value1, value2, value3);
292
293 access.unlock();
294
295 return result;
296 }
297
298 //*************************************************************************
302 //*************************************************************************
303 template <typename T1, typename T2, typename T3, typename T4>
304 bool emplace(const T1& value1, const T2& value2, const T3& value3, const T4& value4)
305 {
306 access.lock();
307
308 bool result = emplace_implementation(value1, value2, value3, value4);
309
310 access.unlock();
311
312 return result;
313 }
314 #endif
315
316 //*************************************************************************
318 //*************************************************************************
319 bool pop(reference value)
320 {
321 access.lock();
322
323 bool result = pop_implementation(value);
324
325 access.unlock();
326
327 return result;
328 }
329
330 //*************************************************************************
332 //*************************************************************************
333 bool pop()
334 {
335 access.lock();
336
337 bool result = pop_implementation();
338
339 access.unlock();
340
341 return result;
342 }
343
344 //*************************************************************************
348 //*************************************************************************
349 reference front()
350 {
351 #if ETL_CHECKING_EXTRA
352 access.lock();
353 if (current_size != 0)
354 {
355 reference inner_result = front_implementation();
356 access.unlock();
357 return inner_result;
358 }
359 else
360 {
361 access.unlock();
362 ETL_ASSERT_FAIL(ETL_ERROR(queue_mpmc_empty));
363 // fall through to return something to satisfy the compiler, even
364 // though this should never be reached due to undefined behaviour.
365 }
366 #endif
367 access.lock();
368 reference result = front_implementation();
369 access.unlock();
370 return result;
371 }
372
373 //*************************************************************************
377 //*************************************************************************
378 const_reference front() const
379 {
380 #if ETL_CHECKING_EXTRA
381 access.lock();
382 if (current_size != 0)
383 {
384 const_reference inner_result = front_implementation();
385 access.unlock();
386 return inner_result;
387 }
388 else
389 {
390 access.unlock();
391 ETL_ASSERT_FAIL(ETL_ERROR(queue_mpmc_empty));
392 // fall through to return something to satisfy the compiler, even
393 // though this should never be reached due to undefined behaviour.
394 }
395 #endif
396 access.lock();
397 const_reference result = front_implementation();
398 access.unlock();
399 return result;
400 }
401
402 //*************************************************************************
404 //*************************************************************************
405 void clear()
406 {
407 access.lock();
408
409 if ETL_IF_CONSTEXPR (etl::is_trivially_destructible<T>::value)
410 {
411 this->write_index = 0;
412 this->read_index = 0;
413 this->current_size = 0;
414 }
415 else
416 {
417 while (pop_implementation())
418 {
419 // Do nothing.
420 }
421 }
422
423 access.unlock();
424 }
425
426 //*************************************************************************
428 //*************************************************************************
429 bool empty() const
430 {
431 access.lock();
432
433 size_type result = (current_size == 0);
434
435 access.unlock();
436
437 return result;
438 }
439
440 //*************************************************************************
442 //*************************************************************************
443 bool full() const
444 {
445 access.lock();
446
447 size_type result = (current_size == MAX_SIZE);
448
449 access.unlock();
450
451 return result;
452 }
453
454 //*************************************************************************
456 //*************************************************************************
457 size_type size() const
458 {
459 access.lock();
460
461 size_type result = current_size;
462
463 access.unlock();
464
465 return result;
466 }
467
468 //*************************************************************************
470 //*************************************************************************
471 size_type available() const
472 {
473 access.lock();
474
475 size_type result = MAX_SIZE - current_size;
476
477 access.unlock();
478
479 return result;
480 }
481
482 protected:
483
484 //*************************************************************************
486 //*************************************************************************
487 iqueue_mpmc_mutex(T* p_buffer_, size_type max_size_)
488 : base_t(max_size_)
489 , p_buffer(p_buffer_)
490 {
491 }
492
493 private:
494
495 //*************************************************************************
497 //*************************************************************************
498 bool push_implementation(const_reference value)
499 {
500 if (current_size != MAX_SIZE)
501 {
502 ::new (&p_buffer[write_index]) T(value);
503
504 write_index = get_next_index(write_index, MAX_SIZE);
505
506 ++current_size;
507
508 return true;
509 }
510
511 // Queue is full.
512 return false;
513 }
514
515 #if ETL_USING_CPP11 && ETL_NOT_USING_STLPORT && !defined(ETL_QUEUE_MPMC_MUTEX_FORCE_CPP03_IMPLEMENTATION)
516 //*************************************************************************
518 //*************************************************************************
519 bool push_implementation(rvalue_reference value)
520 {
521 if (current_size != MAX_SIZE)
522 {
523 ::new (&p_buffer[write_index]) T(etl::move(value));
524
525 write_index = get_next_index(write_index, MAX_SIZE);
526
527 ++current_size;
528
529 return true;
530 }
531
532 // Queue is full.
533 return false;
534 }
535 #endif
536
537 #if ETL_USING_CPP11 && ETL_NOT_USING_STLPORT && !defined(ETL_QUEUE_MPMC_MUTEX_FORCE_CPP03_IMPLEMENTATION)
538 //*************************************************************************
540 //*************************************************************************
541 template <typename... Args>
542 bool emplace_implementation(Args&&... args)
543 {
544 if (current_size != MAX_SIZE)
545 {
546 ::new (&p_buffer[write_index]) T(etl::forward<Args>(args)...);
547
548 write_index = get_next_index(write_index, MAX_SIZE);
549
550 ++current_size;
551
552 return true;
553 }
554
555 // Queue is full.
556 return false;
557 }
558 #else
559 //*************************************************************************
561 //*************************************************************************
562 bool emplace_implementation()
563 {
564 if (current_size != MAX_SIZE)
565 {
566 ::new (&p_buffer[write_index]) T();
567
568 write_index = get_next_index(write_index, MAX_SIZE);
569
570 ++current_size;
571
572 return true;
573 }
574
575 // Queue is full.
576 return false;
577 }
578
579 //*************************************************************************
580 template <typename T1>
581 bool emplace_implementation(const T1& value1)
582 {
583 if (current_size != MAX_SIZE)
584 {
585 ::new (&p_buffer[write_index]) T(value1);
586
587 write_index = get_next_index(write_index, MAX_SIZE);
588
589 ++current_size;
590
591 return true;
592 }
593
594 // Queue is full.
595 return false;
596 }
597
598 //*************************************************************************
600 //*************************************************************************
601 template <typename T1, typename T2>
602 bool emplace_implementation(const T1& value1, const T2& value2)
603 {
604 if (current_size != MAX_SIZE)
605 {
606 ::new (&p_buffer[write_index]) T(value1, value2);
607
608 write_index = get_next_index(write_index, MAX_SIZE);
609
610 ++current_size;
611
612 return true;
613 }
614
615 // Queue is full.
616 return false;
617 }
618
619 //*************************************************************************
621 //*************************************************************************
622 template <typename T1, typename T2, typename T3>
623 bool emplace_implementation(const T1& value1, const T2& value2, const T3& value3)
624 {
625 if (current_size != MAX_SIZE)
626 {
627 ::new (&p_buffer[write_index]) T(value1, value2, value3);
628
629 write_index = get_next_index(write_index, MAX_SIZE);
630
631 ++current_size;
632
633 return true;
634 }
635
636 // Queue is full.
637 return false;
638 }
639
640 //*************************************************************************
642 //*************************************************************************
643 template <typename T1, typename T2, typename T3, typename T4>
644 bool emplace_implementation(const T1& value1, const T2& value2, const T3& value3, const T4& value4)
645 {
646 if (current_size != MAX_SIZE)
647 {
648 ::new (&p_buffer[write_index]) T(value1, value2, value3, value4);
649
650 write_index = get_next_index(write_index, MAX_SIZE);
651
652 ++current_size;
653
654 return true;
655 }
656
657 // Queue is full.
658 return false;
659 }
660 #endif
661
662 //*************************************************************************
664 //*************************************************************************
665 bool pop_implementation(reference value)
666 {
667 if (current_size == 0)
668 {
669 // Queue is empty
670 return false;
671 }
672
673 #if ETL_USING_CPP11 && ETL_NOT_USING_STLPORT && !defined(ETL_QUEUE_LOCKABLE_FORCE_CPP03_IMPLEMENTATION)
674 value = etl::move(p_buffer[read_index]);
675 #else
676 value = p_buffer[read_index];
677 #endif
678
679 p_buffer[read_index].~T();
680
681 read_index = get_next_index(read_index, MAX_SIZE);
682
683 --current_size;
684
685 return true;
686 }
687
688 //*************************************************************************
690 //*************************************************************************
691 bool pop_implementation()
692 {
693 if (current_size == 0)
694 {
695 // Queue is empty
696 return false;
697 }
698
699 p_buffer[read_index].~T();
700
701 read_index = get_next_index(read_index, MAX_SIZE);
702
703 --current_size;
704
705 return true;
706 }
707
708 //*************************************************************************
710 //*************************************************************************
711 reference front_implementation()
712 {
713 return p_buffer[read_index];
714 }
715
716 //*************************************************************************
718 //*************************************************************************
719 const_reference front_implementation() const
720 {
721 return p_buffer[read_index];
722 }
723
724 // Disable copy construction and assignment.
725 iqueue_mpmc_mutex(const iqueue_mpmc_mutex&);
726 iqueue_mpmc_mutex& operator=(const iqueue_mpmc_mutex&);
727
728 T* p_buffer;
729
730 mutable etl::mutex access;
731 };
732
733 //***************************************************************************
741 //***************************************************************************
742 template <typename T, size_t SIZE, const size_t MEMORY_MODEL = etl::memory_model::MEMORY_MODEL_LARGE>
743 class queue_mpmc_mutex : public etl::iqueue_mpmc_mutex<T, MEMORY_MODEL>
744 {
745 private:
746
747 typedef etl::iqueue_mpmc_mutex<T, MEMORY_MODEL> base_t;
748
749 public:
750
751 typedef typename base_t::size_type size_type;
752
753 ETL_STATIC_ASSERT((SIZE <= etl::integral_limits<size_type>::max), "Size too large for memory model");
754
755 static ETL_CONSTANT size_type MAX_SIZE = size_type(SIZE);
756
757 //*************************************************************************
759 //*************************************************************************
760 queue_mpmc_mutex()
761 : base_t(reinterpret_cast<T*>(&buffer[0]), MAX_SIZE)
762 {
763 }
764
765 //*************************************************************************
767 //*************************************************************************
768 ~queue_mpmc_mutex()
769 {
770 base_t::clear();
771 }
772
773 private:
774
775 queue_mpmc_mutex(const queue_mpmc_mutex&) ETL_DELETE;
776 queue_mpmc_mutex& operator=(const queue_mpmc_mutex&) ETL_DELETE;
777
778 #if ETL_USING_CPP11
779 queue_mpmc_mutex(queue_mpmc_mutex&&) = delete;
780 queue_mpmc_mutex& operator=(queue_mpmc_mutex&&) = delete;
781 #endif
782
784 typename etl::aligned_storage<sizeof(T), etl::alignment_of<T>::value>::type buffer[MAX_SIZE];
785 };
786
787 template <typename T, size_t SIZE, const size_t MEMORY_MODEL>
788 ETL_CONSTANT typename queue_mpmc_mutex<T, SIZE, MEMORY_MODEL>::size_type queue_mpmc_mutex<T, SIZE, MEMORY_MODEL>::MAX_SIZE;
789} // namespace etl
790
791#endif
792#endif
Definition exception.h:59
bitset_ext
Definition absolute.h:40
std::mutex mutex
This mutex class is implemented using std::mutex.
Definition mutex_std.h:42
ETL_CONSTEXPR TContainer::size_type size(const TContainer &container)
Definition iterator.h:1192