Page MenuHomeFreeBSD

D40791.id123922.diff
No OneTemporary

D40791.id123922.diff

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

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)

Event Timeline