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
This commit is contained in:
Justine Tunney 2022-03-25 07:11:44 -07:00
parent 3b9e66ecba
commit 072e1d2910
82 changed files with 1388 additions and 450 deletions

View file

@ -18,32 +18,64 @@
*/
#include "libc/calls/calls.h"
#include "libc/calls/internal.h"
#include "libc/calls/sig.internal.h"
#include "libc/calls/sigbits.h"
#include "libc/calls/strace.internal.h"
#include "libc/calls/struct/sigset.h"
#include "libc/dce.h"
#include "libc/intrin/asan.internal.h"
#include "libc/nt/synchronization.h"
#include "libc/sysv/errfuns.h"
/**
* Blocks until SIG MASK is delivered to process.
*
* @param ignore is a bitset of signals to block temporarily
* @return -1 w/ EINTR
* @return -1 w/ EINTR or possibly EFAULT
* @asyncsignalsafe
* @norestart
*/
int sigsuspend(const sigset_t *ignore) {
int rc;
char buf[41];
if (!ignore || (IsAsan() && !__asan_is_valid(ignore, sizeof(*ignore)))) {
sigset_t save, mask, *arg;
STRACE("sigsuspend(%s) → [...]",
__strace_sigset(buf, sizeof(buf), 0, ignore));
if (IsAsan() && ignore && !__asan_is_valid(ignore, sizeof(*ignore))) {
rc = efault();
} else if (!IsWindows()) {
STRACE("sigsuspend(%s)", __strace_sigset(buf, sizeof(buf), 0, ignore));
if (IsOpenbsd()) ignore = (sigset_t *)(uintptr_t)(*(uint32_t *)ignore);
return sys_sigsuspend(ignore, 8);
} else if (IsXnu() || IsOpenbsd()) {
// openbsd and xnu only support 32 signals
// they use a register calling convention for sigsuspend
if (ignore) {
arg = (sigset_t *)(uintptr_t)(*(uint32_t *)ignore);
} else {
arg = 0;
}
rc = sys_sigsuspend(arg, 8);
} else if (IsLinux() || IsFreebsd() || IsNetbsd() || IsWindows()) {
if (ignore) {
arg = ignore;
} else {
sigemptyset(&mask);
arg = &mask;
}
if (!IsWindows()) {
rc = sys_sigsuspend(arg, 8);
} else {
save = __sig_mask(arg);
do {
if (_check_interrupts(false, g_fds.p)) {
rc = eintr();
break;
}
SleepEx(__SIG_POLLING_INTERVAL_MS, true);
} while (1);
__sig_mask(&save);
}
} else {
rc = enosys(); /* TODO(jart): Implement me! */
// TODO(jart): sigsuspend metal support
rc = enosys();
}
STRACE("sigsuspend(%s) → %d% m", __strace_sigset(buf, sizeof(buf), 0, ignore),
rc);
STRACE("[...] sigsuspend → %d% m", rc);
return rc;
}