|
@@ -12,25 +12,22 @@
|
|
|
/* How a subscribed listener wants to receive an event. */
|
|
|
typedef struct event_subscription_t {
|
|
|
event_listener_t *listener;
|
|
|
- bool send_full_event;
|
|
|
} event_subscription_t;
|
|
|
|
|
|
/* What a listener should do if it receives an event. */
|
|
|
typedef struct event_callback_t {
|
|
|
- bool edge_triggered;
|
|
|
- bool is_edge_pending;
|
|
|
- void (*process_event_fn)(event_label_t, event_data_t, void *);
|
|
|
+ event_update_fn_t update_fn;
|
|
|
+ process_event_fn_t process_event_fn;
|
|
|
} event_callback_t;
|
|
|
|
|
|
/**************************/
|
|
|
|
|
|
static event_subscription_t *
|
|
|
-event_subscription_new(event_listener_t *listener, bool send_full_event)
|
|
|
+event_subscription_new(event_listener_t *listener)
|
|
|
{
|
|
|
tor_assert(listener != NULL);
|
|
|
event_subscription_t *sub = tor_malloc_zero(sizeof(event_subscription_t));
|
|
|
sub->listener = listener;
|
|
|
- sub->send_full_event = send_full_event;
|
|
|
return sub;
|
|
|
}
|
|
|
|
|
@@ -45,13 +42,12 @@ event_subscription_free(event_subscription_t *sub)
|
|
|
/**************************/
|
|
|
|
|
|
static event_callback_t *
|
|
|
-event_callback_new(bool edge_triggered,
|
|
|
- void (*process_event_fn)(event_label_t, event_data_t, void *))
|
|
|
+event_callback_new(event_update_fn_t update_fn,
|
|
|
+ process_event_fn_t process_event_fn)
|
|
|
{
|
|
|
tor_assert(process_event_fn != NULL);
|
|
|
event_callback_t *cb = tor_malloc_zero(sizeof(event_callback_t));
|
|
|
- cb->edge_triggered = edge_triggered;
|
|
|
- cb->is_edge_pending = false;
|
|
|
+ cb->update_fn = update_fn;
|
|
|
cb->process_event_fn = process_event_fn;
|
|
|
return cb;
|
|
|
}
|
|
@@ -253,10 +249,8 @@ event_listener_detach(event_listener_t *listener)
|
|
|
|
|
|
void
|
|
|
event_listener_set_callback(event_listener_t *listener, event_label_t label,
|
|
|
- bool edge_triggered,
|
|
|
- void (*process_event_fn)(event_label_t,
|
|
|
- event_data_t,
|
|
|
- void *))
|
|
|
+ event_update_fn_t update_fn,
|
|
|
+ process_event_fn_t process_event_fn)
|
|
|
{
|
|
|
tor_assert(listener != NULL);
|
|
|
tor_assert(label != EVENT_LABEL_UNSET);
|
|
@@ -265,7 +259,7 @@ event_listener_set_callback(event_listener_t *listener, event_label_t label,
|
|
|
int index = (int)label;
|
|
|
tor_assert(index >= 0);
|
|
|
|
|
|
- event_callback_t *cb = event_callback_new(edge_triggered, process_event_fn);
|
|
|
+ event_callback_t *cb = event_callback_new(update_fn, process_event_fn);
|
|
|
|
|
|
if (index >= 1000) {
|
|
|
log_warn(LD_BUG, "An event label was very large (%d), but the event "
|
|
@@ -322,10 +316,13 @@ event_listener_receive(event_listener_t *listener, event_label_t label,
|
|
|
return;
|
|
|
}
|
|
|
|
|
|
- if (cb->edge_triggered) {
|
|
|
- cb->is_edge_pending = true;
|
|
|
+ event_wrapper_t *last = TOR_TAILQ_LAST(&listener->pending_events,
|
|
|
+ pending_events_head_t);
|
|
|
+ if (cb->update_fn != NULL && last != NULL && last->label == label) {
|
|
|
+ // the last added event was of the same type and we set an update function,
|
|
|
+ // so we should update the last event rather than adding a new one
|
|
|
+ cb->update_fn(label, &last->data, &wrapper->data);
|
|
|
if (wrapper != NULL) {
|
|
|
- log_warn(LD_BUG, "An edge-triggered event received a full event");
|
|
|
event_wrapper_free(wrapper);
|
|
|
}
|
|
|
} else {
|
|
@@ -351,73 +348,34 @@ event_listener_process(event_listener_t *listener)
|
|
|
tor_mutex_acquire(&listener->lock);
|
|
|
|
|
|
void *context = listener->context;
|
|
|
- bool more_events = true;
|
|
|
-
|
|
|
- while (more_events) {
|
|
|
- // first process edge-triggered events
|
|
|
- event_data_t null_data = { .ptr = NULL };
|
|
|
- SMARTLIST_FOREACH_BEGIN(listener->callbacks, event_callback_t *, cb) {
|
|
|
- if (cb != NULL && cb->is_edge_pending) {
|
|
|
- void (*process_event_fn)(event_label_t, event_data_t, void *) = NULL;
|
|
|
- process_event_fn = cb->process_event_fn;
|
|
|
- event_label_t label = (int)cb_sl_idx;
|
|
|
- cb->is_edge_pending = false;
|
|
|
-
|
|
|
- tor_mutex_release(&listener->lock);
|
|
|
-
|
|
|
- if (PREDICT_LIKELY(process_event_fn != NULL)) {
|
|
|
- process_event_fn(label, null_data, context);
|
|
|
- // edge-triggered events don't have corresponding event data
|
|
|
- } else {
|
|
|
- // no callback available
|
|
|
- log_warn(LD_BUG, "An edge event was received but had no callback");
|
|
|
- }
|
|
|
-
|
|
|
- tor_mutex_acquire(&listener->lock);
|
|
|
- // while we were unlocked, the list may have changed length,
|
|
|
- // so we make sure it's correct
|
|
|
- cb_sl_len = smartlist_len(listener->callbacks);
|
|
|
- }
|
|
|
- } SMARTLIST_FOREACH_END(cb);
|
|
|
-
|
|
|
- // then process regular events
|
|
|
- while (!TOR_TAILQ_EMPTY(&listener->pending_events)) {
|
|
|
- event_wrapper_t *wrapper = TOR_TAILQ_FIRST(&listener->pending_events);
|
|
|
- TOR_TAILQ_REMOVE(&listener->pending_events, wrapper, next_event);
|
|
|
- tor_assert(wrapper != NULL);
|
|
|
-
|
|
|
- void (*process_event_fn)(event_label_t, event_data_t, void *) = NULL;
|
|
|
- int index = (int)wrapper->label;
|
|
|
-
|
|
|
- // do we have a callback for this event label?
|
|
|
- if (PREDICT_LIKELY(index < smartlist_len(listener->callbacks))) {
|
|
|
- event_callback_t *cb = smartlist_get(listener->callbacks, index);
|
|
|
- if (cb != NULL) {
|
|
|
- tor_assert(!cb->edge_triggered);
|
|
|
- process_event_fn = cb->process_event_fn;
|
|
|
- }
|
|
|
- }
|
|
|
|
|
|
- tor_mutex_release(&listener->lock);
|
|
|
+ while (!TOR_TAILQ_EMPTY(&listener->pending_events)) {
|
|
|
+ event_wrapper_t *wrapper = TOR_TAILQ_FIRST(&listener->pending_events);
|
|
|
+ TOR_TAILQ_REMOVE(&listener->pending_events, wrapper, next_event);
|
|
|
+ tor_assert(wrapper != NULL);
|
|
|
+
|
|
|
+ process_event_fn_t process_event_fn = NULL;
|
|
|
+ int index = (int)wrapper->label;
|
|
|
|
|
|
- if (PREDICT_LIKELY(process_event_fn != NULL)) {
|
|
|
- process_event_fn(wrapper->label, wrapper->data, context);
|
|
|
- } else {
|
|
|
- // no callback available
|
|
|
- log_warn(LD_BUG, "An event was received but had no callback");
|
|
|
+ // do we have a callback for this event label?
|
|
|
+ if (PREDICT_LIKELY(index < smartlist_len(listener->callbacks))) {
|
|
|
+ event_callback_t *cb = smartlist_get(listener->callbacks, index);
|
|
|
+ if (cb != NULL) {
|
|
|
+ process_event_fn = cb->process_event_fn;
|
|
|
}
|
|
|
+ }
|
|
|
|
|
|
- event_wrapper_free(wrapper);
|
|
|
- tor_mutex_acquire(&listener->lock);
|
|
|
+ tor_mutex_release(&listener->lock);
|
|
|
+
|
|
|
+ if (PREDICT_LIKELY(process_event_fn != NULL)) {
|
|
|
+ process_event_fn(wrapper->label, wrapper->data, context);
|
|
|
+ } else {
|
|
|
+ // no callback available
|
|
|
+ log_warn(LD_BUG, "An event was received but had no callback");
|
|
|
}
|
|
|
|
|
|
- // there's a possibility edge events have been added while running callbacks
|
|
|
- more_events = false;
|
|
|
- SMARTLIST_FOREACH_BEGIN(listener->callbacks, event_callback_t *, cb) {
|
|
|
- if (cb != NULL && cb->is_edge_pending) {
|
|
|
- more_events = true;
|
|
|
- }
|
|
|
- } SMARTLIST_FOREACH_END(cb);
|
|
|
+ event_wrapper_free(wrapper);
|
|
|
+ tor_mutex_acquire(&listener->lock);
|
|
|
}
|
|
|
|
|
|
listener->is_pending = false;
|
|
@@ -457,7 +415,7 @@ event_source_free(event_source_t *source)
|
|
|
|
|
|
void
|
|
|
event_source_subscribe(event_source_t *source, event_listener_t *listener,
|
|
|
- event_label_t label, bool send_full_event)
|
|
|
+ event_label_t label)
|
|
|
{
|
|
|
tor_assert(source != NULL);
|
|
|
tor_assert(listener != NULL);
|
|
@@ -475,7 +433,7 @@ event_source_subscribe(event_source_t *source, event_listener_t *listener,
|
|
|
inefficiently. */
|
|
|
}
|
|
|
|
|
|
- event_subscription_t *sub = event_subscription_new(listener, send_full_event);
|
|
|
+ event_subscription_t *sub = event_subscription_new(listener);
|
|
|
|
|
|
tor_mutex_acquire(&source->lock);
|
|
|
|
|
@@ -575,16 +533,7 @@ event_source_publish(event_source_t *source, event_label_t label,
|
|
|
}
|
|
|
|
|
|
event_wrapper_t *wrapper = NULL;
|
|
|
-
|
|
|
- if (sub->send_full_event) {
|
|
|
- wrapper = event_wrapper_new(label, data, free_data_fn);
|
|
|
- } else {
|
|
|
- // we don't need to send an event, so free the data now
|
|
|
- if (free_data_fn != NULL) {
|
|
|
- free_data_fn(data.ptr);
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
+ wrapper = event_wrapper_new(label, data, free_data_fn);
|
|
|
event_listener_receive(sub->listener, label, wrapper);
|
|
|
|
|
|
tor_mutex_release(&source->lock);
|