1 // 2 // custom_tracking.hpp 3 // ~~~~~~~~~~~~~~~~~~~ 4 // 5 // Copyright (c) 2003-2020 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 CUSTOM_TRACKING_HPP 12 #define CUSTOM_TRACKING_HPP 13 14 #include <cinttypes> 15 #include <cstdint> 16 #include <cstdio> 17 18 # define BOOST_ASIO_INHERIT_TRACKED_HANDLER \ 19 : public ::custom_tracking::tracked_handler 20 21 # define BOOST_ASIO_ALSO_INHERIT_TRACKED_HANDLER \ 22 , public ::custom_tracking::tracked_handler 23 24 # define BOOST_ASIO_HANDLER_TRACKING_INIT \ 25 ::custom_tracking::init() 26 27 # define BOOST_ASIO_HANDLER_LOCATION(args) \ 28 ::custom_tracking::location args 29 30 # define BOOST_ASIO_HANDLER_CREATION(args) \ 31 ::custom_tracking::creation args 32 33 # define BOOST_ASIO_HANDLER_COMPLETION(args) \ 34 ::custom_tracking::completion tracked_completion args 35 36 # define BOOST_ASIO_HANDLER_INVOCATION_BEGIN(args) \ 37 tracked_completion.invocation_begin args 38 39 # define BOOST_ASIO_HANDLER_INVOCATION_END \ 40 tracked_completion.invocation_end() 41 42 # define BOOST_ASIO_HANDLER_OPERATION(args) \ 43 ::custom_tracking::operation args 44 45 # define BOOST_ASIO_HANDLER_REACTOR_REGISTRATION(args) \ 46 ::custom_tracking::reactor_registration args 47 48 # define BOOST_ASIO_HANDLER_REACTOR_DEREGISTRATION(args) \ 49 ::custom_tracking::reactor_deregistration args 50 51 # define BOOST_ASIO_HANDLER_REACTOR_READ_EVENT 1 52 # define BOOST_ASIO_HANDLER_REACTOR_WRITE_EVENT 2 53 # define BOOST_ASIO_HANDLER_REACTOR_ERROR_EVENT 4 54 55 # define BOOST_ASIO_HANDLER_REACTOR_EVENTS(args) \ 56 ::custom_tracking::reactor_events args 57 58 # define BOOST_ASIO_HANDLER_REACTOR_OPERATION(args) \ 59 ::custom_tracking::reactor_operation args 60 61 struct custom_tracking 62 { 63 // Base class for objects containing tracked handlers. 64 struct tracked_handler 65 { 66 std::uintmax_t handler_id_ = 0; // To uniquely identify a handler. 67 std::uintmax_t tree_id_ = 0; // To identify related handlers. 68 const char* object_type_; // The object type associated with the handler. 69 std::uintmax_t native_handle_; // Native handle, if any. 70 }; 71 72 // Initialise the tracking system. initcustom_tracking73 static void init() 74 { 75 } 76 77 // Record a source location. locationcustom_tracking78 static void location(const char* file_name, 79 int line, const char* function_name) 80 { 81 std::printf("At location %s:%d in %s\n", file_name, line, function_name); 82 } 83 84 // Record the creation of a tracked handler. creationcustom_tracking85 static void creation(boost::asio::execution_context& /*ctx*/, 86 tracked_handler& h, const char* object_type, void* /*object*/, 87 std::uintmax_t native_handle, const char* op_name) 88 { 89 // Generate a unique id for the new handler. 90 static std::atomic<std::uintmax_t> next_handler_id{1}; 91 h.handler_id_ = next_handler_id++; 92 93 // Copy the tree identifier forward from the current handler. 94 if (*current_completion()) 95 h.tree_id_ = (*current_completion())->handler_.tree_id_; 96 97 // Store various attributes of the operation to use in later output. 98 h.object_type_ = object_type; 99 h.native_handle_ = native_handle; 100 101 std::printf( 102 "Starting operation %s.%s for native_handle = %" PRIuMAX 103 ", handler = %" PRIuMAX ", tree = %" PRIuMAX "\n", 104 object_type, op_name, h.native_handle_, h.handler_id_, h.tree_id_); 105 } 106 107 struct completion 108 { completioncustom_tracking::completion109 explicit completion(const tracked_handler& h) 110 : handler_(h), 111 next_(*current_completion()) 112 { 113 *current_completion() = this; 114 } 115 116 completion(const completion&) = delete; 117 completion& operator=(const completion&) = delete; 118 119 // Destructor records only when an exception is thrown from the handler, or 120 // if the memory is being freed without the handler having been invoked. ~completioncustom_tracking::completion121 ~completion() 122 { 123 *current_completion() = next_; 124 } 125 126 // Records that handler is to be invoked with the specified arguments. 127 template <class... Args> invocation_begincustom_tracking::completion128 void invocation_begin(Args&&... /*args*/) 129 { 130 std::printf("Entering handler %" PRIuMAX " in tree %" PRIuMAX "\n", 131 handler_.handler_id_, handler_.tree_id_); 132 } 133 134 // Record that handler invocation has ended. invocation_endcustom_tracking::completion135 void invocation_end() 136 { 137 std::printf("Leaving handler %" PRIuMAX " in tree %" PRIuMAX "\n", 138 handler_.handler_id_, handler_.tree_id_); 139 } 140 141 tracked_handler handler_; 142 143 // Completions may nest. Here we stash a pointer to the outer completion. 144 completion* next_; 145 }; 146 current_completioncustom_tracking147 static completion** current_completion() 148 { 149 static BOOST_ASIO_THREAD_KEYWORD completion* current = nullptr; 150 return ¤t; 151 } 152 153 // Record an operation that is not directly associated with a handler. operationcustom_tracking154 static void operation(boost::asio::execution_context& /*ctx*/, 155 const char* /*object_type*/, void* /*object*/, 156 std::uintmax_t /*native_handle*/, const char* /*op_name*/) 157 { 158 } 159 160 // Record that a descriptor has been registered with the reactor. reactor_registrationcustom_tracking161 static void reactor_registration(boost::asio::execution_context& context, 162 uintmax_t native_handle, uintmax_t registration) 163 { 164 std::printf("Adding to reactor native_handle = %" PRIuMAX 165 ", registration = %" PRIuMAX "\n", native_handle, registration); 166 } 167 168 // Record that a descriptor has been deregistered from the reactor. reactor_deregistrationcustom_tracking169 static void reactor_deregistration(boost::asio::execution_context& context, 170 uintmax_t native_handle, uintmax_t registration) 171 { 172 std::printf("Removing from reactor native_handle = %" PRIuMAX 173 ", registration = %" PRIuMAX "\n", native_handle, registration); 174 } 175 176 // Record reactor-based readiness events associated with a descriptor. reactor_eventscustom_tracking177 static void reactor_events(boost::asio::execution_context& context, 178 uintmax_t registration, unsigned events) 179 { 180 std::printf( 181 "Reactor readiness for registration = %" PRIuMAX ", events =%s%s%s\n", 182 registration, 183 (events & BOOST_ASIO_HANDLER_REACTOR_READ_EVENT) ? " read" : "", 184 (events & BOOST_ASIO_HANDLER_REACTOR_WRITE_EVENT) ? " write" : "", 185 (events & BOOST_ASIO_HANDLER_REACTOR_ERROR_EVENT) ? " error" : ""); 186 } 187 188 // Record a reactor-based operation that is associated with a handler. reactor_operationcustom_tracking189 static void reactor_operation(const tracked_handler& h, 190 const char* op_name, const boost::system::error_code& ec) 191 { 192 std::printf( 193 "Performed operation %s.%s for native_handle = %" PRIuMAX 194 ", ec = %s:%d\n", h.object_type_, op_name, h.native_handle_, 195 ec.category().name(), ec.value()); 196 } 197 198 // Record a reactor-based operation that is associated with a handler. reactor_operationcustom_tracking199 static void reactor_operation(const tracked_handler& h, 200 const char* op_name, const boost::system::error_code& ec, 201 std::size_t bytes_transferred) 202 { 203 std::printf( 204 "Performed operation %s.%s for native_handle = %" PRIuMAX 205 ", ec = %s:%d, n = %" PRIuMAX "\n", h.object_type_, op_name, 206 h.native_handle_, ec.category().name(), ec.value(), 207 static_cast<uintmax_t>(bytes_transferred)); 208 } 209 }; 210 211 #endif // CUSTOM_TRACKING_HPP 212