aboutsummaryrefslogtreecommitdiff
path: root/winsup
diff options
context:
space:
mode:
authorCorinna Vinschen <corinna@vinschen.de>2019-01-13 23:13:33 +0100
committerCorinna Vinschen <corinna@vinschen.de>2019-01-13 23:13:33 +0100
commit9d13a2995cb4b6fd26cd7b7a2c478ad85115e055 (patch)
tree0289386fa2b7426d34d731deafaa60cf5c564a14 /winsup
parent8ae26f96ae710f8562162fd5d4e9a5d7434beb7b (diff)
downloadnewlib-9d13a2995cb4b6fd26cd7b7a2c478ad85115e055.zip
newlib-9d13a2995cb4b6fd26cd7b7a2c478ad85115e055.tar.gz
newlib-9d13a2995cb4b6fd26cd7b7a2c478ad85115e055.tar.bz2
Cygwin: signal: implement signalfd
First cut of a signalfd implementation. Still TODO: Non-polling select. This should mostly work as on Linux except for missing support for some members of struct signalfd_siginfo, namely ssi_fd, ssi_band (both SIGIO/SIGPOLL, not fully implemented) and ssi_trapno (HW exception, required HW support). Signed-off-by: Corinna Vinschen <corinna@vinschen.de>
Diffstat (limited to 'winsup')
-rw-r--r--winsup/cygwin/Makefile.in1
-rw-r--r--winsup/cygwin/common.din1
-rw-r--r--winsup/cygwin/devices.cc3
-rw-r--r--winsup/cygwin/devices.h4
-rw-r--r--winsup/cygwin/devices.in3
-rw-r--r--winsup/cygwin/dtable.cc3
-rw-r--r--winsup/cygwin/fhandler.cc3
-rw-r--r--winsup/cygwin/fhandler.h40
-rw-r--r--winsup/cygwin/fhandler_signalfd.cc153
-rw-r--r--winsup/cygwin/include/cygwin/version.h3
-rw-r--r--winsup/cygwin/include/sys/signalfd.h54
-rw-r--r--winsup/cygwin/release/2.12.02
-rw-r--r--winsup/cygwin/select.cc65
-rw-r--r--winsup/cygwin/signal.cc62
-rw-r--r--winsup/cygwin/sigproc.h1
-rw-r--r--winsup/doc/new-features.xml2
-rw-r--r--winsup/doc/posix.xml1
17 files changed, 397 insertions, 4 deletions
diff --git a/winsup/cygwin/Makefile.in b/winsup/cygwin/Makefile.in
index e4ce31f..6147e7c 100644
--- a/winsup/cygwin/Makefile.in
+++ b/winsup/cygwin/Makefile.in
@@ -298,6 +298,7 @@ DLL_OFILES:= \
fhandler_raw.o \
fhandler_registry.o \
fhandler_serial.o \
+ fhandler_signalfd.o \
fhandler_socket.o \
fhandler_socket_inet.o \
fhandler_socket_local.o \
diff --git a/winsup/cygwin/common.din b/winsup/cygwin/common.din
index a6363e1..b7f39f9 100644
--- a/winsup/cygwin/common.din
+++ b/winsup/cygwin/common.din
@@ -1333,6 +1333,7 @@ siginterrupt SIGFE
sigismember SIGFE
siglongjmp NOSIGFE
signal SIGFE
+signalfd SIGFE
significand NOSIGFE
significandf NOSIGFE
sigpause SIGFE
diff --git a/winsup/cygwin/devices.cc b/winsup/cygwin/devices.cc
index a830b32..31fd64f 100644
--- a/winsup/cygwin/devices.cc
+++ b/winsup/cygwin/devices.cc
@@ -120,6 +120,9 @@ const _device dev_piper_storage =
const _device dev_pipew_storage =
{"", {FH_PIPEW}, "", exists_internal};
+const _device dev_signalfd_storage =
+ {"", {FH_SIGNALFD}, "", exists_internal};
+
const _device dev_socket_storage =
{"", {FH_SOCKET}, "", exists_internal};
diff --git a/winsup/cygwin/devices.h b/winsup/cygwin/devices.h
index 0c1bf26..065f77e 100644
--- a/winsup/cygwin/devices.h
+++ b/winsup/cygwin/devices.h
@@ -72,6 +72,8 @@ enum fh_devices
FH_DEV = FHDEV (DEV_VIRTFS_MAJOR, 193),
FH_CYGDRIVE= FHDEV (DEV_VIRTFS_MAJOR, 192),
+ FH_SIGNALFD= FHDEV (DEV_VIRTFS_MAJOR, 13),
+
DEV_FLOPPY_MAJOR = 2,
FH_FLOPPY = FHDEV (DEV_FLOPPY_MAJOR, 0),
@@ -400,6 +402,8 @@ extern const _device dev_af_local_storage;
extern const _device dev_af_unix_storage;
#define af_unix_dev ((device *) &dev_af_unix_storage)
+extern const _device dev_signalfd_storage;
+#define signalfd_dev ((device *) &dev_signalfd_storage)
extern const _device dev_piper_storage;
#define piper_dev ((device *) &dev_piper_storage)
extern const _device dev_pipew_storage;
diff --git a/winsup/cygwin/devices.in b/winsup/cygwin/devices.in
index 9ad8738..79a7fe7 100644
--- a/winsup/cygwin/devices.in
+++ b/winsup/cygwin/devices.in
@@ -116,6 +116,9 @@ const _device dev_piper_storage =
const _device dev_pipew_storage =
{"", {FH_PIPEW}, "", exists_internal};
+const _device dev_signalfd_storage =
+ {"", {FH_SIGNALFD}, "", exists_internal};
+
const _device dev_socket_storage =
{"", {FH_SOCKET}, "", exists_internal};
diff --git a/winsup/cygwin/dtable.cc b/winsup/cygwin/dtable.cc
index 780deb5..c8aecfa 100644
--- a/winsup/cygwin/dtable.cc
+++ b/winsup/cygwin/dtable.cc
@@ -575,6 +575,9 @@ fh_alloc (path_conv& pc)
case FH_CYGDRIVE:
fh = cnew (fhandler_cygdrive);
break;
+ case FH_SIGNALFD:
+ fh = cnew (fhandler_signalfd);
+ break;
case FH_TTY:
if (!pc.isopen ())
{
diff --git a/winsup/cygwin/fhandler.cc b/winsup/cygwin/fhandler.cc
index 9643373..2c1fcb7 100644
--- a/winsup/cygwin/fhandler.cc
+++ b/winsup/cygwin/fhandler.cc
@@ -1345,6 +1345,9 @@ fhandler_base::fstat (struct stat *buf)
case FH_PIPER:
buf->st_mode = S_IFIFO | S_IRUSR;
break;
+ case FH_SIGNALFD:
+ buf->st_mode = S_IRUSR | S_IWUSR;
+ break;
default:
buf->st_mode = S_IFCHR | STD_RBITS | STD_WBITS | S_IWGRP | S_IWOTH;
break;
diff --git a/winsup/cygwin/fhandler.h b/winsup/cygwin/fhandler.h
index ec111de..a908964 100644
--- a/winsup/cygwin/fhandler.h
+++ b/winsup/cygwin/fhandler.h
@@ -420,6 +420,7 @@ public:
virtual class fhandler_socket *is_socket () { return NULL; }
virtual class fhandler_socket_wsock *is_wsock_socket () { return NULL; }
virtual class fhandler_console *is_console () { return 0; }
+ virtual class fhandler_signalfd *is_signalfd () { return NULL; }
virtual int is_windows () {return 0; }
virtual void __reg3 raw_read (void *ptr, size_t& ulen);
@@ -2633,6 +2634,44 @@ class fhandler_procnet: public fhandler_proc
}
};
+class fhandler_signalfd : public fhandler_base
+{
+ sigset_t sigset;
+
+ public:
+ fhandler_signalfd ();
+ fhandler_signalfd (void *) {}
+
+ fhandler_signalfd *is_signalfd () { return this; }
+
+ char *get_proc_fd_name (char *buf);
+
+ int signalfd (const sigset_t *mask, int flags);
+ int __reg2 fstat (struct stat *buf);
+ void __reg3 read (void *ptr, size_t& len);
+
+ int poll ();
+
+ select_record *select_read (select_stuff *);
+ select_record *select_write (select_stuff *);
+ select_record *select_except (select_stuff *);
+
+ void copyto (fhandler_base *x)
+ {
+ x->pc.free_strings ();
+ *reinterpret_cast<fhandler_signalfd *> (x) = *this;
+ x->reset (this);
+ }
+
+ fhandler_signalfd *clone (cygheap_types malloc_type = HEAP_FHANDLER)
+ {
+ void *ptr = (void *) ccalloc (malloc_type, 1, sizeof (fhandler_signalfd));
+ fhandler_signalfd *fh = new (ptr) fhandler_signalfd (ptr);
+ copyto (fh);
+ return fh;
+ }
+};
+
struct fhandler_nodevice: public fhandler_base
{
fhandler_nodevice ();
@@ -2672,6 +2711,7 @@ typedef union
char __pty_master[sizeof (fhandler_pty_master)];
char __registry[sizeof (fhandler_registry)];
char __serial[sizeof (fhandler_serial)];
+ char __signalfd[sizeof (fhandler_signalfd)];
char __socket_inet[sizeof (fhandler_socket_inet)];
char __socket_local[sizeof (fhandler_socket_local)];
#ifdef __WITH_AF_UNIX
diff --git a/winsup/cygwin/fhandler_signalfd.cc b/winsup/cygwin/fhandler_signalfd.cc
new file mode 100644
index 0000000..ec80948
--- /dev/null
+++ b/winsup/cygwin/fhandler_signalfd.cc
@@ -0,0 +1,153 @@
+/* fhandler_signalfd.cc: fhandler for /proc/<pid>/fd/<desc> operations
+
+This file is part of Cygwin.
+
+This software is a copyrighted work licensed under the terms of the
+Cygwin license. Please consult the file "CYGWIN_LICENSE" for
+details. */
+
+#include "winsup.h"
+#include "path.h"
+#include "fhandler.h"
+#include "pinfo.h"
+#include "dtable.h"
+#include "cygheap.h"
+#include "sigproc.h"
+#include <cygwin/signal.h>
+#include <sys/signalfd.h>
+
+fhandler_signalfd::fhandler_signalfd () :
+ fhandler_base (),
+ sigset (0)
+{
+}
+
+char *
+fhandler_signalfd::get_proc_fd_name (char *buf)
+{
+ return strcpy (buf, "anon_inode:[signalfd]");
+}
+
+int
+fhandler_signalfd::signalfd (const sigset_t *mask, int flags)
+{
+ __try
+ {
+ sigset = *mask & ~(SIGKILL | SIGSTOP);
+ }
+ __except (EINVAL)
+ {
+ return -1;
+ }
+ __endtry
+ if (flags & SFD_NONBLOCK)
+ set_nonblocking (true);
+ if (flags & SFD_CLOEXEC)
+ set_close_on_exec (true);
+ if (get_unique_id () == 0)
+ {
+ nohandle (true);
+ set_unique_id ();
+ set_ino (get_unique_id ());
+ }
+ return 0;
+}
+
+int __reg2
+fhandler_signalfd::fstat (struct stat *buf)
+{
+ int ret = fhandler_base::fstat (buf);
+ if (!ret)
+ {
+ buf->st_dev = FH_SIGNALFD;
+ buf->st_ino = get_unique_id ();
+ }
+ return ret;
+}
+
+static inline void
+copy_siginfo_to_signalfd (struct signalfd_siginfo *sfd,
+ const siginfo_t * const si)
+{
+ sfd->ssi_signo = si->si_signo;
+ sfd->ssi_errno = si->si_errno;
+ sfd->ssi_code = si->si_code;
+ sfd->ssi_pid = si->si_pid;
+ sfd->ssi_uid = si->si_uid;
+ sfd->ssi_fd = -1;
+ sfd->ssi_tid = si->si_tid;
+ sfd->ssi_band = 0;
+ sfd->ssi_overrun = si->si_overrun;
+ sfd->ssi_trapno = 0;
+ sfd->ssi_status = si->si_status;
+ sfd->ssi_int = si->si_value.sival_int;
+ sfd->ssi_ptr = (uint64_t) si->si_value.sival_ptr;
+ sfd->ssi_utime = si->si_utime;
+ sfd->ssi_stime = si->si_stime;
+ sfd->ssi_addr = (uint64_t) si->si_addr;
+}
+
+void __reg3
+fhandler_signalfd::read (void *ptr, size_t& len)
+{
+ const LARGE_INTEGER poll = { QuadPart : 0 };
+ siginfo_t si;
+ int ret, old_errno;
+ size_t curlen = 0;
+ signalfd_siginfo *sfd_ptr = (signalfd_siginfo *) ptr;
+
+ if (len < sizeof (struct signalfd_siginfo))
+ {
+ set_errno (EINVAL);
+ len = (size_t) -1;
+ return;
+ }
+ old_errno = get_errno ();
+ do
+ {
+ /* Even when read is blocking, only one pending signal is actually
+ required to return. Subsequently use sigtimedwait to just poll
+ if some more signal is available. */
+ ret = sigwait_common (&sigset, &si, (is_nonblocking () || curlen)
+ ? (PLARGE_INTEGER) &poll : NULL);
+ if (ret == -1)
+ {
+ if (curlen == 0)
+ {
+ if (get_errno () == EINTR && curlen == 0)
+ continue;
+ set_errno (old_errno);
+ }
+ len = curlen ?: (size_t) -1;
+ return;
+ }
+ __try
+ {
+ copy_siginfo_to_signalfd (sfd_ptr, &si);
+ }
+ __except (EFAULT)
+ {
+ len = (size_t) -1;
+ return;
+ }
+ __endtry
+ sfd_ptr++;
+ curlen += sizeof (*sfd_ptr);
+ }
+ while ((len - curlen >= sizeof (struct signalfd_siginfo)));
+ set_errno (old_errno);
+ len = curlen;
+ return;
+}
+
+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;
+ if ((outset & sigset) != 0)
+ return 0;
+ return -1;
+}
diff --git a/winsup/cygwin/include/cygwin/version.h b/winsup/cygwin/include/cygwin/version.h
index 1bcec33..ec5f55f 100644
--- a/winsup/cygwin/include/cygwin/version.h
+++ b/winsup/cygwin/include/cygwin/version.h
@@ -502,12 +502,13 @@ details. */
330: Add CLOCK_REALTIME_COARSE, CLOCK_MONOTONIC_RAW, CLOCK_MONOTONIC_COARSE,
CLOCK_BOOTTIME.
331: Add timer_getoverrun, DELAYTIMER_MAX.
+ 332: Add signalfd.
Note that we forgot to bump the api for ualarm, strtoll, strtoull,
sigaltstack, sethostname. */
#define CYGWIN_VERSION_API_MAJOR 0
-#define CYGWIN_VERSION_API_MINOR 331
+#define CYGWIN_VERSION_API_MINOR 332
/* There is also a compatibity version number associated with the shared memory
regions. It is incremented when incompatible changes are made to the shared
diff --git a/winsup/cygwin/include/sys/signalfd.h b/winsup/cygwin/include/sys/signalfd.h
new file mode 100644
index 0000000..f4e5bd5
--- /dev/null
+++ b/winsup/cygwin/include/sys/signalfd.h
@@ -0,0 +1,54 @@
+/* sys/signalfd.h: define signalfd(2) and struct signalfd_siginfo
+
+This file is part of Cygwin.
+
+This software is a copyrighted work licensed under the terms of the
+Cygwin license. Please consult the file "CYGWIN_LICENSE" for
+details. */
+
+#ifndef _SYS_SIGNALFD_H
+#define _SYS_SIGNALFD_H
+
+#include <stdint.h>
+#include <sys/_default_fcntl.h>
+
+enum
+{
+ SFD_CLOEXEC = O_CLOEXEC,
+ SFD_NONBLOCK = O_NONBLOCK
+};
+#define SFD_CLOEXEC SFD_CLOEXEC
+#define SFD_NONBLOCK SFD_NONBLOCK
+
+struct signalfd_siginfo
+{
+ uint32_t ssi_signo;
+ int32_t ssi_errno;
+ int32_t ssi_code;
+ uint32_t ssi_pid;
+ uint32_t ssi_uid;
+ int32_t ssi_fd;
+ uint32_t ssi_tid;
+ uint32_t ssi_band;
+ uint32_t ssi_overrun;
+ uint32_t ssi_trapno;
+ int32_t ssi_status;
+ int32_t ssi_int;
+ uint64_t ssi_ptr;
+ uint64_t ssi_utime;
+ uint64_t ssi_stime;
+ uint64_t ssi_addr;
+ uint8_t pad[48];
+};
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+extern int signalfd (int, const sigset_t *, int);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _SYS_SIGNALFD_H */
diff --git a/winsup/cygwin/release/2.12.0 b/winsup/cygwin/release/2.12.0
index dbda788..299ea6d 100644
--- a/winsup/cygwin/release/2.12.0
+++ b/winsup/cygwin/release/2.12.0
@@ -27,7 +27,7 @@ What's new:
- Support overrun counter for posix timers (via timer_getoverrun() or
siginfo_t::si_overrun).
-- New API: timer_getoverrun.
+- New API: signalfd, timer_getoverrun.
What changed:
diff --git a/winsup/cygwin/select.cc b/winsup/cygwin/select.cc
index 6ce679a..3927b98 100644
--- a/winsup/cygwin/select.cc
+++ b/winsup/cygwin/select.cc
@@ -1731,3 +1731,68 @@ fhandler_windows::select_except (select_stuff *ss)
s->windows_handle = true;
return s;
}
+
+static int
+peek_signalfd (select_record *me, bool)
+{
+ if (((fhandler_signalfd *) me->fh)->poll () == 0)
+ {
+ select_printf ("signalfd %d ready", me->fd);
+ 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)
+{
+ return peek_signalfd (me, true);
+}
+
+select_record *
+fhandler_signalfd::select_read (select_stuff *ss)
+{
+ select_record *s = ss->start.next;
+ if (!s->startup)
+ {
+ s->startup = no_startup;
+ }
+ s->verify = verify_signalfd;
+ s->peek = peek_signalfd;
+ s->read_selected = true;
+ s->read_ready = true;
+ return s;
+}
+
+select_record *
+fhandler_signalfd::select_write (select_stuff *ss)
+{
+ select_record *s = ss->start.next;
+ if (!s->startup)
+ {
+ s->startup = no_startup;
+ s->verify = no_verify;
+ }
+ s->peek = NULL;
+ s->write_selected = false;
+ s->write_ready = false;
+ return s;
+}
+
+select_record *
+fhandler_signalfd::select_except (select_stuff *ss)
+{
+ select_record *s = ss->start.next;
+ if (!s->startup)
+ {
+ s->startup = no_startup;
+ s->verify = no_verify;
+ }
+ s->peek = NULL;
+ s->except_selected = false;
+ s->except_ready = false;
+ return s;
+}
diff --git a/winsup/cygwin/signal.cc b/winsup/cygwin/signal.cc
index c5e9d01..5dee402 100644
--- a/winsup/cygwin/signal.cc
+++ b/winsup/cygwin/signal.cc
@@ -12,6 +12,7 @@ details. */
#include "winsup.h"
#include <stdlib.h>
#include <sys/cygwin.h>
+#include <sys/signalfd.h>
#include "pinfo.h"
#include "sigproc.h"
#include "cygtls.h"
@@ -592,7 +593,7 @@ siginterrupt (int sig, int flag)
return res;
}
-static inline int
+int
sigwait_common (const sigset_t *set, siginfo_t *info, PLARGE_INTEGER waittime)
{
int res = -1;
@@ -781,3 +782,62 @@ sigaltstack (const stack_t *ss, stack_t *oss)
__endtry
return 0;
}
+
+extern "C" int
+signalfd (int fd_in, const sigset_t *mask, int flags)
+{
+ int ret = -1;
+ fhandler_signalfd *fh;
+
+ debug_printf ("signalfd (%d, %p, %y)", fd_in, mask, flags);
+
+ if ((flags & ~(SFD_NONBLOCK | SFD_CLOEXEC)) != 0)
+ {
+ set_errno (EINVAL);
+ goto done;
+ }
+
+ if (fd_in != -1)
+ {
+ /* Change signal mask. */
+ cygheap_fdget fd (fd_in);
+
+ if (fd < 0)
+ goto done;
+ fh = fd->is_signalfd ();
+ if (!fh)
+ {
+ set_errno (EINVAL);
+ goto done;
+ }
+ __try
+ {
+ if (fh->signalfd (mask, flags) == 0)
+ ret = fd_in;
+ }
+ __except (EINVAL) {}
+ __endtry
+ }
+ else
+ {
+ /* Create new signalfd descriptor. */
+ cygheap_fdnew fd;
+
+ if (fd < 0)
+ goto done;
+ fh = (fhandler_signalfd *) build_fh_dev (*signalfd_dev);
+ if (fh && fh->signalfd (mask, flags) == 0)
+ {
+ fd = fh;
+ if (fd <= 2)
+ set_std_handle (fd);
+ ret = fd;
+ }
+ else
+ delete fh;
+ }
+
+done:
+ syscall_printf ("%R = signalfd (%d, %p, %y)", ret, fd_in, mask, flags);
+ return ret;
+}
diff --git a/winsup/cygwin/sigproc.h b/winsup/cygwin/sigproc.h
index f2cd113..9beb31d 100644
--- a/winsup/cygwin/sigproc.h
+++ b/winsup/cygwin/sigproc.h
@@ -79,6 +79,7 @@ void __stdcall sigalloc ();
int kill_pgrp (pid_t, siginfo_t&);
void __reg1 exit_thread (DWORD) __attribute__ ((noreturn));
void __reg1 setup_signal_exit (int);
+int sigwait_common (const sigset_t *, siginfo_t *, PLARGE_INTEGER);
class no_thread_exit_protect
{
diff --git a/winsup/doc/new-features.xml b/winsup/doc/new-features.xml
index 2e1645f..1707130 100644
--- a/winsup/doc/new-features.xml
+++ b/winsup/doc/new-features.xml
@@ -51,7 +51,7 @@ siginfo_t::si_overrun).
</para></listitem>
<listitem><para>
-New API: timer_getoverrun.
+New API: signalfd, timer_getoverrun.
</para></listitem>
<listitem><para>
diff --git a/winsup/doc/posix.xml b/winsup/doc/posix.xml
index 021b596..365a8f0 100644
--- a/winsup/doc/posix.xml
+++ b/winsup/doc/posix.xml
@@ -1378,6 +1378,7 @@ also IEEE Std 1003.1-2008 (POSIX.1-2008).</para>
scandirat
sched_getcpu
setxattr
+ signalfd
sincos
sincosf
sincosl