Skip to content

Commit

Permalink
Cygwin: cygwait: Make cygwait() reentrant
Browse files Browse the repository at this point in the history
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 <[email protected]>
Signed-off-by: Takashi Yano <[email protected]>
  • Loading branch information
tyan0 and github-cygwin committed Jan 21, 2025
1 parent 6172e52 commit ea19140
Show file tree
Hide file tree
Showing 4 changed files with 28 additions and 9 deletions.
2 changes: 2 additions & 0 deletions winsup/cygwin/cygtls.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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;
}
Expand Down
22 changes: 15 additions & 7 deletions winsup/cygwin/cygwait.cc
Original file line number Diff line number Diff line change
Expand Up @@ -58,16 +58,20 @@ cygwait (HANDLE object, PLARGE_INTEGER timeout, unsigned mask)
}

DWORD timeout_n;
HANDLE local_timer = NULL;
HANDLE &wait_timer =
_my_tls.locals.cw_timer_inuse ? local_timer : _my_tls.locals.cw_timer;
if (!timeout)
timeout_n = WAIT_TIMEOUT + 1;
else
{
if (!_my_tls.locals.cw_timer_inuse)
_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)
Expand Down Expand Up @@ -100,15 +104,19 @@ 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 */
if (timeout->QuadPart < 0LL) {
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_timer)
NtClose(local_timer);
else
_my_tls.locals.cw_timer_inuse = false;
}

if (res == WAIT_CANCELED && is_cw_cancel_self)
Expand Down
3 changes: 2 additions & 1 deletion winsup/cygwin/local_includes/cygtls.h
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,7 @@ struct _local_storage

/* thread.cc */
HANDLE cw_timer;
bool cw_timer_inuse;

tls_pathbuf pathbufs;
char ttybuf[32];
Expand Down Expand Up @@ -180,7 +181,7 @@ class _cygtls
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.
Expand Down
10 changes: 9 additions & 1 deletion winsup/cygwin/select.cc
Original file line number Diff line number Diff line change
Expand Up @@ -385,10 +385,14 @@ 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 local_timer = NULL;
HANDLE &wait_timer =
_my_tls.locals.cw_timer_inuse ? local_timer : _my_tls.locals.cw_timer;
if (us > 0LL)
{
NTSTATUS status;
if (!_my_tls.locals.cw_timer_inuse)
_my_tls.locals.cw_timer_inuse = true;
if (!wait_timer)
{
status = NtCreateTimer (&wait_timer, TIMER_ALL_ACCESS, NULL,
Expand Down Expand Up @@ -431,6 +435,10 @@ next_while:;
{
BOOLEAN current_state;
NtCancelTimer (wait_timer, &current_state);
if (local_timer)
NtClose (local_timer);
else
_my_tls.locals.cw_timer_inuse = false;
}

wait_states res;
Expand Down

0 comments on commit ea19140

Please sign in to comment.