123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179 |
- /* Copyright (c) 2016-2017, The Tor Project, Inc. */
- /* See LICENSE for licensing information */
- /**
- * \file pubsub.h
- * \brief Macros to implement publish/subscribe abstractions.
- *
- * To use these macros, call DECLARE_PUBSUB_TOPIC() with an identifier to use
- * as your topic. Below, I'm going to assume you say DECLARE_PUBSUB_TOPIC(T).
- *
- * Doing this will declare the following types:
- * typedef struct T_event_data_t T_event_data_t; // you define this struct
- * typedef struct T_subscriber_data_t T_subscriber_data_t; // this one too.
- * typedef struct T_subscriber_t T_subscriber_t; // opaque
- * typedef int (*T_subscriber_fn_t)(T_event_data_t*, T_subscriber_data_t*);
- *
- * and it will declare the following functions:
- * const T_subscriber_t *T_subscribe(T_subscriber_fn_t,
- * T_subscriber_data_t *,
- * unsigned flags,
- * unsigned priority);
- * int T_unsubscribe(const T_subscriber_t *)
- *
- * Elsewhere you can say DECLARE_NOTIFY_PUBSUB_TOPIC(static, T), which
- * declares:
- *
- * static int T_notify(T_event_data_t *, unsigned notify_flags);
- * static void T_clear(void);
- *
- * And in some C file, you would define these functions with:
- * IMPLEMENT_PUBSUB_TOPIC(static, T).
- *
- * The implementations will be small typesafe wrappers over generic versions
- * of the above functions.
- *
- * To use the typesafe functions, you add any number of subscribers with
- * T_subscribe(). Each has an associated function pointer, data pointer,
- * and priority. Later, you can invoke T_notify() to declare that the
- * event has occurred. Each of the subscribers will be invoked once.
- **/
- #ifndef TOR_PUBSUB_H
- #define TOR_PUBSUB_H
- #include "torint.h"
- /**
- * Flag for T_subscribe: die with an assertion failure if the event
- * have ever been published before. Used when a subscriber must absolutely
- * never have missed an event.
- */
- #define SUBSCRIBE_ATSTART (1u<<0)
- #define DECLARE_PUBSUB_STRUCT_TYPES(name) \
- /* You define this type. */ \
- typedef struct name ## _event_data_t name ## _event_data_t; \
- /* You define this type. */ \
- typedef struct name ## _subscriber_data_t name ## _subscriber_data_t;
- #define DECLARE_PUBSUB_TOPIC(name) \
- /* This type is opaque. */ \
- typedef struct name ## _subscriber_t name ## _subscriber_t; \
- /* You declare functions matching this type. */ \
- typedef int (*name ## _subscriber_fn_t)( \
- name ## _event_data_t *data, \
- name ## _subscriber_data_t *extra); \
- /* Call this function to subscribe to a topic. */ \
- const name ## _subscriber_t *name ## _subscribe( \
- name##_subscriber_fn_t subscriber, \
- name##_subscriber_data_t *extra_data, \
- unsigned flags, \
- unsigned priority); \
- /* Call this function to unsubscribe from a topic. */ \
- int name ## _unsubscribe(const name##_subscriber_t *s);
- #define DECLARE_NOTIFY_PUBSUB_TOPIC(linkage, name) \
- /* Call this function to notify all subscribers. Flags not yet used. */ \
- linkage int name ## _notify(name ## _event_data_t *data, unsigned flags); \
- /* Call this function to release storage held by the topic. */ \
- linkage void name ## _clear(void);
- /**
- * Type used to hold a generic function for a subscriber.
- *
- * [Yes, it is safe to cast to this, so long as we cast back to the original
- * type before calling. From C99: "A pointer to a function of one type may be
- * converted to a pointer to a function of another type and back again; the
- * result shall compare equal to the original pointer."]
- */
- typedef int (*pubsub_subscriber_fn_t)(void *, void *);
- /**
- * Helper type to implement pubsub abstraction. Don't use this directly.
- * It represents a subscriber.
- */
- typedef struct pubsub_subscriber_t {
- /** Function to invoke when the event triggers. */
- pubsub_subscriber_fn_t fn;
- /** Data associated with this subscriber. */
- void *subscriber_data;
- /** Priority for this subscriber. Low priorities happen first. */
- unsigned priority;
- /** Flags set on this subscriber. Not yet used.*/
- unsigned subscriber_flags;
- } pubsub_subscriber_t;
- /**
- * Helper type to implement pubsub abstraction. Don't use this directly.
- * It represents a topic, and keeps a record of subscribers.
- */
- typedef struct pubsub_topic_t {
- /** List of subscribers to this topic. May be NULL. */
- struct smartlist_t *subscribers;
- /** Total number of times that pubsub_notify_() has ever been called on this
- * topic. */
- uint64_t n_events_fired;
- /** True iff we're running 'notify' on this topic, and shouldn't allow
- * any concurrent modifications or events. */
- unsigned locked;
- } pubsub_topic_t;
- const pubsub_subscriber_t *pubsub_subscribe_(pubsub_topic_t *topic,
- pubsub_subscriber_fn_t fn,
- void *subscriber_data,
- unsigned subscribe_flags,
- unsigned priority);
- int pubsub_unsubscribe_(pubsub_topic_t *topic, const pubsub_subscriber_t *sub);
- void pubsub_clear_(pubsub_topic_t *topic);
- typedef int (*pubsub_notify_fn_t)(pubsub_subscriber_t *subscriber,
- void *notify_data);
- int pubsub_notify_(pubsub_topic_t *topic, pubsub_notify_fn_t notify_fn,
- void *notify_data, unsigned notify_flags);
- #define IMPLEMENT_PUBSUB_TOPIC(notify_linkage, name) \
- static pubsub_topic_t name ## _topic_ = { NULL, 0, 0 }; \
- const name ## _subscriber_t * \
- name ## _subscribe(name##_subscriber_fn_t subscriber, \
- name##_subscriber_data_t *extra_data, \
- unsigned flags, \
- unsigned priority) \
- { \
- const pubsub_subscriber_t *s; \
- s = pubsub_subscribe_(&name##_topic_, \
- (pubsub_subscriber_fn_t)subscriber, \
- extra_data, \
- flags, \
- priority); \
- return (const name##_subscriber_t *)s; \
- } \
- int \
- name ## _unsubscribe(const name##_subscriber_t *subscriber) \
- { \
- return pubsub_unsubscribe_(&name##_topic_, \
- (const pubsub_subscriber_t *)subscriber); \
- } \
- static int \
- name##_call_the_notify_fn_(pubsub_subscriber_t *subscriber, \
- void *notify_data) \
- { \
- name ## _subscriber_fn_t fn; \
- fn = (name ## _subscriber_fn_t) subscriber->fn; \
- return fn(notify_data, subscriber->subscriber_data); \
- } \
- notify_linkage int \
- name ## _notify(name ## _event_data_t *event_data, unsigned flags) \
- { \
- return pubsub_notify_(&name##_topic_, \
- name##_call_the_notify_fn_, \
- event_data, \
- flags); \
- } \
- notify_linkage void \
- name ## _clear(void) \
- { \
- pubsub_clear_(&name##_topic_); \
- }
- #endif /* !defined(TOR_PUBSUB_H) */
|