Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F156518911
D40791.id123922.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
24 KB
Referenced Files
None
Subscribers
None
D40791.id123922.diff
View Options
diff --git a/lib/libc/sys/Symbol.map b/lib/libc/sys/Symbol.map
--- a/lib/libc/sys/Symbol.map
+++ b/lib/libc/sys/Symbol.map
@@ -420,6 +420,7 @@
_Fork;
fspacectl;
kqueuex;
+ signalfd;
swapoff;
timerfd_create;
timerfd_gettime;
diff --git a/sys/bsm/audit_kevents.h b/sys/bsm/audit_kevents.h
--- a/sys/bsm/audit_kevents.h
+++ b/sys/bsm/audit_kevents.h
@@ -664,6 +664,7 @@
#define AUE_AIO_READV 43268 /* FreeBSD-specific. */
#define AUE_FSPACECTL 43269 /* FreeBSD-specific. */
#define AUE_TIMERFD 43270 /* FreeBSD/Linux. */
+#define AUE_SIGNALFD 43271 /* FreeBSD/Linux. */
/*
* Darwin BSM uses a number of AUE_O_* definitions, which are aliased to the
diff --git a/sys/compat/freebsd32/freebsd32_syscall.h b/sys/compat/freebsd32/freebsd32_syscall.h
--- a/sys/compat/freebsd32/freebsd32_syscall.h
+++ b/sys/compat/freebsd32/freebsd32_syscall.h
@@ -504,4 +504,5 @@
#define FREEBSD32_SYS_timerfd_create 584
#define FREEBSD32_SYS_freebsd32_timerfd_gettime 585
#define FREEBSD32_SYS_freebsd32_timerfd_settime 586
-#define FREEBSD32_SYS_MAXSYSCALL 587
+#define FREEBSD32_SYS_signalfd 587
+#define FREEBSD32_SYS_MAXSYSCALL 588
diff --git a/sys/compat/freebsd32/freebsd32_syscalls.c b/sys/compat/freebsd32/freebsd32_syscalls.c
--- a/sys/compat/freebsd32/freebsd32_syscalls.c
+++ b/sys/compat/freebsd32/freebsd32_syscalls.c
@@ -592,4 +592,5 @@
"timerfd_create", /* 584 = timerfd_create */
"freebsd32_timerfd_gettime", /* 585 = freebsd32_timerfd_gettime */
"freebsd32_timerfd_settime", /* 586 = freebsd32_timerfd_settime */
+ "signalfd", /* 587 = signalfd */
};
diff --git a/sys/compat/freebsd32/freebsd32_sysent.c b/sys/compat/freebsd32/freebsd32_sysent.c
--- a/sys/compat/freebsd32/freebsd32_sysent.c
+++ b/sys/compat/freebsd32/freebsd32_sysent.c
@@ -648,4 +648,5 @@
{ .sy_narg = AS(timerfd_create_args), .sy_call = (sy_call_t *)sys_timerfd_create, .sy_auevent = AUE_TIMERFD, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 584 = timerfd_create */
{ .sy_narg = AS(freebsd32_timerfd_gettime_args), .sy_call = (sy_call_t *)freebsd32_timerfd_gettime, .sy_auevent = AUE_TIMERFD, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 585 = freebsd32_timerfd_gettime */
{ .sy_narg = AS(freebsd32_timerfd_settime_args), .sy_call = (sy_call_t *)freebsd32_timerfd_settime, .sy_auevent = AUE_TIMERFD, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 586 = freebsd32_timerfd_settime */
+ { .sy_narg = AS(signalfd_args), .sy_call = (sy_call_t *)sys_signalfd, .sy_auevent = AUE_SIGNALFD, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 587 = signalfd */
};
diff --git a/sys/compat/freebsd32/freebsd32_systrace_args.c b/sys/compat/freebsd32/freebsd32_systrace_args.c
--- a/sys/compat/freebsd32/freebsd32_systrace_args.c
+++ b/sys/compat/freebsd32/freebsd32_systrace_args.c
@@ -3353,6 +3353,15 @@
*n_args = 4;
break;
}
+ /* signalfd */
+ case 587: {
+ struct signalfd_args *p = params;
+ iarg[a++] = p->fd; /* int */
+ uarg[a++] = (intptr_t)p->mask; /* const sigset_t * */
+ iarg[a++] = p->flags; /* int */
+ *n_args = 3;
+ break;
+ }
default:
*n_args = 0;
break;
@@ -9051,6 +9060,22 @@
break;
};
break;
+ /* signalfd */
+ case 587:
+ switch (ndx) {
+ case 0:
+ p = "int";
+ break;
+ case 1:
+ p = "userland const sigset_t *";
+ break;
+ case 2:
+ p = "int";
+ break;
+ default:
+ break;
+ };
+ break;
default:
break;
};
@@ -10929,6 +10954,11 @@
if (ndx == 0 || ndx == 1)
p = "int";
break;
+ /* signalfd */
+ case 587:
+ if (ndx == 0 || ndx == 1)
+ p = "int";
+ break;
default:
break;
};
diff --git a/sys/conf/files b/sys/conf/files
--- a/sys/conf/files
+++ b/sys/conf/files
@@ -3918,6 +3918,7 @@
kern/sys_pipe.c standard
kern/sys_procdesc.c standard
kern/sys_process.c standard
+kern/sys_signalfd.c standard
kern/sys_socket.c standard
kern/sys_timerfd.c standard
kern/syscalls.c standard
diff --git a/sys/kern/init_sysent.c b/sys/kern/init_sysent.c
--- a/sys/kern/init_sysent.c
+++ b/sys/kern/init_sysent.c
@@ -647,4 +647,5 @@
{ .sy_narg = AS(timerfd_create_args), .sy_call = (sy_call_t *)sys_timerfd_create, .sy_auevent = AUE_TIMERFD, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 584 = timerfd_create */
{ .sy_narg = AS(timerfd_gettime_args), .sy_call = (sy_call_t *)sys_timerfd_gettime, .sy_auevent = AUE_TIMERFD, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 585 = timerfd_gettime */
{ .sy_narg = AS(timerfd_settime_args), .sy_call = (sy_call_t *)sys_timerfd_settime, .sy_auevent = AUE_TIMERFD, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 586 = timerfd_settime */
+ { .sy_narg = AS(signalfd_args), .sy_call = (sy_call_t *)sys_signalfd, .sy_auevent = AUE_SIGNALFD, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 587 = signalfd */
};
diff --git a/sys/kern/kern_sig.c b/sys/kern/kern_sig.c
--- a/sys/kern/kern_sig.c
+++ b/sys/kern/kern_sig.c
@@ -73,6 +73,7 @@
#include <sys/resourcevar.h>
#include <sys/sdt.h>
#include <sys/sbuf.h>
+#include <sys/signalfd.h>
#include <sys/sleepqueue.h>
#include <sys/smp.h>
#include <sys/stat.h>
@@ -2284,13 +2285,16 @@
/*
* If the signal is being ignored, then we forget about it
- * immediately, except when the target process executes
- * sigwait(). (Note: we don't set SIGCONT in ps_sigignore,
- * and if it is set to SIG_IGN, action will be SIG_DFL here.)
+ * immediately, except when the target process has an active
+ * signalfd or executes sigwait(). (Note: we don't set
+ * SIGCONT in ps_sigignore, and if it is set to SIG_IGN,
+ * action will be SIG_DFL here.)
*/
mtx_lock(&ps->ps_mtx);
if (SIGISMEMBER(ps->ps_sigignore, sig)) {
- if (kern_sig_discard_ign &&
+ if (!LIST_EMPTY(&p->p_sfd)) {
+ action = SIG_HOLD;
+ } else if (kern_sig_discard_ign &&
(p->p_sysent->sv_flags & SV_SIG_DISCIGN) == 0) {
SDT_PROBE3(proc, , , signal__discard, td, p, sig);
@@ -2344,6 +2348,8 @@
ret = sigqueue_add(sigqueue, sig, ksi);
if (ret != 0)
return (ret);
+ if (!LIST_EMPTY(&p->p_sfd) && action != SIG_CATCH)
+ signalfd_post(p, sig);
signotify(td);
/*
* Defer further processing for signals which are held,
diff --git a/sys/kern/kern_thread.c b/sys/kern/kern_thread.c
--- a/sys/kern/kern_thread.c
+++ b/sys/kern/kern_thread.c
@@ -97,11 +97,11 @@
"struct proc KBI p_flag");
_Static_assert(offsetof(struct proc, p_pid) == 0xc4,
"struct proc KBI p_pid");
-_Static_assert(offsetof(struct proc, p_filemon) == 0x3c8,
+_Static_assert(offsetof(struct proc, p_filemon) == 0x3d0,
"struct proc KBI p_filemon");
-_Static_assert(offsetof(struct proc, p_comm) == 0x3e0,
+_Static_assert(offsetof(struct proc, p_comm) == 0x3e8,
"struct proc KBI p_comm");
-_Static_assert(offsetof(struct proc, p_emuldata) == 0x4d0,
+_Static_assert(offsetof(struct proc, p_emuldata) == 0x4d8,
"struct proc KBI p_emuldata");
#endif
#ifdef __i386__
@@ -117,11 +117,11 @@
"struct proc KBI p_flag");
_Static_assert(offsetof(struct proc, p_pid) == 0x78,
"struct proc KBI p_pid");
-_Static_assert(offsetof(struct proc, p_filemon) == 0x270,
+_Static_assert(offsetof(struct proc, p_filemon) == 0x274,
"struct proc KBI p_filemon");
-_Static_assert(offsetof(struct proc, p_comm) == 0x284,
+_Static_assert(offsetof(struct proc, p_comm) == 0x288,
"struct proc KBI p_comm");
-_Static_assert(offsetof(struct proc, p_emuldata) == 0x318,
+_Static_assert(offsetof(struct proc, p_emuldata) == 0x31c,
"struct proc KBI p_emuldata");
#endif
diff --git a/sys/kern/sys_signalfd.c b/sys/kern/sys_signalfd.c
new file mode 100644
--- /dev/null
+++ b/sys/kern/sys_signalfd.c
@@ -0,0 +1,382 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2023 Jake Freeland <jfree@FreeBSD.org>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/param.h>
+#include <sys/event.h>
+#include <sys/file.h>
+#include <sys/filedesc.h>
+#include <sys/filio.h>
+#include <sys/kernel.h>
+#include <sys/malloc.h>
+#include <sys/mutex.h>
+#include <sys/poll.h>
+#include <sys/selinfo.h>
+#include <sys/signalfd.h>
+#include <sys/signalvar.h>
+#include <sys/stat.h>
+#include <sys/sysproto.h>
+#include <sys/uio.h>
+#include <sys/user.h>
+
+static MALLOC_DEFINE(M_SIGNALFD, "signalfd", "signalfd structures");
+
+struct signalfd {
+ sigset_t sfd_mask;
+ int sfd_flags;
+ struct mtx sfd_lock;
+ struct selinfo sfd_sel;
+ LIST_ENTRY(signalfd) sfd_link;
+};
+
+void
+signalfd_post(struct proc *p, int signo)
+{
+ struct signalfd *sfd;
+ if (signo == SIGKILL || signo == SIGSTOP)
+ return;
+ LIST_FOREACH(sfd, &p->p_sfd, sfd_link) {
+ mtx_lock(&sfd->sfd_lock);
+ if (SIGISMEMBER(sfd->sfd_mask, signo))
+ wakeup(&sfd->sfd_mask);
+ mtx_unlock(&sfd->sfd_lock);
+ }
+}
+
+static bool
+signalfd_pending(struct proc *p, struct signalfd *sfd)
+{
+ int sig;
+ SIG_FOREACH(sig, &p->p_siglist) {
+ if (SIGISMEMBER(sfd->sfd_mask, sig))
+ return (true);
+ }
+ return (false);
+}
+
+static void
+sitossi(siginfo_t *si, struct signalfd_siginfo *ssi)
+{
+ _Static_assert(sizeof(*ssi) == 128, "signalfd_siginfo");
+ ssi->ssi_signo = si->si_signo;
+ ssi->ssi_errno = si->si_errno;
+ ssi->ssi_code = si->si_code;
+ ssi->ssi_pid = si->si_pid;
+ ssi->ssi_uid = si->si_uid;
+ ssi->ssi_status = si->si_status;
+ ssi->ssi_addr = (uint64_t)(uintptr_t)si->si_addr;
+ ssi->ssi_int = si->si_value.sival_int;
+ ssi->ssi_ptr = (uint64_t)(uintptr_t)si->si_value.sival_ptr;
+ ssi->ssi_addr_lsb = ssi->ssi_addr & 0x1;
+
+ /* Linux-specific fields. Extend later, if applicable. */
+ ssi->ssi_fd = -1;
+ /* ssi->ssi_utime = si-> */
+ /* ssi->ssi_stime = si-> */
+ ssi->ssi_call_addr = (uint64_t)(uintptr_t)NULL;
+ /* ssi->ssi_arch = si-> */
+
+ /* Unioned fields. Only one at a time. */
+ if (si->si_signo == SIGBUS) {
+ ssi->ssi_trapno = si->si_trapno;
+ } else if (si->si_code == SI_TIMER) {
+ ssi->ssi_tid = si->si_timerid;
+ ssi->ssi_overrun = si->si_overrun;
+ } else if (si->si_code == SI_MESGQ) {
+ ssi->ssi_fd = si->si_mqd;
+ } else if (si->si_signo == SIGIO) {
+ ssi->ssi_band = si->si_band;
+ } else if (si->si_code == TRAP_CAP) {
+ ssi->ssi_syscall = si->si_syscall;
+ }
+}
+
+static int
+signalfd_read(struct file *fp, struct uio *uio, struct ucred *active_cred,
+ int flags, struct thread *td)
+{
+ struct signalfd *sfd = fp->f_data;
+ struct signalfd_siginfo ssi;
+ struct proc *p = td->td_proc;
+ sigqueue_t *sq = &p->p_sigqueue;
+ ksiginfo_t *ksi, *next;
+ int error = 0;
+
+ if (uio->uio_resid < sizeof(struct signalfd_siginfo))
+ return (EINVAL);
+
+retry:
+ PROC_LOCK(p);
+ mtx_lock(&sfd->sfd_lock);
+ if (!signalfd_pending(p, sfd)) {
+ if ((fp->f_flag & O_NONBLOCK) != 0) {
+ error = EAGAIN;
+ goto out;
+ }
+ PROC_UNLOCK(p);
+ error = mtx_sleep(&sfd->sfd_mask, &sfd->sfd_lock,
+ PCATCH | PDROP, "sfdrd", 0);
+ if (error != 0)
+ return (error);
+ goto retry;
+ }
+
+ TAILQ_FOREACH_SAFE(ksi, &sq->sq_list, ksi_link, next) {
+ if (SIGISMEMBER(sfd->sfd_mask, ksi->ksi_signo)) {
+ sitossi(&ksi->ksi_info, &ssi);
+ error = uiomove_nofault(&ssi, sizeof(ssi), uio);
+ if (error != 0)
+ goto out;
+ TAILQ_REMOVE(&sq->sq_list, ksi, ksi_link);
+ ksi->ksi_sigq = NULL;
+ if ((ksi->ksi_flags & KSI_EXT) == 0) {
+ ksiginfo_free(ksi);
+ --p->p_pendingcnt;
+ }
+ }
+ }
+ SIGSETNAND(sq->sq_kill, sfd->sfd_mask);
+ SIGSETNAND(sq->sq_ptrace, sfd->sfd_mask);
+ SIGSETNAND(sq->sq_signals, sfd->sfd_mask);
+
+out:
+ mtx_unlock(&sfd->sfd_lock);
+ PROC_UNLOCK(p);
+ return (error);
+}
+
+static int
+signalfd_ioctl(struct file *fp, u_long cmd, void *data,
+ struct ucred *active_cred, struct thread *td)
+{
+ switch (cmd) {
+ case FIOASYNC:
+ if (*(int *)data != 0)
+ atomic_set_int(&fp->f_flag, O_ASYNC);
+ else
+ atomic_clear_int(&fp->f_flag, O_ASYNC);
+ return (0);
+ case FIONBIO:
+ if (*(int *)data != 0)
+ atomic_set_int(&fp->f_flag, O_NONBLOCK);
+ else
+ atomic_clear_int(&fp->f_flag, O_NONBLOCK);
+ return (0);
+ }
+ return (ENOTTY);
+}
+
+static int
+signalfd_poll(struct file *fp, int events, struct ucred *active_cred,
+ struct thread *td)
+{
+ struct proc *p = td->td_proc;
+ struct signalfd *sfd = fp->f_data;
+ int revents = 0;
+
+ PROC_LOCK(p);
+ mtx_lock(&sfd->sfd_lock);
+ if ((events & (POLLIN | POLLRDNORM)) != 0 &&
+ signalfd_pending(p, sfd))
+ revents |= events & (POLLIN | POLLRDNORM);
+
+ if (revents == 0)
+ selrecord(td, &sfd->sfd_sel);
+ mtx_unlock(&sfd->sfd_lock);
+ PROC_UNLOCK(p);
+ return (revents);
+}
+
+static void
+filt_signalfddetach(struct knote *kn)
+{
+ struct signalfd *sfd = kn->kn_hook;
+
+ mtx_lock(&sfd->sfd_lock);
+ knlist_remove(&sfd->sfd_sel.si_note, kn, 1);
+ mtx_unlock(&sfd->sfd_lock);
+}
+
+static int
+filt_signalfdread(struct knote *kn, long hint)
+{
+ struct signalfd *sfd = kn->kn_hook;
+ return (signalfd_pending(curthread->td_proc, sfd));
+}
+
+static struct filterops signalfd_rfiltops = {
+ .f_isfd = 1,
+ .f_detach = filt_signalfddetach,
+ .f_event = filt_signalfdread,
+};
+
+static int
+signalfd_kqfilter(struct file *fp, struct knote *kn)
+{
+ struct signalfd *sfd = fp->f_data;
+
+ if (kn->kn_filter != EVFILT_READ)
+ return (EINVAL);
+
+ kn->kn_fop = &signalfd_rfiltops;
+ kn->kn_hook = sfd;
+ knlist_add(&sfd->sfd_sel.si_note, kn, 0);
+
+ return (0);
+}
+
+static int
+signalfd_stat(struct file *fp, struct stat *sb, struct ucred *active_cred)
+{
+ bzero(sb, sizeof(*sb));
+ sb->st_nlink = fp->f_count - 1;
+ sb->st_uid = fp->f_cred->cr_uid;
+ sb->st_gid = fp->f_cred->cr_gid;
+ sb->st_blksize = PAGE_SIZE;
+ return (0);
+}
+
+static int
+signalfd_close(struct file *fp, struct thread *td)
+{
+ struct proc *p = td->td_proc;
+ struct signalfd *sfd = fp->f_data;
+
+ PROC_LOCK(p);
+ LIST_REMOVE(sfd, sfd_link);
+ PROC_UNLOCK(p);
+ seldrain(&sfd->sfd_sel);
+ knlist_destroy(&sfd->sfd_sel.si_note);
+ mtx_destroy(&sfd->sfd_lock);
+ free(sfd, M_SIGNALFD);
+ fp->f_ops = &badfileops;
+
+ return (0);
+}
+
+static int
+signalfd_fill_kinfo(struct file *fp, struct kinfo_file *kif,
+ struct filedesc *fdp)
+{
+
+ struct signalfd *sfd = fp->f_data;
+
+ kif->kf_type = KF_TYPE_SIGNALFD;
+ mtx_lock(&sfd->sfd_lock);
+ kif->kf_un.kf_signalfd.kf_signalfd_mask = (uintptr_t)&sfd->sfd_mask;
+ kif->kf_un.kf_signalfd.kf_signalfd_flags = sfd->sfd_flags;
+ kif->kf_un.kf_signalfd.kf_signalfd_addr = (uintptr_t)sfd;
+ mtx_unlock(&sfd->sfd_lock);
+
+ return (0);
+}
+
+static struct fileops signalfdops = {
+ .fo_read = signalfd_read,
+ .fo_write = invfo_rdwr,
+ .fo_truncate = invfo_truncate,
+ .fo_ioctl = signalfd_ioctl,
+ .fo_poll = signalfd_poll,
+ .fo_kqfilter = signalfd_kqfilter,
+ .fo_stat = signalfd_stat,
+ .fo_close = signalfd_close,
+ .fo_chmod = invfo_chmod,
+ .fo_chown = invfo_chown,
+ .fo_sendfile = invfo_sendfile,
+ .fo_fill_kinfo = signalfd_fill_kinfo,
+ .fo_flags = DFLAG_PASSABLE,
+};
+
+int
+kern_signalfd(struct thread *td, int fd, const sigset_t *mask, int flags)
+{
+ struct proc *p = td->td_proc;
+ struct signalfd *sfd;
+ struct file *fp;
+ int error, fflags = 0;
+ bool new = fd == -1 ? true : false;
+
+ if ((flags & ~(SFD_NONBLOCK | SFD_CLOEXEC)) != 0)
+ return (EINVAL);
+ if ((flags & SFD_CLOEXEC) != 0)
+ fflags |= O_CLOEXEC;
+
+ if (new) {
+ sfd = malloc(sizeof(*sfd), M_SIGNALFD, M_WAITOK | M_ZERO);
+ if (sfd == NULL)
+ return (ENOMEM);
+ mtx_init(&sfd->sfd_lock, "signalfd", NULL, MTX_DEF);
+ knlist_init_mtx(&sfd->sfd_sel.si_note, &sfd->sfd_lock);
+
+ error = falloc(td, &fp, &fd, fflags);
+ if (error != 0)
+ return (error);
+ fflags = FREAD;
+ if ((flags & SFD_NONBLOCK) != 0)
+ fflags |= O_NONBLOCK;
+ finit(fp, fflags, DTYPE_SIGNALFD, sfd, &signalfdops);
+ } else {
+ error = fget(td, fd, &cap_write_rights, &fp);
+ if (error != 0)
+ return (error);
+ sfd = fp->f_data;
+ if (sfd == NULL || fp->f_type != DTYPE_SIGNALFD) {
+ fdrop(fp, td);
+ return (EINVAL);
+ }
+ mtx_lock(&sfd->sfd_lock);
+ if ((flags & SFD_NONBLOCK) != 0)
+ fp->f_flag |= O_NONBLOCK;
+ else
+ fp->f_flag &= ~O_NONBLOCK;
+ }
+ sfd->sfd_mask = *mask;
+ SIG_CANTMASK(sfd->sfd_mask);
+ sfd->sfd_flags = flags;
+ if (new) {
+ PROC_LOCK(p);
+ LIST_INSERT_HEAD(&p->p_sfd, sfd, sfd_link);
+ PROC_UNLOCK(p);
+ } else {
+ mtx_unlock(&sfd->sfd_lock);
+ }
+
+ fdrop(fp, td);
+ td->td_retval[0] = fd;
+ return (0);
+}
+
+int
+sys_signalfd(struct thread *td, struct signalfd_args *uap)
+{
+ sigset_t mask;
+ int error;
+
+ error = copyin(uap->mask, &mask, sizeof(mask));
+ if (error != 0)
+ return (error);
+ return (kern_signalfd(td, uap->fd, &mask, uap->flags));
+}
diff --git a/sys/kern/syscalls.c b/sys/kern/syscalls.c
--- a/sys/kern/syscalls.c
+++ b/sys/kern/syscalls.c
@@ -592,4 +592,5 @@
"timerfd_create", /* 584 = timerfd_create */
"timerfd_gettime", /* 585 = timerfd_gettime */
"timerfd_settime", /* 586 = timerfd_settime */
+ "signalfd", /* 587 = signalfd */
};
diff --git a/sys/kern/syscalls.master b/sys/kern/syscalls.master
--- a/sys/kern/syscalls.master
+++ b/sys/kern/syscalls.master
@@ -3333,5 +3333,12 @@
_Out_opt_ _Contains_long_timet_ struct itimerspec *old_value
);
}
+587 AUE_SIGNALFD STD|CAPENABLED {
+ int signalfd(
+ int fd,
+ _In_ const sigset_t *mask,
+ int flags
+ );
+ }
; vim: syntax=off
diff --git a/sys/kern/systrace_args.c b/sys/kern/systrace_args.c
--- a/sys/kern/systrace_args.c
+++ b/sys/kern/systrace_args.c
@@ -3449,6 +3449,15 @@
*n_args = 4;
break;
}
+ /* signalfd */
+ case 587: {
+ struct signalfd_args *p = params;
+ iarg[a++] = p->fd; /* int */
+ uarg[a++] = (intptr_t)p->mask; /* const sigset_t * */
+ iarg[a++] = p->flags; /* int */
+ *n_args = 3;
+ break;
+ }
default:
*n_args = 0;
break;
@@ -9221,6 +9230,22 @@
break;
};
break;
+ /* signalfd */
+ case 587:
+ switch (ndx) {
+ case 0:
+ p = "int";
+ break;
+ case 1:
+ p = "userland const sigset_t *";
+ break;
+ case 2:
+ p = "int";
+ break;
+ default:
+ break;
+ };
+ break;
default:
break;
};
@@ -11194,6 +11219,11 @@
if (ndx == 0 || ndx == 1)
p = "int";
break;
+ /* signalfd */
+ case 587:
+ if (ndx == 0 || ndx == 1)
+ p = "int";
+ break;
default:
break;
};
diff --git a/sys/sys/file.h b/sys/sys/file.h
--- a/sys/sys/file.h
+++ b/sys/sys/file.h
@@ -71,6 +71,7 @@
#define DTYPE_PROCDESC 12 /* process descriptor */
#define DTYPE_EVENTFD 13 /* eventfd */
#define DTYPE_TIMERFD 14 /* timerfd */
+#define DTYPE_SIGNALFD 15 /* signalfd */
#ifdef _KERNEL
diff --git a/sys/sys/proc.h b/sys/sys/proc.h
--- a/sys/sys/proc.h
+++ b/sys/sys/proc.h
@@ -707,6 +707,7 @@
struct sigiolst p_sigiolst; /* (c) List of sigio sources. */
int p_sigparent; /* (c) Signal to parent on exit. */
int p_sig; /* (n) For core dump/debugger XXX. */
+ LIST_HEAD(, signalfd) p_sfd; /* (c) Sig descriptor queue. */
u_int p_ptevents; /* (c + e) ptrace() event mask. */
struct kaioinfo *p_aioinfo; /* (y) ASYNC I/O info. */
struct thread *p_singlethread;/* (c + j) If single threading this is it */
diff --git a/sys/sys/signalfd.h b/sys/sys/signalfd.h
new file mode 100644
--- /dev/null
+++ b/sys/sys/signalfd.h
@@ -0,0 +1,80 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2023 Jake Freeland <jfree@FreeBSD.org>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef _SYS_SIGNALFD_H_
+#define _SYS_SIGNALFD_H_
+
+#include <sys/types.h>
+#include <sys/fcntl.h>
+#include <sys/proc.h>
+#include <sys/selinfo.h>
+
+/* Creation flags. */
+#define SFD_NONBLOCK O_NONBLOCK
+#define SFD_CLOEXEC O_CLOEXEC
+
+/* Signal information returned by signalfd. */
+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;
+ uint16_t ssi_addr_lsb;
+ uint16_t __pad2;
+ int32_t ssi_syscall;
+ uint64_t ssi_call_addr;
+ uint32_t ssi_arch;
+ uint8_t __pad[28];
+ /* sizeof(struct signalfd_siginfo) must be 128. */
+};
+
+#ifndef _KERNEL
+
+__BEGIN_DECLS
+int signalfd(int fd, const sigset_t *mask, int flags);
+__END_DECLS
+
+#else /* _KERNEL */
+
+int kern_signalfd(struct thread *td, int fd, const sigset_t *mask, int flags);
+void signalfd_post(struct proc *p, int signo);
+
+#endif /* !_KERNEL */
+
+#endif /* !_SYS_SIGNALFD_H_ */
diff --git a/sys/sys/syscall.h b/sys/sys/syscall.h
--- a/sys/sys/syscall.h
+++ b/sys/sys/syscall.h
@@ -523,4 +523,5 @@
#define SYS_timerfd_create 584
#define SYS_timerfd_gettime 585
#define SYS_timerfd_settime 586
-#define SYS_MAXSYSCALL 587
+#define SYS_signalfd 587
+#define SYS_MAXSYSCALL 588
diff --git a/sys/sys/syscall.mk b/sys/sys/syscall.mk
--- a/sys/sys/syscall.mk
+++ b/sys/sys/syscall.mk
@@ -428,4 +428,5 @@
kqueuex.o \
timerfd_create.o \
timerfd_gettime.o \
- timerfd_settime.o
+ timerfd_settime.o \
+ signalfd.o
diff --git a/sys/sys/sysproto.h b/sys/sys/sysproto.h
--- a/sys/sys/sysproto.h
+++ b/sys/sys/sysproto.h
@@ -1871,6 +1871,11 @@
char new_value_l_[PADL_(const struct itimerspec *)]; const struct itimerspec * new_value; char new_value_r_[PADR_(const struct itimerspec *)];
char old_value_l_[PADL_(struct itimerspec *)]; struct itimerspec * old_value; char old_value_r_[PADR_(struct itimerspec *)];
};
+struct signalfd_args {
+ char fd_l_[PADL_(int)]; int fd; char fd_r_[PADR_(int)];
+ char mask_l_[PADL_(const sigset_t *)]; const sigset_t * mask; char mask_r_[PADR_(const sigset_t *)];
+ char flags_l_[PADL_(int)]; int flags; char flags_r_[PADR_(int)];
+};
int sys_exit(struct thread *, struct exit_args *);
int sys_fork(struct thread *, struct fork_args *);
int sys_read(struct thread *, struct read_args *);
@@ -2270,6 +2275,7 @@
int sys_timerfd_create(struct thread *, struct timerfd_create_args *);
int sys_timerfd_gettime(struct thread *, struct timerfd_gettime_args *);
int sys_timerfd_settime(struct thread *, struct timerfd_settime_args *);
+int sys_signalfd(struct thread *, struct signalfd_args *);
#ifdef COMPAT_43
@@ -3243,6 +3249,7 @@
#define SYS_AUE_timerfd_create AUE_TIMERFD
#define SYS_AUE_timerfd_gettime AUE_TIMERFD
#define SYS_AUE_timerfd_settime AUE_TIMERFD
+#define SYS_AUE_signalfd AUE_SIGNALFD
#undef PAD_
#undef PADL_
diff --git a/sys/sys/user.h b/sys/sys/user.h
--- a/sys/sys/user.h
+++ b/sys/sys/user.h
@@ -269,6 +269,7 @@
#define KF_TYPE_DEV 12
#define KF_TYPE_EVENTFD 13
#define KF_TYPE_TIMERFD 14
+#define KF_TYPE_SIGNALFD 15
#define KF_TYPE_UNKNOWN 255
#define KF_VTYPE_VNON 0
@@ -455,6 +456,12 @@
uint32_t kf_timerfd_flags;
uint64_t kf_timerfd_addr;
} kf_timerfd;
+ struct {
+ uint64_t kf_signalfd_mask;
+ uint32_t kf_signalfd_flags;
+ uint32_t kf_signalfd_spareint[3];
+ uint64_t kf_signalfd_addr;
+ } kf_signalfd;
struct {
uint64_t kf_kqueue_addr;
int32_t kf_kqueue_count;
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Fri, May 15, 8:44 AM (44 m, 24 s)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
33075772
Default Alt Text
D40791.id123922.diff (24 KB)
Attached To
Mode
D40791: signalfd: Add native support for Linux's signalfd
Attached
Detach File
Event Timeline
Log In to Comment