2#ifndef __ASE_ATOMICS_HH__
3#define __ASE_ATOMICS_HH__
7#include <boost/atomic/atomic.hpp>
14template<
class T>
using Atomic = boost::atomic<T>;
28 "Required: std::atomic<T*>& atomic_next_ptrref (T&)");
34 return head_.
load() ==
nullptr;
40 AtomicTPtr &last_nextptr = atomic_next_ptrref (last);
42 T *exchange = head_.
load();
44 last_nextptr = exchange;
46 const bool was_empty = exchange ==
nullptr;
60 T *exchange = head_.
load();
71 T *current =
pop_all(), *prev =
nullptr;;
74 AtomicTPtr &el_nextptr = atomic_next_ptrref (current);
95template<
typename Node>
101 thead.next = (Node*) TAIL_;
109 Head nhead, ohead = head_.load();
112 nhead.aba_counter = ohead.aba_counter;
113 nhead.next =
nullptr;
115 while (!head_.compare_exchange_weak (ohead, nhead));
116 ohead = head_.load();
117 assert (ohead.next ==
nullptr);
122 const Head ohead = head_.load();
123 return ohead.next == (Node*) TAIL_;
128 assert (node && !node->intr_ptr_);
129 Head nhead, ohead = head_.load();
133 node->intr_ptr_ = ohead.next;
134 nhead.aba_counter = ohead.aba_counter;
137 while (!head_.compare_exchange_weak (ohead, nhead));
138 const bool was_empty = ohead.next == (Node*) TAIL_;
145 Head nhead, ohead = head_.load();
150 if (node == (Node*) TAIL_)
152 nhead.next = node->intr_ptr_;
153 nhead.aba_counter = ohead.aba_counter + 1;
155 while (!head_.compare_exchange_weak (ohead, nhead));
156 node->intr_ptr_ =
nullptr;
163 const Head ohead = head_.load();
168 Node *next =
nullptr;
172 static constexpr uintptr_t TAIL_ = ~uintptr_t (0);
178template<
typename Value,
template<
class>
class GrowOnlyAllocator =
Loft::Allocator>
181 bool empty()
const {
return stack_.empty(); }
186 Node *node = node_realloc (
nullptr);
188 return stack_.push (node);
200 Node *node = stack_.pop();
203 value = std::move (node->value);
211 Atomic<Node*> intr_ptr_ =
nullptr;
213 MpmcStack<Node> stack_;
215 node_realloc (Node *node)
217 static constexpr GrowOnlyAllocator<Node> grow_only_alloc;
218 static_assert (GrowOnlyAllocator<Node>::allows_read_after_free ==
true);
220 grow_only_alloc.deallocate (node, 1);
223 node = grow_only_alloc.allocate (1);
239 size_t u_ = ~size_t (0), s_ = 0;
240 AtomicU64& ubits()
const {
return const_cast<Iter*
> (
this)->atomics_->u64 (u_); }
241 size_t usize()
const {
return atomics_ ? atomics_->usize() : 0; }
243 explicit Iter (
AtomicBits *a,
size_t p) : atomics_ (a), u_ (p >> 6), s_ (p & 63) {}
246 Iter& operator= (
const Iter&) =
default;
247 size_t position ()
const {
return u_ + s_; }
248 bool is_set ()
const {
return valid() && ubits().
load() & (
uint64 (1) << s_); }
249 bool done ()
const {
return !valid(); }
250 bool valid ()
const {
return atomics_ && u_ < usize(); }
252 bool set (
bool toggle);
253 bool xor_ (
bool toggle);
255 Iter& operator= (
bool toggle) { set (toggle);
return *
this; }
256 Iter& operator^= (
bool toggle) { xor_ (toggle);
return *
this; }
257 Iter& operator|= (
bool toggle) {
if (toggle) set (1);
return *
this; }
258 Iter& operator&= (
bool toggle) {
if (!toggle) set (0);
return *
this; }
259 Iter& operator++ () {
if (!done()) { s_ = (s_ + 1) & 63; u_ += s_ == 0; }
return *
this;}
260 Iter& operator++ (
int) {
return this->operator++(); }
261 bool operator== (
const Iter &o)
const {
return (done() && o.done()) || position() == o.position(); }
262 bool operator!= (
const Iter &o)
const {
return !operator== (o); }
263 bool operator== (
bool b)
const {
return b == is_set(); }
264 bool operator!= (
bool b)
const {
return b != is_set(); }
265 explicit operator bool ()
const {
return is_set(); }
269 explicit AtomicBits (
const AtomicBits&) =
delete;
270 size_t usize ()
const {
return base().
size(); }
271 size_t size ()
const {
return 64 * usize(); }
272 uint64 u64 (
size_t upos)
const {
return base()[upos]; }
273 AtomicU64& u64 (
size_t upos) {
return base()[upos]; }
274 AtomicBits& operator= (
const AtomicBits&) =
delete;
275 Iter iter (
size_t pos) {
return Iter (
this, pos); }
276 Iter begin () {
return iter (0); }
277 Iter end ()
const {
return {}; }
278 bool all (
bool toggle)
const;
279 bool any (
bool toggle)
const;
280 bool set (
size_t pos,
bool toggle) {
return iter (pos).set (toggle); }
281 bool operator[] (
size_t pos)
const {
return const_cast<AtomicBits*
> (
this)->iter (pos).is_set(); }
282 Iter operator[] (
size_t pos) {
return iter (pos); }
286AtomicBits::all (
bool toggle)
const
288 const uint64 match = toggle * ~uint64 (0);
289 for (
size_t u = 0; u < usize(); u++)
290 if (u64 (u) != match)
296AtomicBits::any (
bool toggle)
const
299 for (
size_t u = 0; u < usize(); u++)
303 for (
size_t u = 0; u < usize(); u++)
304 if (u64 (u) != ~uint64 (0))
311AtomicBits::Iter::set (
bool toggle)
323AtomicBits::Iter::clear()
332AtomicBits::Iter::xor_ (
bool toggle)
336 last = ubits().fetch_xor (toggle ?
uint64 (1) << s_ : 0);
341inline AtomicBits::Iter&
352 while (!ubits().load() && u_ < usize());
Iter & big_inc1()
Increment iterator by 1, allow big increments skipping zero bits.
Vector of atomic bits, operates in blocks of 64 bits.
bool push_chain(T *first, T *last)
Atomically push linked nodes first->…->last onto the stack, returns was_empty.
bool push(T *el)
Atomically push el onto the stack, returns was_empty.
bool empty() const
Check if poppingreturns null.
Allocator for STL containers.
T compare_exchange_strong(T... args)
T construct_at(T... args)
#define ASE_ASSERT_RETURN(expr,...)
Return from the current function if expr evaluates to false and issue an assertion warning.
#define ASE_RETURN_UNLESS(cond,...)
Return silently if cond does not evaluate to true, with return value ...
#define ASE_ISLIKELY(expr)
Compiler hint to optimize for expr evaluating to true.
The Anklang C++ API namespace.
boost::atomic< T > Atomic
Substitute for std::atomic<> with fixes for GCC.
uint64_t uint64
A 64-bit unsigned integer, use PRI*64 in format strings.
bool push(const Value &value)
Add a copy of value to top of the stack, returns if the stack was empty (true).
bool empty() const
Return true if the stack holds no items.
bool pop(Value &value)
Pop value from top of the stack, returns if value was reassigned (true), otherwise the stack was empt...
bool push(Value &&value)
Add value to top of the stack, returns if the stack was empty (true).
Value type used to interface with various property types.