aboutsummaryrefslogtreecommitdiff
path: root/src/or/control.c
diff options
context:
space:
mode:
authorNick Mathewson <nickm@torproject.org>2015-08-12 10:49:19 -0400
committerNick Mathewson <nickm@torproject.org>2015-08-18 08:56:23 -0400
commit9ec94f1d22a87fbf86f721c6106f78f85b8be33c (patch)
tree9f2e36dad0208158c77be8a986e49973a4401988 /src/or/control.c
parente2a6a7ec6178834c3de7a3be614679120e2c00c8 (diff)
downloadtor-9ec94f1d22a87fbf86f721c6106f78f85b8be33c.tar.gz
tor-9ec94f1d22a87fbf86f721c6106f78f85b8be33c.zip
Use thread-local storage to block event_queue recursion.
Diffstat (limited to 'src/or/control.c')
-rw-r--r--src/or/control.c47
1 files changed, 29 insertions, 18 deletions
diff --git a/src/or/control.c b/src/or/control.c
index 2be99d5d7a..c80546529e 100644
--- a/src/or/control.c
+++ b/src/or/control.c
@@ -594,9 +594,9 @@ typedef struct queued_event_s {
char *msg;
} queued_event_t;
-/** If this is greater than 0, we don't allow new events to be queued.
- * XXXX This should be thread-local. */
-static int block_event_queue = 0;
+/** Pointer to int. If this is greater than 0, we don't allow new events to be
+ * queued. */
+static tor_threadlocal_t block_event_queue;
/** Holds a smartlist of queued_event_t objects that may need to be sent
* to one or more controllers */
@@ -631,9 +631,21 @@ control_initialize_event_queue(void)
if (queued_control_events_lock == NULL) {
queued_control_events_lock = tor_mutex_new();
+ tor_threadlocal_init(&block_event_queue);
}
}
+static int *
+get_block_event_queue(void)
+{
+ int *val = tor_threadlocal_get(&block_event_queue);
+ if (PREDICT_UNLIKELY(val == NULL)) {
+ val = tor_malloc_zero(sizeof(int));
+ tor_threadlocal_set(&block_event_queue, val);
+ }
+ return val;
+}
+
/** Helper: inserts an event on the list of events queued to be sent to
* one or more controllers, and schedules the events to be flushed if needed.
*
@@ -655,21 +667,20 @@ queue_control_event_string,(uint16_t event, char *msg))
return;
}
- queued_event_t *ev = tor_malloc(sizeof(*ev));
- ev->event = event;
- ev->msg = msg;
-
- tor_mutex_acquire(queued_control_events_lock);
- if (block_event_queue) { /* XXXX This should be thread-specific. */
- tor_mutex_release(queued_control_events_lock);
+ int *block_event_queue = get_block_event_queue();
+ if (*block_event_queue) {
tor_free(msg);
- tor_free(ev);
return;
}
+ queued_event_t *ev = tor_malloc(sizeof(*ev));
+ ev->event = event;
+ ev->msg = msg;
+
/* No queueing an event while queueing an event */
- ++block_event_queue;
+ ++*block_event_queue;
+ tor_mutex_acquire(queued_control_events_lock);
tor_assert(queued_control_events);
smartlist_add(queued_control_events, ev);
@@ -679,10 +690,10 @@ queue_control_event_string,(uint16_t event, char *msg))
flush_queued_event_pending = 1;
}
- --block_event_queue;
-
tor_mutex_release(queued_control_events_lock);
+ --*block_event_queue;
+
/* We just put an event on the queue; mark the queue to be
* flushed. We only do this from the main thread for now; otherwise,
* we'd need to incur locking overhead in Libevent or use a socket.
@@ -718,9 +729,11 @@ queued_events_flush_all(int force)
smartlist_t *controllers = smartlist_new();
smartlist_t *queued_events;
+ int *block_event_queue = get_block_event_queue();
+ ++*block_event_queue;
+
tor_mutex_acquire(queued_control_events_lock);
/* No queueing an event while flushing events. */
- ++block_event_queue;
flush_queued_event_pending = 0;
queued_events = queued_control_events;
queued_control_events = smartlist_new();
@@ -760,9 +773,7 @@ queued_events_flush_all(int force)
smartlist_free(queued_events);
smartlist_free(controllers);
- tor_mutex_acquire(queued_control_events_lock);
- --block_event_queue;
- tor_mutex_release(queued_control_events_lock);
+ --*block_event_queue;
}
/** Libevent callback: Flushes pending events to controllers that are