pthread and synccall cleanup, new __synccall_wait op
[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 static pthread_rwlock_t lock = PTHREAD_RWLOCK_INITIALIZER;
13
14 static void handler(int sig, siginfo_t *si, void *ctx)
15 {
16         struct chain ch;
17         pthread_t self = __pthread_self();
18         int old_errno = errno;
19
20         if (chainlen == libc.threads_minus_1) return;
21
22         sigqueue(self->pid, SIGSYNCCALL, (union sigval){0});
23
24         /* Threads which have already decremented themselves from the
25          * thread count must not act. Block further receipt of signals
26          * and return. */
27         if (self->dead) {
28                 memset(&((ucontext_t *)ctx)->uc_sigmask, -1, 8);
29                 errno = old_errno;
30                 return;
31         }
32
33         sem_init(&ch.sem, 0, 0);
34         sem_init(&ch.sem2, 0, 0);
35
36         while (sem_wait(&chainlock));
37         ch.next = head;
38         head = &ch;
39         if (++chainlen == libc.threads_minus_1) sem_post(&chaindone);
40         sem_post(&chainlock);
41
42         while (sem_wait(&ch.sem));
43         callback(context);
44         sem_post(&ch.sem2);
45         while (sem_wait(&ch.sem));
46
47         errno = old_errno;
48 }
49
50 void __synccall_wait()
51 {
52         struct chain *ch = cur;
53         sem_post(&ch->sem2);
54         while (sem_wait(&ch->sem));
55         sem_post(&ch->sem);
56 }
57
58 void __synccall(void (*func)(void *), void *ctx)
59 {
60         pthread_t self;
61         struct sigaction sa;
62         struct chain *next;
63         uint64_t oldmask;
64
65         if (!libc.threads_minus_1) {
66                 func(ctx);
67                 return;
68         }
69
70         pthread_rwlock_wrlock(&lock);
71
72         __syscall(SYS_rt_sigprocmask, SIG_BLOCK, (uint64_t[]){-1}, &oldmask, 8);
73
74         sem_init(&chaindone, 0, 0);
75         sem_init(&chainlock, 0, 1);
76         chainlen = 0;
77         callback = func;
78         context = ctx;
79
80         sa.sa_flags = SA_SIGINFO | SA_RESTART;
81         sa.sa_sigaction = handler;
82         sigfillset(&sa.sa_mask);
83         __libc_sigaction(SIGSYNCCALL, &sa, 0);
84
85         self = __pthread_self();
86         sigqueue(self->pid, SIGSYNCCALL, (union sigval){0});
87         while (sem_wait(&chaindone));
88
89         for (cur=head; cur; cur=cur->next) {
90                 sem_post(&cur->sem);
91                 while (sem_wait(&cur->sem2));
92         }
93         func(ctx);
94
95         for (cur=head; cur; cur=next) {
96                 next = cur->next;
97                 sem_post(&cur->sem);
98         }
99
100         sa.sa_flags = 0;
101         sa.sa_handler = SIG_IGN;
102         __libc_sigaction(SIGSYNCCALL, &sa, 0);
103
104         __syscall(SYS_rt_sigprocmask, SIG_SETMASK, &oldmask, 0, 8);
105
106         pthread_rwlock_unlock(&lock);
107 }
108
109 void __synccall_lock()
110 {
111         pthread_rwlock_rdlock(&lock);
112 }
113
114 void __synccall_unlock()
115 {
116         pthread_rwlock_unlock(&lock);
117 }