2
0
mirror of https://github.com/boostorg/log.git synced 2026-01-27 19:02:17 +00:00
Files
log/src/timestamp.cpp
Andrey Semashev 8c4e805f6a Correct alignment attribute placement to fic compilation with clang 5.
The alignment attribute should come before the storage class specifier.
Otherwise the attribute relates to the type that is mentioned in the
declaration.

This should fix https://github.com/boostorg/log/issues/38.
2017-09-02 20:23:16 +03:00

229 lines
6.7 KiB
C++

/*
* Copyright Andrey Semashev 2007 - 2015.
* 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)
*/
/*!
* \file timestamp.cpp
* \author Andrey Semashev
* \date 31.07.2011
*
* \brief This header is the Boost.Log library implementation, see the library documentation
* at http://www.boost.org/doc/libs/release/libs/log/doc/html/index.html.
*/
#include <boost/log/detail/config.hpp>
#include <boost/log/detail/timestamp.hpp>
#if defined(BOOST_WINDOWS) && !defined(__CYGWIN__)
#if !defined(BOOST_LOG_NO_THREADS)
#include <boost/memory_order.hpp>
#include <boost/atomic/atomic.hpp>
#endif
#include <boost/detail/winapi/dll.hpp>
#include <boost/detail/winapi/time.hpp>
#else
#include <unistd.h> // for config macros
#if defined(macintosh) || defined(__APPLE__) || defined(__APPLE_CC__)
#include <mach/mach_time.h>
#include <mach/kern_return.h>
#include <boost/log/utility/once_block.hpp>
#include <boost/system/error_code.hpp>
#endif
#include <time.h>
#include <errno.h>
#include <boost/throw_exception.hpp>
#include <boost/log/exceptions.hpp>
#endif
#include <boost/log/detail/header.hpp>
namespace boost {
BOOST_LOG_OPEN_NAMESPACE
namespace aux {
#if defined(BOOST_WINDOWS) && !defined(__CYGWIN__)
#if BOOST_USE_WINAPI_VERSION >= BOOST_WINAPI_VERSION_WIN6
// Directly use API from Vista and later
BOOST_LOG_API get_tick_count_t get_tick_count = &boost::detail::winapi::GetTickCount64;
#else // BOOST_USE_WINAPI_VERSION >= BOOST_WINAPI_VERSION_WIN6
BOOST_LOG_ANONYMOUS_NAMESPACE {
// Zero-initialized initially
#if !defined(BOOST_LOG_NO_THREADS)
BOOST_ALIGNMENT(BOOST_LOG_CPU_CACHE_LINE_SIZE) static boost::atomic< uint64_t > g_ticks;
#else
BOOST_ALIGNMENT(BOOST_LOG_CPU_CACHE_LINE_SIZE) static uint64_t g_ticks;
#endif
//! Artifical implementation of GetTickCount64
uint64_t WINAPI get_tick_count64()
{
#if !defined(BOOST_LOG_NO_THREADS)
uint64_t old_state = g_ticks.load(boost::memory_order_acquire);
#else
uint64_t old_state = g_ticks;
#endif
uint32_t new_ticks = boost::detail::winapi::GetTickCount();
uint32_t old_ticks = static_cast< uint32_t >(old_state & UINT64_C(0x00000000ffffffff));
uint64_t new_state = ((old_state & UINT64_C(0xffffffff00000000)) + (static_cast< uint64_t >(new_ticks < old_ticks) << 32)) | static_cast< uint64_t >(new_ticks);
#if !defined(BOOST_LOG_NO_THREADS)
g_ticks.store(new_state, boost::memory_order_release);
#else
g_ticks = new_state;
#endif
return new_state;
}
uint64_t WINAPI get_tick_count_init()
{
boost::detail::winapi::HMODULE_ hKernel32 = boost::detail::winapi::GetModuleHandleW(L"kernel32.dll");
if (hKernel32)
{
get_tick_count_t p = (get_tick_count_t)boost::detail::winapi::get_proc_address(hKernel32, "GetTickCount64");
if (p)
{
// Use native API
get_tick_count = p;
return p();
}
}
// No native API available
get_tick_count = &get_tick_count64;
return get_tick_count64();
}
} // namespace
BOOST_LOG_API get_tick_count_t get_tick_count = &get_tick_count_init;
#endif // BOOST_USE_WINAPI_VERSION >= BOOST_WINAPI_VERSION_WIN6
#elif (defined(_POSIX_TIMERS) && (_POSIX_TIMERS+0) > 0) /* POSIX timers supported */ \
|| defined(__GNU__) || defined(__OpenBSD__) || defined(__CloudABI__) /* GNU Hurd, OpenBSD and Nuxi CloudABI don't support POSIX timers fully but do provide clock_gettime() */
BOOST_LOG_API int64_t duration::milliseconds() const
{
// Timestamps are always in nanoseconds
return m_ticks / INT64_C(1000000);
}
BOOST_LOG_ANONYMOUS_NAMESPACE {
/*!
* \c get_timestamp implementation based on POSIX realtime clock.
* Note that this implementation is only used as a last resort since
* this timer can be manually set and may jump due to DST change.
*/
timestamp get_timestamp_realtime_clock()
{
timespec ts;
if (BOOST_UNLIKELY(clock_gettime(CLOCK_REALTIME, &ts) != 0))
{
const int err = errno;
BOOST_LOG_THROW_DESCR_PARAMS(system_error, "Failed to acquire current time", (err));
}
return timestamp(static_cast< uint64_t >(ts.tv_sec) * UINT64_C(1000000000) + ts.tv_nsec);
}
# if defined(_POSIX_MONOTONIC_CLOCK)
//! \c get_timestamp implementation based on POSIX monotonic clock
timestamp get_timestamp_monotonic_clock()
{
timespec ts;
if (BOOST_UNLIKELY(clock_gettime(CLOCK_MONOTONIC, &ts) != 0))
{
const int err = errno;
if (err == EINVAL)
{
// The current platform does not support monotonic timer.
// Fall back to realtime clock, which is not exactly what we need
// but is better than nothing.
get_timestamp = &get_timestamp_realtime_clock;
return get_timestamp_realtime_clock();
}
BOOST_LOG_THROW_DESCR_PARAMS(system_error, "Failed to acquire current time", (err));
}
return timestamp(static_cast< uint64_t >(ts.tv_sec) * UINT64_C(1000000000) + ts.tv_nsec);
}
# define BOOST_LOG_DEFAULT_GET_TIMESTAMP get_timestamp_monotonic_clock
# else // if defined(_POSIX_MONOTONIC_CLOCK)
# define BOOST_LOG_DEFAULT_GET_TIMESTAMP get_timestamp_realtime_clock
# endif // if defined(_POSIX_MONOTONIC_CLOCK)
} // namespace
// Use POSIX API
BOOST_LOG_API get_timestamp_t get_timestamp = &BOOST_LOG_DEFAULT_GET_TIMESTAMP;
# undef BOOST_LOG_DEFAULT_GET_TIMESTAMP
#elif defined(macintosh) || defined(__APPLE__) || defined(__APPLE_CC__)
BOOST_LOG_API int64_t duration::milliseconds() const
{
static mach_timebase_info_data_t timebase_info = {};
BOOST_LOG_ONCE_BLOCK()
{
kern_return_t err = mach_timebase_info(&timebase_info);
if (err != KERN_SUCCESS)
{
BOOST_LOG_THROW_DESCR_PARAMS(system_error, "Failed to initialize timebase info", (boost::system::errc::not_supported));
}
}
// Often the timebase rational equals 1, we can optimize for this case
if (timebase_info.numer == timebase_info.denom)
{
// Timestamps are in nanoseconds
return m_ticks / INT64_C(1000000);
}
else
{
return (m_ticks * timebase_info.numer) / (INT64_C(1000000) * timebase_info.denom);
}
}
BOOST_LOG_ANONYMOUS_NAMESPACE {
//! \c get_timestamp implementation based on MacOS X absolute time
timestamp get_timestamp_mach()
{
return timestamp(mach_absolute_time());
}
} // namespace
// Use MacOS X API
BOOST_LOG_API get_timestamp_t get_timestamp = &get_timestamp_mach;
#else
# error Boost.Log: Timestamp generation is not supported for your platform
#endif
} // namespace aux
BOOST_LOG_CLOSE_NAMESPACE // namespace log
} // namespace boost
#include <boost/log/detail/footer.hpp>