Skip to content

Commit 0d74673

Browse files
committed
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
1 parent 8527462 commit 0d74673

22 files changed

+302
-62
lines changed

libc/calls/createpipename.c

Lines changed: 3 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -17,36 +17,20 @@
1717
│ PERFORMANCE OF THIS SOFTWARE. │
1818
╚─────────────────────────────────────────────────────────────────────────────*/
1919
#include "libc/atomic.h"
20+
#include "libc/fmt/internal.h"
2021
#include "libc/intrin/atomic.h"
2122
#include "libc/runtime/internal.h"
2223

23-
static textwindows char16_t *itoa16(char16_t p[21], uint64_t x) {
24-
char t;
25-
size_t a, b, i = 0;
26-
do {
27-
p[i++] = x % 10 + '0';
28-
x = x / 10;
29-
} while (x > 0);
30-
if (i) {
31-
for (a = 0, b = i - 1; a < b; ++a, --b) {
32-
t = p[a];
33-
p[a] = p[b];
34-
p[b] = t;
35-
}
36-
}
37-
return p + i;
38-
}
39-
4024
// This function is called very early by WinMain().
4125
textwindows char16_t *__create_pipe_name(char16_t *a) {
4226
char16_t *p = a;
4327
const char *q = "\\\\?\\pipe\\cosmo\\";
4428
static atomic_uint x;
4529
while (*q)
4630
*p++ = *q++;
47-
p = itoa16(p, __pid);
31+
p = __itoa16(p, __pid);
4832
*p++ = '-';
49-
p = itoa16(p, atomic_fetch_add(&x, 1));
33+
p = __itoa16(p, atomic_fetch_add(&x, 1));
5034
*p = 0;
5135
return a;
5236
}

libc/calls/sig.c

Lines changed: 27 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -32,12 +32,13 @@
3232
#include "libc/intrin/bsf.h"
3333
#include "libc/intrin/describebacktrace.h"
3434
#include "libc/intrin/dll.h"
35-
#include "libc/intrin/kprintf.h"
35+
#include "libc/intrin/maps.h"
3636
#include "libc/intrin/strace.h"
3737
#include "libc/intrin/weaken.h"
3838
#include "libc/nt/console.h"
3939
#include "libc/nt/enum/context.h"
4040
#include "libc/nt/enum/exceptionhandleractions.h"
41+
#include "libc/nt/enum/processcreationflags.h"
4142
#include "libc/nt/enum/signal.h"
4243
#include "libc/nt/enum/status.h"
4344
#include "libc/nt/events.h"
@@ -46,6 +47,7 @@
4647
#include "libc/nt/struct/ntexceptionpointers.h"
4748
#include "libc/nt/synchronization.h"
4849
#include "libc/nt/thread.h"
50+
#include "libc/runtime/internal.h"
4951
#include "libc/runtime/symbols.internal.h"
5052
#include "libc/str/str.h"
5153
#include "libc/sysv/consts/sa.h"
@@ -58,6 +60,8 @@
5860
* @fileoverview Cosmopolitan Signals for Windows.
5961
*/
6062

63+
#define STKSZ 65536
64+
6165
struct SignalFrame {
6266
unsigned rva;
6367
unsigned flags;
@@ -80,7 +84,7 @@ textwindows bool __sig_ignored(int sig) {
8084

8185
textwindows void __sig_delete(int sig) {
8286
struct Dll *e;
83-
atomic_fetch_and_explicit(&__sig.pending, ~(1ull << (sig - 1)),
87+
atomic_fetch_and_explicit(__sig.process, ~(1ull << (sig - 1)),
8488
memory_order_relaxed);
8589
_pthread_lock();
8690
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) {
108112
textwindows int __sig_get(sigset_t masked) {
109113
int sig;
110114
if (!(sig = __sig_getter(&__get_tls()->tib_sigpending, masked)))
111-
sig = __sig_getter(&__sig.pending, masked);
115+
sig = __sig_getter(__sig.process, masked);
112116
return sig;
113117
}
114118

@@ -179,6 +183,7 @@ textwindows int __sig_raise(volatile int sig, int sic) {
179183
unsigned rva, flags;
180184
struct PosixThread *pt = _pthread_self();
181185
if (__sig_start(pt, sig, &rva, &flags)) {
186+
182187
if (flags & SA_RESETHAND) {
183188
STRACE("resetting %G handler", sig);
184189
__sighandrvas[sig] = (int32_t)(intptr_t)SIG_DFL;
@@ -410,7 +415,7 @@ textwindows void __sig_generate(int sig, int sic) {
410415
STRACE("terminating on %G due to no handler", sig);
411416
__sig_terminate(sig);
412417
}
413-
if (atomic_load_explicit(&__sig.pending, memory_order_acquire) &
418+
if (atomic_load_explicit(__sig.process, memory_order_acquire) &
414419
(1ull << (sig - 1))) {
415420
return;
416421
}
@@ -448,7 +453,7 @@ textwindows void __sig_generate(int sig, int sic) {
448453
__sig_killer(mark, sig, sic);
449454
_pthread_unref(mark);
450455
} else {
451-
atomic_fetch_or_explicit(&__sig.pending, 1ull << (sig - 1),
456+
atomic_fetch_or_explicit(__sig.process, 1ull << (sig - 1),
452457
memory_order_relaxed);
453458
}
454459
ALLOW_SIGNALS;
@@ -611,11 +616,28 @@ textwindows int __sig_check(void) {
611616
}
612617
}
613618

619+
// delivers signals from other processes asynchronously
620+
textwindows dontinstrument static uint32_t __sig_worker(void *arg) {
621+
struct CosmoTib tls;
622+
__bootstrap_tls(&tls, __builtin_frame_address(0));
623+
char *sp = __builtin_frame_address(0);
624+
__maps_track((char *)(((uintptr_t)sp + __pagesize - 1) & -__pagesize) - STKSZ,
625+
STKSZ);
626+
for (;;) {
627+
int sig;
628+
if ((sig = __sig_getter(__sig.process, 0)))
629+
__sig_generate(sig, SI_KERNEL);
630+
Sleep(1);
631+
}
632+
return 0;
633+
}
634+
614635
__attribute__((__constructor__(10))) textstartup void __sig_init(void) {
615636
if (!IsWindows())
616637
return;
617638
AddVectoredExceptionHandler(true, (void *)__sig_crash);
618639
SetConsoleCtrlHandler((void *)__sig_console, true);
640+
CreateThread(0, STKSZ, __sig_worker, 0, kNtStackSizeParamIsAReservation, 0);
619641
}
620642

621643
#endif /* __x86_64__ */

libc/calls/sig.internal.h

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
#ifndef COSMOPOLITAN_LIBC_CALLS_SIGNALS_INTERNAL_H_
22
#define COSMOPOLITAN_LIBC_CALLS_SIGNALS_INTERNAL_H_
3+
#include "libc/atomic.h"
34
#include "libc/calls/struct/sigset.h"
45
#include "libc/thread/posixthread.internal.h"
56

@@ -9,8 +10,8 @@
910
COSMOPOLITAN_C_START_
1011

1112
struct Signals {
12-
_Atomic(uint64_t) pending;
13-
_Atomic(uint64_t) count;
13+
atomic_ulong *process;
14+
atomic_ulong count;
1415
};
1516

1617
extern struct Signals __sig;
@@ -27,5 +28,8 @@ void __sig_delete(int);
2728
void __sig_generate(int, int);
2829
void __sig_init(void);
2930

31+
char16_t *__sig_process_path(char16_t *, uint32_t);
32+
atomic_ulong *__sig_map_process(int);
33+
3034
COSMOPOLITAN_C_END_
3135
#endif /* COSMOPOLITAN_LIBC_CALLS_SIGNALS_INTERNAL_H_ */

libc/calls/sigpending.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ int sigpending(sigset_t *pending) {
5353
}
5454
rc = 0;
5555
} else if (IsWindows()) {
56-
*pending = atomic_load_explicit(&__sig.pending, memory_order_acquire) |
56+
*pending = atomic_load_explicit(__sig.process, memory_order_acquire) |
5757
atomic_load_explicit(&__get_tls()->tib_sigpending,
5858
memory_order_acquire);
5959
rc = 0;

libc/fmt/internal.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,5 +48,6 @@
4848
int __vcscanf(int (*)(void *), int (*)(int, void *), void *, const char *,
4949
va_list);
5050
int __fmt(void *, void *, const char *, va_list, int *);
51+
char16_t *__itoa16(char16_t[21], uint64_t);
5152

5253
#endif /* COSMOPOLITAN_LIBC_FMT_STRTOL_H_ */

libc/intrin/itoa16.c

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
2+
│ vi: set et ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi │
3+
╞══════════════════════════════════════════════════════════════════════════════╡
4+
│ Copyright 2024 Justine Alexandra Roberts Tunney │
5+
│ │
6+
│ Permission to use, copy, modify, and/or distribute this software for │
7+
│ any purpose with or without fee is hereby granted, provided that the │
8+
│ above copyright notice and this permission notice appear in all copies. │
9+
│ │
10+
│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │
11+
│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │
12+
│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │
13+
│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │
14+
│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │
15+
│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │
16+
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
17+
│ PERFORMANCE OF THIS SOFTWARE. │
18+
╚─────────────────────────────────────────────────────────────────────────────*/
19+
#include "libc/fmt/internal.h"
20+
21+
textwindows char16_t *__itoa16(char16_t p[21], uint64_t x) {
22+
char t;
23+
size_t a, b, i = 0;
24+
do {
25+
p[i++] = x % 10 + '0';
26+
x = x / 10;
27+
} while (x > 0);
28+
if (i) {
29+
for (a = 0, b = i - 1; a < b; ++a, --b) {
30+
t = p[a];
31+
p[a] = p[b];
32+
p[b] = t;
33+
}
34+
}
35+
return p + i;
36+
}

libc/intrin/sig.c

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,11 +17,25 @@
1717
│ PERFORMANCE OF THIS SOFTWARE. │
1818
╚─────────────────────────────────────────────────────────────────────────────*/
1919
#include "libc/sysv/consts/sig.h"
20+
#include "libc/atomic.h"
2021
#include "libc/calls/sig.internal.h"
2122
#include "libc/calls/struct/sigset.internal.h"
2223
#include "libc/dce.h"
24+
#include "libc/fmt/internal.h"
2325
#include "libc/intrin/atomic.h"
2426
#include "libc/intrin/weaken.h"
27+
#include "libc/limits.h"
28+
#include "libc/nt/createfile.h"
29+
#include "libc/nt/enum/accessmask.h"
30+
#include "libc/nt/enum/creationdisposition.h"
31+
#include "libc/nt/enum/fileflagandattributes.h"
32+
#include "libc/nt/enum/filemapflags.h"
33+
#include "libc/nt/enum/filemovemethod.h"
34+
#include "libc/nt/enum/filesharemode.h"
35+
#include "libc/nt/enum/pageflags.h"
36+
#include "libc/nt/files.h"
37+
#include "libc/nt/memory.h"
38+
#include "libc/nt/runtime.h"
2539
#include "libc/thread/tls.h"
2640

2741
struct Signals __sig;
@@ -52,3 +66,65 @@ void __sig_unblock(sigset_t m) {
5266
sys_sigprocmask(SIG_SETMASK, &m, 0);
5367
}
5468
}
69+
70+
#ifdef __x86_64__
71+
72+
textwindows char16_t *__sig_process_path(char16_t *path, uint32_t pid) {
73+
char16_t *p = path;
74+
*p++ = 'C';
75+
*p++ = ':';
76+
*p++ = '\\';
77+
*p++ = 'v';
78+
*p++ = 'a';
79+
*p++ = 'r';
80+
*p = 0;
81+
CreateDirectory(path, 0);
82+
*p++ = '\\';
83+
*p++ = 's';
84+
*p++ = 'i';
85+
*p++ = 'g';
86+
*p = 0;
87+
CreateDirectory(path, 0);
88+
*p++ = '\\';
89+
p = __itoa16(p, (pid & 0x000fff00) >> 8);
90+
*p = 0;
91+
CreateDirectory(path, 0);
92+
*p++ = '\\';
93+
p = __itoa16(p, pid);
94+
*p++ = '.';
95+
*p++ = 'p';
96+
*p++ = 'i';
97+
*p++ = 'd';
98+
*p = 0;
99+
return path;
100+
}
101+
102+
textwindows static atomic_ulong *__sig_map_process_impl(int pid) {
103+
char16_t path[128];
104+
intptr_t hand = CreateFile(__sig_process_path(path, pid),
105+
kNtGenericRead | kNtGenericWrite,
106+
kNtFileShareRead | kNtFileShareWrite, 0,
107+
kNtOpenAlways, kNtFileAttributeNormal, 0);
108+
if (hand == -1)
109+
return 0;
110+
SetFilePointer(hand, 8, 0, kNtFileBegin);
111+
SetEndOfFile(hand);
112+
intptr_t map = CreateFileMapping(hand, 0, kNtPageReadwrite, 0, 8, 0);
113+
if (!map) {
114+
CloseHandle(hand);
115+
return 0;
116+
}
117+
atomic_ulong *sigs = MapViewOfFileEx(map, kNtFileMapWrite, 0, 0, 8, 0);
118+
CloseHandle(map);
119+
CloseHandle(hand);
120+
return sigs;
121+
}
122+
123+
textwindows atomic_ulong *__sig_map_process(int pid) {
124+
int e = errno;
125+
atomic_ulong *res = __sig_map_process_impl(pid);
126+
errno = e;
127+
return res;
128+
}
129+
130+
#endif /* __x86_64__ */

libc/intrin/sigprocmask-nt.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
│ PERFORMANCE OF THIS SOFTWARE. │
1818
╚─────────────────────────────────────────────────────────────────────────────*/
1919
#include "libc/assert.h"
20+
#include "libc/atomic.h"
2021
#include "libc/calls/sig.internal.h"
2122
#include "libc/calls/struct/sigset.h"
2223
#include "libc/intrin/atomic.h"
@@ -34,7 +35,7 @@ textwindows int __sig_mask(int how, const sigset_t *neu, sigset_t *old) {
3435
}
3536

3637
// get address of sigset to modify
37-
_Atomic(uint64_t) *mask = &__get_tls()->tib_sigmask;
38+
atomic_ulong *mask = &__get_tls()->tib_sigmask;
3839

3940
// handle read-only case
4041
sigset_t oldmask;

libc/intrin/terminatethisprocess.c

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,17 +16,37 @@
1616
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
1717
│ PERFORMANCE OF THIS SOFTWARE. │
1818
╚─────────────────────────────────────────────────────────────────────────────*/
19+
#include "libc/atomic.h"
20+
#include "libc/calls/sig.internal.h"
21+
#include "libc/intrin/kprintf.h"
22+
#include "libc/limits.h"
23+
#include "libc/nt/files.h"
24+
#include "libc/nt/memory.h"
1925
#include "libc/nt/runtime.h"
2026
#include "libc/nt/thunk/msabi.h"
27+
#include "libc/runtime/internal.h"
28+
#ifdef __x86_64__
2129

2230
__msabi extern typeof(TerminateProcess) *const __imp_TerminateProcess;
2331

2432
/**
2533
* Terminates the calling process and all of its threads.
2634
*/
2735
textwindows dontinstrument void TerminateThisProcess(uint32_t dwWaitStatus) {
36+
37+
// delete sig file
38+
char16_t path[128];
39+
atomic_ulong *real;
40+
atomic_ulong fake = 0;
41+
real = __sig.process;
42+
__sig.process = &fake;
43+
UnmapViewOfFile(real);
44+
DeleteFile(__sig_process_path(path, __pid));
45+
2846
// "When a process terminates itself, TerminateProcess stops execution
2947
// of the calling thread and does not return." -Quoth MSDN
3048
__imp_TerminateProcess(-1, dwWaitStatus);
3149
__builtin_unreachable();
3250
}
51+
52+
#endif /* __x86_64__ */

libc/nt/files.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -225,6 +225,10 @@ bool32 GetVolumeInformationByHandle(int64_t hFile,
225225
char16_t *opt_out_lpFileSystemNameBuffer,
226226
uint32_t nFileSystemNameSize);
227227

228+
uint32_t SetFilePointer(intptr_t hFile, int32_t lDistanceToMove,
229+
long *opt_inout_lpDistanceToMoveHigh,
230+
uint32_t dwMoveMethod);
231+
228232
#if ShouldUseMsabiAttribute()
229233
#include "libc/nt/thunk/files.inc"
230234
#endif /* ShouldUseMsabiAttribute() */

0 commit comments

Comments
 (0)