123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127 |
- #include "stack.hpp"
- #include "xatomic.hpp"
- #include <atomic>
- namespace xrcu
- {
- namespace detail
- {
- static const uintptr_t SPIN_BIT = 1;
- static inline bool
- node_spinning_p (const stack_node_base *np)
- {
- return (((uintptr_t)np) & SPIN_BIT);
- }
- static inline stack_node_base*
- get_node (const stack_node_base::ptr_type& head)
- {
- return (head.load (std::memory_order_relaxed));
- }
- stack_node_base* stack_node_base::root (const ptr_type& head)
- {
- auto ret = (uintptr_t)get_node (head);
- return (((stack_node_base *)(ret & ~SPIN_BIT)));
- }
- void stack_node_base::push (ptr_type& head, stack_node_base *nodep)
- {
- while (true)
- {
- nodep->next = get_node (head);
- if (!node_spinning_p (nodep->next) &&
- head.compare_exchange_weak (nodep->next, nodep,
- std::memory_order_acq_rel, std::memory_order_relaxed))
- break;
- xatomic_spin_nop ();
- }
- }
- void stack_node_base::push (ptr_type& head,
- stack_node_base *nodep, stack_node_base **outp)
- {
- while (true)
- {
- auto tmp = get_node (head);
- if (!node_spinning_p (tmp))
- {
- *outp = tmp;
- if (head.compare_exchange_weak (tmp, nodep,
- std::memory_order_acq_rel, std::memory_order_relaxed))
- break;
- }
- xatomic_spin_nop ();
- }
- }
- stack_node_base* stack_node_base::pop (ptr_type& head)
- {
- while (true)
- {
- auto nodep = get_node (head);
- if (node_spinning_p (nodep))
- ;
- else if (!nodep)
- return (nodep);
- else if (head.compare_exchange_weak (nodep, nodep->next,
- std::memory_order_acq_rel, std::memory_order_relaxed))
- {
- nodep->next = nullptr;
- return (nodep);
- }
- xatomic_spin_nop ();
- }
- }
- static inline stack_node_base*
- set_spin (stack_node_base::ptr_type& head)
- {
- while (true)
- {
- auto tmp = get_node (head);
- if (!node_spinning_p (tmp) &&
- head.compare_exchange_weak (tmp,
- (stack_node_base *)((uintptr_t)tmp | SPIN_BIT),
- std::memory_order_acq_rel, std::memory_order_relaxed))
- return (tmp);
- xatomic_spin_nop ();
- }
- }
- void stack_node_base::swap (ptr_type& h1, ptr_type& h2)
- {
- // Prevent any further modifications.
- auto ln = set_spin (h1), rn = set_spin (h2);
- // Swap the root nodes.
- h1.store (rn, std::memory_order_release);
- h2.store (ln, std::memory_order_release);
- }
- stack_node_base* stack_node_base::clear (ptr_type& head)
- {
- auto ret = set_spin (head);
- head.store (nullptr, std::memory_order_release);
- return (ret);
- }
- size_t stack_node_base::size (const ptr_type& head)
- {
- auto runp = get_node (head);
- size_t ret = 0;
- for (; runp; runp = runp->next, ++ret) ;
- return (ret);
- }
- } } // namespaces
|