Page MenuHomeFreeBSD

D12773.diff
No OneTemporary

D12773.diff

Index: head/lib/libc/sys/Makefile.inc
===================================================================
--- head/lib/libc/sys/Makefile.inc
+++ head/lib/libc/sys/Makefile.inc
@@ -317,6 +317,7 @@
shutdown.2 \
sigaction.2 \
sigaltstack.2 \
+ sigfastblock.2 \
sigpending.2 \
sigprocmask.2 \
sigqueue.2 \
Index: head/lib/libc/sys/Symbol.map
===================================================================
--- head/lib/libc/sys/Symbol.map
+++ head/lib/libc/sys/Symbol.map
@@ -567,6 +567,7 @@
__sys_extattr_set_link;
_extattrctl;
__sys_extattrctl;
+ __sys_sigfastblock;
_fchdir;
__sys_fchdir;
_fchflags;
Index: head/lib/libc/sys/sigfastblock.2
===================================================================
--- head/lib/libc/sys/sigfastblock.2
+++ head/lib/libc/sys/sigfastblock.2
@@ -0,0 +1,166 @@
+.\" Copyright (c) 2016 The FreeBSD Foundation, Inc.
+.\"
+.\" This documentation was written by
+.\" Konstantin Belousov <kib@FreeBSD.org> under sponsorship
+.\" from the FreeBSD Foundation.
+.\"
+.\" 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 AUTHORS 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 AUTHORS 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.
+.\"
+.\" $FreeBSD$
+.\"
+.Dd December 13, 2019
+.Dt SIGFASTBLOCK 2
+.Os
+.Sh NAME
+.Nm sigfastblock
+.Nd controls signals blocking with a simple memory write
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In sys/signalvar.h
+.Ft int
+.Fn sigfastblock "int cmd" "void *ptr"
+.Sh DESCRIPTION
+.Bf -symbolic
+This function is not intended for a direct usage by applications.
+The functionality is provided for implementing some optimizations in
+.Xr ld-elf.so.1 8
+and
+.Lb libthr .
+.Ef
+.Pp
+The function configures the kernel facility that allows a thread to
+block asynchronous signals delivery with a single write to userspace
+memory, avoiding overhead of system calls like
+.Xr sigprocmask 2
+for establishing critical sections.
+The C runtime uses it to optimize implementation of async-signal-safe
+functionality.
+.Pp
+A thread might register a
+.Dv sigblock
+variable of type
+.Vt int
+as a location which is consulted by kernel when calculating the
+blocked signal mask for delivery of asynchronous signals.
+If the variable indicates that blocking is requested, then the kernel
+effectively operates as if the mask containing all blockable signals was
+supplied to
+.Xr sigprocmask 2 .
+.Pp
+The variable is supposed to be modified only from the owning thread,
+there is no way to guarantee visibility of update from other thread
+to kernel when signals are delivered.
+.Pp
+Lower bits of the sigblock variable are reserved as flags,
+which might be set or cleared by kernel at arbitrary moments.
+Userspace code should use
+.Xr atomic 9
+operations of incrementing and decrementing by
+.Dv SIGFASTBLOCK_INC
+quantity to recursively block or unblock signals delivery.
+.Pp
+If a signal would be delivered when unmasked, kernel might set the
+.Dv SIGFASTBLOCK_PEND
+.Dq pending signal
+flag in the sigblock variable.
+Userspace should perform
+.Dv SIGFASTBLOCK_UNBLOCK
+operation when clearing the variable if it notes the pending signal
+bit is set, which would deliver the pending signals immediately.
+Otherwise, signals delivery might be postponed.
+.Pp
+The
+.Fa cmd
+argument specifies one of the following operations:
+.Bl -tag -width SIGFASTBLOCK_UNSETPTR
+.It Dv SIGFASTBLOCK_SETPTR
+Register the variable of type
+.Vt int
+at location pointed to by the
+.Fa ptr
+argument as sigblock variable for the calling thread.
+.It Dv SIGFASTBLOCK_UNSETPTR
+Unregister the currently registered sigblock location.
+Kernel stops inferring the blocked mask from non-zero value of its
+blocked count.
+New location can be registered after previous one is deregistered.
+.It Dv SIGFASTBLOCK_UNBLOCK
+If there are pending signals which should be delivered to the calling
+thread, they are delivered before returning from the call.
+The sigblock variable should have zero blocking count, and indicate
+that the pending signal exists.
+Effectively this means that the variable should have the value
+.Dv SIGFASTBLOCK_PEND .
+.El
+.Sh RETURN VALUES
+.Rv -std
+.Sh ERRORS
+The operation may fail with the following errors:
+.Bl -tag -width Er
+.It Bq Er EBUSY
+The
+.Dv SIGFASTBLOCK_SETPTR
+attempted while the sigblock address was already registered.
+The
+.Dv SIGFASTBLOCK_UNBLOCK
+was called while sigblock variable value is not equal to
+.Dv SIGFASTBLOCK_PEND .
+.It Bq Er EINVAL
+The variable address passed to
+.Dv SIGFASTBLOCK_SETPTR
+is not aligned naturally.
+The
+.Dv SIGFASTBLOCK_UNSETPTR
+operation was attempted without prior successfull call to
+.Dv SIGFASTBLOCK_SETPTR .
+.It Bq Er EFAULT
+Attempt to read or write to the sigblock variable failed.
+Note that kernel generates the
+.Dv SIGSEGV
+signal if an attempt to read from the sigblock variable faulted
+during implicit accesses from syscall entry.
+.El
+.Sh SEE ALSO
+.Xr kill 2 ,
+.Xr signal 2 ,
+.Xr sigprocmask 2 ,
+.Xr libthr 3 ,
+.Xr ld-elf.so.1 8
+.Sh STANDARDS
+The
+.Nm
+function is non-standard, although a similar functionality is a common
+optimization provided by several other systems.
+.Sh HISTORY
+The
+.Nm
+function was introduced in
+.Fx 13.0 .
+.Sh BUGS
+The
+.Nm
+symbol is currently not exported by libc, on purpose.
+Consumers should either use the
+.Dv __sys_fast_sigblock
+symbol from the private libc namespace, or utilize
+.Xr syscall 2 .
Index: head/sys/compat/freebsd32/syscalls.master
===================================================================
--- head/sys/compat/freebsd32/syscalls.master
+++ head/sys/compat/freebsd32/syscalls.master
@@ -1159,5 +1159,6 @@
int shmflags, const char *name); }
572 AUE_SHMRENAME NOPROTO { int shm_rename(const char *path_from, \
const char *path_to, int flags); }
+573 AUE_NULL NOPROTO { int sigfastblock(int cmd, uint32_t *ptr); }
; vim: syntax=off
Index: head/sys/kern/capabilities.conf
===================================================================
--- head/sys/kern/capabilities.conf
+++ head/sys/kern/capabilities.conf
@@ -668,6 +668,7 @@
sigaction
sigaltstack
sigblock
+sigfastblock
sigpending
sigprocmask
sigqueue
Index: head/sys/kern/kern_exec.c
===================================================================
--- head/sys/kern/kern_exec.c
+++ head/sys/kern/kern_exec.c
@@ -1025,6 +1025,7 @@
int error;
struct proc *p = imgp->proc;
struct vmspace *vmspace = p->p_vmspace;
+ struct thread *td = curthread;
vm_object_t obj;
struct rlimit rlim_stack;
vm_offset_t sv_minuser, stack_addr;
@@ -1033,6 +1034,10 @@
imgp->vmspace_destroyed = 1;
imgp->sysent = sv;
+
+ td->td_pflags &= ~TDP_SIGFASTBLOCK;
+ td->td_sigblock_ptr = NULL;
+ td->td_sigblock_val = 0;
/* May be called with Giant held */
EVENTHANDLER_DIRECT_INVOKE(process_exec, p, imgp);
Index: head/sys/kern/kern_fork.c
===================================================================
--- head/sys/kern/kern_fork.c
+++ head/sys/kern/kern_fork.c
@@ -563,7 +563,8 @@
* been preserved.
*/
p2->p_flag |= p1->p_flag & P_SUGID;
- td2->td_pflags |= (td->td_pflags & TDP_ALTSTACK) | TDP_FORKING;
+ td2->td_pflags |= (td->td_pflags & (TDP_ALTSTACK |
+ TDP_SIGFASTBLOCK)) | TDP_FORKING;
SESS_LOCK(p1->p_session);
if (p1->p_session->s_ttyvp != NULL && p1->p_flag & P_CONTROLT)
p2->p_flag |= P_CONTROLT;
Index: head/sys/kern/kern_sig.c
===================================================================
--- head/sys/kern/kern_sig.c
+++ head/sys/kern/kern_sig.c
@@ -114,7 +114,7 @@
static int filt_sigattach(struct knote *kn);
static void filt_sigdetach(struct knote *kn);
static int filt_signal(struct knote *kn, long hint);
-static struct thread *sigtd(struct proc *p, int sig, int prop);
+static struct thread *sigtd(struct proc *p, int sig, bool fast_sigblock);
static void sigqueue_start(void);
static uma_zone_t ksiginfo_zone = NULL;
@@ -238,7 +238,7 @@
[SIGUSR2] = SIGPROP_KILL,
};
-static void reschedule_signals(struct proc *p, sigset_t block, int flags);
+sigset_t fastblock_mask;
static void
sigqueue_start(void)
@@ -249,6 +249,8 @@
p31b_setcfg(CTL_P1003_1B_REALTIME_SIGNALS, _POSIX_REALTIME_SIGNALS);
p31b_setcfg(CTL_P1003_1B_RTSIG_MAX, SIGRTMAX - SIGRTMIN + 1);
p31b_setcfg(CTL_P1003_1B_SIGQUEUE_MAX, max_pending_per_proc);
+ SIGFILLSET(fastblock_mask);
+ SIG_CANTMASK(fastblock_mask);
}
ksiginfo_t *
@@ -1995,8 +1997,8 @@
{
struct sigacts *ps;
struct proc *p;
- int sig;
- int code;
+ sigset_t sigmask;
+ int code, sig;
p = td->td_proc;
sig = ksi->ksi_signo;
@@ -2006,8 +2008,11 @@
PROC_LOCK(p);
ps = p->p_sigacts;
mtx_lock(&ps->ps_mtx);
+ sigmask = td->td_sigmask;
+ if (td->td_sigblock_val != 0)
+ SIGSETOR(sigmask, fastblock_mask);
if ((p->p_flag & P_TRACED) == 0 && SIGISMEMBER(ps->ps_sigcatch, sig) &&
- !SIGISMEMBER(td->td_sigmask, sig)) {
+ !SIGISMEMBER(sigmask, sig)) {
#ifdef KTRACE
if (KTRPOINT(curthread, KTR_PSIG))
ktrpsig(sig, ps->ps_sigact[_SIG_IDX(sig)],
@@ -2023,13 +2028,14 @@
* masking the signal or process is ignoring the
* signal.
*/
- if (kern_forcesigexit &&
- (SIGISMEMBER(td->td_sigmask, sig) ||
- ps->ps_sigact[_SIG_IDX(sig)] == SIG_IGN)) {
+ if (kern_forcesigexit && (SIGISMEMBER(sigmask, sig) ||
+ ps->ps_sigact[_SIG_IDX(sig)] == SIG_IGN)) {
SIGDELSET(td->td_sigmask, sig);
SIGDELSET(ps->ps_sigcatch, sig);
SIGDELSET(ps->ps_sigignore, sig);
ps->ps_sigact[_SIG_IDX(sig)] = SIG_DFL;
+ td->td_pflags &= ~TDP_SIGFASTBLOCK;
+ td->td_sigblock_val = 0;
}
mtx_unlock(&ps->ps_mtx);
p->p_sig = sig; /* XXX to verify code */
@@ -2039,21 +2045,24 @@
}
static struct thread *
-sigtd(struct proc *p, int sig, int prop)
+sigtd(struct proc *p, int sig, bool fast_sigblock)
{
struct thread *td, *signal_td;
PROC_LOCK_ASSERT(p, MA_OWNED);
+ MPASS(!fast_sigblock || p == curproc);
/*
* Check if current thread can handle the signal without
* switching context to another thread.
*/
- if (curproc == p && !SIGISMEMBER(curthread->td_sigmask, sig))
+ if (curproc == p && !SIGISMEMBER(curthread->td_sigmask, sig) &&
+ (!fast_sigblock || curthread->td_sigblock_val == 0))
return (curthread);
signal_td = NULL;
FOREACH_THREAD_IN_PROC(p, td) {
- if (!SIGISMEMBER(td->td_sigmask, sig)) {
+ if (!SIGISMEMBER(td->td_sigmask, sig) && (!fast_sigblock ||
+ td != curthread || td->td_sigblock_val == 0)) {
signal_td = td;
break;
}
@@ -2167,7 +2176,7 @@
prop = sigprop(sig);
if (td == NULL) {
- td = sigtd(p, sig, prop);
+ td = sigtd(p, sig, false);
sigqueue = &p->p_sigqueue;
} else
sigqueue = &td->td_sigqueue;
@@ -2562,7 +2571,6 @@
struct proc *p = td->td_proc;
struct thread *td2;
ksiginfo_t ksi;
- int prop;
PROC_LOCK_ASSERT(p, MA_OWNED);
KASSERT(!(p->p_flag & P_WEXIT), ("Stopping exiting process"));
@@ -2659,8 +2667,7 @@
ksiginfo_init(&ksi);
ksi.ksi_signo = td->td_xsig;
ksi.ksi_flags |= KSI_PTRACE;
- prop = sigprop(td->td_xsig);
- td2 = sigtd(p, td->td_xsig, prop);
+ td2 = sigtd(p, td->td_xsig, false);
tdsendsignal(p, td2, td->td_xsig, &ksi);
if (td != td2)
return (0);
@@ -2669,33 +2676,45 @@
return (td->td_xsig);
}
-static void
+void
reschedule_signals(struct proc *p, sigset_t block, int flags)
{
struct sigacts *ps;
struct thread *td;
int sig;
+ bool fastblk, pslocked;
PROC_LOCK_ASSERT(p, MA_OWNED);
ps = p->p_sigacts;
- mtx_assert(&ps->ps_mtx, (flags & SIGPROCMASK_PS_LOCKED) != 0 ?
- MA_OWNED : MA_NOTOWNED);
+ pslocked = (flags & SIGPROCMASK_PS_LOCKED) != 0;
+ mtx_assert(&ps->ps_mtx, pslocked ? MA_OWNED : MA_NOTOWNED);
if (SIGISEMPTY(p->p_siglist))
return;
SIGSETAND(block, p->p_siglist);
+ fastblk = (flags & SIGPROCMASK_FASTBLK) != 0;
while ((sig = sig_ffs(&block)) != 0) {
SIGDELSET(block, sig);
- td = sigtd(p, sig, 0);
+ td = sigtd(p, sig, fastblk);
+
+ /*
+ * If sigtd() selected us despite sigfastblock is
+ * blocking, do not activate AST or wake us, to avoid
+ * loop in AST handler.
+ */
+ if (fastblk && td == curthread)
+ continue;
+
signotify(td);
- if (!(flags & SIGPROCMASK_PS_LOCKED))
+ if (!pslocked)
mtx_lock(&ps->ps_mtx);
if (p->p_flag & P_TRACED ||
(SIGISMEMBER(ps->ps_sigcatch, sig) &&
- !SIGISMEMBER(td->td_sigmask, sig)))
+ !SIGISMEMBER(td->td_sigmask, sig))) {
tdsigwakeup(td, sig, SIG_CATCH,
(SIGISMEMBER(ps->ps_sigintr, sig) ? EINTR :
- ERESTART));
- if (!(flags & SIGPROCMASK_PS_LOCKED))
+ ERESTART));
+ }
+ if (!pslocked)
mtx_unlock(&ps->ps_mtx);
}
}
@@ -2844,6 +2863,24 @@
SIG_STOPSIGMASK(sigpending);
if (SIGISEMPTY(sigpending)) /* no signal to send */
return (0);
+
+ /*
+ * Do fast sigblock if requested by usermode. Since
+ * we do know that there was a signal pending at this
+ * point, set the FAST_SIGBLOCK_PEND as indicator for
+ * usermode to perform a dummy call to
+ * FAST_SIGBLOCK_UNBLOCK, which causes immediate
+ * delivery of postponed pending signal.
+ */
+ if ((td->td_pflags & TDP_SIGFASTBLOCK) != 0) {
+ if (td->td_sigblock_val != 0)
+ SIGSETNAND(sigpending, fastblock_mask);
+ if (SIGISEMPTY(sigpending)) {
+ td->td_pflags |= TDP_SIGFASTPENDING;
+ return (0);
+ }
+ }
+
if ((p->p_flag & (P_TRACED | P_PPTRACE)) == P_TRACED &&
(p->p_flag2 & P2_PTRACE_FSTP) != 0 &&
SIGISMEMBER(sigpending, SIGSTOP)) {
@@ -3913,4 +3950,119 @@
if ((sigprop(sig) & SIGPROP_IGNORE) != 0)
sigqueue_delete_proc(p, sig);
}
+}
+
+int
+sys_sigfastblock(struct thread *td, struct sigfastblock_args *uap)
+{
+ struct proc *p;
+ int error, res;
+ uint32_t oldval;
+
+ error = 0;
+ switch (uap->cmd) {
+ case SIGFASTBLOCK_SETPTR:
+ if ((td->td_pflags & TDP_SIGFASTBLOCK) != 0) {
+ error = EBUSY;
+ break;
+ }
+ if (((uintptr_t)(uap->ptr) & (sizeof(uint32_t) - 1)) != 0) {
+ error = EINVAL;
+ break;
+ }
+ td->td_pflags |= TDP_SIGFASTBLOCK;
+ td->td_sigblock_ptr = uap->ptr;
+ break;
+
+ case SIGFASTBLOCK_UNBLOCK:
+ if ((td->td_pflags & TDP_SIGFASTBLOCK) != 0) {
+ error = EINVAL;
+ break;
+ }
+again:
+ res = casueword32(td->td_sigblock_ptr, SIGFASTBLOCK_PEND,
+ &oldval, 0);
+ if (res == -1) {
+ error = EFAULT;
+ break;
+ }
+ if (res == 1) {
+ if (oldval != SIGFASTBLOCK_PEND) {
+ error = EBUSY;
+ break;
+ }
+ error = thread_check_susp(td, false);
+ if (error != 0)
+ break;
+ goto again;
+ }
+ td->td_sigblock_val = 0;
+
+ /*
+ * Rely on normal ast mechanism to deliver pending
+ * signals to current thread. But notify others about
+ * fake unblock.
+ */
+ p = td->td_proc;
+ if (error == 0 && p->p_numthreads != 1) {
+ PROC_LOCK(p);
+ reschedule_signals(p, td->td_sigmask, 0);
+ PROC_UNLOCK(p);
+ }
+ break;
+
+ case SIGFASTBLOCK_UNSETPTR:
+ if ((td->td_pflags & TDP_SIGFASTBLOCK) == 0) {
+ error = EINVAL;
+ break;
+ }
+ res = fueword32(td->td_sigblock_ptr, &oldval);
+ if (res == -1) {
+ error = EFAULT;
+ break;
+ }
+ if (oldval != 0 && oldval != SIGFASTBLOCK_PEND) {
+ error = EBUSY;
+ break;
+ }
+ td->td_pflags &= ~TDP_SIGFASTBLOCK;
+ td->td_sigblock_val = 0;
+ break;
+
+ default:
+ error = EINVAL;
+ break;
+ }
+ return (error);
+}
+
+void
+fetch_sigfastblock(struct thread *td)
+{
+
+ if ((td->td_pflags & TDP_SIGFASTBLOCK) == 0)
+ return;
+ if (fueword32(td->td_sigblock_ptr, &td->td_sigblock_val) == -1) {
+ fetch_sigfastblock_failed(td, false);
+ return;
+ }
+ td->td_sigblock_val &= ~SIGFASTBLOCK_FLAGS;
+}
+
+void
+fetch_sigfastblock_failed(struct thread *td, bool write)
+{
+ ksiginfo_t ksi;
+
+ /*
+ * Prevent further fetches and SIGSEGVs, allowing thread to
+ * issue syscalls despite corruption.
+ */
+ td->td_pflags &= ~TDP_SIGFASTBLOCK;
+
+ ksiginfo_init_trap(&ksi);
+ ksi.ksi_signo = SIGSEGV;
+ ksi.ksi_code = write ? SEGV_ACCERR : SEGV_MAPERR;
+ ksi.ksi_addr = td->td_sigblock_ptr;
+ trapsignal(td, &ksi);
}
Index: head/sys/kern/kern_thread.c
===================================================================
--- head/sys/kern/kern_thread.c
+++ head/sys/kern/kern_thread.c
@@ -82,9 +82,9 @@
"struct thread KBI td_flags");
_Static_assert(offsetof(struct thread, td_pflags) == 0x104,
"struct thread KBI td_pflags");
-_Static_assert(offsetof(struct thread, td_frame) == 0x480,
+_Static_assert(offsetof(struct thread, td_frame) == 0x490,
"struct thread KBI td_frame");
-_Static_assert(offsetof(struct thread, td_emuldata) == 0x690,
+_Static_assert(offsetof(struct thread, td_emuldata) == 0x6a0,
"struct thread KBI td_emuldata");
_Static_assert(offsetof(struct proc, p_flag) == 0xb0,
"struct proc KBI p_flag");
@@ -102,9 +102,9 @@
"struct thread KBI td_flags");
_Static_assert(offsetof(struct thread, td_pflags) == 0xa0,
"struct thread KBI td_pflags");
-_Static_assert(offsetof(struct thread, td_frame) == 0x2f0,
+_Static_assert(offsetof(struct thread, td_frame) == 0x2f8,
"struct thread KBI td_frame");
-_Static_assert(offsetof(struct thread, td_emuldata) == 0x338,
+_Static_assert(offsetof(struct thread, td_emuldata) == 0x340,
"struct thread KBI td_emuldata");
_Static_assert(offsetof(struct proc, p_flag) == 0x68,
"struct proc KBI p_flag");
Index: head/sys/kern/subr_syscall.c
===================================================================
--- head/sys/kern/subr_syscall.c
+++ head/sys/kern/subr_syscall.c
@@ -140,6 +140,13 @@
/* Let system calls set td_errno directly. */
td->td_pflags &= ~TDP_NERRNO;
+ /*
+ * Fetch fast sigblock value at the time of syscall
+ * entry because sleepqueue primitives might call
+ * cursig().
+ */
+ fetch_sigfastblock(td);
+
AUDIT_SYSCALL_ENTER(sa->code, td);
error = (sa->callp->sy_call)(td, sa->args);
AUDIT_SYSCALL_EXIT(error, td);
Index: head/sys/kern/subr_trap.c
===================================================================
--- head/sys/kern/subr_trap.c
+++ head/sys/kern/subr_trap.c
@@ -116,12 +116,16 @@
if (p->p_numthreads == 1) {
PROC_LOCK(p);
thread_lock(td);
- if ((p->p_flag & P_PPWAIT) == 0) {
- KASSERT(!SIGPENDING(td) || (td->td_flags &
- (TDF_NEEDSIGCHK | TDF_ASTPENDING)) ==
- (TDF_NEEDSIGCHK | TDF_ASTPENDING),
- ("failed to set signal flags for ast p %p "
- "td %p fl %x", p, td, td->td_flags));
+ if ((p->p_flag & P_PPWAIT) == 0 &&
+ (td->td_pflags & TDP_SIGFASTBLOCK) == 0) {
+ if (SIGPENDING(td) && (td->td_flags &
+ (TDF_NEEDSIGCHK | TDF_ASTPENDING)) !=
+ (TDF_NEEDSIGCHK | TDF_ASTPENDING)) {
+ thread_unlock(td);
+ panic(
+ "failed to set signal flags for ast p %p td %p fl %x",
+ p, td, td->td_flags);
+ }
}
thread_unlock(td);
PROC_UNLOCK(p);
@@ -218,8 +222,8 @@
{
struct thread *td;
struct proc *p;
- int flags;
- int sig;
+ uint32_t oldval;
+ int flags, sig, res;
td = curthread;
p = td->td_proc;
@@ -298,12 +302,16 @@
* the reason for looping check for AST condition.
* See comment in userret() about P_PPWAIT.
*/
- if ((p->p_flag & P_PPWAIT) == 0) {
- KASSERT(!SIGPENDING(td) || (td->td_flags &
- (TDF_NEEDSIGCHK | TDF_ASTPENDING)) ==
- (TDF_NEEDSIGCHK | TDF_ASTPENDING),
- ("failed2 to set signal flags for ast p %p td %p "
- "fl %x %x", p, td, flags, td->td_flags));
+ if ((p->p_flag & P_PPWAIT) == 0 &&
+ (td->td_pflags & TDP_SIGFASTBLOCK) == 0) {
+ if (SIGPENDING(td) && (td->td_flags &
+ (TDF_NEEDSIGCHK | TDF_ASTPENDING)) !=
+ (TDF_NEEDSIGCHK | TDF_ASTPENDING)) {
+ thread_unlock(td); /* fix dumps */
+ panic(
+ "failed2 to set signal flags for ast p %p td %p fl %x %x",
+ p, td, flags, td->td_flags);
+ }
}
thread_unlock(td);
PROC_UNLOCK(p);
@@ -317,15 +325,54 @@
*/
if (flags & TDF_NEEDSIGCHK || p->p_pendingcnt > 0 ||
!SIGISEMPTY(p->p_siglist)) {
+ fetch_sigfastblock(td);
PROC_LOCK(p);
mtx_lock(&p->p_sigacts->ps_mtx);
- while ((sig = cursig(td)) != 0) {
- KASSERT(sig >= 0, ("sig %d", sig));
- postsig(sig);
+ if ((td->td_pflags & TDP_SIGFASTBLOCK) != 0 &&
+ td->td_sigblock_val != 0) {
+ reschedule_signals(p, fastblock_mask,
+ SIGPROCMASK_PS_LOCKED | SIGPROCMASK_FASTBLK);
+ } else {
+ while ((sig = cursig(td)) != 0) {
+ KASSERT(sig >= 0, ("sig %d", sig));
+ postsig(sig);
+ }
}
mtx_unlock(&p->p_sigacts->ps_mtx);
PROC_UNLOCK(p);
}
+
+ /*
+ * Handle deferred update of the fast sigblock value, after
+ * the postsig() loop was performed.
+ */
+ if (td->td_pflags & TDP_SIGFASTPENDING) {
+ td->td_pflags &= ~TDP_SIGFASTPENDING;
+ res = fueword32(td->td_sigblock_ptr, &oldval);
+ if (res == -1) {
+ fetch_sigfastblock_failed(td, false);
+ } else {
+ for (;;) {
+ oldval |= SIGFASTBLOCK_PEND;
+ res = casueword32(td->td_sigblock_ptr, oldval,
+ &oldval, oldval | SIGFASTBLOCK_PEND);
+ if (res == -1) {
+ fetch_sigfastblock_failed(td, true);
+ break;
+ }
+ if (res == 0) {
+ td->td_sigblock_val = oldval &
+ ~SIGFASTBLOCK_FLAGS;
+ break;
+ }
+ MPASS(res == 1);
+ res = thread_check_susp(td, false);
+ if (res != 0)
+ break;
+ }
+ }
+ }
+
/*
* We need to check to see if we have to exit or wait due to a
* single threading requirement or some other STOP condition.
Index: head/sys/kern/syscalls.master
===================================================================
--- head/sys/kern/syscalls.master
+++ head/sys/kern/syscalls.master
@@ -3212,6 +3212,12 @@
int flags
);
}
+573 AUE_NULL STD {
+ int sigfastblock(
+ int cmd,
+ _Inout_opt_ uint32_t *ptr
+ );
+ }
; Please copy any additions and changes to the following compatability tables:
; sys/compat/freebsd32/syscalls.master
Index: head/sys/sys/proc.h
===================================================================
--- head/sys/sys/proc.h
+++ head/sys/sys/proc.h
@@ -322,6 +322,9 @@
uintptr_t td_rb_inact; /* (k) Current in-action mutex loc. */
struct syscall_args td_sa; /* (kx) Syscall parameters. Copied on
fork for child tracing. */
+ void *td_sigblock_ptr; /* (k) uptr for fast sigblock. */
+ uint32_t td_sigblock_val; /* (k) fast sigblock value read at
+ td_sigblock_ptr on kern entry */
#define td_endcopy td_pcb
/*
@@ -486,7 +489,7 @@
#define TDP_ALTSTACK 0x00000020 /* Have alternate signal stack. */
#define TDP_DEADLKTREAT 0x00000040 /* Lock acquisition - deadlock treatment. */
#define TDP_NOFAULTING 0x00000080 /* Do not handle page faults. */
-#define TDP_UNUSED9 0x00000100 /* --available-- */
+#define TDP_SIGFASTBLOCK 0x00000100 /* Fast sigblock active */
#define TDP_OWEUPC 0x00000200 /* Call addupc() at next AST. */
#define TDP_ITHREAD 0x00000400 /* Thread is an interrupt thread. */
#define TDP_SYNCIO 0x00000800 /* Local override, disable async i/o. */
@@ -509,6 +512,7 @@
#define TDP_UIOHELD 0x10000000 /* Current uio has pages held in td_ma */
#define TDP_FORKING 0x20000000 /* Thread is being created through fork() */
#define TDP_EXECVMSPC 0x40000000 /* Execve destroyed old vmspace */
+#define TDP_SIGFASTPENDING 0x80000000 /* Pending signal due to sigfastblock */
/*
* Reasons that the current thread can not be run yet.
Index: head/sys/sys/signalvar.h
===================================================================
--- head/sys/sys/signalvar.h
+++ head/sys/sys/signalvar.h
@@ -256,7 +256,23 @@
/* Flags for ksi_flags */
#define SQ_INIT 0x01
+/*
+ * Fast_sigblock
+ */
+#define SIGFASTBLOCK_SETPTR 1
+#define SIGFASTBLOCK_UNBLOCK 2
+#define SIGFASTBLOCK_UNSETPTR 3
+
+#define SIGFASTBLOCK_PEND 0x1
+#define SIGFASTBLOCK_FLAGS 0xf
+#define SIGFASTBLOCK_INC 0x10
+
+#ifndef _KERNEL
+int __sys_sigfastblock(int cmd, void *ptr);
+#endif
+
#ifdef _KERNEL
+extern sigset_t fastblock_mask;
/* Return nonzero if process p has an unmasked pending signal. */
#define SIGPENDING(td) \
@@ -328,6 +344,7 @@
#define SIGPROCMASK_OLD 0x0001
#define SIGPROCMASK_PROC_LOCKED 0x0002
#define SIGPROCMASK_PS_LOCKED 0x0004
+#define SIGPROCMASK_FASTBLK 0x0008
/*
* Modes for sigdeferstop(). Manages behaviour of
@@ -365,6 +382,8 @@
int cursig(struct thread *td);
void execsigs(struct proc *p);
+void fetch_sigfastblock(struct thread *td);
+void fetch_sigfastblock_failed(struct thread *td, bool write);
void gsignal(int pgid, int sig, ksiginfo_t *ksi);
void killproc(struct proc *p, char *why);
ksiginfo_t * ksiginfo_alloc(int wait);
@@ -375,6 +394,7 @@
int postsig(int sig);
void kern_psignal(struct proc *p, int sig);
int ptracestop(struct thread *td, int sig, ksiginfo_t *si);
+void reschedule_signals(struct proc *p, sigset_t block, int flags);
void sendsig(sig_t catcher, ksiginfo_t *ksi, sigset_t *retmask);
struct sigacts *sigacts_alloc(void);
void sigacts_copy(struct sigacts *dest, struct sigacts *src);

File Metadata

Mime Type
text/plain
Expires
Wed, Feb 12, 5:00 PM (20 h, 47 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
16613382
Default Alt Text
D12773.diff (25 KB)

Event Timeline