1 // 2 // custom_tracking.hpp 3 // ~~~~~~~~~~~~~~~~~~~ 4 // 5 // Copyright (c) 2003-2019 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_CREATION(args) \ 28 ::custom_tracking::creation args 29 30 # define BOOST_ASIO_HANDLER_COMPLETION(args) \ 31 ::custom_tracking::completion tracked_completion args 32 33 # define BOOST_ASIO_HANDLER_INVOCATION_BEGIN(args) \ 34 tracked_completion.invocation_begin args 35 36 # define BOOST_ASIO_HANDLER_INVOCATION_END \ 37 tracked_completion.invocation_end() 38 39 # define BOOST_ASIO_HANDLER_OPERATION(args) \ 40 ::custom_tracking::operation args 41 42 # define BOOST_ASIO_HANDLER_REACTOR_REGISTRATION(args) \ 43 ::custom_tracking::reactor_registration args 44 45 # define BOOST_ASIO_HANDLER_REACTOR_DEREGISTRATION(args) \ 46 ::custom_tracking::reactor_deregistration args 47 48 # define BOOST_ASIO_HANDLER_REACTOR_READ_EVENT 1 49 # define BOOST_ASIO_HANDLER_REACTOR_WRITE_EVENT 2 50 # define BOOST_ASIO_HANDLER_REACTOR_ERROR_EVENT 4 51 52 # define BOOST_ASIO_HANDLER_REACTOR_EVENTS(args) \ 53 ::custom_tracking::reactor_events args 54 55 # define BOOST_ASIO_HANDLER_REACTOR_OPERATION(args) \ 56 ::custom_tracking::reactor_operation args 57 58 struct custom_tracking 59 { 60 // Base class for objects containing tracked handlers. 61 struct tracked_handler 62 { 63 std::uintmax_t handler_id_ = 0; // To uniquely identify a handler. 64 std::uintmax_t tree_id_ = 0; // To identify related handlers. 65 const char* object_type_; // The object type associated with the handler. 66 std::uintmax_t native_handle_; // Native handle, if any. 67 }; 68 69 // Initialise the tracking system. initcustom_tracking70 static void init() 71 { 72 } 73 74 // Record the creation of a tracked handler. creationcustom_tracking75 static void creation(boost::asio::execution_context& /*ctx*/, 76 tracked_handler& h, const char* object_type, void* /*object*/, 77 std::uintmax_t native_handle, const char* op_name) 78 { 79 // Generate a unique id for the new handler. 80 static std::atomic<std::uintmax_t> next_handler_id{1}; 81 h.handler_id_ = next_handler_id++; 82 83 // Copy the tree identifier forward from the current handler. 84 if (*current_completion()) 85 h.tree_id_ = (*current_completion())->handler_.tree_id_; 86 87 // Store various attributes of the operation to use in later output. 88 h.object_type_ = object_type; 89 h.native_handle_ = native_handle; 90 91 std::printf( 92 "Starting operation %s.%s for native_handle = %" PRIuMAX 93 ", handler = %" PRIuMAX ", tree = %" PRIuMAX "\n", 94 object_type, op_name, h.native_handle_, h.handler_id_, h.tree_id_); 95 } 96 97 struct completion 98 { completioncustom_tracking::completion99 explicit completion(const tracked_handler& h) 100 : handler_(h), 101 next_(*current_completion()) 102 { 103 *current_completion() = this; 104 } 105 106 completion(const completion&) = delete; 107 completion& operator=(const completion&) = delete; 108 109 // Destructor records only when an exception is thrown from the handler, or 110 // if the memory is being freed without the handler having been invoked. ~completioncustom_tracking::completion111 ~completion() 112 { 113 *current_completion() = next_; 114 } 115 116 // Records that handler is to be invoked with the specified arguments. 117 template <class... Args> invocation_begincustom_tracking::completion118 void invocation_begin(Args&&... /*args*/) 119 { 120 std::printf("Entering handler %" PRIuMAX " in tree %" PRIuMAX "\n", 121 handler_.handler_id_, handler_.tree_id_); 122 } 123 124 // Record that handler invocation has ended. invocation_endcustom_tracking::completion125 void invocation_end() 126 { 127 std::printf("Leaving handler %" PRIuMAX " in tree %" PRIuMAX "\n", 128 handler_.handler_id_, handler_.tree_id_); 129 } 130 131 tracked_handler handler_; 132 133 // Completions may nest. Here we stash a pointer to the outer completion. 134 completion* next_; 135 }; 136 current_completioncustom_tracking137 static completion** current_completion() 138 { 139 static BOOST_ASIO_THREAD_KEYWORD completion* current = nullptr; 140 return ¤t; 141 } 142 143 // Record an operation that is not directly associated with a handler. operationcustom_tracking144 static void operation(boost::asio::execution_context& /*ctx*/, 145 const char* /*object_type*/, void* /*object*/, 146 std::uintmax_t /*native_handle*/, const char* /*op_name*/) 147 { 148 } 149 150 // Record that a descriptor has been registered with the reactor. reactor_registrationcustom_tracking151 static void reactor_registration(boost::asio::execution_context& context, 152 uintmax_t native_handle, uintmax_t registration) 153 { 154 std::printf("Adding to reactor native_handle = %" PRIuMAX 155 ", registration = %" PRIuMAX "\n", native_handle, registration); 156 } 157 158 // Record that a descriptor has been deregistered from the reactor. reactor_deregistrationcustom_tracking159 static void reactor_deregistration(boost::asio::execution_context& context, 160 uintmax_t native_handle, uintmax_t registration) 161 { 162 std::printf("Removing from reactor native_handle = %" PRIuMAX 163 ", registration = %" PRIuMAX "\n", native_handle, registration); 164 } 165 166 // Record reactor-based readiness events associated with a descriptor. reactor_eventscustom_tracking167 static void reactor_events(boost::asio::execution_context& context, 168 uintmax_t registration, unsigned events) 169 { 170 std::printf( 171 "Reactor readiness for registration = %" PRIuMAX ", events =%s%s%s\n", 172 registration, 173 (events & BOOST_ASIO_HANDLER_REACTOR_READ_EVENT) ? " read" : "", 174 (events & BOOST_ASIO_HANDLER_REACTOR_WRITE_EVENT) ? " write" : "", 175 (events & BOOST_ASIO_HANDLER_REACTOR_ERROR_EVENT) ? " error" : ""); 176 } 177 178 // Record a reactor-based operation that is associated with a handler. reactor_operationcustom_tracking179 static void reactor_operation(const tracked_handler& h, 180 const char* op_name, const boost::system::error_code& ec) 181 { 182 std::printf( 183 "Performed operation %s.%s for native_handle = %" PRIuMAX 184 ", ec = %s:%d\n", h.object_type_, op_name, h.native_handle_, 185 ec.category().name(), ec.value()); 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 std::size_t bytes_transferred) 192 { 193 std::printf( 194 "Performed operation %s.%s for native_handle = %" PRIuMAX 195 ", ec = %s:%d, n = %" PRIuMAX "\n", h.object_type_, op_name, 196 h.native_handle_, ec.category().name(), ec.value(), 197 static_cast<uintmax_t>(bytes_transferred)); 198 } 199 }; 200 201 #endif // CUSTOM_TRACKING_HPP 202