Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F107713767
D12773.id66921.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
42 KB
Referenced Files
None
Subscribers
None
D12773.id66921.diff
View Options
Index: lib/libc/gen/auxv.c
===================================================================
--- lib/libc/gen/auxv.c
+++ lib/libc/gen/auxv.c
@@ -67,7 +67,7 @@
}
static pthread_once_t aux_once = PTHREAD_ONCE_INIT;
-static int pagesize, osreldate, canary_len, ncpus, pagesizes_len;
+static int pagesize, osreldate, canary_len, ncpus, pagesizes_len, bsdflags;
static int hwcap_present, hwcap2_present;
static char *canary, *pagesizes, *execpath;
static void *timekeep;
@@ -80,6 +80,10 @@
for (aux = __elf_aux_vector; aux->a_type != AT_NULL; aux++) {
switch (aux->a_type) {
+ case AT_BSDFLAGS:
+ bsdflags = aux->a_un.a_val;
+ break;
+
case AT_CANARY:
canary = (char *)(aux->a_un.a_ptr);
break;
@@ -224,6 +228,13 @@
} else
res = EINVAL;
break;
+ case AT_BSDFLAGS:
+ if (buflen == sizeof(int)) {
+ *(int *)buf = bsdflags;
+ res = 0;
+ } else
+ res = EINVAL;
+ break;
default:
res = ENOENT;
break;
Index: lib/libc/sys/Makefile.inc
===================================================================
--- lib/libc/sys/Makefile.inc
+++ lib/libc/sys/Makefile.inc
@@ -317,6 +317,7 @@
shutdown.2 \
sigaction.2 \
sigaltstack.2 \
+ sigfastblock.2 \
sigpending.2 \
sigprocmask.2 \
sigqueue.2 \
Index: lib/libc/sys/Symbol.map
===================================================================
--- lib/libc/sys/Symbol.map
+++ lib/libc/sys/Symbol.map
@@ -567,6 +567,7 @@
__sys_extattr_set_link;
_extattrctl;
__sys_extattrctl;
+ __sys_sigfastblock;
_fchdir;
__sys_fchdir;
_fchflags;
Index: lib/libc/sys/sigfastblock.2
===================================================================
--- /dev/null
+++ 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: lib/libthr/thread/thr_create.c
===================================================================
--- lib/libthr/thread/thr_create.c
+++ lib/libthr/thread/thr_create.c
@@ -257,6 +257,7 @@
if (curthread->attr.suspend == THR_CREATE_SUSPENDED)
set = curthread->sigmask;
+ _thr_signal_block_setup(curthread);
/*
* This is used as a serialization point to allow parent
Index: lib/libthr/thread/thr_private.h
===================================================================
--- lib/libthr/thread/thr_private.h
+++ lib/libthr/thread/thr_private.h
@@ -396,6 +396,9 @@
/* Signal blocked counter. */
int sigblock;
+ /* Fast sigblock var. */
+ uint32_t fsigblock;
+
/* Queue entry for list of all threads. */
TAILQ_ENTRY(pthread) tle; /* link for all threads in process */
@@ -813,6 +816,8 @@
void _thr_testcancel(struct pthread *) __hidden;
void _thr_signal_block(struct pthread *) __hidden;
void _thr_signal_unblock(struct pthread *) __hidden;
+void _thr_signal_block_check_fast(void) __hidden;
+void _thr_signal_block_setup(struct pthread *) __hidden;
void _thr_signal_init(int) __hidden;
void _thr_signal_deinit(void) __hidden;
int _thr_send_sig(struct pthread *, int sig) __hidden;
Index: lib/libthr/thread/thr_rtld.c
===================================================================
--- lib/libthr/thread/thr_rtld.c
+++ lib/libthr/thread/thr_rtld.c
@@ -236,6 +236,8 @@
_thr_signal_block(curthread);
_rtld_thread_init(&li);
_thr_signal_unblock(curthread);
+ _thr_signal_block_check_fast();
+ _thr_signal_block_setup(curthread);
uc_len = __getcontextx_size();
uc = alloca(uc_len);
Index: lib/libthr/thread/thr_sig.c
===================================================================
--- lib/libthr/thread/thr_sig.c
+++ lib/libthr/thread/thr_sig.c
@@ -31,7 +31,8 @@
#include "namespace.h"
#include <sys/param.h>
-#include <sys/types.h>
+#include <sys/auxv.h>
+#include <sys/elf.h>
#include <sys/signalvar.h>
#include <sys/syscall.h>
#include <signal.h>
@@ -92,10 +93,9 @@
0xffffffff,
0xffffffff}};
-void
-_thr_signal_block(struct pthread *curthread)
+static void
+thr_signal_block_slow(struct pthread *curthread)
{
-
if (curthread->sigblock > 0) {
curthread->sigblock++;
return;
@@ -104,13 +104,68 @@
curthread->sigblock++;
}
-void
-_thr_signal_unblock(struct pthread *curthread)
+static void
+thr_signal_unblock_slow(struct pthread *curthread)
{
if (--curthread->sigblock == 0)
__sys_sigprocmask(SIG_SETMASK, &curthread->sigmask, NULL);
}
+static void
+thr_signal_block_fast(struct pthread *curthread)
+{
+ atomic_add_32(&curthread->fsigblock, SIGFASTBLOCK_INC);
+}
+
+static void
+thr_signal_unblock_fast(struct pthread *curthread)
+{
+ uint32_t oldval;
+
+ oldval = atomic_fetchadd_32(&curthread->fsigblock, -SIGFASTBLOCK_INC);
+ if (oldval == (SIGFASTBLOCK_PEND | SIGFASTBLOCK_INC))
+ __sys_sigfastblock(SIGFASTBLOCK_UNBLOCK, NULL);
+}
+
+static bool fast_sigblock;
+
+void
+_thr_signal_block(struct pthread *curthread)
+{
+ if (fast_sigblock)
+ thr_signal_block_fast(curthread);
+ else
+ thr_signal_block_slow(curthread);
+}
+
+void
+_thr_signal_unblock(struct pthread *curthread)
+{
+ if (fast_sigblock)
+ thr_signal_unblock_fast(curthread);
+ else
+ thr_signal_unblock_slow(curthread);
+}
+
+void
+_thr_signal_block_check_fast(void)
+{
+ int bsdflags, error;
+
+ error = elf_aux_info(AT_BSDFLAGS, &bsdflags, sizeof(bsdflags));
+ if (error != 0)
+ return;
+ fast_sigblock = (bsdflags & ELF_BSDF_SIGFASTBLK) != 0;
+}
+
+void
+_thr_signal_block_setup(struct pthread *curthread)
+{
+ if (!fast_sigblock)
+ return;
+ __sys_sigfastblock(SIGFASTBLOCK_SETPTR, &curthread->fsigblock);
+}
+
int
_thr_send_sig(struct pthread *thread, int sig)
{
Index: libexec/rtld-elf/rtld-libc/Makefile.inc
===================================================================
--- libexec/rtld-elf/rtld-libc/Makefile.inc
+++ libexec/rtld-elf/rtld-libc/Makefile.inc
@@ -45,8 +45,9 @@
strlen strncmp strncpy strrchr strsep strspn strstr strtok
# Also use all the syscall .o files from libc_nossp_pic:
_libc_other_objects= sigsetjmp lstat stat fstat fstatat fstatfs syscall \
- cerror geteuid getegid munmap mprotect sysarch __sysctl issetugid __getcwd \
- utrace thr_self thr_kill pread mmap lseek _exit _fstat _fstatat _fstatfs \
+ cerror geteuid getegid sigfastblock munmap mprotect \
+ sysarch __sysctl issetugid __getcwd utrace \
+ thr_self thr_kill pread mmap lseek _exit _fstat _fstatat _fstatfs \
getdirentries _getdirentries _close _fcntl _open _openat _read \
_sigprocmask _write readlink _setjmp setjmp setjmperr
Index: libexec/rtld-elf/rtld.h
===================================================================
--- libexec/rtld-elf/rtld.h
+++ libexec/rtld-elf/rtld.h
@@ -365,6 +365,7 @@
extern Elf_Addr _GLOBAL_OFFSET_TABLE_[];
extern Elf_Sym sym_zero; /* For resolving undefined weak refs. */
extern bool ld_bind_not;
+extern bool ld_fast_sigblock;
void dump_relocations(Obj_Entry *);
void dump_obj_relocations(Obj_Entry *);
Index: libexec/rtld-elf/rtld.c
===================================================================
--- libexec/rtld-elf/rtld.c
+++ libexec/rtld-elf/rtld.c
@@ -286,6 +286,7 @@
int tls_max_index = 1; /* Largest module index allocated */
static bool ld_library_path_rpath = false;
+bool ld_fast_sigblock = false;
/*
* Globals for path names, and such
@@ -444,6 +445,10 @@
main_argc = argc;
main_argv = argv;
+ if (aux_info[AT_BSDFLAGS] != NULL &&
+ (aux_info[AT_BSDFLAGS]->a_un.a_val & ELF_BSDF_SIGFASTBLK) != 0)
+ ld_fast_sigblock = true;
+
trust = !issetugid();
md_abi_variant_hook(aux_info);
Index: libexec/rtld-elf/rtld_lock.c
===================================================================
--- libexec/rtld-elf/rtld_lock.c
+++ libexec/rtld-elf/rtld_lock.c
@@ -45,6 +45,7 @@
*/
#include <sys/param.h>
+#include <sys/signalvar.h>
#include <signal.h>
#include <stdlib.h>
#include <time.h>
@@ -68,6 +69,7 @@
static sigset_t fullsigmask, oldsigmask;
static int thread_flag, wnested;
+static uint32_t fsigblock;
static void *
def_lock_create(void)
@@ -117,6 +119,17 @@
; /* Spin */
}
+static void
+sig_fastunblock(void)
+{
+ uint32_t oldval;
+
+ assert((fsigblock & ~SIGFASTBLOCK_FLAGS) >= SIGFASTBLOCK_INC);
+ oldval = atomic_fetchadd_32(&fsigblock, -SIGFASTBLOCK_INC);
+ if (oldval == (SIGFASTBLOCK_PEND | SIGFASTBLOCK_INC))
+ __sys_sigfastblock(SIGFASTBLOCK_UNBLOCK, NULL);
+}
+
static void
def_wlock_acquire(void *lock)
{
@@ -124,14 +137,23 @@
sigset_t tmp_oldsigmask;
l = (Lock *)lock;
- for (;;) {
- sigprocmask(SIG_BLOCK, &fullsigmask, &tmp_oldsigmask);
- if (atomic_cmpset_acq_int(&l->lock, 0, WAFLAG))
- break;
- sigprocmask(SIG_SETMASK, &tmp_oldsigmask, NULL);
+ if (ld_fast_sigblock) {
+ for (;;) {
+ atomic_add_32(&fsigblock, SIGFASTBLOCK_INC);
+ if (atomic_cmpset_acq_int(&l->lock, 0, WAFLAG))
+ break;
+ sig_fastunblock();
+ }
+ } else {
+ for (;;) {
+ sigprocmask(SIG_BLOCK, &fullsigmask, &tmp_oldsigmask);
+ if (atomic_cmpset_acq_int(&l->lock, 0, WAFLAG))
+ break;
+ sigprocmask(SIG_SETMASK, &tmp_oldsigmask, NULL);
+ }
+ if (atomic_fetchadd_int(&wnested, 1) == 0)
+ oldsigmask = tmp_oldsigmask;
}
- if (atomic_fetchadd_int(&wnested, 1) == 0)
- oldsigmask = tmp_oldsigmask;
}
static void
@@ -143,9 +165,10 @@
if ((l->lock & WAFLAG) == 0)
atomic_add_rel_int(&l->lock, -RC_INCR);
else {
- assert(wnested > 0);
atomic_add_rel_int(&l->lock, -WAFLAG);
- if (atomic_fetchadd_int(&wnested, -1) == 1)
+ if (ld_fast_sigblock)
+ sig_fastunblock();
+ else if (atomic_fetchadd_int(&wnested, -1) == 1)
sigprocmask(SIG_SETMASK, &oldsigmask, NULL);
}
}
@@ -279,38 +302,36 @@
void
lockdflt_init(void)
{
- int i;
-
- deflockinfo.rtli_version = RTLI_VERSION;
- deflockinfo.lock_create = def_lock_create;
- deflockinfo.lock_destroy = def_lock_destroy;
- deflockinfo.rlock_acquire = def_rlock_acquire;
- deflockinfo.wlock_acquire = def_wlock_acquire;
- deflockinfo.lock_release = def_lock_release;
- deflockinfo.thread_set_flag = def_thread_set_flag;
- deflockinfo.thread_clr_flag = def_thread_clr_flag;
- deflockinfo.at_fork = NULL;
-
- for (i = 0; i < RTLD_LOCK_CNT; i++) {
- rtld_locks[i].mask = (1 << i);
- rtld_locks[i].handle = NULL;
- }
+ int i;
+
+ deflockinfo.rtli_version = RTLI_VERSION;
+ deflockinfo.lock_create = def_lock_create;
+ deflockinfo.lock_destroy = def_lock_destroy;
+ deflockinfo.rlock_acquire = def_rlock_acquire;
+ deflockinfo.wlock_acquire = def_wlock_acquire;
+ deflockinfo.lock_release = def_lock_release;
+ deflockinfo.thread_set_flag = def_thread_set_flag;
+ deflockinfo.thread_clr_flag = def_thread_clr_flag;
+ deflockinfo.at_fork = NULL;
- memcpy(&lockinfo, &deflockinfo, sizeof(lockinfo));
- _rtld_thread_init(NULL);
- /*
- * Construct a mask to block all signals except traps which might
- * conceivably be generated within the dynamic linker itself.
- */
- sigfillset(&fullsigmask);
- sigdelset(&fullsigmask, SIGILL);
- sigdelset(&fullsigmask, SIGTRAP);
- sigdelset(&fullsigmask, SIGABRT);
- sigdelset(&fullsigmask, SIGEMT);
- sigdelset(&fullsigmask, SIGFPE);
- sigdelset(&fullsigmask, SIGBUS);
- sigdelset(&fullsigmask, SIGSEGV);
- sigdelset(&fullsigmask, SIGSYS);
+ for (i = 0; i < RTLD_LOCK_CNT; i++) {
+ rtld_locks[i].mask = (1 << i);
+ rtld_locks[i].handle = NULL;
+ }
+
+ memcpy(&lockinfo, &deflockinfo, sizeof(lockinfo));
+ _rtld_thread_init(NULL);
+ if (ld_fast_sigblock) {
+ __sys_sigfastblock(SIGFASTBLOCK_SETPTR, &fsigblock);
+ } else {
+ /*
+ * Construct a mask to block all signals. Note that
+ * blocked traps mean that the process is terminated
+ * if trap occurs while we are in locked section, with
+ * the default settings for kern.forcesigexit.
+ */
+ sigfillset(&fullsigmask);
+ }
}
/*
@@ -331,7 +352,10 @@
if (pli == NULL)
pli = &deflockinfo;
-
+ else if (ld_fast_sigblock) {
+ fsigblock = 0;
+ __sys_sigfastblock(SIGFASTBLOCK_UNSETPTR, NULL);
+ }
for (i = 0; i < RTLD_LOCK_CNT; i++)
if ((locks[i] = pli->lock_create()) == NULL)
Index: sys/compat/freebsd32/syscalls.master
===================================================================
--- sys/compat/freebsd32/syscalls.master
+++ 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: sys/kern/capabilities.conf
===================================================================
--- sys/kern/capabilities.conf
+++ sys/kern/capabilities.conf
@@ -668,6 +668,7 @@
sigaction
sigaltstack
sigblock
+sigfastblock
sigpending
sigprocmask
sigqueue
Index: sys/kern/imgact_elf.c
===================================================================
--- sys/kern/imgact_elf.c
+++ sys/kern/imgact_elf.c
@@ -183,6 +183,11 @@
__XSTRING(__CONCAT(ELF, __ELF_WORD_SIZE))
": maximum percentage of main stack to waste on a random gap");
+static int __elfN(fast_sigblock) = 1;
+SYSCTL_INT(__CONCAT(_kern_elf, __ELF_WORD_SIZE), OID_AUTO, fast_sigblock,
+ CTLFLAG_RWTUN, &__elfN(fast_sigblock), 0,
+ "enable fast sigblock for new processes");
+
static Elf_Brandinfo *elf_brand_list[MAX_BRANDS];
#define aligned(a, t) (rounddown2((u_long)(a), sizeof(t)) == (u_long)(a))
@@ -1367,6 +1372,8 @@
AUXARGS_ENTRY(pos, AT_HWCAP, *imgp->sysent->sv_hwcap);
if (imgp->sysent->sv_hwcap2 != NULL)
AUXARGS_ENTRY(pos, AT_HWCAP2, *imgp->sysent->sv_hwcap2);
+ AUXARGS_ENTRY(pos, AT_BSDFLAGS, __elfN(fast_sigblock) ?
+ ELF_BSDF_SIGFASTBLK : 0);
AUXARGS_ENTRY(pos, AT_NULL, 0);
free(imgp->auxargs, M_TEMP);
Index: sys/kern/kern_exec.c
===================================================================
--- sys/kern/kern_exec.c
+++ 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;
@@ -1034,6 +1035,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: sys/kern/kern_fork.c
===================================================================
--- sys/kern/kern_fork.c
+++ 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: sys/kern/kern_proc.c
===================================================================
--- sys/kern/kern_proc.c
+++ sys/kern/kern_proc.c
@@ -2967,6 +2967,77 @@
return (error);
}
+static int
+sysctl_kern_proc_sigfastblk(SYSCTL_HANDLER_ARGS)
+{
+ int *name = (int *)arg1;
+ u_int namelen = arg2;
+ pid_t pid;
+ struct proc *p;
+ struct thread *td1;
+ uintptr_t addr;
+#ifdef COMPAT_FREEBSD32
+ uint32_t addr32;
+#endif
+ int error;
+
+ if (namelen != 1 || req->newptr != NULL)
+ return (EINVAL);
+
+ pid = (pid_t)name[0];
+ error = pget(pid, PGET_HOLD | PGET_NOTWEXIT | PGET_CANDEBUG, &p);
+ if (error != 0)
+ return (error);
+
+ PROC_LOCK(p);
+#ifdef COMPAT_FREEBSD32
+ if (SV_CURPROC_FLAG(SV_ILP32)) {
+ if (!SV_PROC_FLAG(p, SV_ILP32)) {
+ error = EINVAL;
+ goto errlocked;
+ }
+ }
+#endif
+ if (pid <= PID_MAX) {
+ td1 = FIRST_THREAD_IN_PROC(p);
+ } else {
+ FOREACH_THREAD_IN_PROC(p, td1) {
+ if (td1->td_tid == pid)
+ break;
+ }
+ }
+ if (td1 == NULL) {
+ error = ESRCH;
+ goto errlocked;
+ }
+ /*
+ * The access to the private thread flags. It is fine as far
+ * as no out-of-thin-air values are read from td_pflags, and
+ * usermode read of the td_sigblock_ptr is racy inherently,
+ * since target process might have already changed it
+ * meantime.
+ */
+ if ((td1->td_pflags & TDP_SIGFASTBLOCK) != 0)
+ addr = (uintptr_t)td1->td_sigblock_ptr;
+ else
+ error = ENOTTY;
+
+errlocked:
+ _PRELE(p);
+ PROC_UNLOCK(p);
+ if (error != 0)
+ return (error);
+
+#ifdef COMPAT_FREEBSD32
+ if (SV_CURPROC_FLAG(SV_ILP32)) {
+ addr32 = addr;
+ error = SYSCTL_OUT(req, &addr32, sizeof(addr32));
+ } else
+#endif
+ error = SYSCTL_OUT(req, &addr, sizeof(addr));
+ return (error);
+}
+
SYSCTL_NODE(_kern, KERN_PROC, proc, CTLFLAG_RD, 0, "Process table");
SYSCTL_PROC(_kern_proc, KERN_PROC_ALL, all, CTLFLAG_RD|CTLTYPE_STRUCT|
@@ -3080,6 +3151,10 @@
CTLFLAG_MPSAFE, sysctl_kern_proc_sigtramp,
"Process signal trampoline location");
+static SYSCTL_NODE(_kern_proc, KERN_PROC_SIGFASTBLK, sigfastblk, CTLFLAG_RD |
+ CTLFLAG_ANYBODY | CTLFLAG_MPSAFE, sysctl_kern_proc_sigfastblk,
+ "Thread sigfastblock address");
+
int allproc_gen;
/*
Index: sys/kern/kern_sig.c
===================================================================
--- sys/kern/kern_sig.c
+++ 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 *
@@ -1998,8 +2000,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;
@@ -2009,8 +2011,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)],
@@ -2026,13 +2031,13 @@
* 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_sigblock_val = 0;
}
mtx_unlock(&ps->ps_mtx);
p->p_sig = sig; /* XXX to verify code */
@@ -2042,21 +2047,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;
}
@@ -2170,7 +2178,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;
@@ -2565,7 +2573,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"));
@@ -2662,8 +2669,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);
@@ -2672,7 +2678,7 @@
return (td->td_xsig);
}
-static void
+void
reschedule_signals(struct proc *p, sigset_t block, int flags)
{
struct sigacts *ps;
@@ -2688,7 +2694,7 @@
SIGSETAND(block, p->p_siglist);
while ((sig = sig_ffs(&block)) != 0) {
SIGDELSET(block, sig);
- td = sigtd(p, sig, 0);
+ td = sigtd(p, sig, (flags & SIGPROCMASK_FASTBLK) != 0);
signotify(td);
if (!(flags & SIGPROCMASK_PS_LOCKED))
mtx_lock(&ps->ps_mtx);
@@ -2847,6 +2853,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)) {
@@ -3915,3 +3939,118 @@
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: sys/kern/kern_thread.c
===================================================================
--- sys/kern/kern_thread.c
+++ 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: sys/kern/subr_syscall.c
===================================================================
--- sys/kern/subr_syscall.c
+++ 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: sys/kern/subr_trap.c
===================================================================
--- sys/kern/subr_trap.c
+++ sys/kern/subr_trap.c
@@ -218,8 +218,8 @@
{
struct thread *td;
struct proc *p;
- int flags;
- int sig;
+ uint32_t oldval;
+ int flags, sig, res;
td = curthread;
p = td->td_proc;
@@ -317,8 +317,13 @@
*/
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);
+ if (td->td_sigblock_val != 0) {
+ reschedule_signals(p, fastblock_mask,
+ SIGPROCMASK_PS_LOCKED | SIGPROCMASK_FASTBLK);
+ }
while ((sig = cursig(td)) != 0) {
KASSERT(sig >= 0, ("sig %d", sig));
postsig(sig);
@@ -326,6 +331,38 @@
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: sys/kern/syscalls.master
===================================================================
--- sys/kern/syscalls.master
+++ 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: sys/sys/elf_common.h
===================================================================
--- sys/sys/elf_common.h
+++ sys/sys/elf_common.h
@@ -950,8 +950,9 @@
#define AT_EHDRFLAGS 24 /* e_flags field from elf hdr */
#define AT_HWCAP 25 /* CPU feature flags. */
#define AT_HWCAP2 26 /* CPU feature flags 2. */
+#define AT_BSDFLAGS 27 /* ELF BSD Flags. */
-#define AT_COUNT 27 /* Count of defined aux entry types. */
+#define AT_COUNT 28 /* Count of defined aux entry types. */
/*
* Relocation types.
@@ -1452,5 +1453,6 @@
#define R_X86_64_TLSDESC 36
#define R_X86_64_IRELATIVE 37
+#define ELF_BSDF_SIGFASTBLK 0x0001 /* Kernel supports fast sigblock */
#endif /* !_SYS_ELF_COMMON_H_ */
Index: sys/sys/proc.h
===================================================================
--- sys/sys/proc.h
+++ 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: sys/sys/signalvar.h
===================================================================
--- sys/sys/signalvar.h
+++ 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);
Index: sys/sys/sysctl.h
===================================================================
--- sys/sys/sysctl.h
+++ sys/sys/sysctl.h
@@ -988,6 +988,7 @@
#define KERN_PROC_SIGTRAMP 41 /* signal trampoline location */
#define KERN_PROC_CWD 42 /* process current working directory */
#define KERN_PROC_NFDS 43 /* number of open file descriptors */
+#define KERN_PROC_SIGFASTBLK 44 /* address of fastsigblk magic word */
/*
* KERN_IPC identifiers
Index: sys/sys/systm.h
===================================================================
--- sys/sys/systm.h
+++ sys/sys/systm.h
@@ -399,6 +399,7 @@
uint32_t newval);
int casueword(volatile u_long *p, u_long oldval, u_long *oldvalp,
u_long newval);
+int casueword_check_susp(struct thread *td, bool sleep);
void realitexpire(void *);
Index: usr.bin/procstat/procstat.h
===================================================================
--- usr.bin/procstat/procstat.h
+++ usr.bin/procstat/procstat.h
@@ -67,6 +67,8 @@
void procstat_ptlwpinfo(struct procstat *prstat, struct kinfo_proc *kipp);
void procstat_rlimit(struct procstat *prstat, struct kinfo_proc *kipp);
void procstat_rusage(struct procstat *prstat, struct kinfo_proc *kipp);
+void procstat_sigfastblock(struct procstat *procstat,
+ struct kinfo_proc *kipp);
void procstat_sigs(struct procstat *prstat, struct kinfo_proc *kipp);
void procstat_threads(struct procstat *prstat, struct kinfo_proc *kipp);
void procstat_threads_sigs(struct procstat *prstat, struct kinfo_proc *kipp);
Index: usr.bin/procstat/procstat.c
===================================================================
--- usr.bin/procstat/procstat.c
+++ usr.bin/procstat/procstat.c
@@ -94,6 +94,8 @@
PS_CMP_NORMAL },
{ "rusage", "rusage", "[-Ht]", &procstat_rusage, &cmdopt_rusage,
PS_CMP_NORMAL },
+ { "sigfastblock", "sigfastblock", NULL, &procstat_sigfastblock,
+ &cmdopt_none, PS_CMP_NORMAL },
{ "signal", "signals", "[-n]", &procstat_sigs, &cmdopt_signals,
PS_CMP_PLURAL | PS_CMP_SUBSTR },
{ "thread", "threads", NULL, &procstat_threads, &cmdopt_none,
Index: usr.bin/procstat/procstat_auxv.c
===================================================================
--- usr.bin/procstat/procstat_auxv.c
+++ usr.bin/procstat/procstat_auxv.c
@@ -196,6 +196,12 @@
xo_emit("{dw:/%s}{Lw:/%-16s/%s}{:AT_HWCAP2/%#lx}\n",
prefix, "AT_HWCAP2", (u_long)auxv[i].a_un.a_val);
break;
+#endif
+#ifdef AT_BSDFLAGS
+ case AT_BSDFLAGS:
+ xo_emit("{dw:/%s}{Lw:/%-16s/%s}{:AT_BSDFLAGS/%#lx}\n",
+ prefix, "AT_BSDFLAGS", (u_long)auxv[i].a_un.a_val);
+ break;
#endif
default:
xo_emit("{dw:/%s}{Lw:/%16ld/%ld}{:UNKNOWN/%#lx}\n",
Index: usr.bin/procstat/procstat_sigs.c
===================================================================
--- usr.bin/procstat/procstat_sigs.c
+++ usr.bin/procstat/procstat_sigs.c
@@ -37,6 +37,8 @@
#include <err.h>
#include <errno.h>
#include <signal.h>
+#include <stdbool.h>
+#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@@ -162,6 +164,7 @@
xo_open_container(threadid);
xo_emit("{e:thread_id/%6d/%d}", kipp->ki_tid);
xo_open_container("signals");
+
for (j = 1; j <= _SIG_MAXSIG; j++) {
xo_emit("{dk:process_id/%5d/%d} ", kipp->ki_pid);
xo_emit("{d:thread_id/%6d/%d} ", kipp->ki_tid);
@@ -180,3 +183,63 @@
xo_close_container("threads");
procstat_freeprocs(procstat, kip);
}
+
+void
+procstat_sigfastblock(struct procstat *procstat, struct kinfo_proc *kipp)
+{
+ struct kinfo_proc *kip;
+ char *threadid;
+ uintptr_t sigfastblk_addr;
+ int error, name[4];
+ unsigned int count, i;
+ size_t len;
+ bool has_sigfastblk_addr;
+
+ if ((procstat_opts & PS_OPT_NOHEADER) == 0)
+ xo_emit("{T:/%5s %6s %-16s %-16s}\n", "PID", "TID",
+ "COMM", "FSIGBLK");
+
+ kip = procstat_getprocs(procstat, KERN_PROC_PID | KERN_PROC_INC_THREAD,
+ kipp->ki_pid, &count);
+ if (kip == NULL)
+ return;
+ xo_emit("{ek:process_id/%5d/%d}", kipp->ki_pid);
+ xo_emit("{e:command/%-16s/%s}", kipp->ki_comm);
+ xo_open_container("threads");
+ kinfo_proc_sort(kip, count);
+ for (i = 0; i < count; i++) {
+ kipp = &kip[i];
+ len = sizeof(sigfastblk_addr);
+ name[0] = CTL_KERN;
+ name[1] = KERN_PROC;
+ name[2] = KERN_PROC_SIGFASTBLK;
+ name[3] = kipp->ki_tid;
+ error = sysctl(name, 4, &sigfastblk_addr, &len, NULL, 0);
+ if (error < 0) {
+ if (errno != ESRCH && errno != ENOTTY) {
+ warn("sysctl: kern.proc.fastsigblk: %d",
+ kipp->ki_tid);
+ }
+ has_sigfastblk_addr = false;
+ } else
+ has_sigfastblk_addr = true;
+
+ asprintf(&threadid, "%d", kipp->ki_tid);
+ if (threadid == NULL)
+ xo_errc(1, ENOMEM, "Failed to allocate memory in "
+ "procstat_sigfastblock()");
+ xo_open_container(threadid);
+ xo_emit("{dk:process_id/%5d/%d} ", kipp->ki_pid);
+ xo_emit("{d:thread_id/%6d/%d} ", kipp->ki_tid);
+ xo_emit("{d:command/%-16s/%s} ", kipp->ki_comm);
+ xo_emit("{e:sigfastblock/%#-16jx/%#jx}", has_sigfastblk_addr ?
+ (uintmax_t)sigfastblk_addr : (uintmax_t)-1);
+ xo_emit("{d:sigfastblock/%#-16jx/%#jx}", has_sigfastblk_addr ?
+ (uintmax_t)sigfastblk_addr : (uintmax_t)-1);
+ xo_emit("\n");
+ xo_close_container(threadid);
+ free(threadid);
+ }
+ xo_close_container("threads");
+ procstat_freeprocs(procstat, kip);
+}
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Sat, Jan 18, 6:06 PM (5 h, 12 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
15880326
Default Alt Text
D12773.id66921.diff (42 KB)
Attached To
Mode
D12773: Manage thread signal mask using a shared word, instead of syscall.
Attached
Detach File
Event Timeline
Log In to Comment