handler_tracking.ipp 11 KB

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