summaryrefslogtreecommitdiff
path: root/event.c
diff options
context:
space:
mode:
authorDan Rosen <mergeconflict@google.com>2019-04-17 15:44:59 -0400
committerDan Rosen <mergeconflict@google.com>2019-04-17 15:52:05 -0400
commit1cd8830de27c30c5324c75bfb6012c969c09ca2c (patch)
treea82a9312f1eb03794f3830b498ddabe4eebef40c /event.c
parent04563d59d25404d10cda32c78831bdb3f6cf4c0c (diff)
downloadlibevent-1cd8830de27c30c5324c75bfb6012c969c09ca2c.tar.gz
evwatch: fix race condition
There was a race between event_base_loop and evwatch_new (adding a prepare/check watcher while iterating over the watcher list). Only release the mutex immediately before invoking each watcher callback, and reacquire it immediately afterwards (same as is done for normal event handlers).
Diffstat (limited to 'event.c')
-rw-r--r--event.c14
1 files changed, 8 insertions, 6 deletions
diff --git a/event.c b/event.c
index 34f28ba2..a82d5094 100644
--- a/event.c
+++ b/event.c
@@ -2006,11 +2006,12 @@ event_base_loop(struct event_base *base, int flags)
event_queue_make_later_events_active(base);
/* Invoke prepare watchers before polling for events */
- EVBASE_RELEASE_LOCK(base, th_base_lock);
prepare_info.timeout = tv_p;
- TAILQ_FOREACH(watcher, &base->watchers[EVWATCH_PREPARE], next)
+ TAILQ_FOREACH(watcher, &base->watchers[EVWATCH_PREPARE], next) {
+ EVBASE_RELEASE_LOCK(base, th_base_lock);
(*watcher->callback.prepare)(watcher, &prepare_info, watcher->arg);
- EVBASE_ACQUIRE_LOCK(base, th_base_lock);
+ EVBASE_ACQUIRE_LOCK(base, th_base_lock);
+ }
clear_time_cache(base);
@@ -2027,10 +2028,11 @@ event_base_loop(struct event_base *base, int flags)
/* Invoke check watchers after polling for events, and before
* processing them */
- EVBASE_RELEASE_LOCK(base, th_base_lock);
- TAILQ_FOREACH(watcher, &base->watchers[EVWATCH_CHECK], next)
+ TAILQ_FOREACH(watcher, &base->watchers[EVWATCH_CHECK], next) {
+ EVBASE_RELEASE_LOCK(base, th_base_lock);
(*watcher->callback.check)(watcher, &check_info, watcher->arg);
- EVBASE_ACQUIRE_LOCK(base, th_base_lock);
+ EVBASE_ACQUIRE_LOCK(base, th_base_lock);
+ }
timeout_process(base);