once.hpp 39 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090
  1. #ifndef BOOST_THREAD_WIN32_ONCE_HPP
  2. #define BOOST_THREAD_WIN32_ONCE_HPP
  3. // once.hpp
  4. //
  5. // (C) Copyright 2005-7 Anthony Williams
  6. // (C) Copyright 2005 John Maddock
  7. // (C) Copyright 2011-2013 Vicente J. Botet Escriba
  8. //
  9. // Distributed under the Boost Software License, Version 1.0. (See
  10. // accompanying file LICENSE_1_0.txt or copy at
  11. // http://www.boost.org/LICENSE_1_0.txt)
  12. #include <cstring>
  13. #include <cstddef>
  14. #include <boost/assert.hpp>
  15. #include <boost/static_assert.hpp>
  16. #include <boost/detail/interlocked.hpp>
  17. #include <boost/thread/win32/thread_primitives.hpp>
  18. #include <boost/thread/win32/interlocked_read.hpp>
  19. #include <boost/detail/no_exceptions_support.hpp>
  20. #include <boost/thread/detail/move.hpp>
  21. #include <boost/thread/detail/invoke.hpp>
  22. #include <boost/bind.hpp>
  23. #include <boost/config/abi_prefix.hpp>
  24. #ifdef BOOST_NO_STDC_NAMESPACE
  25. namespace std
  26. {
  27. using ::memcpy;
  28. using ::ptrdiff_t;
  29. }
  30. #endif
  31. namespace boost
  32. {
  33. struct once_flag;
  34. namespace detail
  35. {
  36. struct once_context;
  37. inline bool enter_once_region(once_flag& flag, once_context& ctx) BOOST_NOEXCEPT;
  38. inline void commit_once_region(once_flag& flag, once_context& ctx) BOOST_NOEXCEPT;
  39. inline void rollback_once_region(once_flag& flag, once_context& ctx) BOOST_NOEXCEPT;
  40. }
  41. #ifdef BOOST_THREAD_PROVIDES_ONCE_CXX11
  42. struct once_flag
  43. {
  44. BOOST_THREAD_NO_COPYABLE(once_flag)
  45. BOOST_CONSTEXPR once_flag() BOOST_NOEXCEPT
  46. : status(0), count(0)
  47. {}
  48. long status;
  49. long count;
  50. private:
  51. friend inline bool enter_once_region(once_flag& flag, detail::once_context& ctx) BOOST_NOEXCEPT;
  52. friend inline void commit_once_region(once_flag& flag, detail::once_context& ctx) BOOST_NOEXCEPT;
  53. friend inline void rollback_once_region(once_flag& flag, detail::once_context& ctx) BOOST_NOEXCEPT;
  54. };
  55. #define BOOST_ONCE_INIT once_flag()
  56. #else // BOOST_THREAD_PROVIDES_ONCE_CXX11
  57. struct once_flag
  58. {
  59. long status;
  60. long count;
  61. };
  62. #define BOOST_ONCE_INIT {0,0}
  63. #endif // BOOST_THREAD_PROVIDES_ONCE_CXX11
  64. #if defined BOOST_THREAD_PROVIDES_INVOKE
  65. #define BOOST_THREAD_INVOKE_RET_VOID detail::invoke
  66. #define BOOST_THREAD_INVOKE_RET_VOID_CALL
  67. #elif defined BOOST_THREAD_PROVIDES_INVOKE_RET
  68. #define BOOST_THREAD_INVOKE_RET_VOID detail::invoke<void>
  69. #define BOOST_THREAD_INVOKE_RET_VOID_CALL
  70. #else
  71. #define BOOST_THREAD_INVOKE_RET_VOID boost::bind
  72. #define BOOST_THREAD_INVOKE_RET_VOID_CALL ()
  73. #endif
  74. namespace detail
  75. {
  76. #ifdef BOOST_NO_ANSI_APIS
  77. typedef wchar_t once_char_type;
  78. #else
  79. typedef char once_char_type;
  80. #endif
  81. unsigned const once_mutex_name_fixed_length=54;
  82. unsigned const once_mutex_name_length=once_mutex_name_fixed_length+
  83. sizeof(void*)*2+sizeof(unsigned long)*2+1;
  84. template <class I>
  85. void int_to_string(I p, once_char_type* buf)
  86. {
  87. for(unsigned i=0; i < sizeof(I)*2; ++i,++buf)
  88. {
  89. #ifdef BOOST_NO_ANSI_APIS
  90. once_char_type const a=L'A';
  91. #else
  92. once_char_type const a='A';
  93. #endif
  94. *buf = a + static_cast<once_char_type>((p >> (i*4)) & 0x0f);
  95. }
  96. *buf = 0;
  97. }
  98. inline void name_once_mutex(once_char_type* mutex_name,void* flag_address)
  99. {
  100. #ifdef BOOST_NO_ANSI_APIS
  101. static const once_char_type fixed_mutex_name[]=L"Local\\{C15730E2-145C-4c5e-B005-3BC753F42475}-once-flag";
  102. #else
  103. static const once_char_type fixed_mutex_name[]="Local\\{C15730E2-145C-4c5e-B005-3BC753F42475}-once-flag";
  104. #endif
  105. BOOST_STATIC_ASSERT(sizeof(fixed_mutex_name) ==
  106. (sizeof(once_char_type)*(once_mutex_name_fixed_length+1)));
  107. std::memcpy(mutex_name,fixed_mutex_name,sizeof(fixed_mutex_name));
  108. detail::int_to_string(reinterpret_cast<std::ptrdiff_t>(flag_address),
  109. mutex_name + once_mutex_name_fixed_length);
  110. detail::int_to_string(win32::GetCurrentProcessId(),
  111. mutex_name + once_mutex_name_fixed_length + sizeof(void*)*2);
  112. }
  113. inline void* open_once_event(once_char_type* mutex_name,void* flag_address)
  114. {
  115. if(!*mutex_name)
  116. {
  117. name_once_mutex(mutex_name,flag_address);
  118. }
  119. #ifdef BOOST_NO_ANSI_APIS
  120. return ::boost::detail::win32::OpenEventW(
  121. #else
  122. return ::boost::detail::win32::OpenEventA(
  123. #endif
  124. ::boost::detail::win32::synchronize |
  125. ::boost::detail::win32::event_modify_state,
  126. false,
  127. mutex_name);
  128. }
  129. inline void* create_once_event(once_char_type* mutex_name,void* flag_address)
  130. {
  131. if(!*mutex_name)
  132. {
  133. name_once_mutex(mutex_name,flag_address);
  134. }
  135. #ifdef BOOST_NO_ANSI_APIS
  136. return ::boost::detail::win32::CreateEventW(
  137. #else
  138. return ::boost::detail::win32::CreateEventA(
  139. #endif
  140. 0,::boost::detail::win32::manual_reset_event,
  141. ::boost::detail::win32::event_initially_reset,
  142. mutex_name);
  143. }
  144. struct once_context {
  145. long const function_complete_flag_value;
  146. long const running_value;
  147. bool counted;
  148. detail::win32::handle_manager event_handle;
  149. detail::once_char_type mutex_name[once_mutex_name_length];
  150. once_context() :
  151. function_complete_flag_value(0xc15730e2),
  152. running_value(0x7f0725e3),
  153. counted(false)
  154. {
  155. mutex_name[0]=0;
  156. }
  157. };
  158. enum once_action {try_, break_, continue_};
  159. inline bool enter_once_region(once_flag& flag, once_context& ctx) BOOST_NOEXCEPT
  160. {
  161. long status=BOOST_INTERLOCKED_COMPARE_EXCHANGE(&flag.status,ctx.running_value,0);
  162. if(!status)
  163. {
  164. if(!ctx.event_handle)
  165. {
  166. ctx.event_handle=detail::open_once_event(ctx.mutex_name,&flag);
  167. }
  168. if(ctx.event_handle)
  169. {
  170. ::boost::detail::win32::ResetEvent(ctx.event_handle);
  171. }
  172. return true;
  173. }
  174. return false;
  175. }
  176. inline void commit_once_region(once_flag& flag, once_context& ctx) BOOST_NOEXCEPT
  177. {
  178. if(!ctx.counted)
  179. {
  180. BOOST_INTERLOCKED_INCREMENT(&flag.count);
  181. ctx.counted=true;
  182. }
  183. BOOST_INTERLOCKED_EXCHANGE(&flag.status,ctx.function_complete_flag_value);
  184. if(!ctx.event_handle &&
  185. (::boost::detail::interlocked_read_acquire(&flag.count)>1))
  186. {
  187. ctx.event_handle=detail::create_once_event(ctx.mutex_name,&flag);
  188. }
  189. if(ctx.event_handle)
  190. {
  191. ::boost::detail::win32::SetEvent(ctx.event_handle);
  192. }
  193. }
  194. inline void rollback_once_region(once_flag& flag, once_context& ctx) BOOST_NOEXCEPT
  195. {
  196. BOOST_INTERLOCKED_EXCHANGE(&flag.status,0);
  197. if(!ctx.event_handle)
  198. {
  199. ctx.event_handle=detail::open_once_event(ctx.mutex_name,&flag);
  200. }
  201. if(ctx.event_handle)
  202. {
  203. ::boost::detail::win32::SetEvent(ctx.event_handle);
  204. }
  205. }
  206. }
  207. #ifndef BOOST_NO_CXX11_VARIADIC_TEMPLATES
  208. //#if defined(BOOST_THREAD_RVALUE_REFERENCES_DONT_MATCH_FUNTION_PTR)
  209. inline void call_once(once_flag& flag, void (*f)())
  210. {
  211. // Try for a quick win: if the procedure has already been called
  212. // just skip through:
  213. detail::once_context ctx;
  214. while(::boost::detail::interlocked_read_acquire(&flag.status)
  215. !=ctx.function_complete_flag_value)
  216. {
  217. if(detail::enter_once_region(flag, ctx))
  218. {
  219. BOOST_TRY
  220. {
  221. f();
  222. }
  223. BOOST_CATCH(...)
  224. {
  225. detail::rollback_once_region(flag, ctx);
  226. BOOST_RETHROW
  227. }
  228. BOOST_CATCH_END
  229. detail::commit_once_region(flag, ctx);
  230. break;
  231. }
  232. if(!ctx.counted)
  233. {
  234. BOOST_INTERLOCKED_INCREMENT(&flag.count);
  235. ctx.counted=true;
  236. long status=::boost::detail::interlocked_read_acquire(&flag.status);
  237. if(status==ctx.function_complete_flag_value)
  238. {
  239. break;
  240. }
  241. if(!ctx.event_handle)
  242. {
  243. ctx.event_handle=detail::create_once_event(ctx.mutex_name,&flag);
  244. continue;
  245. }
  246. }
  247. BOOST_VERIFY(!::boost::detail::win32::WaitForSingleObject(
  248. ctx.event_handle,::boost::detail::win32::infinite));
  249. }
  250. }
  251. //#endif
  252. template<typename Function>
  253. inline void call_once(once_flag& flag, BOOST_THREAD_RV_REF(Function) f)
  254. {
  255. // Try for a quick win: if the procedure has already been called
  256. // just skip through:
  257. detail::once_context ctx;
  258. while(::boost::detail::interlocked_read_acquire(&flag.status)
  259. !=ctx.function_complete_flag_value)
  260. {
  261. if(detail::enter_once_region(flag, ctx))
  262. {
  263. BOOST_TRY
  264. {
  265. f();
  266. }
  267. BOOST_CATCH(...)
  268. {
  269. detail::rollback_once_region(flag, ctx);
  270. BOOST_RETHROW
  271. }
  272. BOOST_CATCH_END
  273. detail::commit_once_region(flag, ctx);
  274. break;
  275. }
  276. if(!ctx.counted)
  277. {
  278. BOOST_INTERLOCKED_INCREMENT(&flag.count);
  279. ctx.counted=true;
  280. long status=::boost::detail::interlocked_read_acquire(&flag.status);
  281. if(status==ctx.function_complete_flag_value)
  282. {
  283. break;
  284. }
  285. if(!ctx.event_handle)
  286. {
  287. ctx.event_handle=detail::create_once_event(ctx.mutex_name,&flag);
  288. continue;
  289. }
  290. }
  291. BOOST_VERIFY(!::boost::detail::win32::WaitForSingleObject(
  292. ctx.event_handle,::boost::detail::win32::infinite));
  293. }
  294. }
  295. template<typename Function, class A, class ...ArgTypes>
  296. inline void call_once(once_flag& flag, BOOST_THREAD_RV_REF(Function) f, BOOST_THREAD_RV_REF(A) a, BOOST_THREAD_RV_REF(ArgTypes)... args)
  297. {
  298. // Try for a quick win: if the procedure has already been called
  299. // just skip through:
  300. detail::once_context ctx;
  301. while(::boost::detail::interlocked_read_acquire(&flag.status)
  302. !=ctx.function_complete_flag_value)
  303. {
  304. if(detail::enter_once_region(flag, ctx))
  305. {
  306. BOOST_TRY
  307. {
  308. BOOST_THREAD_INVOKE_RET_VOID(
  309. thread_detail::decay_copy(boost::forward<Function>(f)),
  310. thread_detail::decay_copy(boost::forward<A>(a)),
  311. thread_detail::decay_copy(boost::forward<ArgTypes>(args))...
  312. ) BOOST_THREAD_INVOKE_RET_VOID_CALL;
  313. }
  314. BOOST_CATCH(...)
  315. {
  316. detail::rollback_once_region(flag, ctx);
  317. BOOST_RETHROW
  318. }
  319. BOOST_CATCH_END
  320. detail::commit_once_region(flag, ctx);
  321. break;
  322. }
  323. if(!ctx.counted)
  324. {
  325. BOOST_INTERLOCKED_INCREMENT(&flag.count);
  326. ctx.counted=true;
  327. long status=::boost::detail::interlocked_read_acquire(&flag.status);
  328. if(status==ctx.function_complete_flag_value)
  329. {
  330. break;
  331. }
  332. if(!ctx.event_handle)
  333. {
  334. ctx.event_handle=detail::create_once_event(ctx.mutex_name,&flag);
  335. continue;
  336. }
  337. }
  338. BOOST_VERIFY(!::boost::detail::win32::WaitForSingleObject(
  339. ctx.event_handle,::boost::detail::win32::infinite));
  340. }
  341. }
  342. #else
  343. #if ! defined(BOOST_MSVC) && ! defined(BOOST_INTEL)
  344. template<typename Function>
  345. void call_once(once_flag& flag,Function f)
  346. {
  347. // Try for a quick win: if the procedure has already been called
  348. // just skip through:
  349. detail::once_context ctx;
  350. while(::boost::detail::interlocked_read_acquire(&flag.status)
  351. !=ctx.function_complete_flag_value)
  352. {
  353. if(detail::enter_once_region(flag, ctx))
  354. {
  355. BOOST_TRY
  356. {
  357. f();
  358. }
  359. BOOST_CATCH(...)
  360. {
  361. detail::rollback_once_region(flag, ctx);
  362. BOOST_RETHROW
  363. }
  364. BOOST_CATCH_END
  365. detail::commit_once_region(flag, ctx);
  366. break;
  367. }
  368. if(!ctx.counted)
  369. {
  370. BOOST_INTERLOCKED_INCREMENT(&flag.count);
  371. ctx.counted=true;
  372. long status=::boost::detail::interlocked_read_acquire(&flag.status);
  373. if(status==ctx.function_complete_flag_value)
  374. {
  375. break;
  376. }
  377. if(!ctx.event_handle)
  378. {
  379. ctx.event_handle=detail::create_once_event(ctx.mutex_name,&flag);
  380. continue;
  381. }
  382. }
  383. BOOST_VERIFY(!::boost::detail::win32::WaitForSingleObject(
  384. ctx.event_handle,::boost::detail::win32::infinite));
  385. }
  386. }
  387. template<typename Function, typename T1>
  388. void call_once(once_flag& flag,Function f, T1 p1)
  389. {
  390. // Try for a quick win: if the procedure has already been called
  391. // just skip through:
  392. detail::once_context ctx;
  393. while(::boost::detail::interlocked_read_acquire(&flag.status)
  394. !=ctx.function_complete_flag_value)
  395. {
  396. if(detail::enter_once_region(flag, ctx))
  397. {
  398. BOOST_TRY
  399. {
  400. BOOST_THREAD_INVOKE_RET_VOID(f,p1) BOOST_THREAD_INVOKE_RET_VOID_CALL;
  401. }
  402. BOOST_CATCH(...)
  403. {
  404. detail::rollback_once_region(flag, ctx);
  405. BOOST_RETHROW
  406. }
  407. BOOST_CATCH_END
  408. detail::commit_once_region(flag, ctx);
  409. break;
  410. }
  411. if(!ctx.counted)
  412. {
  413. BOOST_INTERLOCKED_INCREMENT(&flag.count);
  414. ctx.counted=true;
  415. long status=::boost::detail::interlocked_read_acquire(&flag.status);
  416. if(status==ctx.function_complete_flag_value)
  417. {
  418. break;
  419. }
  420. if(!ctx.event_handle)
  421. {
  422. ctx.event_handle=detail::create_once_event(ctx.mutex_name,&flag);
  423. continue;
  424. }
  425. }
  426. BOOST_VERIFY(!::boost::detail::win32::WaitForSingleObject(
  427. ctx.event_handle,::boost::detail::win32::infinite));
  428. }
  429. }
  430. template<typename Function, typename T1, typename T2>
  431. void call_once(once_flag& flag,Function f, T1 p1, T2 p2)
  432. {
  433. // Try for a quick win: if the procedure has already been called
  434. // just skip through:
  435. detail::once_context ctx;
  436. while(::boost::detail::interlocked_read_acquire(&flag.status)
  437. !=ctx.function_complete_flag_value)
  438. {
  439. if(detail::enter_once_region(flag, ctx))
  440. {
  441. BOOST_TRY
  442. {
  443. BOOST_THREAD_INVOKE_RET_VOID(f,p1,p2) BOOST_THREAD_INVOKE_RET_VOID_CALL;
  444. }
  445. BOOST_CATCH(...)
  446. {
  447. detail::rollback_once_region(flag, ctx);
  448. BOOST_RETHROW
  449. }
  450. BOOST_CATCH_END
  451. detail::commit_once_region(flag, ctx);
  452. break;
  453. }
  454. if(!ctx.counted)
  455. {
  456. BOOST_INTERLOCKED_INCREMENT(&flag.count);
  457. ctx.counted=true;
  458. long status=::boost::detail::interlocked_read_acquire(&flag.status);
  459. if(status==ctx.function_complete_flag_value)
  460. {
  461. break;
  462. }
  463. if(!ctx.event_handle)
  464. {
  465. ctx.event_handle=detail::create_once_event(ctx.mutex_name,&flag);
  466. continue;
  467. }
  468. }
  469. BOOST_VERIFY(!::boost::detail::win32::WaitForSingleObject(
  470. ctx.event_handle,::boost::detail::win32::infinite));
  471. }
  472. }
  473. template<typename Function, typename T1, typename T2, typename T3>
  474. void call_once(once_flag& flag,Function f, T1 p1, T2 p2, T3 p3)
  475. {
  476. // Try for a quick win: if the procedure has already been called
  477. // just skip through:
  478. detail::once_context ctx;
  479. while(::boost::detail::interlocked_read_acquire(&flag.status)
  480. !=ctx.function_complete_flag_value)
  481. {
  482. if(detail::enter_once_region(flag, ctx))
  483. {
  484. BOOST_TRY
  485. {
  486. BOOST_THREAD_INVOKE_RET_VOID(f,p1,p2,p3) BOOST_THREAD_INVOKE_RET_VOID_CALL;
  487. }
  488. BOOST_CATCH(...)
  489. {
  490. detail::rollback_once_region(flag, ctx);
  491. BOOST_RETHROW
  492. }
  493. BOOST_CATCH_END
  494. detail::commit_once_region(flag, ctx);
  495. break;
  496. }
  497. if(!ctx.counted)
  498. {
  499. BOOST_INTERLOCKED_INCREMENT(&flag.count);
  500. ctx.counted=true;
  501. long status=::boost::detail::interlocked_read_acquire(&flag.status);
  502. if(status==ctx.function_complete_flag_value)
  503. {
  504. break;
  505. }
  506. if(!ctx.event_handle)
  507. {
  508. ctx.event_handle=detail::create_once_event(ctx.mutex_name,&flag);
  509. continue;
  510. }
  511. }
  512. BOOST_VERIFY(!::boost::detail::win32::WaitForSingleObject(
  513. ctx.event_handle,::boost::detail::win32::infinite));
  514. }
  515. }
  516. #elif defined BOOST_NO_CXX11_RVALUE_REFERENCES
  517. template<typename Function>
  518. void call_once(once_flag& flag,Function const&f)
  519. {
  520. // Try for a quick win: if the procedure has already been called
  521. // just skip through:
  522. detail::once_context ctx;
  523. while(::boost::detail::interlocked_read_acquire(&flag.status)
  524. !=ctx.function_complete_flag_value)
  525. {
  526. if(detail::enter_once_region(flag, ctx))
  527. {
  528. BOOST_TRY
  529. {
  530. f();
  531. }
  532. BOOST_CATCH(...)
  533. {
  534. detail::rollback_once_region(flag, ctx);
  535. BOOST_RETHROW
  536. }
  537. BOOST_CATCH_END
  538. detail::commit_once_region(flag, ctx);
  539. break;
  540. }
  541. if(!ctx.counted)
  542. {
  543. BOOST_INTERLOCKED_INCREMENT(&flag.count);
  544. ctx.counted=true;
  545. long status=::boost::detail::interlocked_read_acquire(&flag.status);
  546. if(status==ctx.function_complete_flag_value)
  547. {
  548. break;
  549. }
  550. if(!ctx.event_handle)
  551. {
  552. ctx.event_handle=detail::create_once_event(ctx.mutex_name,&flag);
  553. continue;
  554. }
  555. }
  556. BOOST_VERIFY(!::boost::detail::win32::WaitForSingleObject(
  557. ctx.event_handle,::boost::detail::win32::infinite));
  558. }
  559. }
  560. template<typename Function, typename T1>
  561. void call_once(once_flag& flag,Function const&f, T1 const&p1)
  562. {
  563. // Try for a quick win: if the procedure has already been called
  564. // just skip through:
  565. detail::once_context ctx;
  566. while(::boost::detail::interlocked_read_acquire(&flag.status)
  567. !=ctx.function_complete_flag_value)
  568. {
  569. if(detail::enter_once_region(flag, ctx))
  570. {
  571. BOOST_TRY
  572. {
  573. BOOST_THREAD_INVOKE_RET_VOID(f,p1) BOOST_THREAD_INVOKE_RET_VOID_CALL;
  574. }
  575. BOOST_CATCH(...)
  576. {
  577. detail::rollback_once_region(flag, ctx);
  578. BOOST_RETHROW
  579. }
  580. BOOST_CATCH_END
  581. detail::commit_once_region(flag, ctx);
  582. break;
  583. }
  584. if(!ctx.counted)
  585. {
  586. BOOST_INTERLOCKED_INCREMENT(&flag.count);
  587. ctx.counted=true;
  588. long status=::boost::detail::interlocked_read_acquire(&flag.status);
  589. if(status==ctx.function_complete_flag_value)
  590. {
  591. break;
  592. }
  593. if(!ctx.event_handle)
  594. {
  595. ctx.event_handle=detail::create_once_event(ctx.mutex_name,&flag);
  596. continue;
  597. }
  598. }
  599. BOOST_VERIFY(!::boost::detail::win32::WaitForSingleObject(
  600. ctx.event_handle,::boost::detail::win32::infinite));
  601. }
  602. }
  603. template<typename Function, typename T1, typename T2>
  604. void call_once(once_flag& flag,Function const&f, T1 const&p1, T2 const&p2)
  605. {
  606. // Try for a quick win: if the procedure has already been called
  607. // just skip through:
  608. detail::once_context ctx;
  609. while(::boost::detail::interlocked_read_acquire(&flag.status)
  610. !=ctx.function_complete_flag_value)
  611. {
  612. if(detail::enter_once_region(flag, ctx))
  613. {
  614. BOOST_TRY
  615. {
  616. BOOST_THREAD_INVOKE_RET_VOID(f,p1,p2) BOOST_THREAD_INVOKE_RET_VOID_CALL;
  617. }
  618. BOOST_CATCH(...)
  619. {
  620. detail::rollback_once_region(flag, ctx);
  621. BOOST_RETHROW
  622. }
  623. BOOST_CATCH_END
  624. detail::commit_once_region(flag, ctx);
  625. break;
  626. }
  627. if(!ctx.counted)
  628. {
  629. BOOST_INTERLOCKED_INCREMENT(&flag.count);
  630. ctx.counted=true;
  631. long status=::boost::detail::interlocked_read_acquire(&flag.status);
  632. if(status==ctx.function_complete_flag_value)
  633. {
  634. break;
  635. }
  636. if(!ctx.event_handle)
  637. {
  638. ctx.event_handle=detail::create_once_event(ctx.mutex_name,&flag);
  639. continue;
  640. }
  641. }
  642. BOOST_VERIFY(!::boost::detail::win32::WaitForSingleObject(
  643. ctx.event_handle,::boost::detail::win32::infinite));
  644. }
  645. }
  646. template<typename Function, typename T1, typename T2, typename T3>
  647. void call_once(once_flag& flag,Function const&f, T1 const&p1, T2 const&p2, T3 const&p3)
  648. {
  649. // Try for a quick win: if the procedure has already been called
  650. // just skip through:
  651. detail::once_context ctx;
  652. while(::boost::detail::interlocked_read_acquire(&flag.status)
  653. !=ctx.function_complete_flag_value)
  654. {
  655. if(detail::enter_once_region(flag, ctx))
  656. {
  657. BOOST_TRY
  658. {
  659. BOOST_THREAD_INVOKE_RET_VOID(f,p1,p2,p3) BOOST_THREAD_INVOKE_RET_VOID_CALL;
  660. }
  661. BOOST_CATCH(...)
  662. {
  663. detail::rollback_once_region(flag, ctx);
  664. BOOST_RETHROW
  665. }
  666. BOOST_CATCH_END
  667. detail::commit_once_region(flag, ctx);
  668. break;
  669. }
  670. if(!ctx.counted)
  671. {
  672. BOOST_INTERLOCKED_INCREMENT(&flag.count);
  673. ctx.counted=true;
  674. long status=::boost::detail::interlocked_read_acquire(&flag.status);
  675. if(status==ctx.function_complete_flag_value)
  676. {
  677. break;
  678. }
  679. if(!ctx.event_handle)
  680. {
  681. ctx.event_handle=detail::create_once_event(ctx.mutex_name,&flag);
  682. continue;
  683. }
  684. }
  685. BOOST_VERIFY(!::boost::detail::win32::WaitForSingleObject(
  686. ctx.event_handle,::boost::detail::win32::infinite));
  687. }
  688. }
  689. #endif
  690. #if 1
  691. #if defined(BOOST_THREAD_RVALUE_REFERENCES_DONT_MATCH_FUNTION_PTR)
  692. inline void call_once(once_flag& flag, void (*f)())
  693. {
  694. // Try for a quick win: if the procedure has already been called
  695. // just skip through:
  696. detail::once_context ctx;
  697. while(::boost::detail::interlocked_read_acquire(&flag.status)
  698. !=ctx.function_complete_flag_value)
  699. {
  700. if(detail::enter_once_region(flag, ctx))
  701. {
  702. BOOST_TRY
  703. {
  704. f();
  705. }
  706. BOOST_CATCH(...)
  707. {
  708. detail::rollback_once_region(flag, ctx);
  709. BOOST_RETHROW
  710. }
  711. BOOST_CATCH_END
  712. detail::commit_once_region(flag, ctx);
  713. break;
  714. }
  715. if(!ctx.counted)
  716. {
  717. BOOST_INTERLOCKED_INCREMENT(&flag.count);
  718. ctx.counted=true;
  719. long status=::boost::detail::interlocked_read_acquire(&flag.status);
  720. if(status==ctx.function_complete_flag_value)
  721. {
  722. break;
  723. }
  724. if(!ctx.event_handle)
  725. {
  726. ctx.event_handle=detail::create_once_event(ctx.mutex_name,&flag);
  727. continue;
  728. }
  729. }
  730. BOOST_VERIFY(!::boost::detail::win32::WaitForSingleObject(
  731. ctx.event_handle,::boost::detail::win32::infinite));
  732. }
  733. }
  734. template<typename T1>
  735. void call_once(once_flag& flag,void (*f)(BOOST_THREAD_RV_REF(T1)), BOOST_THREAD_RV_REF(T1) p1)
  736. {
  737. // Try for a quick win: if the procedure has already been called
  738. // just skip through:
  739. detail::once_context ctx;
  740. while(::boost::detail::interlocked_read_acquire(&flag.status)
  741. !=ctx.function_complete_flag_value)
  742. {
  743. if(detail::enter_once_region(flag, ctx))
  744. {
  745. BOOST_TRY
  746. {
  747. f(
  748. thread_detail::decay_copy(boost::forward<T1>(p1))
  749. );
  750. }
  751. BOOST_CATCH(...)
  752. {
  753. detail::rollback_once_region(flag, ctx);
  754. BOOST_RETHROW
  755. }
  756. BOOST_CATCH_END
  757. detail::commit_once_region(flag, ctx);
  758. break;
  759. }
  760. if(!ctx.counted)
  761. {
  762. BOOST_INTERLOCKED_INCREMENT(&flag.count);
  763. ctx.counted=true;
  764. long status=::boost::detail::interlocked_read_acquire(&flag.status);
  765. if(status==ctx.function_complete_flag_value)
  766. {
  767. break;
  768. }
  769. if(!ctx.event_handle)
  770. {
  771. ctx.event_handle=detail::create_once_event(ctx.mutex_name,&flag);
  772. continue;
  773. }
  774. }
  775. BOOST_VERIFY(!::boost::detail::win32::WaitForSingleObject(
  776. ctx.event_handle,::boost::detail::win32::infinite));
  777. }
  778. }
  779. template<typename Function, typename T1, typename T2>
  780. void call_once(once_flag& flag,void (*f)(BOOST_THREAD_RV_REF(T1),BOOST_THREAD_RV_REF(T2)), BOOST_THREAD_RV_REF(T1) p1, BOOST_THREAD_RV_REF(T2) p2)
  781. {
  782. // Try for a quick win: if the procedure has already been called
  783. // just skip through:
  784. detail::once_context ctx;
  785. while(::boost::detail::interlocked_read_acquire(&flag.status)
  786. !=ctx.function_complete_flag_value)
  787. {
  788. if(detail::enter_once_region(flag, ctx))
  789. {
  790. BOOST_TRY
  791. {
  792. f(
  793. thread_detail::decay_copy(boost::forward<T1>(p1)),
  794. thread_detail::decay_copy(boost::forward<T2>(p2))
  795. );
  796. }
  797. BOOST_CATCH(...)
  798. {
  799. detail::rollback_once_region(flag, ctx);
  800. BOOST_RETHROW
  801. }
  802. BOOST_CATCH_END
  803. detail::commit_once_region(flag, ctx);
  804. break;
  805. }
  806. if(!ctx.counted)
  807. {
  808. BOOST_INTERLOCKED_INCREMENT(&flag.count);
  809. ctx.counted=true;
  810. long status=::boost::detail::interlocked_read_acquire(&flag.status);
  811. if(status==ctx.function_complete_flag_value)
  812. {
  813. break;
  814. }
  815. if(!ctx.event_handle)
  816. {
  817. ctx.event_handle=detail::create_once_event(ctx.mutex_name,&flag);
  818. continue;
  819. }
  820. }
  821. BOOST_VERIFY(!::boost::detail::win32::WaitForSingleObject(
  822. ctx.event_handle,::boost::detail::win32::infinite));
  823. }
  824. }
  825. template<typename Function, typename T1, typename T2, typename T3>
  826. void call_once(once_flag& flag,void (*f)(BOOST_THREAD_RV_REF(T1),BOOST_THREAD_RV_REF(T2)), BOOST_THREAD_RV_REF(T1) p1, BOOST_THREAD_RV_REF(T2) p2, BOOST_THREAD_RV_REF(T3) p3)
  827. {
  828. // Try for a quick win: if the procedure has already been called
  829. // just skip through:
  830. detail::once_context ctx;
  831. while(::boost::detail::interlocked_read_acquire(&flag.status)
  832. !=ctx.function_complete_flag_value)
  833. {
  834. if(detail::enter_once_region(flag, ctx))
  835. {
  836. BOOST_TRY
  837. {
  838. f(
  839. thread_detail::decay_copy(boost::forward<T1>(p1)),
  840. thread_detail::decay_copy(boost::forward<T2>(p2)),
  841. thread_detail::decay_copy(boost::forward<T3>(p3))
  842. );
  843. }
  844. BOOST_CATCH(...)
  845. {
  846. detail::rollback_once_region(flag, ctx);
  847. BOOST_RETHROW
  848. }
  849. BOOST_CATCH_END
  850. detail::commit_once_region(flag, ctx);
  851. break;
  852. }
  853. if(!ctx.counted)
  854. {
  855. BOOST_INTERLOCKED_INCREMENT(&flag.count);
  856. ctx.counted=true;
  857. long status=::boost::detail::interlocked_read_acquire(&flag.status);
  858. if(status==ctx.function_complete_flag_value)
  859. {
  860. break;
  861. }
  862. if(!ctx.event_handle)
  863. {
  864. ctx.event_handle=detail::create_once_event(ctx.mutex_name,&flag);
  865. continue;
  866. }
  867. }
  868. BOOST_VERIFY(!::boost::detail::win32::WaitForSingleObject(
  869. ctx.event_handle,::boost::detail::win32::infinite));
  870. }
  871. }
  872. #endif
  873. template<typename Function>
  874. void call_once(once_flag& flag,BOOST_THREAD_RV_REF(Function) f)
  875. {
  876. // Try for a quick win: if the procedure has already been called
  877. // just skip through:
  878. detail::once_context ctx;
  879. while(::boost::detail::interlocked_read_acquire(&flag.status)
  880. !=ctx.function_complete_flag_value)
  881. {
  882. if(detail::enter_once_region(flag, ctx))
  883. {
  884. BOOST_TRY
  885. {
  886. f();
  887. }
  888. BOOST_CATCH(...)
  889. {
  890. detail::rollback_once_region(flag, ctx);
  891. BOOST_RETHROW
  892. }
  893. BOOST_CATCH_END
  894. detail::commit_once_region(flag, ctx);
  895. break;
  896. }
  897. if(!ctx.counted)
  898. {
  899. BOOST_INTERLOCKED_INCREMENT(&flag.count);
  900. ctx.counted=true;
  901. long status=::boost::detail::interlocked_read_acquire(&flag.status);
  902. if(status==ctx.function_complete_flag_value)
  903. {
  904. break;
  905. }
  906. if(!ctx.event_handle)
  907. {
  908. ctx.event_handle=detail::create_once_event(ctx.mutex_name,&flag);
  909. continue;
  910. }
  911. }
  912. BOOST_VERIFY(!::boost::detail::win32::WaitForSingleObject(
  913. ctx.event_handle,::boost::detail::win32::infinite));
  914. }
  915. }
  916. template<typename Function, typename T1>
  917. void call_once(once_flag& flag,BOOST_THREAD_RV_REF(Function) f, BOOST_THREAD_RV_REF(T1) p1)
  918. {
  919. // Try for a quick win: if the procedure has already been called
  920. // just skip through:
  921. detail::once_context ctx;
  922. while(::boost::detail::interlocked_read_acquire(&flag.status)
  923. !=ctx.function_complete_flag_value)
  924. {
  925. if(detail::enter_once_region(flag, ctx))
  926. {
  927. BOOST_TRY
  928. {
  929. BOOST_THREAD_INVOKE_RET_VOID(
  930. thread_detail::decay_copy(boost::forward<Function>(f)),
  931. thread_detail::decay_copy(boost::forward<T1>(p1))
  932. ) BOOST_THREAD_INVOKE_RET_VOID_CALL;
  933. }
  934. BOOST_CATCH(...)
  935. {
  936. detail::rollback_once_region(flag, ctx);
  937. BOOST_RETHROW
  938. }
  939. BOOST_CATCH_END
  940. detail::commit_once_region(flag, ctx);
  941. break;
  942. }
  943. if(!ctx.counted)
  944. {
  945. BOOST_INTERLOCKED_INCREMENT(&flag.count);
  946. ctx.counted=true;
  947. long status=::boost::detail::interlocked_read_acquire(&flag.status);
  948. if(status==ctx.function_complete_flag_value)
  949. {
  950. break;
  951. }
  952. if(!ctx.event_handle)
  953. {
  954. ctx.event_handle=detail::create_once_event(ctx.mutex_name,&flag);
  955. continue;
  956. }
  957. }
  958. BOOST_VERIFY(!::boost::detail::win32::WaitForSingleObject(
  959. ctx.event_handle,::boost::detail::win32::infinite));
  960. }
  961. }
  962. template<typename Function, typename T1, typename T2>
  963. void call_once(once_flag& flag,BOOST_THREAD_RV_REF(Function) f, BOOST_THREAD_RV_REF(T1) p1, BOOST_THREAD_RV_REF(T2) p2)
  964. {
  965. // Try for a quick win: if the procedure has already been called
  966. // just skip through:
  967. detail::once_context ctx;
  968. while(::boost::detail::interlocked_read_acquire(&flag.status)
  969. !=ctx.function_complete_flag_value)
  970. {
  971. if(detail::enter_once_region(flag, ctx))
  972. {
  973. BOOST_TRY
  974. {
  975. BOOST_THREAD_INVOKE_RET_VOID(
  976. thread_detail::decay_copy(boost::forward<Function>(f)),
  977. thread_detail::decay_copy(boost::forward<T1>(p1)),
  978. thread_detail::decay_copy(boost::forward<T2>(p2))
  979. ) BOOST_THREAD_INVOKE_RET_VOID_CALL;
  980. }
  981. BOOST_CATCH(...)
  982. {
  983. detail::rollback_once_region(flag, ctx);
  984. BOOST_RETHROW
  985. }
  986. BOOST_CATCH_END
  987. detail::commit_once_region(flag, ctx);
  988. break;
  989. }
  990. if(!ctx.counted)
  991. {
  992. BOOST_INTERLOCKED_INCREMENT(&flag.count);
  993. ctx.counted=true;
  994. long status=::boost::detail::interlocked_read_acquire(&flag.status);
  995. if(status==ctx.function_complete_flag_value)
  996. {
  997. break;
  998. }
  999. if(!ctx.event_handle)
  1000. {
  1001. ctx.event_handle=detail::create_once_event(ctx.mutex_name,&flag);
  1002. continue;
  1003. }
  1004. }
  1005. BOOST_VERIFY(!::boost::detail::win32::WaitForSingleObject(
  1006. ctx.event_handle,::boost::detail::win32::infinite));
  1007. }
  1008. }
  1009. template<typename Function, typename T1, typename T2, typename T3>
  1010. 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)
  1011. {
  1012. // Try for a quick win: if the procedure has already been called
  1013. // just skip through:
  1014. detail::once_context ctx;
  1015. while(::boost::detail::interlocked_read_acquire(&flag.status)
  1016. !=ctx.function_complete_flag_value)
  1017. {
  1018. if(detail::enter_once_region(flag, ctx))
  1019. {
  1020. BOOST_TRY
  1021. {
  1022. BOOST_THREAD_INVOKE_RET_VOID(
  1023. thread_detail::decay_copy(boost::forward<Function>(f)),
  1024. thread_detail::decay_copy(boost::forward<T1>(p1)),
  1025. thread_detail::decay_copy(boost::forward<T2>(p2)),
  1026. thread_detail::decay_copy(boost::forward<T3>(p3))
  1027. ) BOOST_THREAD_INVOKE_RET_VOID_CALL;
  1028. }
  1029. BOOST_CATCH(...)
  1030. {
  1031. detail::rollback_once_region(flag, ctx);
  1032. BOOST_RETHROW
  1033. }
  1034. BOOST_CATCH_END
  1035. detail::commit_once_region(flag, ctx);
  1036. break;
  1037. }
  1038. if(!ctx.counted)
  1039. {
  1040. BOOST_INTERLOCKED_INCREMENT(&flag.count);
  1041. ctx.counted=true;
  1042. long status=::boost::detail::interlocked_read_acquire(&flag.status);
  1043. if(status==ctx.function_complete_flag_value)
  1044. {
  1045. break;
  1046. }
  1047. if(!ctx.event_handle)
  1048. {
  1049. ctx.event_handle=detail::create_once_event(ctx.mutex_name,&flag);
  1050. continue;
  1051. }
  1052. }
  1053. BOOST_VERIFY(!::boost::detail::win32::WaitForSingleObject(
  1054. ctx.event_handle,::boost::detail::win32::infinite));
  1055. }
  1056. }
  1057. #endif
  1058. #endif
  1059. }
  1060. #include <boost/config/abi_suffix.hpp>
  1061. #endif