mirror of
https://github.com/jart/cosmopolitan.git
synced 2025-01-31 03:27:39 +00:00
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:
parent
8527462b95
commit
0d74673213
22 changed files with 302 additions and 62 deletions
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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__ */
|
||||
|
|
|
@ -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_ */
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -48,5 +48,6 @@
|
|||
int __vcscanf(int (*)(void *), int (*)(int, void *), void *, const char *,
|
||||
va_list);
|
||||
int __fmt(void *, void *, const char *, va_list, int *);
|
||||
char16_t *__itoa16(char16_t[21], uint64_t);
|
||||
|
||||
#endif /* COSMOPOLITAN_LIBC_FMT_STRTOL_H_ */
|
||||
|
|
36
libc/intrin/itoa16.c
Normal file
36
libc/intrin/itoa16.c
Normal file
|
@ -0,0 +1,36 @@
|
|||
/*-*- 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/fmt/internal.h"
|
||||
|
||||
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;
|
||||
}
|
|
@ -17,11 +17,25 @@
|
|||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/sysv/consts/sig.h"
|
||||
#include "libc/atomic.h"
|
||||
#include "libc/calls/sig.internal.h"
|
||||
#include "libc/calls/struct/sigset.internal.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/fmt/internal.h"
|
||||
#include "libc/intrin/atomic.h"
|
||||
#include "libc/intrin/weaken.h"
|
||||
#include "libc/limits.h"
|
||||
#include "libc/nt/createfile.h"
|
||||
#include "libc/nt/enum/accessmask.h"
|
||||
#include "libc/nt/enum/creationdisposition.h"
|
||||
#include "libc/nt/enum/fileflagandattributes.h"
|
||||
#include "libc/nt/enum/filemapflags.h"
|
||||
#include "libc/nt/enum/filemovemethod.h"
|
||||
#include "libc/nt/enum/filesharemode.h"
|
||||
#include "libc/nt/enum/pageflags.h"
|
||||
#include "libc/nt/files.h"
|
||||
#include "libc/nt/memory.h"
|
||||
#include "libc/nt/runtime.h"
|
||||
#include "libc/thread/tls.h"
|
||||
|
||||
struct Signals __sig;
|
||||
|
@ -52,3 +66,65 @@ void __sig_unblock(sigset_t m) {
|
|||
sys_sigprocmask(SIG_SETMASK, &m, 0);
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef __x86_64__
|
||||
|
||||
textwindows char16_t *__sig_process_path(char16_t *path, uint32_t pid) {
|
||||
char16_t *p = path;
|
||||
*p++ = 'C';
|
||||
*p++ = ':';
|
||||
*p++ = '\\';
|
||||
*p++ = 'v';
|
||||
*p++ = 'a';
|
||||
*p++ = 'r';
|
||||
*p = 0;
|
||||
CreateDirectory(path, 0);
|
||||
*p++ = '\\';
|
||||
*p++ = 's';
|
||||
*p++ = 'i';
|
||||
*p++ = 'g';
|
||||
*p = 0;
|
||||
CreateDirectory(path, 0);
|
||||
*p++ = '\\';
|
||||
p = __itoa16(p, (pid & 0x000fff00) >> 8);
|
||||
*p = 0;
|
||||
CreateDirectory(path, 0);
|
||||
*p++ = '\\';
|
||||
p = __itoa16(p, pid);
|
||||
*p++ = '.';
|
||||
*p++ = 'p';
|
||||
*p++ = 'i';
|
||||
*p++ = 'd';
|
||||
*p = 0;
|
||||
return path;
|
||||
}
|
||||
|
||||
textwindows static atomic_ulong *__sig_map_process_impl(int pid) {
|
||||
char16_t path[128];
|
||||
intptr_t hand = CreateFile(__sig_process_path(path, pid),
|
||||
kNtGenericRead | kNtGenericWrite,
|
||||
kNtFileShareRead | kNtFileShareWrite, 0,
|
||||
kNtOpenAlways, kNtFileAttributeNormal, 0);
|
||||
if (hand == -1)
|
||||
return 0;
|
||||
SetFilePointer(hand, 8, 0, kNtFileBegin);
|
||||
SetEndOfFile(hand);
|
||||
intptr_t map = CreateFileMapping(hand, 0, kNtPageReadwrite, 0, 8, 0);
|
||||
if (!map) {
|
||||
CloseHandle(hand);
|
||||
return 0;
|
||||
}
|
||||
atomic_ulong *sigs = MapViewOfFileEx(map, kNtFileMapWrite, 0, 0, 8, 0);
|
||||
CloseHandle(map);
|
||||
CloseHandle(hand);
|
||||
return sigs;
|
||||
}
|
||||
|
||||
textwindows atomic_ulong *__sig_map_process(int pid) {
|
||||
int e = errno;
|
||||
atomic_ulong *res = __sig_map_process_impl(pid);
|
||||
errno = e;
|
||||
return res;
|
||||
}
|
||||
|
||||
#endif /* __x86_64__ */
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/assert.h"
|
||||
#include "libc/atomic.h"
|
||||
#include "libc/calls/sig.internal.h"
|
||||
#include "libc/calls/struct/sigset.h"
|
||||
#include "libc/intrin/atomic.h"
|
||||
|
@ -34,7 +35,7 @@ textwindows int __sig_mask(int how, const sigset_t *neu, sigset_t *old) {
|
|||
}
|
||||
|
||||
// get address of sigset to modify
|
||||
_Atomic(uint64_t) *mask = &__get_tls()->tib_sigmask;
|
||||
atomic_ulong *mask = &__get_tls()->tib_sigmask;
|
||||
|
||||
// handle read-only case
|
||||
sigset_t oldmask;
|
||||
|
|
|
@ -16,8 +16,16 @@
|
|||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/atomic.h"
|
||||
#include "libc/calls/sig.internal.h"
|
||||
#include "libc/intrin/kprintf.h"
|
||||
#include "libc/limits.h"
|
||||
#include "libc/nt/files.h"
|
||||
#include "libc/nt/memory.h"
|
||||
#include "libc/nt/runtime.h"
|
||||
#include "libc/nt/thunk/msabi.h"
|
||||
#include "libc/runtime/internal.h"
|
||||
#ifdef __x86_64__
|
||||
|
||||
__msabi extern typeof(TerminateProcess) *const __imp_TerminateProcess;
|
||||
|
||||
|
@ -25,8 +33,20 @@ __msabi extern typeof(TerminateProcess) *const __imp_TerminateProcess;
|
|||
* Terminates the calling process and all of its threads.
|
||||
*/
|
||||
textwindows dontinstrument void TerminateThisProcess(uint32_t dwWaitStatus) {
|
||||
|
||||
// delete sig file
|
||||
char16_t path[128];
|
||||
atomic_ulong *real;
|
||||
atomic_ulong fake = 0;
|
||||
real = __sig.process;
|
||||
__sig.process = &fake;
|
||||
UnmapViewOfFile(real);
|
||||
DeleteFile(__sig_process_path(path, __pid));
|
||||
|
||||
// "When a process terminates itself, TerminateProcess stops execution
|
||||
// of the calling thread and does not return." -Quoth MSDN
|
||||
__imp_TerminateProcess(-1, dwWaitStatus);
|
||||
__builtin_unreachable();
|
||||
}
|
||||
|
||||
#endif /* __x86_64__ */
|
||||
|
|
|
@ -225,6 +225,10 @@ bool32 GetVolumeInformationByHandle(int64_t hFile,
|
|||
char16_t *opt_out_lpFileSystemNameBuffer,
|
||||
uint32_t nFileSystemNameSize);
|
||||
|
||||
uint32_t SetFilePointer(intptr_t hFile, int32_t lDistanceToMove,
|
||||
long *opt_inout_lpDistanceToMoveHigh,
|
||||
uint32_t dwMoveMethod);
|
||||
|
||||
#if ShouldUseMsabiAttribute()
|
||||
#include "libc/nt/thunk/files.inc"
|
||||
#endif /* ShouldUseMsabiAttribute() */
|
||||
|
|
18
libc/nt/kernel32/SetFilePointer.S
Normal file
18
libc/nt/kernel32/SetFilePointer.S
Normal file
|
@ -0,0 +1,18 @@
|
|||
#include "libc/nt/codegen.h"
|
||||
.imp kernel32,__imp_SetFilePointer,SetFilePointer
|
||||
|
||||
.text.windows
|
||||
.ftrace1
|
||||
SetFilePointer:
|
||||
.ftrace2
|
||||
#ifdef __x86_64__
|
||||
push %rbp
|
||||
mov %rsp,%rbp
|
||||
mov __imp_SetFilePointer(%rip),%rax
|
||||
jmp __sysv2nt
|
||||
#elif defined(__aarch64__)
|
||||
mov x0,#0
|
||||
ret
|
||||
#endif
|
||||
.endfn SetFilePointer,globl
|
||||
.previous
|
|
@ -259,6 +259,7 @@ imp 'SetEvent' SetEvent kernel32 1
|
|||
imp 'SetFileAttributes' SetFileAttributesW kernel32 2
|
||||
imp 'SetFileCompletionNotificationModes' SetFileCompletionNotificationModes kernel32 2
|
||||
imp 'SetFileInformationByHandle' SetFileInformationByHandle kernel32 4
|
||||
imp 'SetFilePointer' SetFilePointer kernel32 4
|
||||
imp 'SetFileTime' SetFileTime kernel32 4
|
||||
imp 'SetFileValidData' SetFileValidData kernel32 2
|
||||
imp 'SetHandleCount' SetHandleCount kernel32 1
|
||||
|
|
|
@ -196,9 +196,13 @@ textwindows void WinMainForked(void) {
|
|||
int64_t reader;
|
||||
int64_t savetsc;
|
||||
uint32_t varlen;
|
||||
atomic_ulong *sigproc;
|
||||
char16_t fvar[21 + 1 + 21 + 1];
|
||||
struct Fds *fds = __veil("r", &g_fds);
|
||||
|
||||
// save signal pointer
|
||||
sigproc = __sig.process;
|
||||
|
||||
// check to see if the process was actually forked
|
||||
// this variable should have the pipe handle numba
|
||||
varlen = GetEnvironmentVariable(u"_FORK", fvar, ARRAYLEN(fvar));
|
||||
|
@ -295,12 +299,13 @@ textwindows void WinMainForked(void) {
|
|||
fds->p[1].handle = GetStdHandle(kNtStdOutputHandle);
|
||||
fds->p[2].handle = GetStdHandle(kNtStdErrorHandle);
|
||||
|
||||
// restore signal pointer
|
||||
__sig.process = sigproc;
|
||||
|
||||
// restore the crash reporting stuff
|
||||
#if SYSDEBUG
|
||||
RemoveVectoredExceptionHandler(oncrash);
|
||||
#endif
|
||||
if (_weaken(__sig_init))
|
||||
_weaken(__sig_init)();
|
||||
|
||||
// jump back into function below
|
||||
longjmp(jb, 1);
|
||||
|
@ -460,15 +465,16 @@ textwindows int sys_fork_nt(uint32_t dwCreationFlags) {
|
|||
__morph_tls();
|
||||
__tls_enabled = true;
|
||||
// the child's pending signals is initially empty
|
||||
atomic_store_explicit(&__sig.pending, 0, memory_order_relaxed);
|
||||
atomic_store_explicit(__sig.process, 0, memory_order_relaxed);
|
||||
atomic_store_explicit(&tib->tib_sigpending, 0, memory_order_relaxed);
|
||||
// re-apply code morphing for function tracing
|
||||
if (ftrace_stackdigs) {
|
||||
if (ftrace_stackdigs)
|
||||
_weaken(__hook)(_weaken(ftrace_hook), _weaken(GetSymbolTable)());
|
||||
}
|
||||
// reset core runtime services
|
||||
__proc_wipe();
|
||||
WipeKeystrokes();
|
||||
if (_weaken(__sig_init))
|
||||
_weaken(__sig_init)();
|
||||
if (_weaken(__itimer_wipe))
|
||||
_weaken(__itimer_wipe)();
|
||||
// notify pthread join
|
||||
|
|
|
@ -16,16 +16,21 @@
|
|||
│ 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/sig.internal.h"
|
||||
#include "libc/calls/struct/sigset.internal.h"
|
||||
#include "libc/calls/syscall-nt.internal.h"
|
||||
#include "libc/errno.h"
|
||||
#include "libc/intrin/atomic.h"
|
||||
#include "libc/intrin/dll.h"
|
||||
#include "libc/intrin/kprintf.h"
|
||||
#include "libc/intrin/strace.h"
|
||||
#include "libc/nt/console.h"
|
||||
#include "libc/nt/enum/ctrlevent.h"
|
||||
#include "libc/nt/enum/processaccess.h"
|
||||
#include "libc/nt/errors.h"
|
||||
#include "libc/nt/memory.h"
|
||||
#include "libc/nt/process.h"
|
||||
#include "libc/nt/runtime.h"
|
||||
#include "libc/proc/proc.internal.h"
|
||||
|
@ -36,21 +41,18 @@
|
|||
textwindows int sys_kill_nt(int pid, int sig) {
|
||||
|
||||
// validate api usage
|
||||
if (!(0 <= sig && sig <= 64)) {
|
||||
if (!(0 <= sig && sig <= 64))
|
||||
return einval();
|
||||
}
|
||||
|
||||
// XXX: NT doesn't really have process groups. For instance the
|
||||
// CreateProcess() flag for starting a process group actually
|
||||
// just does an "ignore ctrl-c" internally.
|
||||
if (pid < -1) {
|
||||
if (pid < -1)
|
||||
pid = -pid;
|
||||
}
|
||||
|
||||
// no support for kill all yet
|
||||
if (pid == -1) {
|
||||
if (pid == -1)
|
||||
return einval();
|
||||
}
|
||||
|
||||
// just call raise() if we're targeting self
|
||||
if (pid <= 0 || pid == getpid()) {
|
||||
|
@ -70,6 +72,18 @@ textwindows int sys_kill_nt(int pid, int sig) {
|
|||
}
|
||||
}
|
||||
|
||||
// attempt to signal via /var/sig shared memory file
|
||||
if (pid > 0 && sig != 9) {
|
||||
atomic_ulong *sigproc;
|
||||
if ((sigproc = __sig_map_process(pid))) {
|
||||
if (sig > 0)
|
||||
atomic_fetch_or_explicit(sigproc, 1ull << (sig - 1),
|
||||
memory_order_release);
|
||||
UnmapViewOfFile(sigproc);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
// find existing handle we own for process
|
||||
int64_t handle, closeme = 0;
|
||||
if (!(handle = __proc_handle(pid))) {
|
||||
|
|
|
@ -17,11 +17,11 @@
|
|||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/assert.h"
|
||||
#include "libc/atomic.h"
|
||||
#include "libc/calls/internal.h"
|
||||
#include "libc/calls/sig.internal.h"
|
||||
#include "libc/calls/syscall_support-nt.internal.h"
|
||||
#include "libc/intrin/dll.h"
|
||||
#include "libc/intrin/kprintf.h"
|
||||
#include "libc/intrin/maps.h"
|
||||
#include "libc/intrin/nomultics.h"
|
||||
#include "libc/intrin/weaken.h"
|
||||
|
@ -294,7 +294,6 @@ static abi wontreturn void WinInit(const char16_t *cmdline) {
|
|||
ARRAYLEN(wa->envp) - 1);
|
||||
__imp_FreeEnvironmentStringsW(env16);
|
||||
__envp = &wa->envp[0];
|
||||
|
||||
// handover control to cosmopolitan runtime
|
||||
__stack_call(count, wa->argv, wa->envp, wa->auxv, cosmo,
|
||||
(uintptr_t)(stackaddr + (stacksize - sizeof(struct WinArgs))));
|
||||
|
@ -302,6 +301,7 @@ static abi wontreturn void WinInit(const char16_t *cmdline) {
|
|||
|
||||
abi int64_t WinMain(int64_t hInstance, int64_t hPrevInstance,
|
||||
const char *lpCmdLine, int64_t nCmdShow) {
|
||||
static atomic_ulong fake_process_signals;
|
||||
const char16_t *cmdline;
|
||||
extern char os asm("__hostos");
|
||||
os = _HOSTWINDOWS; // madness https://news.ycombinator.com/item?id=21019722
|
||||
|
@ -317,19 +317,20 @@ abi int64_t WinMain(int64_t hInstance, int64_t hPrevInstance,
|
|||
__gransize = si.dwAllocationGranularity;
|
||||
__umask = 077;
|
||||
__pid = __imp_GetCurrentProcessId();
|
||||
if (!(__sig.process = __sig_map_process(__pid)))
|
||||
__sig.process = &fake_process_signals;
|
||||
atomic_store_explicit(__sig.process, 0, memory_order_release);
|
||||
cmdline = __imp_GetCommandLineW();
|
||||
#if SYSDEBUG
|
||||
// sloppy flag-only check for early initialization
|
||||
if (StrStr(cmdline, u"--strace"))
|
||||
++__strace;
|
||||
#endif
|
||||
if (_weaken(WinSockInit)) {
|
||||
if (_weaken(WinSockInit))
|
||||
_weaken(WinSockInit)();
|
||||
}
|
||||
DeduplicateStdioHandles();
|
||||
if (_weaken(WinMainForked)) {
|
||||
if (_weaken(WinMainForked))
|
||||
_weaken(WinMainForked)();
|
||||
}
|
||||
WinInit(cmdline);
|
||||
}
|
||||
|
||||
|
|
|
@ -76,10 +76,6 @@ TEST(sigsuspend, testSignalQueuingSelf) {
|
|||
}
|
||||
|
||||
TEST(sigsuspend, testSignalQueuingIpc) {
|
||||
if (IsWindows()) {
|
||||
// xxx: probably need a signal server to do this kind of signalling
|
||||
return;
|
||||
}
|
||||
int pid, ws;
|
||||
sigset_t neu, old, bits;
|
||||
struct sigaction oldusr1, oldusr2;
|
||||
|
|
|
@ -103,8 +103,6 @@ static void OnSigusr2(int sig) {
|
|||
}
|
||||
|
||||
TEST(fork, childToChild) {
|
||||
if (IsWindows())
|
||||
return; // :'(
|
||||
sigset_t mask, oldmask;
|
||||
int ws, parent, child1, child2;
|
||||
gotsigusr1 = false;
|
||||
|
|
|
@ -125,8 +125,6 @@ TEST(handkill, thread2thread_async) {
|
|||
}
|
||||
|
||||
TEST(handkill, process_async) {
|
||||
if (IsWindows())
|
||||
return;
|
||||
SPAWN(fork);
|
||||
shm->ready = true;
|
||||
while (!shm->got_signal)
|
||||
|
@ -142,8 +140,6 @@ TEST(handkill, process_async) {
|
|||
}
|
||||
|
||||
TEST(handkill, process_pause) {
|
||||
if (IsWindows())
|
||||
return;
|
||||
SPAWN(fork);
|
||||
shm->ready = true;
|
||||
pause();
|
||||
|
|
|
@ -262,8 +262,6 @@ void EmptySigHandler(int sig) {
|
|||
}
|
||||
|
||||
TEST(posix_spawn, etxtbsy) {
|
||||
if (IsWindows())
|
||||
return; // can't deliver signals between processes
|
||||
if (IsXnu())
|
||||
return; // they don't appear impacted by this race condition
|
||||
if (IsNetbsd())
|
||||
|
|
|
@ -166,13 +166,12 @@ TEST(system, notequals) {
|
|||
}
|
||||
|
||||
TEST(system, usleep) {
|
||||
ASSERT_EQ(0, GETEXITSTATUS(system("usleep & kill $!")));
|
||||
ASSERT_EQ(0, GETEXITSTATUS(system("usleep & kill $!; wait")));
|
||||
}
|
||||
|
||||
TEST(system, kill) {
|
||||
int ws = system("kill -TERM $$; usleep");
|
||||
if (!IsWindows())
|
||||
ASSERT_EQ(SIGTERM, WTERMSIG(ws));
|
||||
ASSERT_EQ(SIGTERM, WTERMSIG(ws));
|
||||
}
|
||||
|
||||
TEST(system, exitStatusPreservedAfterSemiColon) {
|
||||
|
|
|
@ -120,8 +120,6 @@ void OnSig(int sig) {
|
|||
}
|
||||
|
||||
TEST(popen, complicated) {
|
||||
if (IsWindows())
|
||||
return; // windows treats sigusr1 as terminate
|
||||
char cmd[64];
|
||||
signal(SIGUSR1, OnSig);
|
||||
sprintf(cmd, "read a ; test \"x$a\" = xhello && kill -USR1 %d", getpid());
|
||||
|
|
67
test/posix/interprocess_signaling_test.c
Normal file
67
test/posix/interprocess_signaling_test.c
Normal file
|
@ -0,0 +1,67 @@
|
|||
// 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 <signal.h>
|
||||
#include <stdatomic.h>
|
||||
#include <sys/mman.h>
|
||||
#include <unistd.h>
|
||||
|
||||
atomic_int *got;
|
||||
|
||||
void onsig(int sig) {
|
||||
*got = sig;
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
|
||||
// create process shared memory
|
||||
got = mmap(0, 4, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, -1, 0);
|
||||
if (got == MAP_FAILED)
|
||||
return 5;
|
||||
|
||||
// listen for signal
|
||||
if (signal(SIGUSR1, onsig))
|
||||
return 6;
|
||||
|
||||
// block signals
|
||||
sigset_t full;
|
||||
if (sigfillset(&full))
|
||||
return 7;
|
||||
if (sigprocmask(SIG_BLOCK, &full, 0))
|
||||
return 8;
|
||||
|
||||
// create child process
|
||||
int pid;
|
||||
if (!(pid = fork())) {
|
||||
sigset_t empty;
|
||||
sigemptyset(&empty);
|
||||
sigsuspend(&empty);
|
||||
*got |= 128;
|
||||
_exit(0);
|
||||
}
|
||||
|
||||
// send signal
|
||||
if (kill(pid, SIGUSR1))
|
||||
return 9;
|
||||
|
||||
// wait for child to die
|
||||
int ws;
|
||||
if (wait(&ws) != pid)
|
||||
return 10;
|
||||
if (ws)
|
||||
return 11;
|
||||
if (*got != (128 | SIGUSR1))
|
||||
return 12;
|
||||
}
|
Loading…
Reference in a new issue