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