mirror of
git://sourceware.org/git/newlib-cygwin.git
synced 2025-03-02 04:55:35 +08:00
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.
This commit is contained in:
parent
b7c9ab1af6
commit
73e3ff9328
@ -34,3 +34,6 @@ Bug Fixes
|
|||||||
- Define missing MSG_EOR. It's unsupported by the underlying Winsock
|
- Define missing MSG_EOR. It's unsupported by the underlying Winsock
|
||||||
layer so using it in send(2), sendto(2), or sendmsg(2) will return -1
|
layer so using it in send(2), sendto(2), or sendmsg(2) will return -1
|
||||||
with errno set to EOPNOTSUPP and recvmsg(2) will never return it.
|
with errno set to EOPNOTSUPP and recvmsg(2) will never return it.
|
||||||
|
|
||||||
|
- Fix a race condition in the timerfd code.
|
||||||
|
Addresses: https://cygwin.com/ml/cygwin/2019-06/msg00096.html
|
||||||
|
@ -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
|
DWORD
|
||||||
timerfd_tracker::thread_func ()
|
timerfd_tracker::thread_func ()
|
||||||
{
|
{
|
||||||
@ -137,7 +156,10 @@ timerfd_tracker::thread_func ()
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!enter_critical_section ())
|
int ec = enter_critical_section_cancelable ();
|
||||||
|
if (ec < 0)
|
||||||
|
goto canceled;
|
||||||
|
else if (!ec)
|
||||||
continue;
|
continue;
|
||||||
/* Make sure we haven't been abandoned and/or disarmed
|
/* Make sure we haven't been abandoned and/or disarmed
|
||||||
in the meantime */
|
in the meantime */
|
||||||
|
@ -86,6 +86,8 @@ class timerfd_tracker /* cygheap! */
|
|||||||
return (WaitForSingleObject (_access_mtx, INFINITE) & ~WAIT_ABANDONED_0)
|
return (WaitForSingleObject (_access_mtx, INFINITE) & ~WAIT_ABANDONED_0)
|
||||||
== WAIT_OBJECT_0;
|
== WAIT_OBJECT_0;
|
||||||
}
|
}
|
||||||
|
/* A version that honors a cancel event, for use in thread_func. */
|
||||||
|
int enter_critical_section_cancelable ();
|
||||||
void leave_critical_section ()
|
void leave_critical_section ()
|
||||||
{
|
{
|
||||||
ReleaseMutex (_access_mtx);
|
ReleaseMutex (_access_mtx);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user