]> git.proxmox.com Git - ceph.git/blob - ceph/src/boost/libs/thread/src/win32/thread.cpp
update sources to v12.2.3
[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-2017 Vicente J. Botet Escriba
7
8 //#define BOOST_THREAD_VERSION 3
9
10 #include <boost/detail/winapi/config.hpp>
11 #include <boost/thread/thread_only.hpp>
12 #include <boost/thread/once.hpp>
13 #include <boost/thread/tss.hpp>
14 #include <boost/thread/condition_variable.hpp>
15 #include <boost/thread/detail/tss_hooks.hpp>
16 #include <boost/thread/future.hpp>
17 #include <boost/assert.hpp>
18 #include <boost/cstdint.hpp>
19 #if defined BOOST_THREAD_USES_DATETIME
20 #include <boost/date_time/posix_time/conversion.hpp>
21 #include <boost/thread/thread_time.hpp>
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::timeout::sentinel());
443 release_handle();
444 return true;
445 }
446 else
447 {
448 return false;
449 }
450 }
451
452 #if defined BOOST_THREAD_USES_DATETIME
453 bool thread::timed_join(boost::system_time const& wait_until)
454 {
455 return do_try_join_until(boost::detail::get_milliseconds_until(wait_until));
456 }
457 #endif
458 bool thread::do_try_join_until_noexcept(uintmax_t milli, bool& res)
459 {
460 detail::thread_data_ptr local_thread_info=(get_thread_info)();
461 if(local_thread_info)
462 {
463 if(!this_thread::interruptible_wait(this->native_handle(),milli))
464 {
465 res=false;
466 return true;
467 }
468 release_handle();
469 res=true;
470 return true;
471 }
472 else
473 {
474 return false;
475 }
476 }
477
478 void thread::detach()
479 {
480 release_handle();
481 }
482
483 void thread::release_handle()
484 {
485 thread_info=0;
486 }
487
488 #if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
489 void thread::interrupt()
490 {
491 detail::thread_data_ptr local_thread_info=(get_thread_info)();
492 if(local_thread_info)
493 {
494 local_thread_info->interrupt();
495 }
496 }
497
498 bool thread::interruption_requested() const BOOST_NOEXCEPT
499 {
500 detail::thread_data_ptr local_thread_info=(get_thread_info)();
501 return local_thread_info.get() && (detail::winapi::WaitForSingleObjectEx(local_thread_info->interruption_handle,0,0)==0);
502 }
503
504 #endif
505
506 unsigned thread::hardware_concurrency() BOOST_NOEXCEPT
507 {
508 detail::win32::system_info info;
509 detail::win32::get_system_info(&info);
510 return info.dwNumberOfProcessors;
511 }
512
513 unsigned thread::physical_concurrency() BOOST_NOEXCEPT
514 {
515 // a bit too strict: Windows XP with SP3 would be sufficient
516 #if BOOST_PLAT_WINDOWS_RUNTIME \
517 || ( BOOST_USE_WINAPI_VERSION <= BOOST_WINAPI_VERSION_WINXP ) \
518 || ( ( defined(__MINGW32__) && !defined(__MINGW64__) ) && _WIN32_WINNT < 0x0600)
519 return 0;
520 #else
521 unsigned cores = 0;
522 DWORD size = 0;
523
524 GetLogicalProcessorInformation(NULL, &size);
525 if (ERROR_INSUFFICIENT_BUFFER != GetLastError())
526 return 0;
527
528 std::vector<SYSTEM_LOGICAL_PROCESSOR_INFORMATION> buffer(size);
529 if (GetLogicalProcessorInformation(&buffer.front(), &size) == FALSE)
530 return 0;
531
532 const size_t Elements = size / sizeof(SYSTEM_LOGICAL_PROCESSOR_INFORMATION);
533
534 for (size_t i = 0; i < Elements; ++i) {
535 if (buffer[i].Relationship == RelationProcessorCore)
536 ++cores;
537 }
538 return cores;
539 #endif
540 }
541
542 thread::native_handle_type thread::native_handle()
543 {
544 detail::thread_data_ptr local_thread_info=(get_thread_info)();
545 if(!local_thread_info)
546 {
547 return detail::win32::invalid_handle_value;
548 }
549 #if BOOST_PLAT_WINDOWS_RUNTIME
550 // There is no 'real' Win32 handle so we return a handle that at least can be waited on.
551 return local_thread_info->thread_handle.waitable_handle();
552 #else
553 return (detail::win32::handle)local_thread_info->thread_handle;
554 #endif
555 }
556
557 detail::thread_data_ptr thread::get_thread_info BOOST_PREVENT_MACRO_SUBSTITUTION () const
558 {
559 return thread_info;
560 }
561
562 namespace this_thread
563 {
564 namespace
565 {
566 LARGE_INTEGER get_due_time(detail::timeout const& target_time)
567 {
568 LARGE_INTEGER due_time={{0,0}};
569 if(target_time.relative)
570 {
571 detail::win32::ticks_type const elapsed_milliseconds=detail::win32::GetTickCount64_()()-target_time.start;
572 LONGLONG const remaining_milliseconds=(target_time.milliseconds-elapsed_milliseconds);
573 LONGLONG const hundred_nanoseconds_in_one_millisecond=10000;
574
575 if(remaining_milliseconds>0)
576 {
577 due_time.QuadPart=-(remaining_milliseconds*hundred_nanoseconds_in_one_millisecond);
578 }
579 }
580 else
581 {
582 SYSTEMTIME target_system_time={0,0,0,0,0,0,0,0};
583 target_system_time.wYear=target_time.abs_time.date().year();
584 target_system_time.wMonth=target_time.abs_time.date().month();
585 target_system_time.wDay=target_time.abs_time.date().day();
586 target_system_time.wHour=(WORD)target_time.abs_time.time_of_day().hours();
587 target_system_time.wMinute=(WORD)target_time.abs_time.time_of_day().minutes();
588 target_system_time.wSecond=(WORD)target_time.abs_time.time_of_day().seconds();
589
590 if(!SystemTimeToFileTime(&target_system_time,((FILETIME*)&due_time)))
591 {
592 due_time.QuadPart=0;
593 }
594 else
595 {
596 long const hundred_nanoseconds_in_one_second=10000000;
597 posix_time::time_duration::tick_type const ticks_per_second=
598 target_time.abs_time.time_of_day().ticks_per_second();
599 if(ticks_per_second>hundred_nanoseconds_in_one_second)
600 {
601 posix_time::time_duration::tick_type const
602 ticks_per_hundred_nanoseconds=
603 ticks_per_second/hundred_nanoseconds_in_one_second;
604 due_time.QuadPart+=
605 target_time.abs_time.time_of_day().fractional_seconds()/
606 ticks_per_hundred_nanoseconds;
607 }
608 else
609 {
610 due_time.QuadPart+=
611 target_time.abs_time.time_of_day().fractional_seconds()*
612 (hundred_nanoseconds_in_one_second/ticks_per_second);
613 }
614 }
615 }
616 return due_time;
617 }
618 }
619
620 #ifndef UNDER_CE
621 #if !BOOST_PLAT_WINDOWS_RUNTIME
622 namespace detail_
623 {
624 typedef struct _REASON_CONTEXT {
625 ULONG Version;
626 DWORD Flags;
627 union {
628 LPWSTR SimpleReasonString;
629 struct {
630 HMODULE LocalizedReasonModule;
631 ULONG LocalizedReasonId;
632 ULONG ReasonStringCount;
633 LPWSTR *ReasonStrings;
634 } Detailed;
635 } Reason;
636 } REASON_CONTEXT, *PREASON_CONTEXT;
637 typedef BOOL (WINAPI *setwaitabletimerex_t)(HANDLE, const LARGE_INTEGER *, LONG, PTIMERAPCROUTINE, LPVOID, PREASON_CONTEXT, ULONG);
638 static inline BOOL WINAPI SetWaitableTimerEx_emulation(HANDLE hTimer, const LARGE_INTEGER *lpDueTime, LONG lPeriod, PTIMERAPCROUTINE pfnCompletionRoutine, LPVOID lpArgToCompletionRoutine, PREASON_CONTEXT WakeContext, ULONG TolerableDelay)
639 {
640 return SetWaitableTimer(hTimer, lpDueTime, lPeriod, pfnCompletionRoutine, lpArgToCompletionRoutine, FALSE);
641 }
642 #ifdef _MSC_VER
643 #pragma warning(push)
644 #pragma warning(disable: 6387) // MSVC sanitiser warns that GetModuleHandleA() might fail
645 #endif
646 static inline setwaitabletimerex_t SetWaitableTimerEx()
647 {
648 static setwaitabletimerex_t setwaitabletimerex_impl;
649 if(setwaitabletimerex_impl)
650 return setwaitabletimerex_impl;
651 void (*addr)()=(void (*)()) GetProcAddress(
652 #if !defined(BOOST_NO_ANSI_APIS)
653 GetModuleHandleA("KERNEL32.DLL"),
654 #else
655 GetModuleHandleW(L"KERNEL32.DLL"),
656 #endif
657 "SetWaitableTimerEx");
658 if(addr)
659 setwaitabletimerex_impl=(setwaitabletimerex_t) addr;
660 else
661 setwaitabletimerex_impl=&SetWaitableTimerEx_emulation;
662 return setwaitabletimerex_impl;
663 }
664 #ifdef _MSC_VER
665 #pragma warning(pop)
666 #endif
667 }
668 #endif
669 #endif
670 bool interruptible_wait(detail::win32::handle handle_to_wait_for,detail::timeout target_time)
671 {
672 detail::win32::handle handles[4]={0};
673 unsigned handle_count=0;
674 unsigned wait_handle_index=~0U;
675 #if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
676 unsigned interruption_index=~0U;
677 #endif
678 unsigned timeout_index=~0U;
679 if(handle_to_wait_for!=detail::win32::invalid_handle_value)
680 {
681 wait_handle_index=handle_count;
682 handles[handle_count++]=handle_to_wait_for;
683 }
684 #if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
685 if(detail::get_current_thread_data() && detail::get_current_thread_data()->interruption_enabled)
686 {
687 interruption_index=handle_count;
688 handles[handle_count++]=detail::get_current_thread_data()->interruption_handle;
689 }
690 #endif
691 detail::win32::handle_manager timer_handle;
692
693 #ifndef UNDER_CE
694 #if !BOOST_PLAT_WINDOWS_RUNTIME
695 // Preferentially use coalescing timers for better power consumption and timer accuracy
696 if(!target_time.is_sentinel())
697 {
698 detail::timeout::remaining_time const time_left=target_time.remaining_milliseconds();
699 timer_handle=CreateWaitableTimer(NULL,false,NULL);
700 if(timer_handle!=0)
701 {
702 ULONG tolerable=32; // Empirical testing shows Windows ignores this when <= 26
703 if(time_left.milliseconds/20>tolerable) // 5%
704 tolerable=time_left.milliseconds/20;
705 LARGE_INTEGER due_time=get_due_time(target_time);
706 bool const set_time_succeeded=detail_::SetWaitableTimerEx()(timer_handle,&due_time,0,0,0,NULL,tolerable)!=0;
707 if(set_time_succeeded)
708 {
709 timeout_index=handle_count;
710 handles[handle_count++]=timer_handle;
711 }
712 }
713 }
714 #endif
715 #endif
716
717 bool const using_timer=timeout_index!=~0u;
718 detail::timeout::remaining_time time_left(0);
719
720 do
721 {
722 if(!using_timer)
723 {
724 time_left=target_time.remaining_milliseconds();
725 }
726
727 if(handle_count)
728 {
729 unsigned long const notified_index=detail::winapi::WaitForMultipleObjectsEx(handle_count,handles,false,using_timer?INFINITE:time_left.milliseconds, 0);
730 if(notified_index<handle_count)
731 {
732 if(notified_index==wait_handle_index)
733 {
734 return true;
735 }
736 #if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
737 else if(notified_index==interruption_index)
738 {
739 detail::winapi::ResetEvent(detail::get_current_thread_data()->interruption_handle);
740 throw thread_interrupted();
741 }
742 #endif
743 else if(notified_index==timeout_index)
744 {
745 return false;
746 }
747 }
748 }
749 else
750 {
751 detail::win32::sleep(time_left.milliseconds);
752 }
753 if(target_time.relative)
754 {
755 target_time.milliseconds-=detail::timeout::max_non_infinite_wait;
756 }
757 }
758 while(time_left.more);
759 return false;
760 }
761
762 namespace no_interruption_point
763 {
764 bool non_interruptible_wait(detail::win32::handle handle_to_wait_for,detail::timeout target_time)
765 {
766 detail::win32::handle handles[3]={0};
767 unsigned handle_count=0;
768 unsigned wait_handle_index=~0U;
769 unsigned timeout_index=~0U;
770 if(handle_to_wait_for!=detail::win32::invalid_handle_value)
771 {
772 wait_handle_index=handle_count;
773 handles[handle_count++]=handle_to_wait_for;
774 }
775 detail::win32::handle_manager timer_handle;
776
777 #ifndef UNDER_CE
778 #if !BOOST_PLAT_WINDOWS_RUNTIME
779 // Preferentially use coalescing timers for better power consumption and timer accuracy
780 if(!target_time.is_sentinel())
781 {
782 detail::timeout::remaining_time const time_left=target_time.remaining_milliseconds();
783 timer_handle=CreateWaitableTimer(NULL,false,NULL);
784 if(timer_handle!=0)
785 {
786 ULONG tolerable=32; // Empirical testing shows Windows ignores this when <= 26
787 if(time_left.milliseconds/20>tolerable) // 5%
788 tolerable=time_left.milliseconds/20;
789 LARGE_INTEGER due_time=get_due_time(target_time);
790 bool const set_time_succeeded=detail_::SetWaitableTimerEx()(timer_handle,&due_time,0,0,0,NULL,tolerable)!=0;
791 if(set_time_succeeded)
792 {
793 timeout_index=handle_count;
794 handles[handle_count++]=timer_handle;
795 }
796 }
797 }
798 #endif
799 #endif
800
801 bool const using_timer=timeout_index!=~0u;
802 detail::timeout::remaining_time time_left(0);
803
804 do
805 {
806 if(!using_timer)
807 {
808 time_left=target_time.remaining_milliseconds();
809 }
810
811 if(handle_count)
812 {
813 unsigned long const notified_index=detail::winapi::WaitForMultipleObjectsEx(handle_count,handles,false,using_timer?INFINITE:time_left.milliseconds, 0);
814 if(notified_index<handle_count)
815 {
816 if(notified_index==wait_handle_index)
817 {
818 return true;
819 }
820 else if(notified_index==timeout_index)
821 {
822 return false;
823 }
824 }
825 }
826 else
827 {
828 detail::win32::sleep(time_left.milliseconds);
829 }
830 if(target_time.relative)
831 {
832 target_time.milliseconds-=detail::timeout::max_non_infinite_wait;
833 }
834 }
835 while(time_left.more);
836 return false;
837 }
838 }
839
840 thread::id get_id() BOOST_NOEXCEPT
841 {
842 #if defined BOOST_THREAD_PROVIDES_BASIC_THREAD_ID
843 #if BOOST_PLAT_WINDOWS_RUNTIME
844 detail::thread_data_base* current_thread_data(detail::get_current_thread_data());
845 if (current_thread_data)
846 {
847 return current_thread_data->id;
848 }
849 #endif
850 return detail::winapi::GetCurrentThreadId();
851 #else
852 return thread::id(get_or_make_current_thread_data());
853 #endif
854 }
855
856 #if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
857 void interruption_point()
858 {
859 if(interruption_enabled() && interruption_requested())
860 {
861 detail::winapi::ResetEvent(detail::get_current_thread_data()->interruption_handle);
862 throw thread_interrupted();
863 }
864 }
865
866 bool interruption_enabled() BOOST_NOEXCEPT
867 {
868 return detail::get_current_thread_data() && detail::get_current_thread_data()->interruption_enabled;
869 }
870
871 bool interruption_requested() BOOST_NOEXCEPT
872 {
873 return detail::get_current_thread_data() && (detail::winapi::WaitForSingleObjectEx(detail::get_current_thread_data()->interruption_handle,0,0)==0);
874 }
875 #endif
876
877 void yield() BOOST_NOEXCEPT
878 {
879 detail::win32::sleep(0);
880 }
881
882 #if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
883 disable_interruption::disable_interruption() BOOST_NOEXCEPT:
884 interruption_was_enabled(interruption_enabled())
885 {
886 if(interruption_was_enabled)
887 {
888 detail::get_current_thread_data()->interruption_enabled=false;
889 }
890 }
891
892 disable_interruption::~disable_interruption() BOOST_NOEXCEPT
893 {
894 if(detail::get_current_thread_data())
895 {
896 detail::get_current_thread_data()->interruption_enabled=interruption_was_enabled;
897 }
898 }
899
900 restore_interruption::restore_interruption(disable_interruption& d) BOOST_NOEXCEPT
901 {
902 if(d.interruption_was_enabled)
903 {
904 detail::get_current_thread_data()->interruption_enabled=true;
905 }
906 }
907
908 restore_interruption::~restore_interruption() BOOST_NOEXCEPT
909 {
910 if(detail::get_current_thread_data())
911 {
912 detail::get_current_thread_data()->interruption_enabled=false;
913 }
914 }
915 #endif
916 }
917
918 namespace detail
919 {
920 void add_thread_exit_function(thread_exit_function_base* func)
921 {
922 detail::thread_data_base* const current_thread_data(get_or_make_current_thread_data());
923 thread_exit_callback_node* const new_node=
924 heap_new<thread_exit_callback_node>(
925 func,current_thread_data->thread_exit_callbacks);
926 current_thread_data->thread_exit_callbacks=new_node;
927 }
928
929 tss_data_node* find_tss_data(void const* key)
930 {
931 detail::thread_data_base* const current_thread_data(get_current_thread_data());
932 if(current_thread_data)
933 {
934 std::map<void const*,tss_data_node>::iterator current_node=
935 current_thread_data->tss_data.find(key);
936 if(current_node!=current_thread_data->tss_data.end())
937 {
938 return &current_node->second;
939 }
940 }
941 return NULL;
942 }
943
944 void* get_tss_data(void const* key)
945 {
946 if(tss_data_node* const current_node=find_tss_data(key))
947 {
948 return current_node->value;
949 }
950 return NULL;
951 }
952
953 void add_new_tss_node(void const* key,
954 boost::shared_ptr<tss_cleanup_function> func,
955 void* tss_data)
956 {
957 detail::thread_data_base* const current_thread_data(get_or_make_current_thread_data());
958 current_thread_data->tss_data.insert(std::make_pair(key,tss_data_node(func,tss_data)));
959 }
960
961 void erase_tss_node(void const* key)
962 {
963 detail::thread_data_base* const current_thread_data(get_or_make_current_thread_data());
964 current_thread_data->tss_data.erase(key);
965 }
966
967 void set_tss_data(void const* key,
968 boost::shared_ptr<tss_cleanup_function> func,
969 void* tss_data,bool cleanup_existing)
970 {
971 if(tss_data_node* const current_node=find_tss_data(key))
972 {
973 if(cleanup_existing && current_node->func && (current_node->value!=0))
974 {
975 (*current_node->func)(current_node->value);
976 }
977 if(func || (tss_data!=0))
978 {
979 current_node->func=func;
980 current_node->value=tss_data;
981 }
982 else
983 {
984 erase_tss_node(key);
985 }
986 }
987 else if(func || (tss_data!=0))
988 {
989 add_new_tss_node(key,func,tss_data);
990 }
991 }
992 }
993
994 BOOST_THREAD_DECL void __cdecl on_process_enter()
995 {}
996
997 BOOST_THREAD_DECL void __cdecl on_thread_enter()
998 {}
999
1000 BOOST_THREAD_DECL void __cdecl on_process_exit()
1001 {
1002 boost::cleanup_tls_key();
1003 }
1004
1005 BOOST_THREAD_DECL void __cdecl on_thread_exit()
1006 {
1007 boost::run_thread_exit_callbacks();
1008 }
1009
1010 BOOST_THREAD_DECL void notify_all_at_thread_exit(condition_variable& cond, unique_lock<mutex> lk)
1011 {
1012 detail::thread_data_base* const current_thread_data(detail::get_current_thread_data());
1013 if(current_thread_data)
1014 {
1015 current_thread_data->notify_all_at_thread_exit(&cond, lk.release());
1016 }
1017 }
1018 }
1019