1 | // |
2 | // detail/impl/handler_tracking.ipp |
3 | // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
4 | // |
5 | // Copyright (c) 2003-2015 Christopher M. Kohlhoff (chris at kohlhoff dot com) |
6 | // |
7 | // Distributed under the Boost Software License, Version 1.0. (See accompanying |
8 | // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) |
9 | // |
10 | |
11 | #ifndef BOOST_ASIO_DETAIL_IMPL_HANDLER_TRACKING_IPP |
12 | #define BOOST_ASIO_DETAIL_IMPL_HANDLER_TRACKING_IPP |
13 | |
14 | #if defined(_MSC_VER) && (_MSC_VER >= 1200) |
15 | # pragma once |
16 | #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) |
17 | |
18 | #include <boost/asio/detail/config.hpp> |
19 | |
20 | #if defined(BOOST_ASIO_ENABLE_HANDLER_TRACKING) |
21 | |
22 | #include <cstdarg> |
23 | #include <cstdio> |
24 | #include <boost/asio/detail/handler_tracking.hpp> |
25 | |
26 | #if defined(BOOST_ASIO_HAS_BOOST_DATE_TIME) |
27 | # include <boost/asio/time_traits.hpp> |
28 | #else // defined(BOOST_ASIO_HAS_BOOST_DATE_TIME) |
29 | # if defined(BOOST_ASIO_HAS_STD_CHRONO) |
30 | # include <chrono> |
31 | # elif defined(BOOST_ASIO_HAS_BOOST_CHRONO) |
32 | # include <boost/chrono/system_clocks.hpp> |
33 | # endif |
34 | # include <boost/asio/detail/chrono_time_traits.hpp> |
35 | # include <boost/asio/wait_traits.hpp> |
36 | #endif // defined(BOOST_ASIO_HAS_BOOST_DATE_TIME) |
37 | |
38 | #if !defined(BOOST_ASIO_WINDOWS) |
39 | # include <unistd.h> |
40 | #endif // !defined(BOOST_ASIO_WINDOWS) |
41 | |
42 | #include <boost/asio/detail/push_options.hpp> |
43 | |
44 | namespace boost { |
45 | namespace asio { |
46 | namespace detail { |
47 | |
48 | struct handler_tracking_timestamp |
49 | { |
50 | uint64_t seconds; |
51 | uint64_t microseconds; |
52 | |
53 | handler_tracking_timestamp() |
54 | { |
55 | #if defined(BOOST_ASIO_HAS_BOOST_DATE_TIME) |
56 | boost::posix_time::ptime epoch(boost::gregorian::date(1970, 1, 1)); |
57 | boost::posix_time::time_duration now = |
58 | boost::posix_time::microsec_clock::universal_time() - epoch; |
59 | #elif defined(BOOST_ASIO_HAS_STD_CHRONO) |
60 | typedef chrono_time_traits<std::chrono::system_clock, |
61 | boost::asio::wait_traits<std::chrono::system_clock> > traits_helper; |
62 | traits_helper::posix_time_duration now( |
63 | std::chrono::system_clock::now().time_since_epoch()); |
64 | #elif defined(BOOST_ASIO_HAS_BOOST_CHRONO) |
65 | typedef chrono_time_traits<boost::chrono::system_clock, |
66 | boost::asio::wait_traits<boost::chrono::system_clock> > traits_helper; |
67 | traits_helper::posix_time_duration now( |
68 | boost::chrono::system_clock::now().time_since_epoch()); |
69 | #endif |
70 | seconds = static_cast<uint64_t>(now.total_seconds()); |
71 | microseconds = static_cast<uint64_t>(now.total_microseconds() % 1000000); |
72 | } |
73 | }; |
74 | |
75 | struct handler_tracking::tracking_state |
76 | { |
77 | static_mutex mutex_; |
78 | uint64_t next_id_; |
79 | tss_ptr<completion>* current_completion_; |
80 | }; |
81 | |
82 | handler_tracking::tracking_state* handler_tracking::get_state() |
83 | { |
84 | static tracking_state state = { BOOST_ASIO_STATIC_MUTEX_INIT, 1, 0 }; |
85 | return &state; |
86 | } |
87 | |
88 | void handler_tracking::init() |
89 | { |
90 | static tracking_state* state = get_state(); |
91 | |
92 | state->mutex_.init(); |
93 | |
94 | static_mutex::scoped_lock lock(state->mutex_); |
95 | if (state->current_completion_ == 0) |
96 | state->current_completion_ = new tss_ptr<completion>; |
97 | } |
98 | |
99 | void handler_tracking::creation(handler_tracking::tracked_handler* h, |
100 | const char* object_type, void* object, const char* op_name) |
101 | { |
102 | static tracking_state* state = get_state(); |
103 | |
104 | static_mutex::scoped_lock lock(state->mutex_); |
105 | h->id_ = state->next_id_++; |
106 | lock.unlock(); |
107 | |
108 | handler_tracking_timestamp timestamp; |
109 | |
110 | uint64_t current_id = 0; |
111 | if (completion* current_completion = *state->current_completion_) |
112 | current_id = current_completion->id_; |
113 | |
114 | write_line( |
115 | #if defined(BOOST_ASIO_WINDOWS) |
116 | "@asio|%I64u.%06I64u|%I64u*%I64u|%.20s@%p.%.50s\n" , |
117 | #else // defined(BOOST_ASIO_WINDOWS) |
118 | "@asio|%llu.%06llu|%llu*%llu|%.20s@%p.%.50s\n" , |
119 | #endif // defined(BOOST_ASIO_WINDOWS) |
120 | timestamp.seconds, timestamp.microseconds, |
121 | current_id, h->id_, object_type, object, op_name); |
122 | } |
123 | |
124 | handler_tracking::completion::completion(handler_tracking::tracked_handler* h) |
125 | : id_(h->id_), |
126 | invoked_(false), |
127 | next_(*get_state()->current_completion_) |
128 | { |
129 | *get_state()->current_completion_ = this; |
130 | } |
131 | |
132 | handler_tracking::completion::~completion() |
133 | { |
134 | if (id_) |
135 | { |
136 | handler_tracking_timestamp timestamp; |
137 | |
138 | write_line( |
139 | #if defined(BOOST_ASIO_WINDOWS) |
140 | "@asio|%I64u.%06I64u|%c%I64u|\n" , |
141 | #else // defined(BOOST_ASIO_WINDOWS) |
142 | "@asio|%llu.%06llu|%c%llu|\n" , |
143 | #endif // defined(BOOST_ASIO_WINDOWS) |
144 | timestamp.seconds, timestamp.microseconds, |
145 | invoked_ ? '!' : '~', id_); |
146 | } |
147 | |
148 | *get_state()->current_completion_ = next_; |
149 | } |
150 | |
151 | void handler_tracking::completion::invocation_begin() |
152 | { |
153 | handler_tracking_timestamp timestamp; |
154 | |
155 | write_line( |
156 | #if defined(BOOST_ASIO_WINDOWS) |
157 | "@asio|%I64u.%06I64u|>%I64u|\n" , |
158 | #else // defined(BOOST_ASIO_WINDOWS) |
159 | "@asio|%llu.%06llu|>%llu|\n" , |
160 | #endif // defined(BOOST_ASIO_WINDOWS) |
161 | timestamp.seconds, timestamp.microseconds, id_); |
162 | |
163 | invoked_ = true; |
164 | } |
165 | |
166 | void handler_tracking::completion::invocation_begin( |
167 | const boost::system::error_code& ec) |
168 | { |
169 | handler_tracking_timestamp timestamp; |
170 | |
171 | write_line( |
172 | #if defined(BOOST_ASIO_WINDOWS) |
173 | "@asio|%I64u.%06I64u|>%I64u|ec=%.20s:%d\n" , |
174 | #else // defined(BOOST_ASIO_WINDOWS) |
175 | "@asio|%llu.%06llu|>%llu|ec=%.20s:%d\n" , |
176 | #endif // defined(BOOST_ASIO_WINDOWS) |
177 | timestamp.seconds, timestamp.microseconds, |
178 | id_, ec.category().name(), ec.value()); |
179 | |
180 | invoked_ = true; |
181 | } |
182 | |
183 | void handler_tracking::completion::invocation_begin( |
184 | const boost::system::error_code& ec, std::size_t bytes_transferred) |
185 | { |
186 | handler_tracking_timestamp timestamp; |
187 | |
188 | write_line( |
189 | #if defined(BOOST_ASIO_WINDOWS) |
190 | "@asio|%I64u.%06I64u|>%I64u|ec=%.20s:%d,bytes_transferred=%I64u\n" , |
191 | #else // defined(BOOST_ASIO_WINDOWS) |
192 | "@asio|%llu.%06llu|>%llu|ec=%.20s:%d,bytes_transferred=%llu\n" , |
193 | #endif // defined(BOOST_ASIO_WINDOWS) |
194 | timestamp.seconds, timestamp.microseconds, |
195 | id_, ec.category().name(), ec.value(), |
196 | static_cast<uint64_t>(bytes_transferred)); |
197 | |
198 | invoked_ = true; |
199 | } |
200 | |
201 | void handler_tracking::completion::invocation_begin( |
202 | const boost::system::error_code& ec, int signal_number) |
203 | { |
204 | handler_tracking_timestamp timestamp; |
205 | |
206 | write_line( |
207 | #if defined(BOOST_ASIO_WINDOWS) |
208 | "@asio|%I64u.%06I64u|>%I64u|ec=%.20s:%d,signal_number=%d\n" , |
209 | #else // defined(BOOST_ASIO_WINDOWS) |
210 | "@asio|%llu.%06llu|>%llu|ec=%.20s:%d,signal_number=%d\n" , |
211 | #endif // defined(BOOST_ASIO_WINDOWS) |
212 | timestamp.seconds, timestamp.microseconds, |
213 | id_, ec.category().name(), ec.value(), signal_number); |
214 | |
215 | invoked_ = true; |
216 | } |
217 | |
218 | void handler_tracking::completion::invocation_begin( |
219 | const boost::system::error_code& ec, const char* arg) |
220 | { |
221 | handler_tracking_timestamp timestamp; |
222 | |
223 | write_line( |
224 | #if defined(BOOST_ASIO_WINDOWS) |
225 | "@asio|%I64u.%06I64u|>%I64u|ec=%.20s:%d,%.50s\n" , |
226 | #else // defined(BOOST_ASIO_WINDOWS) |
227 | "@asio|%llu.%06llu|>%llu|ec=%.20s:%d,%.50s\n" , |
228 | #endif // defined(BOOST_ASIO_WINDOWS) |
229 | timestamp.seconds, timestamp.microseconds, |
230 | id_, ec.category().name(), ec.value(), arg); |
231 | |
232 | invoked_ = true; |
233 | } |
234 | |
235 | void handler_tracking::completion::invocation_end() |
236 | { |
237 | if (id_) |
238 | { |
239 | handler_tracking_timestamp timestamp; |
240 | |
241 | write_line( |
242 | #if defined(BOOST_ASIO_WINDOWS) |
243 | "@asio|%I64u.%06I64u|<%I64u|\n" , |
244 | #else // defined(BOOST_ASIO_WINDOWS) |
245 | "@asio|%llu.%06llu|<%llu|\n" , |
246 | #endif // defined(BOOST_ASIO_WINDOWS) |
247 | timestamp.seconds, timestamp.microseconds, id_); |
248 | |
249 | id_ = 0; |
250 | } |
251 | } |
252 | |
253 | void handler_tracking::operation(const char* object_type, |
254 | void* object, const char* op_name) |
255 | { |
256 | static tracking_state* state = get_state(); |
257 | |
258 | handler_tracking_timestamp timestamp; |
259 | |
260 | unsigned long long current_id = 0; |
261 | if (completion* current_completion = *state->current_completion_) |
262 | current_id = current_completion->id_; |
263 | |
264 | write_line( |
265 | #if defined(BOOST_ASIO_WINDOWS) |
266 | "@asio|%I64u.%06I64u|%I64u|%.20s@%p.%.50s\n" , |
267 | #else // defined(BOOST_ASIO_WINDOWS) |
268 | "@asio|%llu.%06llu|%llu|%.20s@%p.%.50s\n" , |
269 | #endif // defined(BOOST_ASIO_WINDOWS) |
270 | timestamp.seconds, timestamp.microseconds, |
271 | current_id, object_type, object, op_name); |
272 | } |
273 | |
274 | void handler_tracking::write_line(const char* format, ...) |
275 | { |
276 | using namespace std; // For sprintf (or equivalent). |
277 | |
278 | va_list args; |
279 | va_start(args, format); |
280 | |
281 | char line[256] = "" ; |
282 | #if defined(BOOST_ASIO_HAS_SECURE_RTL) |
283 | int length = vsprintf_s(line, sizeof(line), format, args); |
284 | #else // defined(BOOST_ASIO_HAS_SECURE_RTL) |
285 | int length = vsprintf(line, format, args); |
286 | #endif // defined(BOOST_ASIO_HAS_SECURE_RTL) |
287 | |
288 | va_end(args); |
289 | |
290 | #if defined(BOOST_ASIO_WINDOWS) |
291 | HANDLE stderr_handle = ::GetStdHandle(STD_ERROR_HANDLE); |
292 | DWORD bytes_written = 0; |
293 | ::WriteFile(stderr_handle, line, length, &bytes_written, 0); |
294 | #else // defined(BOOST_ASIO_WINDOWS) |
295 | ::write(STDERR_FILENO, line, length); |
296 | #endif // defined(BOOST_ASIO_WINDOWS) |
297 | } |
298 | |
299 | } // namespace detail |
300 | } // namespace asio |
301 | } // namespace boost |
302 | |
303 | #include <boost/asio/detail/pop_options.hpp> |
304 | |
305 | #endif // defined(BOOST_ASIO_ENABLE_HANDLER_TRACKING) |
306 | |
307 | #endif // BOOST_ASIO_DETAIL_IMPL_HANDLER_TRACKING_IPP |
308 | |