nlib
LockFree.h
Go to the documentation of this file.
1 
2 /*--------------------------------------------------------------------------------*
3  Project: CrossRoad
4  Copyright (C)Nintendo All rights reserved.
5 
6  These coded instructions, statements, and computer programs contain proprietary
7  information of Nintendo and/or its licensed developers and are protected by
8  national and international copyright laws. They may not be disclosed to third
9  parties or copied or duplicated in any form, in whole or in part, without the
10  prior written consent of Nintendo.
11 
12  The content herein is highly confidential and should be handled accordingly.
13  *--------------------------------------------------------------------------------*/
14 
15 #pragma once
16 #ifndef INCLUDE_NN_NLIB_LOCKFREE_H_
17 #define INCLUDE_NN_NLIB_LOCKFREE_H_
18 
19 #include <new>
20 #include "nn/nlib/Config.h"
21 #include "nn/nlib/TypeTraits.h"
22 #include "nn/nlib/UniquePtr.h"
24 #include "nn/nlib/Swap.h"
25 
26 NLIB_NAMESPACE_BEGIN
27 
28 template<class T1, class T2 = void>
29 struct LockFreePlaceHolder {
30  T1 data; // T1 must be POD
31  union next_type {
32  uintptr_t aba_ptr;
33  LockFreePlaceHolder<T1, T2>* raw_ptr;
34  } next;
35  T2 aux;
36  void Init(const T1& elem) NLIB_NOEXCEPT NLIB_NO_TSAN {
37  data = elem;
38  aux = T2();
39  }
40 };
41 
42 template<class T1>
43 struct LockFreePlaceHolder<T1, void> {
44  T1 data; // T1 must be POD
45  union next_type {
46  uintptr_t aba_ptr;
47  LockFreePlaceHolder<T1, void>* raw_ptr;
48  } next;
49  void Init(const T1& elem) NLIB_NOEXCEPT NLIB_NO_TSAN {
50  data = elem;
51  }
52 };
53 
54 template<class T1, class T2 = void>
55 class LockFreePlaceHolderPool NLIB_FINAL {
56  public:
57 #if !defined(CAFE) && !defined(NN_PLATFORM_CTR)
58  // some old compilers may complain that T1 is incomplete type even if it is not.
59  NLIB_STATIC_ASSERT(IsPod<T1>::value);
60 #endif
61  LockFreePlaceHolderPool() NLIB_NOEXCEPT : invariant_(0), mask_(0), mem_(nullptr) {}
62  ~LockFreePlaceHolderPool() NLIB_NOEXCEPT { delete[] mem_; }
63  errno_t Init(size_t count) NLIB_NOEXCEPT;
64  NLIB_ALWAYS_INLINE LockFreePlaceHolder<T1, T2>* CalcPtr(uintptr_t aba) const NLIB_NOEXCEPT {
65  return reinterpret_cast<LockFreePlaceHolder<T1, T2>*>((aba & mask_) | invariant_);
66  }
67  NLIB_ALWAYS_INLINE bool IsNull(uintptr_t aba) const NLIB_NOEXCEPT {
68  return aba & 1;
69  }
70  NLIB_ALWAYS_INLINE LockFreePlaceHolder<T1, T2>* Alloc() NLIB_NOEXCEPT NLIB_NO_TSAN {
71  LockFreePlaceHolder<T1, T2>* ptr;
72  uintptr_t expected = Load(&freelist_);
73  for (;;) {
74  if (NLIB_UNLIKELY(IsNull(expected))) return nullptr;
75  ptr = this->CalcPtr(expected);
76  uintptr_t desired = Load(&ptr->next.aba_ptr);
77  if (NLIB_LIKELY(Cas(&freelist_, &expected, &desired, 1)))
78  break;
79  }
80  uintptr_t mask = mask_;
81  ptr->next.aba_ptr = (ptr->next.aba_ptr & ~mask) + (mask + 2);
82  return ptr;
83  }
84  NLIB_ALWAYS_INLINE void Free(LockFreePlaceHolder<T1, T2>* p) NLIB_NOEXCEPT NLIB_NO_TSAN {
85  uintptr_t mask = mask_;
86  uintptr_t desired = reinterpret_cast<uintptr_t>(p);
87  uintptr_t expected = Load(&freelist_);
88  uintptr_t base = (p->next.aba_ptr & ~mask) + (mask + 1);
89  for (;;) {
90  Store(&p->next.aba_ptr, base | (expected & mask));
91  // must comfirm p->next written
92  if (NLIB_LIKELY(Cas(&freelist_, &expected, &desired, 1, NLIB_ATOMIC_RELEASE)))
93  break;
94  }
95  }
96  NLIB_ALWAYS_INLINE LockFreePlaceHolder<T1, T2>* AllocUnsafe() NLIB_NOEXCEPT {
97  uintptr_t expected = freelist_;
98  if (NLIB_UNLIKELY(IsNull(expected))) return nullptr;
99  LockFreePlaceHolder<T1, T2>* ptr = this->CalcPtr(expected);
100  freelist_ = ptr->next.aba_ptr;
101  ptr->next.aba_ptr = 1;
102  return ptr;
103  }
104  NLIB_ALWAYS_INLINE void FreeUnsafe(LockFreePlaceHolder<T1, T2>* p) NLIB_NOEXCEPT {
105  p->next.aba_ptr = freelist_;
106  freelist_ = reinterpret_cast<uintptr_t>(p);
107  }
108  NLIB_ALWAYS_INLINE uintptr_t Load(uintptr_t* ptr) NLIB_NOEXCEPT NLIB_NO_TSAN {
109  void* val = nlib_atomic_loadptr(reinterpret_cast<void**>(ptr), NLIB_ATOMIC_RELAXED);
110  return reinterpret_cast<uintptr_t>(val);
111  }
112  NLIB_ALWAYS_INLINE uintptr_t Load(uintptr_t* ptr, int memorder) NLIB_NOEXCEPT NLIB_NO_TSAN {
113  void* val = nlib_atomic_loadptr(reinterpret_cast<void**>(ptr), memorder);
114  return reinterpret_cast<uintptr_t>(val);
115  }
116  NLIB_ALWAYS_INLINE void Store(uintptr_t* ptr, uintptr_t value) NLIB_NOEXCEPT NLIB_NO_TSAN {
117  nlib_atomic_storeptr(reinterpret_cast<void**>(ptr),
118  reinterpret_cast<void*>(value),
120  }
121  NLIB_ALWAYS_INLINE void Store(uintptr_t* ptr, uintptr_t value, int memorder)
122  NLIB_NOEXCEPT NLIB_NO_TSAN {
123  nlib_atomic_storeptr(reinterpret_cast<void**>(ptr),
124  reinterpret_cast<void*>(value),
125  memorder);
126  }
127  NLIB_ALWAYS_INLINE int Cas(uintptr_t* ptr, uintptr_t* expected, uintptr_t* desired, int weak,
128  int success_memorder, int failure_memorder)
129  NLIB_NOEXCEPT NLIB_NO_TSAN {
130  uintptr_t mask = mask_;
131  *desired = ((*desired & mask) | (mask + 1)) + (*expected & ~mask);
132  int rval = nlib_atomic_compare_exchangeptr(reinterpret_cast<void**>(ptr),
133  reinterpret_cast<void**>(expected),
134  reinterpret_cast<void*>(*desired),
135  weak, success_memorder, failure_memorder);
136  return rval;
137  }
138  NLIB_ALWAYS_INLINE int Cas(uintptr_t* ptr, uintptr_t* expected, uintptr_t* desired, int weak,
139  int success_memorder) NLIB_NOEXCEPT {
140  return Cas(ptr, expected, desired, weak, success_memorder, NLIB_ATOMIC_RELAXED);
141  }
142  NLIB_ALWAYS_INLINE int Cas(uintptr_t* ptr, uintptr_t* expected, uintptr_t* desired,
143  int weak) NLIB_NOEXCEPT {
144  return Cas(ptr, expected, desired, weak, NLIB_ATOMIC_RELAXED, NLIB_ATOMIC_RELAXED);
145  }
146  void SwapUnsafe(LockFreePlaceHolderPool& rhs) NLIB_NOEXCEPT { // NOLINT
147  std::swap(freelist_, rhs.freelist_);
148  std::swap(invariant_, rhs.invariant_);
149  std::swap(mask_, rhs.mask_);
150  std::swap(mem_, rhs.mem_);
151  }
152 
153  public:
154  errno_t Push(uintptr_t* stack, const T1& elem) NLIB_NOEXCEPT;
155  errno_t Pop(uintptr_t* stack, T1* elem) NLIB_NOEXCEPT;
156  errno_t Enqueue(uintptr_t* tail, const T1& elem) NLIB_NOEXCEPT;
157  errno_t Dequeue(uintptr_t* head, uintptr_t* tail, T1* elem) NLIB_NOEXCEPT;
158  errno_t PushUnsafe(uintptr_t* stack, const T1& elem) NLIB_NOEXCEPT {
159  typedef LockFreePlaceHolder<T1, T2> item_type;
160  item_type* item_ptr = AllocUnsafe();
161  if (NLIB_UNLIKELY(!item_ptr)) return EAGAIN;
162 
163  // point of no failure
164  item_ptr->data = elem;
165  item_ptr->next.aba_ptr = *stack;
166  *stack = reinterpret_cast<uintptr_t>(item_ptr);
167  return 0;
168  }
169  errno_t PopUnsafe(uintptr_t* stack, T1* elem) NLIB_NOEXCEPT {
170  if (NLIB_UNLIKELY(IsNull(*stack))) return EAGAIN;
171  LockFreePlaceHolder<T1, T2>* ptr = CalcPtr(*stack);
172  *elem = ptr->data;
173  *stack = ptr->next.aba_ptr;
174  FreeUnsafe(ptr);
175  return 0;
176  }
177  errno_t EnqueueUnsafe(uintptr_t* tail, const T1& elem) NLIB_NOEXCEPT {
178  LockFreePlaceHolder<T1, T2>* item_ptr = AllocUnsafe();
179  if (NLIB_UNLIKELY(!item_ptr)) return EAGAIN;
180 
181  // point of no failure
182  item_ptr->data = elem;
183  CalcPtr(*tail)->next.aba_ptr = reinterpret_cast<uintptr_t>(item_ptr);
184  *tail = reinterpret_cast<uintptr_t>(item_ptr);
185  return 0;
186  }
187  errno_t DequeueUnsafe(uintptr_t* head, uintptr_t* tail, T1* elem) NLIB_NOEXCEPT {
188  typedef LockFreePlaceHolder<T1, T2> item_type;
189  item_type* first_ptr = CalcPtr(*head);
190  item_type* last_ptr = CalcPtr(*tail);
191  if (first_ptr == last_ptr) return EAGAIN;
192 
193  uintptr_t first_next = first_ptr->next.aba_ptr;
194  item_type* first_next_ptr = CalcPtr(first_next);
195  *elem = first_next_ptr->data;
196  *head = first_next;
197  FreeUnsafe(first_ptr);
198  return 0;
199  }
200 
201  private:
202  uintptr_t freelist_;
203  uintptr_t invariant_;
204  uintptr_t mask_;
205  LockFreePlaceHolder<T1, T2>* mem_;
206  NLIB_DISALLOW_COPY_AND_ASSIGN(LockFreePlaceHolderPool);
207 };
208 
209 template<class T1, class T2>
210 errno_t LockFreePlaceHolderPool<T1, T2>::Init(size_t count) NLIB_NOEXCEPT {
211  if (NLIB_UNLIKELY(mem_)) return EALREADY;
212  LockFreePlaceHolder<T1, T2>* mem = new (std::nothrow) LockFreePlaceHolder<T1, T2>[count];
213  if (NLIB_UNLIKELY(!mem)) return ENOMEM;
214  uintptr_t freelist = 1;
215 #ifdef NLIB_64BIT
216  for (size_t j = 0; j < 4; ++j) {
217  for (size_t i = j; i < count; i += 4) {
218  mem[i].next.aba_ptr = freelist;
219  mem[i].data = T1();
220  freelist = reinterpret_cast<uintptr_t>(&mem[i]);
221  }
222  }
223 #else
224  for (size_t j = 0; j < 8; ++j) {
225  for (size_t i = j; i < count; i += 8) {
226  mem[i].next.aba_ptr = freelist;
227  mem[i].data = T1();
228  freelist = reinterpret_cast<uintptr_t>(&mem[i]);
229  }
230  }
231 #endif
232  uintptr_t first = reinterpret_cast<uintptr_t>(mem);
233  uintptr_t last = reinterpret_cast<uintptr_t>(mem + count);
234 #ifdef NLIB_64BIT
235  int sft = nlib_clz64(first ^ last);
236 #else
237  int sft = nlib_clz32(first ^ last);
238 #endif
239  freelist_ = freelist;
240  mask_ = (static_cast<uintptr_t>(0) - 1) >> sft;
241  invariant_ = first & ~mask_;
242  mem_ = mem;
243  return 0;
244 }
245 
246 template<class T1, class T2>
247 NLIB_ALWAYS_INLINE errno_t LockFreePlaceHolderPool<T1, T2>::Push(
248  uintptr_t* stack, const T1& elem) NLIB_NOEXCEPT NLIB_NO_TSAN {
249  typedef LockFreePlaceHolder<T1, T2> item_type;
250  item_type* item_ptr = Alloc();
251  if (NLIB_UNLIKELY(!item_ptr)) return EAGAIN;
252 
253  // point of no failure
254  item_ptr->data = elem;
255  uintptr_t mask = mask_;
256  uintptr_t desired = reinterpret_cast<uintptr_t>(item_ptr);
257  uintptr_t expected = Load(&freelist_);
258  uintptr_t base = (item_ptr->next.aba_ptr & ~mask) + (mask + 1);
259  for (;;) {
260  Store(&item_ptr->next.aba_ptr, base | (expected & mask));
261  // must comfirm p->next written
262  if (NLIB_LIKELY(Cas(stack, &expected, &desired, 1, NLIB_ATOMIC_RELEASE)))
263  break;
264  }
265  return 0;
266 }
267 
268 template<class T1, class T2>
269 NLIB_ALWAYS_INLINE errno_t LockFreePlaceHolderPool<T1, T2>::Pop(
270  uintptr_t* stack, T1* elem) NLIB_NOEXCEPT NLIB_NO_TSAN {
271  LockFreePlaceHolder<T1, T2>* ptr;
272  uintptr_t expected = Load(stack);
273  for (;;) {
274  if (NLIB_UNLIKELY(IsNull(expected))) return EAGAIN;
275  ptr = this->CalcPtr(expected);
276  uintptr_t desired = Load(&ptr->next.aba_ptr);
277  if (NLIB_LIKELY(Cas(stack, &expected, &desired, 1)))
278  break;
279  }
280  *elem = ptr->data;
281  Free(ptr);
282  return 0;
283 }
284 
285 template<class T1, class T2>
286 NLIB_ALWAYS_INLINE errno_t LockFreePlaceHolderPool<T1, T2>::Enqueue(
287  uintptr_t* tail, const T1& elem) NLIB_NOEXCEPT NLIB_NO_TSAN {
288  LockFreePlaceHolder<T1, T2>* item_ptr = Alloc();
289  if (NLIB_UNLIKELY(!item_ptr)) return EAGAIN;
290 
291  // point of no failure
292  item_ptr->Init(elem);
293 #if !defined(_M_IX86) && !defined(_M_AMD64) && !defined(__i386__) && !defined(__x86_64__)
295 #endif
296  uintptr_t last = Load(tail);
297  for (;;) {
298  uintptr_t* last_next_ptr = &CalcPtr(last)->next.aba_ptr;
299  uintptr_t last_next = Load(last_next_ptr,
300  NLIB_ATOMIC_ACQUIRE); // before last_new is loaded
301  uintptr_t last_new = Load(tail);
302  if (NLIB_LIKELY(last == last_new)) {
303  if (NLIB_LIKELY(IsNull(last_next))) {
304  if (NLIB_LIKELY(Cas(last_next_ptr, &last_next,
305  reinterpret_cast<uintptr_t*>(&item_ptr),
306  1, NLIB_ATOMIC_ACQUIRE))) {
307  // Update tail
308  Cas(tail, &last, reinterpret_cast<uintptr_t*>(&item_ptr), 0);
309  return 0;
310  }
311  } else {
312  // Update tail and retry
313  if (NLIB_LIKELY(Cas(tail, &last, &last_next, 0))) {
314  last = last_next;
315  }
316  }
317  } else {
318  last = last_new;
319  }
320  }
321 }
322 
323 template<class T1, class T2>
324 NLIB_ALWAYS_INLINE errno_t LockFreePlaceHolderPool<T1, T2>::Dequeue(
325  uintptr_t* head, uintptr_t* tail, T1* elem) NLIB_NOEXCEPT NLIB_NO_TSAN {
326  typedef LockFreePlaceHolder<T1, T2> item_type;
327  // Load(head), then Load(tail)
328  uintptr_t first = Load(head, NLIB_ATOMIC_ACQUIRE);
329  uintptr_t last = Load(tail);
330  for (;;) {
331  item_type* first_ptr = CalcPtr(first);
332  item_type* last_ptr = CalcPtr(last);
333  uintptr_t first_next = Load(&first_ptr->next.aba_ptr,
334  NLIB_ATOMIC_ACQUIRE); // before first_new is loaded
335  uintptr_t first_new = Load(head);
336  if (NLIB_LIKELY(first == first_new)) {
337  if (NLIB_UNLIKELY(first_ptr == last_ptr)) {
338  if (NLIB_UNLIKELY(IsNull(first_next))) return EAGAIN;
339  // Update tail and retry
340  first = Load(head, NLIB_ATOMIC_ACQUIRE);
341  if (NLIB_LIKELY(Cas(tail, &last, &first_next, 0))) {
342  last = first_next;
343  }
344  } else {
345  item_type* first_next_ptr = CalcPtr(first_next);
346  *elem = first_next_ptr->data;
347  if (NLIB_LIKELY(Cas(head, &first, &first_next, 0))) {
348  Free(CalcPtr(first));
349  return 0;
350  }
351  first = Load(head, NLIB_ATOMIC_ACQUIRE);
352  last = Load(tail);
353  }
354  } else {
355  first = first_new;
356  last = Load(tail);
357  }
358  }
359 }
360 
361 template<size_t N>
363  public:
364  LockFreePipe() NLIB_NOEXCEPT : ofs_read_(0), ofs_write_(0) {}
365  size_t GetBufferSize() NLIB_NOEXCEPT {
366  NLIB_STATIC_ASSERT(N > 0);
367  NLIB_STATIC_ASSERT((N & (N - 1)) == 0);
368  NLIB_STATIC_ASSERT(N < INT32_MAX);
369  return N;
370  }
371  NLIB_ALWAYS_INLINE errno_t Read(void* dest, size_t nbytes) NLIB_NOEXCEPT {
372  uint32_t rofs = this->Load(&ofs_read_, NLIB_ATOMIC_RELAXED);
373  uint32_t wofs = this->Load(&ofs_write_, NLIB_ATOMIC_ACQUIRE);
374  // read ofs_write_, then read buffer_[rofs_actual]
375 
376  if (NLIB_UNLIKELY(nbytes > wofs - rofs)) return EAGAIN;
377  uint32_t rofs_actual = rofs & (N - 1);
378 
379  size_t ntail = N - rofs_actual;
380  if (ntail >= nbytes) {
381  // ARMCC needs this cast.
382  nlib_memcpy(dest,
383  nbytes,
384  reinterpret_cast<const void*>(&buffer_[rofs_actual]),
385  nbytes);
386  } else {
387  nlib_memcpy(dest,
388  nbytes,
389  reinterpret_cast<const void*>(&buffer_[rofs_actual]),
390  ntail);
391  nlib_memcpy(reinterpret_cast<void*>(reinterpret_cast<uint8_t*>(dest) + ntail),
392  nbytes - ntail,
393  reinterpret_cast<void*>(&buffer_[0]),
394  nbytes - ntail);
395  }
396  rofs += static_cast<uint32_t>(nbytes);
397 
398  // must not be reordered
399  this->Store(&ofs_read_, rofs, NLIB_ATOMIC_RELEASE);
400  return 0;
401  }
402  NLIB_ALWAYS_INLINE errno_t Write(const void* src, size_t nbytes) NLIB_NOEXCEPT {
403  uint32_t wofs = this->Load(&ofs_write_, NLIB_ATOMIC_RELAXED);
404  uint32_t rofs = this->Load(&ofs_read_, NLIB_ATOMIC_ACQUIRE);
405  // read ofs_read_, then write buffer_[wofs_actual]
406 
407  if (NLIB_UNLIKELY(nbytes > N - (wofs - rofs))) return EAGAIN;
408  uint32_t wofs_actual = wofs & (N - 1);
409 
410  size_t ntail = N - wofs_actual;
411  if (ntail >= nbytes) {
412  nlib_memcpy(reinterpret_cast<void*>(&buffer_[wofs_actual]),
413  nbytes,
414  src,
415  nbytes);
416  } else {
417  nlib_memcpy(reinterpret_cast<void*>(&buffer_[wofs_actual]),
418  ntail,
419  src,
420  ntail);
421  nlib_memcpy(reinterpret_cast<void*>(&buffer_[0]),
422  nbytes - ntail,
423  reinterpret_cast<const void*>(
424  reinterpret_cast<const uint8_t*>(src) + ntail),
425  nbytes - ntail);
426  }
427  wofs += static_cast<uint32_t>(nbytes);
428 
429  // must not be reordered
430  this->Store(&ofs_write_, wofs, NLIB_ATOMIC_RELEASE);
431  return 0;
432  }
433 
434  private:
435  NLIB_ALWAYS_INLINE uint32_t Load(uint32_t* p, int memorder) NLIB_NOEXCEPT {
436  return static_cast<uint32_t>(nlib_atomic_load32(
437  reinterpret_cast<int32_t*>(p), memorder));
438  }
439  NLIB_ALWAYS_INLINE void Store(uint32_t* p, uint32_t value, int memorder) NLIB_NOEXCEPT {
440  nlib_atomic_store32(reinterpret_cast<int32_t*>(p),
441  static_cast<int32_t>(value), memorder);
442  }
443 
444  uint32_t ofs_read_;
445  uint32_t ofs_write_;
446  uint8_t buffer_[N];
448 };
449 
450 template<class T>
452  public:
453  T* operator()() NLIB_NOEXCEPT { return new (std::nothrow) T(); }
454 };
455 
456 template<class T>
458  public:
459  void operator()(T* ptr) NLIB_NOEXCEPT { delete ptr; }
460 };
461 
462 template<class T>
464  public:
465  typedef T* PopType;
466  LockFreeStack() NLIB_NOEXCEPT : top_(0), pool_() {}
467  ~LockFreeStack() NLIB_NOEXCEPT {
468  // T is POD, and not pointer
469  }
470  // NOT thread safe
471  errno_t Init(size_t count) NLIB_NOEXCEPT {
472  errno_t e = pool_.Init(count);
473  if (NLIB_UNLIKELY(e != 0)) return e;
474  top_ = 1;
475  return 0;
476  }
477  errno_t Push(const T& x) NLIB_NOEXCEPT { return pool_.Push(&top_, x); }
478  errno_t Pop(PopType x) NLIB_NOEXCEPT { return pool_.Pop(&top_, x); }
479  // NOT thread safe
480  errno_t PushUnsafe(const T& x) NLIB_NOEXCEPT { return pool_.PushUnsafe(&top_, x); }
481  // NOT thread safe
482  errno_t PopUnsafe(PopType x) NLIB_NOEXCEPT { return pool_.PopUnsafe(&top_, x); }
483  void SwapUnsafe(LockFreeStack& rhs) NLIB_NOEXCEPT { // NOLINT
484  std::swap(top_, rhs.top_);
485  pool_.SwapUnsafe(rhs.pool_);
486  }
487 
488  private:
489  uintptr_t top_;
490  LockFreePlaceHolderPool<T> pool_;
491 };
492 
493 template<class T>
494 class LockFreeStack<T*> NLIB_FINAL {
495  public:
497  LockFreeStack() NLIB_NOEXCEPT : top_(0), pool_() {}
498  ~LockFreeStack() NLIB_NOEXCEPT {
499  if (top_ != 0) {
500  T* elem;
501  while (0 == pool_.PopUnsafe(&top_, &elem)) {
502  DestructorForLockFree<T>()(elem);
503  }
504  }
505  }
506  // NOT thread safe
507  errno_t Init(size_t count) NLIB_NOEXCEPT {
508  errno_t e = pool_.Init(count);
509  if (NLIB_UNLIKELY(e != 0)) return e;
510  top_ = 1;
511  return 0;
512  }
513  errno_t Push(T* obj) NLIB_NOEXCEPT { return pool_.Push(&top_, obj); }
514  errno_t Pop(PopType& obj) NLIB_NOEXCEPT { // NOLINT
515  T* x;
516  errno_t e = pool_.Pop(&top_, &x);
517  if (e != 0) return e;
518  obj.reset(x);
519  return 0;
520  }
521  // NOT thread safe
522  errno_t PushUnsafe(T* obj) NLIB_NOEXCEPT { return pool_.PushUnsafe(&top_, obj); }
523  // NOT thread safe
524  errno_t PopUnsafe(PopType& obj) NLIB_NOEXCEPT { // NOLINT
525  T* x;
526  errno_t e = pool_.PopUnsafe(&top_, &x);
527  if (e != 0) return e;
528  obj.reset(x);
529  return 0;
530  }
531  void SwapUnsafe(LockFreeStack& rhs) NLIB_NOEXCEPT { // NOLINT
532  std::swap(top_, rhs.top_);
533  pool_.SwapUnsafe(rhs.pool_);
534  }
535 
536  private:
537  uintptr_t top_;
538  LockFreePlaceHolderPool<T*> pool_;
539 };
540 
541 template<class T>
543  public:
544  typedef T* DequeueType;
545  LockFreeQueue() NLIB_NOEXCEPT : head_(0), tail_(0), pool_() {}
546  ~LockFreeQueue() NLIB_NOEXCEPT {
547  // T is POD, and not pointer
548  }
549  // NOT thread safe
550  errno_t Init(size_t count) NLIB_NOEXCEPT {
551  errno_t e = pool_.Init(count + 1);
552  if (NLIB_UNLIKELY(e != 0)) return e;
553  head_ = tail_ = reinterpret_cast<uintptr_t>(pool_.AllocUnsafe());
554  return 0;
555  }
556  errno_t Enqueue(const T& x) NLIB_NOEXCEPT { return pool_.Enqueue(&tail_, x); }
557  errno_t Dequeue(DequeueType x) NLIB_NOEXCEPT { return pool_.Dequeue(&head_, &tail_, x); }
558  // NOT thread safe
559  errno_t EnqueueUnsafe(const T& x) NLIB_NOEXCEPT { return pool_.EnqueueUnsafe(&tail_, x); }
560  // NOT thread safe
561  errno_t DequeueUnsafe(DequeueType x) NLIB_NOEXCEPT {
562  return pool_.DequeueUnsafe(&head_, &tail_, x);
563  }
564  void SwapUnsafe(LockFreeQueue& rhs) NLIB_NOEXCEPT { // NOLINT
565  std::swap(head_, rhs.head_);
566  std::swap(tail_, rhs.tail_);
567  pool_.SwapUnsafe(rhs.pool_);
568  }
569 
570  private:
571  uintptr_t head_;
572  uintptr_t tail_;
573  LockFreePlaceHolderPool<T> pool_;
574 };
575 
576 template<class T>
577 class LockFreeQueue<T*> NLIB_FINAL {
578  public:
580  LockFreeQueue() NLIB_NOEXCEPT : head_(0), tail_(0), pool_() {}
581  ~LockFreeQueue() NLIB_NOEXCEPT {
582  if (head_ != 0) {
583  T* elem;
584  while (0 == pool_.DequeueUnsafe(&head_, &tail_, &elem)) {
585  DestructorForLockFree<T>()(elem);
586  }
587  }
588  }
589  // NOT thread safe
590  errno_t Init(size_t count) NLIB_NOEXCEPT {
591  errno_t e = pool_.Init(count + 1);
592  if (NLIB_UNLIKELY(e != 0)) return e;
593  head_ = tail_ = reinterpret_cast<uintptr_t>(pool_.AllocUnsafe());
594  return 0;
595  }
596  errno_t Enqueue(T* obj) NLIB_NOEXCEPT { return pool_.Enqueue(&tail_, obj); }
597  errno_t Dequeue(DequeueType& obj) NLIB_NOEXCEPT { // NOLINT
598  T* x;
599  errno_t e = pool_.Dequeue(&head_, &tail_, &x);
600  if (e != 0) return e;
601  obj.reset(x);
602  return 0;
603  }
604  // NOT thread safe
605  errno_t EnqueueUnsafe(T* x) NLIB_NOEXCEPT { return pool_.EnqueueUnsafe(&tail_, x); }
606  // NOT thread safe
607  errno_t DequeueUnsafe(DequeueType& obj) NLIB_NOEXCEPT { // NOLINT
608  T* x;
609  errno_t e = pool_.DequeueUnsafe(&head_, &tail_, &x);
610  if (e != 0) return e;
611  obj.reset(x);
612  return 0;
613  }
614  void SwapUnsafe(LockFreeQueue& rhs) NLIB_NOEXCEPT { // NOLINT
615  std::swap(head_, rhs.head_);
616  std::swap(tail_, rhs.tail_);
617  pool_.SwapUnsafe(rhs.pool_);
618  }
619 
620  private:
621  uintptr_t head_;
622  uintptr_t tail_;
623  LockFreePlaceHolderPool<T*> pool_;
624 };
625 
626 template<class T>
627 errno_t LockFreeInit(T** ptr) NLIB_NOEXCEPT NLIB_NONNULL;
628 
629 template<class T>
630 inline errno_t LockFreeInit(T** ptr) NLIB_NOEXCEPT {
631  NLIB_EINVAL_IFNULL(ptr);
632  void* pold = nlib_atomic_loadptr(reinterpret_cast<void**>(ptr), NLIB_ATOMIC_RELAXED);
633  if (pold) return 0;
634  T* obj = ConstructorForLockFree<T>()();
635  if (!obj) {
636  pold = nlib_atomic_loadptr(reinterpret_cast<void**>(ptr), NLIB_ATOMIC_RELAXED);
637  return pold ? 0 : EAGAIN;
638  }
639  if (nlib_atomic_compare_exchangeptr(reinterpret_cast<void**>(ptr),
640  &pold, reinterpret_cast<void*>(obj), 0,
642  return 0;
643  } else {
645  return 0;
646  }
647 }
648 
649 template<class T>
651  public:
653  LockFreePriorityQueue() NLIB_NOEXCEPT : mq_() {
654  mq_.raw_handle = 0;
655  }
656  ~LockFreePriorityQueue() NLIB_NOEXCEPT {
657  if (mq_.raw_handle != 0) (void)nlib_mq_close(mq_);
658  }
659  // NOT thread safe
660  errno_t Init(size_t max_size) NLIB_NOEXCEPT {
661  // not thread safe
662  if (mq_.raw_handle != 0) return EALREADY;
663  if (max_size > INT32_MAX) return EINVAL;
664  nlib_mq_attr attr;
665  attr.flag = NLIB_MQ_LOCKFREE;
666  attr.max_msg = static_cast<int32_t>(max_size);
667  attr.destructor = LockFreePriorityQueue::dtor;
668  return nlib_mq_open(&mq_, &attr);
669  }
670  // NOT thread safe
671  errno_t Close() NLIB_NOEXCEPT {
672  // not thread safe
673  nlib_mq mq = mq_;
674  mq_.raw_handle = 0;
675  return nlib_mq_close(mq);
676  }
677  errno_t Enqueue(T* obj, int prio) NLIB_NOEXCEPT {
678  // thread safe
679  return nlib_mq_send(mq_, obj, prio);
680  }
681  errno_t Dequeue(DequeueType& obj, int* prio) NLIB_NOEXCEPT { // NOLINT
682  // thread safe
683  T* x;
684  errno_t e = nlib_mq_receive(mq_, reinterpret_cast<nlib_mq_msg*>(&x), prio);
685  if (e != 0) return e;
686  obj.reset(x);
687  return 0;
688  }
689  void SwapUnsafe(LockFreePriorityQueue& rhs) NLIB_NOEXCEPT { // NOLINT
690  nlib_mq mq = rhs.mq_;
691  rhs.mq_ = mq_;
692  mq_ = mq;
693  }
694 
695  private:
696  static void dtor(nlib_mq_msg msg) {
697  T* obj = reinterpret_cast<T*>(msg);
699  }
700 
701  nlib_mq mq_;
702 };
703 
704 namespace detail {
705 
706 class LockFreeBroadcastQueueImpl {
707  typedef LockFreePlaceHolder<const void*, int32_t> item_type;
708 
709  public:
710  LockFreeBroadcastQueueImpl() NLIB_NOEXCEPT
711  : head_(1), tail_(1), listener_count_(0), pool_(), listeners_() {}
712  NLIB_VIS_PUBLIC ~LockFreeBroadcastQueueImpl() NLIB_NOEXCEPT;
713  NLIB_VIS_PUBLIC errno_t Init(size_t max_size, size_t listeners) NLIB_NOEXCEPT;
714  errno_t Enqueue(const void* msg) NLIB_NOEXCEPT {
715  // thread safe
716  return pool_.Enqueue(&tail_, msg);
717  }
718  errno_t Dequeue(int32_t listener_id, const void** msg) NLIB_NOEXCEPT {
719  // thread safe if listener_id is different
720  if (NLIB_UNLIKELY(listener_id < 0) ||
721  NLIB_UNLIKELY(listener_id >= listener_count_)) return ERANGE;
722  uintptr_t& pos = listeners_[listener_id];
723  item_type* item = pool_.CalcPtr(pos);
724  uintptr_t next = item->next.aba_ptr;
725  if (pool_.IsNull(next)) return ENOENT;
726  *msg = pool_.CalcPtr(next)->data;
727  pos = next;
729  return 0;
730  }
731  NLIB_VIS_PUBLIC const void* CheckAndRemove() NLIB_NOEXCEPT;
732  errno_t DeleteUnsafe(const void** msg) NLIB_NOEXCEPT {
733  if (pool_.IsNull(head_)) return ENOENT;
734  item_type* item = pool_.CalcPtr(head_);
735  const void* p = item->data;
736  head_ = item->next.aba_ptr;
737  *msg = p;
738  return 0;
739  }
740  size_t GetListenerCount() const NLIB_NOEXCEPT { return listener_count_; }
741  void SwapUnsafe(LockFreeBroadcastQueueImpl& rhs) NLIB_NOEXCEPT { // NOLINT
742  std::swap(head_, rhs.head_);
743  std::swap(tail_, rhs.tail_);
744  std::swap(listener_count_, rhs.listener_count_);
745  pool_.SwapUnsafe(rhs.pool_);
746  listeners_.swap(rhs.listeners_);
747  }
748 
749  private:
750  uintptr_t Load(uintptr_t* p, int memorder = NLIB_ATOMIC_RELAXED) NLIB_NOEXCEPT {
751  return reinterpret_cast<uintptr_t>(nlib_atomic_loadptr(reinterpret_cast<void**>(p),
752  memorder));
753  }
754 
755  private:
756  uintptr_t head_;
757  uintptr_t tail_;
758  int32_t listener_count_;
759  LockFreePlaceHolderPool<const void*, int32_t> pool_;
760  UniquePtr<uintptr_t[]> listeners_;
761 };
762 
763 } // namespace detail
764 
765 template<class T>
767  public:
768  struct empty_func {
769  void operator()(const T*) {}
770  };
772  LockFreeBroadcastQueue() NLIB_NOEXCEPT : impl_() {}
773  ~LockFreeBroadcastQueue() NLIB_NOEXCEPT {
774  const void* p;
775  while (impl_.DeleteUnsafe(&p) == 0) {
776  DestructorForLockFree<const T>()(reinterpret_cast<const T*>(p));
777  }
778  }
779  // NOT thread safe
780  errno_t Init(size_t max_size, size_t listeners) NLIB_NOEXCEPT {
781  // not thread safe
782  return impl_.Init(max_size, listeners);
783  }
784  errno_t Enqueue(const T* obj) NLIB_NOEXCEPT {
785  // thread safe
786  return impl_.Enqueue(obj);
787  }
788  errno_t Dequeue(int32_t listener_id, DequeueType& obj) NLIB_NOEXCEPT { // NOLINT
789  // thread safe if listener_id is different
790  const void* x;
791  errno_t e = impl_.Dequeue(listener_id, &x);
792  if (e != 0) return e;
793  obj.reset(reinterpret_cast<const T*>(x));
794  const T* p = reinterpret_cast<const T*>(impl_.CheckAndRemove());
795  if (p) {
797  }
798  return 0;
799  }
800  size_t GetListenerCount() const NLIB_NOEXCEPT {
801  // thread safe
802  return impl_.GetListenerCount();
803  }
804  void SwapUnsafe(LockFreeBroadcastQueue& rhs) NLIB_NOEXCEPT { // NOLINT
805  impl_.SwapUnsafe(rhs);
806  }
807 
808  private:
809  detail::LockFreeBroadcastQueueImpl impl_;
810 };
811 
813  public:
814  class MemHolder {
815  public:
816  void* Get() NLIB_NOEXCEPT { return ptr_; }
817 
818  private:
819  void* const ptr_;
821  };
822  LockFreeUnitHeap() NLIB_NOEXCEPT : mem_(), pool_() {}
823  // NOT thread safe
824  NLIB_VIS_PUBLIC errno_t Init(size_t unit_size, size_t align,
825  size_t count) NLIB_NOEXCEPT;
827 
828  // MemHolder* x = heap.Alloc();
829  // void* ptr = x->Get(); // 'ptr' is what you want.
830  NLIB_ALWAYS_INLINE MemHolder* Alloc() NLIB_NOEXCEPT {
831  return reinterpret_cast<MemHolder*>(pool_.Alloc());
832  }
833 
834  NLIB_ALWAYS_INLINE void Free(MemHolder* p) NLIB_NOEXCEPT {
835  pool_.Free(reinterpret_cast<LockFreePlaceHolder<void*>*>(p));
836  }
837 
838  // NOT thread safe
839  // MemHolder* x = heap.Alloc();
840  // void* ptr = x->Get(); // 'ptr' is what you want.
841  NLIB_ALWAYS_INLINE MemHolder* AllocUnsafe() NLIB_NOEXCEPT {
842  return reinterpret_cast<MemHolder*>(pool_.AllocUnsafe());
843  }
844  // NOT thread safe
845  NLIB_ALWAYS_INLINE void FreeUnsafe(MemHolder* p) NLIB_NOEXCEPT {
846  pool_.FreeUnsafe(reinterpret_cast<LockFreePlaceHolder<void*>*>(p));
847  }
848  void SwapUnsafe(LockFreeUnitHeap& rhs) NLIB_NOEXCEPT { // NOLINT
849  using std::swap;
850  swap(mem_, rhs.mem_);
851  pool_.SwapUnsafe(rhs.pool_);
852  }
853 
854  private:
856  LockFreePlaceHolderPool<void*> pool_;
858 };
859 
860 NLIB_NAMESPACE_END
861 
862 #endif // INCLUDE_NN_NLIB_LOCKFREE_H_
void FreeUnsafe(MemHolder *p) noexcept
This function is similar to Free(), but not thread-safe.
Definition: LockFree.h:845
errno_t PopUnsafe(PopType x) noexcept
Picks up an element from the stack and stores it in x. This is not thread-safe.
Definition: LockFree.h:482
LockFreePipe() noexcept
Instantiates the object with default parameters (default constructor).
Definition: LockFree.h:364
int nlib_atomic_compare_exchangeptr(void **ptr, void **expected, void *desired, int weak, int success_memorder, int failure_memorder)
Compares and swaps atomic values. Its behavior is similar to the one for __atomic_compare_exchange_n(...
int32_t nlib_atomic_load32(const int32_t *ptr, int memorder)
Loads a value in an atomic operation. Its behavior is similar to the one for __atomic_load_n() of gcc...
#define NLIB_ALWAYS_INLINE
Indicates that the compiler is forced to perform inline expansion of functions.
Definition: Platform_unix.h:97
LockFreeQueue() noexcept
Instantiates the object with default parameters (default constructor).
Definition: LockFree.h:545
Substitute definitions for the C++11 standard header type_traits. These substitute definitions are us...
UniquePtr< const T, empty_func > DequeueType
The type for the argument of Dequeue().
Definition: LockFree.h:771
nlib_mq_msg_destructor destructor
A destructor function for a message taken from a message queue can be set or obtained.
Definition: Platform.h:1179
errno_t nlib_mq_close(nlib_mq mq)
Closes the message queue indicated with a handle.
#define NLIB_DISALLOW_COPY_AND_ASSIGN(TypeName)
Prohibits use of the copy constructor and assignment operator for the class specified by TypeName...
Definition: Config.h:179
errno_t nlib_mq_receive(nlib_mq mq, nlib_mq_msg *msg, int *prio)
Receives a message from a queue. It is the user&#39;s responsibility to delete the received messages usin...
errno_t Init(size_t count) noexcept
Initializes the stack. This is not thread-safe.
Definition: LockFree.h:471
T * PopType
The type for the argument of Pop() and PopUnsafe().
Definition: LockFree.h:465
#define NLIB_ATOMIC_RELEASE
Similar to __ATOMIC_RELEASE of gcc or std::memory_order_release of C++11.
LockFreeStack() noexcept
Instantiates the object with default parameters (default constructor).
Definition: LockFree.h:466
~LockFreeQueue() noexcept
Destructor.
Definition: LockFree.h:546
#define NLIB_UNLIKELY(x)
Indicates to the compiler that condition x is likely to be false.
A class for obtaining aligned memory.
errno_t DequeueUnsafe(DequeueType x) noexcept
Picks up an element from the queue and stores it in x. This is not thread-safe.
Definition: LockFree.h:561
size_t GetBufferSize() noexcept
Returns the buffer size. This is thread-safe.
Definition: LockFree.h:365
UniquePtr owns the pointer, and when it goes out of scope, the pointer is released by the destructor ...
Definition: UniquePtr.h:109
errno_t PushUnsafe(const T &x) noexcept
Places the element x in the stack. This is not thread-safe.
Definition: LockFree.h:480
Defines that class that is corresponding to std::unique_ptr.
errno_t nlib_mq_open(nlib_mq *mq, const nlib_mq_attr *attr)
Creates a message queue to be used to exchange messages across threads.
errno_t Pop(PopType x) noexcept
Picks up an element from the stack and stores it in x. This is thread-safe.
Definition: LockFree.h:478
errno_t LockFreeInit(T **ptr) noexcept
Constructs an object in a thread safe manner.
Definition: LockFree.h:630
static int nlib_clz32(uint32_t x)
Returns the number of consecutive zero bits, with respect to the most significant bit (MSB)...
Definition: Platform.h:2615
void SwapUnsafe(LockFreePriorityQueue &rhs) noexcept
Swaps an object. This is not thread-safe.
Definition: LockFree.h:689
errno_t EnqueueUnsafe(const T &x) noexcept
Adds the element x to the queue. This is not thread-safe.
Definition: LockFree.h:559
#define NLIB_VIS_PUBLIC
Symbols for functions and classes are made available outside of the library.
Definition: Platform_unix.h:89
A pool allocator that can allocate or free a fixed size of memory region in a lock free manner...
Definition: LockFree.h:812
int32_t max_msg
When creating a message queue, you can set the maximum number of messages.
Definition: Platform.h:1177
The specified number of listeners can obtain elements from the queue. After all the listeners have ob...
Definition: LockFree.h:766
#define NLIB_ATOMIC_ACQUIRE
Similar to __ATOMIC_ACQUIRE of gcc or std::memory_order_acquire of C++11.
MemHolder * AllocUnsafe() noexcept
This function is similar to Alloc(), but not thread-safe.
Definition: LockFree.h:841
errno_t Read(void *dest, size_t nbytes) noexcept
Reads data from a pipe. This is thread-safe.
Definition: LockFree.h:371
int32_t nlib_mq
Handle associated with a message queue. If the handle is cleared to zero (using memset()), it will always be an invalid handle.
Definition: Platform.h:1161
void * nlib_atomic_loadptr(void *const *ptr, int memorder)
Loads a value in an atomic operation. Its behavior is similar to the one for __atomic_load_n() of gcc...
void SwapUnsafe(LockFreeStack &rhs) noexcept
Swaps an object. This is not thread-safe.
Definition: LockFree.h:483
errno_t Enqueue(T *obj, int prio) noexcept
Adds an element to the queue. This is thread-safe.
Definition: LockFree.h:677
errno_t Enqueue(const T &x) noexcept
Adds the element x to the queue. This is thread-safe.
Definition: LockFree.h:556
UniquePtr< T, DestructorForLockFree< T > > DequeueType
The type for the argument of Dequeue().
Definition: LockFree.h:652
errno_t Write(const void *src, size_t nbytes) noexcept
Writes data to a pipe. This is thread-safe.
Definition: LockFree.h:402
#define NLIB_LIKELY(x)
Indicates to the compiler that condition x is likely to be true.
Definition: Platform_unix.h:99
T * DequeueType
The type for the argument of Dequeue() and DequeueUnsafe().
Definition: LockFree.h:544
static errno_t nlib_memcpy(void *s1, size_t s1max, const void *s2, size_t n)
An implementation corresponding to N1078 memcpy_s.
Definition: Platform.h:2437
int32_t nlib_atomic_add_fetch32(int32_t *ptr, int32_t val, int memorder)
Adds atomic values. Its behavior is similar to the one for __atomic_add_fetch() of gcc...
This class implements a lock-free stack.
Definition: LockFree.h:463
void nlib_atomic_storeptr(void **ptr, void *val, int memorder)
Stores a value in an atomic operation. Its behavior is similar to the one for __atomic_store_n() of g...
size_t GetListenerCount() const noexcept
Returns the number of listeners specified in Init(). This is thread-safe.
Definition: LockFree.h:800
Class template for destructing an object. This should be specialized before use.
Definition: LockFree.h:457
void SwapUnsafe(LockFreeQueue &rhs) noexcept
Swaps an object. This is not thread-safe.
Definition: LockFree.h:564
void nlib_atomic_thread_fence(int memorder)
Places the specified memory barrier.
MemHolder * Alloc() noexcept
Allocates memory. This is thread-safe.
Definition: LockFree.h:830
void SwapUnsafe(LockFreeUnitHeap &rhs) noexcept
Swaps an object. This is not thread-safe.
Definition: LockFree.h:848
Structure to store the settings and current status of a message queue.
Definition: Platform.h:1175
This class implements a lock-free queue.
Definition: LockFree.h:542
#define NLIB_NOEXCEPT
Defines noexcept geared to the environment, or the equivalent.
Definition: Config.h:105
void SwapUnsafe(LockFreeBroadcastQueue &rhs) noexcept
Swaps an object. This is not thread-safe.
Definition: LockFree.h:804
errno_t Dequeue(DequeueType &obj, int *prio) noexcept
Picks up an element from the queue. This is thread-safe.
Definition: LockFree.h:681
A file that contains the configuration information for each development environment.
errno_t Close() noexcept
Closes the queue and restores it to the state before its initialization. This is not thread-safe...
Definition: LockFree.h:671
errno_t Init(size_t count) noexcept
Initializes the queue. This is not thread-safe.
Definition: LockFree.h:550
errno_t Dequeue(DequeueType x) noexcept
Picks up an element from the queue and stores it in x. This is thread-safe.
Definition: LockFree.h:557
Used when aligned memory needs to be obtained.
errno_t Push(const T &x) noexcept
Places the element x in the stack. This is thread-safe.
Definition: LockFree.h:477
errno_t nlib_mq_send(nlib_mq mq, nlib_mq_msg msg, int prio)
Sends a message to a queue.
#define NLIB_ATOMIC_RELAXED
Similar to __ATOMIC_RELAXED of gcc or std::memory_order_relaxed of C++11.
LockFreeUnitHeap() noexcept
Instantiates the object with default parameters (default constructor).
Definition: LockFree.h:822
errno_t Init(size_t max_size, size_t listeners) noexcept
Initializes the queue. This is not thread-safe.
Definition: LockFree.h:780
When a single sender thread sends data and a single receiver thread receives that data...
Definition: LockFree.h:362
#define NLIB_FINAL
Defines final if it is available for use. If not, holds an empty string.
Definition: Config.h:245
errno_t Init(size_t max_size) noexcept
Initializes the queue. This is not thread-safe.
Definition: LockFree.h:660
#define NLIB_STATIC_ASSERT(exp)
Defines a static assertion. Uses static_assert if it is available for use.
Definition: Config.h:170
LockFreeBroadcastQueue() noexcept
Instantiates the object with default parameters (default constructor).
Definition: LockFree.h:772
Class template for initializing an object. This should be specialized before use. ...
Definition: LockFree.h:451
~LockFreeStack() noexcept
Destructor.
Definition: LockFree.h:467
~LockFreeBroadcastQueue() noexcept
Destructor.
Definition: LockFree.h:773
errno_t Dequeue(int32_t listener_id, DequeueType &obj) noexcept
Specifies the listener and then reads an element from the queue. This is thread-safe when using a dif...
Definition: LockFree.h:788
void Free(MemHolder *p) noexcept
Frees memory. This is thread-safe.
Definition: LockFree.h:834
LockFreePriorityQueue() noexcept
Instantiates the object with default parameters (default constructor).
Definition: LockFree.h:653
#define NLIB_NONNULL
Indicates that you cannot specify NULL for all arguments.
void nlib_atomic_store32(int32_t *ptr, int32_t val, int memorder)
Stores a value in an atomic operation. Its behavior is similar to the one for __atomic_store_n() of g...
int32_t flag
Settings to be used when creating a message queue.
Definition: Platform.h:1176
Wraps nlib_mq with a class implementing a lock-free queue with a priority set.
Definition: LockFree.h:650
~LockFreePriorityQueue() noexcept
Destructor.
Definition: LockFree.h:656
void * nlib_mq_msg
Type of messages stored in a message queue.
Definition: Platform.h:1167
static int nlib_clz64(uint64_t x)
Returns the number of consecutive zero bits, with respect to the most significant bit (MSB)...
Definition: Platform.h:2617
errno_t Enqueue(const T *obj) noexcept
Adds an element to the queue. This is thread-safe.
Definition: LockFree.h:784
int errno_t
Indicates with an int-type typedef that a POSIX error value is returned as the return value...
Definition: NMalloc.h:37