]>
Commit | Line | Data |
---|---|---|
b32b8144 FG |
1 | // |
2 | // custom_tracking.hpp | |
3 | // ~~~~~~~~~~~~~~~~~~~ | |
4 | // | |
f67539c2 | 5 | // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) |
b32b8144 FG |
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 | ||
20effc67 TL |
27 | # define BOOST_ASIO_HANDLER_LOCATION(args) \ |
28 | ::custom_tracking::location args | |
29 | ||
b32b8144 FG |
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. | |
73 | static void init() | |
74 | { | |
75 | } | |
76 | ||
20effc67 TL |
77 | // Record a source location. |
78 | 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 | ||
b32b8144 FG |
84 | // Record the creation of a tracked handler. |
85 | 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 | { | |
109 | 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. | |
121 | ~completion() | |
122 | { | |
123 | *current_completion() = next_; | |
124 | } | |
125 | ||
126 | // Records that handler is to be invoked with the specified arguments. | |
127 | template <class... Args> | |
128 | 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. | |
135 | 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 | ||
147 | 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. | |
154 | 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. | |
161 | 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. | |
169 | 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. | |
177 | 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. | |
189 | 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. | |
199 | 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 |