2017-03-15 21:13:17 +01:00
|
|
|
/* Copyright (c) 2016-2017, The Tor Project, Inc. */
|
2016-03-24 16:15:19 +01:00
|
|
|
/* See LICENSE for licensing information */
|
|
|
|
|
|
|
|
/**
|
|
|
|
* \file pubsub.c
|
|
|
|
*
|
|
|
|
* \brief DOCDOC
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include "orconfig.h"
|
|
|
|
#include "pubsub.h"
|
|
|
|
#include "container.h"
|
|
|
|
|
|
|
|
/** Helper: insert <b>s</b> into <b>topic's</b> list of subscribers, keeping
|
|
|
|
* them sorted in priority order. */
|
|
|
|
static void
|
|
|
|
subscriber_insert(pubsub_topic_t *topic, pubsub_subscriber_t *s)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
smartlist_t *sl = topic->subscribers;
|
|
|
|
for (i = 0; i < smartlist_len(sl); ++i) {
|
|
|
|
pubsub_subscriber_t *other = smartlist_get(sl, i);
|
|
|
|
if (s->priority < other->priority) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
smartlist_insert(sl, i, s);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Add a new subscriber to <b>topic</b>, where (when an event is triggered),
|
|
|
|
* we'll notify the function <b>fn</b> by passing it <b>subscriber_data</b>.
|
|
|
|
* Return a handle to the subscribe which can later be passed to
|
|
|
|
* pubsub_unsubscribe_().
|
|
|
|
*
|
|
|
|
* Functions are called in priority order, from lowest to highest.
|
|
|
|
*
|
|
|
|
* See pubsub.h for <b>subscribe_flags</b>.
|
|
|
|
*/
|
|
|
|
const pubsub_subscriber_t *
|
|
|
|
pubsub_subscribe_(pubsub_topic_t *topic,
|
|
|
|
pubsub_subscriber_fn_t fn,
|
|
|
|
void *subscriber_data,
|
|
|
|
unsigned subscribe_flags,
|
|
|
|
unsigned priority)
|
|
|
|
{
|
|
|
|
tor_assert(! topic->locked);
|
|
|
|
if (subscribe_flags & SUBSCRIBE_ATSTART) {
|
|
|
|
tor_assert(topic->n_events_fired == 0);
|
|
|
|
}
|
2016-05-12 15:56:42 +02:00
|
|
|
pubsub_subscriber_t *r = tor_malloc_zero(sizeof(*r));
|
2016-03-24 16:15:19 +01:00
|
|
|
r->priority = priority;
|
|
|
|
r->subscriber_flags = subscribe_flags;
|
|
|
|
r->fn = fn;
|
|
|
|
r->subscriber_data = subscriber_data;
|
|
|
|
if (topic->subscribers == NULL) {
|
|
|
|
topic->subscribers = smartlist_new();
|
|
|
|
}
|
|
|
|
subscriber_insert(topic, r);
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Remove the subscriber <b>s</b> from <b>topic</b>. After calling this
|
|
|
|
* function, <b>s</b> may no longer be used.
|
|
|
|
*/
|
|
|
|
int
|
|
|
|
pubsub_unsubscribe_(pubsub_topic_t *topic,
|
|
|
|
const pubsub_subscriber_t *s)
|
|
|
|
{
|
|
|
|
tor_assert(! topic->locked);
|
|
|
|
smartlist_t *sl = topic->subscribers;
|
|
|
|
if (sl == NULL)
|
|
|
|
return -1;
|
|
|
|
int i = smartlist_pos(sl, s);
|
|
|
|
if (i == -1)
|
|
|
|
return -1;
|
|
|
|
pubsub_subscriber_t *tmp = smartlist_get(sl, i);
|
|
|
|
tor_assert(tmp == s);
|
|
|
|
smartlist_del_keeporder(sl, i);
|
|
|
|
tor_free(tmp);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* For every subscriber s in <b>topic</b>, invoke notify_fn on s and
|
|
|
|
* event_data. Return 0 if there were no nonzero return values, and -1 if
|
|
|
|
* there were any.
|
|
|
|
*/
|
|
|
|
int
|
|
|
|
pubsub_notify_(pubsub_topic_t *topic, pubsub_notify_fn_t notify_fn,
|
|
|
|
void *event_data, unsigned notify_flags)
|
|
|
|
{
|
|
|
|
tor_assert(! topic->locked);
|
|
|
|
(void) notify_flags;
|
|
|
|
smartlist_t *sl = topic->subscribers;
|
|
|
|
int n_bad = 0;
|
|
|
|
++topic->n_events_fired;
|
|
|
|
if (sl == NULL)
|
|
|
|
return -1;
|
|
|
|
topic->locked = 1;
|
|
|
|
SMARTLIST_FOREACH_BEGIN(sl, pubsub_subscriber_t *, s) {
|
|
|
|
int r = notify_fn(s, event_data);
|
|
|
|
if (r != 0)
|
|
|
|
++n_bad;
|
|
|
|
} SMARTLIST_FOREACH_END(s);
|
|
|
|
topic->locked = 0;
|
|
|
|
return (n_bad == 0) ? 0 : -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Release all storage held by <b>topic</b>.
|
|
|
|
*/
|
|
|
|
void
|
|
|
|
pubsub_clear_(pubsub_topic_t *topic)
|
|
|
|
{
|
|
|
|
tor_assert(! topic->locked);
|
|
|
|
|
|
|
|
smartlist_t *sl = topic->subscribers;
|
|
|
|
if (sl == NULL)
|
|
|
|
return;
|
|
|
|
SMARTLIST_FOREACH_BEGIN(sl, pubsub_subscriber_t *, s) {
|
|
|
|
tor_free(s);
|
|
|
|
} SMARTLIST_FOREACH_END(s);
|
|
|
|
smartlist_free(sl);
|
|
|
|
topic->subscribers = NULL;
|
|
|
|
topic->n_events_fired = 0;
|
|
|
|
}
|
|
|
|
|