Changeset View
Standalone View
lib/libc/sys/fast_sigblock.2
- This file was added.
.\" Copyright (c) 2016 The FreeBSD Foundation, Inc. | |||||
.\" All rights reserved. | |||||
emaste: we can drop the `All rights reserved.` | |||||
.\" | |||||
.\" 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 FAST_SIGBLOCK 2 | |||||
.Os | |||||
.Sh NAME | |||||
.Nm fast_sigblock | |||||
.Nd controls signals blocking with a simple memory write | |||||
.Sh LIBRARY | |||||
Done Inline ActionsThis description doesn't seem right. brooks: This description doesn't seem right. | |||||
.Lb libc | |||||
.Sh SYNOPSIS | |||||
.In sys/signalvar.h | |||||
.Ft int | |||||
.Fn fast_sigblock "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 contains non-zero count of blocks (see below), | |||||
Not Done Inline ActionsDid you mean count of blockers, or count of blocked threads, or something else? count of blocks doesn't scan as correct English to me. rpokala: Did you mean `count of blockers`, or `count of blocked threads`, or something else? `count of… | |||||
Done Inline ActionsThis thing only works for current thread. Block is one increment of the variable. I have to make this possible because both rtld and libthr might need to recurse into critical sections. kib: This thing only works for current thread. Block is one increment of the variable.
I have to… | |||||
Not Done Inline Actions
But what does that mean? re-reads Okay, it's incremented every time something says "block signals until I'm done", right? And its possible for multiple things to say that recursively, leading to a count greater than one? If that's correct, then "blocks" means "requests to block signals"; in that case, it could be worded more clearly like this:: If the variable contains a non-zero count of requests to block signals (see below) rpokala: > This thing only works for current thread. Block is one increment of the variable.
But what… | |||||
Not Done Inline Actions@rpokala It's just a recursion count, yeah. I might phrase the sentence as: "If the variable indicates that blocking is requested, then the kernel ..." (and just leave out the recursion detail, which isn't important to the description of the on/off behavior). The recursion is already described later (sentence ending in l. 80). cem: @rpokala It's just a recursion count, yeah. I might phrase the sentence as: "If the variable… | |||||
then kernel effectively operates as if the mask contained all | |||||
Not Done Inline Actionsnit: s/contained/containing/ cem: nit: s/contained/containing/ | |||||
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 | |||||
Not Done Inline ActionsThis implies that fast signal blocking should not be in effect for an indefinite time in a multi-threaded process, since fast signal blocking is not taken into account by the mechanism that directs a process-wide signal to a thread that does not have it masked (taking it into account would require access to other process memory when sending a signal). jilles: This implies that fast signal blocking should not be in effect for an indefinite time in a… | |||||
Done Inline ActionsIf used properly (in other words, if there is no memory corruption), then it is. But if application wrote a garbage into the fast_sigblock word, it breaks of course. I understand your point that this significantly increases the possible non-compliance for misbehaving programs, and this was one of the reasons why I did not rushed with the patch, which was written several years ago. But in the end, I think that it is not too bad, because the kernel integrity is maintained, and stuff like SIGKILL/SIGSTOP is not affected. kib: If used properly (in other words, if there is no memory corruption), then it is. But if… | |||||
Not Done Inline ActionsHmm, my point was that in this scenario:
the signal will not be handled until thread 1 disables fast signal blocking, or thread 2 does something that causes the process's signal queue to be checked. The same thing happens with libthr's deferred signals (but in that case only for signals that have a handler, not ones that use the default action). When thread 1 masks SIGUSR1 normally, sigtd() will always pick thread 2, and the signal is handled without delay. As a result, fast signal blocking is only suitable for short critical sections, not as a generic replacement for sigprocmask()/pthread_sigmask(). To @cem, making this work as a generic replacement for sigprocmask()/pthread_sigmask() would require a rather different design since accessing a different process's pageable memory while sending a signal (in sigtd()) seems a bad idea. jilles: Hmm, my point was that in this scenario:
- The process does not ignore SIGUSR1.
- Thread 1… | |||||
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 FAST_SIGBLOCK_INC | |||||
quantity to recursively block or unblock signals delivery. | |||||
.Pp | |||||
Not Done Inline ActionsIf the kernel only sets and clears the flags from the same thread, then on x86 read-modify-write operations without LOCK prefix would suffice (counter(9) uses this). However, it may not be worth the trouble. jilles: If the kernel only sets and clears the flags from the same thread, then on x86 read-modify… | |||||
If a signal would be delivered when unmasked, kernel might set the | |||||
.Dv FAST_SIGBLOCK_PEND | |||||
.Dq pending signal | |||||
flag in the sigblock variable. | |||||
Userspace should perform | |||||
.Dv FAST_SIGBLOCK_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 FAST_SIGBLOCK_UNSETPTR | |||||
.It Dv FAST_SIGBLOCK_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 FAST_SIGBLOCK_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 FAST_SIGBLOCK_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 FAST_SIGBLOCK_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 FAST_SIGBLOCK_SETPTR | |||||
attempted while the sigblock address was already registered. | |||||
The | |||||
.Dv FAST_SIGBLOCK_UNBLOCK | |||||
was called while sigblock variable value is not equal to | |||||
.Dv FAST_SIGBLOCK_PEND . | |||||
.It Bq Er EINVAL | |||||
The variable address passed to | |||||
.Dv FAST_SIGBLOCK_SETPTR | |||||
is not aligned naturally. | |||||
The | |||||
.Dv FAST_SIGBLOCK_UNSETPTR | |||||
operation was attempted without prior successfull call to | |||||
.Dv FAST_SIGBLOCK_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 . |
we can drop the All rights reserved.