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
7 
8 //#define BOOST_THREAD_VERSION 3
9 
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>
22 #endif
23 #include <boost/thread/csbl/memory/unique_ptr.hpp>
24 #include <memory>
25 #include <algorithm>
26 #ifndef UNDER_CE
27 #include <process.h>
28 #endif
29 #include <stdio.h>
30 #include <windows.h>
31 #include <boost/predef/platform.h>
32 
33 #if BOOST_PLAT_WINDOWS_RUNTIME
34 #include <mutex>
35 #include <atomic>
36 #include <Activation.h>
37 #include <wrl\client.h>
38 #include <wrl\event.h>
39 #include <wrl\wrappers\corewrappers.h>
40 #include <wrl\ftm.h>
41 #include <windows.system.threading.h>
42 #pragma comment(lib, "runtimeobject.lib")
43 #endif
44 
45 namespace boost
46 {
47   namespace detail
48   {
~thread_data_base()49     thread_data_base::~thread_data_base()
50     {
51         for (notify_list_t::iterator i = notify.begin(), e = notify.end();
52                 i != e; ++i)
53         {
54             i->second->unlock();
55             i->first->notify_all();
56         }
57 //#ifndef BOOST_NO_EXCEPTIONS
58         for (async_states_t::iterator i = async_states_.begin(), e = async_states_.end();
59                 i != e; ++i)
60         {
61             (*i)->notify_deferred();
62         }
63 //#endif
64     }
65   }
66 
67     namespace
68     {
69 #ifdef BOOST_THREAD_PROVIDES_ONCE_CXX11
70         boost::once_flag current_thread_tls_init_flag;
71 #else
72         boost::once_flag current_thread_tls_init_flag=BOOST_ONCE_INIT;
73 #endif
74 #if defined(UNDER_CE)
75         // Windows CE does not define the TLS_OUT_OF_INDEXES constant.
76 #define TLS_OUT_OF_INDEXES 0xFFFFFFFF
77 #endif
78 #if !BOOST_PLAT_WINDOWS_RUNTIME
79         DWORD current_thread_tls_key=TLS_OUT_OF_INDEXES;
80 #else
81         __declspec(thread) boost::detail::thread_data_base* current_thread_data_base;
82 #endif
83 
create_current_thread_tls_key()84         void create_current_thread_tls_key()
85         {
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);
90 #endif
91         }
92 
cleanup_tls_key()93         void cleanup_tls_key()
94         {
95 #if !BOOST_PLAT_WINDOWS_RUNTIME
96             if(current_thread_tls_key!=TLS_OUT_OF_INDEXES)
97             {
98                 TlsFree(current_thread_tls_key);
99                 current_thread_tls_key=TLS_OUT_OF_INDEXES;
100             }
101 #endif
102         }
103 
set_current_thread_data(detail::thread_data_base * new_data)104         void set_current_thread_data(detail::thread_data_base* new_data)
105         {
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;
109 #else
110             if (current_thread_tls_key != TLS_OUT_OF_INDEXES)
111             {
112                 BOOST_VERIFY(TlsSetValue(current_thread_tls_key, new_data));
113             }
114             else
115             {
116                 BOOST_VERIFY(false);
117                 //boost::throw_exception(thread_resource_error());
118             }
119 #endif
120         }
121     }
122 
123     namespace detail
124     {
get_current_thread_data()125       thread_data_base* get_current_thread_data()
126       {
127 #if BOOST_PLAT_WINDOWS_RUNTIME
128           return current_thread_data_base;
129 #else
130           if (current_thread_tls_key == TLS_OUT_OF_INDEXES)
131           {
132               return 0;
133           }
134           return (detail::thread_data_base*)TlsGetValue(current_thread_tls_key);
135 #endif
136       }
137     }
138 
139     namespace
140     {
141 #ifndef BOOST_HAS_THREADEX
142 // Windows CE doesn't define _beginthreadex
143 
144         struct ThreadProxyData
145         {
146             typedef unsigned (__stdcall* func)(void*);
147             func start_address_;
148             void* arglist_;
ThreadProxyDataboost::__anon6a3018440211::ThreadProxyData149             ThreadProxyData(func start_address,void* arglist) : start_address_(start_address), arglist_(arglist) {}
150         };
151 
ThreadProxy(LPVOID args)152         DWORD WINAPI ThreadProxy(LPVOID args)
153         {
154             boost::csbl::unique_ptr<ThreadProxyData> data(reinterpret_cast<ThreadProxyData*>(args));
155             DWORD ret=data->start_address_(data->arglist_);
156             return ret;
157         }
158 
_beginthreadex(void * security,unsigned stack_size,unsigned (__stdcall * start_address)(void *),void * arglist,unsigned initflag,unsigned * thrdaddr)159         inline uintptr_t _beginthreadex(void* security, unsigned stack_size, unsigned (__stdcall* start_address)(void*),
160                                               void* arglist, unsigned initflag, unsigned* thrdaddr)
161         {
162             DWORD threadID;
163             ThreadProxyData* data = new ThreadProxyData(start_address,arglist);
164             HANDLE hthread=CreateThread(static_cast<LPSECURITY_ATTRIBUTES>(security),stack_size,ThreadProxy,
165                                         data,initflag,&threadID);
166             if (hthread==0) {
167               delete data;
168               return 0;
169             }
170             *thrdaddr=threadID;
171             return reinterpret_cast<uintptr_t const>(hthread);
172         }
173 
174 #endif
175 
176     }
177 
178     namespace detail
179     {
180         struct thread_exit_callback_node
181         {
182             boost::detail::thread_exit_function_base* func;
183             thread_exit_callback_node* next;
184 
thread_exit_callback_nodeboost::detail::thread_exit_callback_node185             thread_exit_callback_node(boost::detail::thread_exit_function_base* func_,
186                                       thread_exit_callback_node* next_):
187                 func(func_),next(next_)
188             {}
189         };
190 
191     }
192 
193 #if BOOST_PLAT_WINDOWS_RUNTIME
194     namespace detail
195     {
196         std::atomic_uint threadCount;
197 
start(thread_func address,void * parameter,unsigned int * thrdId)198         bool win32::scoped_winrt_thread::start(thread_func address, void *parameter, unsigned int *thrdId)
199         {
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(),
203                 &threadPoolFactory);
204             if (hr != S_OK)
205             {
206                 return false;
207             }
208 
209             // Create event for tracking work item completion.
210             *thrdId = ++threadCount;
211             handle completionHandle = CreateEventExW(NULL, NULL, 0, EVENT_ALL_ACCESS);
212             if (!completionHandle)
213             {
214                 return false;
215             }
216             m_completionHandle = completionHandle;
217 
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 *)
222             {
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);
228 
229                 __try
230                 {
231                     address(parameter);
232                 }
233                 __finally
234                 {
235                     SetEvent(completionHandle);
236                     intrusive_ptr_release(thread_info);
237                 }
238                 return S_OK;
239             });
240 
241             // Schedule work item on the threadpool.
242             Microsoft::WRL::ComPtr<ABI::Windows::Foundation::IAsyncAction> asyncAction;
243             hr = threadPoolFactory->RunWithPriorityAndOptionsAsync(
244                 workItem.Get(),
245                 ABI::Windows::System::Threading::WorkItemPriority_Normal,
246                 ABI::Windows::System::Threading::WorkItemOptions_TimeSliced,
247                 &asyncAction);
248             return hr == S_OK;
249         }
250     }
251 #endif
252 
253     namespace
254     {
run_thread_exit_callbacks()255         void run_thread_exit_callbacks()
256         {
257             detail::thread_data_ptr current_thread_data(detail::get_current_thread_data(),false);
258             if(current_thread_data)
259             {
260                 while(! current_thread_data->tss_data.empty() || current_thread_data->thread_exit_callbacks)
261                 {
262                     while(current_thread_data->thread_exit_callbacks)
263                     {
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)
267                         {
268                             (*current_node->func)();
269                             boost::detail::heap_delete(current_node->func);
270                         }
271                         boost::detail::heap_delete(current_node);
272                     }
273                     while (!current_thread_data->tss_data.empty())
274                     {
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))
278                         {
279                             (*current->second.caller)(current->second.func,current->second.value);
280                         }
281                         current_thread_data->tss_data.erase(current);
282                     }
283                 }
284                 set_current_thread_data(0);
285             }
286         }
287 
thread_start_function(void * param)288         unsigned __stdcall thread_start_function(void* param)
289         {
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
293             BOOST_TRY
294             {
295 #endif
296                 thread_info->run();
297 #if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
298             }
299             BOOST_CATCH(thread_interrupted const&)
300             {
301             }
302             // Unhandled exceptions still cause the application to terminate
303             BOOST_CATCH_END
304 #endif
305             run_thread_exit_callbacks();
306             return 0;
307         }
308     }
309 
thread()310     thread::thread() BOOST_NOEXCEPT
311     {}
312 
start_thread_noexcept()313     bool thread::start_thread_noexcept()
314     {
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))
318          {
319              intrusive_ptr_release(thread_info.get());
320              return false;
321          }
322          return true;
323 #else
324         uintptr_t const new_thread=_beginthreadex(0,0,&thread_start_function,thread_info.get(),CREATE_SUSPENDED,&thread_info->id);
325         if(!new_thread)
326         {
327             return false;
328         }
329         intrusive_ptr_add_ref(thread_info.get());
330         thread_info->thread_handle=(detail::win32::handle)(new_thread);
331         ResumeThread(thread_info->thread_handle);
332         return true;
333 #endif
334     }
335 
start_thread_noexcept(const attributes & attr)336     bool thread::start_thread_noexcept(const attributes& attr)
337     {
338 #if BOOST_PLAT_WINDOWS_RUNTIME
339         // Stack size isn't supported with Windows Runtime.
340         attr;
341         return start_thread_noexcept();
342 #else
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);
345       if(!new_thread)
346       {
347         return false;
348       }
349       intrusive_ptr_add_ref(thread_info.get());
350       thread_info->thread_handle=(detail::win32::handle)(new_thread);
351       ResumeThread(thread_info->thread_handle);
352       return true;
353 #endif
354     }
355 
thread(detail::thread_data_ptr data)356     thread::thread(detail::thread_data_ptr data):
357         thread_info(data)
358     {}
359 
360     namespace
361     {
362         struct externally_launched_thread:
363             detail::thread_data_base
364         {
externally_launched_threadboost::__anon6a3018440511::externally_launched_thread365             externally_launched_thread()
366             {
367                 ++count;
368 #if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
369                 interruption_enabled=false;
370 #endif
371             }
~externally_launched_threadboost::__anon6a3018440511::externally_launched_thread372             ~externally_launched_thread() {
373               BOOST_ASSERT(notify.empty());
374               notify.clear();
375 //#ifndef BOOST_NO_EXCEPTIONS
376               BOOST_ASSERT(async_states_.empty());
377               async_states_.clear();
378 //#endif
379             }
380 
runboost::__anon6a3018440511::externally_launched_thread381             void run()
382             {}
notify_all_at_thread_exitboost::__anon6a3018440511::externally_launched_thread383             void notify_all_at_thread_exit(condition_variable*, mutex*)
384             {}
385 
386         private:
387             externally_launched_thread(externally_launched_thread&);
388             void operator=(externally_launched_thread&);
389         };
390 
make_external_thread_data()391         void make_external_thread_data()
392         {
393             externally_launched_thread* me=detail::heap_new<externally_launched_thread>();
394             BOOST_TRY
395             {
396                 set_current_thread_data(me);
397             }
398             BOOST_CATCH(...)
399             {
400                 detail::heap_delete(me);
401                 BOOST_RETHROW
402             }
403             BOOST_CATCH_END
404         }
405 
get_or_make_current_thread_data()406         detail::thread_data_base* get_or_make_current_thread_data()
407         {
408             detail::thread_data_base* current_thread_data(detail::get_current_thread_data());
409             if(!current_thread_data)
410             {
411                 make_external_thread_data();
412                 current_thread_data=detail::get_current_thread_data();
413             }
414             return current_thread_data;
415         }
416     }
417 
get_id() const418     thread::id thread::get_id() const BOOST_NOEXCEPT
419     {
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)
423         {
424             return 0;
425         }
426         return local_thread_info->id;
427 #else
428         return thread::id((get_thread_info)());
429 #endif
430     }
431 
joinable() const432     bool thread::joinable() const BOOST_NOEXCEPT
433     {
434         detail::thread_data_ptr local_thread_info = (get_thread_info)();
435         if(!local_thread_info)
436         {
437             return false;
438         }
439         return true;
440     }
join_noexcept()441     bool thread::join_noexcept()
442     {
443         detail::thread_data_ptr local_thread_info=(get_thread_info)();
444         if(local_thread_info)
445         {
446             this_thread::interruptible_wait(this->native_handle(), detail::internal_platform_timepoint::getMax());
447             release_handle();
448             return true;
449         }
450         else
451         {
452           return false;
453         }
454     }
455 
do_try_join_until_noexcept(detail::internal_platform_timepoint const & timeout,bool & res)456     bool thread::do_try_join_until_noexcept(detail::internal_platform_timepoint const &timeout, bool& res)
457     {
458       detail::thread_data_ptr local_thread_info=(get_thread_info)();
459       if(local_thread_info)
460       {
461           if(!this_thread::interruptible_wait(this->native_handle(), timeout))
462           {
463             res=false;
464             return true;
465           }
466           release_handle();
467           res=true;
468           return true;
469       }
470       else
471       {
472         return false;
473       }
474     }
475 
detach()476     void thread::detach()
477     {
478         release_handle();
479     }
480 
release_handle()481     void thread::release_handle()
482     {
483         thread_info=0;
484     }
485 
486 #if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
interrupt()487     void thread::interrupt()
488     {
489         detail::thread_data_ptr local_thread_info=(get_thread_info)();
490         if(local_thread_info)
491         {
492             local_thread_info->interrupt();
493         }
494     }
495 
interruption_requested() const496     bool thread::interruption_requested() const BOOST_NOEXCEPT
497     {
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);
500     }
501 
502 #endif
503 
hardware_concurrency()504     unsigned thread::hardware_concurrency() BOOST_NOEXCEPT
505     {
506         detail::win32::system_info info;
507         detail::win32::get_system_info(&info);
508         return info.dwNumberOfProcessors;
509     }
510 
physical_concurrency()511     unsigned thread::physical_concurrency() BOOST_NOEXCEPT
512     {
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)
517         return 0;
518 #else
519         unsigned cores = 0;
520         DWORD size = 0;
521 
522         GetLogicalProcessorInformation(NULL, &size);
523         if (ERROR_INSUFFICIENT_BUFFER != GetLastError())
524             return 0;
525         const size_t Elements = size / sizeof(SYSTEM_LOGICAL_PROCESSOR_INFORMATION);
526 
527         std::vector<SYSTEM_LOGICAL_PROCESSOR_INFORMATION> buffer(Elements);
528         if (GetLogicalProcessorInformation(&buffer.front(), &size) == FALSE)
529             return 0;
530 
531 
532         for (size_t i = 0; i < Elements; ++i) {
533             if (buffer[i].Relationship == RelationProcessorCore)
534                 ++cores;
535         }
536         return cores;
537 #endif
538     }
539 
native_handle()540     thread::native_handle_type thread::native_handle()
541     {
542         detail::thread_data_ptr local_thread_info=(get_thread_info)();
543         if(!local_thread_info)
544         {
545             return detail::win32::invalid_handle_value;
546         }
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();
550 #else
551         return (detail::win32::handle)local_thread_info->thread_handle;
552 #endif
553     }
554 
BOOST_PREVENT_MACRO_SUBSTITUTION() const555     detail::thread_data_ptr thread::get_thread_info BOOST_PREVENT_MACRO_SUBSTITUTION () const
556     {
557         return thread_info;
558     }
559 
560     namespace this_thread
561     {
562 #ifndef UNDER_CE
563 #if !BOOST_PLAT_WINDOWS_RUNTIME
564         namespace detail_
565         {
566             typedef struct _REASON_CONTEXT {
567                 ULONG Version;
568                 DWORD Flags;
569                 union {
570                     LPWSTR SimpleReasonString;
571                     struct {
572                         HMODULE LocalizedReasonModule;
573                         ULONG   LocalizedReasonId;
574                         ULONG   ReasonStringCount;
575                         LPWSTR  *ReasonStrings;
576                     } Detailed;
577                 } Reason;
578             } REASON_CONTEXT, *PREASON_CONTEXT;
579             typedef BOOL (WINAPI *setwaitabletimerex_t)(HANDLE, const LARGE_INTEGER *, LONG, PTIMERAPCROUTINE, LPVOID, PREASON_CONTEXT, ULONG);
SetWaitableTimerEx_emulation(HANDLE hTimer,const LARGE_INTEGER * lpDueTime,LONG lPeriod,PTIMERAPCROUTINE pfnCompletionRoutine,LPVOID lpArgToCompletionRoutine,PREASON_CONTEXT WakeContext,ULONG TolerableDelay)580             static inline BOOL WINAPI SetWaitableTimerEx_emulation(HANDLE hTimer, const LARGE_INTEGER *lpDueTime, LONG lPeriod, PTIMERAPCROUTINE pfnCompletionRoutine, LPVOID lpArgToCompletionRoutine, PREASON_CONTEXT WakeContext, ULONG TolerableDelay)
581             {
582                 return SetWaitableTimer(hTimer, lpDueTime, lPeriod, pfnCompletionRoutine, lpArgToCompletionRoutine, FALSE);
583             }
584 #ifdef _MSC_VER
585 #pragma warning(push)
586 #pragma warning(disable: 6387) // MSVC sanitiser warns that GetModuleHandleA() might fail
587 #endif
SetWaitableTimerEx()588             static inline setwaitabletimerex_t SetWaitableTimerEx()
589             {
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"),
596 #else
597                     GetModuleHandleW(L"KERNEL32.DLL"),
598 #endif
599                     "SetWaitableTimerEx");
600                 if(addr)
601                     setwaitabletimerex_impl=(setwaitabletimerex_t) addr;
602                 else
603                     setwaitabletimerex_impl=&SetWaitableTimerEx_emulation;
604                 return setwaitabletimerex_impl;
605             }
606 #ifdef _MSC_VER
607 #pragma warning(pop)
608 #endif
609         }
610 #endif
611 #endif
interruptible_wait(detail::win32::handle handle_to_wait_for,detail::internal_platform_timepoint const & timeout)612         bool interruptible_wait(detail::win32::handle handle_to_wait_for, detail::internal_platform_timepoint const &timeout)
613         {
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;
619 #endif
620             unsigned timeout_index=~0U;
621             if(handle_to_wait_for!=detail::win32::invalid_handle_value)
622             {
623                 wait_handle_index=handle_count;
624                 handles[handle_count++]=handle_to_wait_for;
625             }
626 #if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
627             if(detail::get_current_thread_data() && detail::get_current_thread_data()->interruption_enabled)
628             {
629                 interruption_index=handle_count;
630                 handles[handle_count++]=detail::get_current_thread_data()->interruption_handle;
631             }
632 #endif
633             detail::win32::handle_manager timer_handle;
634 
635 #ifndef UNDER_CE
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())
639             {
640                 boost::intmax_t const time_left_msec = (timeout - detail::internal_platform_clock::now()).getMs();
641                 timer_handle=CreateWaitableTimer(NULL,false,NULL);
642                 if(timer_handle!=0)
643                 {
644                     ULONG tolerable=32; // Empirical testing shows Windows ignores this when <= 26
645                     if(time_left_msec/20>tolerable)  // 5%
646                         tolerable=static_cast<ULONG>(time_left_msec/20);
647                     LARGE_INTEGER due_time={{0,0}};
648                     if(time_left_msec>0)
649                     {
650                         due_time.QuadPart=-(time_left_msec*10000); // negative indicates relative time
651                     }
652                     bool const set_time_succeeded=detail_::SetWaitableTimerEx()(timer_handle,&due_time,0,0,0,NULL,tolerable)!=0;
653                     if(set_time_succeeded)
654                     {
655                         timeout_index=handle_count;
656                         handles[handle_count++]=timer_handle;
657                     }
658                 }
659             }
660 #endif
661 #endif
662 
663             bool const using_timer=timeout_index!=~0u;
664             boost::intmax_t time_left_msec(INFINITE);
665             if(!using_timer && timeout != detail::internal_platform_timepoint::getMax())
666             {
667                 time_left_msec = (timeout - detail::internal_platform_clock::now()).getMs();
668                 if(time_left_msec < 0)
669                 {
670                     time_left_msec = 0;
671                 }
672             }
673 
674             do
675             {
676                 if(handle_count)
677                 {
678                     unsigned long const notified_index=winapi::WaitForMultipleObjectsEx(handle_count,handles,false,static_cast<DWORD>(time_left_msec), 0);
679                     if(notified_index<handle_count)
680                     {
681                         if(notified_index==wait_handle_index)
682                         {
683                             return true;
684                         }
685 #if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
686                         else if(notified_index==interruption_index)
687                         {
688                             winapi::ResetEvent(detail::get_current_thread_data()->interruption_handle);
689                             throw thread_interrupted();
690                         }
691 #endif
692                         else if(notified_index==timeout_index)
693                         {
694                             return false;
695                         }
696                     }
697                 }
698                 else
699                 {
700                     detail::win32::sleep(static_cast<unsigned long>(time_left_msec));
701                 }
702 
703                 if(!using_timer && timeout != detail::internal_platform_timepoint::getMax())
704                 {
705                     time_left_msec = (timeout - detail::internal_platform_clock::now()).getMs();
706                 }
707             }
708             while(time_left_msec == INFINITE || time_left_msec > 0);
709             return false;
710         }
711 
712         namespace no_interruption_point
713         {
non_interruptible_wait(detail::win32::handle handle_to_wait_for,detail::internal_platform_timepoint const & timeout)714         bool non_interruptible_wait(detail::win32::handle handle_to_wait_for, detail::internal_platform_timepoint const &timeout)
715         {
716             detail::win32::handle handles[3]={0};
717             unsigned handle_count=0;
718             unsigned wait_handle_index=~0U;
719             unsigned timeout_index=~0U;
720             if(handle_to_wait_for!=detail::win32::invalid_handle_value)
721             {
722                 wait_handle_index=handle_count;
723                 handles[handle_count++]=handle_to_wait_for;
724             }
725             detail::win32::handle_manager timer_handle;
726 
727 #ifndef UNDER_CE
728 #if !BOOST_PLAT_WINDOWS_RUNTIME
729             // Preferentially use coalescing timers for better power consumption and timer accuracy
730             if(timeout != detail::internal_platform_timepoint::getMax())
731             {
732                 boost::intmax_t const time_left_msec = (timeout - detail::internal_platform_clock::now()).getMs();
733                 timer_handle=CreateWaitableTimer(NULL,false,NULL);
734                 if(timer_handle!=0)
735                 {
736                     ULONG tolerable=32; // Empirical testing shows Windows ignores this when <= 26
737                     if(time_left_msec/20>tolerable)  // 5%
738                         tolerable=static_cast<ULONG>(time_left_msec/20);
739                     LARGE_INTEGER due_time={{0,0}};
740                     if(time_left_msec>0)
741                     {
742                         due_time.QuadPart=-(time_left_msec*10000); // negative indicates relative time
743                     }
744                     bool const set_time_succeeded=detail_::SetWaitableTimerEx()(timer_handle,&due_time,0,0,0,NULL,tolerable)!=0;
745                     if(set_time_succeeded)
746                     {
747                         timeout_index=handle_count;
748                         handles[handle_count++]=timer_handle;
749                     }
750                 }
751             }
752 #endif
753 #endif
754 
755             bool const using_timer=timeout_index!=~0u;
756             boost::intmax_t time_left_msec(INFINITE);
757             if(!using_timer && timeout != detail::internal_platform_timepoint::getMax())
758             {
759                 time_left_msec = (timeout - detail::internal_platform_clock::now()).getMs();
760                 if(time_left_msec < 0)
761                 {
762                     time_left_msec = 0;
763                 }
764             }
765 
766             do
767             {
768                 if(handle_count)
769                 {
770                     unsigned long const notified_index=winapi::WaitForMultipleObjectsEx(handle_count,handles,false,static_cast<DWORD>(time_left_msec), 0);
771                     if(notified_index<handle_count)
772                     {
773                         if(notified_index==wait_handle_index)
774                         {
775                             return true;
776                         }
777                         else if(notified_index==timeout_index)
778                         {
779                             return false;
780                         }
781                     }
782                 }
783                 else
784                 {
785                     detail::win32::sleep(static_cast<unsigned long>(time_left_msec));
786                 }
787 
788                 if(!using_timer && timeout != detail::internal_platform_timepoint::getMax())
789                 {
790                     time_left_msec = (timeout - detail::internal_platform_clock::now()).getMs();
791                 }
792             }
793             while(time_left_msec == INFINITE || time_left_msec > 0);
794             return false;
795         }
796         }
797 
get_id()798         thread::id get_id() BOOST_NOEXCEPT
799         {
800 #if defined BOOST_THREAD_PROVIDES_BASIC_THREAD_ID
801 #if BOOST_PLAT_WINDOWS_RUNTIME
802             detail::thread_data_base* current_thread_data(detail::get_current_thread_data());
803             if (current_thread_data)
804             {
805                 return current_thread_data->id;
806             }
807 #endif
808             return winapi::GetCurrentThreadId();
809 #else
810             return thread::id(get_or_make_current_thread_data());
811 #endif
812         }
813 
814 #if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
interruption_point()815         void interruption_point()
816         {
817             if(interruption_enabled() && interruption_requested())
818             {
819                 winapi::ResetEvent(detail::get_current_thread_data()->interruption_handle);
820                 throw thread_interrupted();
821             }
822         }
823 
interruption_enabled()824         bool interruption_enabled() BOOST_NOEXCEPT
825         {
826             return detail::get_current_thread_data() && detail::get_current_thread_data()->interruption_enabled;
827         }
828 
interruption_requested()829         bool interruption_requested() BOOST_NOEXCEPT
830         {
831             return detail::get_current_thread_data() && (winapi::WaitForSingleObjectEx(detail::get_current_thread_data()->interruption_handle,0,0)==0);
832         }
833 #endif
834 
yield()835         void yield() BOOST_NOEXCEPT
836         {
837             detail::win32::sleep(0);
838         }
839 
840 #if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
disable_interruption()841         disable_interruption::disable_interruption() BOOST_NOEXCEPT:
842             interruption_was_enabled(interruption_enabled())
843         {
844             if(interruption_was_enabled)
845             {
846                 detail::get_current_thread_data()->interruption_enabled=false;
847             }
848         }
849 
~disable_interruption()850         disable_interruption::~disable_interruption() BOOST_NOEXCEPT
851         {
852             if(detail::get_current_thread_data())
853             {
854                 detail::get_current_thread_data()->interruption_enabled=interruption_was_enabled;
855             }
856         }
857 
restore_interruption(disable_interruption & d)858         restore_interruption::restore_interruption(disable_interruption& d) BOOST_NOEXCEPT
859         {
860             if(d.interruption_was_enabled)
861             {
862                 detail::get_current_thread_data()->interruption_enabled=true;
863             }
864         }
865 
~restore_interruption()866         restore_interruption::~restore_interruption() BOOST_NOEXCEPT
867         {
868             if(detail::get_current_thread_data())
869             {
870                 detail::get_current_thread_data()->interruption_enabled=false;
871             }
872         }
873 #endif
874     }
875 
876     namespace detail
877     {
add_thread_exit_function(thread_exit_function_base * func)878         void add_thread_exit_function(thread_exit_function_base* func)
879         {
880             detail::thread_data_base* const current_thread_data(get_or_make_current_thread_data());
881             thread_exit_callback_node* const new_node=
882                 heap_new<thread_exit_callback_node>(
883                     func,current_thread_data->thread_exit_callbacks);
884             current_thread_data->thread_exit_callbacks=new_node;
885         }
886 
find_tss_data(void const * key)887         tss_data_node* find_tss_data(void const* key)
888         {
889             detail::thread_data_base* const current_thread_data(get_current_thread_data());
890             if(current_thread_data)
891             {
892                 std::map<void const*,tss_data_node>::iterator current_node=
893                     current_thread_data->tss_data.find(key);
894                 if(current_node!=current_thread_data->tss_data.end())
895                 {
896                     return &current_node->second;
897                 }
898             }
899             return NULL;
900         }
901 
get_tss_data(void const * key)902         void* get_tss_data(void const* key)
903         {
904             if(tss_data_node* const current_node=find_tss_data(key))
905             {
906                 return current_node->value;
907             }
908             return NULL;
909         }
910 
add_new_tss_node(void const * key,detail::tss_data_node::cleanup_caller_t caller,detail::tss_data_node::cleanup_func_t func,void * tss_data)911         void add_new_tss_node(void const* key,
912                               detail::tss_data_node::cleanup_caller_t caller,
913                               detail::tss_data_node::cleanup_func_t func,
914                               void* tss_data)
915         {
916             detail::thread_data_base* const current_thread_data(get_or_make_current_thread_data());
917             current_thread_data->tss_data.insert(std::make_pair(key,tss_data_node(caller,func,tss_data)));
918         }
919 
erase_tss_node(void const * key)920         void erase_tss_node(void const* key)
921         {
922             detail::thread_data_base* const current_thread_data(get_or_make_current_thread_data());
923             current_thread_data->tss_data.erase(key);
924         }
925 
set_tss_data(void const * key,detail::tss_data_node::cleanup_caller_t caller,detail::tss_data_node::cleanup_func_t func,void * tss_data,bool cleanup_existing)926         void set_tss_data(void const* key,
927                           detail::tss_data_node::cleanup_caller_t caller,
928                           detail::tss_data_node::cleanup_func_t func,
929                           void* tss_data,bool cleanup_existing)
930         {
931             if(tss_data_node* const current_node=find_tss_data(key))
932             {
933                 if(cleanup_existing && current_node->func && (current_node->value!=0))
934                 {
935                     (*current_node->caller)(current_node->func,current_node->value);
936                 }
937                 if(func || (tss_data!=0))
938                 {
939                     current_node->caller=caller;
940                     current_node->func=func;
941                     current_node->value=tss_data;
942                 }
943                 else
944                 {
945                     erase_tss_node(key);
946                 }
947             }
948             else if(func || (tss_data!=0))
949             {
950                 add_new_tss_node(key,caller,func,tss_data);
951             }
952         }
953     }
954 
on_process_enter()955     BOOST_THREAD_DECL void __cdecl on_process_enter()
956     {}
957 
on_thread_enter()958     BOOST_THREAD_DECL void __cdecl on_thread_enter()
959     {}
960 
on_process_exit()961     BOOST_THREAD_DECL void __cdecl on_process_exit()
962     {
963         boost::cleanup_tls_key();
964     }
965 
on_thread_exit()966     BOOST_THREAD_DECL void __cdecl on_thread_exit()
967     {
968         boost::run_thread_exit_callbacks();
969     }
970 
notify_all_at_thread_exit(condition_variable & cond,unique_lock<mutex> lk)971     BOOST_THREAD_DECL void notify_all_at_thread_exit(condition_variable& cond, unique_lock<mutex> lk)
972     {
973       detail::thread_data_base* const current_thread_data(detail::get_current_thread_data());
974       if(current_thread_data)
975       {
976         current_thread_data->notify_all_at_thread_exit(&cond, lk.release());
977       }
978     }
979 }
980 
981