]>
Commit | Line | Data |
---|---|---|
b32b8144 FG |
1 | // |
2 | // custom_tracking.hpp | |
3 | // ~~~~~~~~~~~~~~~~~~~ | |
4 | // | |
92f5a8d4 | 5 | // Copyright (c) 2003-2019 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 | ||
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. | |
70 | static void init() | |
71 | { | |
72 | } | |
73 | ||
74 | // Record the creation of a tracked handler. | |
75 | 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 | { | |
99 | 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. | |
111 | ~completion() | |
112 | { | |
113 | *current_completion() = next_; | |
114 | } | |
115 | ||
116 | // Records that handler is to be invoked with the specified arguments. | |
117 | template <class... Args> | |
118 | 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. | |
125 | 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 | ||
137 | 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. | |
144 | 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. | |
151 | 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. | |
159 | 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. | |
167 | 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. | |
179 | 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. | |
189 | 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 |