chrono.hpp 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241
  1. // mac/chrono.cpp --------------------------------------------------------------//
  2. // Copyright Beman Dawes 2008
  3. // Copyright 2009-2010 Vicente J. Botet Escriba
  4. // Distributed under the Boost Software License, Version 1.0.
  5. // See http://www.boost.org/LICENSE_1_0.txt
  6. //----------------------------------------------------------------------------//
  7. // Mac //
  8. //----------------------------------------------------------------------------//
  9. #include <sys/time.h> //for gettimeofday and timeval
  10. #include <mach/mach_time.h> // mach_absolute_time, mach_timebase_info_data_t
  11. namespace boost
  12. {
  13. namespace chrono
  14. {
  15. // system_clock
  16. // gettimeofday is the most precise "system time" available on this platform.
  17. // It returns the number of microseconds since New Years 1970 in a struct called timeval
  18. // which has a field for seconds and a field for microseconds.
  19. // Fill in the timeval and then convert that to the time_point
  20. system_clock::time_point
  21. system_clock::now() BOOST_NOEXCEPT
  22. {
  23. timeval tv;
  24. gettimeofday(&tv, 0);
  25. return time_point(seconds(tv.tv_sec) + microseconds(tv.tv_usec));
  26. }
  27. #if !defined BOOST_CHRONO_DONT_PROVIDE_HYBRID_ERROR_HANDLING
  28. system_clock::time_point
  29. system_clock::now(system::error_code & ec)
  30. {
  31. timeval tv;
  32. gettimeofday(&tv, 0);
  33. if (!BOOST_CHRONO_IS_THROWS(ec))
  34. {
  35. ec.clear();
  36. }
  37. return time_point(seconds(tv.tv_sec) + microseconds(tv.tv_usec));
  38. }
  39. #endif
  40. // Take advantage of the fact that on this platform time_t is nothing but
  41. // an integral count of seconds since New Years 1970 (same epoch as timeval).
  42. // Just get the duration out of the time_point and truncate it to seconds.
  43. time_t
  44. system_clock::to_time_t(const time_point& t) BOOST_NOEXCEPT
  45. {
  46. return time_t(duration_cast<seconds>(t.time_since_epoch()).count());
  47. }
  48. // Just turn the time_t into a count of seconds and construct a time_point with it.
  49. system_clock::time_point
  50. system_clock::from_time_t(time_t t) BOOST_NOEXCEPT
  51. {
  52. return system_clock::time_point(seconds(t));
  53. }
  54. namespace chrono_detail
  55. {
  56. // steady_clock
  57. // Note, in this implementation steady_clock and high_resolution_clock
  58. // are the same clock. They are both based on mach_absolute_time().
  59. // mach_absolute_time() * MachInfo.numer / MachInfo.denom is the number of
  60. // nanoseconds since the computer booted up. MachInfo.numer and MachInfo.denom
  61. // are run time constants supplied by the OS. This clock has no relationship
  62. // to the Gregorian calendar. It's main use is as a high resolution timer.
  63. // MachInfo.numer / MachInfo.denom is often 1 on the latest equipment. Specialize
  64. // for that case as an optimization.
  65. BOOST_CHRONO_STATIC
  66. steady_clock::rep
  67. steady_simplified()
  68. {
  69. return mach_absolute_time();
  70. }
  71. #if !defined BOOST_CHRONO_DONT_PROVIDE_HYBRID_ERROR_HANDLING
  72. BOOST_CHRONO_STATIC
  73. steady_clock::rep
  74. steady_simplified_ec(system::error_code & ec)
  75. {
  76. if (!BOOST_CHRONO_IS_THROWS(ec))
  77. {
  78. ec.clear();
  79. }
  80. return mach_absolute_time();
  81. }
  82. #endif
  83. BOOST_CHRONO_STATIC
  84. double
  85. compute_steady_factor(kern_return_t& err)
  86. {
  87. mach_timebase_info_data_t MachInfo;
  88. err = mach_timebase_info(&MachInfo);
  89. if ( err != 0 ) {
  90. return 0;
  91. }
  92. return static_cast<double>(MachInfo.numer) / MachInfo.denom;
  93. }
  94. BOOST_CHRONO_STATIC
  95. steady_clock::rep
  96. steady_full()
  97. {
  98. static kern_return_t err;
  99. static const double factor = chrono_detail::compute_steady_factor(err);
  100. if (err != 0)
  101. {
  102. BOOST_ASSERT(0 && "Boost::Chrono - Internal Error");
  103. }
  104. return static_cast<steady_clock::rep>(mach_absolute_time() * factor);
  105. }
  106. #if !defined BOOST_CHRONO_DONT_PROVIDE_HYBRID_ERROR_HANDLING
  107. BOOST_CHRONO_STATIC
  108. steady_clock::rep
  109. steady_full_ec(system::error_code & ec)
  110. {
  111. static kern_return_t err;
  112. static const double factor = chrono_detail::compute_steady_factor(err);
  113. if (err != 0)
  114. {
  115. if (BOOST_CHRONO_IS_THROWS(ec))
  116. {
  117. boost::throw_exception(
  118. system::system_error(
  119. err,
  120. BOOST_CHRONO_SYSTEM_CATEGORY,
  121. "chrono::steady_clock" ));
  122. }
  123. else
  124. {
  125. ec.assign( errno, BOOST_CHRONO_SYSTEM_CATEGORY );
  126. return steady_clock::rep();
  127. }
  128. }
  129. if (!BOOST_CHRONO_IS_THROWS(ec))
  130. {
  131. ec.clear();
  132. }
  133. return static_cast<steady_clock::rep>(mach_absolute_time() * factor);
  134. }
  135. #endif
  136. typedef steady_clock::rep (*FP)();
  137. #if !defined BOOST_CHRONO_DONT_PROVIDE_HYBRID_ERROR_HANDLING
  138. typedef steady_clock::rep (*FP_ec)(system::error_code &);
  139. #endif
  140. BOOST_CHRONO_STATIC
  141. FP
  142. init_steady_clock(kern_return_t & err)
  143. {
  144. mach_timebase_info_data_t MachInfo;
  145. err = mach_timebase_info(&MachInfo);
  146. if ( err != 0 )
  147. {
  148. return 0;
  149. }
  150. if (MachInfo.numer == MachInfo.denom)
  151. {
  152. return &chrono_detail::steady_simplified;
  153. }
  154. return &chrono_detail::steady_full;
  155. }
  156. #if !defined BOOST_CHRONO_DONT_PROVIDE_HYBRID_ERROR_HANDLING
  157. BOOST_CHRONO_STATIC
  158. FP_ec
  159. init_steady_clock_ec(kern_return_t & err)
  160. {
  161. mach_timebase_info_data_t MachInfo;
  162. err = mach_timebase_info(&MachInfo);
  163. if ( err != 0 )
  164. {
  165. return 0;
  166. }
  167. if (MachInfo.numer == MachInfo.denom)
  168. {
  169. return &chrono_detail::steady_simplified_ec;
  170. }
  171. return &chrono_detail::steady_full_ec;
  172. }
  173. #endif
  174. }
  175. steady_clock::time_point
  176. steady_clock::now() BOOST_NOEXCEPT
  177. {
  178. static kern_return_t err;
  179. static chrono_detail::FP fp = chrono_detail::init_steady_clock(err);
  180. if ( err != 0 )
  181. {
  182. BOOST_ASSERT(0 && "Boost::Chrono - Internal Error");
  183. }
  184. return time_point(duration(fp()));
  185. }
  186. #if !defined BOOST_CHRONO_DONT_PROVIDE_HYBRID_ERROR_HANDLING
  187. steady_clock::time_point
  188. steady_clock::now(system::error_code & ec)
  189. {
  190. static kern_return_t err;
  191. static chrono_detail::FP_ec fp = chrono_detail::init_steady_clock_ec(err);
  192. if ( err != 0 )
  193. {
  194. if (BOOST_CHRONO_IS_THROWS(ec))
  195. {
  196. boost::throw_exception(
  197. system::system_error(
  198. err,
  199. BOOST_CHRONO_SYSTEM_CATEGORY,
  200. "chrono::steady_clock" ));
  201. }
  202. else
  203. {
  204. ec.assign( err, BOOST_CHRONO_SYSTEM_CATEGORY );
  205. return time_point();
  206. }
  207. }
  208. if (!BOOST_CHRONO_IS_THROWS(ec))
  209. {
  210. ec.clear();
  211. }
  212. return time_point(duration(fp(ec)));
  213. }
  214. #endif
  215. } // namespace chrono
  216. } // namespace boost