comparison DEPENDENCIES/generic/include/boost/thread/win32/once.hpp @ 16:2665513ce2d3

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