Tor 0.4.9.0-alpha-dev
pubsub_macros.h
Go to the documentation of this file.
1/* Copyright (c) 2001, Matej Pfajfar.
2 * Copyright (c) 2001-2004, Roger Dingledine.
3 * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
4 * Copyright (c) 2007-2021, The Tor Project, Inc. */
5/* See LICENSE for licensing information */
6
7/**
8 * \file pubsub_macros.h
9 * \brief Macros to help with the publish/subscribe dispatch API.
10 *
11 * The dispatch API allows different subsystems of Tor to communicate with
12 * another asynchronously via a shared "message" system. Some subsystems
13 * declare that they publish a given message, and others declare that they
14 * subscribe to it. Both subsystems depend on the message, but not upon one
15 * another.
16 *
17 * To declare a message, use DECLARE_MESSAGE() (for messages that take their
18 * data as a pointer) or DECLARE_MESSAGE_INT() (for messages that take their
19 * data as an integer. For example, you might say
20 *
21 * DECLARE_MESSAGE(new_circuit, circ, circuit_handle_t *);
22 * or
23 * DECLARE_MESSAGE_INT(shutdown_requested, boolean, bool);
24 *
25 * Every message has a unique name, a "type name" that the dispatch system
26 * uses to manage associated data, and a C type name. You'll want to put
27 * these declarations in a header, to be included by all publishers and all
28 * subscribers.
29 *
30 * When a subsystem wants to publish a message, it uses DECLARE_PUBLISH() at
31 * file scope to create necessary static functions. Then, in its subsystem
32 * initialization (in the "bind to dispatcher" callback) (TODO: name this
33 * properly!), it calls DISPATCH_ADD_PUB() to tell the dispatcher about its
34 * intent to publish. When it actually wants to publish, it uses the
35 * PUBLISH() macro. For example:
36 *
37 * // At file scope
38 * DECLARE_PUBLISH(shutdown_requested);
39 *
40 * static void bind_to_dispatcher(pubsub_connector_t *con)
41 * {
42 * DISPATCH_ADD_PUB(con, mainchannel, shutdown_requested);
43 * }
44 *
45 * // somewhere in a function
46 * {
47 * PUBLISH(shutdown_requested, true);
48 * }
49 *
50 * When a subsystem wants to subscribe to a message, it uses
51 * DECLARE_SUBSCRIBE() at file scope to declare static functions. It must
52 * declare a hook function that receives the message type. Then, in its "bind
53 * to dispatcher" function, it calls DISPATCHER_ADD_SUB() to tell the
54 * dispatcher about its intent to subscribe. When another module publishes
55 * the message, the dispatcher will call the provided hook function.
56 *
57 * // At file scope. The first argument is the message that you're
58 * // subscribing to; the second argument is the hook function to declare.
59 * DECLARE_SUBSCRIBE(shutdown_requested, on_shutdown_req_cb);
60 *
61 * // You need to declare this function.
62 * static void on_shutdown_req_cb(const msg_t *msg,
63 * bool value)
64 * {
65 * // (do something here.)
66 * }
67 *
68 * static void bind_to_dispatcher(pubsub_connector_t *con)
69 * {
70 * DISPATCH_ADD_SUB(con, mainchannel, shutdown_requested);
71 * }
72 *
73 * Where did these types come from? Somewhere in the code, you need to call
74 * DISPATCH_REGISTER_TYPE() to make sure that the dispatcher can manage the
75 * message auxiliary data. It associates a vtbl-like structure with the
76 * type name, so that the dispatcher knows how to manipulate the type you're
77 * giving it.
78 *
79 * For example, the "boolean" type we're using above could be defined as:
80 *
81 * static char *boolean_fmt(msg_aux_data_t d)
82 * {
83 * // This is used for debugging and dumping messages.
84 * if (d.u64)
85 * return tor_strdup("true");
86 * else
87 * return tor_strdup("false");
88 * }
89 *
90 * static void boolean_free(msg_aux_data_t d)
91 * {
92 * // We don't actually need to do anything to free a boolean.
93 * // We could use "NULL" instead of this function, but I'm including
94 * // it as an example.
95 * }
96 *
97 * static void bind_to_dispatcher(pubsub_connector_t *con)
98 * {
99 * dispatch_typefns_t boolean_fns = {
100 * .fmt_fn = boolean_fmt,
101 * .free_fn = boolean_free,
102 * };
103 * DISPATCH_REGISTER_TYPE(con, boolean, &boolean_fns);
104 * }
105 *
106 *
107 *
108 * So, how does this all work? (You can stop reading here, unless you're
109 * debugging something.)
110 *
111 * When you declare a message in a header with DECLARE_MESSAGE() or
112 * DECLARE_MESSAGE_INT(), it creates five things:
113 *
114 * * two typedefs for the message argument (constant and non-constant
115 * variants).
116 * * a constant string to hold the declared message type name
117 * * two inline functions, to coerce the message argument type to and from
118 * a "msg_aux_data_t" union.
119 *
120 * All of these declarations have names based on the message name.
121 *
122 * Later, when you say DECLARE_PUBLISH() or DECLARE_SUBSCRIBE(), we use the
123 * elements defined by DECLARE_MESSAGE() to make sure that the publish
124 * function takes the correct argument type, and that the subscription hook is
125 * declared with the right argument type.
126 **/
127
128#ifndef TOR_DISPATCH_MSG_H
129#define TOR_DISPATCH_MSG_H
130
137
138/* Implementation notes:
139 *
140 * For a messagename "foo", the DECLARE_MESSAGE*() macros must declare:
141 *
142 * msg_arg_type__foo -- a typedef for the argument type of the foo message.
143 * msg_arg_consttype__foo -- a typedef for the const argument type of the
144 * foo message.
145 * msg_arg_name__foo[] -- a static string constant holding the unique
146 * identifier for the type of the foo message.
147 * msg_arg_get__foo() -- an inline function taking a msg_aux_data_t and
148 * returning the C data type.
149 * msg_arg_set__foo() -- an inline function taking a msg_aux_data_t and
150 * the C type, setting the msg_aux_data_t to hold the C type.
151 *
152 * For a messagename "foo", the DECLARE_PUBLISH() macro must declare:
153 *
154 * pub_binding__foo -- A static pub_binding_t object used to send messages
155 * from this module.
156 * publish_fn__foo -- A function taking an argument of the appropriate
157 * C type, to be invoked by PUBLISH().
158 *
159 * For a messagename "foo", the DECLARE_SUBSCRIBE() macro must declare:
160 *
161 * hookfn -- A user-provided function name, with the correct signature.
162 * recv_fn__foo -- A wrapper callback that takes a msg_t *, and calls
163 * hookfn with the appropriate arguments.
164 */
165
166/** Macro to declare common elements shared by DECLARE_MESSAGE and
167 * DECLARE_MESSAGE_INT. Don't call this directly.
168 *
169 * Note that the "msg_arg_name" string constant is defined in each
170 * translation unit. This might be undesirable; we can tweak it in the
171 * future if need be.
172 */
173#define DECLARE_MESSAGE_COMMON__(messagename, typename, c_type) \
174 typedef c_type msg_arg_type__ ##messagename; \
175 typedef const c_type msg_arg_consttype__ ##messagename; \
176 ATTR_UNUSED static const char msg_arg_name__ ##messagename[] = # typename;
177
178/**
179 * Use this macro in a header to declare the existence of a given message,
180 * taking a pointer as auxiliary data.
181 *
182 * "messagename" is a unique identifier for the message; it must be a valid
183 * C identifier.
184 *
185 * "typename" is a unique identifier for the type of the auxiliary data.
186 * It needs to be defined somewhere in Tor, using
187 * "DISPATCH_REGISTER_TYPE."
188 *
189 * "c_ptr_type" is a C pointer type (like "char *" or "struct foo *").
190 * The "*" needs to be included.
191 */
192#define DECLARE_MESSAGE(messagename, typename, c_ptr_type) \
193 DECLARE_MESSAGE_COMMON__(messagename, typename, c_ptr_type) \
194 ATTR_UNUSED static inline c_ptr_type \
195 msg_arg_get__ ##messagename(msg_aux_data_t m) \
196 { \
197 return m.ptr; \
198 } \
199 ATTR_UNUSED static inline void \
200 msg_arg_set__ ##messagename(msg_aux_data_t *m, c_ptr_type v) \
201 { \
202 m->ptr = v; \
203 } \
204 EAT_SEMICOLON
205
206/**
207 * Use this macro in a header to declare the existence of a given message,
208 * taking an integer as auxiliary data.
209 *
210 * "messagename" is a unique identifier for the message; it must be a valid
211 * C identifier.
212 *
213 * "typename" is a unique identifier for the type of the auxiliary data. It
214 * needs to be defined somewhere in Tor, using "DISPATCH_REGISTER_TYPE."
215 *
216 * "c_type" is a C integer type, like "int" or "bool". It needs to fit inside
217 * a uint64_t.
218 */
219#define DECLARE_MESSAGE_INT(messagename, typename, c_type) \
220 DECLARE_MESSAGE_COMMON__(messagename, typename, c_type) \
221 ATTR_UNUSED static inline c_type \
222 msg_arg_get__ ##messagename(msg_aux_data_t m) \
223 { \
224 return (c_type)m.u64; \
225 } \
226 ATTR_UNUSED static inline void \
227 msg_arg_set__ ##messagename(msg_aux_data_t *m, c_type v) \
228 { \
229 m->u64 = (uint64_t)v; \
230 } \
231 EAT_SEMICOLON
232
233/**
234 * Use this macro inside a C module declare that we'll be publishing a given
235 * message type from within this module.
236 *
237 * It creates necessary functions and wrappers to publish a message whose
238 * unique identifier is "messagename".
239 *
240 * Before you use this, you need to include the header where DECLARE_MESSAGE*()
241 * was used for this message.
242 *
243 * You can only use this once per message in each subsystem.
244 */
245#define DECLARE_PUBLISH(messagename) \
246 static pub_binding_t pub_binding__ ##messagename; \
247 static void \
248 publish_fn__ ##messagename(msg_arg_type__ ##messagename arg) \
249 { \
250 msg_aux_data_t data; \
251 msg_arg_set__ ##messagename(&data, arg); \
252 pubsub_pub_(&pub_binding__ ##messagename, data); \
253 } \
254 EAT_SEMICOLON
255
256/**
257 * Use this macro inside a C file to declare that we're subscribing to a
258 * given message and associating it with a given "hook function". It
259 * declares the hook function static, and helps with strong typing.
260 *
261 * Before you use this, you need to include the header where
262 * DECLARE_MESSAGE*() was used for the message whose unique identifier is
263 * "messagename".
264 *
265 * You will need to define a function with the name that you provide for
266 * "hookfn". The type of this function will be:
267 * static void hookfn(const msg_t *, const c_type)
268 * where c_type is the c type that you declared in the header.
269 *
270 * You can only use this once per message in each subsystem.
271 */
272#define DECLARE_SUBSCRIBE(messagename, hookfn) \
273 static void hookfn(const msg_t *, \
274 const msg_arg_consttype__ ##messagename); \
275 static void recv_fn__ ## messagename(const msg_t *m) \
276 { \
277 msg_arg_type__ ## messagename arg; \
278 arg = msg_arg_get__ ##messagename(m->aux_data__); \
279 hookfn(m, arg); \
280 } \
281 EAT_SEMICOLON
282
283/**
284 * Add a fake use of the publish function for 'messagename', so that
285 * the compiler does not call it unused.
286 */
287#define DISPATCH__FAKE_USE_OF_PUBFN_(messagename) \
288 ( 0 ? (publish_fn__ ##messagename((msg_arg_type__##messagename)0), 1) \
289 : 1)
290
291/**
292 * This macro is for internal use. It backs DISPATCH_ADD_PUB*()
293 */
294#define DISPATCH_ADD_PUB_(connector, channel, messagename, flags) \
295 ( \
296 DISPATCH__FAKE_USE_OF_PUBFN_(messagename), \
297 pubsub_add_pub_((connector), \
298 &pub_binding__ ##messagename, \
299 get_channel_id(# channel), \
300 get_message_id(# messagename), \
301 get_msg_type_id(msg_arg_name__ ## messagename), \
302 (flags), \
303 __FILE__, \
304 __LINE__) \
305 )
306
307/**
308 * Use a given connector and channel name to declare that this subsystem will
309 * publish a given message type.
310 *
311 * Call this macro from within the add_subscriptions() function of a module.
312 */
313#define DISPATCH_ADD_PUB(connector, channel, messagename) \
314 DISPATCH_ADD_PUB_(connector, channel, messagename, 0)
315
316/**
317 * Use a given connector and channel name to declare that this subsystem will
318 * publish a given message type, and that no other subsystem is allowed to.
319 *
320 * Call this macro from within the add_subscriptions() function of a module.
321 */
322#define DISPATCH_ADD_PUB_EXCL(connector, channel, messagename) \
323 DISPATCH_ADD_PUB_(connector, channel, messagename, DISP_FLAG_EXCL)
324
325/**
326 * This macro is for internal use. It backs DISPATCH_ADD_SUB*()
327 */
328#define DISPATCH_ADD_SUB_(connector, channel, messagename, flags) \
329 pubsub_add_sub_((connector), \
330 recv_fn__ ##messagename, \
331 get_channel_id(#channel), \
332 get_message_id(# messagename), \
333 get_msg_type_id(msg_arg_name__ ##messagename), \
334 (flags), \
335 __FILE__, \
336 __LINE__)
337/**
338 * Use a given connector and channel name to declare that this subsystem will
339 * receive a given message type.
340 *
341 * Call this macro from within the add_subscriptions() function of a module.
342 */
343#define DISPATCH_ADD_SUB(connector, channel, messagename) \
344 DISPATCH_ADD_SUB_(connector, channel, messagename, 0)
345/**
346 * Use a given connector and channel name to declare that this subsystem will
347 * receive a given message type, and that no other subsystem is allowed to do
348 * so.
349 *
350 * Call this macro from within the add_subscriptions() function of a module.
351 */
352#define DISPATCH_ADD_SUB_EXCL(connector, channel, messagename) \
353 DISPATCH_ADD_SUB_(connector, channel, messagename, DISP_FLAG_EXCL)
354
355/**
356 * Publish a given message with a given argument. (Takes ownership of the
357 * argument if it is a pointer.)
358 */
359#define PUBLISH(messagename, arg) \
360 publish_fn__ ##messagename(arg)
361
362/**
363 * Use a given connector to declare that the functions to be used to manipuate
364 * a certain C type.
365 **/
366#define DISPATCH_REGISTER_TYPE(con, type, fns) \
367 pubsub_connector_register_type_((con), \
368 get_msg_type_id(#type), \
369 (fns), \
370 __FILE__, \
371 __LINE__)
372
373#endif /* !defined(TOR_DISPATCH_MSG_H) */
Utility macros to handle different features and behavior in different compilers.
Header for dispatch_naming.c.
Declaration of pub_binding_t.
Header for functions that add relationships to a pubsub builder.
Flags that can be set on publish/subscribe messages.
Header for pubsub_publish.c.