////////////////////////////////////////////////////////////////////////////// // // (C) Copyright Ion Gaztanaga 2021-2021. // // 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) // // See http://www.boost.org/libs/interprocess for documentation. // ////////////////////////////////////////////////////////////////////////////// #ifndef BOOST_INTERPROCESS_DETAIL_TIMED_UTILS_HPP #define BOOST_INTERPROCESS_DETAIL_TIMED_UTILS_HPP #ifndef BOOST_CONFIG_HPP # include #endif # #if defined(BOOST_HAS_PRAGMA_ONCE) # pragma once #endif #include #include #include #include #include #include #include //The following is used to support high precision time clocks #ifdef BOOST_HAS_GETTIMEOFDAY #include #endif #ifdef BOOST_HAS_FTIME #include #include #endif namespace boost { namespace interprocess { class ustime; class usduration; namespace ipcdetail { BOOST_INTRUSIVE_INSTANTIATE_DEFAULT_TYPE_TMPLT(time_duration_type) BOOST_INTRUSIVE_INSTANTIATE_DEFAULT_TYPE_TMPLT(clock) BOOST_INTRUSIVE_INSTANTIATE_DEFAULT_TYPE_TMPLT(rep_type) BOOST_INTRUSIVE_INSTANTIATE_DEFAULT_TYPE_TMPLT(rep) template struct enable_if_ptime : enable_if_c< BOOST_INTRUSIVE_HAS_TYPE(boost::interprocess::ipcdetail::, T, time_duration_type) > {}; template struct disable_if_ptime : enable_if_c< ! BOOST_INTRUSIVE_HAS_TYPE(boost::interprocess::ipcdetail::, T, time_duration_type) > {}; template struct enable_if_ptime_duration : enable_if_c< BOOST_INTRUSIVE_HAS_TYPE(boost::interprocess::ipcdetail::, T, rep_type) > {}; template struct enable_if_time_point : enable_if_c< BOOST_INTRUSIVE_HAS_TYPE(boost::interprocess::ipcdetail::, T, clock) > {}; template struct enable_if_duration : enable_if_c< BOOST_INTRUSIVE_HAS_TYPE(boost::interprocess::ipcdetail::, T, rep) > {}; template struct enable_if_ustime : enable_if_c< is_same::value > {}; template struct enable_if_usduration : enable_if_c< is_same::value > {}; #if defined(BOOST_INTERPROCESS_HAS_REENTRANT_STD_FUNCTIONS) inline std::tm* interprocess_gmtime(const std::time_t* t, std::tm* result) { // gmtime_r() not in namespace std??? #if defined(__VMS) && __INITIAL_POINTER_SIZE == 64 std::tm tmp; if(!gmtime_r(t,&tmp)) result = 0; else *result = tmp; #else result = gmtime_r(t, result); #endif return result; } #else // BOOST_DATE_TIME_HAS_REENTRANT_STD_FUNCTIONS #if defined(__clang__) // Clang has to be checked before MSVC # pragma clang diagnostic push # pragma clang diagnostic ignored "-Wdeprecated-declarations" #elif (defined(_MSC_VER) && (_MSC_VER >= 1400)) # pragma warning(push) // preserve warning settings # pragma warning(disable : 4996) // disable depricated localtime/gmtime warning on vc8 #endif inline std::tm* interprocess_gmtime(const std::time_t* t, std::tm* result) { result = std::gmtime(t); return result; } #if defined(__clang__) // Clang has to be checked before MSVC # pragma clang diagnostic pop #elif (defined(_MSC_VER) && (_MSC_VER >= 1400)) # pragma warning(pop) // restore warnings to previous state #endif #endif // BOOST_DATE_TIME_HAS_REENTRANT_STD_FUNCTIONS #if defined(BOOST_HAS_FTIME) /*! * The function converts file_time into number of microseconds elapsed since 1970-Jan-01 * * \note Only dates after 1970-Jan-01 are supported. Dates before will be wrapped. */ inline boost::uint64_t file_time_to_microseconds(const boost::winapi::FILETIME_ & ft) { // shift is difference between 1970-Jan-01 & 1601-Jan-01 // in 100-nanosecond units const boost::uint64_t shift = 116444736000000000ULL; // (27111902 << 32) + 3577643008 // 100-nanos since 1601-Jan-01 boost::uint64_t ft_as_integer = (static_cast< boost::uint64_t >(ft.dwHighDateTime) << 32) | static_cast< boost::uint64_t >(ft.dwLowDateTime); ft_as_integer -= shift; // filetime is now 100-nanos since 1970-Jan-01 return (ft_as_integer / 10U); // truncate to microseconds } #endif inline boost::uint64_t universal_time_u64_us() { #ifdef BOOST_HAS_GETTIMEOFDAY timeval tv; gettimeofday(&tv, 0); //gettimeofday does not support TZ adjust on Linux. boost::uint64_t micros = boost::uint64_t(tv.tv_sec)*1000000u; micros += (boost::uint64_t)tv.tv_usec; #elif defined(BOOST_HAS_FTIME) boost::winapi::FILETIME_ ft; boost::winapi::GetSystemTimeAsFileTime(&ft); boost::uint64_t micros = file_time_to_microseconds(ft); // it will not wrap, since ft is the current time // and cannot be before 1970-Jan-01 #else #error "Unsupported date-time error: neither gettimeofday nor FILETIME support is detected" #endif return micros; } template class microsec_clock; template class microsec_clock::type> { private: typedef typename TimeType::date_type date_type; typedef typename TimeType::time_duration_type time_duration_type; typedef typename time_duration_type::rep_type resolution_traits_type; public: typedef TimeType time_point; static time_point universal_time() { #ifdef BOOST_HAS_GETTIMEOFDAY timeval tv; gettimeofday(&tv, 0); //gettimeofday does not support TZ adjust on Linux. std::time_t t = tv.tv_sec; boost::uint32_t sub_sec = static_cast(tv.tv_usec); #elif defined(BOOST_HAS_FTIME) boost::winapi::FILETIME_ ft; boost::winapi::GetSystemTimeAsFileTime(&ft); boost::uint64_t micros = file_time_to_microseconds(ft); // it will not wrap, since ft is the current time // and cannot be before 1970-Jan-01 std::time_t t = static_cast(micros / 1000000UL); // seconds since epoch // microseconds -- static casts suppress warnings boost::uint32_t sub_sec = static_cast(micros % 1000000UL); #else #error "Unsupported date-time error: neither gettimeofday nor FILETIME support is detected" #endif std::tm curr; std::tm* curr_ptr = interprocess_gmtime(&t, &curr); date_type d(static_cast< typename date_type::year_type::value_type >(curr_ptr->tm_year + 1900), static_cast< typename date_type::month_type::value_type >(curr_ptr->tm_mon + 1), static_cast< typename date_type::day_type::value_type >(curr_ptr->tm_mday)); //The following line will adjust the fractional second tick in terms //of the current time system. For example, if the time system //doesn't support fractional seconds then res_adjust returns 0 //and all the fractional seconds return 0. unsigned adjust = static_cast< unsigned >(resolution_traits_type::res_adjust() / 1000000); time_duration_type td(static_cast< typename time_duration_type::hour_type >(curr_ptr->tm_hour), static_cast< typename time_duration_type::min_type >(curr_ptr->tm_min), static_cast< typename time_duration_type::sec_type >(curr_ptr->tm_sec), static_cast< typename time_duration_type::fractional_seconds_type >(sub_sec * adjust) ); return time_point(d,td); } }; template class microsec_clock::type> { public: typedef typename TimePoint::clock::time_point time_point; static time_point universal_time() { return TimePoint::clock::now(); } }; template inline bool is_pos_infinity(const TimePoint &abs_time, typename enable_if_ptime::type* = 0) { return abs_time.is_pos_infinity(); } template inline bool is_pos_infinity(const TimePoint &, typename disable_if_ptime::type* = 0) { return false; } // duration_to_milliseconds template inline boost::uint64_t duration_to_milliseconds(const Duration &abs_time, typename enable_if_ptime_duration::type* = 0) { return static_cast(abs_time.total_milliseconds()); } template inline boost::uint64_t duration_to_milliseconds(const Duration &d, typename enable_if_duration::type* = 0) { const double factor = double(Duration::period::num)*1000.0/double(Duration::period::den); return static_cast(double(d.count())*factor); } template inline boost::uint64_t duration_to_milliseconds(const Duration&d, typename enable_if_usduration::type* = 0) { return d.get_microsecs()/1000u; } } //namespace ipcdetail { } //namespace interprocess { } //namespace boost { #include #endif //#ifndef BOOST_INTERPROCESS_DETAIL_TIMED_UTILS_HPP