Tor  0.4.7.0-alpha-dev
Macros
pubsub_macros.h File Reference

Macros to help with the publish/subscribe dispatch API. More...

#include "lib/cc/compat_compiler.h"
#include "lib/dispatch/dispatch_naming.h"
#include "lib/pubsub/pub_binding_st.h"
#include "lib/pubsub/pubsub_connect.h"
#include "lib/pubsub/pubsub_flags.h"
#include "lib/pubsub/pubsub_publish.h"

Go to the source code of this file.

Macros

#define DECLARE_MESSAGE_COMMON__(messagename, typename, c_type)
 
#define DECLARE_MESSAGE(messagename, typename, c_ptr_type)
 
#define DECLARE_MESSAGE_INT(messagename, typename, c_type)
 
#define DECLARE_PUBLISH(messagename)
 
#define DECLARE_SUBSCRIBE(messagename, hookfn)
 
#define DISPATCH__FAKE_USE_OF_PUBFN_(messagename)
 
#define DISPATCH_ADD_PUB_(connector, channel, messagename, flags)
 
#define DISPATCH_ADD_PUB(connector, channel, messagename)    DISPATCH_ADD_PUB_(connector, channel, messagename, 0)
 
#define DISPATCH_ADD_PUB_EXCL(connector, channel, messagename)    DISPATCH_ADD_PUB_(connector, channel, messagename, DISP_FLAG_EXCL)
 
#define DISPATCH_ADD_SUB_(connector, channel, messagename, flags)
 
#define DISPATCH_ADD_SUB(connector, channel, messagename)    DISPATCH_ADD_SUB_(connector, channel, messagename, 0)
 
#define DISPATCH_ADD_SUB_EXCL(connector, channel, messagename)    DISPATCH_ADD_SUB_(connector, channel, messagename, DISP_FLAG_EXCL)
 
#define PUBLISH(messagename, arg)    publish_fn__ ##messagename(arg)
 
#define DISPATCH_REGISTER_TYPE(con, type, fns)
 

Detailed Description

Macros to help with the publish/subscribe dispatch API.

The dispatch API allows different subsystems of Tor to communicate with another asynchronously via a shared "message" system. Some subsystems declare that they publish a given message, and others declare that they subscribe to it. Both subsystems depend on the message, but not upon one another.

To declare a message, use DECLARE_MESSAGE() (for messages that take their data as a pointer) or DECLARE_MESSAGE_INT() (for messages that take their data as an integer. For example, you might say

DECLARE_MESSAGE(new_circuit, circ, circuit_handle_t *);

or DECLARE_MESSAGE_INT(shutdown_requested, boolean, bool);

Every message has a unique name, a "type name" that the dispatch system uses to manage associated data, and a C type name. You'll want to put these declarations in a header, to be included by all publishers and all subscribers.

When a subsystem wants to publish a message, it uses DECLARE_PUBLISH() at file scope to create necessary static functions. Then, in its subsystem initialization (in the "bind to dispatcher" callback) (TODO: name this properly!), it calls DISPATCH_ADD_PUB() to tell the dispatcher about its intent to publish. When it actually wants to publish, it uses the PUBLISH() macro. For example:

// At file scope
DECLARE_PUBLISH(shutdown_requested);

static void bind_to_dispatcher(pubsub_connector_t *con)
{
    DISPATCH_ADD_PUB(con, mainchannel, shutdown_requested);
}

// somewhere in a function
   {
       PUBLISH(shutdown_requested, true);
   }

When a subsystem wants to subscribe to a message, it uses DECLARE_SUBSCRIBE() at file scope to declare static functions. It must declare a hook function that receives the message type. Then, in its "bind to dispatcher" function, it calls DISPATCHER_ADD_SUB() to tell the dispatcher about its intent to subscribe. When another module publishes the message, the dispatcher will call the provided hook function.

// At file scope.  The first argument is the message that you're
// subscribing to; the second argument is the hook function to declare.
DECLARE_SUBSCRIBE(shutdown_requested, on_shutdown_req_cb);

// You need to declare this function.
static void on_shutdown_req_cb(const msg_t *msg,
                               bool value)
{
    // (do something here.)
}

static void bind_to_dispatcher(pubsub_connector_t *con)
{
    DISPATCH_ADD_SUB(con, mainchannel, shutdown_requested);
}

Where did these types come from? Somewhere in the code, you need to call DISPATCH_REGISTER_TYPE() to make sure that the dispatcher can manage the message auxiliary data. It associates a vtbl-like structure with the type name, so that the dispatcher knows how to manipulate the type you're giving it.

For example, the "boolean" type we're using above could be defined as:

static char *boolean_fmt(msg_aux_data_t d) { // This is used for debugging and dumping messages. if (d.u64) return tor_strdup("true"); else return tor_strdup("false"); }

static void boolean_free(msg_aux_data_t d) { // We don't actually need to do anything to free a boolean. // We could use "NULL" instead of this function, but I'm including // it as an example. }

static void bind_to_dispatcher(pubsub_connector_t *con) { dispatch_typefns_t boolean_fns = { .fmt_fn = boolean_fmt, .free_fn = boolean_free, }; DISPATCH_REGISTER_TYPE(con, boolean, &boolean_fns); }

So, how does this all work? (You can stop reading here, unless you're debugging something.)

When you declare a message in a header with DECLARE_MESSAGE() or DECLARE_MESSAGE_INT(), it creates five things:

All of these declarations have names based on the message name.

Later, when you say DECLARE_PUBLISH() or DECLARE_SUBSCRIBE(), we use the elements defined by DECLARE_MESSAGE() to make sure that the publish function takes the correct argument type, and that the subscription hook is declared with the right argument type.

Definition in file pubsub_macros.h.

Macro Definition Documentation

◆ DECLARE_MESSAGE

#define DECLARE_MESSAGE (   messagename,
  typename,
  c_ptr_type 
)
Value:
DECLARE_MESSAGE_COMMON__(messagename, typename, c_ptr_type) \
ATTR_UNUSED static inline c_ptr_type \
msg_arg_get__ ##messagename(msg_aux_data_t m) \
{ \
return m.ptr; \
} \
ATTR_UNUSED static inline void \
msg_arg_set__ ##messagename(msg_aux_data_t *m, c_ptr_type v) \
{ \
m->ptr = v; \
} \
EAT_SEMICOLON
#define DECLARE_MESSAGE_COMMON__(messagename, typename, c_type)

Use this macro in a header to declare the existence of a given message, taking a pointer as auxiliary data.

"messagename" is a unique identifier for the message; it must be a valid C identifier.

"typename" is a unique identifier for the type of the auxiliary data. It needs to be defined somewhere in Tor, using "DISPATCH_REGISTER_TYPE."

"c_ptr_type" is a C pointer type (like "char *" or "struct foo *"). The "*" needs to be included.

Definition at line 192 of file pubsub_macros.h.

◆ DECLARE_MESSAGE_COMMON__

#define DECLARE_MESSAGE_COMMON__ (   messagename,
  typename,
  c_type 
)
Value:
typedef c_type msg_arg_type__ ##messagename; \
typedef const c_type msg_arg_consttype__ ##messagename; \
ATTR_UNUSED static const char msg_arg_name__ ##messagename[] = # typename;

Macro to declare common elements shared by DECLARE_MESSAGE and DECLARE_MESSAGE_INT. Don't call this directly.

Note that the "msg_arg_name" string constant is defined in each translation unit. This might be undesirable; we can tweak it in the future if need be.

Definition at line 173 of file pubsub_macros.h.

◆ DECLARE_MESSAGE_INT

#define DECLARE_MESSAGE_INT (   messagename,
  typename,
  c_type 
)
Value:
DECLARE_MESSAGE_COMMON__(messagename, typename, c_type) \
ATTR_UNUSED static inline c_type \
msg_arg_get__ ##messagename(msg_aux_data_t m) \
{ \
return (c_type)m.u64; \
} \
ATTR_UNUSED static inline void \
msg_arg_set__ ##messagename(msg_aux_data_t *m, c_type v) \
{ \
m->u64 = (uint64_t)v; \
} \
EAT_SEMICOLON

Use this macro in a header to declare the existence of a given message, taking an integer as auxiliary data.

"messagename" is a unique identifier for the message; it must be a valid C identifier.

"typename" is a unique identifier for the type of the auxiliary data. It needs to be defined somewhere in Tor, using "DISPATCH_REGISTER_TYPE."

"c_type" is a C integer type, like "int" or "bool". It needs to fit inside a uint64_t.

Definition at line 219 of file pubsub_macros.h.

◆ DECLARE_PUBLISH

#define DECLARE_PUBLISH (   messagename)
Value:
static pub_binding_t pub_binding__ ##messagename; \
static void \
publish_fn__ ##messagename(msg_arg_type__ ##messagename arg) \
{ \
msg_aux_data_t data; \
msg_arg_set__ ##messagename(&data, arg); \
pubsub_pub_(&pub_binding__ ##messagename, data); \
} \
EAT_SEMICOLON

Use this macro inside a C module declare that we'll be publishing a given message type from within this module.

It creates necessary functions and wrappers to publish a message whose unique identifier is "messagename".

Before you use this, you need to include the header where DECLARE_MESSAGE*() was used for this message.

You can only use this once per message in each subsystem.

Definition at line 245 of file pubsub_macros.h.

◆ DECLARE_SUBSCRIBE

#define DECLARE_SUBSCRIBE (   messagename,
  hookfn 
)
Value:
static void hookfn(const msg_t *, \
const msg_arg_consttype__ ##messagename); \
static void recv_fn__ ## messagename(const msg_t *m) \
{ \
msg_arg_type__ ## messagename arg; \
arg = msg_arg_get__ ##messagename(m->aux_data__); \
hookfn(m, arg); \
} \
EAT_SEMICOLON
Definition: msgtypes.h:50

Use this macro inside a C file to declare that we're subscribing to a given message and associating it with a given "hook function". It declares the hook function static, and helps with strong typing.

Before you use this, you need to include the header where DECLARE_MESSAGE*() was used for the message whose unique identifier is "messagename".

You will need to define a function with the name that you provide for "hookfn". The type of this function will be: static void hookfn(const msg_t *, const c_type) where c_type is the c type that you declared in the header.

You can only use this once per message in each subsystem.

Definition at line 272 of file pubsub_macros.h.

◆ DISPATCH__FAKE_USE_OF_PUBFN_

#define DISPATCH__FAKE_USE_OF_PUBFN_ (   messagename)
Value:
( 0 ? (publish_fn__ ##messagename((msg_arg_type__##messagename)0), 1) \
: 1)

Add a fake use of the publish function for 'messagename', so that the compiler does not call it unused.

Definition at line 287 of file pubsub_macros.h.

◆ DISPATCH_ADD_PUB

#define DISPATCH_ADD_PUB (   connector,
  channel,
  messagename 
)     DISPATCH_ADD_PUB_(connector, channel, messagename, 0)

Use a given connector and channel name to declare that this subsystem will publish a given message type.

Call this macro from within the add_subscriptions() function of a module.

Definition at line 313 of file pubsub_macros.h.

◆ DISPATCH_ADD_PUB_

#define DISPATCH_ADD_PUB_ (   connector,
  channel,
  messagename,
  flags 
)
Value:
( \
DISPATCH__FAKE_USE_OF_PUBFN_(messagename), \
pubsub_add_pub_((connector), \
&pub_binding__ ##messagename, \
get_channel_id(# channel), \
get_message_id(# messagename), \
get_msg_type_id(msg_arg_name__ ## messagename), \
(flags), \
__FILE__, \
__LINE__) \
)
channel_id_t get_channel_id(const char *)

This macro is for internal use. It backs DISPATCH_ADD_PUB*()

Definition at line 294 of file pubsub_macros.h.

◆ DISPATCH_ADD_PUB_EXCL

#define DISPATCH_ADD_PUB_EXCL (   connector,
  channel,
  messagename 
)     DISPATCH_ADD_PUB_(connector, channel, messagename, DISP_FLAG_EXCL)

Use a given connector and channel name to declare that this subsystem will publish a given message type, and that no other subsystem is allowed to.

Call this macro from within the add_subscriptions() function of a module.

Definition at line 322 of file pubsub_macros.h.

◆ DISPATCH_ADD_SUB

#define DISPATCH_ADD_SUB (   connector,
  channel,
  messagename 
)     DISPATCH_ADD_SUB_(connector, channel, messagename, 0)

Use a given connector and channel name to declare that this subsystem will receive a given message type.

Call this macro from within the add_subscriptions() function of a module.

Definition at line 343 of file pubsub_macros.h.

◆ DISPATCH_ADD_SUB_

#define DISPATCH_ADD_SUB_ (   connector,
  channel,
  messagename,
  flags 
)
Value:
pubsub_add_sub_((connector), \
recv_fn__ ##messagename, \
get_channel_id(#channel), \
get_message_id(# messagename), \
get_msg_type_id(msg_arg_name__ ##messagename), \
(flags), \
__FILE__, \
__LINE__)
int pubsub_add_sub_(pubsub_connector_t *con, recv_fn_t recv_fn, channel_id_t channel, message_id_t msg, msg_type_id_t type, unsigned flags, const char *file, unsigned line)
Definition: pubsub_build.c:171

This macro is for internal use. It backs DISPATCH_ADD_SUB*()

Definition at line 328 of file pubsub_macros.h.

◆ DISPATCH_ADD_SUB_EXCL

#define DISPATCH_ADD_SUB_EXCL (   connector,
  channel,
  messagename 
)     DISPATCH_ADD_SUB_(connector, channel, messagename, DISP_FLAG_EXCL)

Use a given connector and channel name to declare that this subsystem will receive a given message type, and that no other subsystem is allowed to do so.

Call this macro from within the add_subscriptions() function of a module.

Definition at line 352 of file pubsub_macros.h.

◆ DISPATCH_REGISTER_TYPE

#define DISPATCH_REGISTER_TYPE (   con,
  type,
  fns 
)
Value:
get_msg_type_id(#type), \
(fns), \
__FILE__, \
__LINE__)
int pubsub_connector_register_type_(pubsub_connector_t *con, msg_type_id_t type, dispatch_typefns_t *fns, const char *file, unsigned line)
Definition: pubsub_build.c:216

Use a given connector to declare that the functions to be used to manipuate a certain C type.

Definition at line 366 of file pubsub_macros.h.

◆ PUBLISH

#define PUBLISH (   messagename,
  arg 
)     publish_fn__ ##messagename(arg)

Publish a given message with a given argument. (Takes ownership of the argument if it is a pointer.)

Definition at line 359 of file pubsub_macros.h.