handler_tracking.ipp 12 KB

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