To allow cygwait() to be called in the signal handler, a locally created timer is used instead of _cygtls::locals.cw_timer if it is in use.
Co-Authored-By: Corinna Vinschen <cori...@vinschen.de> Signed-off-by: Takashi Yano <takashi.y...@nifty.ne.jp> --- winsup/cygwin/cygtls.cc | 2 ++ winsup/cygwin/cygwait.cc | 23 ++++++++++++++++------- winsup/cygwin/local_includes/cygtls.h | 3 ++- winsup/cygwin/select.cc | 21 +++++++++++++++------ 4 files changed, 35 insertions(+), 14 deletions(-) diff --git a/winsup/cygwin/cygtls.cc b/winsup/cygwin/cygtls.cc index bfaa19867..1134adc3e 100644 --- a/winsup/cygwin/cygtls.cc +++ b/winsup/cygwin/cygtls.cc @@ -64,6 +64,7 @@ _cygtls::init_thread (void *x, DWORD (*func) (void *, void *)) initialized = CYGTLS_INITIALIZED; errno_addr = &(local_clib._errno); locals.cw_timer = NULL; + locals.cw_timer_inuse = false; locals.pathbufs.clear (); if ((void *) func == (void *) cygthread::stub @@ -85,6 +86,7 @@ _cygtls::fixup_after_fork () signal_arrived = NULL; locals.select.sockevt = NULL; locals.cw_timer = NULL; + locals.cw_timer_inuse = false; locals.pathbufs.clear (); wq.thread_ev = NULL; } diff --git a/winsup/cygwin/cygwait.cc b/winsup/cygwin/cygwait.cc index 80c0e971c..e9ac420e4 100644 --- a/winsup/cygwin/cygwait.cc +++ b/winsup/cygwin/cygwait.cc @@ -58,16 +58,21 @@ cygwait (HANDLE object, PLARGE_INTEGER timeout, unsigned mask) } DWORD timeout_n; + HANDLE *wait_timer = &_my_tls.locals.cw_timer; + HANDLE local_wait_timer = NULL; if (!timeout) timeout_n = WAIT_TIMEOUT + 1; else { + if (_my_tls.locals.cw_timer_inuse) + wait_timer = &local_wait_timer; + else + _my_tls.locals.cw_timer_inuse = true; timeout_n = WAIT_OBJECT_0 + num++; - if (!_my_tls.locals.cw_timer) - NtCreateTimer (&_my_tls.locals.cw_timer, TIMER_ALL_ACCESS, NULL, - NotificationTimer); - NtSetTimer (_my_tls.locals.cw_timer, timeout, NULL, NULL, FALSE, 0, NULL); - wait_objects[timeout_n] = _my_tls.locals.cw_timer; + if (!*wait_timer) + NtCreateTimer (wait_timer, TIMER_ALL_ACCESS, NULL, NotificationTimer); + NtSetTimer (*wait_timer, timeout, NULL, NULL, FALSE, 0, NULL); + wait_objects[timeout_n] = *wait_timer; } while (1) @@ -100,7 +105,7 @@ cygwait (HANDLE object, PLARGE_INTEGER timeout, unsigned mask) { TIMER_BASIC_INFORMATION tbi; - NtQueryTimer (_my_tls.locals.cw_timer, TimerBasicInformation, &tbi, + NtQueryTimer (*wait_timer, TimerBasicInformation, &tbi, sizeof tbi, NULL); /* if timer expired, TimeRemaining is negative and represents the system uptime when signalled */ @@ -108,7 +113,11 @@ cygwait (HANDLE object, PLARGE_INTEGER timeout, unsigned mask) timeout->QuadPart = tbi.SignalState || tbi.TimeRemaining.QuadPart < 0LL ? 0LL : tbi.TimeRemaining.QuadPart; } - NtCancelTimer (_my_tls.locals.cw_timer, NULL); + NtCancelTimer (*wait_timer, NULL); + if (local_wait_timer) + NtClose(local_wait_timer); + else + _my_tls.locals.cw_timer_inuse = false; } if (res == WAIT_CANCELED && is_cw_cancel_self) diff --git a/winsup/cygwin/local_includes/cygtls.h b/winsup/cygwin/local_includes/cygtls.h index e0de712f4..d814814b1 100644 --- a/winsup/cygwin/local_includes/cygtls.h +++ b/winsup/cygwin/local_includes/cygtls.h @@ -135,6 +135,7 @@ struct _local_storage /* thread.cc */ HANDLE cw_timer; + bool cw_timer_inuse; tls_pathbuf pathbufs; char ttybuf[32]; @@ -180,7 +181,7 @@ public: /* Do NOT remove this public: line, it's a marker for gentls_offsets. */ siginfo_t *sigwait_info; HANDLE signal_arrived; bool will_wait_for_signal; -#if 0 +#if 1 long __align; /* Needed to align context to 16 byte. */ #endif /* context MUST be aligned to 16 byte, otherwise RtlCaptureContext fails. diff --git a/winsup/cygwin/select.cc b/winsup/cygwin/select.cc index a440a98d4..e44d42a0d 100644 --- a/winsup/cygwin/select.cc +++ b/winsup/cygwin/select.cc @@ -385,13 +385,18 @@ next_while:; to create the timer once per thread. Since WFMO checks the handles in order, we append the timer as last object, otherwise it's preferred over actual events on the descriptors. */ - HANDLE &wait_timer = _my_tls.locals.cw_timer; + HANDLE *wait_timer = &_my_tls.locals.cw_timer; + HANDLE local_wait_timer = NULL; if (us > 0LL) { NTSTATUS status; - if (!wait_timer) + if (_my_tls.locals.cw_timer_inuse) + wait_timer = &local_wait_timer; + else + _my_tls.locals.cw_timer_inuse = true; + if (!*wait_timer) { - status = NtCreateTimer (&wait_timer, TIMER_ALL_ACCESS, NULL, + status = NtCreateTimer (wait_timer, TIMER_ALL_ACCESS, NULL, NotificationTimer); if (!NT_SUCCESS (status)) { @@ -400,7 +405,7 @@ next_while:; } } LARGE_INTEGER ms_clock_ticks = { .QuadPart = -us * 10 }; - status = NtSetTimer (wait_timer, &ms_clock_ticks, NULL, NULL, FALSE, + status = NtSetTimer (*wait_timer, &ms_clock_ticks, NULL, NULL, FALSE, 0, NULL); if (!NT_SUCCESS (status)) { @@ -408,7 +413,7 @@ next_while:; status, ms_clock_ticks.QuadPart); return select_error; } - w4[m] = wait_timer; + w4[m] = *wait_timer; timer_idx = m++; } @@ -430,7 +435,11 @@ next_while:; if (timer_idx) { BOOLEAN current_state; - NtCancelTimer (wait_timer, ¤t_state); + NtCancelTimer (*wait_timer, ¤t_state); + if (local_wait_timer) + NtClose (local_wait_timer); + else + _my_tls.locals.cw_timer_inuse = false; } wait_states res; -- 2.45.1