1 //////////////////////////////////////////////////////////////////////////////
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)
7 // See http://www.boost.org/libs/interprocess for documentation.
9 //////////////////////////////////////////////////////////////////////////////
11 //Thread launching functions are adapted from boost/detail/lightweight_thread.hpp
13 // boost/detail/lightweight_thread.hpp
15 // Copyright (c) 2002 Peter Dimov and Multi Media Ltd.
16 // Copyright (c) 2008 Peter Dimov
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
22 #ifndef BOOST_INTERPROCESS_DETAIL_OS_THREAD_FUNCTIONS_HPP
23 #define BOOST_INTERPROCESS_DETAIL_OS_THREAD_FUNCTIONS_HPP
25 #ifndef BOOST_CONFIG_HPP
26 # include <boost/config.hpp>
29 #if defined(BOOST_HAS_PRAGMA_ONCE)
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>
40 #if defined(BOOST_INTERPROCESS_WINDOWS)
41 # include <boost/interprocess/detail/win32_api.hpp>
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>
55 //According to the article "C/C++ tip: How to measure elapsed real time for benchmarking"
56 # if defined(CLOCK_MONOTONIC_PRECISE) //BSD
57 # define BOOST_INTERPROCESS_CLOCK_MONOTONIC CLOCK_MONOTONIC_PRECISE
58 # elif defined(CLOCK_MONOTONIC_RAW) //Linux
59 # define BOOST_INTERPROCESS_CLOCK_MONOTONIC CLOCK_MONOTONIC_RAW
60 # elif defined(CLOCK_HIGHRES) //Solaris
61 # define BOOST_INTERPROCESS_CLOCK_MONOTONIC CLOCK_HIGHRES
62 # elif defined(CLOCK_MONOTONIC) //POSIX (AIX, BSD, Linux, Solaris)
63 # define BOOST_INTERPROCESS_CLOCK_MONOTONIC CLOCK_MONOTONIC
64 # elif !defined(CLOCK_MONOTONIC) && (defined(macintosh) || defined(__APPLE__) || defined(__APPLE_CC__))
65 # include <mach/mach_time.h> // mach_absolute_time, mach_timebase_info_data_t
66 # define BOOST_INTERPROCESS_MATCH_ABSOLUTE_TIME
68 # error "No high resolution steady clock in your system, please provide a patch"
73 namespace interprocess {
76 #if defined (BOOST_INTERPROCESS_WINDOWS)
78 typedef unsigned long OS_process_id_t;
79 typedef unsigned long OS_thread_id_t;
93 typedef OS_thread_id_t OS_systemwide_thread_id_t;
96 inline OS_process_id_t get_current_process_id()
97 { return winapi::get_current_process_id(); }
99 inline OS_process_id_t get_invalid_process_id()
100 { return OS_process_id_t(0); }
103 inline OS_thread_id_t get_current_thread_id()
104 { return winapi::get_current_thread_id(); }
106 inline OS_thread_id_t get_invalid_thread_id()
107 { return OS_thread_id_t(0xffffffff); }
109 inline bool equal_thread_id(OS_thread_id_t id1, OS_thread_id_t id2)
110 { return id1 == id2; }
112 //return the system tick in ns
113 inline unsigned long get_system_tick_ns()
115 unsigned long curres;
116 winapi::set_timer_resolution(10000, 0, &curres);
117 //Windows API returns the value in hundreds of ns
118 return (curres - 1ul)*100ul;
121 //return the system tick in us
122 inline unsigned long get_system_tick_us()
124 unsigned long curres;
125 winapi::set_timer_resolution(10000, 0, &curres);
126 //Windows API returns the value in hundreds of ns
127 return (curres - 1ul)/10ul + 1ul;
130 typedef unsigned __int64 OS_highres_count_t;
132 inline unsigned long get_system_tick_in_highres_counts()
135 unsigned long curres;
136 winapi::set_timer_resolution(10000, 0, &curres);
137 //Frequency in counts per second
138 if(!winapi::query_performance_frequency(&freq)){
139 //Tick resolution in ms
140 return (curres-1ul)/10000ul + 1ul;
144 __int64 count_fs = (1000000000000000LL - 1LL)/freq + 1LL;
145 __int64 tick_counts = (static_cast<__int64>(curres)*100000000LL - 1LL)/count_fs + 1LL;
146 return static_cast<unsigned long>(tick_counts);
150 inline OS_highres_count_t get_current_system_highres_count()
153 if(!winapi::query_performance_counter(&count)){
154 count = winapi::get_tick_count();
159 inline void zero_highres_count(OS_highres_count_t &count)
162 inline bool is_highres_count_zero(const OS_highres_count_t &count)
163 { return count == 0; }
165 template <class Ostream>
166 inline Ostream &ostream_highres_count(Ostream &ostream, const OS_highres_count_t &count)
172 inline OS_highres_count_t system_highres_count_subtract(const OS_highres_count_t &l, const OS_highres_count_t &r)
175 inline bool system_highres_count_less(const OS_highres_count_t &l, const OS_highres_count_t &r)
178 inline bool system_highres_count_less_ul(const OS_highres_count_t &l, unsigned long r)
179 { return l < static_cast<OS_highres_count_t>(r); }
181 inline void thread_sleep_tick()
182 { winapi::sleep_tick(); }
184 inline void thread_yield()
185 { winapi::sched_yield(); }
187 inline void thread_sleep(unsigned int ms)
188 { winapi::sleep(ms); }
191 inline OS_systemwide_thread_id_t get_current_systemwide_thread_id()
193 return get_current_thread_id();
196 inline void systemwide_thread_id_copy
197 (const volatile OS_systemwide_thread_id_t &from, volatile OS_systemwide_thread_id_t &to)
202 inline bool equal_systemwide_thread_id(const OS_systemwide_thread_id_t &id1, const OS_systemwide_thread_id_t &id2)
204 return equal_thread_id(id1, id2);
207 inline OS_systemwide_thread_id_t get_invalid_systemwide_thread_id()
209 return get_invalid_thread_id();
212 inline long double get_current_process_creation_time()
214 winapi::interprocess_filetime CreationTime, ExitTime, KernelTime, UserTime;
216 winapi::get_process_times
217 ( winapi::get_current_process(), &CreationTime, &ExitTime, &KernelTime, &UserTime);
219 typedef long double ldouble_t;
220 const ldouble_t resolution = (100.0l/1000000000.0l);
221 return CreationTime.dwHighDateTime*(ldouble_t(1u<<31u)*2.0l*resolution) +
222 CreationTime.dwLowDateTime*resolution;
225 inline unsigned int get_num_cores()
227 winapi::system_info sysinfo;
228 winapi::get_system_info( &sysinfo );
229 //in Windows dw is long which is equal in bits to int
230 return static_cast<unsigned>(sysinfo.dwNumberOfProcessors);
233 #else //#if defined (BOOST_INTERPROCESS_WINDOWS)
235 typedef pthread_t OS_thread_t;
236 typedef pthread_t OS_thread_id_t;
237 typedef pid_t OS_process_id_t;
239 struct OS_systemwide_thread_id_t
241 OS_systemwide_thread_id_t()
245 OS_systemwide_thread_id_t(pid_t p, pthread_t t)
249 OS_systemwide_thread_id_t(const OS_systemwide_thread_id_t &x)
250 : pid(x.pid), tid(x.tid)
253 OS_systemwide_thread_id_t(const volatile OS_systemwide_thread_id_t &x)
254 : pid(x.pid), tid(x.tid)
257 OS_systemwide_thread_id_t & operator=(const OS_systemwide_thread_id_t &x)
258 { pid = x.pid; tid = x.tid; return *this; }
260 OS_systemwide_thread_id_t & operator=(const volatile OS_systemwide_thread_id_t &x)
261 { pid = x.pid; tid = x.tid; return *this; }
263 void operator=(const OS_systemwide_thread_id_t &x) volatile
264 { pid = x.pid; tid = x.tid; }
270 inline void systemwide_thread_id_copy
271 (const volatile OS_systemwide_thread_id_t &from, volatile OS_systemwide_thread_id_t &to)
278 inline OS_process_id_t get_current_process_id()
279 { return ::getpid(); }
281 inline OS_process_id_t get_invalid_process_id()
285 inline OS_thread_id_t get_current_thread_id()
286 { return ::pthread_self(); }
288 inline OS_thread_id_t get_invalid_thread_id()
290 static pthread_t invalid_id;
294 inline bool equal_thread_id(OS_thread_id_t id1, OS_thread_id_t id2)
295 { return 0 != pthread_equal(id1, id2); }
297 inline void thread_yield()
300 #ifndef BOOST_INTERPROCESS_MATCH_ABSOLUTE_TIME
301 typedef struct timespec OS_highres_count_t;
303 typedef unsigned long long OS_highres_count_t;
306 inline unsigned long get_system_tick_ns()
309 long ticks_per_second =::sysconf(_SC_CLK_TCK); // ticks per sec
310 if(ticks_per_second <= 0){ //Try a typical value on error
311 ticks_per_second = 100;
313 return 999999999ul/static_cast<unsigned long>(ticks_per_second)+1ul;
315 #error "Can't obtain system tick value for your system, please provide a patch"
319 inline unsigned long get_system_tick_in_highres_counts()
321 #ifndef BOOST_INTERPROCESS_MATCH_ABSOLUTE_TIME
322 return get_system_tick_ns();
324 mach_timebase_info_data_t info;
325 mach_timebase_info(&info);
327 return static_cast<unsigned long>
329 static_cast<double>(get_system_tick_ns())
330 / (static_cast<double>(info.numer) / info.denom)
335 //return system ticks in us
336 inline unsigned long get_system_tick_us()
338 return (get_system_tick_ns()-1)/1000ul + 1ul;
341 inline OS_highres_count_t get_current_system_highres_count()
343 #if defined(BOOST_INTERPROCESS_CLOCK_MONOTONIC)
344 struct timespec count;
345 ::clock_gettime(BOOST_INTERPROCESS_CLOCK_MONOTONIC, &count);
347 #elif defined(BOOST_INTERPROCESS_MATCH_ABSOLUTE_TIME)
348 return ::mach_absolute_time();
352 #ifndef BOOST_INTERPROCESS_MATCH_ABSOLUTE_TIME
354 inline void zero_highres_count(OS_highres_count_t &count)
355 { count.tv_sec = 0; count.tv_nsec = 0; }
357 inline bool is_highres_count_zero(const OS_highres_count_t &count)
358 { return count.tv_sec == 0 && count.tv_nsec == 0; }
360 template <class Ostream>
361 inline Ostream &ostream_highres_count(Ostream &ostream, const OS_highres_count_t &count)
363 ostream << count.tv_sec << "s:" << count.tv_nsec << "ns";
367 inline OS_highres_count_t system_highres_count_subtract(const OS_highres_count_t &l, const OS_highres_count_t &r)
369 OS_highres_count_t res;
371 if (l.tv_nsec < r.tv_nsec){
372 res.tv_nsec = 1000000000 + l.tv_nsec - r.tv_nsec;
373 res.tv_sec = l.tv_sec - 1 - r.tv_sec;
376 res.tv_nsec = l.tv_nsec - r.tv_nsec;
377 res.tv_sec = l.tv_sec - r.tv_sec;
383 inline bool system_highres_count_less(const OS_highres_count_t &l, const OS_highres_count_t &r)
384 { return l.tv_sec < r.tv_sec || (l.tv_sec == r.tv_sec && l.tv_nsec < r.tv_nsec); }
386 inline bool system_highres_count_less_ul(const OS_highres_count_t &l, unsigned long r)
387 { return !l.tv_sec && (static_cast<unsigned long>(l.tv_nsec) < r); }
391 inline void zero_highres_count(OS_highres_count_t &count)
394 inline bool is_highres_count_zero(const OS_highres_count_t &count)
395 { return count == 0; }
397 template <class Ostream>
398 inline Ostream &ostream_highres_count(Ostream &ostream, const OS_highres_count_t &count)
404 inline OS_highres_count_t system_highres_count_subtract(const OS_highres_count_t &l, const OS_highres_count_t &r)
407 inline bool system_highres_count_less(const OS_highres_count_t &l, const OS_highres_count_t &r)
410 inline bool system_highres_count_less_ul(const OS_highres_count_t &l, unsigned long r)
411 { return l < static_cast<OS_highres_count_t>(r); }
415 inline void thread_sleep_tick()
418 //Sleep for the half of the tick time
420 rqt.tv_nsec = get_system_tick_ns()/2;
421 ::nanosleep(&rqt, 0);
424 inline void thread_sleep(unsigned int ms)
427 rqt.tv_sec = ms/1000u;
428 rqt.tv_nsec = (ms%1000u)*1000000u;
429 ::nanosleep(&rqt, 0);
433 inline OS_systemwide_thread_id_t get_current_systemwide_thread_id()
435 return OS_systemwide_thread_id_t(::getpid(), ::pthread_self());
438 inline bool equal_systemwide_thread_id(const OS_systemwide_thread_id_t &id1, const OS_systemwide_thread_id_t &id2)
440 return (0 != pthread_equal(id1.tid, id2.tid)) && (id1.pid == id2.pid);
443 inline OS_systemwide_thread_id_t get_invalid_systemwide_thread_id()
445 return OS_systemwide_thread_id_t(get_invalid_process_id(), get_invalid_thread_id());
448 inline long double get_current_process_creation_time()
451 inline unsigned int get_num_cores()
453 #ifdef _SC_NPROCESSORS_ONLN
454 long cores = ::sysconf(_SC_NPROCESSORS_ONLN);
455 // sysconf returns -1 if the name is invalid, the option does not exist or
456 // does not have a definite limit.
457 // if sysconf returns some other negative number, we have no idea
458 // what is going on. Default to something safe.
462 //Check for overflow (unlikely)
463 else if(static_cast<unsigned long>(cores) >=
464 static_cast<unsigned long>(static_cast<unsigned int>(-1))){
465 return static_cast<unsigned int>(-1);
468 return static_cast<unsigned int>(cores);
470 #elif defined(BOOST_INTERPROCESS_BSD_DERIVATIVE) && defined(HW_NCPU)
471 int request[2] = { CTL_HW, HW_NCPU };
473 std::size_t result_len = sizeof(num_cores);
474 if ( (::sysctl (request, 2, &num_cores, &result_len, 0, 0) < 0) || (num_cores <= 0) ){
475 //Return a safe value
479 return static_cast<unsigned int>(num_cores);
484 inline int thread_create(OS_thread_t * thread, void *(*start_routine)(void*), void* arg)
485 { return pthread_create(thread, 0, start_routine, arg); }
487 inline void thread_join(OS_thread_t thread)
488 { (void)pthread_join(thread, 0); }
490 #endif //#if defined (BOOST_INTERPROCESS_WINDOWS)
492 typedef char pid_str_t[sizeof(OS_process_id_t)*3+1];
494 inline void get_pid_str(pid_str_t &pid_str, OS_process_id_t pid)
496 bufferstream bstream(pid_str, sizeof(pid_str));
497 bstream << pid << std::ends;
500 inline void get_pid_str(pid_str_t &pid_str)
501 { get_pid_str(pid_str, get_current_process_id()); }
503 #if defined(BOOST_INTERPROCESS_WINDOWS)
505 inline int thread_create( OS_thread_t * thread, unsigned (__stdcall * start_routine) (void*), void* arg )
507 void* h = (void*)_beginthreadex( 0, 0, start_routine, arg, 0, 0 );
510 thread->m_handle = h;
517 thread->m_handle = (void*)_beginthreadex( 0, 0, start_routine, arg, 0, 0 );
518 return thread->m_handle != 0;
521 inline void thread_join( OS_thread_t thread)
523 winapi::wait_for_single_object( thread.handle(), winapi::infinite_time );
524 winapi::close_handle( thread.handle() );
529 class abstract_thread
532 virtual ~abstract_thread() {}
533 virtual void run() = 0;
537 class os_thread_func_ptr_deleter
540 explicit os_thread_func_ptr_deleter(T* p)
545 { T *p = m_p; m_p = 0; return p; }
550 T *operator ->() const
553 ~os_thread_func_ptr_deleter()
560 #if defined(BOOST_INTERPROCESS_WINDOWS)
562 inline unsigned __stdcall launch_thread_routine( void * pv )
564 os_thread_func_ptr_deleter<abstract_thread> pt( static_cast<abstract_thread *>( pv ) );
571 extern "C" void * launch_thread_routine( void * pv );
573 inline void * launch_thread_routine( void * pv )
575 os_thread_func_ptr_deleter<abstract_thread> pt( static_cast<abstract_thread *>( pv ) );
583 class launch_thread_impl
584 : public abstract_thread
587 explicit launch_thread_impl( F f )
599 inline int thread_launch( OS_thread_t & pt, F f )
601 os_thread_func_ptr_deleter<abstract_thread> p( new launch_thread_impl<F>( f ) );
603 int r = thread_create(&pt, launch_thread_routine, p.get());
611 } //namespace ipcdetail{
612 } //namespace interprocess {
613 } //namespace boost {
615 #include <boost/interprocess/detail/config_end.hpp>
617 #endif //BOOST_INTERPROCESS_DETAIL_OS_THREAD_FUNCTIONS_HPP