once.hpp 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541
  1. #ifndef BOOST_THREAD_PTHREAD_ONCE_HPP
  2. #define BOOST_THREAD_PTHREAD_ONCE_HPP
  3. // once.hpp
  4. //
  5. // (C) Copyright 2007-8 Anthony Williams
  6. // (C) Copyright 2011-2012 Vicente J. Botet Escriba
  7. //
  8. // Distributed under the Boost Software License, Version 1.0. (See
  9. // accompanying file LICENSE_1_0.txt or copy at
  10. // http://www.boost.org/LICENSE_1_0.txt)
  11. #include <boost/thread/detail/config.hpp>
  12. #include <boost/thread/detail/move.hpp>
  13. #include <boost/thread/detail/invoke.hpp>
  14. #include <boost/thread/pthread/pthread_helpers.hpp>
  15. #include <boost/thread/pthread/pthread_mutex_scoped_lock.hpp>
  16. #include <boost/thread/detail/delete.hpp>
  17. #include <boost/core/no_exceptions_support.hpp>
  18. #include <boost/bind.hpp>
  19. #include <boost/assert.hpp>
  20. #include <boost/config/abi_prefix.hpp>
  21. #include <boost/cstdint.hpp>
  22. #include <pthread.h>
  23. #include <csignal>
  24. namespace boost
  25. {
  26. struct once_flag;
  27. #define BOOST_ONCE_INITIAL_FLAG_VALUE 0
  28. namespace thread_detail
  29. {
  30. typedef boost::uint32_t uintmax_atomic_t;
  31. #define BOOST_THREAD_DETAIL_UINTMAX_ATOMIC_C2(value) value##u
  32. #define BOOST_THREAD_DETAIL_UINTMAX_ATOMIC_MAX_C BOOST_THREAD_DETAIL_UINTMAX_ATOMIC_C2(~0)
  33. }
  34. #ifdef BOOST_THREAD_PROVIDES_ONCE_CXX11
  35. #if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) && !defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
  36. template<typename Function, class ...ArgTypes>
  37. inline void call_once(once_flag& flag, BOOST_THREAD_RV_REF(Function) f, BOOST_THREAD_RV_REF(ArgTypes)... args);
  38. #else
  39. template<typename Function>
  40. inline void call_once(once_flag& flag, Function f);
  41. template<typename Function, typename T1>
  42. inline void call_once(once_flag& flag, Function f, T1 p1);
  43. template<typename Function, typename T1, typename T2>
  44. inline void call_once(once_flag& flag, Function f, T1 p1, T2 p2);
  45. template<typename Function, typename T1, typename T2, typename T3>
  46. inline void call_once(once_flag& flag, Function f, T1 p1, T2 p2, T3 p3);
  47. #endif
  48. struct once_flag
  49. {
  50. BOOST_THREAD_NO_COPYABLE(once_flag)
  51. BOOST_CONSTEXPR once_flag() BOOST_NOEXCEPT
  52. : epoch(BOOST_ONCE_INITIAL_FLAG_VALUE)
  53. {}
  54. private:
  55. volatile thread_detail::uintmax_atomic_t epoch;
  56. #if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) && !defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
  57. template<typename Function, class ...ArgTypes>
  58. friend void call_once(once_flag& flag, BOOST_THREAD_RV_REF(Function) f, BOOST_THREAD_RV_REF(ArgTypes)... args);
  59. #else
  60. template<typename Function>
  61. friend void call_once(once_flag& flag, Function f);
  62. template<typename Function, typename T1>
  63. friend void call_once(once_flag& flag, Function f, T1 p1);
  64. template<typename Function, typename T1, typename T2>
  65. friend void call_once(once_flag& flag, Function f, T1 p1, T2 p2);
  66. template<typename Function, typename T1, typename T2, typename T3>
  67. friend void call_once(once_flag& flag, Function f, T1 p1, T2 p2, T3 p3);
  68. #endif
  69. };
  70. #define BOOST_ONCE_INIT once_flag()
  71. #else // BOOST_THREAD_PROVIDES_ONCE_CXX11
  72. struct once_flag
  73. {
  74. volatile thread_detail::uintmax_atomic_t epoch;
  75. };
  76. #define BOOST_ONCE_INIT {BOOST_ONCE_INITIAL_FLAG_VALUE}
  77. #endif // BOOST_THREAD_PROVIDES_ONCE_CXX11
  78. #if defined BOOST_THREAD_PROVIDES_INVOKE
  79. #define BOOST_THREAD_INVOKE_RET_VOID detail::invoke
  80. #define BOOST_THREAD_INVOKE_RET_VOID_CALL
  81. #elif defined BOOST_THREAD_PROVIDES_INVOKE_RET
  82. #define BOOST_THREAD_INVOKE_RET_VOID detail::invoke<void>
  83. #define BOOST_THREAD_INVOKE_RET_VOID_CALL
  84. #else
  85. #define BOOST_THREAD_INVOKE_RET_VOID boost::bind
  86. #define BOOST_THREAD_INVOKE_RET_VOID_CALL ()
  87. #endif
  88. namespace thread_detail
  89. {
  90. BOOST_THREAD_DECL uintmax_atomic_t& get_once_per_thread_epoch();
  91. BOOST_THREAD_DECL extern uintmax_atomic_t once_global_epoch;
  92. BOOST_THREAD_DECL extern pthread_mutex_t once_epoch_mutex;
  93. BOOST_THREAD_DECL extern pthread_cond_t once_epoch_cv;
  94. }
  95. // Based on Mike Burrows fast_pthread_once algorithm as described in
  96. // http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2444.html
  97. #if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) && !defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
  98. template<typename Function, class ...ArgTypes>
  99. inline void call_once(once_flag& flag, BOOST_THREAD_RV_REF(Function) f, BOOST_THREAD_RV_REF(ArgTypes)... args)
  100. {
  101. static thread_detail::uintmax_atomic_t const uninitialized_flag=BOOST_ONCE_INITIAL_FLAG_VALUE;
  102. static thread_detail::uintmax_atomic_t const being_initialized=uninitialized_flag+1;
  103. thread_detail::uintmax_atomic_t const epoch=flag.epoch;
  104. thread_detail::uintmax_atomic_t& this_thread_epoch=thread_detail::get_once_per_thread_epoch();
  105. if(epoch<this_thread_epoch)
  106. {
  107. pthread::pthread_mutex_scoped_lock lk(&thread_detail::once_epoch_mutex);
  108. while(flag.epoch<=being_initialized)
  109. {
  110. if(flag.epoch==uninitialized_flag)
  111. {
  112. flag.epoch=being_initialized;
  113. BOOST_TRY
  114. {
  115. pthread::pthread_mutex_scoped_unlock relocker(&thread_detail::once_epoch_mutex);
  116. BOOST_THREAD_INVOKE_RET_VOID(
  117. thread_detail::decay_copy(boost::forward<Function>(f)),
  118. thread_detail::decay_copy(boost::forward<ArgTypes>(args))...
  119. ) BOOST_THREAD_INVOKE_RET_VOID_CALL;
  120. }
  121. BOOST_CATCH (...)
  122. {
  123. flag.epoch=uninitialized_flag;
  124. BOOST_VERIFY(!posix::pthread_cond_broadcast(&thread_detail::once_epoch_cv));
  125. BOOST_RETHROW
  126. }
  127. BOOST_CATCH_END
  128. flag.epoch=--thread_detail::once_global_epoch;
  129. BOOST_VERIFY(!posix::pthread_cond_broadcast(&thread_detail::once_epoch_cv));
  130. }
  131. else
  132. {
  133. while(flag.epoch==being_initialized)
  134. {
  135. BOOST_VERIFY(!posix::pthread_cond_wait(&thread_detail::once_epoch_cv,&thread_detail::once_epoch_mutex));
  136. }
  137. }
  138. }
  139. this_thread_epoch=thread_detail::once_global_epoch;
  140. }
  141. }
  142. #else
  143. template<typename Function>
  144. inline void call_once(once_flag& flag, Function f)
  145. {
  146. static thread_detail::uintmax_atomic_t const uninitialized_flag=BOOST_ONCE_INITIAL_FLAG_VALUE;
  147. static thread_detail::uintmax_atomic_t const being_initialized=uninitialized_flag+1;
  148. thread_detail::uintmax_atomic_t const epoch=flag.epoch;
  149. thread_detail::uintmax_atomic_t& this_thread_epoch=thread_detail::get_once_per_thread_epoch();
  150. if(epoch<this_thread_epoch)
  151. {
  152. pthread::pthread_mutex_scoped_lock lk(&thread_detail::once_epoch_mutex);
  153. while(flag.epoch<=being_initialized)
  154. {
  155. if(flag.epoch==uninitialized_flag)
  156. {
  157. flag.epoch=being_initialized;
  158. BOOST_TRY
  159. {
  160. pthread::pthread_mutex_scoped_unlock relocker(&thread_detail::once_epoch_mutex);
  161. f();
  162. }
  163. BOOST_CATCH (...)
  164. {
  165. flag.epoch=uninitialized_flag;
  166. BOOST_VERIFY(!posix::pthread_cond_broadcast(&thread_detail::once_epoch_cv));
  167. BOOST_RETHROW
  168. }
  169. BOOST_CATCH_END
  170. flag.epoch=--thread_detail::once_global_epoch;
  171. BOOST_VERIFY(!posix::pthread_cond_broadcast(&thread_detail::once_epoch_cv));
  172. }
  173. else
  174. {
  175. while(flag.epoch==being_initialized)
  176. {
  177. BOOST_VERIFY(!posix::pthread_cond_wait(&thread_detail::once_epoch_cv,&thread_detail::once_epoch_mutex));
  178. }
  179. }
  180. }
  181. this_thread_epoch=thread_detail::once_global_epoch;
  182. }
  183. }
  184. template<typename Function, typename T1>
  185. inline void call_once(once_flag& flag, Function f, T1 p1)
  186. {
  187. static thread_detail::uintmax_atomic_t const uninitialized_flag=BOOST_ONCE_INITIAL_FLAG_VALUE;
  188. static thread_detail::uintmax_atomic_t const being_initialized=uninitialized_flag+1;
  189. thread_detail::uintmax_atomic_t const epoch=flag.epoch;
  190. thread_detail::uintmax_atomic_t& this_thread_epoch=thread_detail::get_once_per_thread_epoch();
  191. if(epoch<this_thread_epoch)
  192. {
  193. pthread::pthread_mutex_scoped_lock lk(&thread_detail::once_epoch_mutex);
  194. while(flag.epoch<=being_initialized)
  195. {
  196. if(flag.epoch==uninitialized_flag)
  197. {
  198. flag.epoch=being_initialized;
  199. BOOST_TRY
  200. {
  201. pthread::pthread_mutex_scoped_unlock relocker(&thread_detail::once_epoch_mutex);
  202. BOOST_THREAD_INVOKE_RET_VOID(f,p1) BOOST_THREAD_INVOKE_RET_VOID_CALL;
  203. }
  204. BOOST_CATCH (...)
  205. {
  206. flag.epoch=uninitialized_flag;
  207. BOOST_VERIFY(!posix::pthread_cond_broadcast(&thread_detail::once_epoch_cv));
  208. BOOST_RETHROW
  209. }
  210. BOOST_CATCH_END
  211. flag.epoch=--thread_detail::once_global_epoch;
  212. BOOST_VERIFY(!posix::pthread_cond_broadcast(&thread_detail::once_epoch_cv));
  213. }
  214. else
  215. {
  216. while(flag.epoch==being_initialized)
  217. {
  218. BOOST_VERIFY(!posix::pthread_cond_wait(&thread_detail::once_epoch_cv,&thread_detail::once_epoch_mutex));
  219. }
  220. }
  221. }
  222. this_thread_epoch=thread_detail::once_global_epoch;
  223. }
  224. }
  225. template<typename Function, typename T1, typename T2>
  226. inline void call_once(once_flag& flag, Function f, T1 p1, T2 p2)
  227. {
  228. static thread_detail::uintmax_atomic_t const uninitialized_flag=BOOST_ONCE_INITIAL_FLAG_VALUE;
  229. static thread_detail::uintmax_atomic_t const being_initialized=uninitialized_flag+1;
  230. thread_detail::uintmax_atomic_t const epoch=flag.epoch;
  231. thread_detail::uintmax_atomic_t& this_thread_epoch=thread_detail::get_once_per_thread_epoch();
  232. if(epoch<this_thread_epoch)
  233. {
  234. pthread::pthread_mutex_scoped_lock lk(&thread_detail::once_epoch_mutex);
  235. while(flag.epoch<=being_initialized)
  236. {
  237. if(flag.epoch==uninitialized_flag)
  238. {
  239. flag.epoch=being_initialized;
  240. BOOST_TRY
  241. {
  242. pthread::pthread_mutex_scoped_unlock relocker(&thread_detail::once_epoch_mutex);
  243. BOOST_THREAD_INVOKE_RET_VOID(f,p1, p2) BOOST_THREAD_INVOKE_RET_VOID_CALL;
  244. }
  245. BOOST_CATCH (...)
  246. {
  247. flag.epoch=uninitialized_flag;
  248. BOOST_VERIFY(!posix::pthread_cond_broadcast(&thread_detail::once_epoch_cv));
  249. BOOST_RETHROW
  250. }
  251. BOOST_CATCH_END
  252. flag.epoch=--thread_detail::once_global_epoch;
  253. BOOST_VERIFY(!posix::pthread_cond_broadcast(&thread_detail::once_epoch_cv));
  254. }
  255. else
  256. {
  257. while(flag.epoch==being_initialized)
  258. {
  259. BOOST_VERIFY(!posix::pthread_cond_wait(&thread_detail::once_epoch_cv,&thread_detail::once_epoch_mutex));
  260. }
  261. }
  262. }
  263. this_thread_epoch=thread_detail::once_global_epoch;
  264. }
  265. }
  266. template<typename Function, typename T1, typename T2, typename T3>
  267. inline void call_once(once_flag& flag, Function f, T1 p1, T2 p2, T3 p3)
  268. {
  269. static thread_detail::uintmax_atomic_t const uninitialized_flag=BOOST_ONCE_INITIAL_FLAG_VALUE;
  270. static thread_detail::uintmax_atomic_t const being_initialized=uninitialized_flag+1;
  271. thread_detail::uintmax_atomic_t const epoch=flag.epoch;
  272. thread_detail::uintmax_atomic_t& this_thread_epoch=thread_detail::get_once_per_thread_epoch();
  273. if(epoch<this_thread_epoch)
  274. {
  275. pthread::pthread_mutex_scoped_lock lk(&thread_detail::once_epoch_mutex);
  276. while(flag.epoch<=being_initialized)
  277. {
  278. if(flag.epoch==uninitialized_flag)
  279. {
  280. flag.epoch=being_initialized;
  281. BOOST_TRY
  282. {
  283. pthread::pthread_mutex_scoped_unlock relocker(&thread_detail::once_epoch_mutex);
  284. BOOST_THREAD_INVOKE_RET_VOID(f,p1, p2, p3) BOOST_THREAD_INVOKE_RET_VOID_CALL;
  285. }
  286. BOOST_CATCH (...)
  287. {
  288. flag.epoch=uninitialized_flag;
  289. BOOST_VERIFY(!posix::pthread_cond_broadcast(&thread_detail::once_epoch_cv));
  290. BOOST_RETHROW
  291. }
  292. BOOST_CATCH_END
  293. flag.epoch=--thread_detail::once_global_epoch;
  294. BOOST_VERIFY(!posix::pthread_cond_broadcast(&thread_detail::once_epoch_cv));
  295. }
  296. else
  297. {
  298. while(flag.epoch==being_initialized)
  299. {
  300. BOOST_VERIFY(!posix::pthread_cond_wait(&thread_detail::once_epoch_cv,&thread_detail::once_epoch_mutex));
  301. }
  302. }
  303. }
  304. this_thread_epoch=thread_detail::once_global_epoch;
  305. }
  306. }
  307. template<typename Function>
  308. inline void call_once(once_flag& flag, BOOST_THREAD_RV_REF(Function) f)
  309. {
  310. static thread_detail::uintmax_atomic_t const uninitialized_flag=BOOST_ONCE_INITIAL_FLAG_VALUE;
  311. static thread_detail::uintmax_atomic_t const being_initialized=uninitialized_flag+1;
  312. thread_detail::uintmax_atomic_t const epoch=flag.epoch;
  313. thread_detail::uintmax_atomic_t& this_thread_epoch=thread_detail::get_once_per_thread_epoch();
  314. if(epoch<this_thread_epoch)
  315. {
  316. pthread::pthread_mutex_scoped_lock lk(&thread_detail::once_epoch_mutex);
  317. while(flag.epoch<=being_initialized)
  318. {
  319. if(flag.epoch==uninitialized_flag)
  320. {
  321. flag.epoch=being_initialized;
  322. BOOST_TRY
  323. {
  324. pthread::pthread_mutex_scoped_unlock relocker(&thread_detail::once_epoch_mutex);
  325. f();
  326. }
  327. BOOST_CATCH (...)
  328. {
  329. flag.epoch=uninitialized_flag;
  330. BOOST_VERIFY(!posix::pthread_cond_broadcast(&thread_detail::once_epoch_cv));
  331. BOOST_RETHROW
  332. }
  333. BOOST_CATCH_END
  334. flag.epoch=--thread_detail::once_global_epoch;
  335. BOOST_VERIFY(!posix::pthread_cond_broadcast(&thread_detail::once_epoch_cv));
  336. }
  337. else
  338. {
  339. while(flag.epoch==being_initialized)
  340. {
  341. BOOST_VERIFY(!posix::pthread_cond_wait(&thread_detail::once_epoch_cv,&thread_detail::once_epoch_mutex));
  342. }
  343. }
  344. }
  345. this_thread_epoch=thread_detail::once_global_epoch;
  346. }
  347. }
  348. template<typename Function, typename T1>
  349. inline void call_once(once_flag& flag, BOOST_THREAD_RV_REF(Function) f, BOOST_THREAD_RV_REF(T1) p1)
  350. {
  351. static thread_detail::uintmax_atomic_t const uninitialized_flag=BOOST_ONCE_INITIAL_FLAG_VALUE;
  352. static thread_detail::uintmax_atomic_t const being_initialized=uninitialized_flag+1;
  353. thread_detail::uintmax_atomic_t const epoch=flag.epoch;
  354. thread_detail::uintmax_atomic_t& this_thread_epoch=thread_detail::get_once_per_thread_epoch();
  355. if(epoch<this_thread_epoch)
  356. {
  357. pthread::pthread_mutex_scoped_lock lk(&thread_detail::once_epoch_mutex);
  358. while(flag.epoch<=being_initialized)
  359. {
  360. if(flag.epoch==uninitialized_flag)
  361. {
  362. flag.epoch=being_initialized;
  363. BOOST_TRY
  364. {
  365. pthread::pthread_mutex_scoped_unlock relocker(&thread_detail::once_epoch_mutex);
  366. BOOST_THREAD_INVOKE_RET_VOID(
  367. thread_detail::decay_copy(boost::forward<Function>(f)),
  368. thread_detail::decay_copy(boost::forward<T1>(p1))
  369. ) BOOST_THREAD_INVOKE_RET_VOID_CALL;
  370. }
  371. BOOST_CATCH (...)
  372. {
  373. flag.epoch=uninitialized_flag;
  374. BOOST_VERIFY(!posix::pthread_cond_broadcast(&thread_detail::once_epoch_cv));
  375. BOOST_RETHROW
  376. }
  377. BOOST_CATCH_END
  378. flag.epoch=--thread_detail::once_global_epoch;
  379. BOOST_VERIFY(!posix::pthread_cond_broadcast(&thread_detail::once_epoch_cv));
  380. }
  381. else
  382. {
  383. while(flag.epoch==being_initialized)
  384. {
  385. BOOST_VERIFY(!posix::pthread_cond_wait(&thread_detail::once_epoch_cv,&thread_detail::once_epoch_mutex));
  386. }
  387. }
  388. }
  389. this_thread_epoch=thread_detail::once_global_epoch;
  390. }
  391. }
  392. template<typename Function, typename T1, typename T2>
  393. inline void call_once(once_flag& flag, BOOST_THREAD_RV_REF(Function) f, BOOST_THREAD_RV_REF(T1) p1, BOOST_THREAD_RV_REF(T2) p2)
  394. {
  395. static thread_detail::uintmax_atomic_t const uninitialized_flag=BOOST_ONCE_INITIAL_FLAG_VALUE;
  396. static thread_detail::uintmax_atomic_t const being_initialized=uninitialized_flag+1;
  397. thread_detail::uintmax_atomic_t const epoch=flag.epoch;
  398. thread_detail::uintmax_atomic_t& this_thread_epoch=thread_detail::get_once_per_thread_epoch();
  399. if(epoch<this_thread_epoch)
  400. {
  401. pthread::pthread_mutex_scoped_lock lk(&thread_detail::once_epoch_mutex);
  402. while(flag.epoch<=being_initialized)
  403. {
  404. if(flag.epoch==uninitialized_flag)
  405. {
  406. flag.epoch=being_initialized;
  407. BOOST_TRY
  408. {
  409. pthread::pthread_mutex_scoped_unlock relocker(&thread_detail::once_epoch_mutex);
  410. BOOST_THREAD_INVOKE_RET_VOID(
  411. thread_detail::decay_copy(boost::forward<Function>(f)),
  412. thread_detail::decay_copy(boost::forward<T1>(p1)),
  413. thread_detail::decay_copy(boost::forward<T1>(p2))
  414. ) BOOST_THREAD_INVOKE_RET_VOID_CALL;
  415. }
  416. BOOST_CATCH (...)
  417. {
  418. flag.epoch=uninitialized_flag;
  419. BOOST_VERIFY(!posix::pthread_cond_broadcast(&thread_detail::once_epoch_cv));
  420. BOOST_RETHROW
  421. }
  422. BOOST_CATCH_END
  423. flag.epoch=--thread_detail::once_global_epoch;
  424. BOOST_VERIFY(!posix::pthread_cond_broadcast(&thread_detail::once_epoch_cv));
  425. }
  426. else
  427. {
  428. while(flag.epoch==being_initialized)
  429. {
  430. BOOST_VERIFY(!posix::pthread_cond_wait(&thread_detail::once_epoch_cv,&thread_detail::once_epoch_mutex));
  431. }
  432. }
  433. }
  434. this_thread_epoch=thread_detail::once_global_epoch;
  435. }
  436. }
  437. template<typename Function, typename T1, typename T2, typename T3>
  438. inline void call_once(once_flag& flag, BOOST_THREAD_RV_REF(Function) f, BOOST_THREAD_RV_REF(T1) p1, BOOST_THREAD_RV_REF(T2) p2, BOOST_THREAD_RV_REF(T3) p3)
  439. {
  440. static thread_detail::uintmax_atomic_t const uninitialized_flag=BOOST_ONCE_INITIAL_FLAG_VALUE;
  441. static thread_detail::uintmax_atomic_t const being_initialized=uninitialized_flag+1;
  442. thread_detail::uintmax_atomic_t const epoch=flag.epoch;
  443. thread_detail::uintmax_atomic_t& this_thread_epoch=thread_detail::get_once_per_thread_epoch();
  444. if(epoch<this_thread_epoch)
  445. {
  446. pthread::pthread_mutex_scoped_lock lk(&thread_detail::once_epoch_mutex);
  447. while(flag.epoch<=being_initialized)
  448. {
  449. if(flag.epoch==uninitialized_flag)
  450. {
  451. flag.epoch=being_initialized;
  452. BOOST_TRY
  453. {
  454. pthread::pthread_mutex_scoped_unlock relocker(&thread_detail::once_epoch_mutex);
  455. BOOST_THREAD_INVOKE_RET_VOID(
  456. thread_detail::decay_copy(boost::forward<Function>(f)),
  457. thread_detail::decay_copy(boost::forward<T1>(p1)),
  458. thread_detail::decay_copy(boost::forward<T1>(p2)),
  459. thread_detail::decay_copy(boost::forward<T1>(p3))
  460. ) BOOST_THREAD_INVOKE_RET_VOID_CALL;
  461. }
  462. BOOST_CATCH (...)
  463. {
  464. flag.epoch=uninitialized_flag;
  465. BOOST_VERIFY(!posix::pthread_cond_broadcast(&thread_detail::once_epoch_cv));
  466. BOOST_RETHROW
  467. }
  468. BOOST_CATCH_END
  469. flag.epoch=--thread_detail::once_global_epoch;
  470. BOOST_VERIFY(!posix::pthread_cond_broadcast(&thread_detail::once_epoch_cv));
  471. }
  472. else
  473. {
  474. while(flag.epoch==being_initialized)
  475. {
  476. BOOST_VERIFY(!posix::pthread_cond_wait(&thread_detail::once_epoch_cv,&thread_detail::once_epoch_mutex));
  477. }
  478. }
  479. }
  480. this_thread_epoch=thread_detail::once_global_epoch;
  481. }
  482. }
  483. #endif
  484. }
  485. #include <boost/config/abi_suffix.hpp>
  486. #endif