Cygwin: strptime: add release note
[newlib-cygwin.git] / winsup / cygwin / fhandler / signalfd.cc
blobbdd8bc93e7c7960b4e2cba22e00a288016dc5a2a
1 /* fhandler_signalfd.cc: fhandler for signalfd
3 This file is part of Cygwin.
5 This software is a copyrighted work licensed under the terms of the
6 Cygwin license. Please consult the file "CYGWIN_LICENSE" for
7 details. */
9 #include "winsup.h"
10 #include "path.h"
11 #include "fhandler.h"
12 #include "pinfo.h"
13 #include "dtable.h"
14 #include "cygheap.h"
15 #include "sigproc.h"
16 #include <cygwin/signal.h>
17 #include <sys/signalfd.h>
19 fhandler_signalfd::fhandler_signalfd () :
20 fhandler_base (),
21 sigset (0)
25 char *
26 fhandler_signalfd::get_proc_fd_name (char *buf)
28 return strcpy (buf, "anon_inode:[signalfd]");
31 int
32 fhandler_signalfd::signalfd (const sigset_t *mask, int flags)
34 __try
36 sigset = *mask & ~(SIGKILL | SIGSTOP);
38 __except (EINVAL)
40 return -1;
42 __endtry
43 if (flags & SFD_NONBLOCK)
44 set_nonblocking (true);
45 if (flags & SFD_CLOEXEC)
46 set_close_on_exec (true);
47 if (get_unique_id () == 0)
49 nohandle (true);
50 set_unique_id ();
51 set_ino (get_unique_id ());
52 set_flags (O_RDWR | O_BINARY);
54 return 0;
57 int
58 fhandler_signalfd::fstat (struct stat *buf)
60 int ret = fhandler_base::fstat (buf);
61 if (!ret)
63 buf->st_mode = S_IRUSR | S_IWUSR;
64 buf->st_dev = FH_SIGNALFD;
65 buf->st_ino = get_unique_id ();
67 return ret;
70 static inline void
71 copy_siginfo_to_signalfd (struct signalfd_siginfo *sfd,
72 const siginfo_t * const si)
74 sfd->ssi_signo = si->si_signo;
75 sfd->ssi_errno = si->si_errno;
76 sfd->ssi_code = si->si_code;
77 sfd->ssi_pid = si->si_pid;
78 sfd->ssi_uid = si->si_uid;
79 sfd->ssi_fd = -1;
80 sfd->ssi_tid = si->si_tid;
81 sfd->ssi_band = 0;
82 sfd->ssi_overrun = si->si_overrun;
83 sfd->ssi_trapno = 0;
84 sfd->ssi_status = si->si_status;
85 sfd->ssi_int = si->si_value.sival_int;
86 sfd->ssi_ptr = (uint64_t) si->si_value.sival_ptr;
87 sfd->ssi_utime = si->si_utime;
88 sfd->ssi_stime = si->si_stime;
89 sfd->ssi_addr = (uint64_t) si->si_addr;
92 void
93 fhandler_signalfd::read (void *ptr, size_t& len)
95 const LARGE_INTEGER poll = { QuadPart : 0 };
96 siginfo_t si;
97 int ret, old_errno;
98 size_t curlen = 0;
99 signalfd_siginfo *sfd_ptr = (signalfd_siginfo *) ptr;
101 if (len < sizeof (struct signalfd_siginfo))
103 set_errno (EINVAL);
104 len = (size_t) -1;
105 return;
107 old_errno = get_errno ();
110 /* Even when read is blocking, only one pending signal is actually
111 required to return. Subsequently use sigtimedwait to just poll
112 if some more signal is available. */
113 ret = sigwait_common (&sigset, &si, (is_nonblocking () || curlen)
114 ? (PLARGE_INTEGER) &poll : NULL);
115 if (ret == -1)
117 /* If we already read a signal so the buffer isn't empty, just
118 return success. */
119 if (curlen > 0)
120 break;
121 len = -1;
122 return;
124 __try
126 copy_siginfo_to_signalfd (sfd_ptr, &si);
128 __except (EFAULT)
130 len = (size_t) -1;
131 return;
133 __endtry
134 sfd_ptr++;
135 curlen += sizeof (*sfd_ptr);
137 while ((len - curlen >= sizeof (struct signalfd_siginfo)));
138 set_errno (old_errno);
139 len = curlen;
140 return;
143 ssize_t
144 fhandler_signalfd::write (const void *, size_t)
146 set_errno (EINVAL);
147 return -1;
150 /* Called from select */
152 fhandler_signalfd::poll ()
154 sigset_t outset = sig_send (myself, __SIGPENDING, &_my_tls);
155 if (outset == SIG_BAD_MASK)
156 return -1;
157 if ((outset & sigset) != 0)
158 return 0;
159 return -1;