Fix pathbias interactions with entry guards
[tor.git] / src / common / pubsub.c
blobb3faf40e006200dc9d5c7b4b3fc807a391d92dcc
1 /* Copyright (c) 2016, The Tor Project, Inc. */
2 /* See LICENSE for licensing information */
4 /**
5 * \file pubsub.c
7 * \brief DOCDOC
8 */
10 #include "orconfig.h"
11 #include "pubsub.h"
12 #include "container.h"
14 /** Helper: insert <b>s</b> into <b>topic's</b> list of subscribers, keeping
15 * them sorted in priority order. */
16 static void
17 subscriber_insert(pubsub_topic_t *topic, pubsub_subscriber_t *s)
19 int i;
20 smartlist_t *sl = topic->subscribers;
21 for (i = 0; i < smartlist_len(sl); ++i) {
22 pubsub_subscriber_t *other = smartlist_get(sl, i);
23 if (s->priority < other->priority) {
24 break;
27 smartlist_insert(sl, i, s);
30 /**
31 * Add a new subscriber to <b>topic</b>, where (when an event is triggered),
32 * we'll notify the function <b>fn</b> by passing it <b>subscriber_data</b>.
33 * Return a handle to the subscribe which can later be passed to
34 * pubsub_unsubscribe_().
36 * Functions are called in priority order, from lowest to highest.
38 * See pubsub.h for <b>subscribe_flags</b>.
40 const pubsub_subscriber_t *
41 pubsub_subscribe_(pubsub_topic_t *topic,
42 pubsub_subscriber_fn_t fn,
43 void *subscriber_data,
44 unsigned subscribe_flags,
45 unsigned priority)
47 tor_assert(! topic->locked);
48 if (subscribe_flags & SUBSCRIBE_ATSTART) {
49 tor_assert(topic->n_events_fired == 0);
51 pubsub_subscriber_t *r = tor_malloc_zero(sizeof(*r));
52 r->priority = priority;
53 r->subscriber_flags = subscribe_flags;
54 r->fn = fn;
55 r->subscriber_data = subscriber_data;
56 if (topic->subscribers == NULL) {
57 topic->subscribers = smartlist_new();
59 subscriber_insert(topic, r);
60 return r;
63 /**
64 * Remove the subscriber <b>s</b> from <b>topic</b>. After calling this
65 * function, <b>s</b> may no longer be used.
67 int
68 pubsub_unsubscribe_(pubsub_topic_t *topic,
69 const pubsub_subscriber_t *s)
71 tor_assert(! topic->locked);
72 smartlist_t *sl = topic->subscribers;
73 if (sl == NULL)
74 return -1;
75 int i = smartlist_pos(sl, s);
76 if (i == -1)
77 return -1;
78 pubsub_subscriber_t *tmp = smartlist_get(sl, i);
79 tor_assert(tmp == s);
80 smartlist_del_keeporder(sl, i);
81 tor_free(tmp);
82 return 0;
85 /**
86 * For every subscriber s in <b>topic</b>, invoke notify_fn on s and
87 * event_data. Return 0 if there were no nonzero return values, and -1 if
88 * there were any.
90 int
91 pubsub_notify_(pubsub_topic_t *topic, pubsub_notify_fn_t notify_fn,
92 void *event_data, unsigned notify_flags)
94 tor_assert(! topic->locked);
95 (void) notify_flags;
96 smartlist_t *sl = topic->subscribers;
97 int n_bad = 0;
98 ++topic->n_events_fired;
99 if (sl == NULL)
100 return -1;
101 topic->locked = 1;
102 SMARTLIST_FOREACH_BEGIN(sl, pubsub_subscriber_t *, s) {
103 int r = notify_fn(s, event_data);
104 if (r != 0)
105 ++n_bad;
106 } SMARTLIST_FOREACH_END(s);
107 topic->locked = 0;
108 return (n_bad == 0) ? 0 : -1;
112 * Release all storage held by <b>topic</b>.
114 void
115 pubsub_clear_(pubsub_topic_t *topic)
117 tor_assert(! topic->locked);
119 smartlist_t *sl = topic->subscribers;
120 if (sl == NULL)
121 return;
122 SMARTLIST_FOREACH_BEGIN(sl, pubsub_subscriber_t *, s) {
123 tor_free(s);
124 } SMARTLIST_FOREACH_END(s);
125 smartlist_free(sl);
126 topic->subscribers = NULL;
127 topic->n_events_fired = 0;