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