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