diff options
author | Dan Rosen <mergeconflict@google.com> | 2019-04-17 15:44:59 -0400 |
---|---|---|
committer | Dan Rosen <mergeconflict@google.com> | 2019-04-17 15:52:05 -0400 |
commit | 1cd8830de27c30c5324c75bfb6012c969c09ca2c (patch) | |
tree | a82a9312f1eb03794f3830b498ddabe4eebef40c /event.c | |
parent | 04563d59d25404d10cda32c78831bdb3f6cf4c0c (diff) | |
download | libevent-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.c | 14 |
1 files changed, 8 insertions, 6 deletions
@@ -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); |