1 #ifndef BOOST_THREAD_WIN32_ONCE_HPP
2 #define BOOST_THREAD_WIN32_ONCE_HPP
6 // (C) Copyright 2005-7 Anthony Williams
7 // (C) Copyright 2005 John Maddock
8 // (C) Copyright 2011-2013 Vicente J. Botet Escriba
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)
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>
25 #include <boost/bind.hpp>
27 #include <boost/config/abi_prefix.hpp>
29 #ifdef BOOST_NO_STDC_NAMESPACE
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;
49 #ifdef BOOST_THREAD_PROVIDES_ONCE_CXX11
53 BOOST_THREAD_NO_COPYABLE(once_flag)
54 BOOST_CONSTEXPR once_flag() BOOST_NOEXCEPT
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;
65 #define BOOST_ONCE_INIT once_flag()
66 #else // BOOST_THREAD_PROVIDES_ONCE_CXX11
74 #define BOOST_ONCE_INIT {0,0}
75 #endif // BOOST_THREAD_PROVIDES_ONCE_CXX11
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
84 #define BOOST_THREAD_INVOKE_RET_VOID boost::bind
85 #define BOOST_THREAD_INVOKE_RET_VOID_CALL ()
90 #ifdef BOOST_NO_ANSI_APIS
91 typedef wchar_t once_char_type;
93 typedef char once_char_type;
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;
100 void int_to_string(I p, once_char_type* buf)
102 for(unsigned i=0; i < sizeof(I)*2; ++i,++buf)
104 #ifdef BOOST_NO_ANSI_APIS
105 once_char_type const a=L'A';
107 once_char_type const a='A';
109 *buf = a + static_cast<once_char_type>((p >> (i*4)) & 0x0f);
114 inline void name_once_mutex(once_char_type* mutex_name,void* flag_address)
116 #ifdef BOOST_NO_ANSI_APIS
117 static const once_char_type fixed_mutex_name[]=L"Local\\{C15730E2-145C-4c5e-B005-3BC753F42475}-once-flag";
119 static const once_char_type fixed_mutex_name[]="Local\\{C15730E2-145C-4c5e-B005-3BC753F42475}-once-flag";
121 BOOST_STATIC_ASSERT(sizeof(fixed_mutex_name) ==
122 (sizeof(once_char_type)*(once_mutex_name_fixed_length+1)));
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(win32::GetCurrentProcessId(),
128 mutex_name + once_mutex_name_fixed_length + sizeof(void*)*2);
131 inline void* open_once_event(once_char_type* mutex_name,void* flag_address)
135 name_once_mutex(mutex_name,flag_address);
138 #ifdef BOOST_NO_ANSI_APIS
139 return ::boost::detail::win32::OpenEventW(
141 return ::boost::detail::win32::OpenEventA(
143 ::boost::detail::win32::synchronize |
144 ::boost::detail::win32::event_modify_state,
149 inline void* create_once_event(once_char_type* mutex_name,void* flag_address)
153 name_once_mutex(mutex_name,flag_address);
156 return ::boost::detail::win32::create_event(
158 ::boost::detail::win32::manual_reset_event,
159 ::boost::detail::win32::event_initially_reset);
162 struct once_context {
163 long const function_complete_flag_value;
164 long const running_value;
166 detail::win32::handle_manager event_handle;
167 detail::once_char_type mutex_name[once_mutex_name_length];
169 function_complete_flag_value(0xc15730e2),
170 running_value(0x7f0725e3),
176 enum once_action {try_, break_, continue_};
178 inline bool enter_once_region(once_flag& flag, once_context& ctx) BOOST_NOEXCEPT
180 long status=BOOST_INTERLOCKED_COMPARE_EXCHANGE(&flag.status,ctx.running_value,0);
183 if(!ctx.event_handle)
185 ctx.event_handle=detail::open_once_event(ctx.mutex_name,&flag);
189 ::boost::detail::win32::ResetEvent(ctx.event_handle);
195 inline void commit_once_region(once_flag& flag, once_context& ctx) BOOST_NOEXCEPT
199 BOOST_INTERLOCKED_INCREMENT(&flag.count);
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))
206 ctx.event_handle=detail::create_once_event(ctx.mutex_name,&flag);
210 ::boost::detail::win32::SetEvent(ctx.event_handle);
213 inline void rollback_once_region(once_flag& flag, once_context& ctx) BOOST_NOEXCEPT
215 BOOST_INTERLOCKED_EXCHANGE(&flag.status,0);
216 if(!ctx.event_handle)
218 ctx.event_handle=detail::open_once_event(ctx.mutex_name,&flag);
222 ::boost::detail::win32::SetEvent(ctx.event_handle);
227 #if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) && !defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
228 //#if defined(BOOST_THREAD_RVALUE_REFERENCES_DONT_MATCH_FUNTION_PTR)
229 inline void call_once(once_flag& flag, void (*f)())
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)
237 if(detail::enter_once_region(flag, ctx))
245 detail::rollback_once_region(flag, ctx);
249 detail::commit_once_region(flag, ctx);
254 BOOST_INTERLOCKED_INCREMENT(&flag.count);
256 long status=::boost::detail::interlocked_read_acquire(&flag.status);
257 if(status==ctx.function_complete_flag_value)
261 if(!ctx.event_handle)
263 ctx.event_handle=detail::create_once_event(ctx.mutex_name,&flag);
267 BOOST_VERIFY(!::boost::detail::win32::WaitForSingleObjectEx(
268 ctx.event_handle,::boost::detail::win32::infinite, 0));
272 template<typename Function>
273 inline void call_once(once_flag& flag, BOOST_THREAD_RV_REF(Function) f)
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)
281 if(detail::enter_once_region(flag, ctx))
289 detail::rollback_once_region(flag, ctx);
293 detail::commit_once_region(flag, ctx);
298 BOOST_INTERLOCKED_INCREMENT(&flag.count);
300 long status=::boost::detail::interlocked_read_acquire(&flag.status);
301 if(status==ctx.function_complete_flag_value)
305 if(!ctx.event_handle)
307 ctx.event_handle=detail::create_once_event(ctx.mutex_name,&flag);
311 BOOST_VERIFY(!::boost::detail::win32::WaitForSingleObjectEx(
312 ctx.event_handle,::boost::detail::win32::infinite,0));
315 template<typename Function, class A, class ...ArgTypes>
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)
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)
324 if(detail::enter_once_region(flag, ctx))
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;
336 detail::rollback_once_region(flag, ctx);
340 detail::commit_once_region(flag, ctx);
345 BOOST_INTERLOCKED_INCREMENT(&flag.count);
347 long status=::boost::detail::interlocked_read_acquire(&flag.status);
348 if(status==ctx.function_complete_flag_value)
352 if(!ctx.event_handle)
354 ctx.event_handle=detail::create_once_event(ctx.mutex_name,&flag);
358 BOOST_VERIFY(!::boost::detail::win32::WaitForSingleObjectEx(
359 ctx.event_handle,::boost::detail::win32::infinite,0));
363 #if ! defined(BOOST_MSVC) && ! defined(BOOST_INTEL)
364 template<typename Function>
365 void call_once(once_flag& flag,Function f)
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)
373 if(detail::enter_once_region(flag, ctx))
381 detail::rollback_once_region(flag, ctx);
385 detail::commit_once_region(flag, ctx);
390 BOOST_INTERLOCKED_INCREMENT(&flag.count);
392 long status=::boost::detail::interlocked_read_acquire(&flag.status);
393 if(status==ctx.function_complete_flag_value)
397 if(!ctx.event_handle)
399 ctx.event_handle=detail::create_once_event(ctx.mutex_name,&flag);
403 BOOST_VERIFY(!::boost::detail::win32::WaitForSingleObjectEx(
404 ctx.event_handle,::boost::detail::win32::infinite,0));
407 template<typename Function, typename T1>
408 void call_once(once_flag& flag,Function f, T1 p1)
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)
416 if(detail::enter_once_region(flag, ctx))
420 BOOST_THREAD_INVOKE_RET_VOID(f,p1) BOOST_THREAD_INVOKE_RET_VOID_CALL;
424 detail::rollback_once_region(flag, ctx);
428 detail::commit_once_region(flag, ctx);
433 BOOST_INTERLOCKED_INCREMENT(&flag.count);
435 long status=::boost::detail::interlocked_read_acquire(&flag.status);
436 if(status==ctx.function_complete_flag_value)
440 if(!ctx.event_handle)
442 ctx.event_handle=detail::create_once_event(ctx.mutex_name,&flag);
446 BOOST_VERIFY(!::boost::detail::win32::WaitForSingleObjectEx(
447 ctx.event_handle,::boost::detail::win32::infinite,0));
450 template<typename Function, typename T1, typename T2>
451 void call_once(once_flag& flag,Function f, T1 p1, T2 p2)
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)
459 if(detail::enter_once_region(flag, ctx))
463 BOOST_THREAD_INVOKE_RET_VOID(f,p1,p2) BOOST_THREAD_INVOKE_RET_VOID_CALL;
467 detail::rollback_once_region(flag, ctx);
471 detail::commit_once_region(flag, ctx);
476 BOOST_INTERLOCKED_INCREMENT(&flag.count);
478 long status=::boost::detail::interlocked_read_acquire(&flag.status);
479 if(status==ctx.function_complete_flag_value)
483 if(!ctx.event_handle)
485 ctx.event_handle=detail::create_once_event(ctx.mutex_name,&flag);
489 BOOST_VERIFY(!::boost::detail::win32::WaitForSingleObjectEx(
490 ctx.event_handle,::boost::detail::win32::infinite,0));
493 template<typename Function, typename T1, typename T2, typename T3>
494 void call_once(once_flag& flag,Function f, T1 p1, T2 p2, T3 p3)
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)
502 if(detail::enter_once_region(flag, ctx))
506 BOOST_THREAD_INVOKE_RET_VOID(f,p1,p2,p3) BOOST_THREAD_INVOKE_RET_VOID_CALL;
510 detail::rollback_once_region(flag, ctx);
514 detail::commit_once_region(flag, ctx);
519 BOOST_INTERLOCKED_INCREMENT(&flag.count);
521 long status=::boost::detail::interlocked_read_acquire(&flag.status);
522 if(status==ctx.function_complete_flag_value)
526 if(!ctx.event_handle)
528 ctx.event_handle=detail::create_once_event(ctx.mutex_name,&flag);
532 BOOST_VERIFY(!::boost::detail::win32::WaitForSingleObjectEx(
533 ctx.event_handle,::boost::detail::win32::infinite,0));
536 #elif defined BOOST_NO_CXX11_RVALUE_REFERENCES
538 template<typename Function>
539 void call_once(once_flag& flag,Function const&f)
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)
547 if(detail::enter_once_region(flag, ctx))
555 detail::rollback_once_region(flag, ctx);
559 detail::commit_once_region(flag, ctx);
564 BOOST_INTERLOCKED_INCREMENT(&flag.count);
566 long status=::boost::detail::interlocked_read_acquire(&flag.status);
567 if(status==ctx.function_complete_flag_value)
571 if(!ctx.event_handle)
573 ctx.event_handle=detail::create_once_event(ctx.mutex_name,&flag);
577 BOOST_VERIFY(!::boost::detail::win32::WaitForSingleObjectEx(
578 ctx.event_handle,::boost::detail::win32::infinite,0));
581 template<typename Function, typename T1>
582 void call_once(once_flag& flag,Function const&f, T1 const&p1)
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)
590 if(detail::enter_once_region(flag, ctx))
594 BOOST_THREAD_INVOKE_RET_VOID(f,p1) BOOST_THREAD_INVOKE_RET_VOID_CALL;
598 detail::rollback_once_region(flag, ctx);
602 detail::commit_once_region(flag, ctx);
607 BOOST_INTERLOCKED_INCREMENT(&flag.count);
609 long status=::boost::detail::interlocked_read_acquire(&flag.status);
610 if(status==ctx.function_complete_flag_value)
614 if(!ctx.event_handle)
616 ctx.event_handle=detail::create_once_event(ctx.mutex_name,&flag);
620 BOOST_VERIFY(!::boost::detail::win32::WaitForSingleObjectEx(
621 ctx.event_handle,::boost::detail::win32::infinite,0));
624 template<typename Function, typename T1, typename T2>
625 void call_once(once_flag& flag,Function const&f, T1 const&p1, T2 const&p2)
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)
633 if(detail::enter_once_region(flag, ctx))
637 BOOST_THREAD_INVOKE_RET_VOID(f,p1,p2) BOOST_THREAD_INVOKE_RET_VOID_CALL;
641 detail::rollback_once_region(flag, ctx);
645 detail::commit_once_region(flag, ctx);
650 BOOST_INTERLOCKED_INCREMENT(&flag.count);
652 long status=::boost::detail::interlocked_read_acquire(&flag.status);
653 if(status==ctx.function_complete_flag_value)
657 if(!ctx.event_handle)
659 ctx.event_handle=detail::create_once_event(ctx.mutex_name,&flag);
663 BOOST_VERIFY(!::boost::detail::win32::WaitForSingleObjectEx(
664 ctx.event_handle,::boost::detail::win32::infinite,0));
667 template<typename Function, typename T1, typename T2, typename T3>
668 void call_once(once_flag& flag,Function const&f, T1 const&p1, T2 const&p2, T3 const&p3)
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)
676 if(detail::enter_once_region(flag, ctx))
680 BOOST_THREAD_INVOKE_RET_VOID(f,p1,p2,p3) BOOST_THREAD_INVOKE_RET_VOID_CALL;
684 detail::rollback_once_region(flag, ctx);
688 detail::commit_once_region(flag, ctx);
693 BOOST_INTERLOCKED_INCREMENT(&flag.count);
695 long status=::boost::detail::interlocked_read_acquire(&flag.status);
696 if(status==ctx.function_complete_flag_value)
700 if(!ctx.event_handle)
702 ctx.event_handle=detail::create_once_event(ctx.mutex_name,&flag);
706 BOOST_VERIFY(!::boost::detail::win32::WaitForSingleObjectEx(
707 ctx.event_handle,::boost::detail::win32::infinite,0));
712 #if defined(BOOST_THREAD_RVALUE_REFERENCES_DONT_MATCH_FUNTION_PTR)
713 inline void call_once(once_flag& flag, void (*f)())
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)
721 if(detail::enter_once_region(flag, ctx))
729 detail::rollback_once_region(flag, ctx);
733 detail::commit_once_region(flag, ctx);
738 BOOST_INTERLOCKED_INCREMENT(&flag.count);
740 long status=::boost::detail::interlocked_read_acquire(&flag.status);
741 if(status==ctx.function_complete_flag_value)
745 if(!ctx.event_handle)
747 ctx.event_handle=detail::create_once_event(ctx.mutex_name,&flag);
751 BOOST_VERIFY(!::boost::detail::win32::WaitForSingleObjectEx(
752 ctx.event_handle,::boost::detail::win32::infinite,0));
755 template<typename T1>
756 void call_once(once_flag& flag,void (*f)(BOOST_THREAD_RV_REF(T1)), BOOST_THREAD_RV_REF(T1) p1)
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)
764 if(detail::enter_once_region(flag, ctx))
769 thread_detail::decay_copy(boost::forward<T1>(p1))
774 detail::rollback_once_region(flag, ctx);
778 detail::commit_once_region(flag, ctx);
783 BOOST_INTERLOCKED_INCREMENT(&flag.count);
785 long status=::boost::detail::interlocked_read_acquire(&flag.status);
786 if(status==ctx.function_complete_flag_value)
790 if(!ctx.event_handle)
792 ctx.event_handle=detail::create_once_event(ctx.mutex_name,&flag);
796 BOOST_VERIFY(!::boost::detail::win32::WaitForSingleObjectEx(
797 ctx.event_handle,::boost::detail::win32::infinite,0));
800 template<typename Function, typename T1, typename T2>
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)
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)
809 if(detail::enter_once_region(flag, ctx))
814 thread_detail::decay_copy(boost::forward<T1>(p1)),
815 thread_detail::decay_copy(boost::forward<T2>(p2))
820 detail::rollback_once_region(flag, ctx);
824 detail::commit_once_region(flag, ctx);
829 BOOST_INTERLOCKED_INCREMENT(&flag.count);
831 long status=::boost::detail::interlocked_read_acquire(&flag.status);
832 if(status==ctx.function_complete_flag_value)
836 if(!ctx.event_handle)
838 ctx.event_handle=detail::create_once_event(ctx.mutex_name,&flag);
842 BOOST_VERIFY(!::boost::detail::win32::WaitForSingleObjectEx(
843 ctx.event_handle,::boost::detail::win32::infinite,0));
846 template<typename Function, typename T1, typename T2, typename T3>
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)
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)
855 if(detail::enter_once_region(flag, ctx))
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))
867 detail::rollback_once_region(flag, ctx);
871 detail::commit_once_region(flag, ctx);
876 BOOST_INTERLOCKED_INCREMENT(&flag.count);
878 long status=::boost::detail::interlocked_read_acquire(&flag.status);
879 if(status==ctx.function_complete_flag_value)
883 if(!ctx.event_handle)
885 ctx.event_handle=detail::create_once_event(ctx.mutex_name,&flag);
889 BOOST_VERIFY(!::boost::detail::win32::WaitForSingleObjectEx(
890 ctx.event_handle,::boost::detail::win32::infinite,0));
894 template<typename Function>
895 void call_once(once_flag& flag,BOOST_THREAD_RV_REF(Function) f)
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)
903 if(detail::enter_once_region(flag, ctx))
911 detail::rollback_once_region(flag, ctx);
915 detail::commit_once_region(flag, ctx);
920 BOOST_INTERLOCKED_INCREMENT(&flag.count);
922 long status=::boost::detail::interlocked_read_acquire(&flag.status);
923 if(status==ctx.function_complete_flag_value)
927 if(!ctx.event_handle)
929 ctx.event_handle=detail::create_once_event(ctx.mutex_name,&flag);
933 BOOST_VERIFY(!::boost::detail::win32::WaitForSingleObjectEx(
934 ctx.event_handle,::boost::detail::win32::infinite,0));
938 template<typename Function, typename T1>
939 void call_once(once_flag& flag,BOOST_THREAD_RV_REF(Function) f, BOOST_THREAD_RV_REF(T1) p1)
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)
947 if(detail::enter_once_region(flag, ctx))
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;
958 detail::rollback_once_region(flag, ctx);
962 detail::commit_once_region(flag, ctx);
967 BOOST_INTERLOCKED_INCREMENT(&flag.count);
969 long status=::boost::detail::interlocked_read_acquire(&flag.status);
970 if(status==ctx.function_complete_flag_value)
974 if(!ctx.event_handle)
976 ctx.event_handle=detail::create_once_event(ctx.mutex_name,&flag);
980 BOOST_VERIFY(!::boost::detail::win32::WaitForSingleObjectEx(
981 ctx.event_handle,::boost::detail::win32::infinite,0));
984 template<typename Function, typename T1, typename T2>
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)
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)
993 if(detail::enter_once_region(flag, ctx))
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;
1005 detail::rollback_once_region(flag, ctx);
1009 detail::commit_once_region(flag, ctx);
1014 BOOST_INTERLOCKED_INCREMENT(&flag.count);
1016 long status=::boost::detail::interlocked_read_acquire(&flag.status);
1017 if(status==ctx.function_complete_flag_value)
1021 if(!ctx.event_handle)
1023 ctx.event_handle=detail::create_once_event(ctx.mutex_name,&flag);
1027 BOOST_VERIFY(!::boost::detail::win32::WaitForSingleObjectEx(
1028 ctx.event_handle,::boost::detail::win32::infinite,0));
1031 template<typename Function, typename T1, typename T2, typename T3>
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)
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)
1040 if(detail::enter_once_region(flag, ctx))
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;
1054 detail::rollback_once_region(flag, ctx);
1058 detail::commit_once_region(flag, ctx);
1063 BOOST_INTERLOCKED_INCREMENT(&flag.count);
1065 long status=::boost::detail::interlocked_read_acquire(&flag.status);
1066 if(status==ctx.function_complete_flag_value)
1070 if(!ctx.event_handle)
1072 ctx.event_handle=detail::create_once_event(ctx.mutex_name,&flag);
1076 BOOST_VERIFY(!::boost::detail::win32::WaitForSingleObjectEx(
1077 ctx.event_handle,::boost::detail::win32::infinite,0));
1085 #include <boost/config/abi_suffix.hpp>