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
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:
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
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 while (pop_implementation())
346 {
347 // Do nothing.
348 }
349
350 access.unlock();
351 }
352
353 //*************************************************************************
355 //*************************************************************************
356 bool empty() const
357 {
358 access.lock();
359
360 size_type result = (current_size == 0);
361
362 access.unlock();
363
364 return result;
365 }
366
367 //*************************************************************************
369 //*************************************************************************
370 bool full() const
371 {
372 access.lock();
373
374 size_type result = (current_size == MAX_SIZE);
375
376 access.unlock();
377
378 return result;
379 }
380
381 //*************************************************************************
383 //*************************************************************************
384 size_type size() const
385 {
386 access.lock();
387
388 size_type result = current_size;
389
390 access.unlock();
391
392 return result;
393 }
394
395 //*************************************************************************
397 //*************************************************************************
398 size_type available() const
399 {
400 access.lock();
401
402 size_type result = MAX_SIZE - current_size;
403
404 access.unlock();
405
406 return result;
407 }
408
409 protected:
410
411 //*************************************************************************
413 //*************************************************************************
415 : base_t(max_size_),
416 p_buffer(p_buffer_)
417 {
418 }
419
420 private:
421
422 //*************************************************************************
424 //*************************************************************************
425 bool push_implementation(const_reference value)
426 {
427 if (current_size != MAX_SIZE)
428 {
429 ::new (&p_buffer[write_index]) T(value);
430
431 write_index = get_next_index(write_index, MAX_SIZE);
432
433 ++current_size;
434
435 return true;
436 }
437
438 // Queue is full.
439 return false;
440 }
441
442#if ETL_USING_CPP11 && ETL_NOT_USING_STLPORT && !defined(ETL_QUEUE_MPMC_MUTEX_FORCE_CPP03_IMPLEMENTATION)
443 //*************************************************************************
445 //*************************************************************************
446 bool push_implementation(rvalue_reference value)
447 {
448 if (current_size != MAX_SIZE)
449 {
450 ::new (&p_buffer[write_index]) T(etl::move(value));
451
452 write_index = get_next_index(write_index, MAX_SIZE);
453
454 ++current_size;
455
456 return true;
457 }
458
459 // Queue is full.
460 return false;
461 }
462#endif
463
464#if ETL_USING_CPP11 && ETL_NOT_USING_STLPORT && !defined(ETL_QUEUE_MPMC_MUTEX_FORCE_CPP03_IMPLEMENTATION)
465 //*************************************************************************
467 //*************************************************************************
468 template <typename ... Args>
469 bool emplace_implementation(Args&&... args)
470 {
471 if (current_size != MAX_SIZE)
472 {
473 ::new (&p_buffer[write_index]) T(etl::forward<Args>(args)...);
474
475 write_index = get_next_index(write_index, MAX_SIZE);
476
477 ++current_size;
478
479 return true;
480 }
481
482 // Queue is full.
483 return false;
484 }
485#else
486 //*************************************************************************
488 //*************************************************************************
489 bool emplace_implementation()
490 {
491 if (current_size != MAX_SIZE)
492 {
493 ::new (&p_buffer[write_index]) T();
494
495 write_index = get_next_index(write_index, MAX_SIZE);
496
497 ++current_size;
498
499 return true;
500 }
501
502 // Queue is full.
503 return false;
504 }
505
506 //*************************************************************************
507 template <typename T1>
508 bool emplace_implementation(const T1& value1)
509 {
510 if (current_size != MAX_SIZE)
511 {
512 ::new (&p_buffer[write_index]) T(value1);
513
514 write_index = get_next_index(write_index, MAX_SIZE);
515
516 ++current_size;
517
518 return true;
519 }
520
521 // Queue is full.
522 return false;
523 }
524
525 //*************************************************************************
527 //*************************************************************************
528 template <typename T1, typename T2>
529 bool emplace_implementation(const T1& value1, const T2& value2)
530 {
531 if (current_size != MAX_SIZE)
532 {
533 ::new (&p_buffer[write_index]) T(value1, value2);
534
535 write_index = get_next_index(write_index, MAX_SIZE);
536
537 ++current_size;
538
539 return true;
540 }
541
542 // Queue is full.
543 return false;
544 }
545
546 //*************************************************************************
548 //*************************************************************************
549 template <typename T1, typename T2, typename T3>
550 bool emplace_implementation(const T1& value1, const T2& value2, const T3& value3)
551 {
552 if (current_size != MAX_SIZE)
553 {
554 ::new (&p_buffer[write_index]) T(value1, value2, value3);
555
556 write_index = get_next_index(write_index, MAX_SIZE);
557
558 ++current_size;
559
560 return true;
561 }
562
563 // Queue is full.
564 return false;
565 }
566
567 //*************************************************************************
569 //*************************************************************************
570 template <typename T1, typename T2, typename T3, typename T4>
571 bool emplace_implementation(const T1& value1, const T2& value2, const T3& value3, const T4& value4)
572 {
573 if (current_size != MAX_SIZE)
574 {
575 ::new (&p_buffer[write_index]) T(value1, value2, value3, value4);
576
577 write_index = get_next_index(write_index, MAX_SIZE);
578
579 ++current_size;
580
581 return true;
582 }
583
584 // Queue is full.
585 return false;
586 }
587#endif
588
589 //*************************************************************************
591 //*************************************************************************
592 bool pop_implementation(reference value)
593 {
594 if (current_size == 0)
595 {
596 // Queue is empty
597 return false;
598 }
599
600#if ETL_USING_CPP11 && ETL_NOT_USING_STLPORT && !defined(ETL_QUEUE_LOCKABLE_FORCE_CPP03_IMPLEMENTATION)
601 value = etl::move(p_buffer[read_index]);
602#else
603 value = p_buffer[read_index];
604#endif
605
606 p_buffer[read_index].~T();
607
608 read_index = get_next_index(read_index, MAX_SIZE);
609
610 --current_size;
611
612 return true;
613 }
614
615 //*************************************************************************
617 //*************************************************************************
618 bool pop_implementation()
619 {
620 if (current_size == 0)
621 {
622 // Queue is empty
623 return false;
624 }
625
626 p_buffer[read_index].~T();
627
628 read_index = get_next_index(read_index, MAX_SIZE);
629
630 --current_size;
631
632 return true;
633 }
634
635 //*************************************************************************
637 //*************************************************************************
638 reference front_implementation()
639 {
640 return p_buffer[read_index];
641 }
642
643 //*************************************************************************
645 //*************************************************************************
646 const_reference front_implementation() const
647 {
648 return p_buffer[read_index];
649 }
650
651 // Disable copy construction and assignment.
653 iqueue_mpmc_mutex& operator =(const iqueue_mpmc_mutex&);
654
655 T* p_buffer;
656
657 mutable etl::mutex access;
658 };
659
660 //***************************************************************************
667 //***************************************************************************
668 template <typename T, size_t SIZE, const size_t MEMORY_MODEL = etl::memory_model::MEMORY_MODEL_LARGE>
669 class queue_mpmc_mutex : public etl::iqueue_mpmc_mutex<T, MEMORY_MODEL>
670 {
671 private:
672
674
675 public:
676
677 typedef typename base_t::size_type size_type;
678
679 ETL_STATIC_ASSERT((SIZE <= etl::integral_limits<size_type>::max), "Size too large for memory model");
680
681 static ETL_CONSTANT size_type MAX_SIZE = size_type(SIZE);
682
683 //*************************************************************************
685 //*************************************************************************
687 : base_t(reinterpret_cast<T*>(&buffer[0]), MAX_SIZE)
688 {
689 }
690
691 //*************************************************************************
693 //*************************************************************************
695 {
696 base_t::clear();
697 }
698
699 private:
700
701 queue_mpmc_mutex(const queue_mpmc_mutex&) ETL_DELETE;
702 queue_mpmc_mutex& operator = (const queue_mpmc_mutex&) ETL_DELETE;
703
704#if ETL_USING_CPP11
706 queue_mpmc_mutex& operator = (queue_mpmc_mutex&&) = delete;
707#endif
708
710 typename etl::aligned_storage<sizeof(T), etl::alignment_of<T>::value>::type buffer[MAX_SIZE];
711 };
712
713 template <typename T, size_t SIZE, const size_t MEMORY_MODEL>
714 ETL_CONSTANT typename queue_mpmc_mutex<T, SIZE, MEMORY_MODEL>::size_type queue_mpmc_mutex<T, SIZE, MEMORY_MODEL>::MAX_SIZE;
715}
716
717#endif
718#endif
This mutex class is implemented using CMSIS's RTOS2 mutexes.
Definition mutex_cmsis_os2.h:43
Definition alignment.h:231
Definition integral_limits.h:516
add_rvalue_reference
Definition type_traits_generator.h:1322
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:395
ETL_CONSTEXPR TContainer::size_type size(const TContainer &container)
Definition iterator.h:1187
pair holds two objects of arbitrary type
Definition utility.h:164
ETL_CONSTEXPR pair()
Default constructor.
Definition utility.h:176
Definition memory_model.h:50