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 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::internal_platform_timepoint::getMax());
452 bool thread::do_try_join_until_noexcept(detail::internal_platform_timepoint
const &timeout
, bool& res
)
454 detail::thread_data_ptr local_thread_info
=(get_thread_info
)();
455 if(local_thread_info
)
457 if(!this_thread::interruptible_wait(this->native_handle(), timeout
))
472 void thread::detach()
477 void thread::release_handle()
482 #if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
483 void thread::interrupt()
485 detail::thread_data_ptr local_thread_info
=(get_thread_info
)();
486 if(local_thread_info
)
488 local_thread_info
->interrupt();
492 bool thread::interruption_requested() const BOOST_NOEXCEPT
494 detail::thread_data_ptr local_thread_info
=(get_thread_info
)();
495 return local_thread_info
.get() && (winapi::WaitForSingleObjectEx(local_thread_info
->interruption_handle
,0,0)==0);
500 unsigned thread::hardware_concurrency() BOOST_NOEXCEPT
502 detail::win32::system_info info
;
503 detail::win32::get_system_info(&info
);
504 return info
.dwNumberOfProcessors
;
507 unsigned thread::physical_concurrency() BOOST_NOEXCEPT
509 // a bit too strict: Windows XP with SP3 would be sufficient
510 #if BOOST_PLAT_WINDOWS_RUNTIME \
511 || ( BOOST_USE_WINAPI_VERSION <= BOOST_WINAPI_VERSION_WINXP ) \
512 || ( ( defined(__MINGW32__) && !defined(__MINGW64__) ) && _WIN32_WINNT < 0x0600)
518 GetLogicalProcessorInformation(NULL
, &size
);
519 if (ERROR_INSUFFICIENT_BUFFER
!= GetLastError())
522 std::vector
<SYSTEM_LOGICAL_PROCESSOR_INFORMATION
> buffer(size
);
523 if (GetLogicalProcessorInformation(&buffer
.front(), &size
) == FALSE
)
526 const size_t Elements
= size
/ sizeof(SYSTEM_LOGICAL_PROCESSOR_INFORMATION
);
528 for (size_t i
= 0; i
< Elements
; ++i
) {
529 if (buffer
[i
].Relationship
== RelationProcessorCore
)
536 thread::native_handle_type
thread::native_handle()
538 detail::thread_data_ptr local_thread_info
=(get_thread_info
)();
539 if(!local_thread_info
)
541 return detail::win32::invalid_handle_value
;
543 #if BOOST_PLAT_WINDOWS_RUNTIME
544 // There is no 'real' Win32 handle so we return a handle that at least can be waited on.
545 return local_thread_info
->thread_handle
.waitable_handle();
547 return (detail::win32::handle
)local_thread_info
->thread_handle
;
551 detail::thread_data_ptr
thread::get_thread_info
BOOST_PREVENT_MACRO_SUBSTITUTION () const
556 namespace this_thread
559 #if !BOOST_PLAT_WINDOWS_RUNTIME
562 typedef struct _REASON_CONTEXT
{
566 LPWSTR SimpleReasonString
;
568 HMODULE LocalizedReasonModule
;
569 ULONG LocalizedReasonId
;
570 ULONG ReasonStringCount
;
571 LPWSTR
*ReasonStrings
;
574 } REASON_CONTEXT
, *PREASON_CONTEXT
;
575 typedef BOOL (WINAPI
*setwaitabletimerex_t
)(HANDLE
, const LARGE_INTEGER
*, LONG
, PTIMERAPCROUTINE
, LPVOID
, PREASON_CONTEXT
, ULONG
);
576 static inline BOOL WINAPI
SetWaitableTimerEx_emulation(HANDLE hTimer
, const LARGE_INTEGER
*lpDueTime
, LONG lPeriod
, PTIMERAPCROUTINE pfnCompletionRoutine
, LPVOID lpArgToCompletionRoutine
, PREASON_CONTEXT WakeContext
, ULONG TolerableDelay
)
578 return SetWaitableTimer(hTimer
, lpDueTime
, lPeriod
, pfnCompletionRoutine
, lpArgToCompletionRoutine
, FALSE
);
581 #pragma warning(push)
582 #pragma warning(disable: 6387) // MSVC sanitiser warns that GetModuleHandleA() might fail
584 static inline setwaitabletimerex_t
SetWaitableTimerEx()
586 static setwaitabletimerex_t setwaitabletimerex_impl
;
587 if(setwaitabletimerex_impl
)
588 return setwaitabletimerex_impl
;
589 void (*addr
)()=(void (*)()) GetProcAddress(
590 #if !defined(BOOST_NO_ANSI_APIS)
591 GetModuleHandleA("KERNEL32.DLL"),
593 GetModuleHandleW(L
"KERNEL32.DLL"),
595 "SetWaitableTimerEx");
597 setwaitabletimerex_impl
=(setwaitabletimerex_t
) addr
;
599 setwaitabletimerex_impl
=&SetWaitableTimerEx_emulation
;
600 return setwaitabletimerex_impl
;
608 bool interruptible_wait(detail::win32::handle handle_to_wait_for
, detail::internal_platform_timepoint
const &timeout
)
610 detail::win32::handle handles
[4]={0};
611 unsigned handle_count
=0;
612 unsigned wait_handle_index
=~0U;
613 #if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
614 unsigned interruption_index
=~0U;
616 unsigned timeout_index
=~0U;
617 if(handle_to_wait_for
!=detail::win32::invalid_handle_value
)
619 wait_handle_index
=handle_count
;
620 handles
[handle_count
++]=handle_to_wait_for
;
622 #if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
623 if(detail::get_current_thread_data() && detail::get_current_thread_data()->interruption_enabled
)
625 interruption_index
=handle_count
;
626 handles
[handle_count
++]=detail::get_current_thread_data()->interruption_handle
;
629 detail::win32::handle_manager timer_handle
;
632 #if !BOOST_PLAT_WINDOWS_RUNTIME
633 // Preferentially use coalescing timers for better power consumption and timer accuracy
634 if(timeout
!= detail::internal_platform_timepoint::getMax())
636 boost::intmax_t const time_left_msec
= (timeout
- detail::internal_platform_clock::now()).getMs();
637 timer_handle
=CreateWaitableTimer(NULL
,false,NULL
);
640 ULONG tolerable
=32; // Empirical testing shows Windows ignores this when <= 26
641 if(time_left_msec
/20>tolerable
) // 5%
642 tolerable
=static_cast<ULONG
>(time_left_msec
/20);
643 LARGE_INTEGER due_time
={{0,0}};
646 due_time
.QuadPart
=-(time_left_msec
*10000); // negative indicates relative time
648 bool const set_time_succeeded
=detail_::SetWaitableTimerEx()(timer_handle
,&due_time
,0,0,0,NULL
,tolerable
)!=0;
649 if(set_time_succeeded
)
651 timeout_index
=handle_count
;
652 handles
[handle_count
++]=timer_handle
;
659 bool const using_timer
=timeout_index
!=~0u;
660 boost::intmax_t time_left_msec(INFINITE
);
661 if(!using_timer
&& timeout
!= detail::internal_platform_timepoint::getMax())
663 time_left_msec
= (timeout
- detail::internal_platform_clock::now()).getMs();
664 if(time_left_msec
< 0)
674 unsigned long const notified_index
=winapi::WaitForMultipleObjectsEx(handle_count
,handles
,false,static_cast<DWORD
>(time_left_msec
), 0);
675 if(notified_index
<handle_count
)
677 if(notified_index
==wait_handle_index
)
681 #if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
682 else if(notified_index
==interruption_index
)
684 winapi::ResetEvent(detail::get_current_thread_data()->interruption_handle
);
685 throw thread_interrupted();
688 else if(notified_index
==timeout_index
)
696 detail::win32::sleep(static_cast<unsigned long>(time_left_msec
));
699 if(!using_timer
&& timeout
!= detail::internal_platform_timepoint::getMax())
701 time_left_msec
= (timeout
- detail::internal_platform_clock::now()).getMs();
704 while(time_left_msec
== INFINITE
|| time_left_msec
> 0);
708 namespace no_interruption_point
710 bool non_interruptible_wait(detail::win32::handle handle_to_wait_for
, detail::internal_platform_timepoint
const &timeout
)
712 detail::win32::handle handles
[3]={0};
713 unsigned handle_count
=0;
714 unsigned wait_handle_index
=~0U;
715 unsigned timeout_index
=~0U;
716 if(handle_to_wait_for
!=detail::win32::invalid_handle_value
)
718 wait_handle_index
=handle_count
;
719 handles
[handle_count
++]=handle_to_wait_for
;
721 detail::win32::handle_manager timer_handle
;
724 #if !BOOST_PLAT_WINDOWS_RUNTIME
725 // Preferentially use coalescing timers for better power consumption and timer accuracy
726 if(timeout
!= detail::internal_platform_timepoint::getMax())
728 boost::intmax_t const time_left_msec
= (timeout
- detail::internal_platform_clock::now()).getMs();
729 timer_handle
=CreateWaitableTimer(NULL
,false,NULL
);
732 ULONG tolerable
=32; // Empirical testing shows Windows ignores this when <= 26
733 if(time_left_msec
/20>tolerable
) // 5%
734 tolerable
=static_cast<ULONG
>(time_left_msec
/20);
735 LARGE_INTEGER due_time
={{0,0}};
738 due_time
.QuadPart
=-(time_left_msec
*10000); // negative indicates relative time
740 bool const set_time_succeeded
=detail_::SetWaitableTimerEx()(timer_handle
,&due_time
,0,0,0,NULL
,tolerable
)!=0;
741 if(set_time_succeeded
)
743 timeout_index
=handle_count
;
744 handles
[handle_count
++]=timer_handle
;
751 bool const using_timer
=timeout_index
!=~0u;
752 boost::intmax_t time_left_msec(INFINITE
);
753 if(!using_timer
&& timeout
!= detail::internal_platform_timepoint::getMax())
755 time_left_msec
= (timeout
- detail::internal_platform_clock::now()).getMs();
756 if(time_left_msec
< 0)
766 unsigned long const notified_index
=winapi::WaitForMultipleObjectsEx(handle_count
,handles
,false,static_cast<DWORD
>(time_left_msec
), 0);
767 if(notified_index
<handle_count
)
769 if(notified_index
==wait_handle_index
)
773 else if(notified_index
==timeout_index
)
781 detail::win32::sleep(static_cast<unsigned long>(time_left_msec
));
784 if(!using_timer
&& timeout
!= detail::internal_platform_timepoint::getMax())
786 time_left_msec
= (timeout
- detail::internal_platform_clock::now()).getMs();
789 while(time_left_msec
== INFINITE
|| time_left_msec
> 0);
794 thread::id
get_id() BOOST_NOEXCEPT
796 #if defined BOOST_THREAD_PROVIDES_BASIC_THREAD_ID
797 #if BOOST_PLAT_WINDOWS_RUNTIME
798 detail::thread_data_base
* current_thread_data(detail::get_current_thread_data());
799 if (current_thread_data
)
801 return current_thread_data
->id
;
804 return winapi::GetCurrentThreadId();
806 return thread::id(get_or_make_current_thread_data());
810 #if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
811 void interruption_point()
813 if(interruption_enabled() && interruption_requested())
815 winapi::ResetEvent(detail::get_current_thread_data()->interruption_handle
);
816 throw thread_interrupted();
820 bool interruption_enabled() BOOST_NOEXCEPT
822 return detail::get_current_thread_data() && detail::get_current_thread_data()->interruption_enabled
;
825 bool interruption_requested() BOOST_NOEXCEPT
827 return detail::get_current_thread_data() && (winapi::WaitForSingleObjectEx(detail::get_current_thread_data()->interruption_handle
,0,0)==0);
831 void yield() BOOST_NOEXCEPT
833 detail::win32::sleep(0);
836 #if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
837 disable_interruption::disable_interruption() BOOST_NOEXCEPT
:
838 interruption_was_enabled(interruption_enabled())
840 if(interruption_was_enabled
)
842 detail::get_current_thread_data()->interruption_enabled
=false;
846 disable_interruption::~disable_interruption() BOOST_NOEXCEPT
848 if(detail::get_current_thread_data())
850 detail::get_current_thread_data()->interruption_enabled
=interruption_was_enabled
;
854 restore_interruption::restore_interruption(disable_interruption
& d
) BOOST_NOEXCEPT
856 if(d
.interruption_was_enabled
)
858 detail::get_current_thread_data()->interruption_enabled
=true;
862 restore_interruption::~restore_interruption() BOOST_NOEXCEPT
864 if(detail::get_current_thread_data())
866 detail::get_current_thread_data()->interruption_enabled
=false;
874 void add_thread_exit_function(thread_exit_function_base
* func
)
876 detail::thread_data_base
* const current_thread_data(get_or_make_current_thread_data());
877 thread_exit_callback_node
* const new_node
=
878 heap_new
<thread_exit_callback_node
>(
879 func
,current_thread_data
->thread_exit_callbacks
);
880 current_thread_data
->thread_exit_callbacks
=new_node
;
883 tss_data_node
* find_tss_data(void const* key
)
885 detail::thread_data_base
* const current_thread_data(get_current_thread_data());
886 if(current_thread_data
)
888 std::map
<void const*,tss_data_node
>::iterator current_node
=
889 current_thread_data
->tss_data
.find(key
);
890 if(current_node
!=current_thread_data
->tss_data
.end())
892 return ¤t_node
->second
;
898 void* get_tss_data(void const* key
)
900 if(tss_data_node
* const current_node
=find_tss_data(key
))
902 return current_node
->value
;
907 void add_new_tss_node(void const* key
,
908 boost::shared_ptr
<tss_cleanup_function
> func
,
911 detail::thread_data_base
* const current_thread_data(get_or_make_current_thread_data());
912 current_thread_data
->tss_data
.insert(std::make_pair(key
,tss_data_node(func
,tss_data
)));
915 void erase_tss_node(void const* key
)
917 detail::thread_data_base
* const current_thread_data(get_or_make_current_thread_data());
918 current_thread_data
->tss_data
.erase(key
);
921 void set_tss_data(void const* key
,
922 boost::shared_ptr
<tss_cleanup_function
> func
,
923 void* tss_data
,bool cleanup_existing
)
925 if(tss_data_node
* const current_node
=find_tss_data(key
))
927 if(cleanup_existing
&& current_node
->func
&& (current_node
->value
!=0))
929 (*current_node
->func
)(current_node
->value
);
931 if(func
|| (tss_data
!=0))
933 current_node
->func
=func
;
934 current_node
->value
=tss_data
;
941 else if(func
|| (tss_data
!=0))
943 add_new_tss_node(key
,func
,tss_data
);
948 BOOST_THREAD_DECL
void __cdecl
on_process_enter()
951 BOOST_THREAD_DECL
void __cdecl
on_thread_enter()
954 BOOST_THREAD_DECL
void __cdecl
on_process_exit()
956 boost::cleanup_tls_key();
959 BOOST_THREAD_DECL
void __cdecl
on_thread_exit()
961 boost::run_thread_exit_callbacks();
964 BOOST_THREAD_DECL
void notify_all_at_thread_exit(condition_variable
& cond
, unique_lock
<mutex
> lk
)
966 detail::thread_data_base
* const current_thread_data(detail::get_current_thread_data());
967 if(current_thread_data
)
969 current_thread_data
->notify_all_at_thread_exit(&cond
, lk
.release());