Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(926)

Side by Side Diff: fusl/src/thread/synccall.c

Issue 1714623002: [fusl] clang-format fusl (Closed) Base URL: git@github.com:domokit/mojo.git@master
Patch Set: headers too Created 4 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 #include "pthread_impl.h" 1 #include "pthread_impl.h"
2 #include <semaphore.h> 2 #include <semaphore.h>
3 #include <unistd.h> 3 #include <unistd.h>
4 #include <dirent.h> 4 #include <dirent.h>
5 #include <string.h> 5 #include <string.h>
6 #include <ctype.h> 6 #include <ctype.h>
7 #include "futex.h" 7 #include "futex.h"
8 #include "atomic.h" 8 #include "atomic.h"
9 #include "../dirent/__dirent.h" 9 #include "../dirent/__dirent.h"
10 10
11 static struct chain { 11 static struct chain {
12 » struct chain *next; 12 struct chain* next;
13 » int tid; 13 int tid;
14 » sem_t target_sem, caller_sem; 14 sem_t target_sem, caller_sem;
15 } *volatile head; 15 } * volatile head;
16 16
17 static volatile int synccall_lock[2]; 17 static volatile int synccall_lock[2];
18 static volatile int target_tid; 18 static volatile int target_tid;
19 static void (*callback)(void *), *context; 19 static void (*callback)(void*), *context;
20 static volatile int dummy = 0; 20 static volatile int dummy = 0;
21 weak_alias(dummy, __block_new_threads); 21 weak_alias(dummy, __block_new_threads);
22 22
23 static void handler(int sig) 23 static void handler(int sig) {
24 { 24 struct chain ch;
25 » struct chain ch; 25 int old_errno = errno;
26 » int old_errno = errno;
27 26
28 » sem_init(&ch.target_sem, 0, 0); 27 sem_init(&ch.target_sem, 0, 0);
29 » sem_init(&ch.caller_sem, 0, 0); 28 sem_init(&ch.caller_sem, 0, 0);
30 29
31 » ch.tid = __syscall(SYS_gettid); 30 ch.tid = __syscall(SYS_gettid);
32 31
33 » do ch.next = head; 32 do
34 » while (a_cas_p(&head, ch.next, &ch) != ch.next); 33 ch.next = head;
34 while (a_cas_p(&head, ch.next, &ch) != ch.next);
35 35
36 » if (a_cas(&target_tid, ch.tid, 0) == (ch.tid | 0x80000000)) 36 if (a_cas(&target_tid, ch.tid, 0) == (ch.tid | 0x80000000))
37 » » __syscall(SYS_futex, &target_tid, FUTEX_UNLOCK_PI|FUTEX_PRIVATE) ; 37 __syscall(SYS_futex, &target_tid, FUTEX_UNLOCK_PI | FUTEX_PRIVATE);
38 38
39 » sem_wait(&ch.target_sem); 39 sem_wait(&ch.target_sem);
40 » callback(context); 40 callback(context);
41 » sem_post(&ch.caller_sem); 41 sem_post(&ch.caller_sem);
42 » sem_wait(&ch.target_sem); 42 sem_wait(&ch.target_sem);
43 43
44 » errno = old_errno; 44 errno = old_errno;
45 } 45 }
46 46
47 void __synccall(void (*func)(void *), void *ctx) 47 void __synccall(void (*func)(void*), void* ctx) {
48 { 48 sigset_t oldmask;
49 » sigset_t oldmask; 49 int cs, i, r, pid, self;
50 » int cs, i, r, pid, self;; 50 ;
51 » DIR dir = {0}; 51 DIR dir = {0};
52 » struct dirent *de; 52 struct dirent* de;
53 » struct sigaction sa = { .sa_flags = 0, .sa_handler = handler }; 53 struct sigaction sa = {.sa_flags = 0, .sa_handler = handler};
54 » struct chain *cp, *next; 54 struct chain *cp, *next;
55 » struct timespec ts; 55 struct timespec ts;
56 56
57 » /* Blocking signals in two steps, first only app-level signals 57 /* Blocking signals in two steps, first only app-level signals
58 » * before taking the lock, then all signals after taking the lock, 58 * before taking the lock, then all signals after taking the lock,
59 » * is necessary to achieve AS-safety. Blocking them all first would 59 * is necessary to achieve AS-safety. Blocking them all first would
60 » * deadlock if multiple threads called __synccall. Waiting to block 60 * deadlock if multiple threads called __synccall. Waiting to block
61 » * any until after the lock would allow re-entry in the same thread 61 * any until after the lock would allow re-entry in the same thread
62 » * with the lock already held. */ 62 * with the lock already held. */
63 » __block_app_sigs(&oldmask); 63 __block_app_sigs(&oldmask);
64 » LOCK(synccall_lock); 64 LOCK(synccall_lock);
65 » __block_all_sigs(0); 65 __block_all_sigs(0);
66 » pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &cs); 66 pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &cs);
67 67
68 » head = 0; 68 head = 0;
69 69
70 » if (!libc.threaded) goto single_threaded; 70 if (!libc.threaded)
71 goto single_threaded;
71 72
72 » callback = func; 73 callback = func;
73 » context = ctx; 74 context = ctx;
74 75
75 » /* This atomic store ensures that any signaled threads will see the 76 /* This atomic store ensures that any signaled threads will see the
76 » * above stores, and prevents more than a bounded number of threads, 77 * above stores, and prevents more than a bounded number of threads,
77 » * those already in pthread_create, from creating new threads until 78 * those already in pthread_create, from creating new threads until
78 » * the value is cleared to zero again. */ 79 * the value is cleared to zero again. */
79 » a_store(&__block_new_threads, 1); 80 a_store(&__block_new_threads, 1);
80 81
81 » /* Block even implementation-internal signals, so that nothing 82 /* Block even implementation-internal signals, so that nothing
82 » * interrupts the SIGSYNCCALL handlers. The main possible source 83 * interrupts the SIGSYNCCALL handlers. The main possible source
83 » * of trouble is asynchronous cancellation. */ 84 * of trouble is asynchronous cancellation. */
84 » memset(&sa.sa_mask, -1, sizeof sa.sa_mask); 85 memset(&sa.sa_mask, -1, sizeof sa.sa_mask);
85 » __libc_sigaction(SIGSYNCCALL, &sa, 0); 86 __libc_sigaction(SIGSYNCCALL, &sa, 0);
86 87
87 » pid = __syscall(SYS_getpid); 88 pid = __syscall(SYS_getpid);
88 » self = __syscall(SYS_gettid); 89 self = __syscall(SYS_gettid);
89 90
90 » /* Since opendir is not AS-safe, the DIR needs to be setup manually 91 /* Since opendir is not AS-safe, the DIR needs to be setup manually
91 » * in automatic storage. Thankfully this is easy. */ 92 * in automatic storage. Thankfully this is easy. */
92 » dir.fd = open("/proc/self/task", O_RDONLY|O_DIRECTORY|O_CLOEXEC); 93 dir.fd = open("/proc/self/task", O_RDONLY | O_DIRECTORY | O_CLOEXEC);
93 » if (dir.fd < 0) goto out; 94 if (dir.fd < 0)
95 goto out;
94 96
95 » /* Initially send one signal per counted thread. But since we can't 97 /* Initially send one signal per counted thread. But since we can't
96 » * synchronize with thread creation/exit here, there could be too 98 * synchronize with thread creation/exit here, there could be too
97 » * few signals. This initial signaling is just an optimization, not 99 * few signals. This initial signaling is just an optimization, not
98 » * part of the logic. */ 100 * part of the logic. */
99 » for (i=libc.threads_minus_1; i; i--) 101 for (i = libc.threads_minus_1; i; i--)
100 » » __syscall(SYS_kill, pid, SIGSYNCCALL); 102 __syscall(SYS_kill, pid, SIGSYNCCALL);
101 103
102 » /* Loop scanning the kernel-provided thread list until it shows no 104 /* Loop scanning the kernel-provided thread list until it shows no
103 » * threads that have not already replied to the signal. */ 105 * threads that have not already replied to the signal. */
104 » for (;;) { 106 for (;;) {
105 » » int miss_cnt = 0; 107 int miss_cnt = 0;
106 » » while ((de = readdir(&dir))) { 108 while ((de = readdir(&dir))) {
107 » » » if (!isdigit(de->d_name[0])) continue; 109 if (!isdigit(de->d_name[0]))
108 » » » int tid = atoi(de->d_name); 110 continue;
109 » » » if (tid == self || !tid) continue; 111 int tid = atoi(de->d_name);
112 if (tid == self || !tid)
113 continue;
110 114
111 » » » /* Set the target thread as the PI futex owner before 115 /* Set the target thread as the PI futex owner before
112 » » » * checking if it's in the list of caught threads. If it 116 * checking if it's in the list of caught threads. If it
113 » » » * adds itself to the list after we check for it, then 117 * adds itself to the list after we check for it, then
114 » » » * it will see its own tid in the PI futex and perform 118 * it will see its own tid in the PI futex and perform
115 » » » * the unlock operation. */ 119 * the unlock operation. */
116 » » » a_store(&target_tid, tid); 120 a_store(&target_tid, tid);
117 121
118 » » » /* Thread-already-caught is a success condition. */ 122 /* Thread-already-caught is a success condition. */
119 » » » for (cp = head; cp && cp->tid != tid; cp=cp->next); 123 for (cp = head; cp && cp->tid != tid; cp = cp->next)
120 » » » if (cp) continue; 124 ;
125 if (cp)
126 continue;
121 127
122 » » » r = -__syscall(SYS_tgkill, pid, tid, SIGSYNCCALL); 128 r = -__syscall(SYS_tgkill, pid, tid, SIGSYNCCALL);
123 129
124 » » » /* Target thread exit is a success condition. */ 130 /* Target thread exit is a success condition. */
125 » » » if (r == ESRCH) continue; 131 if (r == ESRCH)
132 continue;
126 133
127 » » » /* The FUTEX_LOCK_PI operation is used to loan priority 134 /* The FUTEX_LOCK_PI operation is used to loan priority
128 » » » * to the target thread, which otherwise may be unable 135 * to the target thread, which otherwise may be unable
129 » » » * to run. Timeout is necessary because there is a race 136 * to run. Timeout is necessary because there is a race
130 » » » * condition where the tid may be reused by a different 137 * condition where the tid may be reused by a different
131 » » » * process. */ 138 * process. */
132 » » » clock_gettime(CLOCK_REALTIME, &ts); 139 clock_gettime(CLOCK_REALTIME, &ts);
133 » » » ts.tv_nsec += 10000000; 140 ts.tv_nsec += 10000000;
134 » » » if (ts.tv_nsec >= 1000000000) { 141 if (ts.tv_nsec >= 1000000000) {
135 » » » » ts.tv_sec++; 142 ts.tv_sec++;
136 » » » » ts.tv_nsec -= 1000000000; 143 ts.tv_nsec -= 1000000000;
137 » » » } 144 }
138 » » » r = -__syscall(SYS_futex, &target_tid, 145 r = -__syscall(SYS_futex, &target_tid, FUTEX_LOCK_PI | FUTEX_PRIVATE, 0,
139 » » » » FUTEX_LOCK_PI|FUTEX_PRIVATE, 0, &ts); 146 &ts);
140 147
141 » » » /* Obtaining the lock means the thread responded. ESRCH 148 /* Obtaining the lock means the thread responded. ESRCH
142 » » » * means the target thread exited, which is okay too. */ 149 * means the target thread exited, which is okay too. */
143 » » » if (!r || r == ESRCH) continue; 150 if (!r || r == ESRCH)
151 continue;
144 152
145 » » » miss_cnt++; 153 miss_cnt++;
146 » » } 154 }
147 » » if (!miss_cnt) break; 155 if (!miss_cnt)
148 » » rewinddir(&dir); 156 break;
149 » } 157 rewinddir(&dir);
150 » close(dir.fd); 158 }
159 close(dir.fd);
151 160
152 » /* Serialize execution of callback in caught threads. */ 161 /* Serialize execution of callback in caught threads. */
153 » for (cp=head; cp; cp=cp->next) { 162 for (cp = head; cp; cp = cp->next) {
154 » » sem_post(&cp->target_sem); 163 sem_post(&cp->target_sem);
155 » » sem_wait(&cp->caller_sem); 164 sem_wait(&cp->caller_sem);
156 » } 165 }
157 166
158 » sa.sa_handler = SIG_IGN; 167 sa.sa_handler = SIG_IGN;
159 » __libc_sigaction(SIGSYNCCALL, &sa, 0); 168 __libc_sigaction(SIGSYNCCALL, &sa, 0);
160 169
161 single_threaded: 170 single_threaded:
162 » func(ctx); 171 func(ctx);
163 172
164 » /* Only release the caught threads once all threads, including the 173 /* Only release the caught threads once all threads, including the
165 » * caller, have returned from the callback function. */ 174 * caller, have returned from the callback function. */
166 » for (cp=head; cp; cp=next) { 175 for (cp = head; cp; cp = next) {
167 » » next = cp->next; 176 next = cp->next;
168 » » sem_post(&cp->target_sem); 177 sem_post(&cp->target_sem);
169 » } 178 }
170 179
171 out: 180 out:
172 » a_store(&__block_new_threads, 0); 181 a_store(&__block_new_threads, 0);
173 » __wake(&__block_new_threads, -1, 1); 182 __wake(&__block_new_threads, -1, 1);
174 183
175 » pthread_setcancelstate(cs, 0); 184 pthread_setcancelstate(cs, 0);
176 » UNLOCK(synccall_lock); 185 UNLOCK(synccall_lock);
177 » __restore_sigs(&oldmask); 186 __restore_sigs(&oldmask);
178 } 187 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698