]> git.proxmox.com Git - ceph.git/blob - ceph/src/boost/libs/thread/src/win32/thread.cpp
update ceph source to reef 18.1.2
[ceph.git] / ceph / src / boost / libs / thread / src / win32 / thread.cpp
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 {
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
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
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
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 {
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_;
149 ThreadProxyData(func start_address,void* arglist) : start_address_(start_address), arglist_(arglist) {}
150 };
151
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
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
185 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
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 {
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
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
310 thread::thread() BOOST_NOEXCEPT
311 {}
312
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
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
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 {
365 externally_launched_thread()
366 {
367 ++count;
368 #if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
369 interruption_enabled=false;
370 #endif
371 }
372 ~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
381 void run()
382 {}
383 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
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
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
418 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
432 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 }
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
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
476 void thread::detach()
477 {
478 release_handle();
479 }
480
481 void thread::release_handle()
482 {
483 thread_info=0;
484 }
485
486 #if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
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
496 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
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
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
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
555 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);
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
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
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 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%
648 {
649 tolerable=static_cast<ULONG>(time_left_msec/20);
650 if(tolerable>max_tolerable)
651 tolerable=max_tolerable;
652 }
653 LARGE_INTEGER due_time={{0,0}};
654 if(time_left_msec>0)
655 {
656 due_time.QuadPart=-(time_left_msec*10000); // negative indicates relative time
657 }
658 bool const set_time_succeeded=detail_::SetWaitableTimerEx()(timer_handle,&due_time,0,0,0,NULL,tolerable)!=0;
659 if(set_time_succeeded)
660 {
661 timeout_index=handle_count;
662 handles[handle_count++]=timer_handle;
663 }
664 }
665 }
666 #endif
667 #endif
668
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())
672 {
673 time_left_msec = (timeout - detail::internal_platform_clock::now()).getMs();
674 if(time_left_msec < 0)
675 {
676 time_left_msec = 0;
677 }
678 }
679
680 do
681 {
682 if(handle_count)
683 {
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)
686 {
687 if(notified_index==wait_handle_index)
688 {
689 return true;
690 }
691 #if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
692 else if(notified_index==interruption_index)
693 {
694 winapi::ResetEvent(detail::get_current_thread_data()->interruption_handle);
695 throw thread_interrupted();
696 }
697 #endif
698 else if(notified_index==timeout_index)
699 {
700 return false;
701 }
702 }
703 }
704 else
705 {
706 detail::win32::sleep(static_cast<unsigned long>(time_left_msec));
707 }
708
709 if(!using_timer && timeout != detail::internal_platform_timepoint::getMax())
710 {
711 time_left_msec = (timeout - detail::internal_platform_clock::now()).getMs();
712 }
713 }
714 while(time_left_msec == INFINITE || time_left_msec > 0);
715 return false;
716 }
717
718 namespace no_interruption_point
719 {
720 bool non_interruptible_wait(detail::win32::handle handle_to_wait_for, detail::internal_platform_timepoint const &timeout)
721 {
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)
727 {
728 wait_handle_index=handle_count;
729 handles[handle_count++]=handle_to_wait_for;
730 }
731 detail::win32::handle_manager timer_handle;
732
733 #ifndef UNDER_CE
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())
737 {
738 boost::intmax_t const time_left_msec = (timeout - detail::internal_platform_clock::now()).getMs();
739 timer_handle=CreateWaitableTimer(NULL,false,NULL);
740 if(timer_handle!=0)
741 {
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%
746 {
747 tolerable=static_cast<ULONG>(time_left_msec/20);
748 if(tolerable>max_tolerable)
749 tolerable=max_tolerable;
750 }
751 LARGE_INTEGER due_time={{0,0}};
752 if(time_left_msec>0)
753 {
754 due_time.QuadPart=-(time_left_msec*10000); // negative indicates relative time
755 }
756 bool const set_time_succeeded=detail_::SetWaitableTimerEx()(timer_handle,&due_time,0,0,0,NULL,tolerable)!=0;
757 if(set_time_succeeded)
758 {
759 timeout_index=handle_count;
760 handles[handle_count++]=timer_handle;
761 }
762 }
763 }
764 #endif
765 #endif
766
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())
770 {
771 time_left_msec = (timeout - detail::internal_platform_clock::now()).getMs();
772 if(time_left_msec < 0)
773 {
774 time_left_msec = 0;
775 }
776 }
777
778 do
779 {
780 if(handle_count)
781 {
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)
784 {
785 if(notified_index==wait_handle_index)
786 {
787 return true;
788 }
789 else if(notified_index==timeout_index)
790 {
791 return false;
792 }
793 }
794 }
795 else
796 {
797 detail::win32::sleep(static_cast<unsigned long>(time_left_msec));
798 }
799
800 if(!using_timer && timeout != detail::internal_platform_timepoint::getMax())
801 {
802 time_left_msec = (timeout - detail::internal_platform_clock::now()).getMs();
803 }
804 }
805 while(time_left_msec == INFINITE || time_left_msec > 0);
806 return false;
807 }
808 }
809
810 thread::id get_id() BOOST_NOEXCEPT
811 {
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)
816 {
817 return current_thread_data->id;
818 }
819 #endif
820 return winapi::GetCurrentThreadId();
821 #else
822 return thread::id(get_or_make_current_thread_data());
823 #endif
824 }
825
826 #if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
827 void interruption_point()
828 {
829 if(interruption_enabled() && interruption_requested())
830 {
831 winapi::ResetEvent(detail::get_current_thread_data()->interruption_handle);
832 throw thread_interrupted();
833 }
834 }
835
836 bool interruption_enabled() BOOST_NOEXCEPT
837 {
838 return detail::get_current_thread_data() && detail::get_current_thread_data()->interruption_enabled;
839 }
840
841 bool interruption_requested() BOOST_NOEXCEPT
842 {
843 return detail::get_current_thread_data() && (winapi::WaitForSingleObjectEx(detail::get_current_thread_data()->interruption_handle,0,0)==0);
844 }
845 #endif
846
847 void yield() BOOST_NOEXCEPT
848 {
849 detail::win32::sleep(0);
850 }
851
852 #if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
853 disable_interruption::disable_interruption() BOOST_NOEXCEPT:
854 interruption_was_enabled(interruption_enabled())
855 {
856 if(interruption_was_enabled)
857 {
858 detail::get_current_thread_data()->interruption_enabled=false;
859 }
860 }
861
862 disable_interruption::~disable_interruption() BOOST_NOEXCEPT
863 {
864 if(detail::get_current_thread_data())
865 {
866 detail::get_current_thread_data()->interruption_enabled=interruption_was_enabled;
867 }
868 }
869
870 restore_interruption::restore_interruption(disable_interruption& d) BOOST_NOEXCEPT
871 {
872 if(d.interruption_was_enabled)
873 {
874 detail::get_current_thread_data()->interruption_enabled=true;
875 }
876 }
877
878 restore_interruption::~restore_interruption() BOOST_NOEXCEPT
879 {
880 if(detail::get_current_thread_data())
881 {
882 detail::get_current_thread_data()->interruption_enabled=false;
883 }
884 }
885 #endif
886 }
887
888 namespace detail
889 {
890 void add_thread_exit_function(thread_exit_function_base* func)
891 {
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;
897 }
898
899 tss_data_node* find_tss_data(void const* key)
900 {
901 detail::thread_data_base* const current_thread_data(get_current_thread_data());
902 if(current_thread_data)
903 {
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())
907 {
908 return &current_node->second;
909 }
910 }
911 return NULL;
912 }
913
914 void* get_tss_data(void const* key)
915 {
916 if(tss_data_node* const current_node=find_tss_data(key))
917 {
918 return current_node->value;
919 }
920 return NULL;
921 }
922
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,
926 void* tss_data)
927 {
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)));
930 }
931
932 void erase_tss_node(void const* key)
933 {
934 detail::thread_data_base* const current_thread_data(get_or_make_current_thread_data());
935 current_thread_data->tss_data.erase(key);
936 }
937
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)
942 {
943 if(tss_data_node* const current_node=find_tss_data(key))
944 {
945 if(cleanup_existing && current_node->func && (current_node->value!=0))
946 {
947 (*current_node->caller)(current_node->func,current_node->value);
948 }
949 if(func || (tss_data!=0))
950 {
951 current_node->caller=caller;
952 current_node->func=func;
953 current_node->value=tss_data;
954 }
955 else
956 {
957 erase_tss_node(key);
958 }
959 }
960 else if(func || (tss_data!=0))
961 {
962 add_new_tss_node(key,caller,func,tss_data);
963 }
964 }
965 }
966
967 BOOST_THREAD_DECL void __cdecl on_process_enter()
968 {}
969
970 BOOST_THREAD_DECL void __cdecl on_thread_enter()
971 {}
972
973 BOOST_THREAD_DECL void __cdecl on_process_exit()
974 {
975 boost::cleanup_tls_key();
976 }
977
978 BOOST_THREAD_DECL void __cdecl on_thread_exit()
979 {
980 boost::run_thread_exit_callbacks();
981 }
982
983 BOOST_THREAD_DECL void notify_all_at_thread_exit(condition_variable& cond, unique_lock<mutex> lk)
984 {
985 detail::thread_data_base* const current_thread_data(detail::get_current_thread_data());
986 if(current_thread_data)
987 {
988 current_thread_data->notify_all_at_thread_exit(&cond, lk.release());
989 }
990 }
991 }
992