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-2017 Vicente J. Botet Escriba
8 //#define BOOST_THREAD_VERSION 3
10 #include <boost/detail/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 for (async_states_t::iterator i
= async_states_
.begin(), e
= async_states_
.end();
60 (*i
)->notify_deferred();
67 #ifdef BOOST_THREAD_PROVIDES_ONCE_CXX11
68 boost::once_flag current_thread_tls_init_flag
;
70 boost::once_flag current_thread_tls_init_flag
=BOOST_ONCE_INIT
;
73 // Windows CE does not define the TLS_OUT_OF_INDEXES constant.
74 #define TLS_OUT_OF_INDEXES 0xFFFFFFFF
76 #if !BOOST_PLAT_WINDOWS_RUNTIME
77 DWORD current_thread_tls_key
=TLS_OUT_OF_INDEXES
;
79 __declspec(thread
) boost::detail::thread_data_base
* current_thread_data_base
;
82 void create_current_thread_tls_key()
84 tss_cleanup_implemented(); // if anyone uses TSS, we need the cleanup linked in
85 #if !BOOST_PLAT_WINDOWS_RUNTIME
86 current_thread_tls_key
=TlsAlloc();
87 BOOST_ASSERT(current_thread_tls_key
!=TLS_OUT_OF_INDEXES
);
91 void cleanup_tls_key()
93 #if !BOOST_PLAT_WINDOWS_RUNTIME
94 if(current_thread_tls_key
!=TLS_OUT_OF_INDEXES
)
96 TlsFree(current_thread_tls_key
);
97 current_thread_tls_key
=TLS_OUT_OF_INDEXES
;
102 void set_current_thread_data(detail::thread_data_base
* new_data
)
104 boost::call_once(current_thread_tls_init_flag
,create_current_thread_tls_key
);
105 #if BOOST_PLAT_WINDOWS_RUNTIME
106 current_thread_data_base
= new_data
;
108 if (current_thread_tls_key
!= TLS_OUT_OF_INDEXES
)
110 BOOST_VERIFY(TlsSetValue(current_thread_tls_key
, new_data
));
115 //boost::throw_exception(thread_resource_error());
123 thread_data_base
* get_current_thread_data()
125 #if BOOST_PLAT_WINDOWS_RUNTIME
126 return current_thread_data_base
;
128 if (current_thread_tls_key
== TLS_OUT_OF_INDEXES
)
132 return (detail::thread_data_base
*)TlsGetValue(current_thread_tls_key
);
139 #ifndef BOOST_HAS_THREADEX
140 // Windows CE doesn't define _beginthreadex
142 struct ThreadProxyData
144 typedef unsigned (__stdcall
* func
)(void*);
147 ThreadProxyData(func start_address
,void* arglist
) : start_address_(start_address
), arglist_(arglist
) {}
150 DWORD WINAPI
ThreadProxy(LPVOID args
)
152 boost::csbl::unique_ptr
<ThreadProxyData
> data(reinterpret_cast<ThreadProxyData
*>(args
));
153 DWORD ret
=data
->start_address_(data
->arglist_
);
157 inline uintptr_t _beginthreadex(void* security
, unsigned stack_size
, unsigned (__stdcall
* start_address
)(void*),
158 void* arglist
, unsigned initflag
, unsigned* thrdaddr
)
161 ThreadProxyData
* data
= new ThreadProxyData(start_address
,arglist
);
162 HANDLE hthread
=CreateThread(static_cast<LPSECURITY_ATTRIBUTES
>(security
),stack_size
,ThreadProxy
,
163 data
,initflag
,&threadID
);
169 return reinterpret_cast<uintptr_t const>(hthread
);
178 struct thread_exit_callback_node
180 boost::detail::thread_exit_function_base
* func
;
181 thread_exit_callback_node
* next
;
183 thread_exit_callback_node(boost::detail::thread_exit_function_base
* func_
,
184 thread_exit_callback_node
* next_
):
185 func(func_
),next(next_
)
191 #if BOOST_PLAT_WINDOWS_RUNTIME
194 std::atomic_uint threadCount
;
196 bool win32::scoped_winrt_thread::start(thread_func address
, void *parameter
, unsigned int *thrdId
)
198 Microsoft::WRL::ComPtr
<ABI::Windows::System::Threading::IThreadPoolStatics
> threadPoolFactory
;
199 HRESULT hr
= ::Windows::Foundation::GetActivationFactory(
200 Microsoft::WRL::Wrappers::HStringReference(RuntimeClass_Windows_System_Threading_ThreadPool
).Get(),
207 // Create event for tracking work item completion.
208 *thrdId
= ++threadCount
;
209 handle completionHandle
= CreateEventExW(NULL
, NULL
, 0, EVENT_ALL_ACCESS
);
210 if (!completionHandle
)
214 m_completionHandle
= completionHandle
;
216 // Create new work item.
217 Microsoft::WRL::ComPtr
<ABI::Windows::System::Threading::IWorkItemHandler
> workItem
=
218 Microsoft::WRL::Callback
<Microsoft::WRL::Implements
<Microsoft::WRL::RuntimeClassFlags
<Microsoft::WRL::ClassicCom
>, ABI::Windows::System::Threading::IWorkItemHandler
, Microsoft::WRL::FtmBase
>>
219 ([address
, parameter
, completionHandle
](ABI::Windows::Foundation::IAsyncAction
*)
221 // Add a reference since we need to access the completionHandle after the thread_start_function.
222 // This is to handle cases where detach() was called and run_thread_exit_callbacks() would end
223 // up closing the handle.
224 ::boost::detail::thread_data_base
* const thread_info(reinterpret_cast<::boost::detail::thread_data_base
*>(parameter
));
225 intrusive_ptr_add_ref(thread_info
);
233 SetEvent(completionHandle
);
234 intrusive_ptr_release(thread_info
);
239 // Schedule work item on the threadpool.
240 Microsoft::WRL::ComPtr
<ABI::Windows::Foundation::IAsyncAction
> asyncAction
;
241 hr
= threadPoolFactory
->RunWithPriorityAndOptionsAsync(
243 ABI::Windows::System::Threading::WorkItemPriority_Normal
,
244 ABI::Windows::System::Threading::WorkItemOptions_TimeSliced
,
253 void run_thread_exit_callbacks()
255 detail::thread_data_ptr
current_thread_data(detail::get_current_thread_data(),false);
256 if(current_thread_data
)
258 while(! current_thread_data
->tss_data
.empty() || current_thread_data
->thread_exit_callbacks
)
260 while(current_thread_data
->thread_exit_callbacks
)
262 detail::thread_exit_callback_node
* const current_node
=current_thread_data
->thread_exit_callbacks
;
263 current_thread_data
->thread_exit_callbacks
=current_node
->next
;
264 if(current_node
->func
)
266 (*current_node
->func
)();
267 boost::detail::heap_delete(current_node
->func
);
269 boost::detail::heap_delete(current_node
);
271 while (!current_thread_data
->tss_data
.empty())
273 std::map
<void const*,detail::tss_data_node
>::iterator current
274 = current_thread_data
->tss_data
.begin();
275 if(current
->second
.func
&& (current
->second
.value
!=0))
277 (*current
->second
.func
)(current
->second
.value
);
279 current_thread_data
->tss_data
.erase(current
);
282 set_current_thread_data(0);
286 unsigned __stdcall
thread_start_function(void* param
)
288 detail::thread_data_base
* const thread_info(reinterpret_cast<detail::thread_data_base
*>(param
));
289 set_current_thread_data(thread_info
);
290 #if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
295 #if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
297 BOOST_CATCH(thread_interrupted
const&)
300 // Unhandled exceptions still cause the application to terminate
303 run_thread_exit_callbacks();
308 thread::thread() BOOST_NOEXCEPT
311 bool thread::start_thread_noexcept()
313 #if BOOST_PLAT_WINDOWS_RUNTIME
314 intrusive_ptr_add_ref(thread_info
.get());
315 if (!thread_info
->thread_handle
.start(&thread_start_function
, thread_info
.get(), &thread_info
->id
))
317 intrusive_ptr_release(thread_info
.get());
322 uintptr_t const new_thread
=_beginthreadex(0,0,&thread_start_function
,thread_info
.get(),CREATE_SUSPENDED
,&thread_info
->id
);
327 intrusive_ptr_add_ref(thread_info
.get());
328 thread_info
->thread_handle
=(detail::win32::handle
)(new_thread
);
329 ResumeThread(thread_info
->thread_handle
);
334 bool thread::start_thread_noexcept(const attributes
& attr
)
336 #if BOOST_PLAT_WINDOWS_RUNTIME
337 // Stack size isn't supported with Windows Runtime.
339 return start_thread_noexcept();
341 uintptr_t const new_thread
=_beginthreadex(0,static_cast<unsigned int>(attr
.get_stack_size()),&thread_start_function
,thread_info
.get(),
342 CREATE_SUSPENDED
| STACK_SIZE_PARAM_IS_A_RESERVATION
, &thread_info
->id
);
347 intrusive_ptr_add_ref(thread_info
.get());
348 thread_info
->thread_handle
=(detail::win32::handle
)(new_thread
);
349 ResumeThread(thread_info
->thread_handle
);
354 thread::thread(detail::thread_data_ptr data
):
360 struct externally_launched_thread
:
361 detail::thread_data_base
363 externally_launched_thread()
366 #if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
367 interruption_enabled
=false;
370 ~externally_launched_thread() {
371 BOOST_ASSERT(notify
.empty());
373 BOOST_ASSERT(async_states_
.empty());
374 async_states_
.clear();
379 void notify_all_at_thread_exit(condition_variable
*, mutex
*)
383 externally_launched_thread(externally_launched_thread
&);
384 void operator=(externally_launched_thread
&);
387 void make_external_thread_data()
389 externally_launched_thread
* me
=detail::heap_new
<externally_launched_thread
>();
392 set_current_thread_data(me
);
396 detail::heap_delete(me
);
402 detail::thread_data_base
* get_or_make_current_thread_data()
404 detail::thread_data_base
* current_thread_data(detail::get_current_thread_data());
405 if(!current_thread_data
)
407 make_external_thread_data();
408 current_thread_data
=detail::get_current_thread_data();
410 return current_thread_data
;
414 thread::id
thread::get_id() const BOOST_NOEXCEPT
416 #if defined BOOST_THREAD_PROVIDES_BASIC_THREAD_ID
417 detail::thread_data_ptr local_thread_info
=(get_thread_info
)();
418 if(!local_thread_info
)
422 return local_thread_info
->id
;
424 return thread::id((get_thread_info
)());
428 bool thread::joinable() const BOOST_NOEXCEPT
430 detail::thread_data_ptr local_thread_info
= (get_thread_info
)();
431 if(!local_thread_info
)
437 bool thread::join_noexcept()
439 detail::thread_data_ptr local_thread_info
=(get_thread_info
)();
440 if(local_thread_info
)
442 this_thread::interruptible_wait(this->native_handle(),detail::timeout::sentinel());
452 #if defined BOOST_THREAD_USES_DATETIME
453 bool thread::timed_join(boost::system_time
const& wait_until
)
455 return do_try_join_until(boost::detail::get_milliseconds_until(wait_until
));
458 bool thread::do_try_join_until_noexcept(uintmax_t milli
, bool& res
)
460 detail::thread_data_ptr local_thread_info
=(get_thread_info
)();
461 if(local_thread_info
)
463 if(!this_thread::interruptible_wait(this->native_handle(),milli
))
478 void thread::detach()
483 void thread::release_handle()
488 #if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
489 void thread::interrupt()
491 detail::thread_data_ptr local_thread_info
=(get_thread_info
)();
492 if(local_thread_info
)
494 local_thread_info
->interrupt();
498 bool thread::interruption_requested() const BOOST_NOEXCEPT
500 detail::thread_data_ptr local_thread_info
=(get_thread_info
)();
501 return local_thread_info
.get() && (detail::winapi::WaitForSingleObjectEx(local_thread_info
->interruption_handle
,0,0)==0);
506 unsigned thread::hardware_concurrency() BOOST_NOEXCEPT
508 detail::win32::system_info info
;
509 detail::win32::get_system_info(&info
);
510 return info
.dwNumberOfProcessors
;
513 unsigned thread::physical_concurrency() BOOST_NOEXCEPT
515 // a bit too strict: Windows XP with SP3 would be sufficient
516 #if BOOST_PLAT_WINDOWS_RUNTIME \
517 || ( BOOST_USE_WINAPI_VERSION <= BOOST_WINAPI_VERSION_WINXP ) \
518 || ( ( defined(__MINGW32__) && !defined(__MINGW64__) ) && _WIN32_WINNT < 0x0600)
524 GetLogicalProcessorInformation(NULL
, &size
);
525 if (ERROR_INSUFFICIENT_BUFFER
!= GetLastError())
528 std::vector
<SYSTEM_LOGICAL_PROCESSOR_INFORMATION
> buffer(size
);
529 if (GetLogicalProcessorInformation(&buffer
.front(), &size
) == FALSE
)
532 const size_t Elements
= size
/ sizeof(SYSTEM_LOGICAL_PROCESSOR_INFORMATION
);
534 for (size_t i
= 0; i
< Elements
; ++i
) {
535 if (buffer
[i
].Relationship
== RelationProcessorCore
)
542 thread::native_handle_type
thread::native_handle()
544 detail::thread_data_ptr local_thread_info
=(get_thread_info
)();
545 if(!local_thread_info
)
547 return detail::win32::invalid_handle_value
;
549 #if BOOST_PLAT_WINDOWS_RUNTIME
550 // There is no 'real' Win32 handle so we return a handle that at least can be waited on.
551 return local_thread_info
->thread_handle
.waitable_handle();
553 return (detail::win32::handle
)local_thread_info
->thread_handle
;
557 detail::thread_data_ptr
thread::get_thread_info
BOOST_PREVENT_MACRO_SUBSTITUTION () const
562 namespace this_thread
566 LARGE_INTEGER
get_due_time(detail::timeout
const& target_time
)
568 LARGE_INTEGER due_time
={{0,0}};
569 if(target_time
.relative
)
571 detail::win32::ticks_type
const elapsed_milliseconds
=detail::win32::GetTickCount64_()()-target_time
.start
;
572 LONGLONG
const remaining_milliseconds
=(target_time
.milliseconds
-elapsed_milliseconds
);
573 LONGLONG
const hundred_nanoseconds_in_one_millisecond
=10000;
575 if(remaining_milliseconds
>0)
577 due_time
.QuadPart
=-(remaining_milliseconds
*hundred_nanoseconds_in_one_millisecond
);
582 SYSTEMTIME target_system_time
={0,0,0,0,0,0,0,0};
583 target_system_time
.wYear
=target_time
.abs_time
.date().year();
584 target_system_time
.wMonth
=target_time
.abs_time
.date().month();
585 target_system_time
.wDay
=target_time
.abs_time
.date().day();
586 target_system_time
.wHour
=(WORD
)target_time
.abs_time
.time_of_day().hours();
587 target_system_time
.wMinute
=(WORD
)target_time
.abs_time
.time_of_day().minutes();
588 target_system_time
.wSecond
=(WORD
)target_time
.abs_time
.time_of_day().seconds();
590 if(!SystemTimeToFileTime(&target_system_time
,((FILETIME
*)&due_time
)))
596 long const hundred_nanoseconds_in_one_second
=10000000;
597 posix_time::time_duration::tick_type
const ticks_per_second
=
598 target_time
.abs_time
.time_of_day().ticks_per_second();
599 if(ticks_per_second
>hundred_nanoseconds_in_one_second
)
601 posix_time::time_duration::tick_type
const
602 ticks_per_hundred_nanoseconds
=
603 ticks_per_second
/hundred_nanoseconds_in_one_second
;
605 target_time
.abs_time
.time_of_day().fractional_seconds()/
606 ticks_per_hundred_nanoseconds
;
611 target_time
.abs_time
.time_of_day().fractional_seconds()*
612 (hundred_nanoseconds_in_one_second
/ticks_per_second
);
621 #if !BOOST_PLAT_WINDOWS_RUNTIME
624 typedef struct _REASON_CONTEXT
{
628 LPWSTR SimpleReasonString
;
630 HMODULE LocalizedReasonModule
;
631 ULONG LocalizedReasonId
;
632 ULONG ReasonStringCount
;
633 LPWSTR
*ReasonStrings
;
636 } REASON_CONTEXT
, *PREASON_CONTEXT
;
637 typedef BOOL (WINAPI
*setwaitabletimerex_t
)(HANDLE
, const LARGE_INTEGER
*, LONG
, PTIMERAPCROUTINE
, LPVOID
, PREASON_CONTEXT
, ULONG
);
638 static inline BOOL WINAPI
SetWaitableTimerEx_emulation(HANDLE hTimer
, const LARGE_INTEGER
*lpDueTime
, LONG lPeriod
, PTIMERAPCROUTINE pfnCompletionRoutine
, LPVOID lpArgToCompletionRoutine
, PREASON_CONTEXT WakeContext
, ULONG TolerableDelay
)
640 return SetWaitableTimer(hTimer
, lpDueTime
, lPeriod
, pfnCompletionRoutine
, lpArgToCompletionRoutine
, FALSE
);
643 #pragma warning(push)
644 #pragma warning(disable: 6387) // MSVC sanitiser warns that GetModuleHandleA() might fail
646 static inline setwaitabletimerex_t
SetWaitableTimerEx()
648 static setwaitabletimerex_t setwaitabletimerex_impl
;
649 if(setwaitabletimerex_impl
)
650 return setwaitabletimerex_impl
;
651 void (*addr
)()=(void (*)()) GetProcAddress(
652 #if !defined(BOOST_NO_ANSI_APIS)
653 GetModuleHandleA("KERNEL32.DLL"),
655 GetModuleHandleW(L
"KERNEL32.DLL"),
657 "SetWaitableTimerEx");
659 setwaitabletimerex_impl
=(setwaitabletimerex_t
) addr
;
661 setwaitabletimerex_impl
=&SetWaitableTimerEx_emulation
;
662 return setwaitabletimerex_impl
;
670 bool interruptible_wait(detail::win32::handle handle_to_wait_for
,detail::timeout target_time
)
672 detail::win32::handle handles
[4]={0};
673 unsigned handle_count
=0;
674 unsigned wait_handle_index
=~0U;
675 #if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
676 unsigned interruption_index
=~0U;
678 unsigned timeout_index
=~0U;
679 if(handle_to_wait_for
!=detail::win32::invalid_handle_value
)
681 wait_handle_index
=handle_count
;
682 handles
[handle_count
++]=handle_to_wait_for
;
684 #if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
685 if(detail::get_current_thread_data() && detail::get_current_thread_data()->interruption_enabled
)
687 interruption_index
=handle_count
;
688 handles
[handle_count
++]=detail::get_current_thread_data()->interruption_handle
;
691 detail::win32::handle_manager timer_handle
;
694 #if !BOOST_PLAT_WINDOWS_RUNTIME
695 // Preferentially use coalescing timers for better power consumption and timer accuracy
696 if(!target_time
.is_sentinel())
698 detail::timeout::remaining_time
const time_left
=target_time
.remaining_milliseconds();
699 timer_handle
=CreateWaitableTimer(NULL
,false,NULL
);
702 ULONG tolerable
=32; // Empirical testing shows Windows ignores this when <= 26
703 if(time_left
.milliseconds
/20>tolerable
) // 5%
704 tolerable
=time_left
.milliseconds
/20;
705 LARGE_INTEGER due_time
=get_due_time(target_time
);
706 bool const set_time_succeeded
=detail_::SetWaitableTimerEx()(timer_handle
,&due_time
,0,0,0,NULL
,tolerable
)!=0;
707 if(set_time_succeeded
)
709 timeout_index
=handle_count
;
710 handles
[handle_count
++]=timer_handle
;
717 bool const using_timer
=timeout_index
!=~0u;
718 detail::timeout::remaining_time
time_left(0);
724 time_left
=target_time
.remaining_milliseconds();
729 unsigned long const notified_index
=detail::winapi::WaitForMultipleObjectsEx(handle_count
,handles
,false,using_timer
?INFINITE
:time_left
.milliseconds
, 0);
730 if(notified_index
<handle_count
)
732 if(notified_index
==wait_handle_index
)
736 #if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
737 else if(notified_index
==interruption_index
)
739 detail::winapi::ResetEvent(detail::get_current_thread_data()->interruption_handle
);
740 throw thread_interrupted();
743 else if(notified_index
==timeout_index
)
751 detail::win32::sleep(time_left
.milliseconds
);
753 if(target_time
.relative
)
755 target_time
.milliseconds
-=detail::timeout::max_non_infinite_wait
;
758 while(time_left
.more
);
762 namespace no_interruption_point
764 bool non_interruptible_wait(detail::win32::handle handle_to_wait_for
,detail::timeout target_time
)
766 detail::win32::handle handles
[3]={0};
767 unsigned handle_count
=0;
768 unsigned wait_handle_index
=~0U;
769 unsigned timeout_index
=~0U;
770 if(handle_to_wait_for
!=detail::win32::invalid_handle_value
)
772 wait_handle_index
=handle_count
;
773 handles
[handle_count
++]=handle_to_wait_for
;
775 detail::win32::handle_manager timer_handle
;
778 #if !BOOST_PLAT_WINDOWS_RUNTIME
779 // Preferentially use coalescing timers for better power consumption and timer accuracy
780 if(!target_time
.is_sentinel())
782 detail::timeout::remaining_time
const time_left
=target_time
.remaining_milliseconds();
783 timer_handle
=CreateWaitableTimer(NULL
,false,NULL
);
786 ULONG tolerable
=32; // Empirical testing shows Windows ignores this when <= 26
787 if(time_left
.milliseconds
/20>tolerable
) // 5%
788 tolerable
=time_left
.milliseconds
/20;
789 LARGE_INTEGER due_time
=get_due_time(target_time
);
790 bool const set_time_succeeded
=detail_::SetWaitableTimerEx()(timer_handle
,&due_time
,0,0,0,NULL
,tolerable
)!=0;
791 if(set_time_succeeded
)
793 timeout_index
=handle_count
;
794 handles
[handle_count
++]=timer_handle
;
801 bool const using_timer
=timeout_index
!=~0u;
802 detail::timeout::remaining_time
time_left(0);
808 time_left
=target_time
.remaining_milliseconds();
813 unsigned long const notified_index
=detail::winapi::WaitForMultipleObjectsEx(handle_count
,handles
,false,using_timer
?INFINITE
:time_left
.milliseconds
, 0);
814 if(notified_index
<handle_count
)
816 if(notified_index
==wait_handle_index
)
820 else if(notified_index
==timeout_index
)
828 detail::win32::sleep(time_left
.milliseconds
);
830 if(target_time
.relative
)
832 target_time
.milliseconds
-=detail::timeout::max_non_infinite_wait
;
835 while(time_left
.more
);
840 thread::id
get_id() BOOST_NOEXCEPT
842 #if defined BOOST_THREAD_PROVIDES_BASIC_THREAD_ID
843 #if BOOST_PLAT_WINDOWS_RUNTIME
844 detail::thread_data_base
* current_thread_data(detail::get_current_thread_data());
845 if (current_thread_data
)
847 return current_thread_data
->id
;
850 return detail::winapi::GetCurrentThreadId();
852 return thread::id(get_or_make_current_thread_data());
856 #if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
857 void interruption_point()
859 if(interruption_enabled() && interruption_requested())
861 detail::winapi::ResetEvent(detail::get_current_thread_data()->interruption_handle
);
862 throw thread_interrupted();
866 bool interruption_enabled() BOOST_NOEXCEPT
868 return detail::get_current_thread_data() && detail::get_current_thread_data()->interruption_enabled
;
871 bool interruption_requested() BOOST_NOEXCEPT
873 return detail::get_current_thread_data() && (detail::winapi::WaitForSingleObjectEx(detail::get_current_thread_data()->interruption_handle
,0,0)==0);
877 void yield() BOOST_NOEXCEPT
879 detail::win32::sleep(0);
882 #if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
883 disable_interruption::disable_interruption() BOOST_NOEXCEPT
:
884 interruption_was_enabled(interruption_enabled())
886 if(interruption_was_enabled
)
888 detail::get_current_thread_data()->interruption_enabled
=false;
892 disable_interruption::~disable_interruption() BOOST_NOEXCEPT
894 if(detail::get_current_thread_data())
896 detail::get_current_thread_data()->interruption_enabled
=interruption_was_enabled
;
900 restore_interruption::restore_interruption(disable_interruption
& d
) BOOST_NOEXCEPT
902 if(d
.interruption_was_enabled
)
904 detail::get_current_thread_data()->interruption_enabled
=true;
908 restore_interruption::~restore_interruption() BOOST_NOEXCEPT
910 if(detail::get_current_thread_data())
912 detail::get_current_thread_data()->interruption_enabled
=false;
920 void add_thread_exit_function(thread_exit_function_base
* func
)
922 detail::thread_data_base
* const current_thread_data(get_or_make_current_thread_data());
923 thread_exit_callback_node
* const new_node
=
924 heap_new
<thread_exit_callback_node
>(
925 func
,current_thread_data
->thread_exit_callbacks
);
926 current_thread_data
->thread_exit_callbacks
=new_node
;
929 tss_data_node
* find_tss_data(void const* key
)
931 detail::thread_data_base
* const current_thread_data(get_current_thread_data());
932 if(current_thread_data
)
934 std::map
<void const*,tss_data_node
>::iterator current_node
=
935 current_thread_data
->tss_data
.find(key
);
936 if(current_node
!=current_thread_data
->tss_data
.end())
938 return ¤t_node
->second
;
944 void* get_tss_data(void const* key
)
946 if(tss_data_node
* const current_node
=find_tss_data(key
))
948 return current_node
->value
;
953 void add_new_tss_node(void const* key
,
954 boost::shared_ptr
<tss_cleanup_function
> func
,
957 detail::thread_data_base
* const current_thread_data(get_or_make_current_thread_data());
958 current_thread_data
->tss_data
.insert(std::make_pair(key
,tss_data_node(func
,tss_data
)));
961 void erase_tss_node(void const* key
)
963 detail::thread_data_base
* const current_thread_data(get_or_make_current_thread_data());
964 current_thread_data
->tss_data
.erase(key
);
967 void set_tss_data(void const* key
,
968 boost::shared_ptr
<tss_cleanup_function
> func
,
969 void* tss_data
,bool cleanup_existing
)
971 if(tss_data_node
* const current_node
=find_tss_data(key
))
973 if(cleanup_existing
&& current_node
->func
&& (current_node
->value
!=0))
975 (*current_node
->func
)(current_node
->value
);
977 if(func
|| (tss_data
!=0))
979 current_node
->func
=func
;
980 current_node
->value
=tss_data
;
987 else if(func
|| (tss_data
!=0))
989 add_new_tss_node(key
,func
,tss_data
);
994 BOOST_THREAD_DECL
void __cdecl
on_process_enter()
997 BOOST_THREAD_DECL
void __cdecl
on_thread_enter()
1000 BOOST_THREAD_DECL
void __cdecl
on_process_exit()
1002 boost::cleanup_tls_key();
1005 BOOST_THREAD_DECL
void __cdecl
on_thread_exit()
1007 boost::run_thread_exit_callbacks();
1010 BOOST_THREAD_DECL
void notify_all_at_thread_exit(condition_variable
& cond
, unique_lock
<mutex
> lk
)
1012 detail::thread_data_base
* const current_thread_data(detail::get_current_thread_data());
1013 if(current_thread_data
)
1015 current_thread_data
->notify_all_at_thread_exit(&cond
, lk
.release());