diff --git a/winsup/cygwin/cygtls.h b/winsup/cygwin/cygtls.h index 39dba1380..65a905c32 100644 --- a/winsup/cygwin/cygtls.h +++ b/winsup/cygwin/cygtls.h @@ -189,8 +189,11 @@ public: stack_t altstack; siginfo_t *sigwait_info; HANDLE signal_arrived; + HANDLE signalfd_select_wait; bool will_wait_for_signal; - long __align; /* Needed to align context to 16 byte. */ + /* context MUST be aligned to 16 byte, otherwise RtlCaptureContext fails. + If you prepend cygtls members here, make sure context stays 16 byte + aligned. */ ucontext_t context; DWORD thread_id; siginfo_t infodata; diff --git a/winsup/cygwin/exceptions.cc b/winsup/cygwin/exceptions.cc index 8c1b3b4e6..205ad850e 100644 --- a/winsup/cygwin/exceptions.cc +++ b/winsup/cygwin/exceptions.cc @@ -1469,6 +1469,14 @@ sigpacket::process () if (issig_wait) { tls->sigwait_mask = 0; + /* If the catching thread is running select on a signalfd, don't call + the signal handler and don't remove the signal from the queue. */ + if (tls->signalfd_select_wait) + { + SetEvent (tls->signalfd_select_wait); + rc = 0; + goto done; + } goto dosig; } diff --git a/winsup/cygwin/fhandler.h b/winsup/cygwin/fhandler.h index a908964e0..f4a8b5463 100644 --- a/winsup/cygwin/fhandler.h +++ b/winsup/cygwin/fhandler.h @@ -2651,6 +2651,7 @@ class fhandler_signalfd : public fhandler_base void __reg3 read (void *ptr, size_t& len); int poll (); + inline sigset_t get_sigset () const { return sigset; } select_record *select_read (select_stuff *); select_record *select_write (select_stuff *); diff --git a/winsup/cygwin/fhandler_signalfd.cc b/winsup/cygwin/fhandler_signalfd.cc index ec80948fb..1bb0d1422 100644 --- a/winsup/cygwin/fhandler_signalfd.cc +++ b/winsup/cygwin/fhandler_signalfd.cc @@ -140,10 +140,10 @@ fhandler_signalfd::read (void *ptr, size_t& len) return; } +/* Called from select */ int fhandler_signalfd::poll () { - Sleep (1L); /* BAD HACK, FIXME, need a non-polling technique. */ sigset_t outset = (sigset_t) sig_send (myself, __SIGPENDING, &_my_tls); if (outset == SIG_BAD_MASK) return -1; diff --git a/winsup/cygwin/select.cc b/winsup/cygwin/select.cc index 3927b9885..d1ae3c649 100644 --- a/winsup/cygwin/select.cc +++ b/winsup/cygwin/select.cc @@ -1732,45 +1732,119 @@ fhandler_windows::select_except (select_stuff *ss) return s; } +static int start_thread_signalfd (select_record *, select_stuff *); + +static DWORD WINAPI +thread_signalfd (void *arg) +{ + select_signalfd_info *si = (select_signalfd_info *) arg; + bool event = false; + + while (!event) + { + sigset_t set = 0; + _cygtls *tls = si->start->tls; + + for (select_record *s = si->start; (s = s->next); ) + if (s->startup == start_thread_signalfd) + set |= ((fhandler_signalfd *) s->fh)->get_sigset (); + set_signal_mask (tls->sigwait_mask, set); + tls->signalfd_select_wait = si->evt; + sig_dispatch_pending (true); + switch (WaitForSingleObject (si->evt, INFINITE)) + { + case WAIT_OBJECT_0: + tls->signalfd_select_wait = NULL; + event = true; + break; + default: + break; + } + if (si->stop_thread) + break; + if (!event) + Sleep (1L); + } + CloseHandle (si->evt); + return 0; +} + +static int +start_thread_signalfd (select_record *me, select_stuff *stuff) +{ + select_signalfd_info *si; + + if ((si = stuff->device_specific_signalfd)) + { + me->h = *si->thread; + return 1; + } + si = new select_signalfd_info; + si->start = &stuff->start; + si->stop_thread = false; + si->evt = CreateEventW (&sec_none_nih, TRUE, FALSE, NULL); + si->thread = new cygthread (thread_signalfd, si, "signalfdsel"); + me->h = *si->thread; + stuff->device_specific_signalfd = si; + return 1; +} + +static void +signalfd_cleanup (select_record *, select_stuff *stuff) +{ + select_signalfd_info *si; + + if (!(si = stuff->device_specific_signalfd)) + return; + if (si->thread) + { + si->stop_thread = true; + SetEvent (si->evt); + si->thread->detach (); + } + delete si; + stuff->device_specific_signalfd = NULL; +} + static int peek_signalfd (select_record *me, bool) { if (((fhandler_signalfd *) me->fh)->poll () == 0) { select_printf ("signalfd %d ready", me->fd); + me->read_ready = true; return 1; } - select_printf ("signalfd %d not ready", me->fd); return 0; } static int -verify_signalfd (select_record *me, fd_set *rfds, fd_set *wfds, - fd_set *efds) +verify_signalfd (select_record *me, fd_set *rfds, fd_set *wfds, fd_set *efds) { return peek_signalfd (me, true); } select_record * -fhandler_signalfd::select_read (select_stuff *ss) +fhandler_signalfd::select_read (select_stuff *stuff) { - select_record *s = ss->start.next; + select_record *s = stuff->start.next; if (!s->startup) { - s->startup = no_startup; + s->startup = start_thread_signalfd; + s->verify = verify_signalfd; + s->cleanup = signalfd_cleanup; } - s->verify = verify_signalfd; s->peek = peek_signalfd; s->read_selected = true; - s->read_ready = true; + s->read_ready = false; return s; } select_record * -fhandler_signalfd::select_write (select_stuff *ss) +fhandler_signalfd::select_write (select_stuff *stuff) { - select_record *s = ss->start.next; + select_record *s = stuff->start.next; if (!s->startup) { s->startup = no_startup; @@ -1783,9 +1857,9 @@ fhandler_signalfd::select_write (select_stuff *ss) } select_record * -fhandler_signalfd::select_except (select_stuff *ss) +fhandler_signalfd::select_except (select_stuff *stuff) { - select_record *s = ss->start.next; + select_record *s = stuff->start.next; if (!s->startup) { s->startup = no_startup; diff --git a/winsup/cygwin/select.h b/winsup/cygwin/select.h index 9a737c39e..71821f76c 100644 --- a/winsup/cygwin/select.h +++ b/winsup/cygwin/select.h @@ -66,6 +66,12 @@ struct select_serial_info: public select_info select_serial_info (): select_info () {} }; +struct select_signalfd_info: public select_info +{ + HANDLE evt; + select_signalfd_info (): select_info () {} +}; + class select_stuff { public: @@ -85,6 +91,7 @@ public: select_pipe_info *device_specific_pipe; select_socket_info *device_specific_socket; select_serial_info *device_specific_serial; + select_signalfd_info *device_specific_signalfd; bool test_and_set (int, fd_set *, fd_set *, fd_set *); int poll (fd_set *, fd_set *, fd_set *); @@ -93,10 +100,11 @@ public: void destroy (); select_stuff (): return_on_signal (false), always_ready (false), - windows_used (false), start (0), + windows_used (false), start (), device_specific_pipe (NULL), device_specific_socket (NULL), - device_specific_serial (NULL) {} + device_specific_serial (NULL), + device_specific_signalfd (NULL) {} }; extern "C" int cygwin_select (int , fd_set *, fd_set *, fd_set *, diff --git a/winsup/cygwin/signal.cc b/winsup/cygwin/signal.cc index 5dee40229..5759cc4d6 100644 --- a/winsup/cygwin/signal.cc +++ b/winsup/cygwin/signal.cc @@ -603,9 +603,11 @@ sigwait_common (const sigset_t *set, siginfo_t *info, PLARGE_INTEGER waittime) __try { set_signal_mask (_my_tls.sigwait_mask, *set); + _my_tls.signalfd_select_wait = NULL; sig_dispatch_pending (true); - switch (cygwait (NULL, waittime, cw_sig_eintr | cw_cancel | cw_cancel_self)) + switch (cygwait (NULL, waittime, + cw_sig_eintr | cw_cancel | cw_cancel_self)) { case WAIT_SIGNALED: if (!sigismember (set, _my_tls.infodata.si_signo)) diff --git a/winsup/cygwin/tlsoffsets.h b/winsup/cygwin/tlsoffsets.h index 13d1003e3..8003a1fff 100644 --- a/winsup/cygwin/tlsoffsets.h +++ b/winsup/cygwin/tlsoffsets.h @@ -29,10 +29,10 @@ //; $tls::psigwait_info = 2852; //; $tls::signal_arrived = -9844; //; $tls::psignal_arrived = 2856; -//; $tls::will_wait_for_signal = -9840; -//; $tls::pwill_wait_for_signal = 2860; -//; $tls::__align = -9836; -//; $tls::p__align = 2864; +//; $tls::signalfd_select_wait = -9840; +//; $tls::psignalfd_select_wait = 2860; +//; $tls::will_wait_for_signal = -9836; +//; $tls::pwill_wait_for_signal = 2864; //; $tls::context = -9832; //; $tls::pcontext = 2868; //; $tls::thread_id = -9084; @@ -91,10 +91,10 @@ #define tls_psigwait_info (2852) #define tls_signal_arrived (-9844) #define tls_psignal_arrived (2856) -#define tls_will_wait_for_signal (-9840) -#define tls_pwill_wait_for_signal (2860) -#define tls___align (-9836) -#define tls_p__align (2864) +#define tls_signalfd_select_wait (-9840) +#define tls_psignalfd_select_wait (2860) +#define tls_will_wait_for_signal (-9836) +#define tls_pwill_wait_for_signal (2864) #define tls_context (-9832) #define tls_pcontext (2868) #define tls_thread_id (-9084) diff --git a/winsup/cygwin/tlsoffsets64.h b/winsup/cygwin/tlsoffsets64.h index d137408d0..735622172 100644 --- a/winsup/cygwin/tlsoffsets64.h +++ b/winsup/cygwin/tlsoffsets64.h @@ -29,10 +29,10 @@ //; $tls::psigwait_info = 4144; //; $tls::signal_arrived = -8648; //; $tls::psignal_arrived = 4152; -//; $tls::will_wait_for_signal = -8640; -//; $tls::pwill_wait_for_signal = 4160; -//; $tls::__align = -8632; -//; $tls::p__align = 4168; +//; $tls::signalfd_select_wait = -8640; +//; $tls::psignalfd_select_wait = 4160; +//; $tls::will_wait_for_signal = -8632; +//; $tls::pwill_wait_for_signal = 4168; //; $tls::context = -8624; //; $tls::pcontext = 4176; //; $tls::thread_id = -7328; @@ -91,10 +91,10 @@ #define tls_psigwait_info (4144) #define tls_signal_arrived (-8648) #define tls_psignal_arrived (4152) -#define tls_will_wait_for_signal (-8640) -#define tls_pwill_wait_for_signal (4160) -#define tls___align (-8632) -#define tls_p__align (4168) +#define tls_sigwait_for_select (-8640) +#define tls_psigwait_for_select (4160) +#define tls_will_wait_for_signal (-8632) +#define tls_pwill_wait_for_signal (4168) #define tls_context (-8624) #define tls_pcontext (4176) #define tls_thread_id (-7328)