Tor  0.4.7.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 
131 #include "lib/cc/compat_compiler.h"
135 #include "lib/pubsub/pubsub_flags.h"
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.