diff --git a/libc/intrin/sig.c b/libc/intrin/sig.c index 4f622a81986..0cf56902d3f 100644 --- a/libc/intrin/sig.c +++ b/libc/intrin/sig.c @@ -87,7 +87,7 @@ __msabi extern typeof(VirtualProtectEx) *const __imp_VirtualProtectEx; __msabi extern typeof(VirtualQuery) *const __imp_VirtualQuery; __msabi extern typeof(WriteFile) *const __imp_WriteFile; -extern pthread_mutex_t __sig_worker_lock; +atomic_int __sig_worker_state; textwindows static bool __sig_ignored_by_default(int sig) { return sig == SIGURG || // @@ -742,39 +742,21 @@ HAIRY static uint32_t __sig_worker(void *arg) { STKSZ, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS | MAP_NOFORK); for (;;) { - _pthread_mutex_lock(&__sig_worker_lock); - - // dequeue all pending signals and fire them off. if there's no - // thread that can handle them then __sig_generate will requeue - // those signals back to __sig.process; hence the need for xchg - unsigned long sigs = - atomic_exchange_explicit(__sig.process, 0, memory_order_acq_rel); - while (sigs) { - int sig = bsfl(sigs) + 1; - sigs &= ~(1ull << (sig - 1)); - __sig_generate(sig, SI_KERNEL); - } - - // unblock stalled i/o signals in threads - _pthread_lock(); - for (struct Dll *e = dll_first(_pthread_list); e; - e = dll_next(_pthread_list, e)) { - struct PosixThread *pt = POSIXTHREAD_CONTAINER(e); - if (atomic_load_explicit(&pt->pt_status, memory_order_acquire) >= - kPosixThreadTerminated) - break; - if (atomic_load_explicit(&pt->pt_blocker, memory_order_acquire) && - (atomic_load_explicit(&pt->tib->tib_sigpending, - memory_order_acquire) & - ~atomic_load_explicit(&pt->pt_blkmask, memory_order_acquire))) - __sig_wake(pt, 0); - } - _pthread_unlock(); + // ok sys_execve_nt() might disable this worker + if (~__sig_worker_state & 2) { + + // dequeue all pending signals and fire them off. if there's no + // thread that can handle them then __sig_generate will requeue + // those signals back to __sig.process; hence the need for xchg + unsigned long sigs = + atomic_exchange_explicit(__sig.process, 0, memory_order_acq_rel); + while (sigs) { + int sig = bsfl(sigs) + 1; + sigs &= ~(1ull << (sig - 1)); + __sig_generate(sig, SI_KERNEL); + } - // unblock stalled asynchronous signals in threads - for (;;) { - sigset_t pending, mask; - struct PosixThread *mark = 0; + // unblock stalled i/o signals in threads _pthread_lock(); for (struct Dll *e = dll_first(_pthread_list); e; e = dll_next(_pthread_list, e)) { @@ -782,34 +764,55 @@ HAIRY static uint32_t __sig_worker(void *arg) { if (atomic_load_explicit(&pt->pt_status, memory_order_acquire) >= kPosixThreadTerminated) break; - pending = atomic_load_explicit(&pt->tib->tib_sigpending, - memory_order_acquire); - mask = - atomic_load_explicit(&pt->tib->tib_sigmask, memory_order_acquire); - if (pending & ~mask) { - _pthread_ref(pt); - mark = pt; - break; - } + if (atomic_load_explicit(&pt->pt_blocker, memory_order_acquire) && + (atomic_load_explicit(&pt->tib->tib_sigpending, + memory_order_acquire) & + ~atomic_load_explicit(&pt->pt_blkmask, memory_order_acquire))) + __sig_wake(pt, 0); } _pthread_unlock(); - if (!mark) - break; - while (!atomic_compare_exchange_weak_explicit( - &mark->tib->tib_sigpending, &pending, pending & ~mask, - memory_order_acq_rel, memory_order_relaxed)) { - } - while ((pending = pending & ~mask)) { - int sig = bsfl(pending) + 1; - pending &= ~(1ull << (sig - 1)); - __sig_killer(mark, sig, SI_KERNEL); + + // unblock stalled asynchronous signals in threads + for (;;) { + sigset_t pending, mask; + struct PosixThread *mark = 0; + _pthread_lock(); + for (struct Dll *e = dll_first(_pthread_list); e; + e = dll_next(_pthread_list, e)) { + struct PosixThread *pt = POSIXTHREAD_CONTAINER(e); + if (atomic_load_explicit(&pt->pt_status, memory_order_acquire) >= + kPosixThreadTerminated) + break; + pending = atomic_load_explicit(&pt->tib->tib_sigpending, + memory_order_acquire); + mask = + atomic_load_explicit(&pt->tib->tib_sigmask, memory_order_acquire); + if (pending & ~mask) { + _pthread_ref(pt); + mark = pt; + break; + } + } + _pthread_unlock(); + if (!mark) + break; + while (!atomic_compare_exchange_weak_explicit( + &mark->tib->tib_sigpending, &pending, pending & ~mask, + memory_order_acq_rel, memory_order_relaxed)) { + } + while ((pending = pending & ~mask)) { + int sig = bsfl(pending) + 1; + pending &= ~(1ull << (sig - 1)); + __sig_killer(mark, sig, SI_KERNEL); + } + _pthread_unref(mark); } - _pthread_unref(mark); } // wait until next scheduler quantum - _pthread_mutex_unlock(&__sig_worker_lock); + __sig_worker_state |= 1; Sleep(POLL_INTERVAL_MS); + __sig_worker_state &= ~1; } __builtin_unreachable(); } diff --git a/libc/intrin/siglock.c b/libc/intrin/siglock.c deleted file mode 100644 index ab6045f4bd7..00000000000 --- a/libc/intrin/siglock.c +++ /dev/null @@ -1,22 +0,0 @@ -/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│ -│ vi: set et ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi │ -╞══════════════════════════════════════════════════════════════════════════════╡ -│ Copyright 2024 Justine Alexandra Roberts Tunney │ -│ │ -│ Permission to use, copy, modify, and/or distribute this software for │ -│ any purpose with or without fee is hereby granted, provided that the │ -│ above copyright notice and this permission notice appear in all copies. │ -│ │ -│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │ -│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │ -│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │ -│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │ -│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │ -│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │ -│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ -│ PERFORMANCE OF THIS SOFTWARE. │ -╚─────────────────────────────────────────────────────────────────────────────*/ -#include "libc/thread/thread.h" - -// this mutex is needed so execve() can shut down the signal worker -pthread_mutex_t __sig_worker_lock = PTHREAD_MUTEX_INITIALIZER; diff --git a/libc/proc/execve-nt.greg.c b/libc/proc/execve-nt.greg.c index 2a65d4f9e76..42cb01c67fd 100644 --- a/libc/proc/execve-nt.greg.c +++ b/libc/proc/execve-nt.greg.c @@ -17,6 +17,7 @@ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/assert.h" +#include "libc/atomic.h" #include "libc/calls/calls.h" #include "libc/calls/internal.h" #include "libc/calls/sig.internal.h" @@ -57,11 +58,10 @@ __msabi extern typeof(CloseHandle) *const __imp_CloseHandle; __msabi extern typeof(TerminateProcess) *const __imp_TerminateProcess; -extern pthread_mutex_t __sig_worker_lock; +extern atomic_int __sig_worker_state; static void sys_execve_nt_abort(sigset_t sigmask) { - _pthread_unlock(); - _pthread_mutex_unlock(&__sig_worker_lock); + __sig_worker_state &= ~2; __sig_unblock(sigmask); } @@ -70,8 +70,10 @@ textwindows int sys_execve_nt(const char *program, char *const argv[], // execve() needs to be @asyncsignalsafe sigset_t sigmask = __sig_block(); - _pthread_mutex_lock(&__sig_worker_lock); // order matters - _pthread_lock(); // order matters + __sig_worker_state |= 2; + for (;;) + if (__sig_worker_state & 1) + break; // new process should be a child of our parent int64_t hParentProcess = @@ -176,6 +178,7 @@ textwindows int sys_execve_nt(const char *program, char *const argv[], STRACE("warning: execve() lingering due to non-cosmo parent process"); // terminate other threads + _pthread_lock(); struct Dll *e; struct PosixThread *me = _pthread_self(); for (e = dll_first(_pthread_list); e; e = dll_next(_pthread_list, e)) { diff --git a/libc/proc/fork.c b/libc/proc/fork.c index 81cb09b9164..fad92dc5a05 100644 --- a/libc/proc/fork.c +++ b/libc/proc/fork.c @@ -16,6 +16,7 @@ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ +#include "libc/atomic.h" #include "libc/calls/calls.h" #include "libc/calls/internal.h" #include "libc/calls/sig.internal.h" @@ -54,9 +55,9 @@ __msabi extern typeof(GetCurrentProcessId) *const __imp_GetCurrentProcessId; +extern atomic_int __sig_worker_state; extern pthread_mutex_t __cxa_lock_obj; extern pthread_mutex_t __pthread_lock_obj; -extern pthread_mutex_t __sig_worker_lock; void __rand64_lock(void); void __rand64_unlock(void); @@ -191,7 +192,7 @@ static void fork_child(int ppid_win32, int ppid_cosmo) { sys_read_nt_wipe_keystrokes(); __proc_wipe_and_reset(); __itimer_wipe_and_reset(); - _pthread_mutex_wipe_np(&__sig_worker_lock); + atomic_init(&__sig_worker_state, 0); if (_weaken(__sig_init)) _weaken(__sig_init)(); if (_weaken(sys_getppid_nt_wipe)) diff --git a/test/libc/proc/execve_test.c b/test/libc/proc/execve_test.c index 58d7680f517..7bfd7b10228 100644 --- a/test/libc/proc/execve_test.c +++ b/test/libc/proc/execve_test.c @@ -58,8 +58,7 @@ TEST(execve, testArgPassing) { FormatInt32(ibuf, i); GenBuf(buf, i); SPAWN(vfork); - execve(prog, (char *const[]){(char *)prog, "-", ibuf, buf, 0}, - (char *const[]){0}); + execl(prog, prog, "-", ibuf, buf, NULL); kprintf("execve failed: %m\n"); EXITS(0); }