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 "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 bool emplace()
207 {
208 access.lock();
209
210 bool result = emplace_implementation();
211
212 access.unlock();
213
214 return result;
215 }
216
217 //*************************************************************************
220 //*************************************************************************
221 template <typename T1>
222 bool emplace(const T1& value1)
223 {
224 access.lock();
225
226 bool result = emplace_implementation(value1);
227
228 access.unlock();
229
230 return result;
231 }
232
233 //*************************************************************************
236 //*************************************************************************
237 template <typename T1, typename T2>
238 bool emplace(const T1& value1, const T2& value2)
239 {
240 access.lock();
241
242 bool result = emplace_implementation(value1, value2);
243
244 access.unlock();
245
246 return result;
247 }
248
249 //*************************************************************************
252 //*************************************************************************
253 template <typename T1, typename T2, typename T3>
254 bool emplace(const T1& value1, const T2& value2, const T3& value3)
255 {
256 access.lock();
257
258 bool result = emplace_implementation(value1, value2, value3);
259
260 access.unlock();
261
262 return result;
263 }
264
265 //*************************************************************************
268 //*************************************************************************
269 template <typename T1, typename T2, typename T3, typename T4>
270 bool emplace(const T1& value1, const T2& value2, const T3& value3, const T4& value4)
271 {
272 access.lock();
273
274 bool result = emplace_implementation(value1, value2, value3, value4);
275
276 access.unlock();
277
278 return result;
279 }
280#endif
281
282 //*************************************************************************
284 //*************************************************************************
285 bool pop(reference value)
286 {
287 access.lock();
288
289 bool result = pop_implementation(value);
290
291 access.unlock();
292
293 return result;
294 }
295
296 //*************************************************************************
298 //*************************************************************************
299 bool pop()
300 {
301 access.lock();
302
303 bool result = pop_implementation();
304
305 access.unlock();
306
307 return result;
308 }
309
310 //*************************************************************************
312 //*************************************************************************
313 reference front()
314 {
315 access.lock();
316
317 reference result = front_implementation();
318
319 access.unlock();
320
321 return result;
322 }
323
324 //*************************************************************************
326 //*************************************************************************
327 const_reference front() const
328 {
329 access.lock();
330
331 const_reference result = front_implementation();
332
333 access.unlock();
334
335 return result;
336 }
337
338 //*************************************************************************
340 //*************************************************************************
341 void clear()
342 {
343 access.lock();
344
345 if ETL_IF_CONSTEXPR(etl::is_trivially_destructible<T>::value)
346 {
347 this->write_index = 0;
348 this->read_index = 0;
349 this->current_size = 0;
350 }
351 else
352 {
353 while (pop_implementation())
354 {
355 // Do nothing.
356 }
357 }
358
359 access.unlock();
360 }
361
362 //*************************************************************************
364 //*************************************************************************
365 bool empty() const
366 {
367 access.lock();
368
369 size_type result = (current_size == 0);
370
371 access.unlock();
372
373 return result;
374 }
375
376 //*************************************************************************
378 //*************************************************************************
379 bool full() const
380 {
381 access.lock();
382
383 size_type result = (current_size == MAX_SIZE);
384
385 access.unlock();
386
387 return result;
388 }
389
390 //*************************************************************************
392 //*************************************************************************
393 size_type size() const
394 {
395 access.lock();
396
397 size_type result = current_size;
398
399 access.unlock();
400
401 return result;
402 }
403
404 //*************************************************************************
406 //*************************************************************************
407 size_type available() const
408 {
409 access.lock();
410
411 size_type result = MAX_SIZE - current_size;
412
413 access.unlock();
414
415 return result;
416 }
417
418 protected:
419
420 //*************************************************************************
422 //*************************************************************************
423 iqueue_mpmc_mutex(T* p_buffer_, size_type max_size_)
424 : base_t(max_size_),
425 p_buffer(p_buffer_)
426 {
427 }
428
429 private:
430
431 //*************************************************************************
433 //*************************************************************************
434 bool push_implementation(const_reference value)
435 {
436 if (current_size != MAX_SIZE)
437 {
438 ::new (&p_buffer[write_index]) T(value);
439
440 write_index = get_next_index(write_index, MAX_SIZE);
441
442 ++current_size;
443
444 return true;
445 }
446
447 // Queue is full.
448 return false;
449 }
450
451#if ETL_USING_CPP11 && ETL_NOT_USING_STLPORT && !defined(ETL_QUEUE_MPMC_MUTEX_FORCE_CPP03_IMPLEMENTATION)
452 //*************************************************************************
454 //*************************************************************************
455 bool push_implementation(rvalue_reference value)
456 {
457 if (current_size != MAX_SIZE)
458 {
459 ::new (&p_buffer[write_index]) T(etl::move(value));
460
461 write_index = get_next_index(write_index, MAX_SIZE);
462
463 ++current_size;
464
465 return true;
466 }
467
468 // Queue is full.
469 return false;
470 }
471#endif
472
473#if ETL_USING_CPP11 && ETL_NOT_USING_STLPORT && !defined(ETL_QUEUE_MPMC_MUTEX_FORCE_CPP03_IMPLEMENTATION)
474 //*************************************************************************
476 //*************************************************************************
477 template <typename ... Args>
478 bool emplace_implementation(Args&&... args)
479 {
480 if (current_size != MAX_SIZE)
481 {
482 ::new (&p_buffer[write_index]) T(etl::forward<Args>(args)...);
483
484 write_index = get_next_index(write_index, MAX_SIZE);
485
486 ++current_size;
487
488 return true;
489 }
490
491 // Queue is full.
492 return false;
493 }
494#else
495 //*************************************************************************
497 //*************************************************************************
498 bool emplace_implementation()
499 {
500 if (current_size != MAX_SIZE)
501 {
502 ::new (&p_buffer[write_index]) T();
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 //*************************************************************************
516 template <typename T1>
517 bool emplace_implementation(const T1& value1)
518 {
519 if (current_size != MAX_SIZE)
520 {
521 ::new (&p_buffer[write_index]) T(value1);
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>
538 bool emplace_implementation(const T1& value1, const T2& value2)
539 {
540 if (current_size != MAX_SIZE)
541 {
542 ::new (&p_buffer[write_index]) T(value1, value2);
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
555 //*************************************************************************
557 //*************************************************************************
558 template <typename T1, typename T2, typename T3>
559 bool emplace_implementation(const T1& value1, const T2& value2, const T3& value3)
560 {
561 if (current_size != MAX_SIZE)
562 {
563 ::new (&p_buffer[write_index]) T(value1, value2, value3);
564
565 write_index = get_next_index(write_index, MAX_SIZE);
566
567 ++current_size;
568
569 return true;
570 }
571
572 // Queue is full.
573 return false;
574 }
575
576 //*************************************************************************
578 //*************************************************************************
579 template <typename T1, typename T2, typename T3, typename T4>
580 bool emplace_implementation(const T1& value1, const T2& value2, const T3& value3, const T4& value4)
581 {
582 if (current_size != MAX_SIZE)
583 {
584 ::new (&p_buffer[write_index]) T(value1, value2, value3, value4);
585
586 write_index = get_next_index(write_index, MAX_SIZE);
587
588 ++current_size;
589
590 return true;
591 }
592
593 // Queue is full.
594 return false;
595 }
596#endif
597
598 //*************************************************************************
600 //*************************************************************************
601 bool pop_implementation(reference value)
602 {
603 if (current_size == 0)
604 {
605 // Queue is empty
606 return false;
607 }
608
609#if ETL_USING_CPP11 && ETL_NOT_USING_STLPORT && !defined(ETL_QUEUE_LOCKABLE_FORCE_CPP03_IMPLEMENTATION)
610 value = etl::move(p_buffer[read_index]);
611#else
612 value = p_buffer[read_index];
613#endif
614
615 p_buffer[read_index].~T();
616
617 read_index = get_next_index(read_index, MAX_SIZE);
618
619 --current_size;
620
621 return true;
622 }
623
624 //*************************************************************************
626 //*************************************************************************
627 bool pop_implementation()
628 {
629 if (current_size == 0)
630 {
631 // Queue is empty
632 return false;
633 }
634
635 p_buffer[read_index].~T();
636
637 read_index = get_next_index(read_index, MAX_SIZE);
638
639 --current_size;
640
641 return true;
642 }
643
644 //*************************************************************************
646 //*************************************************************************
647 reference front_implementation()
648 {
649 return p_buffer[read_index];
650 }
651
652 //*************************************************************************
654 //*************************************************************************
655 const_reference front_implementation() const
656 {
657 return p_buffer[read_index];
658 }
659
660 // Disable copy construction and assignment.
661 iqueue_mpmc_mutex(const iqueue_mpmc_mutex&);
662 iqueue_mpmc_mutex& operator =(const iqueue_mpmc_mutex&);
663
664 T* p_buffer;
665
666 mutable etl::mutex access;
667 };
668
669 //***************************************************************************
676 //***************************************************************************
677 template <typename T, size_t SIZE, const size_t MEMORY_MODEL = etl::memory_model::MEMORY_MODEL_LARGE>
678 class queue_mpmc_mutex : public etl::iqueue_mpmc_mutex<T, MEMORY_MODEL>
679 {
680 private:
681
682 typedef etl::iqueue_mpmc_mutex<T, MEMORY_MODEL> base_t;
683
684 public:
685
686 typedef typename base_t::size_type size_type;
687
688 ETL_STATIC_ASSERT((SIZE <= etl::integral_limits<size_type>::max), "Size too large for memory model");
689
690 static ETL_CONSTANT size_type MAX_SIZE = size_type(SIZE);
691
692 //*************************************************************************
694 //*************************************************************************
695 queue_mpmc_mutex()
696 : base_t(reinterpret_cast<T*>(&buffer[0]), MAX_SIZE)
697 {
698 }
699
700 //*************************************************************************
702 //*************************************************************************
703 ~queue_mpmc_mutex()
704 {
705 base_t::clear();
706 }
707
708 private:
709
710 queue_mpmc_mutex(const queue_mpmc_mutex&) ETL_DELETE;
711 queue_mpmc_mutex& operator = (const queue_mpmc_mutex&) ETL_DELETE;
712
713#if ETL_USING_CPP11
714 queue_mpmc_mutex(queue_mpmc_mutex&&) = delete;
715 queue_mpmc_mutex& operator = (queue_mpmc_mutex&&) = delete;
716#endif
717
719 typename etl::aligned_storage<sizeof(T), etl::alignment_of<T>::value>::type buffer[MAX_SIZE];
720 };
721
722 template <typename T, size_t SIZE, const size_t MEMORY_MODEL>
723 ETL_CONSTANT typename queue_mpmc_mutex<T, SIZE, MEMORY_MODEL>::size_type queue_mpmc_mutex<T, SIZE, MEMORY_MODEL>::MAX_SIZE;
724}
725
726#endif
727#endif
bitset_ext
Definition absolute.h:39
size_t max_size() const
Returns the maximum number of items in the variant_pool.
Definition variant_pool_generator.h:395
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:1187