summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--winsup/cygwin/cygtls.h5
-rw-r--r--winsup/cygwin/exceptions.cc8
-rw-r--r--winsup/cygwin/fhandler.h1
-rw-r--r--winsup/cygwin/fhandler_signalfd.cc2
-rw-r--r--winsup/cygwin/select.cc98
-rw-r--r--winsup/cygwin/select.h12
-rw-r--r--winsup/cygwin/signal.cc4
-rw-r--r--winsup/cygwin/tlsoffsets.h16
-rw-r--r--winsup/cygwin/tlsoffsets64.h16
9 files changed, 129 insertions, 33 deletions
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)