mirror of
https://github.com/fluencelabs/musl
synced 2025-06-05 19:11:34 +00:00
this mirrors the stdio_impl.h cleanup. one header which is not strictly needed, errno.h, is left in pthread_impl.h, because since pthread functions return their error codes rather than using errno, nearly every single pthread function needs the errno constants. in a few places, rather than bringing in string.h to use memset, the memset was replaced by direct assignment. this seems to generate much better code anyway, and makes many functions which were previously non-leaf functions into leaf functions (possibly eliminating a great deal of bloat on some platforms where non-leaf functions require ugly prologue and/or epilogue).
102 lines
2.0 KiB
C
102 lines
2.0 KiB
C
#include "pthread_impl.h"
|
|
#include <semaphore.h>
|
|
#include <string.h>
|
|
|
|
static struct chain {
|
|
struct chain *next;
|
|
sem_t sem, sem2;
|
|
} *head, *cur;
|
|
|
|
static void (*callback)(void *), *context;
|
|
static int chainlen;
|
|
static sem_t chainlock, chaindone;
|
|
|
|
static void handler(int sig, siginfo_t *si, void *ctx)
|
|
{
|
|
struct chain ch;
|
|
pthread_t self = __pthread_self();
|
|
int old_errno = errno;
|
|
|
|
if (chainlen == libc.threads_minus_1) return;
|
|
|
|
sigqueue(self->pid, SIGSYNCCALL, (union sigval){0});
|
|
|
|
/* Threads which have already decremented themselves from the
|
|
* thread count must not act. Block further receipt of signals
|
|
* and return. */
|
|
if (self->dead) {
|
|
memset(&((ucontext_t *)ctx)->uc_sigmask, -1, 8);
|
|
errno = old_errno;
|
|
return;
|
|
}
|
|
|
|
sem_init(&ch.sem, 0, 0);
|
|
sem_init(&ch.sem2, 0, 0);
|
|
|
|
while (sem_wait(&chainlock));
|
|
ch.next = head;
|
|
head = &ch;
|
|
if (++chainlen == libc.threads_minus_1) sem_post(&chaindone);
|
|
sem_post(&chainlock);
|
|
|
|
while (sem_wait(&ch.sem));
|
|
callback(context);
|
|
sem_post(&ch.sem2);
|
|
while (sem_wait(&ch.sem));
|
|
|
|
errno = old_errno;
|
|
}
|
|
|
|
void __synccall(void (*func)(void *), void *ctx)
|
|
{
|
|
pthread_t self;
|
|
struct sigaction sa;
|
|
struct chain *next;
|
|
uint64_t oldmask;
|
|
|
|
if (!libc.threads_minus_1) {
|
|
func(ctx);
|
|
return;
|
|
}
|
|
|
|
__inhibit_ptc();
|
|
|
|
__syscall(SYS_rt_sigprocmask, SIG_BLOCK, SIGALL_SET,
|
|
&oldmask, __SYSCALL_SSLEN);
|
|
|
|
sem_init(&chaindone, 0, 0);
|
|
sem_init(&chainlock, 0, 1);
|
|
chainlen = 0;
|
|
callback = func;
|
|
context = ctx;
|
|
|
|
sa.sa_flags = SA_SIGINFO | SA_RESTART;
|
|
sa.sa_sigaction = handler;
|
|
sigfillset(&sa.sa_mask);
|
|
__libc_sigaction(SIGSYNCCALL, &sa, 0);
|
|
|
|
self = __pthread_self();
|
|
sigqueue(self->pid, SIGSYNCCALL, (union sigval){0});
|
|
while (sem_wait(&chaindone));
|
|
|
|
for (cur=head; cur; cur=cur->next) {
|
|
sem_post(&cur->sem);
|
|
while (sem_wait(&cur->sem2));
|
|
}
|
|
func(ctx);
|
|
|
|
for (cur=head; cur; cur=next) {
|
|
next = cur->next;
|
|
sem_post(&cur->sem);
|
|
}
|
|
|
|
sa.sa_flags = 0;
|
|
sa.sa_handler = SIG_IGN;
|
|
__libc_sigaction(SIGSYNCCALL, &sa, 0);
|
|
|
|
__syscall(SYS_rt_sigprocmask, SIG_SETMASK,
|
|
&oldmask, 0, __SYSCALL_SSLEN);
|
|
|
|
__release_ptc();
|
|
}
|