]> git.proxmox.com Git - ceph.git/blob - ceph/src/boost/boost/thread/win32/thread_primitives.hpp
update sources to v12.2.3
[ceph.git] / ceph / src / boost / boost / thread / win32 / thread_primitives.hpp
1 #ifndef BOOST_WIN32_THREAD_PRIMITIVES_HPP
2 #define BOOST_WIN32_THREAD_PRIMITIVES_HPP
3
4 // win32_thread_primitives.hpp
5 //
6 // (C) Copyright 2005-7 Anthony Williams
7 // (C) Copyright 2007 David Deakins
8 //
9 // Distributed under the Boost Software License, Version 1.0. (See
10 // accompanying file LICENSE_1_0.txt or copy at
11 // http://www.boost.org/LICENSE_1_0.txt)
12
13 #include <boost/thread/detail/config.hpp>
14 #include <boost/predef/platform.h>
15 #include <boost/throw_exception.hpp>
16 #include <boost/assert.hpp>
17 #include <boost/thread/exceptions.hpp>
18 #include <boost/detail/interlocked.hpp>
19 #include <boost/detail/winapi/config.hpp>
20
21 #include <boost/detail/winapi/semaphore.hpp>
22 #include <boost/detail/winapi/dll.hpp>
23 #include <boost/detail/winapi/system.hpp>
24 #include <boost/detail/winapi/time.hpp>
25 #include <boost/detail/winapi/event.hpp>
26 #include <boost/detail/winapi/thread.hpp>
27 #include <boost/detail/winapi/get_current_thread.hpp>
28 #include <boost/detail/winapi/get_current_thread_id.hpp>
29 #include <boost/detail/winapi/get_current_process.hpp>
30 #include <boost/detail/winapi/get_current_process_id.hpp>
31 #include <boost/detail/winapi/wait.hpp>
32 #include <boost/detail/winapi/handles.hpp>
33 #include <boost/detail/winapi/access_rights.hpp>
34
35 //#include <boost/detail/winapi/synchronization.hpp>
36 #include <boost/thread/win32/interlocked_read.hpp>
37 #include <algorithm>
38
39 #if BOOST_PLAT_WINDOWS_RUNTIME
40 #include <thread>
41 #endif
42
43 namespace boost
44 {
45 namespace detail
46 {
47 namespace win32
48 {
49 typedef ::boost::detail::winapi::HANDLE_ handle;
50 typedef ::boost::detail::winapi::SYSTEM_INFO_ system_info;
51 typedef unsigned __int64 ticks_type;
52 typedef ::boost::detail::winapi::FARPROC_ farproc_t;
53 unsigned const infinite=::boost::detail::winapi::INFINITE_;
54 unsigned const timeout=::boost::detail::winapi::WAIT_TIMEOUT_;
55 handle const invalid_handle_value=::boost::detail::winapi::INVALID_HANDLE_VALUE_;
56 unsigned const event_modify_state=::boost::detail::winapi::EVENT_MODIFY_STATE_;
57 unsigned const synchronize=::boost::detail::winapi::SYNCHRONIZE_;
58 unsigned const wait_abandoned=::boost::detail::winapi::WAIT_ABANDONED_;
59 unsigned const create_event_initial_set = 0x00000002;
60 unsigned const create_event_manual_reset = 0x00000001;
61 unsigned const event_all_access = ::boost::detail::winapi::EVENT_ALL_ACCESS_;
62 unsigned const semaphore_all_access = boost::detail::winapi::SEMAPHORE_ALL_ACCESS_;
63 }
64 }
65 }
66
67 #include <boost/config/abi_prefix.hpp>
68
69 namespace boost
70 {
71 namespace detail
72 {
73 namespace win32
74 {
75 namespace detail { typedef ticks_type (__stdcall *gettickcount64_t)(); }
76 #if !BOOST_PLAT_WINDOWS_RUNTIME
77 extern "C"
78 {
79 #ifdef _MSC_VER
80 long _InterlockedCompareExchange(long volatile *, long, long);
81 #pragma intrinsic(_InterlockedCompareExchange)
82 #elif defined(__MINGW64_VERSION_MAJOR)
83 long _InterlockedCompareExchange(long volatile *, long, long);
84 #else
85 // Mingw doesn't provide intrinsics
86 #define _InterlockedCompareExchange InterlockedCompareExchange
87 #endif
88 }
89 // Borrowed from https://stackoverflow.com/questions/8211820/userland-interrupt-timer-access-such-as-via-kequeryinterrupttime-or-similar
90 inline ticks_type __stdcall GetTickCount64emulation()
91 {
92 static long count = -1l;
93 unsigned long previous_count, current_tick32, previous_count_zone, current_tick32_zone;
94 ticks_type current_tick64;
95
96 previous_count = (unsigned long) boost::detail::interlocked_read_acquire(&count);
97 current_tick32 = ::boost::detail::winapi::GetTickCount();
98
99 if(previous_count == (unsigned long)-1l)
100 {
101 // count has never been written
102 unsigned long initial_count;
103 initial_count = current_tick32 >> 28;
104 previous_count = (unsigned long) _InterlockedCompareExchange(&count, (long)initial_count, -1l);
105
106 current_tick64 = initial_count;
107 current_tick64 <<= 28;
108 current_tick64 += current_tick32 & 0x0FFFFFFF;
109 return current_tick64;
110 }
111
112 previous_count_zone = previous_count & 15;
113 current_tick32_zone = current_tick32 >> 28;
114
115 if(current_tick32_zone == previous_count_zone)
116 {
117 // The top four bits of the 32-bit tick count haven't changed since count was last written.
118 current_tick64 = previous_count;
119 current_tick64 <<= 28;
120 current_tick64 += current_tick32 & 0x0FFFFFFF;
121 return current_tick64;
122 }
123
124 if(current_tick32_zone == previous_count_zone + 1 || (current_tick32_zone == 0 && previous_count_zone == 15))
125 {
126 // The top four bits of the 32-bit tick count have been incremented since count was last written.
127 unsigned long new_count = previous_count + 1;
128 _InterlockedCompareExchange(&count, (long)new_count, (long)previous_count);
129 current_tick64 = new_count;
130 current_tick64 <<= 28;
131 current_tick64 += current_tick32 & 0x0FFFFFFF;
132 return current_tick64;
133 }
134
135 // Oops, we weren't called often enough, we're stuck
136 return 0xFFFFFFFF;
137 }
138 #else
139 #endif
140 inline detail::gettickcount64_t GetTickCount64_()
141 {
142 static detail::gettickcount64_t gettickcount64impl;
143 if(gettickcount64impl)
144 return gettickcount64impl;
145
146 // GetTickCount and GetModuleHandle are not allowed in the Windows Runtime,
147 // and kernel32 isn't used in Windows Phone.
148 #if BOOST_PLAT_WINDOWS_RUNTIME
149 gettickcount64impl = &::boost::detail::winapi::GetTickCount64;
150 #else
151 farproc_t addr=GetProcAddress(
152 #if !defined(BOOST_NO_ANSI_APIS)
153 ::boost::detail::winapi::GetModuleHandleA("KERNEL32.DLL"),
154 #else
155 ::boost::detail::winapi::GetModuleHandleW(L"KERNEL32.DLL"),
156 #endif
157 "GetTickCount64");
158 if(addr)
159 gettickcount64impl=(detail::gettickcount64_t) addr;
160 else
161 gettickcount64impl=&GetTickCount64emulation;
162 #endif
163 return gettickcount64impl;
164 }
165
166 enum event_type
167 {
168 auto_reset_event=false,
169 manual_reset_event=true
170 };
171
172 enum initial_event_state
173 {
174 event_initially_reset=false,
175 event_initially_set=true
176 };
177
178 inline handle create_event(
179 #if !defined(BOOST_NO_ANSI_APIS)
180 const char *mutex_name,
181 #else
182 const wchar_t *mutex_name,
183 #endif
184 event_type type,
185 initial_event_state state)
186 {
187 #if !defined(BOOST_NO_ANSI_APIS)
188 handle const res = ::boost::detail::winapi::CreateEventA(0, type, state, mutex_name);
189 #elif BOOST_USE_WINAPI_VERSION < BOOST_WINAPI_VERSION_VISTA
190 handle const res = ::boost::detail::winapi::CreateEventW(0, type, state, mutex_name);
191 #else
192 handle const res = ::boost::detail::winapi::CreateEventExW(
193 0,
194 mutex_name,
195 type ? create_event_manual_reset : 0 | state ? create_event_initial_set : 0,
196 event_all_access);
197 #endif
198 return res;
199 }
200
201 inline handle create_anonymous_event(event_type type,initial_event_state state)
202 {
203 handle const res = create_event(0, type, state);
204 if(!res)
205 {
206 boost::throw_exception(thread_resource_error());
207 }
208 return res;
209 }
210
211 inline handle create_anonymous_semaphore_nothrow(long initial_count,long max_count)
212 {
213 #if !defined(BOOST_NO_ANSI_APIS)
214 handle const res=::boost::detail::winapi::CreateSemaphoreA(0,initial_count,max_count,0);
215 #else
216 #if BOOST_USE_WINAPI_VERSION < BOOST_WINAPI_VERSION_VISTA
217 handle const res=::boost::detail::winapi::CreateSemaphoreEx(0,initial_count,max_count,0,0);
218 #else
219 handle const res=::boost::detail::winapi::CreateSemaphoreExW(0,initial_count,max_count,0,0,semaphore_all_access);
220 #endif
221 #endif
222 return res;
223 }
224
225 inline handle create_anonymous_semaphore(long initial_count,long max_count)
226 {
227 handle const res=create_anonymous_semaphore_nothrow(initial_count,max_count);
228 if(!res)
229 {
230 boost::throw_exception(thread_resource_error());
231 }
232 return res;
233 }
234
235 inline handle duplicate_handle(handle source)
236 {
237 handle const current_process=::boost::detail::winapi::GetCurrentProcess();
238 long const same_access_flag=2;
239 handle new_handle=0;
240 bool const success=::boost::detail::winapi::DuplicateHandle(current_process,source,current_process,&new_handle,0,false,same_access_flag)!=0;
241 if(!success)
242 {
243 boost::throw_exception(thread_resource_error());
244 }
245 return new_handle;
246 }
247
248 inline void release_semaphore(handle semaphore,long count)
249 {
250 BOOST_VERIFY(::boost::detail::winapi::ReleaseSemaphore(semaphore,count,0)!=0);
251 }
252
253 inline void get_system_info(system_info *info)
254 {
255 #if BOOST_PLAT_WINDOWS_RUNTIME
256 ::boost::detail::winapi::GetNativeSystemInfo(info);
257 #else
258 ::boost::detail::winapi::GetSystemInfo(info);
259 #endif
260 }
261
262 inline void sleep(unsigned long milliseconds)
263 {
264 if(milliseconds == 0)
265 {
266 #if BOOST_PLAT_WINDOWS_RUNTIME
267 std::this_thread::yield();
268 #else
269 ::boost::detail::winapi::Sleep(0);
270 #endif
271 }
272 else
273 {
274 #if BOOST_PLAT_WINDOWS_RUNTIME
275 ::boost::detail::winapi::WaitForSingleObjectEx(::boost::detail::winapi::GetCurrentThread(), milliseconds, 0);
276 #else
277 ::boost::detail::winapi::Sleep(milliseconds);
278 #endif
279 }
280 }
281
282 #if BOOST_PLAT_WINDOWS_RUNTIME
283 class BOOST_THREAD_DECL scoped_winrt_thread
284 {
285 public:
286 scoped_winrt_thread() : m_completionHandle(invalid_handle_value)
287 {}
288
289 ~scoped_winrt_thread()
290 {
291 if (m_completionHandle != ::boost::detail::win32::invalid_handle_value)
292 {
293 ::boost::detail::winapi::CloseHandle(m_completionHandle);
294 }
295 }
296
297 typedef unsigned(__stdcall * thread_func)(void *);
298 bool start(thread_func address, void *parameter, unsigned int *thrdId);
299
300 handle waitable_handle() const
301 {
302 BOOST_ASSERT(m_completionHandle != ::boost::detail::win32::invalid_handle_value);
303 return m_completionHandle;
304 }
305
306 private:
307 handle m_completionHandle;
308 };
309 #endif
310 class BOOST_THREAD_DECL handle_manager
311 {
312 private:
313 handle handle_to_manage;
314 handle_manager(handle_manager&);
315 handle_manager& operator=(handle_manager&);
316
317 void cleanup()
318 {
319 if(handle_to_manage && handle_to_manage!=invalid_handle_value)
320 {
321 BOOST_VERIFY(::boost::detail::winapi::CloseHandle(handle_to_manage));
322 }
323 }
324
325 public:
326 explicit handle_manager(handle handle_to_manage_):
327 handle_to_manage(handle_to_manage_)
328 {}
329 handle_manager():
330 handle_to_manage(0)
331 {}
332
333 handle_manager& operator=(handle new_handle)
334 {
335 cleanup();
336 handle_to_manage=new_handle;
337 return *this;
338 }
339
340 operator handle() const
341 {
342 return handle_to_manage;
343 }
344
345 handle duplicate() const
346 {
347 return duplicate_handle(handle_to_manage);
348 }
349
350 void swap(handle_manager& other)
351 {
352 std::swap(handle_to_manage,other.handle_to_manage);
353 }
354
355 handle release()
356 {
357 handle const res=handle_to_manage;
358 handle_to_manage=0;
359 return res;
360 }
361
362 bool operator!() const
363 {
364 return !handle_to_manage;
365 }
366
367 ~handle_manager()
368 {
369 cleanup();
370 }
371 };
372 }
373 }
374 }
375
376 #if defined(BOOST_MSVC) && (_MSC_VER>=1400) && !defined(UNDER_CE)
377
378 namespace boost
379 {
380 namespace detail
381 {
382 namespace win32
383 {
384 #if _MSC_VER==1400
385 extern "C" unsigned char _interlockedbittestandset(long *a,long b);
386 extern "C" unsigned char _interlockedbittestandreset(long *a,long b);
387 #else
388 extern "C" unsigned char _interlockedbittestandset(volatile long *a,long b);
389 extern "C" unsigned char _interlockedbittestandreset(volatile long *a,long b);
390 #endif
391
392 #pragma intrinsic(_interlockedbittestandset)
393 #pragma intrinsic(_interlockedbittestandreset)
394
395 inline bool interlocked_bit_test_and_set(long* x,long bit)
396 {
397 return _interlockedbittestandset(x,bit)!=0;
398 }
399
400 inline bool interlocked_bit_test_and_reset(long* x,long bit)
401 {
402 return _interlockedbittestandreset(x,bit)!=0;
403 }
404
405 }
406 }
407 }
408 #define BOOST_THREAD_BTS_DEFINED
409 #elif (defined(BOOST_MSVC) || defined(BOOST_INTEL_WIN)) && defined(_M_IX86)
410 namespace boost
411 {
412 namespace detail
413 {
414 namespace win32
415 {
416 inline bool interlocked_bit_test_and_set(long* x,long bit)
417 {
418 #ifndef BOOST_INTEL_CXX_VERSION
419 __asm {
420 mov eax,bit;
421 mov edx,x;
422 lock bts [edx],eax;
423 setc al;
424 };
425 #else
426 bool ret;
427 __asm {
428 mov eax,bit
429 mov edx,x
430 lock bts [edx],eax
431 setc al
432 mov ret, al
433 };
434 return ret;
435
436 #endif
437 }
438
439 inline bool interlocked_bit_test_and_reset(long* x,long bit)
440 {
441 #ifndef BOOST_INTEL_CXX_VERSION
442 __asm {
443 mov eax,bit;
444 mov edx,x;
445 lock btr [edx],eax;
446 setc al;
447 };
448 #else
449 bool ret;
450 __asm {
451 mov eax,bit
452 mov edx,x
453 lock btr [edx],eax
454 setc al
455 mov ret, al
456 };
457 return ret;
458
459 #endif
460 }
461
462 }
463 }
464 }
465 #define BOOST_THREAD_BTS_DEFINED
466 #endif
467
468 #ifndef BOOST_THREAD_BTS_DEFINED
469
470 namespace boost
471 {
472 namespace detail
473 {
474 namespace win32
475 {
476 inline bool interlocked_bit_test_and_set(long* x,long bit)
477 {
478 long const value=1<<bit;
479 long old=*x;
480 do
481 {
482 long const current=BOOST_INTERLOCKED_COMPARE_EXCHANGE(x,old|value,old);
483 if(current==old)
484 {
485 break;
486 }
487 old=current;
488 }
489 while(true) ;
490 return (old&value)!=0;
491 }
492
493 inline bool interlocked_bit_test_and_reset(long* x,long bit)
494 {
495 long const value=1<<bit;
496 long old=*x;
497 do
498 {
499 long const current=BOOST_INTERLOCKED_COMPARE_EXCHANGE(x,old&~value,old);
500 if(current==old)
501 {
502 break;
503 }
504 old=current;
505 }
506 while(true) ;
507 return (old&value)!=0;
508 }
509 }
510 }
511 }
512 #endif
513
514 #include <boost/config/abi_suffix.hpp>
515
516 #endif