Chris@16: // mac/chrono.cpp --------------------------------------------------------------// Chris@16: Chris@16: // Copyright Beman Dawes 2008 Chris@16: // Copyright 2009-2010 Vicente J. Botet Escriba Chris@16: Chris@16: // Distributed under the Boost Software License, Version 1.0. Chris@16: // See http://www.boost.org/LICENSE_1_0.txt Chris@16: Chris@16: Chris@16: //----------------------------------------------------------------------------// Chris@16: // Mac // Chris@16: //----------------------------------------------------------------------------// Chris@16: Chris@16: #include //for gettimeofday and timeval Chris@16: #include // mach_absolute_time, mach_timebase_info_data_t Chris@16: Chris@16: namespace boost Chris@16: { Chris@16: namespace chrono Chris@16: { Chris@16: Chris@16: // system_clock Chris@16: Chris@16: // gettimeofday is the most precise "system time" available on this platform. Chris@16: // It returns the number of microseconds since New Years 1970 in a struct called timeval Chris@16: // which has a field for seconds and a field for microseconds. Chris@16: // Fill in the timeval and then convert that to the time_point Chris@16: system_clock::time_point Chris@16: system_clock::now() BOOST_NOEXCEPT Chris@16: { Chris@16: timeval tv; Chris@16: gettimeofday(&tv, 0); Chris@16: return time_point(seconds(tv.tv_sec) + microseconds(tv.tv_usec)); Chris@16: } Chris@16: Chris@16: #if !defined BOOST_CHRONO_DONT_PROVIDE_HYBRID_ERROR_HANDLING Chris@16: system_clock::time_point Chris@16: system_clock::now(system::error_code & ec) Chris@16: { Chris@16: timeval tv; Chris@16: gettimeofday(&tv, 0); Chris@16: if (!BOOST_CHRONO_IS_THROWS(ec)) Chris@16: { Chris@16: ec.clear(); Chris@16: } Chris@16: return time_point(seconds(tv.tv_sec) + microseconds(tv.tv_usec)); Chris@16: } Chris@16: #endif Chris@16: // Take advantage of the fact that on this platform time_t is nothing but Chris@16: // an integral count of seconds since New Years 1970 (same epoch as timeval). Chris@16: // Just get the duration out of the time_point and truncate it to seconds. Chris@16: time_t Chris@16: system_clock::to_time_t(const time_point& t) BOOST_NOEXCEPT Chris@16: { Chris@16: return time_t(duration_cast(t.time_since_epoch()).count()); Chris@16: } Chris@16: Chris@16: // Just turn the time_t into a count of seconds and construct a time_point with it. Chris@16: system_clock::time_point Chris@16: system_clock::from_time_t(time_t t) BOOST_NOEXCEPT Chris@16: { Chris@16: return system_clock::time_point(seconds(t)); Chris@16: } Chris@16: Chris@16: namespace chrono_detail Chris@16: { Chris@16: Chris@16: // steady_clock Chris@16: Chris@16: // Note, in this implementation steady_clock and high_resolution_clock Chris@16: // are the same clock. They are both based on mach_absolute_time(). Chris@16: // mach_absolute_time() * MachInfo.numer / MachInfo.denom is the number of Chris@16: // nanoseconds since the computer booted up. MachInfo.numer and MachInfo.denom Chris@16: // are run time constants supplied by the OS. This clock has no relationship Chris@16: // to the Gregorian calendar. It's main use is as a high resolution timer. Chris@16: Chris@16: // MachInfo.numer / MachInfo.denom is often 1 on the latest equipment. Specialize Chris@16: // for that case as an optimization. Chris@16: BOOST_CHRONO_STATIC Chris@16: steady_clock::rep Chris@16: steady_simplified() Chris@16: { Chris@16: return mach_absolute_time(); Chris@16: } Chris@16: Chris@16: #if !defined BOOST_CHRONO_DONT_PROVIDE_HYBRID_ERROR_HANDLING Chris@16: BOOST_CHRONO_STATIC Chris@16: steady_clock::rep Chris@16: steady_simplified_ec(system::error_code & ec) Chris@16: { Chris@16: if (!BOOST_CHRONO_IS_THROWS(ec)) Chris@16: { Chris@16: ec.clear(); Chris@16: } Chris@16: return mach_absolute_time(); Chris@16: } Chris@16: #endif Chris@16: Chris@16: BOOST_CHRONO_STATIC Chris@16: double Chris@16: compute_steady_factor(kern_return_t& err) Chris@16: { Chris@16: mach_timebase_info_data_t MachInfo; Chris@16: err = mach_timebase_info(&MachInfo); Chris@16: if ( err != 0 ) { Chris@16: return 0; Chris@16: } Chris@16: return static_cast(MachInfo.numer) / MachInfo.denom; Chris@16: } Chris@16: Chris@16: BOOST_CHRONO_STATIC Chris@16: steady_clock::rep Chris@16: steady_full() Chris@16: { Chris@16: static kern_return_t err; Chris@16: static const double factor = chrono_detail::compute_steady_factor(err); Chris@16: if (err != 0) Chris@16: { Chris@16: BOOST_ASSERT(0 && "Boost::Chrono - Internal Error"); Chris@16: } Chris@16: return static_cast(mach_absolute_time() * factor); Chris@16: } Chris@16: Chris@16: #if !defined BOOST_CHRONO_DONT_PROVIDE_HYBRID_ERROR_HANDLING Chris@16: BOOST_CHRONO_STATIC Chris@16: steady_clock::rep Chris@16: steady_full_ec(system::error_code & ec) Chris@16: { Chris@16: static kern_return_t err; Chris@16: static const double factor = chrono_detail::compute_steady_factor(err); Chris@16: if (err != 0) Chris@16: { Chris@16: if (BOOST_CHRONO_IS_THROWS(ec)) Chris@16: { Chris@16: boost::throw_exception( Chris@16: system::system_error( Chris@16: err, Chris@16: BOOST_CHRONO_SYSTEM_CATEGORY, Chris@16: "chrono::steady_clock" )); Chris@16: } Chris@16: else Chris@16: { Chris@16: ec.assign( errno, BOOST_CHRONO_SYSTEM_CATEGORY ); Chris@16: return steady_clock::rep(); Chris@16: } Chris@16: } Chris@16: if (!BOOST_CHRONO_IS_THROWS(ec)) Chris@16: { Chris@16: ec.clear(); Chris@16: } Chris@16: return static_cast(mach_absolute_time() * factor); Chris@16: } Chris@16: #endif Chris@16: Chris@16: typedef steady_clock::rep (*FP)(); Chris@16: #if !defined BOOST_CHRONO_DONT_PROVIDE_HYBRID_ERROR_HANDLING Chris@16: typedef steady_clock::rep (*FP_ec)(system::error_code &); Chris@16: #endif Chris@16: Chris@16: BOOST_CHRONO_STATIC Chris@16: FP Chris@16: init_steady_clock(kern_return_t & err) Chris@16: { Chris@16: mach_timebase_info_data_t MachInfo; Chris@16: err = mach_timebase_info(&MachInfo); Chris@16: if ( err != 0 ) Chris@16: { Chris@16: return 0; Chris@16: } Chris@16: Chris@16: if (MachInfo.numer == MachInfo.denom) Chris@16: { Chris@16: return &chrono_detail::steady_simplified; Chris@16: } Chris@16: return &chrono_detail::steady_full; Chris@16: } Chris@16: Chris@16: #if !defined BOOST_CHRONO_DONT_PROVIDE_HYBRID_ERROR_HANDLING Chris@16: BOOST_CHRONO_STATIC Chris@16: FP_ec Chris@16: init_steady_clock_ec(kern_return_t & err) Chris@16: { Chris@16: mach_timebase_info_data_t MachInfo; Chris@16: err = mach_timebase_info(&MachInfo); Chris@16: if ( err != 0 ) Chris@16: { Chris@16: return 0; Chris@16: } Chris@16: Chris@16: if (MachInfo.numer == MachInfo.denom) Chris@16: { Chris@16: return &chrono_detail::steady_simplified_ec; Chris@16: } Chris@16: return &chrono_detail::steady_full_ec; Chris@16: } Chris@16: #endif Chris@16: } Chris@16: Chris@16: steady_clock::time_point Chris@16: steady_clock::now() BOOST_NOEXCEPT Chris@16: { Chris@16: static kern_return_t err; Chris@16: static chrono_detail::FP fp = chrono_detail::init_steady_clock(err); Chris@16: if ( err != 0 ) Chris@16: { Chris@16: BOOST_ASSERT(0 && "Boost::Chrono - Internal Error"); Chris@16: } Chris@16: return time_point(duration(fp())); Chris@16: } Chris@16: Chris@16: #if !defined BOOST_CHRONO_DONT_PROVIDE_HYBRID_ERROR_HANDLING Chris@16: steady_clock::time_point Chris@16: steady_clock::now(system::error_code & ec) Chris@16: { Chris@16: static kern_return_t err; Chris@16: static chrono_detail::FP_ec fp = chrono_detail::init_steady_clock_ec(err); Chris@16: if ( err != 0 ) Chris@16: { Chris@16: if (BOOST_CHRONO_IS_THROWS(ec)) Chris@16: { Chris@16: boost::throw_exception( Chris@16: system::system_error( Chris@16: err, Chris@16: BOOST_CHRONO_SYSTEM_CATEGORY, Chris@16: "chrono::steady_clock" )); Chris@16: } Chris@16: else Chris@16: { Chris@16: ec.assign( err, BOOST_CHRONO_SYSTEM_CATEGORY ); Chris@16: return time_point(); Chris@16: } Chris@16: } Chris@16: if (!BOOST_CHRONO_IS_THROWS(ec)) Chris@16: { Chris@16: ec.clear(); Chris@16: } Chris@16: return time_point(duration(fp(ec))); Chris@16: } Chris@16: #endif Chris@16: } // namespace chrono Chris@16: } // namespace boost