]>
Commit | Line | Data |
---|---|---|
7c673cae FG |
1 | /* |
2 | * Copyright Andrey Semashev 2007 - 2015. | |
3 | * Distributed under the Boost Software License, Version 1.0. | |
4 | * (See accompanying file LICENSE_1_0.txt or copy at | |
5 | * http://www.boost.org/LICENSE_1_0.txt) | |
6 | */ | |
7 | /*! | |
8 | * \file timestamp.cpp | |
9 | * \author Andrey Semashev | |
10 | * \date 31.07.2011 | |
11 | * | |
12 | * \brief This header is the Boost.Log library implementation, see the library documentation | |
13 | * at http://www.boost.org/doc/libs/release/libs/log/doc/html/index.html. | |
14 | */ | |
15 | ||
16 | #include <boost/log/detail/config.hpp> | |
17 | #include <boost/log/detail/timestamp.hpp> | |
18 | ||
19 | #if defined(BOOST_WINDOWS) && !defined(__CYGWIN__) | |
20 | #if !defined(BOOST_LOG_NO_THREADS) | |
21 | #include <boost/memory_order.hpp> | |
22 | #include <boost/atomic/atomic.hpp> | |
23 | #endif | |
b32b8144 FG |
24 | #include <boost/winapi/dll.hpp> |
25 | #include <boost/winapi/time.hpp> | |
7c673cae FG |
26 | #else |
27 | #include <unistd.h> // for config macros | |
28 | #if defined(macintosh) || defined(__APPLE__) || defined(__APPLE_CC__) | |
29 | #include <mach/mach_time.h> | |
30 | #include <mach/kern_return.h> | |
31 | #include <boost/log/utility/once_block.hpp> | |
32 | #include <boost/system/error_code.hpp> | |
33 | #endif | |
34 | #include <time.h> | |
35 | #include <errno.h> | |
36 | #include <boost/throw_exception.hpp> | |
37 | #include <boost/log/exceptions.hpp> | |
38 | #endif | |
39 | #include <boost/log/detail/header.hpp> | |
40 | ||
41 | namespace boost { | |
42 | ||
43 | BOOST_LOG_OPEN_NAMESPACE | |
44 | ||
45 | namespace aux { | |
46 | ||
47 | #if defined(BOOST_WINDOWS) && !defined(__CYGWIN__) | |
48 | ||
49 | #if BOOST_USE_WINAPI_VERSION >= BOOST_WINAPI_VERSION_WIN6 | |
50 | ||
51 | // Directly use API from Vista and later | |
b32b8144 | 52 | BOOST_LOG_API get_tick_count_t get_tick_count = &boost::winapi::GetTickCount64; |
7c673cae FG |
53 | |
54 | #else // BOOST_USE_WINAPI_VERSION >= BOOST_WINAPI_VERSION_WIN6 | |
55 | ||
56 | BOOST_LOG_ANONYMOUS_NAMESPACE { | |
57 | ||
58 | // Zero-initialized initially | |
59 | #if !defined(BOOST_LOG_NO_THREADS) | |
b32b8144 | 60 | BOOST_ALIGNMENT(BOOST_LOG_CPU_CACHE_LINE_SIZE) static boost::atomic< uint64_t > g_ticks; |
7c673cae | 61 | #else |
b32b8144 | 62 | BOOST_ALIGNMENT(BOOST_LOG_CPU_CACHE_LINE_SIZE) static uint64_t g_ticks; |
7c673cae FG |
63 | #endif |
64 | ||
65 | //! Artifical implementation of GetTickCount64 | |
66 | uint64_t WINAPI get_tick_count64() | |
67 | { | |
68 | #if !defined(BOOST_LOG_NO_THREADS) | |
69 | uint64_t old_state = g_ticks.load(boost::memory_order_acquire); | |
70 | #else | |
71 | uint64_t old_state = g_ticks; | |
72 | #endif | |
73 | ||
b32b8144 | 74 | uint32_t new_ticks = boost::winapi::GetTickCount(); |
7c673cae FG |
75 | |
76 | uint32_t old_ticks = static_cast< uint32_t >(old_state & UINT64_C(0x00000000ffffffff)); | |
77 | uint64_t new_state = ((old_state & UINT64_C(0xffffffff00000000)) + (static_cast< uint64_t >(new_ticks < old_ticks) << 32)) | static_cast< uint64_t >(new_ticks); | |
78 | ||
79 | #if !defined(BOOST_LOG_NO_THREADS) | |
80 | g_ticks.store(new_state, boost::memory_order_release); | |
81 | #else | |
82 | g_ticks = new_state; | |
83 | #endif | |
84 | ||
85 | return new_state; | |
86 | } | |
87 | ||
88 | uint64_t WINAPI get_tick_count_init() | |
89 | { | |
b32b8144 | 90 | boost::winapi::HMODULE_ hKernel32 = boost::winapi::GetModuleHandleW(L"kernel32.dll"); |
7c673cae FG |
91 | if (hKernel32) |
92 | { | |
b32b8144 | 93 | get_tick_count_t p = (get_tick_count_t)boost::winapi::get_proc_address(hKernel32, "GetTickCount64"); |
7c673cae FG |
94 | if (p) |
95 | { | |
96 | // Use native API | |
97 | get_tick_count = p; | |
98 | return p(); | |
99 | } | |
100 | } | |
101 | ||
102 | // No native API available | |
103 | get_tick_count = &get_tick_count64; | |
104 | return get_tick_count64(); | |
105 | } | |
106 | ||
107 | } // namespace | |
108 | ||
109 | BOOST_LOG_API get_tick_count_t get_tick_count = &get_tick_count_init; | |
110 | ||
111 | #endif // BOOST_USE_WINAPI_VERSION >= BOOST_WINAPI_VERSION_WIN6 | |
112 | ||
113 | #elif (defined(_POSIX_TIMERS) && (_POSIX_TIMERS+0) > 0) /* POSIX timers supported */ \ | |
114 | || defined(__GNU__) || defined(__OpenBSD__) || defined(__CloudABI__) /* GNU Hurd, OpenBSD and Nuxi CloudABI don't support POSIX timers fully but do provide clock_gettime() */ | |
115 | ||
116 | BOOST_LOG_API int64_t duration::milliseconds() const | |
117 | { | |
118 | // Timestamps are always in nanoseconds | |
119 | return m_ticks / INT64_C(1000000); | |
120 | } | |
121 | ||
122 | BOOST_LOG_ANONYMOUS_NAMESPACE { | |
123 | ||
124 | /*! | |
125 | * \c get_timestamp implementation based on POSIX realtime clock. | |
126 | * Note that this implementation is only used as a last resort since | |
127 | * this timer can be manually set and may jump due to DST change. | |
128 | */ | |
129 | timestamp get_timestamp_realtime_clock() | |
130 | { | |
131 | timespec ts; | |
132 | if (BOOST_UNLIKELY(clock_gettime(CLOCK_REALTIME, &ts) != 0)) | |
133 | { | |
134 | const int err = errno; | |
135 | BOOST_LOG_THROW_DESCR_PARAMS(system_error, "Failed to acquire current time", (err)); | |
136 | } | |
137 | ||
138 | return timestamp(static_cast< uint64_t >(ts.tv_sec) * UINT64_C(1000000000) + ts.tv_nsec); | |
139 | } | |
140 | ||
141 | # if defined(_POSIX_MONOTONIC_CLOCK) | |
142 | ||
143 | //! \c get_timestamp implementation based on POSIX monotonic clock | |
144 | timestamp get_timestamp_monotonic_clock() | |
145 | { | |
146 | timespec ts; | |
147 | if (BOOST_UNLIKELY(clock_gettime(CLOCK_MONOTONIC, &ts) != 0)) | |
148 | { | |
149 | const int err = errno; | |
150 | if (err == EINVAL) | |
151 | { | |
152 | // The current platform does not support monotonic timer. | |
153 | // Fall back to realtime clock, which is not exactly what we need | |
154 | // but is better than nothing. | |
155 | get_timestamp = &get_timestamp_realtime_clock; | |
156 | return get_timestamp_realtime_clock(); | |
157 | } | |
158 | BOOST_LOG_THROW_DESCR_PARAMS(system_error, "Failed to acquire current time", (err)); | |
159 | } | |
160 | ||
161 | return timestamp(static_cast< uint64_t >(ts.tv_sec) * UINT64_C(1000000000) + ts.tv_nsec); | |
162 | } | |
163 | ||
164 | # define BOOST_LOG_DEFAULT_GET_TIMESTAMP get_timestamp_monotonic_clock | |
165 | ||
166 | # else // if defined(_POSIX_MONOTONIC_CLOCK) | |
167 | # define BOOST_LOG_DEFAULT_GET_TIMESTAMP get_timestamp_realtime_clock | |
168 | # endif // if defined(_POSIX_MONOTONIC_CLOCK) | |
169 | ||
170 | } // namespace | |
171 | ||
172 | // Use POSIX API | |
173 | BOOST_LOG_API get_timestamp_t get_timestamp = &BOOST_LOG_DEFAULT_GET_TIMESTAMP; | |
174 | ||
175 | # undef BOOST_LOG_DEFAULT_GET_TIMESTAMP | |
176 | ||
177 | #elif defined(macintosh) || defined(__APPLE__) || defined(__APPLE_CC__) | |
178 | ||
179 | BOOST_LOG_API int64_t duration::milliseconds() const | |
180 | { | |
181 | static mach_timebase_info_data_t timebase_info = {}; | |
182 | BOOST_LOG_ONCE_BLOCK() | |
183 | { | |
184 | kern_return_t err = mach_timebase_info(&timebase_info); | |
185 | if (err != KERN_SUCCESS) | |
186 | { | |
187 | BOOST_LOG_THROW_DESCR_PARAMS(system_error, "Failed to initialize timebase info", (boost::system::errc::not_supported)); | |
188 | } | |
189 | } | |
190 | ||
191 | // Often the timebase rational equals 1, we can optimize for this case | |
192 | if (timebase_info.numer == timebase_info.denom) | |
193 | { | |
194 | // Timestamps are in nanoseconds | |
195 | return m_ticks / INT64_C(1000000); | |
196 | } | |
197 | else | |
198 | { | |
199 | return (m_ticks * timebase_info.numer) / (INT64_C(1000000) * timebase_info.denom); | |
200 | } | |
201 | } | |
202 | ||
203 | BOOST_LOG_ANONYMOUS_NAMESPACE { | |
204 | ||
205 | //! \c get_timestamp implementation based on MacOS X absolute time | |
206 | timestamp get_timestamp_mach() | |
207 | { | |
208 | return timestamp(mach_absolute_time()); | |
209 | } | |
210 | ||
211 | } // namespace | |
212 | ||
213 | // Use MacOS X API | |
214 | BOOST_LOG_API get_timestamp_t get_timestamp = &get_timestamp_mach; | |
215 | ||
216 | #else | |
217 | ||
218 | # error Boost.Log: Timestamp generation is not supported for your platform | |
219 | ||
220 | #endif | |
221 | ||
222 | } // namespace aux | |
223 | ||
224 | BOOST_LOG_CLOSE_NAMESPACE // namespace log | |
225 | ||
226 | } // namespace boost | |
227 | ||
228 | #include <boost/log/detail/footer.hpp> |