Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

backport patches for hangs #253

Merged
merged 4 commits into from
Jan 22, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
36 changes: 13 additions & 23 deletions winsup/cygwin/exceptions.cc
Original file line number Diff line number Diff line change
Expand Up @@ -1420,7 +1420,7 @@ api_fatal_debug ()

/* Attempt to carefully handle SIGCONT when we are stopped. */
void
_cygtls::handle_SIGCONT (threadlist_t * &tl_entry)
_cygtls::handle_SIGCONT ()
{
if (NOTSTATE (myself, PID_STOPPED))
return;
Expand All @@ -1431,23 +1431,17 @@ _cygtls::handle_SIGCONT (threadlist_t * &tl_entry)
Make sure that any pending signal is handled before trying to
send a new one. Then make sure that SIGCONT has been recognized
before exiting the loop. */
bool sigsent = false;
while (1)
if (sig) /* Assume that it's ok to just test sig outside of a
lock since setup_handler does it this way. */
{
cygheap->unlock_tls (tl_entry);
yield (); /* Attempt to schedule another thread. */
tl_entry = cygheap->find_tls (_main_tls);
}
else if (sigsent)
break; /* SIGCONT has been recognized by other thread */
else
{
sig = SIGCONT;
set_signal_arrived (); /* alert sig_handle_tty_stop */
sigsent = true;
}
while (sig) /* Assume that it's ok to just test sig outside of a */
yield (); /* lock since setup_handler does it this way. */

lock ();
sig = SIGCONT;
set_signal_arrived (); /* alert sig_handle_tty_stop */
unlock ();

while (sig == SIGCONT)
yield ();

/* Clear pending stop signals */
sig_clear (SIGSTOP, false);
sig_clear (SIGTSTP, false);
Expand Down Expand Up @@ -1479,11 +1473,7 @@ sigpacket::process ()
myself->rusage_self.ru_nsignals++;

if (si.si_signo == SIGCONT)
{
tl_entry = cygheap->find_tls (_main_tls);
_main_tls->handle_SIGCONT (tl_entry);
cygheap->unlock_tls (tl_entry);
}
_main_tls->handle_SIGCONT ();

/* SIGKILL is special. It always goes through. */
if (si.si_signo == SIGKILL)
Expand Down
7 changes: 4 additions & 3 deletions 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 All @@ -194,7 +195,7 @@ class _cygtls
class cygthread *_ctinfo;
class san *andreas;
waitq wq;
int sig;
volatile int sig;
unsigned incyg;
volatile unsigned spinning;
volatile unsigned stacklock;
Expand Down Expand Up @@ -275,7 +276,7 @@ class _cygtls
{
will_wait_for_signal = false;
}
void handle_SIGCONT (threadlist_t * &);
void handle_SIGCONT ();
static void cleanup_early(struct _reent *);
private:
void call2 (DWORD (*) (void *, void *), void *, void *);
Expand Down
5 changes: 0 additions & 5 deletions winsup/cygwin/release/3.5.6

This file was deleted.

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
21 changes: 5 additions & 16 deletions winsup/cygwin/sigproc.cc
Original file line number Diff line number Diff line change
Expand Up @@ -742,6 +742,9 @@ sig_send (_pinfo *p, siginfo_t& si, _cygtls *tls)
memcpy (p, si._si_commune._si_str, n); p += n;
}

unsigned cw_mask;
cw_mask = pack.si.si_signo == __SIGFLUSHFAST ? 0 : cw_sig_restart;

DWORD nb;
BOOL res;
/* Try multiple times to send if packsize != nb since that probably
Expand All @@ -751,14 +754,9 @@ sig_send (_pinfo *p, siginfo_t& si, _cygtls *tls)
res = WriteFile (sendsig, leader, packsize, &nb, NULL);
if (!res || packsize == nb)
break;
if (cygwait (NULL, 10, cw_sig_eintr) == WAIT_SIGNALED
&& pack.si.si_signo != __SIGFLUSHFAST)
_my_tls.call_signal_handler ();
cygwait (NULL, 10, cw_mask);
res = 0;
}
/* Re-assert signal_arrived which has been cleared in cygwait(). */
if (_my_tls.sig)
_my_tls.set_signal_arrived ();

if (!res)
{
Expand Down Expand Up @@ -789,16 +787,7 @@ sig_send (_pinfo *p, siginfo_t& si, _cygtls *tls)
if (wait_for_completion)
{
sigproc_printf ("Waiting for pack.wakeup %p", pack.wakeup);
do
{
rc = cygwait (pack.wakeup, WSSC, cw_sig_eintr);
if (rc == WAIT_SIGNALED && pack.si.si_signo != __SIGFLUSHFAST)
_my_tls.call_signal_handler ();
}
while (rc != WAIT_OBJECT_0 && rc != WAIT_TIMEOUT);
/* Re-assert signal_arrived which has been cleared in cygwait(). */
if (_my_tls.sig)
_my_tls.set_signal_arrived ();
rc = cygwait (pack.wakeup, WSSC, cw_mask);
ForceCloseHandle (pack.wakeup);
}
else
Expand Down