Skip to content

Commit 072e1d2

Browse files
committed
Make signal handling work well across platforms
- Fix sigsuspend() on XNU - Fix strsignal() on non-Linux - Add unit tests for strsignal() - Add unit tests for setitimer() - Add unit tests for sigsuspend() - Rewrite setitimer() for New Technology - Rewrite nanosleep() for New Technology - Polyfill SIGALRM on the New Technology - select(0,0,0,0) on NT now calls pause() - Remove some NTDLL calls that aren't needed - Polyfill SA_NOCLDWAIT on the New Technology - Polyfill SA_RESETHAND on the New Technology - Polyfill sigprocmask() on the New Technology - Polyfill SIGCHLD+SIG_IGN on the New Technology - Polyfill SA_RESTART masking on the New Technology - Deliver console signals from main thread on New Technology - Document SA_RESTART behavior w/ @sarestartable / @norestart - System call trace in MODE=dbg now prints inherited FDs and signal mask
1 parent 3b9e66e commit 072e1d2

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

82 files changed

+1382
-444
lines changed

examples/exec.c

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,14 +8,24 @@
88
╚─────────────────────────────────────────────────────────────────*/
99
#endif
1010
#include "libc/calls/calls.h"
11+
#include "libc/calls/sigbits.h"
12+
#include "libc/calls/struct/sigset.h"
1113
#include "libc/runtime/runtime.h"
1214
#include "libc/stdio/stdio.h"
15+
#include "libc/sysv/consts/sig.h"
1316

1417
int main(int argc, char *argv[]) {
18+
sigset_t ss;
1519
if (argc < 3) {
1620
fputs("USAGE: EXEC.COM PROG ARGV₀ [ARGV₁...]\n", stderr);
1721
return 1;
1822
}
23+
24+
// block arbitrary signal so __printargs() looks cooler
25+
sigemptyset(&ss);
26+
sigaddset(&ss, SIGPWR);
27+
sigprocmask(SIG_BLOCK, &ss, 0);
28+
1929
execv(argv[1], argv + 1);
2030
return 127;
2131
}

examples/setitimer.c

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
#if 0
2+
/*─────────────────────────────────────────────────────────────────╗
3+
│ To the extent possible under law, Justine Tunney has waived │
4+
│ all copyright and related or neighboring rights to this file, │
5+
│ as it is written in the following disclaimers: │
6+
│ • http://unlicense.org/ │
7+
│ • http://creativecommons.org/publicdomain/zero/1.0/ │
8+
╚─────────────────────────────────────────────────────────────────*/
9+
#endif
10+
#include "libc/calls/calls.h"
11+
#include "libc/calls/struct/itimerval.h"
12+
#include "libc/calls/struct/sigaction.h"
13+
#include "libc/calls/struct/siginfo.h"
14+
#include "libc/calls/ucontext.h"
15+
#include "libc/log/check.h"
16+
#include "libc/stdio/stdio.h"
17+
#include "libc/sysv/consts/itimer.h"
18+
#include "libc/sysv/consts/sa.h"
19+
#include "libc/sysv/consts/sig.h"
20+
#include "libc/time/time.h"
21+
22+
volatile bool gotalrm;
23+
24+
void OnSigAlrm(int sig, siginfo_t *si, ucontext_t *ctx) {
25+
gotalrm = true;
26+
}
27+
28+
int main() {
29+
30+
//////////////////////////////////////////////////////////////////////////////
31+
printf("first tutorial: set singleshot alarm for 1.5 seconds from now\n");
32+
33+
// setup alarm in 1.5 seconds
34+
// this timer tears itself down once it's handled
35+
struct itimerval shot = {{0, 0}, {1, 500000}};
36+
struct sigaction handler = {.sa_sigaction = OnSigAlrm,
37+
.sa_flags = SA_RESETHAND | SA_SIGINFO};
38+
CHECK_EQ(0, sigaction(SIGALRM, &handler, 0));
39+
CHECK_EQ(0, setitimer(ITIMER_REAL, &shot, 0));
40+
41+
// wait for alarm
42+
pause();
43+
printf("got singleshot alarm!\n\n");
44+
45+
//////////////////////////////////////////////////////////////////////////////
46+
printf("second tutorial: interval timer\n");
47+
48+
// setup timer every 1.5 seconds
49+
struct sigaction oldalrm;
50+
struct sigaction sigalrm = {.sa_sigaction = OnSigAlrm,
51+
.sa_flags = SA_SIGINFO};
52+
CHECK_EQ(0, sigaction(SIGALRM, &sigalrm, &oldalrm));
53+
struct itimerval oldtimer;
54+
struct itimerval timer = {{1, 500000}, {1, 500000}};
55+
CHECK_EQ(0, setitimer(ITIMER_REAL, &timer, &oldtimer));
56+
57+
// wait for three timeouts
58+
int i = 0;
59+
int n = 3;
60+
while (i < n) {
61+
pause();
62+
if (gotalrm) {
63+
++i;
64+
printf("got timeout %d out of %d\n", i, n);
65+
gotalrm = false;
66+
}
67+
}
68+
69+
// teardown timer
70+
CHECK_EQ(0, setitimer(ITIMER_REAL, &oldtimer, 0));
71+
CHECK_EQ(0, sigaction(SIGALRM, &oldalrm, 0));
72+
}

libc/calls/clock_gettime.c

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
╚─────────────────────────────────────────────────────────────────────────────*/
1919
#include "libc/assert.h"
2020
#include "libc/calls/internal.h"
21+
#include "libc/calls/strace.internal.h"
2122
#include "libc/calls/struct/timeval.h"
2223
#include "libc/dce.h"
2324
#include "libc/fmt/conv.h"
@@ -39,9 +40,10 @@
3940
* @see strftime(), gettimeofday()
4041
* @asyncsignalsafe
4142
*/
42-
int clock_gettime(int clockid, struct timespec *ts) {
43+
noinstrument int clock_gettime(int clockid, struct timespec *ts) {
4344
int rc, e;
4445
axdx_t ad;
46+
char buf[45];
4547
if (!ts) {
4648
rc = efault();
4749
} else if (IsAsan() && !__asan_is_valid(ts, sizeof(*ts))) {
@@ -64,6 +66,9 @@ int clock_gettime(int clockid, struct timespec *ts) {
6466
} else {
6567
rc = sys_clock_gettime_nt(clockid, ts);
6668
}
67-
/* TODO(jart): Add get_clock_gettime() so we can STRACE() */
69+
if (!__time_critical) {
70+
STRACE("clock_gettime(%d, [%s]) → %d% m", clockid,
71+
__strace_timespec(buf, sizeof(buf), rc, ts), rc);
72+
}
6873
return rc;
6974
}

libc/calls/fcntl.c

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
#include "libc/bits/weaken.h"
2020
#include "libc/calls/calls.h"
2121
#include "libc/calls/internal.h"
22+
#include "libc/calls/strace.internal.h"
2223
#include "libc/dce.h"
2324
#include "libc/sysv/errfuns.h"
2425
#include "libc/zipos/zipos.internal.h"
@@ -47,22 +48,26 @@
4748
* @param arg can be FD_CLOEXEC, etc. depending
4849
* @return 0 on success, or -1 w/ errno
4950
* @asyncsignalsafe
51+
* @restartable
5052
*/
5153
int fcntl(int fd, int cmd, ...) {
54+
int rc;
5255
va_list va;
5356
uintptr_t arg;
5457
va_start(va, cmd);
5558
arg = va_arg(va, uintptr_t);
5659
va_end(va);
5760
if (fd >= 0) {
5861
if (fd < g_fds.n && g_fds.p[fd].kind == kFdZip) {
59-
return weaken(__zipos_fcntl)(fd, cmd, arg);
62+
rc = weaken(__zipos_fcntl)(fd, cmd, arg);
6063
} else if (!IsWindows()) {
61-
return sys_fcntl(fd, cmd, arg);
64+
rc = sys_fcntl(fd, cmd, arg);
6265
} else {
63-
return sys_fcntl_nt(fd, cmd, arg);
66+
rc = sys_fcntl_nt(fd, cmd, arg);
6467
}
6568
} else {
66-
return einval();
69+
rc = einval();
6770
}
71+
STRACE("fcntl(%d, %d, %p) → %d% m", fd, cmd, arg);
72+
return rc;
6873
}

libc/calls/flock.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
* @param op can have LOCK_{SH,EX,NB,UN} for shared, exclusive,
3030
* non-blocking, and unlocking
3131
* @return 0 on success, or -1 w/ errno
32+
* @restartable
3233
*/
3334
int flock(int fd, int op) {
3435
int rc;

libc/calls/winalarm.S renamed to libc/calls/fmodl.S

Lines changed: 25 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*-*- mode:unix-assembly; indent-tabs-mode:t; tab-width:8; coding:utf-8 -*-│
2-
│vi: set et ft=asm ts=8 tw=8 fenc=utf-8 :vi│
2+
│vi: set et ft=asm ts=8 sw=8 fenc=utf-8 :vi│
33
╞══════════════════════════════════════════════════════════════════════════════╡
44
│ Copyright 2020 Justine Alexandra Roberts Tunney │
55
│ │
@@ -16,10 +16,29 @@
1616
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
1717
│ PERFORMANCE OF THIS SOFTWARE. │
1818
╚─────────────────────────────────────────────────────────────────────────────*/
19+
#include "libc/runtime/pc.internal.h"
1920
#include "libc/macros.internal.h"
20-
.text.windows
2121

22-
__winalarm_nt:
23-
ezlea __winalarm,ax
24-
jmp __nt2sysv
25-
.endfn __winalarm_nt,globl,hidden
22+
// fmod [sic] does (𝑥 rem 𝑦) w/ round()-style rounding.
23+
//
24+
// @param 𝑥 is an 80-bit long double passed on stack in 16-bytes
25+
// @param 𝑦 is the power, also pushed on stack, in reverse order
26+
// @return remainder ∈ (-|𝑦|,|𝑦|) in %st
27+
// @define 𝑥-truncl(𝑥/𝑦)*𝑦
28+
// @see emod()
29+
fmodl: push %rbp
30+
mov %rsp,%rbp
31+
.profilable
32+
fldt 32(%rbp)
33+
fldt 16(%rbp)
34+
1: fprem
35+
fnstsw
36+
test $FPU_C2>>8,%ah
37+
jnz 1b
38+
fstp %st(1)
39+
pop %rbp
40+
ret
41+
1: int3
42+
pop %rbp
43+
ret
44+
.endfn fmodl,globl

libc/calls/g_sighandrvas.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,3 +19,4 @@
1919
#include "libc/calls/internal.h"
2020

2121
unsigned __sighandrvas[NSIG];
22+
unsigned __sighandflags[NSIG];

libc/calls/getconsolectrlevent.h

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,6 @@ static inline int GetConsoleCtrlEvent(int sig) {
99
switch (sig) {
1010
case SIGINT:
1111
return kNtCtrlCEvent;
12-
case SIGHUP:
13-
return kNtCtrlCloseEvent;
1412
case SIGQUIT:
1513
return kNtCtrlBreakEvent;
1614
default:

libc/calls/internal.h

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@ struct Fd {
5858
unsigned flags;
5959
int64_t handle;
6060
int64_t extra;
61+
bool zombie;
6162
};
6263

6364
struct Fds {
@@ -69,9 +70,10 @@ struct Fds {
6970

7071
extern const struct Fd kEmptyFd;
7172

72-
hidden extern volatile bool __interrupted;
7373
hidden extern int __vforked;
74+
hidden extern bool __time_critical;
7475
hidden extern unsigned __sighandrvas[NSIG];
76+
hidden extern unsigned __sighandflags[NSIG];
7577
hidden extern struct Fds g_fds;
7678
hidden extern const struct NtSecurityAttributes kNtIsInheritable;
7779

@@ -306,8 +308,10 @@ int ioctl_tiocgwinsz_nt(struct Fd *, struct winsize *) hidden;
306308
│ cosmopolitan § syscalls » windows nt » support ─╬─│┼
307309
╚────────────────────────────────────────────────────────────────────────────│*/
308310

309-
bool _check_sigchld(void) hidden;
310-
int __sample_pids(int[hasatleast 64], int64_t[hasatleast 64]) hidden;
311+
bool _check_interrupts(bool, struct Fd *) hidden;
312+
void _check_sigchld(void) hidden;
313+
void _check_sigalrm(void) hidden;
314+
int __sample_pids(int[hasatleast 64], int64_t[hasatleast 64], bool) hidden;
311315
bool isdirectory_nt(const char *) hidden;
312316
bool isregularfile_nt(const char *) hidden;
313317
bool issymlink_nt(const char *) hidden;
@@ -327,7 +331,6 @@ struct NtOverlapped *offset2overlap(int64_t, struct NtOverlapped *) hidden;
327331
unsigned __wincrash_nt(struct NtExceptionPointers *);
328332
void *GetProcAddressModule(const char *, const char *) hidden;
329333
void WinMainForked(void) hidden;
330-
void __winalarm(void *, uint32_t, uint32_t) hidden;
331334
void ntcontext2linux(struct ucontext *, const struct NtContext *) hidden;
332335

333336
/*───────────────────────────────────────────────────────────────────────────│─╗
Lines changed: 14 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
22
│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│
33
╞══════════════════════════════════════════════════════════════════════════════╡
4-
│ Copyright 2020 Justine Alexandra Roberts Tunney │
4+
│ Copyright 2022 Justine Alexandra Roberts Tunney │
55
│ │
66
│ Permission to use, copy, modify, and/or distribute this software for │
77
│ any purpose with or without fee is hereby granted, provided that the │
@@ -16,32 +16,18 @@
1616
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
1717
│ PERFORMANCE OF THIS SOFTWARE. │
1818
╚─────────────────────────────────────────────────────────────────────────────*/
19-
#include "libc/calls/calls.h"
20-
#include "libc/calls/sigbits.h"
21-
#include "libc/calls/struct/sigset.h"
22-
#include "libc/log/log.h"
23-
#include "libc/nexgen32e/nexgen32e.h"
24-
#include "libc/sysv/consts/clock.h"
25-
#include "libc/sysv/consts/sig.h"
26-
#include "libc/testlib/testlib.h"
27-
#include "libc/time/time.h"
28-
#include "libc/x/x.h"
19+
#include "libc/assert.h"
20+
#include "libc/bits/weaken.h"
21+
#include "libc/calls/internal.h"
22+
#include "libc/calls/sig.internal.h"
23+
#include "libc/calls/strace.internal.h"
24+
#include "libc/calls/struct/sigaction.h"
25+
#include "libc/dce.h"
2926

30-
TEST(fastdiv, test) {
31-
long x = 123000000321;
32-
EXPECT_EQ(123, div1000000000int64(x));
33-
EXPECT_EQ(321, rem1000000000int64(x));
34-
}
35-
36-
TEST(dsleep, test) {
37-
long double t1, t2;
38-
sigset_t mask, oldmask;
39-
sigfillset(&mask);
40-
sigprocmask(SIG_BLOCK, &mask, &oldmask);
41-
sched_yield();
42-
t1 = dtime(CLOCK_MONOTONIC);
43-
dsleep(0.001L);
44-
t2 = dtime(CLOCK_MONOTONIC);
45-
sigprocmask(SIG_SETMASK, &oldmask, NULL);
46-
ASSERT_LDBL_GT(t2 - t1, 0.0005L);
27+
textwindows bool _check_interrupts(bool restartable, struct Fd *fd) {
28+
if (__time_critical) return false;
29+
if (weaken(_check_sigalrm)) weaken(_check_sigalrm)();
30+
if (weaken(_check_sigchld)) weaken(_check_sigchld)();
31+
if (fd && weaken(_check_sigwinch)) weaken(_check_sigwinch)(fd);
32+
return weaken(__sig_check) && weaken(__sig_check)(restartable);
4733
}

0 commit comments

Comments
 (0)