25
25
#include "libc/calls/struct/siginfo.h"
26
26
#include "libc/calls/struct/sigset.internal.h"
27
27
#include "libc/calls/struct/ucontext.internal.h"
28
+ #include "libc/calls/syscall_support-nt.internal.h"
28
29
#include "libc/calls/ucontext.h"
29
30
#include "libc/dce.h"
30
31
#include "libc/errno.h"
@@ -135,7 +136,24 @@ static textwindows wontreturn void __sig_terminate(int sig) {
135
136
TerminateThisProcess (sig );
136
137
}
137
138
138
- static textwindows bool __sig_start (struct PosixThread * pt , int sig ,
139
+ textwindows static void __sig_wake (struct PosixThread * pt , int sig ) {
140
+ atomic_int * blocker ;
141
+ blocker = atomic_load_explicit (& pt -> pt_blocker , memory_order_acquire );
142
+ if (!blocker )
143
+ return ;
144
+ // threads can create semaphores on an as-needed basis
145
+ if (blocker == PT_BLOCKER_EVENT ) {
146
+ STRACE ("%G set %d's event object" , sig , _pthread_tid (pt ));
147
+ SetEvent (pt -> pt_event );
148
+ return ;
149
+ }
150
+ // all other blocking ops that aren't overlap should use futexes
151
+ // we force restartable futexes to churn by waking w/o releasing
152
+ STRACE ("%G waking %d's futex" , sig , _pthread_tid (pt ));
153
+ WakeByAddressSingle (blocker );
154
+ }
155
+
156
+ textwindows static bool __sig_start (struct PosixThread * pt , int sig ,
139
157
unsigned * rva , unsigned * flags ) {
140
158
* rva = __sighandrvas [sig ];
141
159
* flags = __sighandflags [sig ];
@@ -149,6 +167,7 @@ static textwindows bool __sig_start(struct PosixThread *pt, int sig,
149
167
STRACE ("enqueing %G on %d" , sig , _pthread_tid (pt ));
150
168
atomic_fetch_or_explicit (& pt -> tib -> tib_sigpending , 1ull << (sig - 1 ),
151
169
memory_order_relaxed );
170
+ __sig_wake (pt , sig );
152
171
return false;
153
172
}
154
173
if (* rva == (intptr_t )SIG_DFL ) {
@@ -158,7 +177,7 @@ static textwindows bool __sig_start(struct PosixThread *pt, int sig,
158
177
return true;
159
178
}
160
179
161
- static textwindows sigaction_f __sig_handler (unsigned rva ) {
180
+ textwindows static sigaction_f __sig_handler (unsigned rva ) {
162
181
atomic_fetch_add_explicit (& __sig .count , 1 , memory_order_relaxed );
163
182
return (sigaction_f )(__executable_start + rva );
164
183
}
@@ -228,34 +247,15 @@ textwindows int __sig_relay(int sig, int sic, sigset_t waitmask) {
228
247
return handler_was_called ;
229
248
}
230
249
231
- // cancels blocking operations being performed by signaled thread
232
- textwindows void __sig_cancel (struct PosixThread * pt , int sig , unsigned flags ) {
233
- atomic_int * blocker ;
234
- blocker = atomic_load_explicit (& pt -> pt_blocker , memory_order_acquire );
235
- if (!blocker ) {
236
- STRACE ("%G sent to %d asynchronously" , sig , _pthread_tid (pt ));
237
- return ;
238
- }
239
- // threads can create semaphores on an as-needed basis
240
- if (blocker == PT_BLOCKER_EVENT ) {
241
- STRACE ("%G set %d's event object" , sig , _pthread_tid (pt ));
242
- SetEvent (pt -> pt_event );
243
- return ;
244
- }
245
- // all other blocking ops that aren't overlap should use futexes
246
- // we force restartable futexes to churn by waking w/o releasing
247
- STRACE ("%G waking %d's futex" , sig , _pthread_tid (pt ));
248
- WakeByAddressSingle (blocker );
249
- }
250
-
251
250
// the user's signal handler callback is wrapped with this trampoline
252
251
static textwindows wontreturn void __sig_tramp (struct SignalFrame * sf ) {
253
252
int sig = sf -> si .si_signo ;
254
253
struct CosmoTib * tib = __get_tls ();
255
254
struct PosixThread * pt = (struct PosixThread * )tib -> tib_pthread ;
255
+ atomic_store_explicit (& pt -> pt_intoff , 0 , memory_order_release );
256
256
for (;;) {
257
257
258
- // update the signal mask in preparation for signal handller
258
+ // update the signal mask in preparation for signal handler
259
259
sigset_t blocksigs = __sighandmask [sig ];
260
260
if (!(sf -> flags & SA_NODEFER ))
261
261
blocksigs |= 1ull << (sig - 1 );
@@ -302,12 +302,16 @@ static textwindows int __sig_killer(struct PosixThread *pt, int sig, int sic) {
302
302
return 0 ;
303
303
}
304
304
305
- // we can't preempt threads that masked sig or are blocked
306
- if (atomic_load_explicit (& pt -> tib -> tib_sigmask , memory_order_acquire ) &
307
- (1ull << (sig - 1 ))) {
305
+ // we can't preempt threads that masked sig or are blocked. we aso
306
+ // need to ensure we don't the target thread's stack if many signals
307
+ // need to be delivered at once. we also need to make sure two threads
308
+ // can't deadlock by killing each other at the same time.
309
+ if ((atomic_load_explicit (& pt -> tib -> tib_sigmask , memory_order_acquire ) &
310
+ (1ull << (sig - 1 ))) ||
311
+ atomic_exchange_explicit (& pt -> pt_intoff , 1 , memory_order_acquire )) {
308
312
atomic_fetch_or_explicit (& pt -> tib -> tib_sigpending , 1ull << (sig - 1 ),
309
313
memory_order_relaxed );
310
- __sig_cancel (pt , sig , flags );
314
+ __sig_wake (pt , sig );
311
315
return 0 ;
312
316
}
313
317
@@ -321,28 +325,26 @@ static textwindows int __sig_killer(struct PosixThread *pt, int sig, int sic) {
321
325
uintptr_t th = _pthread_syshand (pt );
322
326
if (atomic_load_explicit (& pt -> tib -> tib_sigpending , memory_order_acquire ) &
323
327
(1ull << (sig - 1 ))) {
328
+ atomic_store_explicit (& pt -> pt_intoff , 0 , memory_order_release );
324
329
return 0 ;
325
330
}
326
331
327
332
// take control of thread
328
333
// suspending the thread happens asynchronously
329
334
// however getting the context blocks until it's frozen
330
- static pthread_spinlock_t killer_lock ;
331
- pthread_spin_lock (& killer_lock );
332
335
if (SuspendThread (th ) == -1u ) {
333
336
STRACE ("SuspendThread failed w/ %d" , GetLastError ());
334
- pthread_spin_unlock ( & killer_lock );
337
+ atomic_store_explicit ( & pt -> pt_intoff , 0 , memory_order_release );
335
338
return ESRCH ;
336
339
}
337
340
struct NtContext nc ;
338
341
nc .ContextFlags = kNtContextFull ;
339
342
if (!GetThreadContext (th , & nc )) {
340
343
STRACE ("GetThreadContext failed w/ %d" , GetLastError ());
341
344
ResumeThread (th );
342
- pthread_spin_unlock ( & killer_lock );
345
+ atomic_store_explicit ( & pt -> pt_intoff , 0 , memory_order_release );
343
346
return ESRCH ;
344
347
}
345
- pthread_spin_unlock (& killer_lock );
346
348
347
349
// we can't preempt threads that masked sig or are blocked
348
350
// we can't preempt threads that are running in win32 code
@@ -354,7 +356,8 @@ static textwindows int __sig_killer(struct PosixThread *pt, int sig, int sic) {
354
356
atomic_fetch_or_explicit (& pt -> tib -> tib_sigpending , 1ull << (sig - 1 ),
355
357
memory_order_relaxed );
356
358
ResumeThread (th );
357
- __sig_cancel (pt , sig , flags );
359
+ atomic_store_explicit (& pt -> pt_intoff , 0 , memory_order_release );
360
+ __sig_wake (pt , sig );
358
361
return 0 ;
359
362
}
360
363
@@ -387,10 +390,11 @@ static textwindows int __sig_killer(struct PosixThread *pt, int sig, int sic) {
387
390
nc .Rsp = sp ;
388
391
if (!SetThreadContext (th , & nc )) {
389
392
STRACE ("SetThreadContext failed w/ %d" , GetLastError ());
393
+ atomic_store_explicit (& pt -> pt_intoff , 0 , memory_order_release );
390
394
return ESRCH ;
391
395
}
392
396
ResumeThread (th );
393
- __sig_cancel (pt , sig , flags );
397
+ __sig_wake (pt , sig );
394
398
return 0 ;
395
399
}
396
400
@@ -404,6 +408,7 @@ textwindows int __sig_kill(struct PosixThread *pt, int sig, int sic) {
404
408
}
405
409
406
410
// sends signal to any other thread
411
+ // this should only be called by non-posix threads
407
412
textwindows void __sig_generate (int sig , int sic ) {
408
413
struct Dll * e ;
409
414
struct PosixThread * pt , * mark = 0 ;
@@ -450,6 +455,7 @@ textwindows void __sig_generate(int sig, int sic) {
450
455
}
451
456
_pthread_unlock ();
452
457
if (mark ) {
458
+ // no lock needed since current thread is nameless and formless
453
459
__sig_killer (mark , sig , sic );
454
460
_pthread_unref (mark );
455
461
} else {
@@ -610,13 +616,11 @@ __msabi textwindows dontinstrument bool32 __sig_console(uint32_t dwCtrlType) {
610
616
// didn't have the SA_RESTART flag, and `2`, which means SA_RESTART
611
617
// handlers were called (or `3` if both were the case).
612
618
textwindows int __sig_check (void ) {
613
- int sig ;
614
- if ((sig = __sig_get (atomic_load_explicit (& __get_tls ()-> tib_sigmask ,
615
- memory_order_acquire )))) {
616
- return __sig_raise (sig , SI_KERNEL );
617
- } else {
618
- return 0 ;
619
- }
619
+ int sig , res = 0 ;
620
+ while ((sig = __sig_get (atomic_load_explicit (& __get_tls ()-> tib_sigmask ,
621
+ memory_order_acquire ))))
622
+ res |= __sig_raise (sig , SI_KERNEL );
623
+ return res ;
620
624
}
621
625
622
626
// background thread for delivering inter-process signals asynchronously
@@ -642,7 +646,7 @@ textwindows dontinstrument static uint32_t __sig_worker(void *arg) {
642
646
sigs &= ~(1ull << (sig - 1 ));
643
647
__sig_generate (sig , SI_KERNEL );
644
648
}
645
- Sleep (1 );
649
+ Sleep (POLL_INTERVAL_MS );
646
650
}
647
651
return 0 ;
648
652
}
0 commit comments