1 #ifndef BOOST_WIN32_THREAD_PRIMITIVES_HPP
2 #define BOOST_WIN32_THREAD_PRIMITIVES_HPP
4 // win32_thread_primitives.hpp
6 // (C) Copyright 2005-7 Anthony Williams
7 // (C) Copyright 2007 David Deakins
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)
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 //#include <boost/detail/winapi/synchronization.hpp>
21 #include <boost/thread/win32/interlocked_read.hpp>
24 #if BOOST_PLAT_WINDOWS_RUNTIME
28 #if defined( BOOST_USE_WINDOWS_H )
37 typedef HANDLE handle;
38 typedef SYSTEM_INFO system_info;
39 typedef unsigned __int64 ticks_type;
40 typedef FARPROC farproc_t;
41 unsigned const infinite=INFINITE;
42 unsigned const timeout=WAIT_TIMEOUT;
43 handle const invalid_handle_value=INVALID_HANDLE_VALUE;
44 unsigned const event_modify_state=EVENT_MODIFY_STATE;
45 unsigned const synchronize=SYNCHRONIZE;
46 unsigned const wait_abandoned=WAIT_ABANDONED;
47 unsigned const create_event_initial_set = 0x00000002;
48 unsigned const create_event_manual_reset = 0x00000001;
49 unsigned const event_all_access = EVENT_ALL_ACCESS;
50 unsigned const semaphore_all_access = SEMAPHORE_ALL_ACCESS;
53 # ifdef BOOST_NO_ANSI_APIS
54 # if BOOST_USE_WINAPI_VERSION < BOOST_WINAPI_VERSION_VISTA
57 using ::CreateSemaphoreW;
59 using ::CreateMutexExW;
60 using ::CreateEventExW;
61 using ::CreateSemaphoreExW;
64 using ::GetModuleHandleW;
69 using ::CreateSemaphoreA;
70 using ::GetModuleHandleA;
72 #if BOOST_PLAT_WINDOWS_RUNTIME
73 using ::GetNativeSystemInfo;
74 using ::GetTickCount64;
76 using ::GetSystemInfo;
81 using ::ReleaseSemaphore;
84 using ::WaitForMultipleObjectsEx;
85 using ::WaitForSingleObjectEx;
86 using ::GetCurrentProcessId;
87 using ::GetCurrentThreadId;
88 using ::GetCurrentThread;
89 using ::GetCurrentProcess;
90 using ::DuplicateHandle;
91 #if !BOOST_PLAT_WINDOWS_RUNTIME
95 using ::GetProcAddress;
100 #elif defined( WIN32 ) || defined( _WIN32 ) || defined( __WIN32__ )
104 # ifndef _WIN32_WCE_EMULATION
105 # define WINAPI __cdecl // Note this doesn't match the desktop definition
107 # define WINAPI __stdcall
115 typedef unsigned long DWORD;
116 typedef void* HANDLE;
138 typedef unsigned __int64 ulong_ptr;
140 typedef unsigned long ulong_ptr;
142 typedef void* handle;
143 typedef _SYSTEM_INFO system_info;
144 typedef unsigned __int64 ticks_type;
145 typedef int (__stdcall *farproc_t)();
146 unsigned const infinite=~0U;
147 unsigned const timeout=258U;
148 handle const invalid_handle_value=(handle)(-1);
149 unsigned const event_modify_state=2;
150 unsigned const synchronize=0x100000u;
151 unsigned const wait_abandoned=0x00000080u;
152 unsigned const create_event_initial_set = 0x00000002;
153 unsigned const create_event_manual_reset = 0x00000001;
154 unsigned const event_all_access = 0x1F0003;
155 unsigned const semaphore_all_access = 0x1F0003;
159 struct _SECURITY_ATTRIBUTES;
160 # ifdef BOOST_NO_ANSI_APIS
161 # if BOOST_USE_WINAPI_VERSION < BOOST_WINAPI_VERSION_VISTA
162 __declspec(dllimport) void* __stdcall CreateMutexW(_SECURITY_ATTRIBUTES*,int,wchar_t const*);
163 __declspec(dllimport) void* __stdcall CreateSemaphoreW(_SECURITY_ATTRIBUTES*,long,long,wchar_t const*);
164 __declspec(dllimport) void* __stdcall CreateEventW(_SECURITY_ATTRIBUTES*,int,int,wchar_t const*);
166 __declspec(dllimport) void* __stdcall CreateMutexExW(_SECURITY_ATTRIBUTES*,wchar_t const*,unsigned long,unsigned long);
167 __declspec(dllimport) void* __stdcall CreateEventExW(_SECURITY_ATTRIBUTES*,wchar_t const*,unsigned long,unsigned long);
168 __declspec(dllimport) void* __stdcall CreateSemaphoreExW(_SECURITY_ATTRIBUTES*,long,long,wchar_t const*,unsigned long,unsigned long);
170 __declspec(dllimport) void* __stdcall OpenEventW(unsigned long,int,wchar_t const*);
171 __declspec(dllimport) void* __stdcall GetModuleHandleW(wchar_t const*);
173 __declspec(dllimport) void* __stdcall CreateMutexA(_SECURITY_ATTRIBUTES*,int,char const*);
174 __declspec(dllimport) void* __stdcall CreateSemaphoreA(_SECURITY_ATTRIBUTES*,long,long,char const*);
175 __declspec(dllimport) void* __stdcall CreateEventA(_SECURITY_ATTRIBUTES*,int,int,char const*);
176 __declspec(dllimport) void* __stdcall OpenEventA(unsigned long,int,char const*);
177 __declspec(dllimport) void* __stdcall GetModuleHandleA(char const*);
179 #if BOOST_PLAT_WINDOWS_RUNTIME
180 __declspec(dllimport) void __stdcall GetNativeSystemInfo(_SYSTEM_INFO*);
181 __declspec(dllimport) ticks_type __stdcall GetTickCount64();
183 __declspec(dllimport) void __stdcall GetSystemInfo(_SYSTEM_INFO*);
184 __declspec(dllimport) unsigned long __stdcall GetTickCount();
186 __declspec(dllimport) int __stdcall CloseHandle(void*);
187 __declspec(dllimport) int __stdcall ReleaseMutex(void*);
188 __declspec(dllimport) unsigned long __stdcall WaitForSingleObjectEx(void*,unsigned long,int);
189 __declspec(dllimport) unsigned long __stdcall WaitForMultipleObjectsEx(unsigned long nCount,void* const * lpHandles,int bWaitAll,unsigned long dwMilliseconds,int bAlertable);
190 __declspec(dllimport) int __stdcall ReleaseSemaphore(void*,long,long*);
191 __declspec(dllimport) int __stdcall DuplicateHandle(void*,void*,void*,void**,unsigned long,int,unsigned long);
192 #if !BOOST_PLAT_WINDOWS_RUNTIME
193 __declspec(dllimport) unsigned long __stdcall SleepEx(unsigned long,int);
194 __declspec(dllimport) void __stdcall Sleep(unsigned long);
195 typedef void (__stdcall *queue_user_apc_callback_function)(ulong_ptr);
196 __declspec(dllimport) unsigned long __stdcall QueueUserAPC(queue_user_apc_callback_function,void*,ulong_ptr);
197 __declspec(dllimport) farproc_t __stdcall GetProcAddress(void *, const char *);
201 __declspec(dllimport) unsigned long __stdcall GetCurrentProcessId();
202 __declspec(dllimport) unsigned long __stdcall GetCurrentThreadId();
203 __declspec(dllimport) void* __stdcall GetCurrentThread();
204 __declspec(dllimport) void* __stdcall GetCurrentProcess();
205 __declspec(dllimport) int __stdcall SetEvent(void*);
206 __declspec(dllimport) int __stdcall ResetEvent(void*);
208 using ::GetCurrentProcessId;
209 using ::GetCurrentThreadId;
210 using ::GetCurrentThread;
211 using ::GetCurrentProcess;
220 # error "Win32 functions not available"
223 #include <boost/config/abi_prefix.hpp>
231 namespace detail { typedef ticks_type (__stdcall *gettickcount64_t)(); }
232 #if !BOOST_PLAT_WINDOWS_RUNTIME
236 long _InterlockedCompareExchange(long volatile *, long, long);
237 #pragma intrinsic(_InterlockedCompareExchange)
238 #elif defined(__MINGW64_VERSION_MAJOR)
239 long _InterlockedCompareExchange(long volatile *, long, long);
241 // Mingw doesn't provide intrinsics
242 #define _InterlockedCompareExchange InterlockedCompareExchange
245 // Borrowed from https://stackoverflow.com/questions/8211820/userland-interrupt-timer-access-such-as-via-kequeryinterrupttime-or-similar
246 inline ticks_type __stdcall GetTickCount64emulation()
248 static long count = -1l;
249 unsigned long previous_count, current_tick32, previous_count_zone, current_tick32_zone;
250 ticks_type current_tick64;
252 previous_count = (unsigned long) boost::detail::interlocked_read_acquire(&count);
253 current_tick32 = GetTickCount();
255 if(previous_count == (unsigned long)-1l)
257 // count has never been written
258 unsigned long initial_count;
259 initial_count = current_tick32 >> 28;
260 previous_count = (unsigned long) _InterlockedCompareExchange(&count, (long)initial_count, -1l);
262 current_tick64 = initial_count;
263 current_tick64 <<= 28;
264 current_tick64 += current_tick32 & 0x0FFFFFFF;
265 return current_tick64;
268 previous_count_zone = previous_count & 15;
269 current_tick32_zone = current_tick32 >> 28;
271 if(current_tick32_zone == previous_count_zone)
273 // The top four bits of the 32-bit tick count haven't changed since count was last written.
274 current_tick64 = previous_count;
275 current_tick64 <<= 28;
276 current_tick64 += current_tick32 & 0x0FFFFFFF;
277 return current_tick64;
280 if(current_tick32_zone == previous_count_zone + 1 || (current_tick32_zone == 0 && previous_count_zone == 15))
282 // The top four bits of the 32-bit tick count have been incremented since count was last written.
283 unsigned long new_count = previous_count + 1;
284 _InterlockedCompareExchange(&count, (long)new_count, (long)previous_count);
285 current_tick64 = new_count;
286 current_tick64 <<= 28;
287 current_tick64 += current_tick32 & 0x0FFFFFFF;
288 return current_tick64;
291 // Oops, we weren't called often enough, we're stuck
296 inline detail::gettickcount64_t GetTickCount64_()
298 static detail::gettickcount64_t gettickcount64impl;
299 if(gettickcount64impl)
300 return gettickcount64impl;
302 // GetTickCount and GetModuleHandle are not allowed in the Windows Runtime,
303 // and kernel32 isn't used in Windows Phone.
304 #if BOOST_PLAT_WINDOWS_RUNTIME
305 gettickcount64impl = &GetTickCount64;
307 farproc_t addr=GetProcAddress(
308 #if !defined(BOOST_NO_ANSI_APIS)
309 GetModuleHandleA("KERNEL32.DLL"),
311 GetModuleHandleW(L"KERNEL32.DLL"),
315 gettickcount64impl=(detail::gettickcount64_t) addr;
317 gettickcount64impl=&GetTickCount64emulation;
319 return gettickcount64impl;
324 auto_reset_event=false,
325 manual_reset_event=true
328 enum initial_event_state
330 event_initially_reset=false,
331 event_initially_set=true
334 inline handle create_event(
335 #if !defined(BOOST_NO_ANSI_APIS)
336 const char *mutex_name,
338 const wchar_t *mutex_name,
341 initial_event_state state)
343 #if !defined(BOOST_NO_ANSI_APIS)
344 handle const res = win32::CreateEventA(0, type, state, mutex_name);
345 #elif BOOST_USE_WINAPI_VERSION < BOOST_WINAPI_VERSION_VISTA
346 handle const res = win32::CreateEventW(0, type, state, mutex_name);
348 handle const res = win32::CreateEventExW(
351 type ? create_event_manual_reset : 0 | state ? create_event_initial_set : 0,
357 inline handle create_anonymous_event(event_type type,initial_event_state state)
359 handle const res = create_event(0, type, state);
362 boost::throw_exception(thread_resource_error());
367 inline handle create_anonymous_semaphore_nothrow(long initial_count,long max_count)
369 #if !defined(BOOST_NO_ANSI_APIS)
370 handle const res=win32::CreateSemaphoreA(0,initial_count,max_count,0);
372 #if BOOST_USE_WINAPI_VERSION < BOOST_WINAPI_VERSION_VISTA
373 handle const res=win32::CreateSemaphoreEx(0,initial_count,max_count,0,0);
375 handle const res=win32::CreateSemaphoreExW(0,initial_count,max_count,0,0,semaphore_all_access);
381 inline handle create_anonymous_semaphore(long initial_count,long max_count)
383 handle const res=create_anonymous_semaphore_nothrow(initial_count,max_count);
386 boost::throw_exception(thread_resource_error());
391 inline handle duplicate_handle(handle source)
393 handle const current_process=GetCurrentProcess();
394 long const same_access_flag=2;
396 bool const success=DuplicateHandle(current_process,source,current_process,&new_handle,0,false,same_access_flag)!=0;
399 boost::throw_exception(thread_resource_error());
404 inline void release_semaphore(handle semaphore,long count)
406 BOOST_VERIFY(ReleaseSemaphore(semaphore,count,0)!=0);
409 inline void get_system_info(system_info *info)
411 #if BOOST_PLAT_WINDOWS_RUNTIME
412 win32::GetNativeSystemInfo(info);
414 win32::GetSystemInfo(info);
418 inline void sleep(unsigned long milliseconds)
420 if(milliseconds == 0)
422 #if BOOST_PLAT_WINDOWS_RUNTIME
423 std::this_thread::yield();
425 ::boost::detail::win32::Sleep(0);
430 #if BOOST_PLAT_WINDOWS_RUNTIME
431 ::boost::detail::win32::WaitForSingleObjectEx(::boost::detail::win32::GetCurrentThread(), milliseconds, 0);
433 ::boost::detail::win32::Sleep(milliseconds);
438 #if BOOST_PLAT_WINDOWS_RUNTIME
439 class BOOST_THREAD_DECL scoped_winrt_thread
442 scoped_winrt_thread() : m_completionHandle(invalid_handle_value)
445 ~scoped_winrt_thread()
447 if (m_completionHandle != ::boost::detail::win32::invalid_handle_value)
449 CloseHandle(m_completionHandle);
453 typedef unsigned(__stdcall * thread_func)(void *);
454 bool start(thread_func address, void *parameter, unsigned int *thrdId);
456 handle waitable_handle() const
458 BOOST_ASSERT(m_completionHandle != ::boost::detail::win32::invalid_handle_value);
459 return m_completionHandle;
463 handle m_completionHandle;
466 class BOOST_THREAD_DECL handle_manager
469 handle handle_to_manage;
470 handle_manager(handle_manager&);
471 handle_manager& operator=(handle_manager&);
475 if(handle_to_manage && handle_to_manage!=invalid_handle_value)
477 BOOST_VERIFY(CloseHandle(handle_to_manage));
482 explicit handle_manager(handle handle_to_manage_):
483 handle_to_manage(handle_to_manage_)
489 handle_manager& operator=(handle new_handle)
492 handle_to_manage=new_handle;
496 operator handle() const
498 return handle_to_manage;
501 handle duplicate() const
503 return duplicate_handle(handle_to_manage);
506 void swap(handle_manager& other)
508 std::swap(handle_to_manage,other.handle_to_manage);
513 handle const res=handle_to_manage;
518 bool operator!() const
520 return !handle_to_manage;
532 #if defined(BOOST_MSVC) && (_MSC_VER>=1400) && !defined(UNDER_CE)
541 extern "C" unsigned char _interlockedbittestandset(long *a,long b);
542 extern "C" unsigned char _interlockedbittestandreset(long *a,long b);
544 extern "C" unsigned char _interlockedbittestandset(volatile long *a,long b);
545 extern "C" unsigned char _interlockedbittestandreset(volatile long *a,long b);
548 #pragma intrinsic(_interlockedbittestandset)
549 #pragma intrinsic(_interlockedbittestandreset)
551 inline bool interlocked_bit_test_and_set(long* x,long bit)
553 return _interlockedbittestandset(x,bit)!=0;
556 inline bool interlocked_bit_test_and_reset(long* x,long bit)
558 return _interlockedbittestandreset(x,bit)!=0;
564 #define BOOST_THREAD_BTS_DEFINED
565 #elif (defined(BOOST_MSVC) || defined(BOOST_INTEL_WIN)) && defined(_M_IX86)
572 inline bool interlocked_bit_test_and_set(long* x,long bit)
574 #ifndef BOOST_INTEL_CXX_VERSION
595 inline bool interlocked_bit_test_and_reset(long* x,long bit)
597 #ifndef BOOST_INTEL_CXX_VERSION
621 #define BOOST_THREAD_BTS_DEFINED
624 #ifndef BOOST_THREAD_BTS_DEFINED
632 inline bool interlocked_bit_test_and_set(long* x,long bit)
634 long const value=1<<bit;
638 long const current=BOOST_INTERLOCKED_COMPARE_EXCHANGE(x,old|value,old);
646 return (old&value)!=0;
649 inline bool interlocked_bit_test_and_reset(long* x,long bit)
651 long const value=1<<bit;
655 long const current=BOOST_INTERLOCKED_COMPARE_EXCHANGE(x,old&~value,old);
663 return (old&value)!=0;
670 #include <boost/config/abi_suffix.hpp>