Attempt to fix MODE=dbg Windows execve() flake

This commit is contained in:
Justine Tunney 2025-01-05 13:46:47 -08:00
parent 7b67b20dae
commit 035b0e2a62
No known key found for this signature in database
GPG key ID: BE714B4575D6E328
5 changed files with 68 additions and 84 deletions

View file

@ -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);
// 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);
}
// 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();
// 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)) {
// 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);
}
while ((pending = pending & ~mask)) {
int sig = bsfl(pending) + 1;
pending &= ~(1ull << (sig - 1));
__sig_killer(mark, sig, SI_KERNEL);
}
_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();
}

View file

@ -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;

View file

@ -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)) {

View file

@ -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))

View file

@ -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);
}