Introduce interprocess signaling on Windows

This change gets rsync working without any warning or errors. On Windows
we now create a bunch of C:\var\sig\x\y.pid shared memory files, so sigs
can be delivered between processes. WinMain() creates this file when the
process starts. If the program links signaling system calls then we make
a thread at startup too, which allows asynchronous delivery each quantum
and cancelation points can spot these signals potentially faster on wait

See #1240
This commit is contained in:
Justine Tunney 2024-09-19 03:02:13 -07:00
parent 8527462b95
commit 0d74673213
No known key found for this signature in database
GPG key ID: BE714B4575D6E328
22 changed files with 302 additions and 62 deletions

View file

@ -17,26 +17,10 @@
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/atomic.h"
#include "libc/fmt/internal.h"
#include "libc/intrin/atomic.h"
#include "libc/runtime/internal.h"
static textwindows char16_t *itoa16(char16_t p[21], uint64_t x) {
char t;
size_t a, b, i = 0;
do {
p[i++] = x % 10 + '0';
x = x / 10;
} while (x > 0);
if (i) {
for (a = 0, b = i - 1; a < b; ++a, --b) {
t = p[a];
p[a] = p[b];
p[b] = t;
}
}
return p + i;
}
// This function is called very early by WinMain().
textwindows char16_t *__create_pipe_name(char16_t *a) {
char16_t *p = a;
@ -44,9 +28,9 @@ textwindows char16_t *__create_pipe_name(char16_t *a) {
static atomic_uint x;
while (*q)
*p++ = *q++;
p = itoa16(p, __pid);
p = __itoa16(p, __pid);
*p++ = '-';
p = itoa16(p, atomic_fetch_add(&x, 1));
p = __itoa16(p, atomic_fetch_add(&x, 1));
*p = 0;
return a;
}

View file

@ -32,12 +32,13 @@
#include "libc/intrin/bsf.h"
#include "libc/intrin/describebacktrace.h"
#include "libc/intrin/dll.h"
#include "libc/intrin/kprintf.h"
#include "libc/intrin/maps.h"
#include "libc/intrin/strace.h"
#include "libc/intrin/weaken.h"
#include "libc/nt/console.h"
#include "libc/nt/enum/context.h"
#include "libc/nt/enum/exceptionhandleractions.h"
#include "libc/nt/enum/processcreationflags.h"
#include "libc/nt/enum/signal.h"
#include "libc/nt/enum/status.h"
#include "libc/nt/events.h"
@ -46,6 +47,7 @@
#include "libc/nt/struct/ntexceptionpointers.h"
#include "libc/nt/synchronization.h"
#include "libc/nt/thread.h"
#include "libc/runtime/internal.h"
#include "libc/runtime/symbols.internal.h"
#include "libc/str/str.h"
#include "libc/sysv/consts/sa.h"
@ -58,6 +60,8 @@
* @fileoverview Cosmopolitan Signals for Windows.
*/
#define STKSZ 65536
struct SignalFrame {
unsigned rva;
unsigned flags;
@ -80,7 +84,7 @@ textwindows bool __sig_ignored(int sig) {
textwindows void __sig_delete(int sig) {
struct Dll *e;
atomic_fetch_and_explicit(&__sig.pending, ~(1ull << (sig - 1)),
atomic_fetch_and_explicit(__sig.process, ~(1ull << (sig - 1)),
memory_order_relaxed);
_pthread_lock();
for (e = dll_last(_pthread_list); e; e = dll_prev(_pthread_list, e))
@ -108,7 +112,7 @@ static textwindows int __sig_getter(atomic_ulong *sigs, sigset_t masked) {
textwindows int __sig_get(sigset_t masked) {
int sig;
if (!(sig = __sig_getter(&__get_tls()->tib_sigpending, masked)))
sig = __sig_getter(&__sig.pending, masked);
sig = __sig_getter(__sig.process, masked);
return sig;
}
@ -179,6 +183,7 @@ textwindows int __sig_raise(volatile int sig, int sic) {
unsigned rva, flags;
struct PosixThread *pt = _pthread_self();
if (__sig_start(pt, sig, &rva, &flags)) {
if (flags & SA_RESETHAND) {
STRACE("resetting %G handler", sig);
__sighandrvas[sig] = (int32_t)(intptr_t)SIG_DFL;
@ -410,7 +415,7 @@ textwindows void __sig_generate(int sig, int sic) {
STRACE("terminating on %G due to no handler", sig);
__sig_terminate(sig);
}
if (atomic_load_explicit(&__sig.pending, memory_order_acquire) &
if (atomic_load_explicit(__sig.process, memory_order_acquire) &
(1ull << (sig - 1))) {
return;
}
@ -448,7 +453,7 @@ textwindows void __sig_generate(int sig, int sic) {
__sig_killer(mark, sig, sic);
_pthread_unref(mark);
} else {
atomic_fetch_or_explicit(&__sig.pending, 1ull << (sig - 1),
atomic_fetch_or_explicit(__sig.process, 1ull << (sig - 1),
memory_order_relaxed);
}
ALLOW_SIGNALS;
@ -611,11 +616,28 @@ textwindows int __sig_check(void) {
}
}
// delivers signals from other processes asynchronously
textwindows dontinstrument static uint32_t __sig_worker(void *arg) {
struct CosmoTib tls;
__bootstrap_tls(&tls, __builtin_frame_address(0));
char *sp = __builtin_frame_address(0);
__maps_track((char *)(((uintptr_t)sp + __pagesize - 1) & -__pagesize) - STKSZ,
STKSZ);
for (;;) {
int sig;
if ((sig = __sig_getter(__sig.process, 0)))
__sig_generate(sig, SI_KERNEL);
Sleep(1);
}
return 0;
}
__attribute__((__constructor__(10))) textstartup void __sig_init(void) {
if (!IsWindows())
return;
AddVectoredExceptionHandler(true, (void *)__sig_crash);
SetConsoleCtrlHandler((void *)__sig_console, true);
CreateThread(0, STKSZ, __sig_worker, 0, kNtStackSizeParamIsAReservation, 0);
}
#endif /* __x86_64__ */

View file

@ -1,5 +1,6 @@
#ifndef COSMOPOLITAN_LIBC_CALLS_SIGNALS_INTERNAL_H_
#define COSMOPOLITAN_LIBC_CALLS_SIGNALS_INTERNAL_H_
#include "libc/atomic.h"
#include "libc/calls/struct/sigset.h"
#include "libc/thread/posixthread.internal.h"
@ -9,8 +10,8 @@
COSMOPOLITAN_C_START_
struct Signals {
_Atomic(uint64_t) pending;
_Atomic(uint64_t) count;
atomic_ulong *process;
atomic_ulong count;
};
extern struct Signals __sig;
@ -27,5 +28,8 @@ void __sig_delete(int);
void __sig_generate(int, int);
void __sig_init(void);
char16_t *__sig_process_path(char16_t *, uint32_t);
atomic_ulong *__sig_map_process(int);
COSMOPOLITAN_C_END_
#endif /* COSMOPOLITAN_LIBC_CALLS_SIGNALS_INTERNAL_H_ */

View file

@ -53,7 +53,7 @@ int sigpending(sigset_t *pending) {
}
rc = 0;
} else if (IsWindows()) {
*pending = atomic_load_explicit(&__sig.pending, memory_order_acquire) |
*pending = atomic_load_explicit(__sig.process, memory_order_acquire) |
atomic_load_explicit(&__get_tls()->tib_sigpending,
memory_order_acquire);
rc = 0;