xrcu.cpp 8.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455
  1. /* Definitions for the RCU API.
  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 "xrcu.hpp"
  14. #include "xatomic.hpp"
  15. #include "version.hpp"
  16. #include <thread>
  17. #include <mutex>
  18. #include <atomic>
  19. #include <chrono>
  20. #include <cstdint>
  21. #include <ctime>
  22. #include <functional>
  23. #if defined (__MINGW32__) || defined (__MINGW64__)
  24. #include <pthread.h>
  25. static void tl_set (void *);
  26. #else
  27. # define tl_set(p)
  28. #endif
  29. namespace xrcu
  30. {
  31. struct td_link
  32. {
  33. td_link *next;
  34. td_link *prev;
  35. void init_head ()
  36. {
  37. this->next = this->prev = this;
  38. }
  39. void add (td_link *headp)
  40. { // Add self to HEADP.
  41. this->next = headp->next;
  42. this->prev = headp;
  43. headp->next->prev = this;
  44. headp->next = this;
  45. }
  46. void del ()
  47. { // Unlink self.
  48. this->next->prev = this->prev;
  49. this->prev->next = this->next;
  50. }
  51. bool empty_p () const
  52. {
  53. return (this == this->next);
  54. }
  55. bool linked_p () const
  56. {
  57. return (this->next != nullptr);
  58. }
  59. void splice (td_link *dst)
  60. {
  61. if (this->empty_p ())
  62. return;
  63. this->next->prev = dst;
  64. this->prev->next = dst->next;
  65. dst->next->prev = this->prev;
  66. dst->next = this->next;
  67. }
  68. };
  69. static const uintptr_t GP_PHASE_BIT =
  70. (uintptr_t)1 << (sizeof (uintptr_t) * 8 - 1);
  71. static const uintptr_t GP_NEST_MASK = GP_PHASE_BIT - 1;
  72. // Possible states for a reader thread.
  73. enum
  74. {
  75. rd_active,
  76. rd_inactive,
  77. rd_old
  78. };
  79. struct registry
  80. {
  81. std::atomic_uintptr_t counter;
  82. td_link root;
  83. std::mutex td_mtx;
  84. std::mutex gp_mtx;
  85. static const unsigned int QS_ATTEMPTS = 1000;
  86. registry () : counter (1)
  87. {
  88. this->root.init_head ();
  89. }
  90. void add_tdata (td_link *lp)
  91. {
  92. tl_set (lp);
  93. this->td_mtx.lock ();
  94. lp->add (&this->root);
  95. this->td_mtx.unlock ();
  96. }
  97. uintptr_t get_ctr () const
  98. {
  99. return (this->counter.load (std::memory_order_relaxed));
  100. }
  101. void poll_readers (td_link *, td_link *, td_link *);
  102. void sync ();
  103. };
  104. static registry global_reg;
  105. // Maximum number of pending finalizers before flushing.
  106. #ifndef XRCU_MAX_FINS
  107. # define XRCU_MAX_FINS 1000
  108. #endif
  109. static const unsigned int MAX_FINS = XRCU_MAX_FINS;
  110. struct tl_data : public td_link
  111. {
  112. bool must_flush;
  113. unsigned int n_fins;
  114. std::atomic_uintptr_t counter;
  115. size_t xrand_val;
  116. finalizable *fin_objs;
  117. uintptr_t get_ctr () const
  118. {
  119. return (this->counter.load (std::memory_order_relaxed));
  120. }
  121. int state () const
  122. {
  123. auto val = this->counter.load (std::memory_order_acquire);
  124. if (!(val & GP_NEST_MASK))
  125. return (rd_inactive);
  126. else if (!((val ^ global_reg.get_ctr ()) & GP_PHASE_BIT))
  127. return (rd_active);
  128. else
  129. return (rd_old);
  130. }
  131. bool in_cs () const
  132. {
  133. return ((this->get_ctr () & GP_NEST_MASK) != 0);
  134. }
  135. bool flush_all ()
  136. {
  137. if (!sync ())
  138. return (false);
  139. for (auto f = this->fin_objs; f != nullptr; )
  140. {
  141. auto next = f->_Fin_next;
  142. f->safe_destroy ();
  143. f = next;
  144. }
  145. this->fin_objs = nullptr;
  146. this->n_fins = 0;
  147. this->must_flush = false;
  148. return (true);
  149. }
  150. void finalize (finalizable *finp)
  151. {
  152. finp->_Fin_next = this->fin_objs;
  153. this->fin_objs = finp;
  154. if (++this->n_fins < MAX_FINS)
  155. ;
  156. else if (!this->flush_all ())
  157. /* Couldn't reclaim memory since we are in a critical section.
  158. * Set the flag to do it ASAP. */
  159. this->must_flush = true;
  160. }
  161. ~tl_data ()
  162. {
  163. if (!this->linked_p ())
  164. return;
  165. this->counter.store (0, std::memory_order_release);
  166. if (this->n_fins > 0)
  167. this->flush_all ();
  168. global_reg.td_mtx.lock ();
  169. this->del ();
  170. global_reg.td_mtx.unlock ();
  171. }
  172. };
  173. #if defined (__MINGW32__) || defined (__MINGW64__)
  174. // Mingw has problems with thread_local destructors.
  175. struct key_handler
  176. {
  177. pthread_key_t key;
  178. static void fini (void *ptr)
  179. {
  180. ((tl_data *)ptr)->~tl_data ();
  181. }
  182. key_handler ()
  183. {
  184. if (pthread_key_create (&this->key, key_handler::fini) != 0)
  185. throw "failed to create thread key";
  186. }
  187. void set (void *ptr)
  188. {
  189. pthread_setspecific (this->key, ptr);
  190. }
  191. };
  192. struct alignas (alignof (tl_data)) tl_buf
  193. {
  194. unsigned char data[sizeof (tl_data)];
  195. };
  196. static thread_local tl_buf tlbuf;
  197. #define tldata (*(tl_data *)&tlbuf)
  198. #else
  199. static thread_local tl_data tldata {};
  200. #endif
  201. static inline tl_data*
  202. local_data ()
  203. {
  204. auto self = &tldata;
  205. if (!self->linked_p ())
  206. global_reg.add_tdata (self);
  207. return (self);
  208. }
  209. void enter_cs ()
  210. {
  211. auto self = local_data ();
  212. auto val = self->get_ctr ();
  213. val = (val & GP_NEST_MASK) == 0 ? global_reg.get_ctr () : val + 1;
  214. self->counter.store (val, std::memory_order_release);
  215. }
  216. void exit_cs ()
  217. {
  218. auto self = local_data ();
  219. auto val = self->get_ctr ();
  220. self->counter.store (val - 1, std::memory_order_release);
  221. if (self->must_flush && !self->in_cs ())
  222. self->flush_all ();
  223. }
  224. bool in_cs ()
  225. {
  226. auto self = &tldata;
  227. return (self->linked_p () && self->in_cs ());
  228. }
  229. void registry::poll_readers (td_link *readers, td_link *outp, td_link *qsp)
  230. {
  231. for (unsigned int loops = 0 ; ; ++loops)
  232. {
  233. td_link *next, *runp = readers->next;
  234. for (; runp != readers; runp = next)
  235. {
  236. next = runp->next;
  237. switch (((tl_data *)runp)->state ())
  238. {
  239. case rd_active:
  240. if (outp != nullptr)
  241. {
  242. runp->del ();
  243. runp->add (outp);
  244. break;
  245. }
  246. // Fallthrough.
  247. case rd_inactive:
  248. runp->del ();
  249. runp->add (qsp);
  250. break;
  251. default:
  252. break;
  253. }
  254. }
  255. if (readers->empty_p ())
  256. break;
  257. this->td_mtx.unlock ();
  258. if (loops < QS_ATTEMPTS)
  259. xatomic_spin_nop ();
  260. else
  261. std::this_thread::sleep_for (std::chrono::milliseconds (1));
  262. this->td_mtx.lock ();
  263. }
  264. }
  265. void registry::sync ()
  266. {
  267. this->gp_mtx.lock ();
  268. this->td_mtx.lock ();
  269. if (this->root.empty_p ())
  270. {
  271. this->td_mtx.unlock ();
  272. this->gp_mtx.unlock ();
  273. return;
  274. }
  275. td_link out, qs;
  276. qs.init_head ();
  277. out.init_head ();
  278. std::atomic_thread_fence (std::memory_order_acq_rel);
  279. poll_readers (&this->root, &out, &qs);
  280. this->counter.store (this->get_ctr () ^ GP_PHASE_BIT,
  281. std::memory_order_relaxed);
  282. poll_readers (&out, nullptr, &qs);
  283. qs.splice (&this->root);
  284. this->td_mtx.unlock ();
  285. this->gp_mtx.unlock ();
  286. }
  287. bool sync ()
  288. {
  289. if (in_cs ())
  290. return (false);
  291. global_reg.sync ();
  292. return (true);
  293. }
  294. void finalize (finalizable *finp)
  295. {
  296. if (finp)
  297. local_data()->finalize (finp);
  298. }
  299. bool flush_finalizers ()
  300. {
  301. auto tld = local_data ();
  302. bool ret = tld->flush_all ();
  303. if (!ret)
  304. tld->must_flush = true;
  305. return (ret);
  306. }
  307. unsigned int xrand ()
  308. {
  309. auto self = &tldata; // Avoid local_data ()
  310. if (!self->xrand_val)
  311. self->xrand_val = (unsigned int)(time (nullptr) ^
  312. std::hash<std::thread::id>() (std::this_thread::get_id ()));
  313. self->xrand_val = self->xrand_val * 1103515245 + 12345;
  314. return (self->xrand_val >> 16);
  315. }
  316. static void
  317. atfork_prepare ()
  318. {
  319. global_reg.gp_mtx.lock ();
  320. global_reg.td_mtx.lock ();
  321. }
  322. static void
  323. atfork_parent ()
  324. {
  325. global_reg.td_mtx.unlock ();
  326. global_reg.gp_mtx.unlock ();
  327. }
  328. static void
  329. atfork_child ()
  330. {
  331. atfork_parent ();
  332. // Reset the registry
  333. global_reg.root.init_head ();
  334. auto self = &tldata;
  335. if (!self->linked_p ())
  336. return;
  337. // Manually add ourselves to the registry without locking.
  338. self->add (&global_reg.root);
  339. }
  340. atfork atfork_data ()
  341. {
  342. atfork ret;
  343. ret.prepare = atfork_prepare;
  344. ret.parent = atfork_parent;
  345. ret.child = atfork_child;
  346. return (ret);
  347. }
  348. void library_version (int& major, int& minor)
  349. {
  350. major = MAJOR, minor = MINOR;
  351. }
  352. } // namespace rcu
  353. #if defined (__MINGW32__) || defined (__MINGW64__)
  354. static void
  355. tl_set (void *ptr)
  356. {
  357. static xrcu::key_handler handler;
  358. handler.set (ptr);
  359. }
  360. #endif