]> sourceware.org Git - newlib-cygwin.git/commitdiff
Cygwin: signal: implement signalfd
authorCorinna Vinschen <corinna@vinschen.de>
Sun, 13 Jan 2019 22:13:33 +0000 (23:13 +0100)
committerCorinna Vinschen <corinna@vinschen.de>
Sun, 13 Jan 2019 22:13:33 +0000 (23:13 +0100)
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>
17 files changed:
winsup/cygwin/Makefile.in
winsup/cygwin/common.din
winsup/cygwin/devices.cc
winsup/cygwin/devices.h
winsup/cygwin/devices.in
winsup/cygwin/dtable.cc
winsup/cygwin/fhandler.cc
winsup/cygwin/fhandler.h
winsup/cygwin/fhandler_signalfd.cc [new file with mode: 0644]
winsup/cygwin/include/cygwin/version.h
winsup/cygwin/include/sys/signalfd.h [new file with mode: 0644]
winsup/cygwin/release/2.12.0
winsup/cygwin/select.cc
winsup/cygwin/signal.cc
winsup/cygwin/sigproc.h
winsup/doc/new-features.xml
winsup/doc/posix.xml

index e4ce31fda9af4392b9db27060187fc7a17348c80..6147e7c9fdce3509f1c0fc70ee025985c9a6387c 100644 (file)
@@ -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 \
index a6363e1ba0e792473d72c4459b4439762b5da18c..b7f39f9c0e0d026b19fadf84520553d8c9dff362 100644 (file)
@@ -1333,6 +1333,7 @@ siginterrupt SIGFE
 sigismember SIGFE
 siglongjmp NOSIGFE
 signal SIGFE
+signalfd SIGFE
 significand NOSIGFE
 significandf NOSIGFE
 sigpause SIGFE
index a830b32027324adfd2340f14ff4883c0338be982..31fd64fa2f829089c1c9d0a84c7ad38b8cca33d6 100644 (file)
@@ -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};
 
index 0c1bf263129f799e45c9eb98416405f33ce19167..065f77e0e195ff151a755d45cdd96af879887e1c 100644 (file)
@@ -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;
index 9ad87389e54d386c132bb3a70b75acadbfb74236..79a7fe726587f0f60b8a7d1950dee3cffa103c4d 100644 (file)
@@ -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};
 
index 780deb5245aff1850a6bbe7374d683062bc79cf9..c8aecfa1a6ca8cba1b056073b9df9f742acedc04 100644 (file)
@@ -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 ())
            {
index 9643373b0bb1cd35b9afb08ce37b0b2b9b825c9a..2c1fcb7db7592e90e184ad9c702d597917872c1d 100644 (file)
@@ -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;
index ec111de369161dbfb5a42e34cc5b0d4fa39bcdb4..a908964e023f19b812cd5e61c690f29b0505e4d3 100644 (file)
@@ -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 (file)
index 0000000..ec80948
--- /dev/null
@@ -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;
+}
index 1bcec331f09e3cfb0797a64b5711dd36deb1c38a..ec5f55fa952d647338256f2199d4003ff4a3dcff 100644 (file)
@@ -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 (file)
index 0000000..f4e5bd5
--- /dev/null
@@ -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 */
index dbda7886efc0bb8ea9fb11a7b46c9373bd1d5973..299ea6d3df2a8bb402b5cb8a03bcf96a1e86a471 100644 (file)
@@ -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:
index 6ce679acf66cb494455c4ccbc54cba3c4ed664c8..3927b9885f46637f6e9e1183dec29b56614bf2d7 100644 (file)
@@ -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;
+}
index c5e9d017ed874603acf87e00c7ff96f973f58a3d..5dee40229b244a9764819967428ae91eb100dd27 100644 (file)
@@ -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;
+}
index f2cd1132be78db56f976965ecec9d88fbaedf23b..9beb31dcf0518f4a3e4b712b9f2d325fe389d8d4 100644 (file)
@@ -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
 {
index 2e1645fbe0401d60661341adc9cb440eb42c7497..17071309ece0f8ec7e71beace1a0f33b18021853 100644 (file)
@@ -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>
index 021b5962c14fc65dcdd65c875daef64e150f4ce1..365a8f0b5c58260bd9f11cb572c015dc60c9e1f6 100644 (file)
@@ -1378,6 +1378,7 @@ also IEEE Std 1003.1-2008 (POSIX.1-2008).</para>
     scandirat
     sched_getcpu
     setxattr
+    signalfd
     sincos
     sincosf
     sincosl
This page took 0.057164 seconds and 5 git commands to generate.