diff --git a/winsup/cygwin/cygserver_ipc.h b/winsup/cygwin/cygserver_ipc.h index 31eea3464..2f7c3531f 100644 --- a/winsup/cygwin/cygserver_ipc.h +++ b/winsup/cygwin/cygserver_ipc.h @@ -43,7 +43,7 @@ ipc_set_proc_info (proc &blk) blk.gidcnt = 0; blk.gidlist = NULL; blk.is_admin = false; - blk.signal_arrived = _my_tls.signal_arrived; + blk.signal_arrived = signal_arrived; } #endif /* __INSIDE_CYGWIN__ */ diff --git a/winsup/cygwin/cygthread.cc b/winsup/cygwin/cygthread.cc index 604521c58..4cbd3b064 100644 --- a/winsup/cygwin/cygthread.cc +++ b/winsup/cygwin/cygthread.cc @@ -373,16 +373,20 @@ cygthread::detach (HANDLE sigwait) LONG prio = GetThreadPriority (hth); ::SetThreadPriority (hth, THREAD_PRIORITY_BELOW_NORMAL); + HANDLE w4[2]; + unsigned n = 2; DWORD howlong = INFINITE; + w4[0] = sigwait; + w4[1] = signal_arrived; /* For a description of the below loop see the end of this file */ for (int i = 0; i < 2; i++) - switch (res = cygwait (sigwait, howlong)) + switch (res = WaitForMultipleObjects (n, w4, FALSE, howlong)) { case WAIT_OBJECT_0: if (n == 1) howlong = 50; break; - case WAIT_SIGNALED: + case WAIT_OBJECT_0 + 1: n = 1; if (i--) howlong = 50; @@ -391,7 +395,20 @@ cygthread::detach (HANDLE sigwait) break; default: if (!exiting) - api_fatal ("WFMO failed waiting for cygthread '%s', %E", __name); + { + system_printf ("WFMO failed waiting for cygthread '%s', %E", __name); + for (unsigned j = 0; j < n; j++) + switch (WaitForSingleObject (w4[j], 0)) + { + case WAIT_OBJECT_0: + case WAIT_TIMEOUT: + break; + default: + system_printf ("%s handle %p is bad", (j ? "signal_arrived" : "semaphore"), w4[j]); + break; + } + api_fatal ("exiting on fatal error"); + } break; } /* WAIT_OBJECT_0 means that the thread successfully read something, diff --git a/winsup/cygwin/cygtls.h b/winsup/cygwin/cygtls.h index e4240984e..40c6151c2 100644 --- a/winsup/cygwin/cygtls.h +++ b/winsup/cygwin/cygtls.h @@ -174,8 +174,7 @@ public: int sa_flags; sigset_t oldmask; sigset_t deltamask; - HANDLE signal_arrived; - bool waiting; + HANDLE event; int *errno_addr; sigset_t sigmask; sigset_t sigwait_mask; diff --git a/winsup/cygwin/cygwait.cc b/winsup/cygwin/cygwait.cc index 377012a1a..9b22bd01f 100644 --- a/winsup/cygwin/cygwait.cc +++ b/winsup/cygwin/cygwait.cc @@ -21,8 +21,6 @@ #define is_cw_sig_handle (mask & (is_cw_sig | is_cw_sig_eintr)) -TIMER_BASIC_INFORMATION cw_nowait; - DWORD cancelable_wait (HANDLE object, PLARGE_INTEGER timeout, unsigned mask) { @@ -85,11 +83,8 @@ cancelable_wait (HANDLE object, PLARGE_INTEGER timeout, unsigned mask) /* all set */; else if (is_cw_sig_eintr) res = WAIT_SIGNALED; - else - { - _my_tls.call_signal_handler (); - continue; - } + else if (_my_tls.call_signal_handler () || &_my_tls != _main_tls) + continue; break; } diff --git a/winsup/cygwin/cygwait.h b/winsup/cygwin/cygwait.h index a7daf88eb..9b2be02ac 100644 --- a/winsup/cygwin/cygwait.h +++ b/winsup/cygwin/cygwait.h @@ -11,6 +11,9 @@ #pragma once +#define WAIT_CANCELED (WAIT_OBJECT_0 + 2) +#define WAIT_SIGNALED (WAIT_OBJECT_0 + 1) + enum cw_wait_mask { cw_cancel = 0x0001, @@ -19,8 +22,6 @@ enum cw_wait_mask cw_sig_eintr = 0x0008 }; -extern TIMER_BASIC_INFORMATION cw_nowait; - const unsigned cw_std_mask = cw_cancel | cw_cancel_self | cw_sig; DWORD cancelable_wait (HANDLE, PLARGE_INTEGER timeout = NULL, @@ -28,7 +29,7 @@ DWORD cancelable_wait (HANDLE, PLARGE_INTEGER timeout = NULL, __attribute__ ((regparm (3))); static inline DWORD __attribute__ ((always_inline)) -cancelable_wait (HANDLE h, DWORD howlong, unsigned mask) +cygwait (HANDLE h, DWORD howlong = INFINITE) { PLARGE_INTEGER pli_howlong; LARGE_INTEGER li_howlong; @@ -39,14 +40,7 @@ cancelable_wait (HANDLE h, DWORD howlong, unsigned mask) li_howlong.QuadPart = 10000ULL * howlong; pli_howlong = &li_howlong; } - - return cancelable_wait (h, pi_howlong, mask); -} - -static inline DWORD __attribute__ ((always_inline)) -cygwait (HANDLE h, DWORD howlong = INFINITE) -{ - return cancelable_wait (h, howlong, cw_cancel | cw_sig_eintr); + return cancelable_wait (h, pli_howlong, cw_cancel | cw_sig); } static inline DWORD __attribute__ ((always_inline)) @@ -54,29 +48,3 @@ cygwait (DWORD howlong) { return cygwait ((HANDLE) NULL, howlong); } - -class set_thread_waiting -{ - void doit (bool setit, DWORD& here) - { - if (setit) - { - if (_my_tls.signal_arrived == NULL) - _my_tls.signal_arrived = CreateEvent (&sec_none_nih, false, false, NULL); - here = _my_tls.signal_arrived; - _my_tls.waiting = true; - } - } -public: - set_thread_waiting (bool setit, DWORD& here) { doit (setit, here); } - set_thread_waiting (DWORD& here) { doit (true, here); } - - ~set_thread_waiting () - { - if (_my_tls.waiting) - { - _my_tls.waiting = false; - ResetEvent (_my_tls.signal_arrived); - } - } -}; diff --git a/winsup/cygwin/dcrt0.cc b/winsup/cygwin/dcrt0.cc index 71b3d2ac3..e28aecde9 100644 --- a/winsup/cygwin/dcrt0.cc +++ b/winsup/cygwin/dcrt0.cc @@ -842,6 +842,8 @@ dll_crt0_1 (void *) strace.microseconds (); #endif + create_signal_arrived (); /* FIXME: move into wait_sig? */ + /* Initialize debug muto, if DLL is built with --enable-debugging. Need to do this before any helper threads start. */ debug_init (); diff --git a/winsup/cygwin/exceptions.cc b/winsup/cygwin/exceptions.cc index fe233cf49..3c22e35c3 100644 --- a/winsup/cygwin/exceptions.cc +++ b/winsup/cygwin/exceptions.cc @@ -715,7 +715,7 @@ handle_sigsuspend (sigset_t tempmask) sigproc_printf ("oldmask %p, newmask %p", oldmask, tempmask); pthread_testcancel (); - cancelable_wait (NULL, NULL, cw_cancel | cw_cancel_self | cw_sig_eintr); + cancelable_wait (signal_arrived, NULL, cw_cancel | cw_cancel_self); set_sig_errno (EINTR); // Per POSIX @@ -748,7 +748,8 @@ sig_handle_tty_stop (int sig) sigproc_printf ("process %d stopped by signal %d", myself->pid, sig); HANDLE w4[2]; w4[0] = sigCONT; - switch (cancelable_wait (sigCONT, NULL, cw_sig_eintr)) + w4[1] = signal_arrived; + switch (WaitForMultipleObjects (2, w4, TRUE, INFINITE)) { case WAIT_OBJECT_0: case WAIT_OBJECT_0 + 1: @@ -1247,7 +1248,7 @@ sigpacket::process () { sigproc_printf ("default signal %d ignored", si.si_signo); if (continue_now) - SetEvent (use_tls->signal_arrived); + SetEvent (signal_arrived); goto done; } diff --git a/winsup/cygwin/fhandler_socket.cc b/winsup/cygwin/fhandler_socket.cc index 611e70619..f78002801 100644 --- a/winsup/cygwin/fhandler_socket.cc +++ b/winsup/cygwin/fhandler_socket.cc @@ -130,7 +130,7 @@ get_inet_addr (const struct sockaddr *in, int inlen, pthread_testcancel (); /* Using IsEventSignalled like this is racy since another thread could be waiting for signal_arrived. */ - if (cancelable_wait (NULL, cw_nowait, cw_sig_eintr) == WAIT_SIGNALED + if (IsEventSignalled (signal_arrived) && !_my_tls.call_signal_handler ()) { set_errno (EINTR); @@ -662,8 +662,7 @@ fhandler_socket::wait_for_events (const long event_mask, const DWORD flags) return SOCKET_ERROR; } - WSAEVENT ev[2] = { wsock_evt }; - set_thread_waiting (ev[1]); + WSAEVENT ev[2] = { wsock_evt, signal_arrived }; switch (WSAWaitForMultipleEvents (2, ev, FALSE, 50, FALSE)) { case WSA_WAIT_TIMEOUT: @@ -1785,7 +1784,7 @@ fhandler_socket::close () res = -1; break; } - if (cygwait (10) == WAIT_SIGNALED) + if (WaitForSingleObject (signal_arrived, 10) == WAIT_OBJECT_0) { set_errno (EINTR); res = -1; diff --git a/winsup/cygwin/fhandler_tape.cc b/winsup/cygwin/fhandler_tape.cc index 2e936c3b1..c394d862d 100644 --- a/winsup/cygwin/fhandler_tape.cc +++ b/winsup/cygwin/fhandler_tape.cc @@ -1142,14 +1142,26 @@ mtinfo::initialize () inline bool fhandler_dev_tape::_lock (bool cancelable) { + HANDLE w4[3] = { mt_mtx, signal_arrived, NULL }; + DWORD cnt = 2; + if (cancelable && (w4[2] = pthread::get_cancel_event ()) != NULL) + cnt = 3; /* O_NONBLOCK is only valid in a read or write call. Only those are cancelable. */ DWORD timeout = cancelable && is_nonblocking () ? 0 : INFINITE; restart: - switch (cancelable_wait (mt_mtx, timeout, cw_sig | cw_cancel | cw_cancel_self)) + switch (WaitForMultipleObjects (cnt, w4, FALSE, timeout)) { case WAIT_OBJECT_0: return true; + case WAIT_OBJECT_0 + 1: + if (_my_tls.call_signal_handler ()) + goto restart; + set_errno (EINTR); + return false; + case WAIT_OBJECT_0 + 2: + pthread::static_cancel_self (); + /*NOTREACHED*/ case WAIT_TIMEOUT: set_errno (EAGAIN); return false; diff --git a/winsup/cygwin/fhandler_termios.cc b/winsup/cygwin/fhandler_termios.cc index 3bfa38a6b..7fddba5b3 100644 --- a/winsup/cygwin/fhandler_termios.cc +++ b/winsup/cygwin/fhandler_termios.cc @@ -204,7 +204,7 @@ fhandler_termios::bg_check (int sig) { /* Don't raise a SIGTT* signal if we have already been interrupted by another signal. */ - if (cygwait (0) != WAIT_SIGNALED) + if (WaitForSingleObject (signal_arrived, 0) != WAIT_OBJECT_0) { siginfo_t si = {0}; si.si_signo = sig; diff --git a/winsup/cygwin/fhandler_tty.cc b/winsup/cygwin/fhandler_tty.cc index c5f1d4618..fe7e283a9 100644 --- a/winsup/cygwin/fhandler_tty.cc +++ b/winsup/cygwin/fhandler_tty.cc @@ -281,7 +281,7 @@ fhandler_pty_master::process_slave_output (char *buf, size_t len, int pktmode_on goto out; } pthread_testcancel (); - if (cancelable_wait (NULL, 10, cw_sig_eintr) == WAIT_SIGNALED + if (WaitForSingleObject (signal_arrived, 10) == WAIT_OBJECT_0 && !_my_tls.call_signal_handler ()) { set_errno (EINTR); diff --git a/winsup/cygwin/fhandler_windows.cc b/winsup/cygwin/fhandler_windows.cc index b592e3217..c89d98e16 100644 --- a/winsup/cygwin/fhandler_windows.cc +++ b/winsup/cygwin/fhandler_windows.cc @@ -96,8 +96,7 @@ fhandler_windows::read (void *buf, size_t& len) return; } - HANDLE w4[3] = { get_handle (), }; - set_thread_waiting (w4[1]); + HANDLE w4[3] = { get_handle (), signal_arrived, NULL }; DWORD cnt = 2; if ((w4[cnt] = pthread::get_cancel_event ()) != NULL) ++cnt; diff --git a/winsup/cygwin/flock.cc b/winsup/cygwin/flock.cc index f40c1e5c6..176e4869e 100644 --- a/winsup/cygwin/flock.cc +++ b/winsup/cygwin/flock.cc @@ -1247,7 +1247,7 @@ lf_setlock (lockf_t *lock, inode_t *node, lockf_t **clean, HANDLE fhdl) timeout = 100L; DWORD WAIT_SIGNAL_ARRIVED = WAIT_OBJECT_0 + wait_count; - set_thread_waiting (w4[wait_count++]); + w4[wait_count++] = signal_arrived; DWORD WAIT_THREAD_CANCELED = WAIT_TIMEOUT + 1; HANDLE cancel_event = pthread::get_cancel_event (); diff --git a/winsup/cygwin/posix_ipc.cc b/winsup/cygwin/posix_ipc.cc index b427d11d6..b9d224e43 100644 --- a/winsup/cygwin/posix_ipc.cc +++ b/winsup/cygwin/posix_ipc.cc @@ -119,12 +119,14 @@ ipc_mutex_init (HANDLE *pmtx, const char *name) static int ipc_mutex_lock (HANDLE mtx) { - switch (cancelable_wait (mtx, NULL, cw_sig_eintr | cw_cancel | cw_cancel_self)) + HANDLE h[2] = { mtx, signal_arrived }; + + switch (WaitForMultipleObjects (2, h, FALSE, INFINITE)) { case WAIT_OBJECT_0: case WAIT_ABANDONED_0: return 0; - case WAIT_SIGNALED: + case WAIT_OBJECT_0 + 1: set_errno (EINTR); return 1; default: @@ -172,12 +174,11 @@ ipc_cond_init (HANDLE *pevt, const char *name, char sr) static int ipc_cond_timedwait (HANDLE evt, HANDLE mtx, const struct timespec *abstime) { - HANDLE w4[4] = { evt, }; + HANDLE w4[4] = { evt, signal_arrived, NULL, NULL }; DWORD cnt = 2; DWORD timer_idx = 0; int ret = 0; - set_thread_waiting (w4[1]); if ((w4[cnt] = pthread::get_cancel_event ()) != NULL) ++cnt; if (abstime) diff --git a/winsup/cygwin/select.cc b/winsup/cygwin/select.cc index d98e13255..0186af733 100644 --- a/winsup/cygwin/select.cc +++ b/winsup/cygwin/select.cc @@ -312,7 +312,7 @@ select_stuff::wait (fd_set *readfds, fd_set *writefds, fd_set *exceptfds, select_record *s = &start; DWORD m = 0; - set_thread_waiting (w4[m++]); + w4[m++] = signal_arrived; /* Always wait for the arrival of a signal. */ if ((w4[m] = pthread::get_cancel_event ()) != NULL) m++; diff --git a/winsup/cygwin/signal.cc b/winsup/cygwin/signal.cc index 595bb01d7..a62c038cd 100644 --- a/winsup/cygwin/signal.cc +++ b/winsup/cygwin/signal.cc @@ -120,9 +120,12 @@ clock_nanosleep (clockid_t clk_id, int flags, const struct timespec *rqtp, syscall_printf ("clock_nanosleep (%ld.%09ld)", rqtp->tv_sec, rqtp->tv_nsec); - int rc = cancelable_wait (NULL, &timeout, cw_sig | cw_cancel | cw_cancel_self); - if (rc == WAIT_SIGNALED) - res = EINTR; + int rc = cancelable_wait (signal_arrived, &timeout); + if (rc == WAIT_OBJECT_0) + { + _my_tls.call_signal_handler (); + res = EINTR; + } /* according to POSIX, rmtp is used only if !abstime */ if (rmtp && !abstime) @@ -562,14 +565,21 @@ extern "C" int sigwaitinfo (const sigset_t *set, siginfo_t *info) { pthread_testcancel (); + HANDLE h; + h = _my_tls.event = CreateEvent (&sec_none_nih, FALSE, FALSE, NULL); + if (!h) + { + __seterrno (); + return -1; + } _my_tls.sigwait_mask = *set; sig_dispatch_pending (true); int res; - switch (cancelable_wait (NULL, NULL, cw_sig | cw_cancel | cw_cancel_self)) + switch (WaitForSingleObject (h, INFINITE)) { - case WAIT_SIGNALED: + case WAIT_OBJECT_0: if (!sigismember (set, _my_tls.infodata.si_signo)) { set_errno (EINTR); @@ -588,6 +598,8 @@ sigwaitinfo (const sigset_t *set, siginfo_t *info) res = -1; } + _my_tls.event = NULL; + CloseHandle (h); sigproc_printf ("returning signal %d", res); return res; } diff --git a/winsup/cygwin/sigproc.cc b/winsup/cygwin/sigproc.cc index 56fce1663..05d98729f 100644 --- a/winsup/cygwin/sigproc.cc +++ b/winsup/cygwin/sigproc.cc @@ -43,6 +43,9 @@ int __sp_ln; char NO_COPY myself_nowait_dummy[1] = {'0'};// Flag to sig_send that signal goes to // current process but no wait is required +HANDLE NO_COPY signal_arrived; // Event signaled when a signal has + // resulted in a user-specified + // function call #define Static static NO_COPY @@ -515,6 +518,17 @@ sig_dispatch_pending (bool fast) sig_send (myself, fast ? __SIGFLUSHFAST : __SIGFLUSH); } +void __stdcall +create_signal_arrived () +{ + if (signal_arrived) + return; + /* local event signaled when main thread has been dispatched + to a signal handler function. */ + signal_arrived = CreateEvent (&sec_none_nih, false, false, NULL); + ProtectHandle (signal_arrived); +} + /* Signal thread initialization. Called from dll_crt0_1. This routine starts the signal handling thread. */ void __stdcall diff --git a/winsup/cygwin/sigproc.h b/winsup/cygwin/sigproc.h index ba8a231b9..d980f1a6e 100644 --- a/winsup/cygwin/sigproc.h +++ b/winsup/cygwin/sigproc.h @@ -58,6 +58,7 @@ struct sigpacket int __stdcall process () __attribute__ ((regparm (1))); }; +extern HANDLE signal_arrived; extern HANDLE sigCONT; void __stdcall sig_dispatch_pending (bool fast = false); @@ -85,6 +86,7 @@ int __stdcall sig_send (_pinfo *, siginfo_t&, class _cygtls *tls = NULL) __attri int __stdcall sig_send (_pinfo *, int) __attribute__ ((regparm (2))); void __stdcall signal_fixup_after_exec (); void __stdcall sigalloc (); +void __stdcall create_signal_arrived (); int kill_pgrp (pid_t, siginfo_t&); int killsys (pid_t, int); diff --git a/winsup/cygwin/syscalls.cc b/winsup/cygwin/syscalls.cc index c0cacac97..2077a0a3c 100644 --- a/winsup/cygwin/syscalls.cc +++ b/winsup/cygwin/syscalls.cc @@ -2295,7 +2295,7 @@ retry: { debug_printf ("status %p", status); if (status == STATUS_SHARING_VIOLATION - && cygwait (10L) != WAIT_SIGNALED) + && WaitForSingleObject (signal_arrived, 10L) != WAIT_OBJECT_0) { /* Typical BLODA problem. Some virus scanners check newly generated files and while doing that disallow DELETE access. That's really diff --git a/winsup/cygwin/thread.h b/winsup/cygwin/thread.h index 0dd9b893b..62a06f60b 100644 --- a/winsup/cygwin/thread.h +++ b/winsup/cygwin/thread.h @@ -344,9 +344,6 @@ public: pthread_spinlock (int); }; -#define WAIT_CANCELED (WAIT_OBJECT_0 + 1) -#define WAIT_SIGNALED (WAIT_OBJECT_0 + 2) - class _cygtls; class pthread: public verifyable_object {