1 // Distributed under the Boost Software License, Version 1.0. (See
2 // accompanying file LICENSE_1_0.txt or copy at
3 // http://www.boost.org/LICENSE_1_0.txt)
4 // (C) Copyright 2007 Anthony Williams
5 // (C) Copyright 2007 David Deakins
6 // (C) Copyright 2011-2018 Vicente J. Botet Escriba
8 //#define BOOST_THREAD_VERSION 3
10 #include <boost/winapi/config.hpp>
11 #include <boost/thread/thread_only.hpp>
12 #include <boost/thread/once.hpp>
13 #include <boost/thread/tss.hpp>
14 #include <boost/thread/condition_variable.hpp>
15 #include <boost/thread/detail/tss_hooks.hpp>
16 #include <boost/thread/future.hpp>
17 #include <boost/assert.hpp>
18 #include <boost/cstdint.hpp>
19 #if defined BOOST_THREAD_USES_DATETIME
20 #include <boost/date_time/posix_time/conversion.hpp>
21 #include <boost/thread/thread_time.hpp>
23 #include <boost/thread/csbl/memory/unique_ptr.hpp>
31 #include <boost/predef/platform.h>
33 #if BOOST_PLAT_WINDOWS_RUNTIME
36 #include <Activation.h>
37 #include <wrl\client.h>
38 #include <wrl\event.h>
39 #include <wrl\wrappers\corewrappers.h>
41 #include <windows.system.threading.h>
42 #pragma comment(lib, "runtimeobject.lib")
49 thread_data_base::~thread_data_base()
51 for (notify_list_t::iterator i
= notify
.begin(), e
= notify
.end();
55 i
->first
->notify_all();
57 //#ifndef BOOST_NO_EXCEPTIONS
58 for (async_states_t::iterator i
= async_states_
.begin(), e
= async_states_
.end();
61 (*i
)->notify_deferred();
69 #ifdef BOOST_THREAD_PROVIDES_ONCE_CXX11
70 boost::once_flag current_thread_tls_init_flag
;
72 boost::once_flag current_thread_tls_init_flag
=BOOST_ONCE_INIT
;
75 // Windows CE does not define the TLS_OUT_OF_INDEXES constant.
76 #define TLS_OUT_OF_INDEXES 0xFFFFFFFF
78 #if !BOOST_PLAT_WINDOWS_RUNTIME
79 DWORD current_thread_tls_key
=TLS_OUT_OF_INDEXES
;
81 __declspec(thread
) boost::detail::thread_data_base
* current_thread_data_base
;
84 void create_current_thread_tls_key()
86 tss_cleanup_implemented(); // if anyone uses TSS, we need the cleanup linked in
87 #if !BOOST_PLAT_WINDOWS_RUNTIME
88 current_thread_tls_key
=TlsAlloc();
89 BOOST_ASSERT(current_thread_tls_key
!=TLS_OUT_OF_INDEXES
);
93 void cleanup_tls_key()
95 #if !BOOST_PLAT_WINDOWS_RUNTIME
96 if(current_thread_tls_key
!=TLS_OUT_OF_INDEXES
)
98 TlsFree(current_thread_tls_key
);
99 current_thread_tls_key
=TLS_OUT_OF_INDEXES
;
104 void set_current_thread_data(detail::thread_data_base
* new_data
)
106 boost::call_once(current_thread_tls_init_flag
,create_current_thread_tls_key
);
107 #if BOOST_PLAT_WINDOWS_RUNTIME
108 current_thread_data_base
= new_data
;
110 if (current_thread_tls_key
!= TLS_OUT_OF_INDEXES
)
112 BOOST_VERIFY(TlsSetValue(current_thread_tls_key
, new_data
));
117 //boost::throw_exception(thread_resource_error());
125 thread_data_base
* get_current_thread_data()
127 #if BOOST_PLAT_WINDOWS_RUNTIME
128 return current_thread_data_base
;
130 if (current_thread_tls_key
== TLS_OUT_OF_INDEXES
)
134 return (detail::thread_data_base
*)TlsGetValue(current_thread_tls_key
);
141 #ifndef BOOST_HAS_THREADEX
142 // Windows CE doesn't define _beginthreadex
144 struct ThreadProxyData
146 typedef unsigned (__stdcall
* func
)(void*);
149 ThreadProxyData(func start_address
,void* arglist
) : start_address_(start_address
), arglist_(arglist
) {}
152 DWORD WINAPI
ThreadProxy(LPVOID args
)
154 boost::csbl::unique_ptr
<ThreadProxyData
> data(reinterpret_cast<ThreadProxyData
*>(args
));
155 DWORD ret
=data
->start_address_(data
->arglist_
);
159 inline uintptr_t _beginthreadex(void* security
, unsigned stack_size
, unsigned (__stdcall
* start_address
)(void*),
160 void* arglist
, unsigned initflag
, unsigned* thrdaddr
)
163 ThreadProxyData
* data
= new ThreadProxyData(start_address
,arglist
);
164 HANDLE hthread
=CreateThread(static_cast<LPSECURITY_ATTRIBUTES
>(security
),stack_size
,ThreadProxy
,
165 data
,initflag
,&threadID
);
171 return reinterpret_cast<uintptr_t const>(hthread
);
180 struct thread_exit_callback_node
182 boost::detail::thread_exit_function_base
* func
;
183 thread_exit_callback_node
* next
;
185 thread_exit_callback_node(boost::detail::thread_exit_function_base
* func_
,
186 thread_exit_callback_node
* next_
):
187 func(func_
),next(next_
)
193 #if BOOST_PLAT_WINDOWS_RUNTIME
196 std::atomic_uint threadCount
;
198 bool win32::scoped_winrt_thread::start(thread_func address
, void *parameter
, unsigned int *thrdId
)
200 Microsoft::WRL::ComPtr
<ABI::Windows::System::Threading::IThreadPoolStatics
> threadPoolFactory
;
201 HRESULT hr
= ::Windows::Foundation::GetActivationFactory(
202 Microsoft::WRL::Wrappers::HStringReference(RuntimeClass_Windows_System_Threading_ThreadPool
).Get(),
209 // Create event for tracking work item completion.
210 *thrdId
= ++threadCount
;
211 handle completionHandle
= CreateEventExW(NULL
, NULL
, 0, EVENT_ALL_ACCESS
);
212 if (!completionHandle
)
216 m_completionHandle
= completionHandle
;
218 // Create new work item.
219 Microsoft::WRL::ComPtr
<ABI::Windows::System::Threading::IWorkItemHandler
> workItem
=
220 Microsoft::WRL::Callback
<Microsoft::WRL::Implements
<Microsoft::WRL::RuntimeClassFlags
<Microsoft::WRL::ClassicCom
>, ABI::Windows::System::Threading::IWorkItemHandler
, Microsoft::WRL::FtmBase
>>
221 ([address
, parameter
, completionHandle
](ABI::Windows::Foundation::IAsyncAction
*)
223 // Add a reference since we need to access the completionHandle after the thread_start_function.
224 // This is to handle cases where detach() was called and run_thread_exit_callbacks() would end
225 // up closing the handle.
226 ::boost::detail::thread_data_base
* const thread_info(reinterpret_cast<::boost::detail::thread_data_base
*>(parameter
));
227 intrusive_ptr_add_ref(thread_info
);
235 SetEvent(completionHandle
);
236 intrusive_ptr_release(thread_info
);
241 // Schedule work item on the threadpool.
242 Microsoft::WRL::ComPtr
<ABI::Windows::Foundation::IAsyncAction
> asyncAction
;
243 hr
= threadPoolFactory
->RunWithPriorityAndOptionsAsync(
245 ABI::Windows::System::Threading::WorkItemPriority_Normal
,
246 ABI::Windows::System::Threading::WorkItemOptions_TimeSliced
,
255 void run_thread_exit_callbacks()
257 detail::thread_data_ptr
current_thread_data(detail::get_current_thread_data(),false);
258 if(current_thread_data
)
260 while(! current_thread_data
->tss_data
.empty() || current_thread_data
->thread_exit_callbacks
)
262 while(current_thread_data
->thread_exit_callbacks
)
264 detail::thread_exit_callback_node
* const current_node
=current_thread_data
->thread_exit_callbacks
;
265 current_thread_data
->thread_exit_callbacks
=current_node
->next
;
266 if(current_node
->func
)
268 (*current_node
->func
)();
269 boost::detail::heap_delete(current_node
->func
);
271 boost::detail::heap_delete(current_node
);
273 while (!current_thread_data
->tss_data
.empty())
275 std::map
<void const*,detail::tss_data_node
>::iterator current
276 = current_thread_data
->tss_data
.begin();
277 if(current
->second
.func
&& (current
->second
.value
!=0))
279 (*current
->second
.caller
)(current
->second
.func
,current
->second
.value
);
281 current_thread_data
->tss_data
.erase(current
);
284 set_current_thread_data(0);
288 unsigned __stdcall
thread_start_function(void* param
)
290 detail::thread_data_base
* const thread_info(reinterpret_cast<detail::thread_data_base
*>(param
));
291 set_current_thread_data(thread_info
);
292 #if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
297 #if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
299 BOOST_CATCH(thread_interrupted
const&)
302 // Unhandled exceptions still cause the application to terminate
305 run_thread_exit_callbacks();
310 thread::thread() BOOST_NOEXCEPT
313 bool thread::start_thread_noexcept()
315 #if BOOST_PLAT_WINDOWS_RUNTIME
316 intrusive_ptr_add_ref(thread_info
.get());
317 if (!thread_info
->thread_handle
.start(&thread_start_function
, thread_info
.get(), &thread_info
->id
))
319 intrusive_ptr_release(thread_info
.get());
324 uintptr_t const new_thread
=_beginthreadex(0,0,&thread_start_function
,thread_info
.get(),CREATE_SUSPENDED
,&thread_info
->id
);
329 intrusive_ptr_add_ref(thread_info
.get());
330 thread_info
->thread_handle
=(detail::win32::handle
)(new_thread
);
331 ResumeThread(thread_info
->thread_handle
);
336 bool thread::start_thread_noexcept(const attributes
& attr
)
338 #if BOOST_PLAT_WINDOWS_RUNTIME
339 // Stack size isn't supported with Windows Runtime.
341 return start_thread_noexcept();
343 uintptr_t const new_thread
=_beginthreadex(0,static_cast<unsigned int>(attr
.get_stack_size()),&thread_start_function
,thread_info
.get(),
344 CREATE_SUSPENDED
| STACK_SIZE_PARAM_IS_A_RESERVATION
, &thread_info
->id
);
349 intrusive_ptr_add_ref(thread_info
.get());
350 thread_info
->thread_handle
=(detail::win32::handle
)(new_thread
);
351 ResumeThread(thread_info
->thread_handle
);
356 thread::thread(detail::thread_data_ptr data
):
362 struct externally_launched_thread
:
363 detail::thread_data_base
365 externally_launched_thread()
368 #if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
369 interruption_enabled
=false;
372 ~externally_launched_thread() {
373 BOOST_ASSERT(notify
.empty());
375 //#ifndef BOOST_NO_EXCEPTIONS
376 BOOST_ASSERT(async_states_
.empty());
377 async_states_
.clear();
383 void notify_all_at_thread_exit(condition_variable
*, mutex
*)
387 externally_launched_thread(externally_launched_thread
&);
388 void operator=(externally_launched_thread
&);
391 void make_external_thread_data()
393 externally_launched_thread
* me
=detail::heap_new
<externally_launched_thread
>();
396 set_current_thread_data(me
);
400 detail::heap_delete(me
);
406 detail::thread_data_base
* get_or_make_current_thread_data()
408 detail::thread_data_base
* current_thread_data(detail::get_current_thread_data());
409 if(!current_thread_data
)
411 make_external_thread_data();
412 current_thread_data
=detail::get_current_thread_data();
414 return current_thread_data
;
418 thread::id
thread::get_id() const BOOST_NOEXCEPT
420 #if defined BOOST_THREAD_PROVIDES_BASIC_THREAD_ID
421 detail::thread_data_ptr local_thread_info
=(get_thread_info
)();
422 if(!local_thread_info
)
426 return local_thread_info
->id
;
428 return thread::id((get_thread_info
)());
432 bool thread::joinable() const BOOST_NOEXCEPT
434 detail::thread_data_ptr local_thread_info
= (get_thread_info
)();
435 if(!local_thread_info
)
441 bool thread::join_noexcept()
443 detail::thread_data_ptr local_thread_info
=(get_thread_info
)();
444 if(local_thread_info
)
446 this_thread::interruptible_wait(this->native_handle(), detail::internal_platform_timepoint::getMax());
456 bool thread::do_try_join_until_noexcept(detail::internal_platform_timepoint
const &timeout
, bool& res
)
458 detail::thread_data_ptr local_thread_info
=(get_thread_info
)();
459 if(local_thread_info
)
461 if(!this_thread::interruptible_wait(this->native_handle(), timeout
))
476 void thread::detach()
481 void thread::release_handle()
486 #if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
487 void thread::interrupt()
489 detail::thread_data_ptr local_thread_info
=(get_thread_info
)();
490 if(local_thread_info
)
492 local_thread_info
->interrupt();
496 bool thread::interruption_requested() const BOOST_NOEXCEPT
498 detail::thread_data_ptr local_thread_info
=(get_thread_info
)();
499 return local_thread_info
.get() && (winapi::WaitForSingleObjectEx(local_thread_info
->interruption_handle
,0,0)==0);
504 unsigned thread::hardware_concurrency() BOOST_NOEXCEPT
506 detail::win32::system_info info
;
507 detail::win32::get_system_info(&info
);
508 return info
.dwNumberOfProcessors
;
511 unsigned thread::physical_concurrency() BOOST_NOEXCEPT
513 // a bit too strict: Windows XP with SP3 would be sufficient
514 #if BOOST_PLAT_WINDOWS_RUNTIME \
515 || ( BOOST_USE_WINAPI_VERSION <= BOOST_WINAPI_VERSION_WINXP ) \
516 || ( ( defined(__MINGW32__) && !defined(__MINGW64__) ) && _WIN32_WINNT < 0x0600)
522 GetLogicalProcessorInformation(NULL
, &size
);
523 if (ERROR_INSUFFICIENT_BUFFER
!= GetLastError())
525 const size_t Elements
= size
/ sizeof(SYSTEM_LOGICAL_PROCESSOR_INFORMATION
);
527 std::vector
<SYSTEM_LOGICAL_PROCESSOR_INFORMATION
> buffer(Elements
);
528 if (GetLogicalProcessorInformation(&buffer
.front(), &size
) == FALSE
)
532 for (size_t i
= 0; i
< Elements
; ++i
) {
533 if (buffer
[i
].Relationship
== RelationProcessorCore
)
540 thread::native_handle_type
thread::native_handle()
542 detail::thread_data_ptr local_thread_info
=(get_thread_info
)();
543 if(!local_thread_info
)
545 return detail::win32::invalid_handle_value
;
547 #if BOOST_PLAT_WINDOWS_RUNTIME
548 // There is no 'real' Win32 handle so we return a handle that at least can be waited on.
549 return local_thread_info
->thread_handle
.waitable_handle();
551 return (detail::win32::handle
)local_thread_info
->thread_handle
;
555 detail::thread_data_ptr
thread::get_thread_info
BOOST_PREVENT_MACRO_SUBSTITUTION () const
560 namespace this_thread
563 #if !BOOST_PLAT_WINDOWS_RUNTIME
566 typedef struct _REASON_CONTEXT
{
570 LPWSTR SimpleReasonString
;
572 HMODULE LocalizedReasonModule
;
573 ULONG LocalizedReasonId
;
574 ULONG ReasonStringCount
;
575 LPWSTR
*ReasonStrings
;
578 } REASON_CONTEXT
, *PREASON_CONTEXT
;
579 typedef BOOL (WINAPI
*setwaitabletimerex_t
)(HANDLE
, const LARGE_INTEGER
*, LONG
, PTIMERAPCROUTINE
, LPVOID
, PREASON_CONTEXT
, ULONG
);
580 static inline BOOL WINAPI
SetWaitableTimerEx_emulation(HANDLE hTimer
, const LARGE_INTEGER
*lpDueTime
, LONG lPeriod
, PTIMERAPCROUTINE pfnCompletionRoutine
, LPVOID lpArgToCompletionRoutine
, PREASON_CONTEXT WakeContext
, ULONG TolerableDelay
)
582 return SetWaitableTimer(hTimer
, lpDueTime
, lPeriod
, pfnCompletionRoutine
, lpArgToCompletionRoutine
, FALSE
);
585 #pragma warning(push)
586 #pragma warning(disable: 6387) // MSVC sanitiser warns that GetModuleHandleA() might fail
588 static inline setwaitabletimerex_t
SetWaitableTimerEx()
590 static setwaitabletimerex_t setwaitabletimerex_impl
;
591 if(setwaitabletimerex_impl
)
592 return setwaitabletimerex_impl
;
593 void (*addr
)()=(void (*)()) GetProcAddress(
594 #if !defined(BOOST_NO_ANSI_APIS)
595 GetModuleHandleA("KERNEL32.DLL"),
597 GetModuleHandleW(L
"KERNEL32.DLL"),
599 "SetWaitableTimerEx");
601 setwaitabletimerex_impl
=(setwaitabletimerex_t
) addr
;
603 setwaitabletimerex_impl
=&SetWaitableTimerEx_emulation
;
604 return setwaitabletimerex_impl
;
612 bool interruptible_wait(detail::win32::handle handle_to_wait_for
, detail::internal_platform_timepoint
const &timeout
)
614 detail::win32::handle handles
[4]={0};
615 unsigned handle_count
=0;
616 unsigned wait_handle_index
=~0U;
617 #if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
618 unsigned interruption_index
=~0U;
620 unsigned timeout_index
=~0U;
621 if(handle_to_wait_for
!=detail::win32::invalid_handle_value
)
623 wait_handle_index
=handle_count
;
624 handles
[handle_count
++]=handle_to_wait_for
;
626 #if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
627 if(detail::get_current_thread_data() && detail::get_current_thread_data()->interruption_enabled
)
629 interruption_index
=handle_count
;
630 handles
[handle_count
++]=detail::get_current_thread_data()->interruption_handle
;
633 detail::win32::handle_manager timer_handle
;
636 #if !BOOST_PLAT_WINDOWS_RUNTIME
637 // Preferentially use coalescing timers for better power consumption and timer accuracy
638 if(timeout
!= detail::internal_platform_timepoint::getMax())
640 boost::intmax_t const time_left_msec
= (timeout
- detail::internal_platform_clock::now()).getMs();
641 timer_handle
=CreateWaitableTimer(NULL
,false,NULL
);
644 ULONG
const min_tolerable
=32; // Empirical testing shows Windows ignores this when <= 26
645 ULONG
const max_tolerable
=1000;
646 ULONG tolerable
=min_tolerable
;
647 if(time_left_msec
/20>tolerable
) // 5%
649 tolerable
=static_cast<ULONG
>(time_left_msec
/20);
650 if(tolerable
>max_tolerable
)
651 tolerable
=max_tolerable
;
653 LARGE_INTEGER due_time
={{0,0}};
656 due_time
.QuadPart
=-(time_left_msec
*10000); // negative indicates relative time
658 bool const set_time_succeeded
=detail_::SetWaitableTimerEx()(timer_handle
,&due_time
,0,0,0,NULL
,tolerable
)!=0;
659 if(set_time_succeeded
)
661 timeout_index
=handle_count
;
662 handles
[handle_count
++]=timer_handle
;
669 bool const using_timer
=timeout_index
!=~0u;
670 boost::intmax_t time_left_msec(INFINITE
);
671 if(!using_timer
&& timeout
!= detail::internal_platform_timepoint::getMax())
673 time_left_msec
= (timeout
- detail::internal_platform_clock::now()).getMs();
674 if(time_left_msec
< 0)
684 unsigned long const notified_index
=winapi::WaitForMultipleObjectsEx(handle_count
,handles
,false,static_cast<DWORD
>(time_left_msec
), 0);
685 if(notified_index
<handle_count
)
687 if(notified_index
==wait_handle_index
)
691 #if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
692 else if(notified_index
==interruption_index
)
694 winapi::ResetEvent(detail::get_current_thread_data()->interruption_handle
);
695 throw thread_interrupted();
698 else if(notified_index
==timeout_index
)
706 detail::win32::sleep(static_cast<unsigned long>(time_left_msec
));
709 if(!using_timer
&& timeout
!= detail::internal_platform_timepoint::getMax())
711 time_left_msec
= (timeout
- detail::internal_platform_clock::now()).getMs();
714 while(time_left_msec
== INFINITE
|| time_left_msec
> 0);
718 namespace no_interruption_point
720 bool non_interruptible_wait(detail::win32::handle handle_to_wait_for
, detail::internal_platform_timepoint
const &timeout
)
722 detail::win32::handle handles
[3]={0};
723 unsigned handle_count
=0;
724 unsigned wait_handle_index
=~0U;
725 unsigned timeout_index
=~0U;
726 if(handle_to_wait_for
!=detail::win32::invalid_handle_value
)
728 wait_handle_index
=handle_count
;
729 handles
[handle_count
++]=handle_to_wait_for
;
731 detail::win32::handle_manager timer_handle
;
734 #if !BOOST_PLAT_WINDOWS_RUNTIME
735 // Preferentially use coalescing timers for better power consumption and timer accuracy
736 if(timeout
!= detail::internal_platform_timepoint::getMax())
738 boost::intmax_t const time_left_msec
= (timeout
- detail::internal_platform_clock::now()).getMs();
739 timer_handle
=CreateWaitableTimer(NULL
,false,NULL
);
742 ULONG
const min_tolerable
=32; // Empirical testing shows Windows ignores this when <= 26
743 ULONG
const max_tolerable
=1000;
744 ULONG tolerable
=min_tolerable
;
745 if(time_left_msec
/20>tolerable
) // 5%
747 tolerable
=static_cast<ULONG
>(time_left_msec
/20);
748 if(tolerable
>max_tolerable
)
749 tolerable
=max_tolerable
;
751 LARGE_INTEGER due_time
={{0,0}};
754 due_time
.QuadPart
=-(time_left_msec
*10000); // negative indicates relative time
756 bool const set_time_succeeded
=detail_::SetWaitableTimerEx()(timer_handle
,&due_time
,0,0,0,NULL
,tolerable
)!=0;
757 if(set_time_succeeded
)
759 timeout_index
=handle_count
;
760 handles
[handle_count
++]=timer_handle
;
767 bool const using_timer
=timeout_index
!=~0u;
768 boost::intmax_t time_left_msec(INFINITE
);
769 if(!using_timer
&& timeout
!= detail::internal_platform_timepoint::getMax())
771 time_left_msec
= (timeout
- detail::internal_platform_clock::now()).getMs();
772 if(time_left_msec
< 0)
782 unsigned long const notified_index
=winapi::WaitForMultipleObjectsEx(handle_count
,handles
,false,static_cast<DWORD
>(time_left_msec
), 0);
783 if(notified_index
<handle_count
)
785 if(notified_index
==wait_handle_index
)
789 else if(notified_index
==timeout_index
)
797 detail::win32::sleep(static_cast<unsigned long>(time_left_msec
));
800 if(!using_timer
&& timeout
!= detail::internal_platform_timepoint::getMax())
802 time_left_msec
= (timeout
- detail::internal_platform_clock::now()).getMs();
805 while(time_left_msec
== INFINITE
|| time_left_msec
> 0);
810 thread::id
get_id() BOOST_NOEXCEPT
812 #if defined BOOST_THREAD_PROVIDES_BASIC_THREAD_ID
813 #if BOOST_PLAT_WINDOWS_RUNTIME
814 detail::thread_data_base
* current_thread_data(detail::get_current_thread_data());
815 if (current_thread_data
)
817 return current_thread_data
->id
;
820 return winapi::GetCurrentThreadId();
822 return thread::id(get_or_make_current_thread_data());
826 #if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
827 void interruption_point()
829 if(interruption_enabled() && interruption_requested())
831 winapi::ResetEvent(detail::get_current_thread_data()->interruption_handle
);
832 throw thread_interrupted();
836 bool interruption_enabled() BOOST_NOEXCEPT
838 return detail::get_current_thread_data() && detail::get_current_thread_data()->interruption_enabled
;
841 bool interruption_requested() BOOST_NOEXCEPT
843 return detail::get_current_thread_data() && (winapi::WaitForSingleObjectEx(detail::get_current_thread_data()->interruption_handle
,0,0)==0);
847 void yield() BOOST_NOEXCEPT
849 detail::win32::sleep(0);
852 #if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
853 disable_interruption::disable_interruption() BOOST_NOEXCEPT
:
854 interruption_was_enabled(interruption_enabled())
856 if(interruption_was_enabled
)
858 detail::get_current_thread_data()->interruption_enabled
=false;
862 disable_interruption::~disable_interruption() BOOST_NOEXCEPT
864 if(detail::get_current_thread_data())
866 detail::get_current_thread_data()->interruption_enabled
=interruption_was_enabled
;
870 restore_interruption::restore_interruption(disable_interruption
& d
) BOOST_NOEXCEPT
872 if(d
.interruption_was_enabled
)
874 detail::get_current_thread_data()->interruption_enabled
=true;
878 restore_interruption::~restore_interruption() BOOST_NOEXCEPT
880 if(detail::get_current_thread_data())
882 detail::get_current_thread_data()->interruption_enabled
=false;
890 void add_thread_exit_function(thread_exit_function_base
* func
)
892 detail::thread_data_base
* const current_thread_data(get_or_make_current_thread_data());
893 thread_exit_callback_node
* const new_node
=
894 heap_new
<thread_exit_callback_node
>(
895 func
,current_thread_data
->thread_exit_callbacks
);
896 current_thread_data
->thread_exit_callbacks
=new_node
;
899 tss_data_node
* find_tss_data(void const* key
)
901 detail::thread_data_base
* const current_thread_data(get_current_thread_data());
902 if(current_thread_data
)
904 std::map
<void const*,tss_data_node
>::iterator current_node
=
905 current_thread_data
->tss_data
.find(key
);
906 if(current_node
!=current_thread_data
->tss_data
.end())
908 return ¤t_node
->second
;
914 void* get_tss_data(void const* key
)
916 if(tss_data_node
* const current_node
=find_tss_data(key
))
918 return current_node
->value
;
923 void add_new_tss_node(void const* key
,
924 detail::tss_data_node::cleanup_caller_t caller
,
925 detail::tss_data_node::cleanup_func_t func
,
928 detail::thread_data_base
* const current_thread_data(get_or_make_current_thread_data());
929 current_thread_data
->tss_data
.insert(std::make_pair(key
,tss_data_node(caller
,func
,tss_data
)));
932 void erase_tss_node(void const* key
)
934 detail::thread_data_base
* const current_thread_data(get_or_make_current_thread_data());
935 current_thread_data
->tss_data
.erase(key
);
938 void set_tss_data(void const* key
,
939 detail::tss_data_node::cleanup_caller_t caller
,
940 detail::tss_data_node::cleanup_func_t func
,
941 void* tss_data
,bool cleanup_existing
)
943 if(tss_data_node
* const current_node
=find_tss_data(key
))
945 if(cleanup_existing
&& current_node
->func
&& (current_node
->value
!=0))
947 (*current_node
->caller
)(current_node
->func
,current_node
->value
);
949 if(func
|| (tss_data
!=0))
951 current_node
->caller
=caller
;
952 current_node
->func
=func
;
953 current_node
->value
=tss_data
;
960 else if(func
|| (tss_data
!=0))
962 add_new_tss_node(key
,caller
,func
,tss_data
);
967 BOOST_THREAD_DECL
void __cdecl
on_process_enter()
970 BOOST_THREAD_DECL
void __cdecl
on_thread_enter()
973 BOOST_THREAD_DECL
void __cdecl
on_process_exit()
975 boost::cleanup_tls_key();
978 BOOST_THREAD_DECL
void __cdecl
on_thread_exit()
980 boost::run_thread_exit_callbacks();
983 BOOST_THREAD_DECL
void notify_all_at_thread_exit(condition_variable
& cond
, unique_lock
<mutex
> lk
)
985 detail::thread_data_base
* const current_thread_data(detail::get_current_thread_data());
986 if(current_thread_data
)
988 current_thread_data
->notify_all_at_thread_exit(&cond
, lk
.release());