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:
@@ -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;
|
||||
|
Reference in New Issue
Block a user