diff options
author | Ken Brown <kbrown@cornell.edu> | 2019-06-24 19:28:48 +0300 |
---|---|---|
committer | Ken Brown <kbrown@cornell.edu> | 2019-06-25 22:44:43 +0300 |
commit | 9604a251bdeb3ae4a4c958efc14b4694d7324d11 (patch) | |
tree | 20cebca7872d3445afd57f7dd74f3fdafe63eeca /winsup/cygwin/timerfd.cc | |
parent | a90aa583fbe7898a7a2699ee380de7783b6e8ed4 (diff) |
Cygwin: timerfd: avoid a deadlock
Add a function timerfd_tracker::enter_critical_section_cancelable,
which is like enter_critical_section but honors a cancel event. Call
this when a timer expires while the timerfd thread is in its inner
loop. This avoids a deadlock if timerfd_tracker::dtor has entered its
critical section and is trying to cancel the thread. See
https://cygwin.com/ml/cygwin/2019-06/msg00096.html.
Diffstat (limited to 'winsup/cygwin/timerfd.cc')
-rw-r--r-- | winsup/cygwin/timerfd.cc | 24 |
1 files changed, 23 insertions, 1 deletions
diff --git a/winsup/cygwin/timerfd.cc b/winsup/cygwin/timerfd.cc index 8e4c94e66..f1a4c2804 100644 --- a/winsup/cygwin/timerfd.cc +++ b/winsup/cygwin/timerfd.cc @@ -89,6 +89,25 @@ timerfd_tracker::handle_timechange_window () } } +/* Like enter_critical_section, but returns -1 on a cancel event. */ +int +timerfd_tracker::enter_critical_section_cancelable () +{ + HANDLE w[2] = { cancel_evt, _access_mtx }; + DWORD waitret = WaitForMultipleObjects (2, w, FALSE, INFINITE); + + switch (waitret) + { + case WAIT_OBJECT_0: + return -1; + case WAIT_OBJECT_0 + 1: + case WAIT_ABANDONED_0 + 1: + return 1; + default: + return 0; + } +} + DWORD timerfd_tracker::thread_func () { @@ -137,7 +156,10 @@ timerfd_tracker::thread_func () continue; } - if (!enter_critical_section ()) + int ec = enter_critical_section_cancelable (); + if (ec < 0) + goto canceled; + else if (!ec) continue; /* Make sure we haven't been abandoned and/or disarmed in the meantime */ |