]>
Commit | Line | Data |
---|---|---|
7c673cae FG |
1 | ////////////////////////////////////////////////////////////////////////////// |
2 | // | |
3 | // (C) Copyright Ion Gaztanaga 2005-2013. Distributed under the Boost | |
4 | // Software License, Version 1.0. (See accompanying file | |
5 | // LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) | |
6 | // | |
7 | // See http://www.boost.org/libs/interprocess for documentation. | |
8 | // | |
9 | ////////////////////////////////////////////////////////////////////////////// | |
10 | ||
11 | //Thread launching functions are adapted from boost/detail/lightweight_thread.hpp | |
12 | // | |
13 | // boost/detail/lightweight_thread.hpp | |
14 | // | |
15 | // Copyright (c) 2002 Peter Dimov and Multi Media Ltd. | |
16 | // Copyright (c) 2008 Peter Dimov | |
17 | // | |
18 | // Distributed under the Boost Software License, Version 1.0. | |
19 | // See accompanying file LICENSE_1_0.txt or copy at | |
20 | // http://www.boost.org/LICENSE_1_0.txt | |
21 | ||
22 | #ifndef BOOST_INTERPROCESS_DETAIL_OS_THREAD_FUNCTIONS_HPP | |
23 | #define BOOST_INTERPROCESS_DETAIL_OS_THREAD_FUNCTIONS_HPP | |
24 | ||
25 | #ifndef BOOST_CONFIG_HPP | |
26 | # include <boost/config.hpp> | |
27 | #endif | |
28 | # | |
29 | #if defined(BOOST_HAS_PRAGMA_ONCE) | |
30 | # pragma once | |
31 | #endif | |
32 | ||
33 | #include <boost/interprocess/detail/config_begin.hpp> | |
34 | #include <boost/interprocess/detail/workaround.hpp> | |
35 | #include <boost/interprocess/streams/bufferstream.hpp> | |
36 | #include <boost/interprocess/detail/posix_time_types_wrk.hpp> | |
37 | #include <cstddef> | |
38 | #include <ostream> | |
39 | ||
40 | #if defined(BOOST_INTERPROCESS_WINDOWS) | |
41 | # include <boost/interprocess/detail/win32_api.hpp> | |
42 | # include <process.h> | |
43 | #else | |
44 | # include <pthread.h> | |
45 | # include <unistd.h> | |
46 | # include <sched.h> | |
47 | # include <time.h> | |
48 | # ifdef BOOST_INTERPROCESS_BSD_DERIVATIVE | |
49 | //Some *BSD systems (OpenBSD & NetBSD) need sys/param.h before sys/sysctl.h, whereas | |
50 | //others (FreeBSD & Darwin) need sys/types.h | |
51 | # include <sys/types.h> | |
52 | # include <sys/param.h> | |
53 | # include <sys/sysctl.h> | |
54 | # endif | |
11fdf7f2 TL |
55 | #if defined(__VXWORKS__) |
56 | #include <vxCpuLib.h> | |
57 | #endif | |
7c673cae | 58 | //According to the article "C/C++ tip: How to measure elapsed real time for benchmarking" |
b32b8144 FG |
59 | //Check MacOs first as macOS 10.12 SDK defines both CLOCK_MONOTONIC and |
60 | //CLOCK_MONOTONIC_RAW and no clock_gettime. | |
61 | # if (defined(macintosh) || defined(__APPLE__) || defined(__APPLE_CC__)) | |
62 | # include <mach/mach_time.h> // mach_absolute_time, mach_timebase_info_data_t | |
63 | # define BOOST_INTERPROCESS_MATCH_ABSOLUTE_TIME | |
64 | # elif defined(CLOCK_MONOTONIC_PRECISE) //BSD | |
7c673cae FG |
65 | # define BOOST_INTERPROCESS_CLOCK_MONOTONIC CLOCK_MONOTONIC_PRECISE |
66 | # elif defined(CLOCK_MONOTONIC_RAW) //Linux | |
67 | # define BOOST_INTERPROCESS_CLOCK_MONOTONIC CLOCK_MONOTONIC_RAW | |
68 | # elif defined(CLOCK_HIGHRES) //Solaris | |
69 | # define BOOST_INTERPROCESS_CLOCK_MONOTONIC CLOCK_HIGHRES | |
70 | # elif defined(CLOCK_MONOTONIC) //POSIX (AIX, BSD, Linux, Solaris) | |
71 | # define BOOST_INTERPROCESS_CLOCK_MONOTONIC CLOCK_MONOTONIC | |
7c673cae FG |
72 | # else |
73 | # error "No high resolution steady clock in your system, please provide a patch" | |
74 | # endif | |
75 | #endif | |
76 | ||
77 | namespace boost { | |
78 | namespace interprocess { | |
79 | namespace ipcdetail{ | |
80 | ||
81 | #if defined (BOOST_INTERPROCESS_WINDOWS) | |
82 | ||
83 | typedef unsigned long OS_process_id_t; | |
84 | typedef unsigned long OS_thread_id_t; | |
85 | struct OS_thread_t | |
86 | { | |
87 | OS_thread_t() | |
88 | : m_handle() | |
89 | {} | |
90 | ||
91 | ||
92 | void* handle() const | |
93 | { return m_handle; } | |
94 | ||
95 | void* m_handle; | |
96 | }; | |
97 | ||
98 | typedef OS_thread_id_t OS_systemwide_thread_id_t; | |
99 | ||
100 | //process | |
101 | inline OS_process_id_t get_current_process_id() | |
102 | { return winapi::get_current_process_id(); } | |
103 | ||
104 | inline OS_process_id_t get_invalid_process_id() | |
105 | { return OS_process_id_t(0); } | |
106 | ||
107 | //thread | |
108 | inline OS_thread_id_t get_current_thread_id() | |
109 | { return winapi::get_current_thread_id(); } | |
110 | ||
111 | inline OS_thread_id_t get_invalid_thread_id() | |
112 | { return OS_thread_id_t(0xffffffff); } | |
113 | ||
114 | inline bool equal_thread_id(OS_thread_id_t id1, OS_thread_id_t id2) | |
115 | { return id1 == id2; } | |
116 | ||
117 | //return the system tick in ns | |
118 | inline unsigned long get_system_tick_ns() | |
119 | { | |
b32b8144 FG |
120 | unsigned long curres, ignore1, ignore2; |
121 | winapi::query_timer_resolution(&ignore1, &ignore2, &curres); | |
7c673cae FG |
122 | //Windows API returns the value in hundreds of ns |
123 | return (curres - 1ul)*100ul; | |
124 | } | |
125 | ||
126 | //return the system tick in us | |
127 | inline unsigned long get_system_tick_us() | |
128 | { | |
b32b8144 FG |
129 | unsigned long curres, ignore1, ignore2; |
130 | winapi::query_timer_resolution(&ignore1, &ignore2, &curres); | |
7c673cae FG |
131 | //Windows API returns the value in hundreds of ns |
132 | return (curres - 1ul)/10ul + 1ul; | |
133 | } | |
134 | ||
135 | typedef unsigned __int64 OS_highres_count_t; | |
136 | ||
137 | inline unsigned long get_system_tick_in_highres_counts() | |
138 | { | |
139 | __int64 freq; | |
b32b8144 FG |
140 | unsigned long curres, ignore1, ignore2; |
141 | winapi::query_timer_resolution(&ignore1, &ignore2, &curres); | |
7c673cae FG |
142 | //Frequency in counts per second |
143 | if(!winapi::query_performance_frequency(&freq)){ | |
144 | //Tick resolution in ms | |
145 | return (curres-1ul)/10000ul + 1ul; | |
146 | } | |
147 | else{ | |
148 | //In femtoseconds | |
149 | __int64 count_fs = (1000000000000000LL - 1LL)/freq + 1LL; | |
150 | __int64 tick_counts = (static_cast<__int64>(curres)*100000000LL - 1LL)/count_fs + 1LL; | |
151 | return static_cast<unsigned long>(tick_counts); | |
152 | } | |
153 | } | |
154 | ||
155 | inline OS_highres_count_t get_current_system_highres_count() | |
156 | { | |
157 | __int64 count; | |
158 | if(!winapi::query_performance_counter(&count)){ | |
159 | count = winapi::get_tick_count(); | |
160 | } | |
161 | return count; | |
162 | } | |
163 | ||
164 | inline void zero_highres_count(OS_highres_count_t &count) | |
165 | { count = 0; } | |
166 | ||
167 | inline bool is_highres_count_zero(const OS_highres_count_t &count) | |
168 | { return count == 0; } | |
169 | ||
170 | template <class Ostream> | |
171 | inline Ostream &ostream_highres_count(Ostream &ostream, const OS_highres_count_t &count) | |
172 | { | |
173 | ostream << count; | |
174 | return ostream; | |
175 | } | |
176 | ||
177 | inline OS_highres_count_t system_highres_count_subtract(const OS_highres_count_t &l, const OS_highres_count_t &r) | |
178 | { return l - r; } | |
179 | ||
180 | inline bool system_highres_count_less(const OS_highres_count_t &l, const OS_highres_count_t &r) | |
181 | { return l < r; } | |
182 | ||
183 | inline bool system_highres_count_less_ul(const OS_highres_count_t &l, unsigned long r) | |
184 | { return l < static_cast<OS_highres_count_t>(r); } | |
185 | ||
186 | inline void thread_sleep_tick() | |
187 | { winapi::sleep_tick(); } | |
188 | ||
189 | inline void thread_yield() | |
190 | { winapi::sched_yield(); } | |
191 | ||
192 | inline void thread_sleep(unsigned int ms) | |
193 | { winapi::sleep(ms); } | |
194 | ||
195 | //systemwide thread | |
196 | inline OS_systemwide_thread_id_t get_current_systemwide_thread_id() | |
197 | { | |
198 | return get_current_thread_id(); | |
199 | } | |
200 | ||
201 | inline void systemwide_thread_id_copy | |
202 | (const volatile OS_systemwide_thread_id_t &from, volatile OS_systemwide_thread_id_t &to) | |
203 | { | |
204 | to = from; | |
205 | } | |
206 | ||
207 | inline bool equal_systemwide_thread_id(const OS_systemwide_thread_id_t &id1, const OS_systemwide_thread_id_t &id2) | |
208 | { | |
209 | return equal_thread_id(id1, id2); | |
210 | } | |
211 | ||
212 | inline OS_systemwide_thread_id_t get_invalid_systemwide_thread_id() | |
213 | { | |
214 | return get_invalid_thread_id(); | |
215 | } | |
216 | ||
217 | inline long double get_current_process_creation_time() | |
218 | { | |
219 | winapi::interprocess_filetime CreationTime, ExitTime, KernelTime, UserTime; | |
220 | ||
221 | winapi::get_process_times | |
222 | ( winapi::get_current_process(), &CreationTime, &ExitTime, &KernelTime, &UserTime); | |
223 | ||
224 | typedef long double ldouble_t; | |
225 | const ldouble_t resolution = (100.0l/1000000000.0l); | |
226 | return CreationTime.dwHighDateTime*(ldouble_t(1u<<31u)*2.0l*resolution) + | |
227 | CreationTime.dwLowDateTime*resolution; | |
228 | } | |
229 | ||
230 | inline unsigned int get_num_cores() | |
231 | { | |
232 | winapi::system_info sysinfo; | |
233 | winapi::get_system_info( &sysinfo ); | |
234 | //in Windows dw is long which is equal in bits to int | |
235 | return static_cast<unsigned>(sysinfo.dwNumberOfProcessors); | |
236 | } | |
237 | ||
238 | #else //#if defined (BOOST_INTERPROCESS_WINDOWS) | |
239 | ||
240 | typedef pthread_t OS_thread_t; | |
241 | typedef pthread_t OS_thread_id_t; | |
242 | typedef pid_t OS_process_id_t; | |
243 | ||
244 | struct OS_systemwide_thread_id_t | |
245 | { | |
246 | OS_systemwide_thread_id_t() | |
247 | : pid(), tid() | |
248 | {} | |
249 | ||
250 | OS_systemwide_thread_id_t(pid_t p, pthread_t t) | |
251 | : pid(p), tid(t) | |
252 | {} | |
253 | ||
254 | OS_systemwide_thread_id_t(const OS_systemwide_thread_id_t &x) | |
255 | : pid(x.pid), tid(x.tid) | |
256 | {} | |
257 | ||
258 | OS_systemwide_thread_id_t(const volatile OS_systemwide_thread_id_t &x) | |
259 | : pid(x.pid), tid(x.tid) | |
260 | {} | |
261 | ||
262 | OS_systemwide_thread_id_t & operator=(const OS_systemwide_thread_id_t &x) | |
263 | { pid = x.pid; tid = x.tid; return *this; } | |
264 | ||
265 | OS_systemwide_thread_id_t & operator=(const volatile OS_systemwide_thread_id_t &x) | |
266 | { pid = x.pid; tid = x.tid; return *this; } | |
267 | ||
268 | void operator=(const OS_systemwide_thread_id_t &x) volatile | |
269 | { pid = x.pid; tid = x.tid; } | |
270 | ||
271 | pid_t pid; | |
272 | pthread_t tid; | |
273 | }; | |
274 | ||
275 | inline void systemwide_thread_id_copy | |
276 | (const volatile OS_systemwide_thread_id_t &from, volatile OS_systemwide_thread_id_t &to) | |
277 | { | |
278 | to.pid = from.pid; | |
279 | to.tid = from.tid; | |
280 | } | |
281 | ||
282 | //process | |
283 | inline OS_process_id_t get_current_process_id() | |
284 | { return ::getpid(); } | |
285 | ||
286 | inline OS_process_id_t get_invalid_process_id() | |
287 | { return pid_t(0); } | |
288 | ||
289 | //thread | |
290 | inline OS_thread_id_t get_current_thread_id() | |
291 | { return ::pthread_self(); } | |
292 | ||
293 | inline OS_thread_id_t get_invalid_thread_id() | |
294 | { | |
295 | static pthread_t invalid_id; | |
296 | return invalid_id; | |
297 | } | |
298 | ||
299 | inline bool equal_thread_id(OS_thread_id_t id1, OS_thread_id_t id2) | |
300 | { return 0 != pthread_equal(id1, id2); } | |
301 | ||
302 | inline void thread_yield() | |
303 | { ::sched_yield(); } | |
304 | ||
305 | #ifndef BOOST_INTERPROCESS_MATCH_ABSOLUTE_TIME | |
306 | typedef struct timespec OS_highres_count_t; | |
307 | #else | |
308 | typedef unsigned long long OS_highres_count_t; | |
309 | #endif | |
310 | ||
311 | inline unsigned long get_system_tick_ns() | |
312 | { | |
313 | #ifdef _SC_CLK_TCK | |
314 | long ticks_per_second =::sysconf(_SC_CLK_TCK); // ticks per sec | |
315 | if(ticks_per_second <= 0){ //Try a typical value on error | |
316 | ticks_per_second = 100; | |
317 | } | |
318 | return 999999999ul/static_cast<unsigned long>(ticks_per_second)+1ul; | |
319 | #else | |
320 | #error "Can't obtain system tick value for your system, please provide a patch" | |
321 | #endif | |
322 | } | |
323 | ||
324 | inline unsigned long get_system_tick_in_highres_counts() | |
325 | { | |
326 | #ifndef BOOST_INTERPROCESS_MATCH_ABSOLUTE_TIME | |
327 | return get_system_tick_ns(); | |
328 | #else | |
329 | mach_timebase_info_data_t info; | |
330 | mach_timebase_info(&info); | |
331 | //ns | |
332 | return static_cast<unsigned long> | |
333 | ( | |
334 | static_cast<double>(get_system_tick_ns()) | |
335 | / (static_cast<double>(info.numer) / info.denom) | |
336 | ); | |
337 | #endif | |
338 | } | |
339 | ||
340 | //return system ticks in us | |
341 | inline unsigned long get_system_tick_us() | |
342 | { | |
343 | return (get_system_tick_ns()-1)/1000ul + 1ul; | |
344 | } | |
345 | ||
346 | inline OS_highres_count_t get_current_system_highres_count() | |
347 | { | |
348 | #if defined(BOOST_INTERPROCESS_CLOCK_MONOTONIC) | |
349 | struct timespec count; | |
350 | ::clock_gettime(BOOST_INTERPROCESS_CLOCK_MONOTONIC, &count); | |
351 | return count; | |
352 | #elif defined(BOOST_INTERPROCESS_MATCH_ABSOLUTE_TIME) | |
353 | return ::mach_absolute_time(); | |
354 | #endif | |
355 | } | |
356 | ||
357 | #ifndef BOOST_INTERPROCESS_MATCH_ABSOLUTE_TIME | |
358 | ||
359 | inline void zero_highres_count(OS_highres_count_t &count) | |
360 | { count.tv_sec = 0; count.tv_nsec = 0; } | |
361 | ||
362 | inline bool is_highres_count_zero(const OS_highres_count_t &count) | |
363 | { return count.tv_sec == 0 && count.tv_nsec == 0; } | |
364 | ||
365 | template <class Ostream> | |
366 | inline Ostream &ostream_highres_count(Ostream &ostream, const OS_highres_count_t &count) | |
367 | { | |
368 | ostream << count.tv_sec << "s:" << count.tv_nsec << "ns"; | |
369 | return ostream; | |
370 | } | |
371 | ||
372 | inline OS_highres_count_t system_highres_count_subtract(const OS_highres_count_t &l, const OS_highres_count_t &r) | |
373 | { | |
374 | OS_highres_count_t res; | |
375 | ||
376 | if (l.tv_nsec < r.tv_nsec){ | |
377 | res.tv_nsec = 1000000000 + l.tv_nsec - r.tv_nsec; | |
378 | res.tv_sec = l.tv_sec - 1 - r.tv_sec; | |
379 | } | |
380 | else{ | |
381 | res.tv_nsec = l.tv_nsec - r.tv_nsec; | |
382 | res.tv_sec = l.tv_sec - r.tv_sec; | |
383 | } | |
384 | ||
385 | return res; | |
386 | } | |
387 | ||
388 | inline bool system_highres_count_less(const OS_highres_count_t &l, const OS_highres_count_t &r) | |
389 | { return l.tv_sec < r.tv_sec || (l.tv_sec == r.tv_sec && l.tv_nsec < r.tv_nsec); } | |
390 | ||
391 | inline bool system_highres_count_less_ul(const OS_highres_count_t &l, unsigned long r) | |
392 | { return !l.tv_sec && (static_cast<unsigned long>(l.tv_nsec) < r); } | |
393 | ||
394 | #else | |
395 | ||
396 | inline void zero_highres_count(OS_highres_count_t &count) | |
397 | { count = 0; } | |
398 | ||
399 | inline bool is_highres_count_zero(const OS_highres_count_t &count) | |
400 | { return count == 0; } | |
401 | ||
402 | template <class Ostream> | |
403 | inline Ostream &ostream_highres_count(Ostream &ostream, const OS_highres_count_t &count) | |
404 | { | |
405 | ostream << count ; | |
406 | return ostream; | |
407 | } | |
408 | ||
409 | inline OS_highres_count_t system_highres_count_subtract(const OS_highres_count_t &l, const OS_highres_count_t &r) | |
410 | { return l - r; } | |
411 | ||
412 | inline bool system_highres_count_less(const OS_highres_count_t &l, const OS_highres_count_t &r) | |
413 | { return l < r; } | |
414 | ||
415 | inline bool system_highres_count_less_ul(const OS_highres_count_t &l, unsigned long r) | |
416 | { return l < static_cast<OS_highres_count_t>(r); } | |
417 | ||
418 | #endif | |
419 | ||
420 | inline void thread_sleep_tick() | |
421 | { | |
422 | struct timespec rqt; | |
423 | //Sleep for the half of the tick time | |
424 | rqt.tv_sec = 0; | |
425 | rqt.tv_nsec = get_system_tick_ns()/2; | |
426 | ::nanosleep(&rqt, 0); | |
427 | } | |
428 | ||
429 | inline void thread_sleep(unsigned int ms) | |
430 | { | |
431 | struct timespec rqt; | |
432 | rqt.tv_sec = ms/1000u; | |
433 | rqt.tv_nsec = (ms%1000u)*1000000u; | |
434 | ::nanosleep(&rqt, 0); | |
435 | } | |
436 | ||
437 | //systemwide thread | |
438 | inline OS_systemwide_thread_id_t get_current_systemwide_thread_id() | |
439 | { | |
440 | return OS_systemwide_thread_id_t(::getpid(), ::pthread_self()); | |
441 | } | |
442 | ||
443 | inline bool equal_systemwide_thread_id(const OS_systemwide_thread_id_t &id1, const OS_systemwide_thread_id_t &id2) | |
444 | { | |
445 | return (0 != pthread_equal(id1.tid, id2.tid)) && (id1.pid == id2.pid); | |
446 | } | |
447 | ||
448 | inline OS_systemwide_thread_id_t get_invalid_systemwide_thread_id() | |
449 | { | |
450 | return OS_systemwide_thread_id_t(get_invalid_process_id(), get_invalid_thread_id()); | |
451 | } | |
452 | ||
453 | inline long double get_current_process_creation_time() | |
454 | { return 0.0L; } | |
455 | ||
456 | inline unsigned int get_num_cores() | |
457 | { | |
458 | #ifdef _SC_NPROCESSORS_ONLN | |
459 | long cores = ::sysconf(_SC_NPROCESSORS_ONLN); | |
460 | // sysconf returns -1 if the name is invalid, the option does not exist or | |
461 | // does not have a definite limit. | |
462 | // if sysconf returns some other negative number, we have no idea | |
463 | // what is going on. Default to something safe. | |
464 | if(cores <= 0){ | |
465 | return 1; | |
466 | } | |
467 | //Check for overflow (unlikely) | |
468 | else if(static_cast<unsigned long>(cores) >= | |
469 | static_cast<unsigned long>(static_cast<unsigned int>(-1))){ | |
470 | return static_cast<unsigned int>(-1); | |
471 | } | |
472 | else{ | |
473 | return static_cast<unsigned int>(cores); | |
474 | } | |
475 | #elif defined(BOOST_INTERPROCESS_BSD_DERIVATIVE) && defined(HW_NCPU) | |
476 | int request[2] = { CTL_HW, HW_NCPU }; | |
477 | int num_cores; | |
478 | std::size_t result_len = sizeof(num_cores); | |
479 | if ( (::sysctl (request, 2, &num_cores, &result_len, 0, 0) < 0) || (num_cores <= 0) ){ | |
480 | //Return a safe value | |
481 | return 1; | |
482 | } | |
483 | else{ | |
484 | return static_cast<unsigned int>(num_cores); | |
485 | } | |
11fdf7f2 TL |
486 | #elif defined(__VXWORKS__) |
487 | cpuset_t set = ::vxCpuEnabledGet(); | |
488 | #ifdef __DCC__ | |
489 | int i; | |
490 | for( i = 0; set; ++i) | |
491 | { | |
492 | set &= set -1; | |
493 | } | |
494 | return(i); | |
495 | #else | |
496 | return (__builtin_popcount(set) ); | |
497 | #endif | |
7c673cae FG |
498 | #endif |
499 | } | |
500 | ||
501 | inline int thread_create(OS_thread_t * thread, void *(*start_routine)(void*), void* arg) | |
502 | { return pthread_create(thread, 0, start_routine, arg); } | |
503 | ||
504 | inline void thread_join(OS_thread_t thread) | |
505 | { (void)pthread_join(thread, 0); } | |
506 | ||
507 | #endif //#if defined (BOOST_INTERPROCESS_WINDOWS) | |
508 | ||
509 | typedef char pid_str_t[sizeof(OS_process_id_t)*3+1]; | |
510 | ||
511 | inline void get_pid_str(pid_str_t &pid_str, OS_process_id_t pid) | |
512 | { | |
513 | bufferstream bstream(pid_str, sizeof(pid_str)); | |
514 | bstream << pid << std::ends; | |
515 | } | |
516 | ||
517 | inline void get_pid_str(pid_str_t &pid_str) | |
518 | { get_pid_str(pid_str, get_current_process_id()); } | |
519 | ||
520 | #if defined(BOOST_INTERPROCESS_WINDOWS) | |
521 | ||
522 | inline int thread_create( OS_thread_t * thread, unsigned (__stdcall * start_routine) (void*), void* arg ) | |
523 | { | |
524 | void* h = (void*)_beginthreadex( 0, 0, start_routine, arg, 0, 0 ); | |
525 | ||
526 | if( h != 0 ){ | |
527 | thread->m_handle = h; | |
528 | return 0; | |
529 | } | |
530 | else{ | |
531 | return 1; | |
532 | } | |
533 | ||
534 | thread->m_handle = (void*)_beginthreadex( 0, 0, start_routine, arg, 0, 0 ); | |
535 | return thread->m_handle != 0; | |
536 | } | |
537 | ||
538 | inline void thread_join( OS_thread_t thread) | |
539 | { | |
540 | winapi::wait_for_single_object( thread.handle(), winapi::infinite_time ); | |
541 | winapi::close_handle( thread.handle() ); | |
542 | } | |
543 | ||
544 | #endif | |
545 | ||
546 | class abstract_thread | |
547 | { | |
548 | public: | |
549 | virtual ~abstract_thread() {} | |
550 | virtual void run() = 0; | |
551 | }; | |
552 | ||
553 | template<class T> | |
554 | class os_thread_func_ptr_deleter | |
555 | { | |
556 | public: | |
557 | explicit os_thread_func_ptr_deleter(T* p) | |
558 | : m_p(p) | |
559 | {} | |
560 | ||
561 | T *release() | |
562 | { T *p = m_p; m_p = 0; return p; } | |
563 | ||
564 | T *get() const | |
565 | { return m_p; } | |
566 | ||
567 | T *operator ->() const | |
568 | { return m_p; } | |
569 | ||
570 | ~os_thread_func_ptr_deleter() | |
571 | { delete m_p; } | |
572 | ||
573 | private: | |
574 | T *m_p; | |
575 | }; | |
576 | ||
577 | #if defined(BOOST_INTERPROCESS_WINDOWS) | |
578 | ||
579 | inline unsigned __stdcall launch_thread_routine( void * pv ) | |
580 | { | |
581 | os_thread_func_ptr_deleter<abstract_thread> pt( static_cast<abstract_thread *>( pv ) ); | |
582 | pt->run(); | |
583 | return 0; | |
584 | } | |
585 | ||
586 | #else | |
587 | ||
588 | extern "C" void * launch_thread_routine( void * pv ); | |
589 | ||
590 | inline void * launch_thread_routine( void * pv ) | |
591 | { | |
592 | os_thread_func_ptr_deleter<abstract_thread> pt( static_cast<abstract_thread *>( pv ) ); | |
593 | pt->run(); | |
594 | return 0; | |
595 | } | |
596 | ||
597 | #endif | |
598 | ||
599 | template<class F> | |
600 | class launch_thread_impl | |
601 | : public abstract_thread | |
602 | { | |
603 | public: | |
604 | explicit launch_thread_impl( F f ) | |
605 | : f_( f ) | |
606 | {} | |
607 | ||
608 | void run() | |
609 | { f_(); } | |
610 | ||
611 | private: | |
612 | F f_; | |
613 | }; | |
614 | ||
615 | template<class F> | |
616 | inline int thread_launch( OS_thread_t & pt, F f ) | |
617 | { | |
618 | os_thread_func_ptr_deleter<abstract_thread> p( new launch_thread_impl<F>( f ) ); | |
619 | ||
620 | int r = thread_create(&pt, launch_thread_routine, p.get()); | |
621 | if( r == 0 ){ | |
622 | p.release(); | |
623 | } | |
624 | ||
625 | return r; | |
626 | } | |
627 | ||
628 | } //namespace ipcdetail{ | |
629 | } //namespace interprocess { | |
630 | } //namespace boost { | |
631 | ||
632 | #include <boost/interprocess/detail/config_end.hpp> | |
633 | ||
634 | #endif //BOOST_INTERPROCESS_DETAIL_OS_THREAD_FUNCTIONS_HPP |