• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 #ifndef BOOST_THREAD_DETAIL_PLATFORM_TIME_HPP
2 #define BOOST_THREAD_DETAIL_PLATFORM_TIME_HPP
3 //  (C) Copyright 2007-8 Anthony Williams
4 //  (C) Copyright 2012 Vicente J. Botet Escriba
5 //
6 //  Distributed under the Boost Software License, Version 1.0. (See
7 //  accompanying file LICENSE_1_0.txt or copy at
8 //  http://www.boost.org/LICENSE_1_0.txt)
9 
10 #include <boost/thread/detail/config.hpp>
11 #include <boost/thread/thread_time.hpp>
12 #if defined BOOST_THREAD_USES_DATETIME
13 #include <boost/date_time/posix_time/conversion.hpp>
14 #endif
15 #ifndef _WIN32
16 #include <unistd.h>
17 #endif
18 #ifdef BOOST_THREAD_USES_CHRONO
19 #include <boost/chrono/duration.hpp>
20 #include <boost/chrono/system_clocks.hpp>
21 #include <boost/chrono/ceil.hpp>
22 #endif
23 
24 #if defined(BOOST_THREAD_CHRONO_WINDOWS_API)
25 #include <boost/winapi/time.hpp>
26 #include <boost/winapi/timers.hpp>
27 #include <boost/thread/win32/thread_primitives.hpp>
28 #elif defined(BOOST_THREAD_CHRONO_MAC_API)
29 #include <sys/time.h> //for gettimeofday and timeval
30 #include <mach/mach_time.h>  // mach_absolute_time, mach_timebase_info_data_t
31 
32 #else
33 #include <time.h>  // for clock_gettime
34 #endif
35 
36 #include <limits>
37 
38 #include <boost/config/abi_prefix.hpp>
39 
40 namespace boost
41 {
42 //typedef boost::int_least64_t time_max_t;
43 typedef boost::intmax_t time_max_t;
44 
45 #if defined BOOST_THREAD_CHRONO_MAC_API
46 namespace threads
47 {
48 
49 namespace chrono_details
50 {
51 
52 // steady_clock
53 
54 // Note, in this implementation steady_clock and high_resolution_clock
55 //   are the same clock.  They are both based on mach_absolute_time().
56 //   mach_absolute_time() * MachInfo.numer / MachInfo.denom is the number of
57 //   nanoseconds since the computer booted up.  MachInfo.numer and MachInfo.denom
58 //   are run time constants supplied by the OS.  This clock has no relationship
59 //   to the Gregorian calendar.  It's main use is as a high resolution timer.
60 
61 // MachInfo.numer / MachInfo.denom is often 1 on the latest equipment.  Specialize
62 //   for that case as an optimization.
63 
64 inline time_max_t
steady_simplified()65 steady_simplified()
66 {
67     return mach_absolute_time();
68 }
69 
compute_steady_factor(kern_return_t & err)70 inline double compute_steady_factor(kern_return_t& err)
71 {
72     mach_timebase_info_data_t MachInfo;
73     err = mach_timebase_info(&MachInfo);
74     if ( err != 0  ) {
75         return 0;
76     }
77     return static_cast<double>(MachInfo.numer) / MachInfo.denom;
78 }
79 
steady_full()80 inline time_max_t steady_full()
81 {
82     kern_return_t err;
83     const double factor = chrono_details::compute_steady_factor(err);
84     if (err != 0)
85     {
86       BOOST_ASSERT(0 && "Boost::Chrono - Internal Error");
87     }
88     return static_cast<time_max_t>(mach_absolute_time() * factor);
89 }
90 
91 
92 typedef time_max_t (*FP)();
93 
init_steady_clock(kern_return_t & err)94 inline FP init_steady_clock(kern_return_t & err)
95 {
96     mach_timebase_info_data_t MachInfo;
97     err = mach_timebase_info(&MachInfo);
98     if ( err != 0  )
99     {
100         return 0;
101     }
102 
103     if (MachInfo.numer == MachInfo.denom)
104     {
105         return &chrono_details::steady_simplified;
106     }
107     return &chrono_details::steady_full;
108 }
109 
110 }
111 }
112 #endif
113 
114   namespace detail
115   {
116 #if defined BOOST_THREAD_CHRONO_POSIX_API || defined BOOST_THREAD_CHRONO_MAC_API
ns_to_timespec(boost::time_max_t const & ns)117     inline timespec ns_to_timespec(boost::time_max_t const& ns)
118     {
119       boost::time_max_t s = ns / 1000000000l;
120       timespec ts;
121       ts.tv_sec = static_cast<long> (s);
122       ts.tv_nsec = static_cast<long> (ns - s * 1000000000l);
123       return ts;
124     }
timespec_to_ns(timespec const & ts)125     inline boost::time_max_t timespec_to_ns(timespec const& ts)
126     {
127       return static_cast<boost::time_max_t>(ts.tv_sec) * 1000000000l + ts.tv_nsec;
128     }
129 #endif
130 
131     struct platform_duration
132     {
133 #if defined BOOST_THREAD_CHRONO_POSIX_API || defined BOOST_THREAD_CHRONO_MAC_API
platform_durationboost::detail::platform_duration134       explicit platform_duration(timespec const& v) : ts_val(v) {}
getTsboost::detail::platform_duration135       timespec const& getTs() const { return ts_val; }
136 
platform_durationboost::detail::platform_duration137       explicit platform_duration(boost::time_max_t const& ns = 0) : ts_val(ns_to_timespec(ns)) {}
getNsboost::detail::platform_duration138       boost::time_max_t getNs() const { return timespec_to_ns(ts_val); }
139 #else
140       explicit platform_duration(boost::time_max_t const& ns = 0) : ns_val(ns) {}
141       boost::time_max_t getNs() const { return ns_val; }
142 #endif
143 
144 #if defined BOOST_THREAD_USES_DATETIME
platform_durationboost::detail::platform_duration145       platform_duration(boost::posix_time::time_duration const& rel_time)
146       {
147 #if defined BOOST_THREAD_CHRONO_POSIX_API || defined BOOST_THREAD_CHRONO_MAC_API
148         ts_val.tv_sec = rel_time.total_seconds();
149         ts_val.tv_nsec = static_cast<long>(rel_time.fractional_seconds() * (1000000000l / rel_time.ticks_per_second()));
150 #else
151         ns_val = static_cast<boost::time_max_t>(rel_time.total_seconds()) * 1000000000l;
152         ns_val += rel_time.fractional_seconds() * (1000000000l / rel_time.ticks_per_second());
153 #endif
154       }
155 #endif
156 
157 #if defined BOOST_THREAD_USES_CHRONO
158       template <class Rep, class Period>
platform_durationboost::detail::platform_duration159       platform_duration(chrono::duration<Rep, Period> const& d)
160       {
161 #if defined BOOST_THREAD_CHRONO_POSIX_API || defined BOOST_THREAD_CHRONO_MAC_API
162         ts_val = ns_to_timespec(chrono::ceil<chrono::nanoseconds>(d).count());
163 #else
164         ns_val = chrono::ceil<chrono::nanoseconds>(d).count();
165 #endif
166       }
167 #endif
168 
getMsboost::detail::platform_duration169       boost::time_max_t getMs() const
170       {
171         const boost::time_max_t ns = getNs();
172         // ceil/floor away from zero
173         if (ns >= 0)
174         {
175           // return ceiling of positive numbers
176           return (ns + 999999) / 1000000;
177         }
178         else
179         {
180           // return floor of negative numbers
181           return (ns - 999999) / 1000000;
182         }
183       }
184 
zeroboost::detail::platform_duration185       static platform_duration zero()
186       {
187         return platform_duration(0);
188       }
189 
190     private:
191 #if defined BOOST_THREAD_CHRONO_POSIX_API || defined BOOST_THREAD_CHRONO_MAC_API
192       timespec ts_val;
193 #else
194       boost::time_max_t ns_val;
195 #endif
196     };
197 
operator ==(platform_duration const & lhs,platform_duration const & rhs)198     inline bool operator==(platform_duration const& lhs, platform_duration const& rhs)
199     {
200       return lhs.getNs() == rhs.getNs();
201     }
operator !=(platform_duration const & lhs,platform_duration const & rhs)202     inline bool operator!=(platform_duration const& lhs, platform_duration const& rhs)
203     {
204       return lhs.getNs() != rhs.getNs();
205     }
operator <(platform_duration const & lhs,platform_duration const & rhs)206     inline bool operator<(platform_duration const& lhs, platform_duration const& rhs)
207     {
208       return lhs.getNs() < rhs.getNs();
209     }
operator <=(platform_duration const & lhs,platform_duration const & rhs)210     inline bool operator<=(platform_duration const& lhs, platform_duration const& rhs)
211     {
212       return lhs.getNs() <= rhs.getNs();
213     }
operator >(platform_duration const & lhs,platform_duration const & rhs)214     inline bool operator>(platform_duration const& lhs, platform_duration const& rhs)
215     {
216       return lhs.getNs() > rhs.getNs();
217     }
operator >=(platform_duration const & lhs,platform_duration const & rhs)218     inline bool operator>=(platform_duration const& lhs, platform_duration const& rhs)
219     {
220       return lhs.getNs() >= rhs.getNs();
221     }
222 
platform_milliseconds(long const & ms)223     static inline platform_duration platform_milliseconds(long const& ms)
224     {
225       return platform_duration(ms * 1000000l);
226     }
227 
228     struct real_platform_timepoint
229     {
230 #if defined BOOST_THREAD_CHRONO_POSIX_API || defined BOOST_THREAD_CHRONO_MAC_API
real_platform_timepointboost::detail::real_platform_timepoint231       explicit real_platform_timepoint(timespec const& v) : dur(v) {}
getTsboost::detail::real_platform_timepoint232       timespec const& getTs() const { return dur.getTs(); }
233 #endif
234 
real_platform_timepointboost::detail::real_platform_timepoint235       explicit real_platform_timepoint(boost::time_max_t const& ns) : dur(ns) {}
getNsboost::detail::real_platform_timepoint236       boost::time_max_t getNs() const { return dur.getNs(); }
237 
238 #if defined BOOST_THREAD_USES_DATETIME
real_platform_timepointboost::detail::real_platform_timepoint239       real_platform_timepoint(boost::system_time const& abs_time)
240         : dur(abs_time - boost::posix_time::from_time_t(0)) {}
241 #endif
242 
243 #if defined BOOST_THREAD_USES_CHRONO
244       template <class Duration>
real_platform_timepointboost::detail::real_platform_timepoint245       real_platform_timepoint(chrono::time_point<chrono::system_clock, Duration> const& abs_time)
246         : dur(abs_time.time_since_epoch()) {}
247 #endif
248 
249     private:
250       platform_duration dur;
251     };
252 
operator ==(real_platform_timepoint const & lhs,real_platform_timepoint const & rhs)253     inline bool operator==(real_platform_timepoint const& lhs, real_platform_timepoint const& rhs)
254     {
255       return lhs.getNs() == rhs.getNs();
256     }
operator !=(real_platform_timepoint const & lhs,real_platform_timepoint const & rhs)257     inline bool operator!=(real_platform_timepoint const& lhs, real_platform_timepoint const& rhs)
258     {
259       return lhs.getNs() != rhs.getNs();
260     }
operator <(real_platform_timepoint const & lhs,real_platform_timepoint const & rhs)261     inline bool operator<(real_platform_timepoint const& lhs, real_platform_timepoint const& rhs)
262     {
263       return lhs.getNs() < rhs.getNs();
264     }
operator <=(real_platform_timepoint const & lhs,real_platform_timepoint const & rhs)265     inline bool operator<=(real_platform_timepoint const& lhs, real_platform_timepoint const& rhs)
266     {
267       return lhs.getNs() <= rhs.getNs();
268     }
operator >(real_platform_timepoint const & lhs,real_platform_timepoint const & rhs)269     inline bool operator>(real_platform_timepoint const& lhs, real_platform_timepoint const& rhs)
270     {
271       return lhs.getNs() > rhs.getNs();
272     }
operator >=(real_platform_timepoint const & lhs,real_platform_timepoint const & rhs)273     inline bool operator>=(real_platform_timepoint const& lhs, real_platform_timepoint const& rhs)
274     {
275       return lhs.getNs() >= rhs.getNs();
276     }
277 
operator +(real_platform_timepoint const & lhs,platform_duration const & rhs)278     inline real_platform_timepoint operator+(real_platform_timepoint const& lhs, platform_duration const& rhs)
279     {
280       return real_platform_timepoint(lhs.getNs() + rhs.getNs());
281     }
operator +(platform_duration const & lhs,real_platform_timepoint const & rhs)282     inline real_platform_timepoint operator+(platform_duration const& lhs, real_platform_timepoint const& rhs)
283     {
284       return real_platform_timepoint(lhs.getNs() + rhs.getNs());
285     }
operator -(real_platform_timepoint const & lhs,real_platform_timepoint const & rhs)286     inline platform_duration operator-(real_platform_timepoint const& lhs, real_platform_timepoint const& rhs)
287     {
288       return platform_duration(lhs.getNs() - rhs.getNs());
289     }
290 
291     struct real_platform_clock
292     {
nowboost::detail::real_platform_clock293       static real_platform_timepoint now()
294       {
295 #if defined(BOOST_THREAD_CHRONO_WINDOWS_API)
296         boost::winapi::FILETIME_ ft;
297         boost::winapi::GetSystemTimeAsFileTime(&ft);  // never fails
298         boost::time_max_t ns = ((((static_cast<boost::time_max_t>(ft.dwHighDateTime) << 32) | ft.dwLowDateTime) - 116444736000000000LL) * 100LL);
299         return real_platform_timepoint(ns);
300 #elif defined(BOOST_THREAD_CHRONO_MAC_API)
301         timeval tv;
302         ::gettimeofday(&tv, 0);
303         timespec ts;
304         ts.tv_sec = tv.tv_sec;
305         ts.tv_nsec = tv.tv_usec * 1000;
306         return real_platform_timepoint(ts);
307 #else
308         timespec ts;
309         if ( ::clock_gettime( CLOCK_REALTIME, &ts ) )
310         {
311           BOOST_ASSERT(0 && "Boost::Thread - clock_gettime(CLOCK_REALTIME) Internal Error");
312           return real_platform_timepoint(0);
313         }
314         return real_platform_timepoint(ts);
315 #endif
316       }
317     };
318 
319 #if defined(BOOST_THREAD_HAS_MONO_CLOCK)
320 
321   struct mono_platform_timepoint
322   {
323 #if defined BOOST_THREAD_CHRONO_POSIX_API || defined BOOST_THREAD_CHRONO_MAC_API
324 
mono_platform_timepointboost::detail::mono_platform_timepoint325     explicit mono_platform_timepoint(timespec const& v) : dur(v) {}
getTsboost::detail::mono_platform_timepoint326     timespec const& getTs() const { return dur.getTs(); }
327 #endif
328 
mono_platform_timepointboost::detail::mono_platform_timepoint329     explicit mono_platform_timepoint(boost::time_max_t const& ns) : dur(ns) {}
getNsboost::detail::mono_platform_timepoint330     boost::time_max_t getNs() const { return dur.getNs(); }
331 
332 #if defined BOOST_THREAD_USES_CHRONO
333     // This conversion assumes that chrono::steady_clock::time_point and mono_platform_timepoint share the same epoch.
334     template <class Duration>
mono_platform_timepointboost::detail::mono_platform_timepoint335     mono_platform_timepoint(chrono::time_point<chrono::steady_clock, Duration> const& abs_time)
336       : dur(abs_time.time_since_epoch()) {}
337 #endif
338 
339     // can't name this max() since that is a macro on some Windows systems
getMaxboost::detail::mono_platform_timepoint340     static mono_platform_timepoint getMax()
341     {
342 #if defined BOOST_THREAD_CHRONO_POSIX_API || defined BOOST_THREAD_CHRONO_MAC_API
343       timespec ts;
344       ts.tv_sec = (std::numeric_limits<time_t>::max)();
345       ts.tv_nsec = 999999999;
346       return mono_platform_timepoint(ts);
347 #else
348       boost::time_max_t ns = (std::numeric_limits<boost::time_max_t>::max)();
349       return mono_platform_timepoint(ns);
350 #endif
351     }
352 
353   private:
354     platform_duration dur;
355   };
356 
operator ==(mono_platform_timepoint const & lhs,mono_platform_timepoint const & rhs)357   inline bool operator==(mono_platform_timepoint const& lhs, mono_platform_timepoint const& rhs)
358   {
359     return lhs.getNs() == rhs.getNs();
360   }
operator !=(mono_platform_timepoint const & lhs,mono_platform_timepoint const & rhs)361   inline bool operator!=(mono_platform_timepoint const& lhs, mono_platform_timepoint const& rhs)
362   {
363     return lhs.getNs() != rhs.getNs();
364   }
operator <(mono_platform_timepoint const & lhs,mono_platform_timepoint const & rhs)365   inline bool operator<(mono_platform_timepoint const& lhs, mono_platform_timepoint const& rhs)
366   {
367     return lhs.getNs() < rhs.getNs();
368   }
operator <=(mono_platform_timepoint const & lhs,mono_platform_timepoint const & rhs)369   inline bool operator<=(mono_platform_timepoint const& lhs, mono_platform_timepoint const& rhs)
370   {
371     return lhs.getNs() <= rhs.getNs();
372   }
operator >(mono_platform_timepoint const & lhs,mono_platform_timepoint const & rhs)373   inline bool operator>(mono_platform_timepoint const& lhs, mono_platform_timepoint const& rhs)
374   {
375     return lhs.getNs() > rhs.getNs();
376   }
operator >=(mono_platform_timepoint const & lhs,mono_platform_timepoint const & rhs)377   inline bool operator>=(mono_platform_timepoint const& lhs, mono_platform_timepoint const& rhs)
378   {
379     return lhs.getNs() >= rhs.getNs();
380   }
381 
operator +(mono_platform_timepoint const & lhs,platform_duration const & rhs)382   inline mono_platform_timepoint operator+(mono_platform_timepoint const& lhs, platform_duration const& rhs)
383   {
384     return mono_platform_timepoint(lhs.getNs() + rhs.getNs());
385   }
operator +(platform_duration const & lhs,mono_platform_timepoint const & rhs)386   inline mono_platform_timepoint operator+(platform_duration const& lhs, mono_platform_timepoint const& rhs)
387   {
388     return mono_platform_timepoint(lhs.getNs() + rhs.getNs());
389   }
operator -(mono_platform_timepoint const & lhs,mono_platform_timepoint const & rhs)390   inline platform_duration operator-(mono_platform_timepoint const& lhs, mono_platform_timepoint const& rhs)
391   {
392     return platform_duration(lhs.getNs() - rhs.getNs());
393   }
394 
395   struct mono_platform_clock
396   {
nowboost::detail::mono_platform_clock397     static mono_platform_timepoint now()
398     {
399 #if defined(BOOST_THREAD_CHRONO_WINDOWS_API)
400 #if defined(BOOST_THREAD_USES_CHRONO)
401       // Use QueryPerformanceCounter() to match the implementation in Boost
402       // Chrono so that chrono::steady_clock::now() and this function share the
403       // same epoch and so can be converted between each other.
404       boost::winapi::LARGE_INTEGER_ freq;
405       if ( !boost::winapi::QueryPerformanceFrequency( &freq ) )
406       {
407         BOOST_ASSERT(0 && "Boost::Thread - QueryPerformanceFrequency Internal Error");
408         return mono_platform_timepoint(0);
409       }
410       if ( freq.QuadPart <= 0 )
411       {
412         BOOST_ASSERT(0 && "Boost::Thread - QueryPerformanceFrequency Internal Error");
413         return mono_platform_timepoint(0);
414       }
415 
416       boost::winapi::LARGE_INTEGER_ pcount;
417       unsigned times=0;
418       while ( ! boost::winapi::QueryPerformanceCounter( &pcount ) )
419       {
420         if ( ++times > 3 )
421         {
422           BOOST_ASSERT(0 && "Boost::Thread - QueryPerformanceCounter Internal Error");
423           return mono_platform_timepoint(0);
424         }
425       }
426 
427       long double ns = 1000000000.0L * pcount.QuadPart / freq.QuadPart;
428       return mono_platform_timepoint(static_cast<boost::time_max_t>(ns));
429 #else
430       // Use GetTickCount64() because it's more reliable on older
431       // systems like Windows XP and Windows Server 2003.
432       win32::ticks_type msec = win32::gettickcount64();
433       return mono_platform_timepoint(msec * 1000000);
434 #endif
435 #elif defined(BOOST_THREAD_CHRONO_MAC_API)
436       kern_return_t err;
437       threads::chrono_details::FP fp = threads::chrono_details::init_steady_clock(err);
438       if ( err != 0  )
439       {
440         BOOST_ASSERT(0 && "Boost::Chrono - Internal Error");
441       }
442       return mono_platform_timepoint(fp());
443 #else
444       timespec ts;
445       if ( ::clock_gettime( CLOCK_MONOTONIC, &ts ) )
446       {
447         BOOST_ASSERT(0 && "Boost::Thread - clock_gettime(CLOCK_MONOTONIC) Internal Error");
448         return mono_platform_timepoint(0);
449       }
450       return mono_platform_timepoint(ts);
451 #endif
452     }
453   };
454 
455 #endif
456 
457 #if defined(BOOST_THREAD_INTERNAL_CLOCK_IS_MONO)
458   typedef mono_platform_clock     internal_platform_clock;
459   typedef mono_platform_timepoint internal_platform_timepoint;
460 #else
461   typedef real_platform_clock     internal_platform_clock;
462   typedef real_platform_timepoint internal_platform_timepoint;
463 #endif
464 
465 #ifdef BOOST_THREAD_USES_CHRONO
466 #ifdef BOOST_THREAD_INTERNAL_CLOCK_IS_MONO
467   typedef chrono::steady_clock internal_chrono_clock;
468 #else
469   typedef chrono::system_clock internal_chrono_clock;
470 #endif
471 #endif
472 
473   }
474 }
475 
476 #include <boost/config/abi_suffix.hpp>
477 
478 #endif
479