support for TLS in dynamic-loaded (dlopen) modules
[musl] / src / thread / synccall.c
1 #include "pthread_impl.h"
2 #include <semaphore.h>
3
4 static struct chain {
5         struct chain *next;
6         sem_t sem, sem2;
7 } *head, *cur;
8
9 static void (*callback)(void *), *context;
10 static int chainlen;
11 static sem_t chainlock, chaindone;
12
13 static void handler(int sig, siginfo_t *si, void *ctx)
14 {
15         struct chain ch;
16         pthread_t self = __pthread_self();
17         int old_errno = errno;
18
19         if (chainlen == libc.threads_minus_1) return;
20
21         sigqueue(self->pid, SIGSYNCCALL, (union sigval){0});
22
23         /* Threads which have already decremented themselves from the
24          * thread count must not act. Block further receipt of signals
25          * and return. */
26         if (self->dead) {
27                 memset(&((ucontext_t *)ctx)->uc_sigmask, -1, 8);
28                 errno = old_errno;
29                 return;
30         }
31
32         sem_init(&ch.sem, 0, 0);
33         sem_init(&ch.sem2, 0, 0);
34
35         while (sem_wait(&chainlock));
36         ch.next = head;
37         head = &ch;
38         if (++chainlen == libc.threads_minus_1) sem_post(&chaindone);
39         sem_post(&chainlock);
40
41         while (sem_wait(&ch.sem));
42         callback(context);
43         sem_post(&ch.sem2);
44         while (sem_wait(&ch.sem));
45
46         errno = old_errno;
47 }
48
49 void __synccall(void (*func)(void *), void *ctx)
50 {
51         pthread_t self;
52         struct sigaction sa;
53         struct chain *next;
54         uint64_t oldmask;
55
56         if (!libc.threads_minus_1) {
57                 func(ctx);
58                 return;
59         }
60
61         __inhibit_ptc();
62
63         __syscall(SYS_rt_sigprocmask, SIG_BLOCK, SIGALL_SET,
64                 &oldmask, __SYSCALL_SSLEN);
65
66         sem_init(&chaindone, 0, 0);
67         sem_init(&chainlock, 0, 1);
68         chainlen = 0;
69         callback = func;
70         context = ctx;
71
72         sa.sa_flags = SA_SIGINFO | SA_RESTART;
73         sa.sa_sigaction = handler;
74         sigfillset(&sa.sa_mask);
75         __libc_sigaction(SIGSYNCCALL, &sa, 0);
76
77         self = __pthread_self();
78         sigqueue(self->pid, SIGSYNCCALL, (union sigval){0});
79         while (sem_wait(&chaindone));
80
81         for (cur=head; cur; cur=cur->next) {
82                 sem_post(&cur->sem);
83                 while (sem_wait(&cur->sem2));
84         }
85         func(ctx);
86
87         for (cur=head; cur; cur=next) {
88                 next = cur->next;
89                 sem_post(&cur->sem);
90         }
91
92         sa.sa_flags = 0;
93         sa.sa_handler = SIG_IGN;
94         __libc_sigaction(SIGSYNCCALL, &sa, 0);
95
96         __syscall(SYS_rt_sigprocmask, SIG_SETMASK,
97                 &oldmask, 0, __SYSCALL_SSLEN);
98
99         __release_ptc();
100 }