Skip to content

Commit d7917ea

Browse files
committed
Make win32 i/o signals atomic and longjmp() safe
1 parent 585c86e commit d7917ea

File tree

20 files changed

+381
-263
lines changed

20 files changed

+381
-263
lines changed

Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -374,6 +374,7 @@ COSMOPOLITAN_OBJECTS = \
374374
THIRD_PARTY_NSYNC_MEM \
375375
LIBC_MEM \
376376
THIRD_PARTY_DLMALLOC \
377+
LIBC_DLOPEN \
377378
LIBC_RUNTIME \
378379
THIRD_PARTY_NSYNC \
379380
LIBC_ELF \

libc/calls/interrupts-nt.c renamed to libc/calls/checkcancel.c

Lines changed: 0 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -17,10 +17,8 @@
1717
│ PERFORMANCE OF THIS SOFTWARE. │
1818
╚─────────────────────────────────────────────────────────────────────────────*/
1919
#include "libc/calls/internal.h"
20-
#include "libc/calls/sig.internal.h"
2120
#include "libc/intrin/atomic.h"
2221
#include "libc/intrin/weaken.h"
23-
#include "libc/sysv/errfuns.h"
2422
#include "libc/thread/posixthread.internal.h"
2523
#ifdef __x86_64__
2624

@@ -34,14 +32,4 @@ textwindows int _check_cancel(void) {
3432
return 0;
3533
}
3634

37-
textwindows int _check_signal(bool restartable) {
38-
int status;
39-
if (_check_cancel() == -1) return -1;
40-
if (!_weaken(__sig_check)) return 0;
41-
if (!(status = _weaken(__sig_check)())) return 0;
42-
if (_check_cancel() == -1) return -1;
43-
if (status == 2 && restartable) return 0;
44-
return eintr();
45-
}
46-
4735
#endif /* __x86_64__ */

libc/calls/checksignal.c

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
2+
│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│
3+
╞══════════════════════════════════════════════════════════════════════════════╡
4+
│ Copyright 2023 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/calls/internal.h"
20+
#include "libc/calls/sig.internal.h"
21+
#include "libc/intrin/weaken.h"
22+
#include "libc/sysv/errfuns.h"
23+
#ifdef __x86_64__
24+
25+
textwindows int _check_signal(bool restartable) {
26+
int status;
27+
if (_check_cancel() == -1) return -1;
28+
if (!_weaken(__sig_check)) return 0;
29+
if (!(status = _weaken(__sig_check)())) return 0;
30+
if (_check_cancel() == -1) return -1;
31+
if (status == 2 && restartable) return 0;
32+
return eintr();
33+
}
34+
35+
#endif /* __x86_64__ */

libc/calls/park.c

Lines changed: 24 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -16,50 +16,40 @@
1616
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
1717
│ PERFORMANCE OF THIS SOFTWARE. │
1818
╚─────────────────────────────────────────────────────────────────────────────*/
19-
#include "libc/assert.h"
20-
#include "libc/calls/calls.h"
2119
#include "libc/calls/internal.h"
22-
#include "libc/calls/struct/sigset.internal.h"
23-
#include "libc/calls/syscall_support-nt.internal.h"
24-
#include "libc/errno.h"
20+
#include "libc/calls/sig.internal.h"
2521
#include "libc/intrin/atomic.h"
26-
#include "libc/nt/enum/wait.h"
27-
#include "libc/nt/runtime.h"
2822
#include "libc/nt/synchronization.h"
23+
#include "libc/sysv/consts/sicode.h"
2924
#include "libc/sysv/errfuns.h"
3025
#include "libc/thread/posixthread.internal.h"
31-
#include "libc/thread/thread.h"
32-
#include "libc/thread/tls.h"
3326
#ifdef __x86_64__
3427

28+
// returns 0 on timeout or spurious wakeup
29+
// raises EINTR if a signal delivery interrupted wait operation
30+
// raises ECANCELED if this POSIX thread was canceled in masked mode
3531
static textwindows int _park_thread(uint32_t msdelay, sigset_t waitmask,
3632
bool restartable) {
37-
int rc;
38-
int64_t sem;
39-
sigset_t om;
40-
uint32_t wi;
41-
struct PosixThread *pt;
42-
pt = _pthread_self();
43-
pt->pt_flags &= ~PT_RESTARTABLE;
44-
if (restartable) pt->pt_flags |= PT_RESTARTABLE;
45-
pt->pt_semaphore = sem = CreateSemaphore(0, 0, 1, 0);
46-
pthread_cleanup_push((void *)CloseHandle, (void *)sem);
47-
atomic_store_explicit(&pt->pt_blocker, PT_BLOCKER_SEM, memory_order_release);
48-
om = __sig_beginwait(waitmask);
49-
if ((rc = _check_signal(restartable)) != -1) {
50-
if ((wi = WaitForSingleObject(sem, msdelay)) != -1u) {
51-
if (restartable && !(pt->pt_flags & PT_RESTARTABLE)) rc = eintr();
52-
rc |= _check_signal(restartable);
53-
} else {
54-
rc = __winerr();
55-
}
33+
int sig;
34+
if (_check_cancel() == -1) return -1;
35+
if ((sig = __sig_get(waitmask))) {
36+
int handler_was_called = __sig_relay(sig, SI_KERNEL, waitmask);
37+
if (_check_cancel() == -1) return -1;
38+
if (!restartable || handler_was_called == 1) return eintr();
5639
}
57-
__sig_finishwait(om);
58-
atomic_store_explicit(&pt->pt_blocker, PT_BLOCKER_CPU, memory_order_release);
59-
pt->pt_flags &= ~PT_RESTARTABLE;
60-
pthread_cleanup_pop(true);
61-
pt->pt_semaphore = 0;
62-
return rc;
40+
int expect = 0;
41+
atomic_int futex = 0;
42+
struct PosixThread *pt = _pthread_self();
43+
pt->pt_blkmask = waitmask;
44+
atomic_store_explicit(&pt->pt_blocker, &futex, memory_order_release);
45+
bool32 ok = WaitOnAddress(&futex, &expect, sizeof(int), msdelay);
46+
atomic_store_explicit(&pt->pt_blocker, 0, memory_order_release);
47+
if (ok && (sig = __sig_get(waitmask))) {
48+
int handler_was_called = __sig_relay(sig, SI_KERNEL, waitmask);
49+
if (_check_cancel() == -1) return -1;
50+
if (!restartable || handler_was_called == 1) return eintr();
51+
}
52+
return 0;
6353
}
6454

6555
textwindows int _park_norestart(uint32_t msdelay, sigset_t waitmask) {

libc/calls/read-nt.c

Lines changed: 26 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -44,13 +44,15 @@
4444
#include "libc/nt/enum/creationdisposition.h"
4545
#include "libc/nt/enum/filesharemode.h"
4646
#include "libc/nt/enum/vk.h"
47+
#include "libc/nt/enum/wait.h"
4748
#include "libc/nt/errors.h"
4849
#include "libc/nt/runtime.h"
4950
#include "libc/nt/struct/inputrecord.h"
5051
#include "libc/nt/synchronization.h"
5152
#include "libc/str/str.h"
5253
#include "libc/str/utf16.h"
5354
#include "libc/sysv/consts/o.h"
55+
#include "libc/sysv/consts/sicode.h"
5456
#include "libc/sysv/consts/sig.h"
5557
#include "libc/sysv/errfuns.h"
5658
#include "libc/thread/posixthread.internal.h"
@@ -718,10 +720,10 @@ static textwindows bool DigestConsoleInput(char *data, size_t size, int *rc) {
718720
}
719721

720722
static textwindows int WaitForConsole(struct Fd *f, sigset_t waitmask) {
721-
int rc;
722-
sigset_t m;
723+
int sig;
723724
int64_t sem;
724-
uint32_t ms = -1u;
725+
uint32_t wi, ms = -1;
726+
int handler_was_called;
725727
struct PosixThread *pt;
726728
if (!__ttyconf.vmin) {
727729
if (!__ttyconf.vtime) {
@@ -733,39 +735,42 @@ static textwindows int WaitForConsole(struct Fd *f, sigset_t waitmask) {
733735
if (f->flags & _O_NONBLOCK) {
734736
return eagain(); // standard unix non-blocking
735737
}
738+
if (_check_cancel() == -1) return -1;
739+
if ((sig = __sig_get(waitmask))) {
740+
handler_was_called = __sig_relay(sig, SI_KERNEL, waitmask);
741+
if (_check_cancel() == -1) return -1;
742+
if (handler_was_called != 1) return -2;
743+
return eintr();
744+
}
736745
pt = _pthread_self();
737-
pt->pt_flags |= PT_RESTARTABLE;
738746
pt->pt_semaphore = sem = CreateSemaphore(0, 0, 1, 0);
739747
pthread_cleanup_push((void *)CloseHandle, (void *)sem);
748+
pt->pt_blkmask = waitmask;
740749
atomic_store_explicit(&pt->pt_blocker, PT_BLOCKER_SEM, memory_order_release);
741-
m = __sig_beginwait(waitmask);
742-
if ((rc = _check_signal(true)) != -1) {
743-
int64_t hands[2] = {sem, __keystroke.cin};
744-
if (WaitForMultipleObjects(2, hands, 0, ms) != -1u) {
745-
if (!(pt->pt_flags & PT_RESTARTABLE)) rc = eintr();
746-
rc |= _check_signal(true);
747-
} else {
748-
rc = __winerr();
749-
}
750-
}
751-
__sig_finishwait(m);
752-
atomic_store_explicit(&pt->pt_blocker, PT_BLOCKER_CPU, memory_order_release);
753-
pt->pt_flags &= ~PT_RESTARTABLE;
750+
wi = WaitForMultipleObjects(2, (int64_t[2]){__keystroke.cin, sem}, 0, ms);
751+
atomic_store_explicit(&pt->pt_blocker, 0, memory_order_release);
754752
pthread_cleanup_pop(true);
755-
return rc;
753+
if (wi == kNtWaitTimeout) return 0; // vtime elapsed
754+
if (wi == 0) return -2; // console data
755+
if (wi != 1) return __winerr(); // wait failed
756+
if (!(sig = __sig_get(waitmask))) return eintr();
757+
handler_was_called = __sig_relay(sig, SI_KERNEL, waitmask);
758+
if (_check_cancel() == -1) return -1;
759+
if (handler_was_called != 1) return -2;
760+
return eintr();
756761
}
757762

758763
static textwindows ssize_t ReadFromConsole(struct Fd *f, void *data,
759764
size_t size, sigset_t waitmask) {
760765
int rc;
761-
bool done = false;
762766
InitConsole();
763767
do {
764768
LockKeystrokes();
765769
IngestConsoleInput();
766-
done = DigestConsoleInput(data, size, &rc);
770+
bool done = DigestConsoleInput(data, size, &rc);
767771
UnlockKeystrokes();
768-
} while (!done && !(rc = WaitForConsole(f, waitmask)));
772+
if (done) return rc;
773+
} while ((rc = WaitForConsole(f, waitmask)) == -2);
769774
return rc;
770775
}
771776

@@ -823,7 +828,6 @@ static textwindows ssize_t sys_read_nt2(int fd, const struct iovec *iov,
823828
total += rc;
824829
if (opt_offset != -1) opt_offset += rc;
825830
if (rc < iov[i].iov_len) break;
826-
waitmask = -1; // disable eintr/ecanceled for remaining iovecs
827831
}
828832
return total;
829833
} else {

0 commit comments

Comments
 (0)