handler_tracking.ipp 11 KB

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