prop250: Initialize the SR subsystem and us it!
[tor.git] / src / common / pubsub.h
blobbbb4f02a42f00793319b304af5a22b46f3e26317
1 /* Copyright (c) 2016, The Tor Project, Inc. */
2 /* See LICENSE for licensing information */
4 /**
5 * \file pubsub.h
6 * \brief Macros to implement publish/subscribe abstractions.
8 * To use these macros, call DECLARE_PUBSUB_TOPIC() with an identifier to use
9 * as your topic. Below, I'm going to assume you say DECLARE_PUBSUB_TOPIC(T).
11 * Doing this will declare the following types:
12 * typedef struct T_event_data_t T_event_data_t; // you define this struct
13 * typedef struct T_subscriber_data_t T_subscriber_data_t; // this one too.
14 * typedef struct T_subscriber_t T_subscriber_t; // opaque
15 * typedef int (*T_subscriber_fn_t)(T_event_data_t*, T_subscriber_data_t*);
17 * and it will declare the following functions:
18 * const T_subscriber_t *T_subscribe(T_subscriber_fn_t,
19 * T_subscriber_data_t *,
20 * unsigned flags,
21 * unsigned priority);
22 * int T_unsubscribe(const T_subscriber_t *)
24 * Elsewhere you can say DECLARE_NOTIFY_PUBSUB_TOPIC(static, T), which
25 * declares:
27 * static int T_notify(T_event_data_t *, unsigned notify_flags);
28 * static void T_clear(void);
30 * And in some C file, you would define these functions with:
31 * IMPLEMENT_PUBSUB_TOPIC(static, T).
33 * The implementations will be small typesafe wrappers over generic versions
34 * of the above functions.
36 * To use the typesafe functions, you add any number of subscribers with
37 * T_subscribe(). Each has an associated function pointer, data pointer,
38 * and priority. Later, you can invoke T_notify() to declare that the
39 * event has occurred. Each of the subscribers will be invoked once.
40 **/
42 #ifndef TOR_PUBSUB_H
43 #define TOR_PUBSUB_H
45 #include "torint.h"
47 /**
48 * Flag for T_subscribe: die with an assertion failure if the event
49 * have ever been published before. Used when a subscriber must absolutely
50 * never have missed an event.
52 #define SUBSCRIBE_ATSTART (1u<<0)
54 #define DECLARE_PUBSUB_STRUCT_TYPES(name) \
55 /* You define this type. */ \
56 typedef struct name ## _event_data_t name ## _event_data_t; \
57 /* You define this type. */ \
58 typedef struct name ## _subscriber_data_t name ## _subscriber_data_t;
60 #define DECLARE_PUBSUB_TOPIC(name) \
61 /* This type is opaque. */ \
62 typedef struct name ## _subscriber_t name ## _subscriber_t; \
63 /* You declare functions matching this type. */ \
64 typedef int (*name ## _subscriber_fn_t)( \
65 name ## _event_data_t *data, \
66 name ## _subscriber_data_t *extra); \
67 /* Call this function to subscribe to a topic. */ \
68 const name ## _subscriber_t *name ## _subscribe( \
69 name##_subscriber_fn_t subscriber, \
70 name##_subscriber_data_t *extra_data, \
71 unsigned flags, \
72 unsigned priority); \
73 /* Call this function to unsubscribe from a topic. */ \
74 int name ## _unsubscribe(const name##_subscriber_t *s);
76 #define DECLARE_NOTIFY_PUBSUB_TOPIC(linkage, name) \
77 /* Call this function to notify all subscribers. Flags not yet used. */ \
78 linkage int name ## _notify(name ## _event_data_t *data, unsigned flags); \
79 /* Call this function to release storage held by the topic. */ \
80 linkage void name ## _clear(void);
82 /**
83 * Type used to hold a generic function for a subscriber.
85 * [Yes, it is safe to cast to this, so long as we cast back to the original
86 * type before calling. From C99: "A pointer to a function of one type may be
87 * converted to a pointer to a function of another type and back again; the
88 * result shall compare equal to the original pointer."]
90 typedef int (*pubsub_subscriber_fn_t)(void *, void *);
92 /**
93 * Helper type to implement pubsub abstraction. Don't use this directly.
94 * It represents a subscriber.
96 typedef struct pubsub_subscriber_t {
97 /** Function to invoke when the event triggers. */
98 pubsub_subscriber_fn_t fn;
99 /** Data associated with this subscriber. */
100 void *subscriber_data;
101 /** Priority for this subscriber. Low priorities happen first. */
102 unsigned priority;
103 /** Flags set on this subscriber. Not yet used.*/
104 unsigned subscriber_flags;
105 } pubsub_subscriber_t;
108 * Helper type to implement pubsub abstraction. Don't use this directly.
109 * It represents a topic, and keeps a record of subscribers.
111 typedef struct pubsub_topic_t {
112 /** List of subscribers to this topic. May be NULL. */
113 struct smartlist_t *subscribers;
114 /** Total number of times that pubsub_notify_() has ever been called on this
115 * topic. */
116 uint64_t n_events_fired;
117 /** True iff we're running 'notify' on this topic, and shouldn't allow
118 * any concurrent modifications or events. */
119 unsigned locked;
120 } pubsub_topic_t;
122 const pubsub_subscriber_t *pubsub_subscribe_(pubsub_topic_t *topic,
123 pubsub_subscriber_fn_t fn,
124 void *subscriber_data,
125 unsigned subscribe_flags,
126 unsigned priority);
127 int pubsub_unsubscribe_(pubsub_topic_t *topic, const pubsub_subscriber_t *sub);
128 void pubsub_clear_(pubsub_topic_t *topic);
129 typedef int (*pubsub_notify_fn_t)(pubsub_subscriber_t *subscriber,
130 void *notify_data);
131 int pubsub_notify_(pubsub_topic_t *topic, pubsub_notify_fn_t notify_fn,
132 void *notify_data, unsigned notify_flags);
134 #define IMPLEMENT_PUBSUB_TOPIC(notify_linkage, name) \
135 static pubsub_topic_t name ## _topic_ = { NULL, 0, 0 }; \
136 const name ## _subscriber_t * \
137 name ## _subscribe(name##_subscriber_fn_t subscriber, \
138 name##_subscriber_data_t *extra_data, \
139 unsigned flags, \
140 unsigned priority) \
142 const pubsub_subscriber_t *s; \
143 s = pubsub_subscribe_(&name##_topic_, \
144 (pubsub_subscriber_fn_t)subscriber, \
145 extra_data, \
146 flags, \
147 priority); \
148 return (const name##_subscriber_t *)s; \
150 int \
151 name ## _unsubscribe(const name##_subscriber_t *subscriber) \
153 return pubsub_unsubscribe_(&name##_topic_, \
154 (const pubsub_subscriber_t *)subscriber); \
156 static int \
157 name##_call_the_notify_fn_(pubsub_subscriber_t *subscriber, \
158 void *notify_data) \
160 name ## _subscriber_fn_t fn; \
161 fn = (name ## _subscriber_fn_t) subscriber->fn; \
162 return fn(notify_data, subscriber->subscriber_data); \
164 notify_linkage int \
165 name ## _notify(name ## _event_data_t *event_data, unsigned flags) \
167 return pubsub_notify_(&name##_topic_, \
168 name##_call_the_notify_fn_, \
169 event_data, \
170 flags); \
172 notify_linkage void \
173 name ## _clear(void) \
175 pubsub_clear_(&name##_topic_); \
178 #endif /* TOR_PUBSUB_H */