Cygwin: signalfd: implement non-polling select

Allow the signal thread to recognize we're called in consequence of
select on a signalfd.  If the signal is part of the wait mask, don't
call any signal handler and don't remove the signal from the queue,
so a subsequent read (or sigwaitinfo/sigtimedwait) still gets the
signal.  Instead, just signal the event object at
_cygtls::signalfd_select_wait for the thread running select.

The addition of signalfd_select_wait to _cygtls unearthed the alignment
problem of the context member again.  To make sure this doesn't get lost,
improve the related comment in the header file so that this (hopefully)
doesn't get lost (again).

Signed-off-by: Corinna Vinschen <corinna@vinschen.de>
This commit is contained in:
Corinna Vinschen 2019-01-14 17:19:37 +01:00
parent 752151e715
commit f42776fa78
9 changed files with 129 additions and 33 deletions

View File

@ -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;

View File

@ -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;
}

View File

@ -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 *);

View File

@ -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;

View File

@ -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;

View File

@ -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 *,

View File

@ -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))

View File

@ -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)

View File

@ -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)