stack.cpp 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144
  1. /* Definitions for the stack template type.
  2. This file is part of xrcu.
  3. xrcu is free software: you can redistribute it and/or modify
  4. it under the terms of the GNU General Public License as published by
  5. the Free Software Foundation; either version 3 of the License, or
  6. (at your option) any later version.
  7. This program is distributed in the hope that it will be useful,
  8. but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  10. GNU General Public License for more details.
  11. You should have received a copy of the GNU General Public License
  12. along with this program. If not, see <https://www.gnu.org/licenses/>. */
  13. #include "stack.hpp"
  14. #include "xatomic.hpp"
  15. #include <atomic>
  16. namespace xrcu
  17. {
  18. namespace detail
  19. {
  20. static const uintptr_t SPIN_BIT = 1;
  21. static inline bool
  22. node_spinning_p (const stack_node_base *np)
  23. {
  24. return (((uintptr_t)np) & SPIN_BIT);
  25. }
  26. static inline stack_node_base*
  27. get_node (const stack_node_base::ptr_type& head)
  28. {
  29. return (head.load (std::memory_order_relaxed));
  30. }
  31. stack_node_base* stack_node_base::root (const ptr_type& head)
  32. {
  33. auto ret = (uintptr_t)get_node (head);
  34. return (((stack_node_base *)(ret & ~SPIN_BIT)));
  35. }
  36. void stack_node_base::push (ptr_type& head, stack_node_base *nodep)
  37. {
  38. while (true)
  39. {
  40. nodep->next = get_node (head);
  41. if (!node_spinning_p (nodep->next) &&
  42. head.compare_exchange_weak (nodep->next, nodep,
  43. std::memory_order_acq_rel, std::memory_order_relaxed))
  44. break;
  45. xatomic_spin_nop ();
  46. }
  47. }
  48. void stack_node_base::push (ptr_type& head,
  49. stack_node_base *nodep, stack_node_base **outp)
  50. {
  51. while (true)
  52. {
  53. auto tmp = get_node (head);
  54. if (!node_spinning_p (tmp))
  55. {
  56. *outp = tmp;
  57. if (head.compare_exchange_weak (tmp, nodep,
  58. std::memory_order_acq_rel, std::memory_order_relaxed))
  59. break;
  60. }
  61. xatomic_spin_nop ();
  62. }
  63. }
  64. stack_node_base* stack_node_base::pop (ptr_type& head)
  65. {
  66. while (true)
  67. {
  68. auto nodep = get_node (head);
  69. if (node_spinning_p (nodep))
  70. ;
  71. else if (!nodep)
  72. return (nodep);
  73. else if (head.compare_exchange_weak (nodep, nodep->next,
  74. std::memory_order_acq_rel, std::memory_order_relaxed))
  75. {
  76. nodep->next = nullptr;
  77. return (nodep);
  78. }
  79. xatomic_spin_nop ();
  80. }
  81. }
  82. static inline stack_node_base*
  83. set_spin (stack_node_base::ptr_type& head)
  84. {
  85. while (true)
  86. {
  87. auto tmp = get_node (head);
  88. if (!node_spinning_p (tmp) &&
  89. head.compare_exchange_weak (tmp,
  90. (stack_node_base *)((uintptr_t)tmp | SPIN_BIT),
  91. std::memory_order_acq_rel, std::memory_order_relaxed))
  92. return (tmp);
  93. xatomic_spin_nop ();
  94. }
  95. }
  96. void stack_node_base::swap (ptr_type& h1, ptr_type& h2)
  97. {
  98. // Prevent any further modifications.
  99. auto ln = set_spin (h1), rn = set_spin (h2);
  100. // Swap the root nodes.
  101. h1.store (rn, std::memory_order_release);
  102. h2.store (ln, std::memory_order_release);
  103. }
  104. stack_node_base* stack_node_base::clear (ptr_type& head)
  105. {
  106. auto ret = set_spin (head);
  107. head.store (nullptr, std::memory_order_release);
  108. return (ret);
  109. }
  110. size_t stack_node_base::size (const ptr_type& head)
  111. {
  112. auto runp = get_node (head);
  113. size_t ret = 0;
  114. for (; runp; runp = runp->next, ++ret) ;
  115. return (ret);
  116. }
  117. } } // namespaces