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