diff options
Diffstat (limited to 'boost/interprocess/detail/os_thread_functions.hpp')
-rw-r--r-- | boost/interprocess/detail/os_thread_functions.hpp | 417 |
1 files changed, 402 insertions, 15 deletions
diff --git a/boost/interprocess/detail/os_thread_functions.hpp b/boost/interprocess/detail/os_thread_functions.hpp index 8d769fc4e9..4604683645 100644 --- a/boost/interprocess/detail/os_thread_functions.hpp +++ b/boost/interprocess/detail/os_thread_functions.hpp @@ -1,6 +1,6 @@ ////////////////////////////////////////////////////////////////////////////// // -// (C) Copyright Ion Gaztanaga 2005-2011. Distributed under the Boost +// (C) Copyright Ion Gaztanaga 2005-2013. Distributed under the Boost // Software License, Version 1.0. (See accompanying file // LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) // @@ -8,24 +8,60 @@ // ////////////////////////////////////////////////////////////////////////////// +//Thread launching functions are adapted from boost/detail/lightweight_thread.hpp +// +// boost/detail/lightweight_thread.hpp +// +// Copyright (c) 2002 Peter Dimov and Multi Media Ltd. +// Copyright (c) 2008 Peter Dimov +// +// Distributed under the Boost Software License, Version 1.0. +// See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt + #ifndef BOOST_INTERPROCESS_DETAIL_OS_THREAD_FUNCTIONS_HPP #define BOOST_INTERPROCESS_DETAIL_OS_THREAD_FUNCTIONS_HPP +#if defined(_MSC_VER) +# pragma once +#endif + #include <boost/interprocess/detail/config_begin.hpp> #include <boost/interprocess/detail/workaround.hpp> #include <boost/interprocess/streams/bufferstream.hpp> #include <boost/interprocess/detail/posix_time_types_wrk.hpp> +#include <cstddef> +#include <memory> -#if (defined BOOST_INTERPROCESS_WINDOWS) +#if defined(BOOST_INTERPROCESS_WINDOWS) # include <boost/interprocess/detail/win32_api.hpp> +# include <process.h> #else -# ifdef BOOST_HAS_UNISTD_H -# include <pthread.h> -# include <unistd.h> -# include <sched.h> -# include <time.h> +# include <pthread.h> +# include <unistd.h> +# include <sched.h> +# include <time.h> +# ifdef BOOST_INTERPROCESS_BSD_DERIVATIVE + //Some *BSD systems (OpenBSD & NetBSD) need sys/param.h before sys/sysctl.h, whereas + //others (FreeBSD & Darwin) need sys/types.h +# include <sys/types.h> +# include <sys/param.h> +# include <sys/sysctl.h> +# endif +//According to the article "C/C++ tip: How to measure elapsed real time for benchmarking" +# if defined(CLOCK_MONOTONIC_PRECISE) //BSD +# define BOOST_INTERPROCESS_CLOCK_MONOTONIC CLOCK_MONOTONIC_PRECISE +# elif defined(CLOCK_MONOTONIC_RAW) //Linux +# define BOOST_INTERPROCESS_CLOCK_MONOTONIC CLOCK_MONOTONIC_RAW +# elif defined(CLOCK_HIGHRES) //Solaris +# define BOOST_INTERPROCESS_CLOCK_MONOTONIC CLOCK_HIGHRES +# elif defined(CLOCK_MONOTONIC) //POSIX (AIX, BSD, Linux, Solaris) +# define BOOST_INTERPROCESS_CLOCK_MONOTONIC CLOCK_MONOTONIC +# elif !defined(CLOCK_MONOTONIC) && (defined(macintosh) || defined(__APPLE__) || defined(__APPLE_CC__)) +# include <mach/mach_time.h> // mach_absolute_time, mach_timebase_info_data_t +# define BOOST_INTERPROCESS_MATCH_ABSOLUTE_TIME # else -# error Unknown platform +# error "No high resolution steady clock in your system, please provide a patch" # endif #endif @@ -33,10 +69,11 @@ namespace boost { namespace interprocess { namespace ipcdetail{ -#if (defined BOOST_INTERPROCESS_WINDOWS) +#if defined (BOOST_INTERPROCESS_WINDOWS) typedef unsigned long OS_process_id_t; typedef unsigned long OS_thread_id_t; +typedef void* OS_thread_t; typedef OS_thread_id_t OS_systemwide_thread_id_t; //process @@ -56,11 +93,83 @@ inline OS_thread_id_t get_invalid_thread_id() inline bool equal_thread_id(OS_thread_id_t id1, OS_thread_id_t id2) { return id1 == id2; } +//return the system tick in ns +inline unsigned long get_system_tick_ns() +{ + unsigned long curres; + winapi::set_timer_resolution(10000, 0, &curres); + //Windows API returns the value in hundreds of ns + return (curres - 1ul)*100ul; +} + +//return the system tick in us +inline unsigned long get_system_tick_us() +{ + unsigned long curres; + winapi::set_timer_resolution(10000, 0, &curres); + //Windows API returns the value in hundreds of ns + return (curres - 1ul)/10ul + 1ul; +} + +typedef unsigned __int64 OS_highres_count_t; + +inline unsigned long get_system_tick_in_highres_counts() +{ + __int64 freq; + unsigned long curres; + winapi::set_timer_resolution(10000, 0, &curres); + //Frequency in counts per second + if(!winapi::query_performance_frequency(&freq)){ + //Tick resolution in ms + return (curres-1ul)/10000ul + 1ul; + } + else{ + //In femtoseconds + __int64 count_fs = (1000000000000000LL - 1LL)/freq + 1LL; + __int64 tick_counts = (static_cast<__int64>(curres)*100000000LL - 1LL)/count_fs + 1LL; + return static_cast<unsigned long>(tick_counts); + } +} + +inline OS_highres_count_t get_current_system_highres_count() +{ + __int64 count; + if(!winapi::query_performance_counter(&count)){ + count = winapi::get_tick_count(); + } + return count; +} + +inline void zero_highres_count(OS_highres_count_t &count) +{ count = 0; } + +inline bool is_highres_count_zero(const OS_highres_count_t &count) +{ return count == 0; } + +template <class Ostream> +inline Ostream &ostream_highres_count(Ostream &ostream, const OS_highres_count_t &count) +{ + ostream << count; + return ostream; +} + +inline OS_highres_count_t system_highres_count_subtract(const OS_highres_count_t &l, const OS_highres_count_t &r) +{ return l - r; } + +inline bool system_highres_count_less(const OS_highres_count_t &l, const OS_highres_count_t &r) +{ return l < r; } + +inline bool system_highres_count_less_ul(const OS_highres_count_t &l, unsigned long r) +{ return l < static_cast<OS_highres_count_t>(r); } + +inline void thread_sleep_tick() +{ winapi::sleep_tick(); } + inline void thread_yield() { winapi::sched_yield(); } inline void thread_sleep(unsigned int ms) -{ winapi::Sleep(ms); } +{ winapi::sleep(ms); } //systemwide thread inline OS_systemwide_thread_id_t get_current_systemwide_thread_id() @@ -88,7 +197,7 @@ inline long double get_current_process_creation_time() { winapi::interprocess_filetime CreationTime, ExitTime, KernelTime, UserTime; - get_process_times + winapi::get_process_times ( winapi::get_current_process(), &CreationTime, &ExitTime, &KernelTime, &UserTime); typedef long double ldouble_t; @@ -97,14 +206,22 @@ inline long double get_current_process_creation_time() CreationTime.dwLowDateTime*resolution; } +inline unsigned int get_num_cores() +{ + winapi::system_info sysinfo; + winapi::get_system_info( &sysinfo ); + //in Windows dw is long which is equal in bits to int + return static_cast<unsigned>(sysinfo.dwNumberOfProcessors); +} -#else //#if (defined BOOST_INTERPROCESS_WINDOWS) +#else //#if defined (BOOST_INTERPROCESS_WINDOWS) +typedef pthread_t OS_thread_t; typedef pthread_t OS_thread_id_t; typedef pid_t OS_process_id_t; struct OS_systemwide_thread_id_t -{ +{ OS_systemwide_thread_id_t() : pid(), tid() {} @@ -164,9 +281,135 @@ inline bool equal_thread_id(OS_thread_id_t id1, OS_thread_id_t id2) inline void thread_yield() { ::sched_yield(); } +#ifndef BOOST_INTERPROCESS_MATCH_ABSOLUTE_TIME +typedef struct timespec OS_highres_count_t; +#else +typedef unsigned long long OS_highres_count_t; +#endif + +inline unsigned long get_system_tick_ns() +{ + #ifdef _SC_CLK_TCK + long ticks_per_second =::sysconf(_SC_CLK_TCK); // ticks per sec + if(ticks_per_second <= 0){ //Try a typical value on error + ticks_per_second = 100; + } + return 999999999ul/static_cast<unsigned long>(ticks_per_second)+1ul; + #else + #error "Can't obtain system tick value for your system, please provide a patch" + #endif +} + +inline unsigned long get_system_tick_in_highres_counts() +{ + #ifndef BOOST_INTERPROCESS_MATCH_ABSOLUTE_TIME + return get_system_tick_ns(); + #else + mach_timebase_info_data_t info; + mach_timebase_info(&info); + //ns + return static_cast<unsigned long> + ( + static_cast<double>(get_system_tick_ns()) + / (static_cast<double>(info.numer) / info.denom) + ); + #endif +} + +//return system ticks in us +inline unsigned long get_system_tick_us() +{ + return (get_system_tick_ns()-1)/1000ul + 1ul; +} + +inline OS_highres_count_t get_current_system_highres_count() +{ + #if defined(BOOST_INTERPROCESS_CLOCK_MONOTONIC) + struct timespec count; + ::clock_gettime(BOOST_INTERPROCESS_CLOCK_MONOTONIC, &count); + return count; + #elif defined(BOOST_INTERPROCESS_MATCH_ABSOLUTE_TIME) + return ::mach_absolute_time(); + #endif +} + +#ifndef BOOST_INTERPROCESS_MATCH_ABSOLUTE_TIME + +inline void zero_highres_count(OS_highres_count_t &count) +{ count.tv_sec = 0; count.tv_nsec = 0; } + +inline bool is_highres_count_zero(const OS_highres_count_t &count) +{ return count.tv_sec == 0 && count.tv_nsec == 0; } + +template <class Ostream> +inline Ostream &ostream_highres_count(Ostream &ostream, const OS_highres_count_t &count) +{ + ostream << count.tv_sec << "s:" << count.tv_nsec << "ns"; + return ostream; +} + +inline OS_highres_count_t system_highres_count_subtract(const OS_highres_count_t &l, const OS_highres_count_t &r) +{ + OS_highres_count_t res; + + if (l.tv_nsec < r.tv_nsec){ + res.tv_nsec = 1000000000 + l.tv_nsec - r.tv_nsec; + res.tv_sec = l.tv_sec - 1 - r.tv_sec; + } + else{ + res.tv_nsec = l.tv_nsec - r.tv_nsec; + res.tv_sec = l.tv_sec - r.tv_sec; + } + + return res; +} + +inline bool system_highres_count_less(const OS_highres_count_t &l, const OS_highres_count_t &r) +{ return l.tv_sec < r.tv_sec || (l.tv_sec == r.tv_sec && l.tv_nsec < r.tv_nsec); } + +inline bool system_highres_count_less_ul(const OS_highres_count_t &l, unsigned long r) +{ return !l.tv_sec && (static_cast<unsigned long>(l.tv_nsec) < r); } + +#else + +inline void zero_highres_count(OS_highres_count_t &count) +{ count = 0; } + +inline bool is_highres_count_zero(const OS_highres_count_t &count) +{ return count == 0; } + +template <class Ostream> +inline Ostream &ostream_highres_count(Ostream &ostream, const OS_highres_count_t &count) +{ + ostream << count ; + return ostream; +} + +inline OS_highres_count_t system_highres_count_subtract(const OS_highres_count_t &l, const OS_highres_count_t &r) +{ return l - r; } + +inline bool system_highres_count_less(const OS_highres_count_t &l, const OS_highres_count_t &r) +{ return l < r; } + +inline bool system_highres_count_less_ul(const OS_highres_count_t &l, unsigned long r) +{ return l < static_cast<OS_highres_count_t>(r); } + +#endif + +inline void thread_sleep_tick() +{ + struct timespec rqt; + //Sleep for the half of the tick time + rqt.tv_sec = 0; + rqt.tv_nsec = get_system_tick_ns()/2; + ::nanosleep(&rqt, 0); +} + inline void thread_sleep(unsigned int ms) { - const struct timespec rqt = { ms/1000u, (ms%1000u)*1000000u }; + struct timespec rqt; + rqt.tv_sec = ms/1000u; + rqt.tv_nsec = (ms%1000u)*1000000u; ::nanosleep(&rqt, 0); } @@ -189,7 +432,46 @@ inline OS_systemwide_thread_id_t get_invalid_systemwide_thread_id() inline long double get_current_process_creation_time() { return 0.0L; } -#endif //#if (defined BOOST_INTERPROCESS_WINDOWS) +inline unsigned int get_num_cores() +{ + #ifdef _SC_NPROCESSORS_ONLN + long cores = ::sysconf(_SC_NPROCESSORS_ONLN); + // sysconf returns -1 if the name is invalid, the option does not exist or + // does not have a definite limit. + // if sysconf returns some other negative number, we have no idea + // what is going on. Default to something safe. + if(cores <= 0){ + return 1; + } + //Check for overflow (unlikely) + else if(static_cast<unsigned long>(cores) >= + static_cast<unsigned long>(static_cast<unsigned int>(-1))){ + return static_cast<unsigned int>(-1); + } + else{ + return static_cast<unsigned int>(cores); + } + #elif defined(BOOST_INTERPROCESS_BSD_DERIVATIVE) && defined(HW_NCPU) + int request[2] = { CTL_HW, HW_NCPU }; + int num_cores; + std::size_t result_len = sizeof(num_cores); + if ( (::sysctl (request, 2, &num_cores, &result_len, 0, 0) < 0) || (num_cores <= 0) ){ + //Return a safe value + return 1; + } + else{ + return static_cast<unsigned int>(num_cores); + } + #endif +} + +inline int thread_create(OS_thread_t * thread, void *(*start_routine)(void*), void* arg) +{ return pthread_create(thread, 0, start_routine, arg); } + +inline void thread_join(OS_thread_t thread) +{ (void)pthread_join(thread, 0); } + +#endif //#if defined (BOOST_INTERPROCESS_WINDOWS) typedef char pid_str_t[sizeof(OS_process_id_t)*3+1]; @@ -202,6 +484,111 @@ inline void get_pid_str(pid_str_t &pid_str, OS_process_id_t pid) inline void get_pid_str(pid_str_t &pid_str) { get_pid_str(pid_str, get_current_process_id()); } +#if defined(BOOST_INTERPROCESS_WINDOWS) + +inline int thread_create( OS_thread_t * thread, unsigned (__stdcall * start_routine) (void*), void* arg ) +{ + void* h = (void*)_beginthreadex( 0, 0, start_routine, arg, 0, 0 ); + + if( h != 0 ){ + *thread = h; + return 0; + } + else{ + return 1; + } +} + +inline void thread_join( OS_thread_t thread) +{ + winapi::wait_for_single_object( thread, winapi::infinite_time ); + winapi::close_handle( thread ); +} + +#endif + +class abstract_thread +{ + public: + virtual ~abstract_thread() {} + virtual void run() = 0; +}; + +template<class T> +class os_thread_func_ptr_deleter +{ + public: + explicit os_thread_func_ptr_deleter(T* p) + : m_p(p) + {} + + T *release() + { T *p = m_p; m_p = 0; return p; } + + T *get() const + { return m_p; } + + T *operator ->() const + { return m_p; } + + ~os_thread_func_ptr_deleter() + { delete m_p; } + + private: + T *m_p; +}; + +#if defined(BOOST_INTERPROCESS_WINDOWS) + +inline unsigned __stdcall launch_thread_routine( void * pv ) +{ + os_thread_func_ptr_deleter<abstract_thread> pt( static_cast<abstract_thread *>( pv ) ); + pt->run(); + return 0; +} + +#else + +extern "C" void * launch_thread_routine( void * pv ); + +inline void * launch_thread_routine( void * pv ) +{ + os_thread_func_ptr_deleter<abstract_thread> pt( static_cast<abstract_thread *>( pv ) ); + pt->run(); + return 0; +} + +#endif + +template<class F> +class launch_thread_impl + : public abstract_thread +{ + public: + explicit launch_thread_impl( F f ) + : f_( f ) + {} + + void run() + { f_(); } + + private: + F f_; +}; + +template<class F> +inline int thread_launch( OS_thread_t & pt, F f ) +{ + os_thread_func_ptr_deleter<abstract_thread> p( new launch_thread_impl<F>( f ) ); + + int r = thread_create(&pt, launch_thread_routine, p.get()); + if( r == 0 ){ + p.release(); + } + + return r; +} + } //namespace ipcdetail{ } //namespace interprocess { } //namespace boost { |