From 4f0f40e31e58677f3e05af64f1412d7a1a8d03d1 Mon Sep 17 00:00:00 2001 From: Azat Khuzhin Date: Tue, 27 Feb 2018 21:12:14 +0300 Subject: [PATCH] Fix base unlocking in event_del() if event_base_set() runned in another thread Image next situation: T1: T2: event_del_() lock the event.ev_base.th_base_lock event_del_nolock_() event_set_base() unlock the event.ev_base.th_base_lock In this case we will unlock the wrong base after event_del_nolock_() returns, and deadlock is likely to happens, since event_base_set() do not check any mutexes (due to it is possible to do this only if event is not inserted anywhere). So event_del_() has to cache the base before removing the event, and cached base.th_base_lock after. (cherry picked from commit 08a0d366073eacf800027725891c2f668f2f0144) --- event.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/event.c b/event.c index 17570c27..c5560707 100644 --- a/event.c +++ b/event.c @@ -2749,17 +2749,16 @@ static int event_del_(struct event *ev, int blocking) { int res; + struct event_base *base = ev->ev_base; - if (EVUTIL_FAILURE_CHECK(!ev->ev_base)) { + if (EVUTIL_FAILURE_CHECK(!base)) { event_warnx("%s: event has no event_base set.", __func__); return -1; } - EVBASE_ACQUIRE_LOCK(ev->ev_base, th_base_lock); - + EVBASE_ACQUIRE_LOCK(base, th_base_lock); res = event_del_nolock_(ev, blocking); - - EVBASE_RELEASE_LOCK(ev->ev_base, th_base_lock); + EVBASE_RELEASE_LOCK(base, th_base_lock); return (res); } -- 2.50.1