]>
Commit | Line | Data |
---|---|---|
7c673cae FG |
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> | |
b32b8144 | 19 | |
11fdf7f2 TL |
20 | #include <boost/winapi/config.hpp> |
21 | #include <boost/winapi/basic_types.hpp> | |
22 | #include <boost/winapi/semaphore.hpp> | |
23 | #include <boost/winapi/system.hpp> | |
24 | #include <boost/winapi/event.hpp> | |
25 | #include <boost/winapi/thread.hpp> | |
26 | #include <boost/winapi/get_current_thread.hpp> | |
27 | #include <boost/winapi/get_current_thread_id.hpp> | |
28 | #include <boost/winapi/get_current_process.hpp> | |
29 | #include <boost/winapi/get_current_process_id.hpp> | |
30 | #include <boost/winapi/wait.hpp> | |
31 | #include <boost/winapi/handles.hpp> | |
32 | #include <boost/winapi/access_rights.hpp> | |
33 | ||
34 | //#include <boost/winapi/synchronization.hpp> | |
b32b8144 | 35 | #include <boost/thread/win32/interlocked_read.hpp> |
7c673cae FG |
36 | #include <algorithm> |
37 | ||
38 | #if BOOST_PLAT_WINDOWS_RUNTIME | |
39 | #include <thread> | |
40 | #endif | |
41 | ||
7c673cae FG |
42 | namespace boost |
43 | { | |
44 | namespace detail | |
45 | { | |
46 | namespace win32 | |
47 | { | |
11fdf7f2 TL |
48 | typedef ::boost::winapi::HANDLE_ handle; |
49 | typedef ::boost::winapi::SYSTEM_INFO_ system_info; | |
50 | typedef ::boost::winapi::ULONGLONG_ ticks_type; | |
51 | unsigned const infinite=::boost::winapi::INFINITE_; | |
52 | unsigned const timeout=::boost::winapi::WAIT_TIMEOUT_; | |
53 | handle const invalid_handle_value=::boost::winapi::INVALID_HANDLE_VALUE_; | |
54 | unsigned const event_modify_state=::boost::winapi::EVENT_MODIFY_STATE_; | |
55 | unsigned const synchronize=::boost::winapi::SYNCHRONIZE_; | |
56 | unsigned const wait_abandoned=::boost::winapi::WAIT_ABANDONED_; | |
7c673cae FG |
57 | unsigned const create_event_initial_set = 0x00000002; |
58 | unsigned const create_event_manual_reset = 0x00000001; | |
11fdf7f2 TL |
59 | unsigned const event_all_access = ::boost::winapi::EVENT_ALL_ACCESS_; |
60 | unsigned const semaphore_all_access = boost::winapi::SEMAPHORE_ALL_ACCESS_; | |
7c673cae FG |
61 | } |
62 | } | |
63 | } | |
7c673cae FG |
64 | |
65 | #include <boost/config/abi_prefix.hpp> | |
66 | ||
67 | namespace boost | |
68 | { | |
69 | namespace detail | |
70 | { | |
71 | namespace win32 | |
72 | { | |
92f5a8d4 | 73 | namespace detail { typedef ticks_type (BOOST_WINAPI_WINAPI_CC *gettickcount64_t)(); } |
11fdf7f2 | 74 | extern BOOST_THREAD_DECL boost::detail::win32::detail::gettickcount64_t gettickcount64; |
7c673cae FG |
75 | |
76 | enum event_type | |
77 | { | |
78 | auto_reset_event=false, | |
79 | manual_reset_event=true | |
80 | }; | |
81 | ||
82 | enum initial_event_state | |
83 | { | |
84 | event_initially_reset=false, | |
85 | event_initially_set=true | |
86 | }; | |
87 | ||
88 | inline handle create_event( | |
89 | #if !defined(BOOST_NO_ANSI_APIS) | |
90 | const char *mutex_name, | |
91 | #else | |
92 | const wchar_t *mutex_name, | |
93 | #endif | |
94 | event_type type, | |
95 | initial_event_state state) | |
96 | { | |
97 | #if !defined(BOOST_NO_ANSI_APIS) | |
11fdf7f2 | 98 | handle const res = ::boost::winapi::CreateEventA(0, type, state, mutex_name); |
7c673cae | 99 | #elif BOOST_USE_WINAPI_VERSION < BOOST_WINAPI_VERSION_VISTA |
11fdf7f2 | 100 | handle const res = ::boost::winapi::CreateEventW(0, type, state, mutex_name); |
7c673cae | 101 | #else |
11fdf7f2 | 102 | handle const res = ::boost::winapi::CreateEventExW( |
7c673cae FG |
103 | 0, |
104 | mutex_name, | |
92f5a8d4 | 105 | (type ? create_event_manual_reset : 0) | (state ? create_event_initial_set : 0), |
7c673cae FG |
106 | event_all_access); |
107 | #endif | |
108 | return res; | |
109 | } | |
110 | ||
111 | inline handle create_anonymous_event(event_type type,initial_event_state state) | |
112 | { | |
113 | handle const res = create_event(0, type, state); | |
114 | if(!res) | |
115 | { | |
116 | boost::throw_exception(thread_resource_error()); | |
117 | } | |
118 | return res; | |
119 | } | |
120 | ||
121 | inline handle create_anonymous_semaphore_nothrow(long initial_count,long max_count) | |
122 | { | |
123 | #if !defined(BOOST_NO_ANSI_APIS) | |
11fdf7f2 | 124 | handle const res=::boost::winapi::CreateSemaphoreA(0,initial_count,max_count,0); |
7c673cae FG |
125 | #else |
126 | #if BOOST_USE_WINAPI_VERSION < BOOST_WINAPI_VERSION_VISTA | |
11fdf7f2 | 127 | handle const res=::boost::winapi::CreateSemaphoreEx(0,initial_count,max_count,0,0); |
7c673cae | 128 | #else |
11fdf7f2 | 129 | handle const res=::boost::winapi::CreateSemaphoreExW(0,initial_count,max_count,0,0,semaphore_all_access); |
7c673cae FG |
130 | #endif |
131 | #endif | |
132 | return res; | |
133 | } | |
134 | ||
135 | inline handle create_anonymous_semaphore(long initial_count,long max_count) | |
136 | { | |
137 | handle const res=create_anonymous_semaphore_nothrow(initial_count,max_count); | |
138 | if(!res) | |
139 | { | |
140 | boost::throw_exception(thread_resource_error()); | |
141 | } | |
142 | return res; | |
143 | } | |
144 | ||
145 | inline handle duplicate_handle(handle source) | |
146 | { | |
11fdf7f2 | 147 | handle const current_process=::boost::winapi::GetCurrentProcess(); |
7c673cae FG |
148 | long const same_access_flag=2; |
149 | handle new_handle=0; | |
11fdf7f2 | 150 | bool const success=::boost::winapi::DuplicateHandle(current_process,source,current_process,&new_handle,0,false,same_access_flag)!=0; |
7c673cae FG |
151 | if(!success) |
152 | { | |
153 | boost::throw_exception(thread_resource_error()); | |
154 | } | |
155 | return new_handle; | |
156 | } | |
157 | ||
158 | inline void release_semaphore(handle semaphore,long count) | |
159 | { | |
11fdf7f2 | 160 | BOOST_VERIFY(::boost::winapi::ReleaseSemaphore(semaphore,count,0)!=0); |
7c673cae FG |
161 | } |
162 | ||
163 | inline void get_system_info(system_info *info) | |
164 | { | |
165 | #if BOOST_PLAT_WINDOWS_RUNTIME | |
11fdf7f2 | 166 | ::boost::winapi::GetNativeSystemInfo(info); |
7c673cae | 167 | #else |
11fdf7f2 | 168 | ::boost::winapi::GetSystemInfo(info); |
7c673cae FG |
169 | #endif |
170 | } | |
171 | ||
172 | inline void sleep(unsigned long milliseconds) | |
173 | { | |
174 | if(milliseconds == 0) | |
175 | { | |
176 | #if BOOST_PLAT_WINDOWS_RUNTIME | |
177 | std::this_thread::yield(); | |
178 | #else | |
11fdf7f2 | 179 | ::boost::winapi::Sleep(0); |
7c673cae FG |
180 | #endif |
181 | } | |
182 | else | |
183 | { | |
184 | #if BOOST_PLAT_WINDOWS_RUNTIME | |
11fdf7f2 | 185 | ::boost::winapi::WaitForSingleObjectEx(::boost::winapi::GetCurrentThread(), milliseconds, 0); |
7c673cae | 186 | #else |
11fdf7f2 | 187 | ::boost::winapi::Sleep(milliseconds); |
7c673cae FG |
188 | #endif |
189 | } | |
190 | } | |
191 | ||
192 | #if BOOST_PLAT_WINDOWS_RUNTIME | |
193 | class BOOST_THREAD_DECL scoped_winrt_thread | |
194 | { | |
195 | public: | |
196 | scoped_winrt_thread() : m_completionHandle(invalid_handle_value) | |
197 | {} | |
198 | ||
199 | ~scoped_winrt_thread() | |
200 | { | |
201 | if (m_completionHandle != ::boost::detail::win32::invalid_handle_value) | |
202 | { | |
11fdf7f2 | 203 | ::boost::winapi::CloseHandle(m_completionHandle); |
7c673cae FG |
204 | } |
205 | } | |
206 | ||
207 | typedef unsigned(__stdcall * thread_func)(void *); | |
208 | bool start(thread_func address, void *parameter, unsigned int *thrdId); | |
209 | ||
210 | handle waitable_handle() const | |
211 | { | |
212 | BOOST_ASSERT(m_completionHandle != ::boost::detail::win32::invalid_handle_value); | |
213 | return m_completionHandle; | |
214 | } | |
215 | ||
216 | private: | |
217 | handle m_completionHandle; | |
218 | }; | |
219 | #endif | |
220 | class BOOST_THREAD_DECL handle_manager | |
221 | { | |
222 | private: | |
223 | handle handle_to_manage; | |
224 | handle_manager(handle_manager&); | |
225 | handle_manager& operator=(handle_manager&); | |
226 | ||
227 | void cleanup() | |
228 | { | |
229 | if(handle_to_manage && handle_to_manage!=invalid_handle_value) | |
230 | { | |
11fdf7f2 | 231 | BOOST_VERIFY(::boost::winapi::CloseHandle(handle_to_manage)); |
7c673cae FG |
232 | } |
233 | } | |
234 | ||
235 | public: | |
236 | explicit handle_manager(handle handle_to_manage_): | |
237 | handle_to_manage(handle_to_manage_) | |
238 | {} | |
239 | handle_manager(): | |
240 | handle_to_manage(0) | |
241 | {} | |
242 | ||
243 | handle_manager& operator=(handle new_handle) | |
244 | { | |
245 | cleanup(); | |
246 | handle_to_manage=new_handle; | |
247 | return *this; | |
248 | } | |
249 | ||
250 | operator handle() const | |
251 | { | |
252 | return handle_to_manage; | |
253 | } | |
254 | ||
255 | handle duplicate() const | |
256 | { | |
257 | return duplicate_handle(handle_to_manage); | |
258 | } | |
259 | ||
260 | void swap(handle_manager& other) | |
261 | { | |
262 | std::swap(handle_to_manage,other.handle_to_manage); | |
263 | } | |
264 | ||
265 | handle release() | |
266 | { | |
267 | handle const res=handle_to_manage; | |
268 | handle_to_manage=0; | |
269 | return res; | |
270 | } | |
271 | ||
272 | bool operator!() const | |
273 | { | |
274 | return !handle_to_manage; | |
275 | } | |
276 | ||
277 | ~handle_manager() | |
278 | { | |
279 | cleanup(); | |
280 | } | |
281 | }; | |
282 | } | |
283 | } | |
284 | } | |
285 | ||
286 | #if defined(BOOST_MSVC) && (_MSC_VER>=1400) && !defined(UNDER_CE) | |
287 | ||
288 | namespace boost | |
289 | { | |
290 | namespace detail | |
291 | { | |
292 | namespace win32 | |
293 | { | |
294 | #if _MSC_VER==1400 | |
295 | extern "C" unsigned char _interlockedbittestandset(long *a,long b); | |
296 | extern "C" unsigned char _interlockedbittestandreset(long *a,long b); | |
297 | #else | |
298 | extern "C" unsigned char _interlockedbittestandset(volatile long *a,long b); | |
299 | extern "C" unsigned char _interlockedbittestandreset(volatile long *a,long b); | |
300 | #endif | |
301 | ||
302 | #pragma intrinsic(_interlockedbittestandset) | |
303 | #pragma intrinsic(_interlockedbittestandreset) | |
304 | ||
305 | inline bool interlocked_bit_test_and_set(long* x,long bit) | |
306 | { | |
307 | return _interlockedbittestandset(x,bit)!=0; | |
308 | } | |
309 | ||
310 | inline bool interlocked_bit_test_and_reset(long* x,long bit) | |
311 | { | |
312 | return _interlockedbittestandreset(x,bit)!=0; | |
313 | } | |
314 | ||
315 | } | |
316 | } | |
317 | } | |
318 | #define BOOST_THREAD_BTS_DEFINED | |
319 | #elif (defined(BOOST_MSVC) || defined(BOOST_INTEL_WIN)) && defined(_M_IX86) | |
320 | namespace boost | |
321 | { | |
322 | namespace detail | |
323 | { | |
324 | namespace win32 | |
325 | { | |
326 | inline bool interlocked_bit_test_and_set(long* x,long bit) | |
327 | { | |
328 | #ifndef BOOST_INTEL_CXX_VERSION | |
329 | __asm { | |
330 | mov eax,bit; | |
331 | mov edx,x; | |
332 | lock bts [edx],eax; | |
333 | setc al; | |
334 | }; | |
335 | #else | |
336 | bool ret; | |
337 | __asm { | |
338 | mov eax,bit | |
339 | mov edx,x | |
340 | lock bts [edx],eax | |
341 | setc al | |
342 | mov ret, al | |
343 | }; | |
344 | return ret; | |
345 | ||
346 | #endif | |
347 | } | |
348 | ||
349 | inline bool interlocked_bit_test_and_reset(long* x,long bit) | |
350 | { | |
351 | #ifndef BOOST_INTEL_CXX_VERSION | |
352 | __asm { | |
353 | mov eax,bit; | |
354 | mov edx,x; | |
355 | lock btr [edx],eax; | |
356 | setc al; | |
357 | }; | |
358 | #else | |
359 | bool ret; | |
360 | __asm { | |
361 | mov eax,bit | |
362 | mov edx,x | |
363 | lock btr [edx],eax | |
364 | setc al | |
365 | mov ret, al | |
366 | }; | |
367 | return ret; | |
368 | ||
369 | #endif | |
370 | } | |
371 | ||
372 | } | |
373 | } | |
374 | } | |
375 | #define BOOST_THREAD_BTS_DEFINED | |
376 | #endif | |
377 | ||
378 | #ifndef BOOST_THREAD_BTS_DEFINED | |
379 | ||
380 | namespace boost | |
381 | { | |
382 | namespace detail | |
383 | { | |
384 | namespace win32 | |
385 | { | |
386 | inline bool interlocked_bit_test_and_set(long* x,long bit) | |
387 | { | |
388 | long const value=1<<bit; | |
389 | long old=*x; | |
390 | do | |
391 | { | |
392 | long const current=BOOST_INTERLOCKED_COMPARE_EXCHANGE(x,old|value,old); | |
393 | if(current==old) | |
394 | { | |
395 | break; | |
396 | } | |
397 | old=current; | |
398 | } | |
399 | while(true) ; | |
400 | return (old&value)!=0; | |
401 | } | |
402 | ||
403 | inline bool interlocked_bit_test_and_reset(long* x,long bit) | |
404 | { | |
405 | long const value=1<<bit; | |
406 | long old=*x; | |
407 | do | |
408 | { | |
409 | long const current=BOOST_INTERLOCKED_COMPARE_EXCHANGE(x,old&~value,old); | |
410 | if(current==old) | |
411 | { | |
412 | break; | |
413 | } | |
414 | old=current; | |
415 | } | |
416 | while(true) ; | |
417 | return (old&value)!=0; | |
418 | } | |
419 | } | |
420 | } | |
421 | } | |
422 | #endif | |
423 | ||
424 | #include <boost/config/abi_suffix.hpp> | |
425 | ||
426 | #endif |