summaryrefslogtreecommitdiff
path: root/boost/thread/detail/platform_time.hpp
diff options
context:
space:
mode:
Diffstat (limited to 'boost/thread/detail/platform_time.hpp')
-rw-r--r--boost/thread/detail/platform_time.hpp478
1 files changed, 478 insertions, 0 deletions
diff --git a/boost/thread/detail/platform_time.hpp b/boost/thread/detail/platform_time.hpp
new file mode 100644
index 0000000000..2180f13c05
--- /dev/null
+++ b/boost/thread/detail/platform_time.hpp
@@ -0,0 +1,478 @@
+#ifndef BOOST_THREAD_DETAIL_PLATFORM_TIME_HPP
+#define BOOST_THREAD_DETAIL_PLATFORM_TIME_HPP
+// (C) Copyright 2007-8 Anthony Williams
+// (C) Copyright 2012 Vicente J. Botet Escriba
+//
+// 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)
+
+#include <boost/thread/detail/config.hpp>
+#include <boost/thread/thread_time.hpp>
+#if defined BOOST_THREAD_USES_DATETIME
+#include <boost/date_time/posix_time/conversion.hpp>
+#endif
+#ifndef _WIN32
+#include <unistd.h>
+#endif
+#ifdef BOOST_THREAD_USES_CHRONO
+#include <boost/chrono/duration.hpp>
+#include <boost/chrono/system_clocks.hpp>
+#include <boost/chrono/ceil.hpp>
+#endif
+
+#if defined(BOOST_THREAD_CHRONO_WINDOWS_API)
+#include <boost/detail/winapi/time.hpp>
+#include <boost/detail/winapi/timers.hpp>
+#include <boost/thread/win32/thread_primitives.hpp>
+#elif defined(BOOST_THREAD_CHRONO_MAC_API)
+#include <sys/time.h> //for gettimeofday and timeval
+#include <mach/mach_time.h> // mach_absolute_time, mach_timebase_info_data_t
+
+#else
+#include <time.h> // for clock_gettime
+#endif
+
+#include <limits>
+
+#include <boost/config/abi_prefix.hpp>
+
+namespace boost
+{
+//typedef boost::int_least64_t time_max_t;
+typedef boost::intmax_t time_max_t;
+
+#if defined BOOST_THREAD_CHRONO_MAC_API
+namespace threads
+{
+
+namespace chrono_details
+{
+
+// steady_clock
+
+// Note, in this implementation steady_clock and high_resolution_clock
+// are the same clock. They are both based on mach_absolute_time().
+// mach_absolute_time() * MachInfo.numer / MachInfo.denom is the number of
+// nanoseconds since the computer booted up. MachInfo.numer and MachInfo.denom
+// are run time constants supplied by the OS. This clock has no relationship
+// to the Gregorian calendar. It's main use is as a high resolution timer.
+
+// MachInfo.numer / MachInfo.denom is often 1 on the latest equipment. Specialize
+// for that case as an optimization.
+
+inline time_max_t
+steady_simplified()
+{
+ return mach_absolute_time();
+}
+
+inline double compute_steady_factor(kern_return_t& err)
+{
+ mach_timebase_info_data_t MachInfo;
+ err = mach_timebase_info(&MachInfo);
+ if ( err != 0 ) {
+ return 0;
+ }
+ return static_cast<double>(MachInfo.numer) / MachInfo.denom;
+}
+
+inline time_max_t steady_full()
+{
+ kern_return_t err;
+ const double factor = chrono_details::compute_steady_factor(err);
+ if (err != 0)
+ {
+ BOOST_ASSERT(0 && "Boost::Chrono - Internal Error");
+ }
+ return static_cast<time_max_t>(mach_absolute_time() * factor);
+}
+
+
+typedef time_max_t (*FP)();
+
+inline FP init_steady_clock(kern_return_t & err)
+{
+ mach_timebase_info_data_t MachInfo;
+ err = mach_timebase_info(&MachInfo);
+ if ( err != 0 )
+ {
+ return 0;
+ }
+
+ if (MachInfo.numer == MachInfo.denom)
+ {
+ return &chrono_details::steady_simplified;
+ }
+ return &chrono_details::steady_full;
+}
+
+}
+}
+#endif
+
+ namespace detail
+ {
+#if defined BOOST_THREAD_CHRONO_POSIX_API || defined BOOST_THREAD_CHRONO_MAC_API
+ inline timespec ns_to_timespec(boost::time_max_t const& ns)
+ {
+ boost::time_max_t s = ns / 1000000000l;
+ timespec ts;
+ ts.tv_sec = static_cast<long> (s);
+ ts.tv_nsec = static_cast<long> (ns - s * 1000000000l);
+ return ts;
+ }
+ inline boost::time_max_t timespec_to_ns(timespec const& ts)
+ {
+ return static_cast<boost::time_max_t>(ts.tv_sec) * 1000000000l + ts.tv_nsec;
+ }
+#endif
+
+ struct platform_duration
+ {
+#if defined BOOST_THREAD_CHRONO_POSIX_API || defined BOOST_THREAD_CHRONO_MAC_API
+ explicit platform_duration(timespec const& v) : ts_val(v) {}
+ timespec const& getTs() const { return ts_val; }
+
+ explicit platform_duration(boost::time_max_t const& ns = 0) : ts_val(ns_to_timespec(ns)) {}
+ boost::time_max_t getNs() const { return timespec_to_ns(ts_val); }
+#else
+ explicit platform_duration(boost::time_max_t const& ns = 0) : ns_val(ns) {}
+ boost::time_max_t getNs() const { return ns_val; }
+#endif
+
+#if defined BOOST_THREAD_USES_DATETIME
+ platform_duration(boost::posix_time::time_duration const& rel_time)
+ {
+#if defined BOOST_THREAD_CHRONO_POSIX_API || defined BOOST_THREAD_CHRONO_MAC_API
+ ts_val.tv_sec = rel_time.total_seconds();
+ ts_val.tv_nsec = static_cast<long>(rel_time.fractional_seconds() * (1000000000l / rel_time.ticks_per_second()));
+#else
+ ns_val = static_cast<boost::time_max_t>(rel_time.total_seconds()) * 1000000000l;
+ ns_val += rel_time.fractional_seconds() * (1000000000l / rel_time.ticks_per_second());
+#endif
+ }
+#endif
+
+#if defined BOOST_THREAD_USES_CHRONO
+ template <class Rep, class Period>
+ platform_duration(chrono::duration<Rep, Period> const& d)
+ {
+#if defined BOOST_THREAD_CHRONO_POSIX_API || defined BOOST_THREAD_CHRONO_MAC_API
+ ts_val = ns_to_timespec(chrono::ceil<chrono::nanoseconds>(d).count());
+#else
+ ns_val = chrono::ceil<chrono::nanoseconds>(d).count();
+#endif
+ }
+#endif
+
+ boost::time_max_t getMs() const
+ {
+ const boost::time_max_t ns = getNs();
+ // ceil/floor away from zero
+ if (ns >= 0)
+ {
+ // return ceiling of positive numbers
+ return (ns + 999999) / 1000000;
+ }
+ else
+ {
+ // return floor of negative numbers
+ return (ns - 999999) / 1000000;
+ }
+ }
+
+ static platform_duration zero()
+ {
+ return platform_duration(0);
+ }
+
+ private:
+#if defined BOOST_THREAD_CHRONO_POSIX_API || defined BOOST_THREAD_CHRONO_MAC_API
+ timespec ts_val;
+#else
+ boost::time_max_t ns_val;
+#endif
+ };
+
+ inline bool operator==(platform_duration const& lhs, platform_duration const& rhs)
+ {
+ return lhs.getNs() == rhs.getNs();
+ }
+ inline bool operator!=(platform_duration const& lhs, platform_duration const& rhs)
+ {
+ return lhs.getNs() != rhs.getNs();
+ }
+ inline bool operator<(platform_duration const& lhs, platform_duration const& rhs)
+ {
+ return lhs.getNs() < rhs.getNs();
+ }
+ inline bool operator<=(platform_duration const& lhs, platform_duration const& rhs)
+ {
+ return lhs.getNs() <= rhs.getNs();
+ }
+ inline bool operator>(platform_duration const& lhs, platform_duration const& rhs)
+ {
+ return lhs.getNs() > rhs.getNs();
+ }
+ inline bool operator>=(platform_duration const& lhs, platform_duration const& rhs)
+ {
+ return lhs.getNs() >= rhs.getNs();
+ }
+
+ static inline platform_duration platform_milliseconds(long const& ms)
+ {
+ return platform_duration(ms * 1000000l);
+ }
+
+ struct real_platform_timepoint
+ {
+#if defined BOOST_THREAD_CHRONO_POSIX_API || defined BOOST_THREAD_CHRONO_MAC_API
+ explicit real_platform_timepoint(timespec const& v) : dur(v) {}
+ timespec const& getTs() const { return dur.getTs(); }
+#endif
+
+ explicit real_platform_timepoint(boost::time_max_t const& ns) : dur(ns) {}
+ boost::time_max_t getNs() const { return dur.getNs(); }
+
+#if defined BOOST_THREAD_USES_DATETIME
+ real_platform_timepoint(boost::system_time const& abs_time)
+ : dur(abs_time - boost::posix_time::from_time_t(0)) {}
+#endif
+
+#if defined BOOST_THREAD_USES_CHRONO
+ template <class Duration>
+ real_platform_timepoint(chrono::time_point<chrono::system_clock, Duration> const& abs_time)
+ : dur(abs_time.time_since_epoch()) {}
+#endif
+
+ private:
+ platform_duration dur;
+ };
+
+ inline bool operator==(real_platform_timepoint const& lhs, real_platform_timepoint const& rhs)
+ {
+ return lhs.getNs() == rhs.getNs();
+ }
+ inline bool operator!=(real_platform_timepoint const& lhs, real_platform_timepoint const& rhs)
+ {
+ return lhs.getNs() != rhs.getNs();
+ }
+ inline bool operator<(real_platform_timepoint const& lhs, real_platform_timepoint const& rhs)
+ {
+ return lhs.getNs() < rhs.getNs();
+ }
+ inline bool operator<=(real_platform_timepoint const& lhs, real_platform_timepoint const& rhs)
+ {
+ return lhs.getNs() <= rhs.getNs();
+ }
+ inline bool operator>(real_platform_timepoint const& lhs, real_platform_timepoint const& rhs)
+ {
+ return lhs.getNs() > rhs.getNs();
+ }
+ inline bool operator>=(real_platform_timepoint const& lhs, real_platform_timepoint const& rhs)
+ {
+ return lhs.getNs() >= rhs.getNs();
+ }
+
+ inline real_platform_timepoint operator+(real_platform_timepoint const& lhs, platform_duration const& rhs)
+ {
+ return real_platform_timepoint(lhs.getNs() + rhs.getNs());
+ }
+ inline real_platform_timepoint operator+(platform_duration const& lhs, real_platform_timepoint const& rhs)
+ {
+ return real_platform_timepoint(lhs.getNs() + rhs.getNs());
+ }
+ inline platform_duration operator-(real_platform_timepoint const& lhs, real_platform_timepoint const& rhs)
+ {
+ return platform_duration(lhs.getNs() - rhs.getNs());
+ }
+
+ struct real_platform_clock
+ {
+ static real_platform_timepoint now()
+ {
+#if defined(BOOST_THREAD_CHRONO_WINDOWS_API)
+ boost::detail::winapi::FILETIME_ ft;
+ boost::detail::winapi::GetSystemTimeAsFileTime(&ft); // never fails
+ boost::time_max_t ns = ((((static_cast<boost::time_max_t>(ft.dwHighDateTime) << 32) | ft.dwLowDateTime) - 116444736000000000LL) * 100LL);
+ return real_platform_timepoint(ns);
+#elif defined(BOOST_THREAD_CHRONO_MAC_API)
+ timeval tv;
+ ::gettimeofday(&tv, 0);
+ timespec ts;
+ ts.tv_sec = tv.tv_sec;
+ ts.tv_nsec = tv.tv_usec * 1000;
+ return real_platform_timepoint(ts);
+#else
+ timespec ts;
+ if ( ::clock_gettime( CLOCK_REALTIME, &ts ) )
+ {
+ BOOST_ASSERT(0 && "Boost::Thread - clock_gettime(CLOCK_REALTIME) Internal Error");
+ return real_platform_timepoint(0);
+ }
+ return real_platform_timepoint(ts);
+#endif
+ }
+ };
+
+#if defined(BOOST_THREAD_HAS_MONO_CLOCK)
+
+ struct mono_platform_timepoint
+ {
+#if defined BOOST_THREAD_CHRONO_POSIX_API || defined BOOST_THREAD_CHRONO_MAC_API
+
+ explicit mono_platform_timepoint(timespec const& v) : dur(v) {}
+ timespec const& getTs() const { return dur.getTs(); }
+#endif
+
+ explicit mono_platform_timepoint(boost::time_max_t const& ns) : dur(ns) {}
+ boost::time_max_t getNs() const { return dur.getNs(); }
+
+#if defined BOOST_THREAD_USES_CHRONO
+ // This conversion assumes that chrono::steady_clock::time_point and mono_platform_timepoint share the same epoch.
+ template <class Duration>
+ mono_platform_timepoint(chrono::time_point<chrono::steady_clock, Duration> const& abs_time)
+ : dur(abs_time.time_since_epoch()) {}
+#endif
+
+ // can't name this max() since that is a macro on some Windows systems
+ static mono_platform_timepoint getMax()
+ {
+#if defined BOOST_THREAD_CHRONO_POSIX_API || defined BOOST_THREAD_CHRONO_MAC_API
+ timespec ts;
+ ts.tv_sec = (std::numeric_limits<time_t>::max)();
+ ts.tv_nsec = 999999999;
+ return mono_platform_timepoint(ts);
+#else
+ boost::time_max_t ns = (std::numeric_limits<boost::time_max_t>::max)();
+ return mono_platform_timepoint(ns);
+#endif
+ }
+
+ private:
+ platform_duration dur;
+ };
+
+ inline bool operator==(mono_platform_timepoint const& lhs, mono_platform_timepoint const& rhs)
+ {
+ return lhs.getNs() == rhs.getNs();
+ }
+ inline bool operator!=(mono_platform_timepoint const& lhs, mono_platform_timepoint const& rhs)
+ {
+ return lhs.getNs() != rhs.getNs();
+ }
+ inline bool operator<(mono_platform_timepoint const& lhs, mono_platform_timepoint const& rhs)
+ {
+ return lhs.getNs() < rhs.getNs();
+ }
+ inline bool operator<=(mono_platform_timepoint const& lhs, mono_platform_timepoint const& rhs)
+ {
+ return lhs.getNs() <= rhs.getNs();
+ }
+ inline bool operator>(mono_platform_timepoint const& lhs, mono_platform_timepoint const& rhs)
+ {
+ return lhs.getNs() > rhs.getNs();
+ }
+ inline bool operator>=(mono_platform_timepoint const& lhs, mono_platform_timepoint const& rhs)
+ {
+ return lhs.getNs() >= rhs.getNs();
+ }
+
+ inline mono_platform_timepoint operator+(mono_platform_timepoint const& lhs, platform_duration const& rhs)
+ {
+ return mono_platform_timepoint(lhs.getNs() + rhs.getNs());
+ }
+ inline mono_platform_timepoint operator+(platform_duration const& lhs, mono_platform_timepoint const& rhs)
+ {
+ return mono_platform_timepoint(lhs.getNs() + rhs.getNs());
+ }
+ inline platform_duration operator-(mono_platform_timepoint const& lhs, mono_platform_timepoint const& rhs)
+ {
+ return platform_duration(lhs.getNs() - rhs.getNs());
+ }
+
+ struct mono_platform_clock
+ {
+ static mono_platform_timepoint now()
+ {
+#if defined(BOOST_THREAD_CHRONO_WINDOWS_API)
+#if defined(BOOST_THREAD_USES_CHRONO)
+ // Use QueryPerformanceCounter() to match the implementation in Boost
+ // Chrono so that chrono::steady_clock::now() and this function share the
+ // same epoch and so can be converted between each other.
+ boost::detail::winapi::LARGE_INTEGER_ freq;
+ if ( !boost::detail::winapi::QueryPerformanceFrequency( &freq ) )
+ {
+ BOOST_ASSERT(0 && "Boost::Thread - QueryPerformanceFrequency Internal Error");
+ return mono_platform_timepoint(0);
+ }
+ if ( freq.QuadPart <= 0 )
+ {
+ BOOST_ASSERT(0 && "Boost::Thread - QueryPerformanceFrequency Internal Error");
+ return mono_platform_timepoint(0);
+ }
+
+ boost::detail::winapi::LARGE_INTEGER_ pcount;
+ unsigned times=0;
+ while ( ! boost::detail::winapi::QueryPerformanceCounter( &pcount ) )
+ {
+ if ( ++times > 3 )
+ {
+ BOOST_ASSERT(0 && "Boost::Thread - QueryPerformanceCounter Internal Error");
+ return mono_platform_timepoint(0);
+ }
+ }
+
+ long double ns = 1000000000.0L * pcount.QuadPart / freq.QuadPart;
+ return mono_platform_timepoint(static_cast<boost::time_max_t>(ns));
+#else
+ // Use GetTickCount64() because it's more reliable on older
+ // systems like Windows XP and Windows Server 2003.
+ win32::ticks_type msec = win32::gettickcount64();
+ return mono_platform_timepoint(msec * 1000000);
+#endif
+#elif defined(BOOST_THREAD_CHRONO_MAC_API)
+ kern_return_t err;
+ threads::chrono_details::FP fp = threads::chrono_details::init_steady_clock(err);
+ if ( err != 0 )
+ {
+ BOOST_ASSERT(0 && "Boost::Chrono - Internal Error");
+ }
+ return mono_platform_timepoint(fp());
+#else
+ timespec ts;
+ if ( ::clock_gettime( CLOCK_MONOTONIC, &ts ) )
+ {
+ BOOST_ASSERT(0 && "Boost::Thread - clock_gettime(CLOCK_MONOTONIC) Internal Error");
+ return mono_platform_timepoint(0);
+ }
+ return mono_platform_timepoint(ts);
+#endif
+ }
+ };
+
+#endif
+
+#if defined(BOOST_THREAD_INTERNAL_CLOCK_IS_MONO)
+ typedef mono_platform_clock internal_platform_clock;
+ typedef mono_platform_timepoint internal_platform_timepoint;
+#else
+ typedef real_platform_clock internal_platform_clock;
+ typedef real_platform_timepoint internal_platform_timepoint;
+#endif
+
+#ifdef BOOST_THREAD_USES_CHRONO
+#ifdef BOOST_THREAD_INTERNAL_CLOCK_IS_MONO
+ typedef chrono::steady_clock internal_chrono_clock;
+#else
+ typedef chrono::system_clock internal_chrono_clock;
+#endif
+#endif
+
+ }
+}
+
+#include <boost/config/abi_suffix.hpp>
+
+#endif