mirror of
git://git.musl-libc.org/musl
synced 2025-03-06 20:48:29 +01:00
a request for this behavior has been open for a long time. the motivation is that application code, particularly under some language runtimes designed around very-low-footprint coroutine type constructs, may be operating with extremely small stack sizes unsuitable for receiving signals, using a separate signal stack for any signals it might handle. progress on this was blocked at one point trying to determine whether the implementation is actually entitled to clobber the alt stack, but the phrasing "available to the implementation" in the POSIX spec for sigaltstack seems to make it clear that the application cannot rely on the contents of this memory to be preserved in the absence of signal delivery (on the abstract machine, excluding implementation-internal signals) and that we can therefore use it for delivery of signals that "don't exist" on the abstract machine. no change is made for SIGTIMER since it is always blocked when used, and accepted via sigwaitinfo rather than execution of the signal handler.
72 lines
2.2 KiB
C
72 lines
2.2 KiB
C
#include <sys/membarrier.h>
|
|
#include <semaphore.h>
|
|
#include <signal.h>
|
|
#include <string.h>
|
|
#include "pthread_impl.h"
|
|
#include "syscall.h"
|
|
|
|
static void dummy_0(void)
|
|
{
|
|
}
|
|
|
|
weak_alias(dummy_0, __tl_lock);
|
|
weak_alias(dummy_0, __tl_unlock);
|
|
|
|
static sem_t barrier_sem;
|
|
|
|
static void bcast_barrier(int s)
|
|
{
|
|
sem_post(&barrier_sem);
|
|
}
|
|
|
|
int __membarrier(int cmd, int flags)
|
|
{
|
|
int r = __syscall(SYS_membarrier, cmd, flags);
|
|
/* Emulate the private expedited command, which is needed by the
|
|
* dynamic linker for installation of dynamic TLS, for older
|
|
* kernels that lack the syscall. Unlike the syscall, this only
|
|
* synchronizes with threads of the process, not other processes
|
|
* sharing the VM, but such sharing is not a supported usage
|
|
* anyway. */
|
|
if (r && cmd == MEMBARRIER_CMD_PRIVATE_EXPEDITED && !flags) {
|
|
pthread_t self=__pthread_self(), td;
|
|
sigset_t set;
|
|
__block_app_sigs(&set);
|
|
__tl_lock();
|
|
sem_init(&barrier_sem, 0, 0);
|
|
struct sigaction sa = {
|
|
.sa_flags = SA_RESTART | SA_ONSTACK,
|
|
.sa_handler = bcast_barrier
|
|
};
|
|
memset(&sa.sa_mask, -1, sizeof sa.sa_mask);
|
|
if (!__libc_sigaction(SIGSYNCCALL, &sa, 0)) {
|
|
for (td=self->next; td!=self; td=td->next)
|
|
__syscall(SYS_tkill, td->tid, SIGSYNCCALL);
|
|
for (td=self->next; td!=self; td=td->next)
|
|
sem_wait(&barrier_sem);
|
|
r = 0;
|
|
sa.sa_handler = SIG_IGN;
|
|
__libc_sigaction(SIGSYNCCALL, &sa, 0);
|
|
}
|
|
sem_destroy(&barrier_sem);
|
|
__tl_unlock();
|
|
__restore_sigs(&set);
|
|
}
|
|
return __syscall_ret(r);
|
|
}
|
|
|
|
void __membarrier_init(void)
|
|
{
|
|
/* If membarrier is linked, attempt to pre-register to be able to use
|
|
* the private expedited command before the process becomes multi-
|
|
* threaded, since registering later has bad, potentially unbounded
|
|
* latency. This syscall should be essentially free, and it's arguably
|
|
* a mistake in the API design that registration was even required.
|
|
* For other commands, registration may impose some cost, so it's left
|
|
* to the application to do so if desired. Unfortunately this means
|
|
* library code initialized after the process becomes multi-threaded
|
|
* cannot use these features without accepting registration latency. */
|
|
__syscall(SYS_membarrier, MEMBARRIER_CMD_REGISTER_PRIVATE_EXPEDITED, 0);
|
|
}
|
|
|
|
weak_alias(__membarrier, membarrier);
|