Elevate Windows production worthiness

- SQLite file locking now works on Windows
- SQLite will now use fdatasync() on non-Apple platforms
- Fix Ctrl-C handler on Windows to not crash with TLS
- Signals now work in multithreaded apps on Windows
- fcntl() will now accurately report EINVAL errors
- fcntl() now has excellent --strace logging
- Token bucket replenish now go 100x faster
- *NSYNC cancellations now work on Windows
- Support closefrom() on NetBSD
This commit is contained in:
Justine Tunney 2022-10-13 13:44:41 -07:00
parent d38700687a
commit 997ce29ddc
No known key found for this signature in database
GPG key ID: BE714B4575D6E328
95 changed files with 959 additions and 418 deletions

21
libc/calls/__sig.c Normal file
View file

@ -0,0 +1,21 @@
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi
Copyright 2022 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/calls/sig.internal.h"
struct Signals __sig;

View file

@ -16,26 +16,22 @@
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/assert.h"
#include "libc/calls/calls.h"
#include "libc/calls/sig.internal.h"
#include "libc/calls/state.internal.h"
#include "libc/calls/struct/sigaction.h"
#include "libc/calls/struct/siginfo.h"
#include "libc/intrin/cmpxchg.h"
#include "libc/intrin/lockcmpxchg.h"
#include "libc/calls/struct/sigset.h"
#include "libc/intrin/strace.internal.h"
#include "libc/log/libfatal.internal.h"
#include "libc/macros.internal.h"
#include "libc/runtime/internal.h"
#include "libc/runtime/runtime.h"
#include "libc/str/str.h"
#include "libc/sysv/consts/sa.h"
#include "libc/sysv/consts/sig.h"
#include "libc/sysv/errfuns.h"
/**
* @fileoverview UNIX signals for the New Technology, Part 2.
* @threadsafe
*/
#include "libc/thread/tls.h"
/**
* Allocates piece of memory for storing pending signal.
@ -61,16 +57,30 @@ static textwindows void __sig_free(struct Signal *mem) {
mem->used = false;
}
static inline textwindows int __sig_is_masked(int sig) {
if (__tls_enabled) {
return __get_tls()->tib_sigmask & (1ull << (sig - 1));
} else {
return __sig.sigmask & (1ull << (sig - 1));
}
}
textwindows int __sig_is_applicable(struct Signal *s) {
return (s->tid <= 0 || s->tid == gettid()) && !__sig_is_masked(s->sig);
}
/**
* Dequeues signal that isn't masked.
* @return signal or null if empty or none unmasked
*/
static textwindows struct Signal *__sig_remove(void) {
int tid;
struct Signal *prev, *res;
if (__sig.queue) {
tid = gettid();
__sig_lock();
for (prev = 0, res = __sig.queue; res; prev = res, res = res->next) {
if (!sigismember(&__sig.mask, res->sig)) {
if (__sig_is_applicable(res)) {
if (res == __sig.queue) {
__sig.queue = res->next;
} else if (prev) {
@ -78,8 +88,6 @@ static textwindows struct Signal *__sig_remove(void) {
}
res->next = 0;
break;
} else {
STRACE("%G is masked", res->sig);
}
}
__sig_unlock();
@ -117,7 +125,7 @@ static bool __sig_deliver(bool restartable, int sig, int si_code,
// setup the somewhat expensive information args
// only if they're requested by the user in sigaction()
if (flags & SA_SIGINFO) {
__repstosb(&info, 0, sizeof(info));
bzero(&info, sizeof(info));
info.si_signo = sig;
info.si_code = si_code;
infop = &info;
@ -134,7 +142,11 @@ static bool __sig_deliver(bool restartable, int sig, int si_code,
// since sigaction() is @asyncsignalsafe we only restore it if the
// user didn't change it during the signal handler. we also don't
// need to do anything if this was a oneshot signal or nodefer.
_lockcmpxchg(__sighandrvas + sig, (int32_t)(intptr_t)SIG_DFL, rva);
__sig_lock();
if (__sighandrvas[sig] == (int32_t)(intptr_t)SIG_DFL) {
__sighandrvas[sig] = rva;
}
__sig_unlock();
}
if (!restartable) {
@ -150,7 +162,7 @@ static bool __sig_deliver(bool restartable, int sig, int si_code,
/**
* Returns true if signal default action is to end process.
*/
static textwindows bool __sig_isfatal(int sig) {
static textwindows bool __sig_is_fatal(int sig) {
if (sig == SIGCHLD || sig == SIGURG || sig == SIGWINCH) {
return false;
} else {
@ -168,7 +180,7 @@ bool __sig_handle(bool restartable, int sig, int si_code, ucontext_t *ctx) {
bool delivered;
switch (__sighandrvas[sig]) {
case (intptr_t)SIG_DFL:
if (__sig_isfatal(sig)) {
if (__sig_is_fatal(sig)) {
STRACE("terminating on %G", sig);
_Exitr(128 + sig);
}
@ -194,20 +206,17 @@ bool __sig_handle(bool restartable, int sig, int si_code, ucontext_t *ctx) {
* @threadsafe
*/
textwindows int __sig_raise(int sig, int si_code) {
int rc;
int candeliver;
__sig_lock();
candeliver = !sigismember(&__sig.mask, sig);
__sig_unlock();
switch (candeliver) {
case 1:
if (1 <= sig && sig <= 64) {
if (!__sig_is_masked(sig)) {
++__sig_count;
__sig_handle(false, sig, si_code, 0);
return 0;
case 0:
} else {
STRACE("%G is masked", sig);
return __sig_add(sig, si_code);
default:
return -1; // sigismember() validates `sig`
return __sig_add(gettid(), sig, si_code);
}
} else {
return einval();
}
}
@ -216,10 +225,10 @@ textwindows int __sig_raise(int sig, int si_code) {
* @return 0 on success, otherwise -1 w/ errno
* @threadsafe
*/
textwindows int __sig_add(int sig, int si_code) {
textwindows int __sig_add(int tid, int sig, int si_code) {
int rc;
struct Signal *mem;
if (1 <= sig && sig <= NSIG) {
if (1 <= sig && sig <= 64) {
__sig_lock();
if (__sighandrvas[sig] == (unsigned)(intptr_t)SIG_IGN) {
STRACE("ignoring %G", sig);
@ -228,6 +237,7 @@ textwindows int __sig_add(int sig, int si_code) {
STRACE("enqueuing %G", sig);
++__sig_count;
if ((mem = __sig_alloc())) {
mem->tid = tid;
mem->sig = sig;
mem->si_code = si_code;
mem->next = __sig.queue;
@ -276,7 +286,7 @@ textwindows bool __sig_check(bool restartable) {
textwindows void __sig_check_ignore(const int sig, const unsigned rva) {
struct Signal *cur, *prev, *next;
if (rva != (unsigned)(intptr_t)SIG_IGN &&
(rva != (unsigned)(intptr_t)SIG_DFL || __sig_isfatal(sig))) {
(rva != (unsigned)(intptr_t)SIG_DFL || __sig_is_fatal(sig))) {
return;
}
if (__sig.queue) {
@ -298,25 +308,3 @@ textwindows void __sig_check_ignore(const int sig, const unsigned rva) {
__sig_unlock();
}
}
/**
* Determines the pending signals on New Technology.
*
* @param pending is to hold the pending signals
* @threadsafe
*/
textwindows void __sig_pending(sigset_t *pending) {
struct Signal *cur;
sigemptyset(pending);
if (__sig.queue) {
__sig_lock();
for (cur = __sig.queue; cur; cur = cur->next) {
if (__sighandrvas[cur->sig] != (unsigned)(intptr_t)SIG_IGN) {
pending->__bits[(cur->sig - 1) >> 6] |= (1ull << ((cur->sig - 1) & 63));
} else {
STRACE("%G is ignored", cur->sig);
}
}
__sig_unlock();
}
}

View file

@ -17,49 +17,39 @@
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/calls/sig.internal.h"
#include "libc/calls/state.internal.h"
#include "libc/macros.internal.h"
#include "libc/sysv/consts/sig.h"
#include "libc/sysv/errfuns.h"
#include "libc/thread/tls.h"
/**
* @fileoverview UNIX signals for the New Technology, Part 1.
* @threadsafe
*/
#define GetSigBit(x) (1ull << (((x)-1) & 63))
struct Signals __sig; // TODO(jart): Need TLS
#define GetSigBit(XXSIG) (1ull << (((XXSIG)-1) & 63))
/**
* Changes signal mask for main thread.
* @return 0 on success, or -1 w/ errno
*/
textwindows int __sig_mask(int how, const sigset_t *neu, sigset_t *old) {
int i;
uint64_t a, b;
uint64_t x, y, *mask;
if (how == SIG_BLOCK || how == SIG_UNBLOCK || how == SIG_SETMASK) {
__sig_lock();
if (__tls_enabled) {
mask = &__get_tls()->tib_sigmask;
} else {
mask = &__sig.sigmask;
}
if (old) {
*old = __sig.mask;
old->__bits[0] = *mask;
old->__bits[1] = 0;
}
if (neu) {
for (i = 0; i < ARRAYLEN(__sig.mask.__bits); ++i) {
if (how == SIG_BLOCK) {
__sig.mask.__bits[i] |= neu->__bits[i];
} else if (how == SIG_UNBLOCK) {
__sig.mask.__bits[i] &= ~neu->__bits[i];
} else {
__sig.mask.__bits[i] = neu->__bits[i];
}
x = *mask;
y = neu->__bits[0];
if (how == SIG_BLOCK) {
x |= y;
} else if (how == SIG_UNBLOCK) {
x &= ~y;
} else {
x = y;
}
__sig.mask.__bits[0] &= ~(GetSigBit(SIGKILL) | GetSigBit(SIGSTOP));
x &= ~(GetSigBit(SIGKILL) | GetSigBit(SIGSTOP) | GetSigBit(SIGABRT));
*mask = x;
}
__sig_unlock();
return 0;
} else {
return einval();
}
}
#undef GetSigBit

View file

@ -0,0 +1,43 @@
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi
Copyright 2022 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/calls/calls.h"
#include "libc/calls/sig.internal.h"
#include "libc/calls/state.internal.h"
#include "libc/calls/struct/sigset.h"
/**
* Determines the pending signals on New Technology.
*
* @param pending is to hold the pending signals
* @threadsafe
*/
textwindows void __sig_pending(sigset_t *pending) {
struct Signal *s;
sigemptyset(pending);
if (__sig.queue) {
__sig_lock();
for (s = __sig.queue; s; s = s->next) {
if (__sig_is_applicable(s) &&
__sighandrvas[s->sig] != (unsigned)(intptr_t)SIG_IGN) {
sigaddset(pending, s->sig);
}
}
__sig_unlock();
}
}

View file

@ -95,7 +95,6 @@ int fchownat(int, const char *, uint32_t, uint32_t, int);
int fcntl(int, int, ...);
int fdatasync(int);
int flock(int, int);
int lockf(int, int, int64_t);
int fork(void);
int fsync(int);
int ftruncate(int, int64_t);

View file

@ -35,27 +35,29 @@
* }
*
* @return 0 on success, or -1 w/ errno
* @error EBADF if `first` is negative
* @error EBADF on OpenBSD if `first` is greater than highest fd
* @error EINVAL if flags are bad or first is greater than last
* @error EMFILE if a weird race condition happens on Linux
* @error ENOSYS if not Linux 5.9+, FreeBSD 8+, or OpenBSD
* @error EINTR possibly on OpenBSD
* @error ENOMEM on Linux maybe
* @raise EBADF if `first` is negative
* @raise ENOSYS if not Linux 5.9+, FreeBSD 8+, OpenBSD, or NetBSD
* @raise EBADF on OpenBSD if `first` is greater than highest fd
* @raise EINVAL if flags are bad or first is greater than last
* @raise EMFILE if a weird race condition happens on Linux
* @raise EINTR possibly on OpenBSD
* @raise ENOMEM on Linux maybe
*/
int closefrom(int first) {
int rc, err;
if (IsNetbsd() || IsWindows() || IsMetal()) {
rc = enosys();
} else if (first < 0) {
if (first < 0) {
// consistent with openbsd
// freebsd allows this but it's dangerous
// necessary on linux due to type signature
rc = ebadf();
} else if (IsFreebsd() || IsOpenbsd()) {
rc = sys_closefrom(first);
} else if (IsLinux()) {
rc = sys_close_range(first, 0xffffffffu, 0);
} else if (IsNetbsd()) {
rc = __sys_fcntl(first, 10 /*F_CLOSEM*/, first);
} else {
rc = sys_closefrom(first);
rc = enosys();
}
STRACE("closefrom(%d) → %d% m", first, rc);
return rc;

View file

@ -37,8 +37,6 @@
#include "libc/sysv/consts/o.h"
#include "libc/sysv/errfuns.h"
bool __force_sqlite_to_work_until_we_can_fix_it;
static textwindows int sys_fcntl_nt_dupfd(int fd, int cmd, int start) {
if (start < 0) return einval();
return sys_dup_nt(fd, -1, (cmd == F_DUPFD_CLOEXEC ? O_CLOEXEC : 0), start);
@ -110,11 +108,7 @@ static textwindows int sys_fcntl_nt_lock(struct Fd *f, int cmd, uintptr_t arg) {
ok = true;
}
}
if (ok || __force_sqlite_to_work_until_we_can_fix_it) {
return 0;
} else {
return -1;
}
return ok ? 0 : -1;
}
if (l->l_type == F_UNLCK) {

View file

@ -18,11 +18,15 @@
*/
#include "libc/calls/calls.h"
#include "libc/calls/internal.h"
#include "libc/calls/struct/flock.h"
#include "libc/calls/struct/flock.internal.h"
#include "libc/calls/syscall-nt.internal.h"
#include "libc/calls/syscall-sysv.internal.h"
#include "libc/dce.h"
#include "libc/intrin/describeflags.internal.h"
#include "libc/intrin/strace.internal.h"
#include "libc/intrin/weaken.h"
#include "libc/sysv/consts/f.h"
#include "libc/sysv/errfuns.h"
#include "libc/zipos/zipos.internal.h"
@ -44,9 +48,49 @@
* Please be warned that locks currently do nothing on Windows since
* figuring out how to polyfill them correctly is a work in progress.
*
* @param cmd can be F_{GET,SET}{FD,FL}, etc.
* @param fd is the file descriptor
* @param cmd can be one of:
* - `F_GETFD` gets `FD_CLOEXEC` status of `fd
* - `F_SETFD` sets `FD_CLOEXEC` status of `arg` file descriptor
* - `F_GETFL` returns file descriptor status flags
* - `F_SETFL` sets file descriptor status flags
* - `F_DUPFD` is like dup() but `arg` is a minimum result, e.g. 3
* - `F_DUPFD_CLOEXEC` ditto but sets `O_CLOEXEC` on returned fd
* - `F_SETLK` for record locking where `arg` is `struct flock`
* - `F_SETLKW` ditto but waits (i.e. blocks) for lock
* - `F_GETLK` to retrieve information about a record lock
* - `F_OFD_SETLK` for better locks on Linux and XNU
* - `F_OFD_SETLKW` for better locks on Linux and XNU
* - `F_OFD_GETLK` for better locks on Linux and XNU
* - `F_FULLFSYNC` on MacOS for fsync() with release barrier
* - `F_BARRIERFSYNC` on MacOS for fsync() with even more barriers
* - `F_SETNOSIGPIPE` on MacOS and NetBSD to control `SIGPIPE`
* - `F_GETNOSIGPIPE` on MacOS and NetBSD to control `SIGPIPE`
* - `F_GETPATH` on MacOS and NetBSD where arg is `char[PATH_MAX]`
* - `F_MAXFD` on NetBSD to get max open file descriptor
* - `F_NOCACHE` on MacOS to toggle data caching
* - `F_GETPIPE_SZ` on Linux to get pipe size
* - `F_SETPIPE_SZ` on Linux to set pipe size
* - `F_NOTIFY` raise `SIGIO` upon `fd` events in `arg` on Linux
* - `DN_ACCESS` for file access
* - `DN_MODIFY` for file modifications
* - `DN_CREATE` for file creations
* - `DN_DELETE` for file deletions
* - `DN_RENAME` for file renames
* - `DN_ATTRIB` for file attribute changes
* - `DN_MULTISHOT` bitwise or for realtime signals (non-coalesced)
* @param arg can be FD_CLOEXEC, etc. depending
* @return 0 on success, or -1 w/ errno
* @raise EBADF if `fd` isn't a valid open file descriptor
* @raise EINVAL if `cmd` is unknown or unsupported by os
* @raise EINVAL if `cmd` is invalid or unsupported by os
* @raise EPERM if pledge() is in play w/o `stdio` or `flock` promise
* @raise ENOLCK if `F_SETLKW` would have exceeded `RLIMIT_LOCKS`
* @raise EPERM if `cmd` is `F_SETOWN` and we weren't authorized
* @raise ESRCH if `cmd` is `F_SETOWN` and process group not found
* @raise EDEADLK if `cmd` was `F_SETLKW` and waiting would deadlock
* @raise EMFILE if `cmd` is `F_DUPFD` or `F_DUPFD_CLOEXEC` and
* `RLIMIT_NOFILE` would be exceeded
* @asyncsignalsafe
* @restartable
*/
@ -54,20 +98,58 @@ int fcntl(int fd, int cmd, ...) {
int rc;
va_list va;
uintptr_t arg;
va_start(va, cmd);
arg = va_arg(va, uintptr_t);
va_end(va);
if (fd >= 0) {
if (fd < g_fds.n && g_fds.p[fd].kind == kFdZip) {
rc = _weaken(__zipos_fcntl)(fd, cmd, arg);
} else if (!IsWindows()) {
rc = sys_fcntl(fd, cmd, arg);
if (cmd >= 0) {
if (fd < g_fds.n && g_fds.p[fd].kind == kFdZip) {
rc = _weaken(__zipos_fcntl)(fd, cmd, arg);
} else if (!IsWindows()) {
rc = sys_fcntl(fd, cmd, arg);
} else {
rc = sys_fcntl_nt(fd, cmd, arg);
}
} else {
rc = sys_fcntl_nt(fd, cmd, arg);
rc = einval();
}
} else {
rc = einval();
rc = ebadf();
}
STRACE("fcntl(%d, %d, %p) → %#x% m", fd, cmd, arg, rc);
#ifdef SYSDEBUG
if (cmd == F_GETFD || //
cmd == F_GETOWN || //
cmd == F_FULLFSYNC || //
cmd == F_BARRIERFSYNC || //
cmd == F_MAXFD) {
STRACE("fcntl(%d, %s) → %d% m", fd, DescribeFcntlCmd(cmd), rc);
} else if (cmd == F_GETFL) {
STRACE("fcntl(%d, %s) → %s% m", fd, DescribeFcntlCmd(cmd),
DescribeOpenFlags(rc));
} else if (cmd == F_SETLK || //
cmd == F_SETLKW || //
cmd == F_GETLK || //
((SupportsLinux() || SupportsXnu()) && //
cmd != -1 && //
(cmd == F_OFD_SETLK || //
cmd == F_OFD_SETLKW || //
cmd == F_OFD_GETLK))) {
STRACE("fcntl(%d, %s, %s) → %d% m", fd, DescribeFcntlCmd(cmd),
DescribeFlock(cmd, (struct flock *)arg), rc);
} else if ((SupportsNetbsd() || SupportsXnu()) && cmd != -1 &&
cmd == F_GETPATH) {
STRACE("fcntl(%d, %s, [%s]) → %d% m", fd, DescribeFcntlCmd(cmd),
!rc ? (const char *)arg : "n/a", rc);
} else if (SupportsLinux() && cmd != -1 && cmd == F_NOTIFY) {
STRACE("fcntl(%d, %s, %s) → %d% m", fd, DescribeFcntlCmd(cmd),
DescribeDnotifyFlags(arg), rc);
} else {
STRACE("fcntl(%d, %s, %ld) → %#x% m", fd, DescribeFcntlCmd(cmd), arg, rc);
}
#endif
return rc;
}

View file

@ -17,10 +17,11 @@
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/calls/calls.h"
#include "libc/intrin/strace.internal.h"
#include "libc/calls/struct/stat.h"
#include "libc/calls/syscall-nt.internal.h"
#include "libc/calls/syscall-sysv.internal.h"
#include "libc/dce.h"
#include "libc/intrin/strace.internal.h"
#include "libc/runtime/runtime.h"
/**
@ -33,6 +34,7 @@
*/
int fdatasync(int fd) {
int rc;
struct stat st;
if (__nosync != 0x5453455454534146) {
if (!IsWindows()) {
rc = sys_fdatasync(fd);
@ -41,8 +43,8 @@ int fdatasync(int fd) {
}
STRACE("fdatasync(%d) → %d% m", fd, rc);
} else {
rc = 0;
STRACE("fdatasync(%d) → disabled% m", fd);
rc = fstat(fd, &st);
STRACE("fdatasync_fake(%d) → %d% m", fd, rc);
}
return rc;
}

View file

@ -17,10 +17,11 @@
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/calls/calls.h"
#include "libc/intrin/strace.internal.h"
#include "libc/calls/struct/stat.h"
#include "libc/calls/syscall-nt.internal.h"
#include "libc/calls/syscall-sysv.internal.h"
#include "libc/dce.h"
#include "libc/intrin/strace.internal.h"
#include "libc/runtime/runtime.h"
/**
@ -33,6 +34,7 @@
*/
int fsync(int fd) {
int rc;
struct stat st;
if (__nosync != 0x5453455454534146) {
if (!IsWindows()) {
rc = sys_fsync(fd);
@ -41,8 +43,8 @@ int fsync(int fd) {
}
STRACE("fysnc(%d) → %d% m", fd, rc);
} else {
rc = 0;
STRACE("fsync(%d) → disabled% m", fd);
rc = fstat(fd, &st);
STRACE("fsync_fake(%d) → %d% m", fd, rc);
}
return rc;
}

View file

@ -33,7 +33,7 @@
#include "libc/sysv/errfuns.h"
textwindows int sys_getrusage_nt(int who, struct rusage *usage) {
int64_t me, nsignals;
int64_t me;
struct NtIoCounters iocount;
struct NtProcessMemoryCountersEx memcount;
struct NtFileTime ftExit, ftUser, ftKernel, ftCreation;
@ -48,9 +48,6 @@ textwindows int sys_getrusage_nt(int who, struct rusage *usage) {
!GetProcessIoCounters(me, &iocount)) {
return __winerr();
}
__sig_lock();
nsignals = __sig_count;
__sig_unlock();
*usage = (struct rusage){
.ru_utime = WindowsDurationToTimeVal(ReadFileTime(ftUser)),
.ru_stime = WindowsDurationToTimeVal(ReadFileTime(ftKernel)),

View file

@ -31,9 +31,8 @@
textwindows bool _check_interrupts(bool restartable, struct Fd *fd) {
bool res;
if (__threaded && __threaded != gettid()) return false;
if (_weaken(_check_sigalrm)) _weaken(_check_sigalrm)();
if (!(__get_tls()->tib_flags & TIB_FLAG_TIME_CRITICAL)) {
if (!__tls_enabled || !(__get_tls()->tib_flags & TIB_FLAG_TIME_CRITICAL)) {
if (_weaken(_check_sigchld)) _weaken(_check_sigchld)();
if (fd && _weaken(_check_sigwinch)) _weaken(_check_sigwinch)(fd);
}

View file

@ -17,25 +17,44 @@
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/calls/sig.internal.h"
#include "libc/intrin/atomic.h"
#include "libc/intrin/strace.internal.h"
#include "libc/nexgen32e/nt2sysv.h"
#include "libc/nt/enum/ctrlevent.h"
#include "libc/nt/thread.h"
#include "libc/str/str.h"
#include "libc/sysv/consts/sicode.h"
#include "libc/sysv/consts/sig.h"
#include "libc/thread/tls.h"
#include "libc/thread/tls2.h"
textwindows bool32 __onntconsoleevent(uint32_t dwCtrlType) {
struct CosmoTib tib;
struct StackFrame *fr;
// win32 spawns a thread on its own just to deliver sigint
// TODO(jart): make signal code lockless so we can delete!
if (__tls_enabled && !__get_tls_win32()) {
bzero(&tib, sizeof(tib));
tib.tib_self = &tib;
tib.tib_self2 = &tib;
atomic_store_explicit(&tib.tib_tid, GetCurrentThreadId(),
memory_order_relaxed);
__set_tls_win32(&tib);
}
STRACE("__onntconsoleevent(%u)", dwCtrlType);
switch (dwCtrlType) {
case kNtCtrlCEvent:
__sig_add(SIGINT, SI_KERNEL);
__sig_add(0, SIGINT, SI_KERNEL);
return true;
case kNtCtrlBreakEvent:
__sig_add(SIGQUIT, SI_KERNEL);
__sig_add(0, SIGQUIT, SI_KERNEL);
return true;
case kNtCtrlCloseEvent:
case kNtCtrlLogoffEvent: // only received by services
case kNtCtrlShutdownEvent: // only received by services
__sig_add(SIGHUP, SI_KERNEL);
__sig_add(0, SIGHUP, SI_KERNEL);
return true;
default:
return false;

View file

@ -1256,16 +1256,18 @@ static privileged void AllowIoctlTty(struct Filter *f) {
// - TCP_FASTOPEN (0x17)
// - TCP_FASTOPEN_CONNECT (0x1e)
// - IPV6_V6ONLY (0x1a)
// - TCP_QUICKACK (0x0c)
//
static privileged void AllowSetsockoptRestrict(struct Filter *f) {
static const struct sock_filter fragment[] = {
BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, __NR_linux_setsockopt, 0, 24),
BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, __NR_linux_setsockopt, 0, 25),
BPF_STMT(BPF_LD | BPF_W | BPF_ABS, OFF(args[1])),
BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, 41, 3, 0),
BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, 0, 2, 0),
BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, 1, 1, 0),
BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, 6, 0, 18),
BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, 6, 0, 19),
BPF_STMT(BPF_LD | BPF_W | BPF_ABS, OFF(args[2])),
BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, 0x0c, 16, 0),
BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, 0x1a, 15, 0),
BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, 0x06, 14, 0),
BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, 0x0f, 13, 0),

View file

@ -18,13 +18,13 @@
*/
#include "libc/calls/calls.h"
#include "libc/calls/sig.internal.h"
#include "libc/intrin/strace.internal.h"
#include "libc/calls/syscall-sysv.internal.h"
#include "libc/dce.h"
#include "libc/thread/tls.h"
#include "libc/intrin/strace.internal.h"
#include "libc/runtime/internal.h"
#include "libc/sysv/consts/sicode.h"
#include "libc/sysv/consts/sig.h"
#include "libc/thread/tls.h"
#include "libc/thread/xnu.internal.h"
static textwindows inline bool HasWorkingConsole(void) {
@ -59,7 +59,7 @@ static noubsan void RaiseSigFpe(void) {
* @asyncsignalsafe
*/
int raise(int sig) {
int rc, event;
int rc, tid, event;
STRACE("raise(%G) → ...", sig);
if (sig == SIGTRAP) {
DebugBreak();
@ -67,7 +67,7 @@ int raise(int sig) {
} else if (sig == SIGFPE) {
RaiseSigFpe();
rc = 0;
} else if (!IsWindows()) {
} else if (!IsWindows() && !IsMetal()) {
rc = sys_tkill(gettid(), sig, 0);
} else {
rc = __sig_raise(sig, SI_TKILL);

View file

@ -19,13 +19,13 @@
#include "libc/assert.h"
#include "libc/calls/calls.h"
#include "libc/calls/sig.internal.h"
#include "libc/intrin/strace.internal.h"
#include "libc/calls/struct/itimerval.h"
#include "libc/calls/struct/siginfo.h"
#include "libc/dce.h"
#include "libc/errno.h"
#include "libc/fmt/conv.h"
#include "libc/intrin/bits.h"
#include "libc/intrin/strace.internal.h"
#include "libc/log/check.h"
#include "libc/math.h"
#include "libc/nexgen32e/nexgen32e.h"
@ -68,7 +68,7 @@ textwindows void _check_sigalrm(void) {
now = nowl();
elapsed = now - __lastalrm;
if (elapsed > __interval) {
__sig_add(SIGALRM, SI_TIMER);
__sig_add(0, SIGALRM, SI_TIMER);
if (__singleshot) {
__hastimer = false;
} else {

View file

@ -1,9 +1,10 @@
#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/calls/ucontext.h"
#define __SIG_QUEUE_LENGTH 8
#define __SIG_QUEUE_LENGTH 32
#define __SIG_POLLING_INTERVAL_MS 50
#define __SIG_LOGGING_INTERVAL_MS 1700
@ -13,26 +14,28 @@ COSMOPOLITAN_C_START_
struct Signal {
struct Signal *next;
bool used;
int tid;
int sig;
int si_code;
};
struct Signals {
sigset_t mask;
uint64_t sigmask; /* only if tls is disabled */
struct Signal *queue;
struct Signal mem[__SIG_QUEUE_LENGTH];
};
extern long __sig_count;
extern struct Signals __sig;
extern atomic_long __sig_count;
bool __sig_check(bool) hidden;
bool __sig_handle(bool, int, int, ucontext_t *) hidden;
int __sig_add(int, int) hidden;
int __sig_add(int, int, int) hidden;
int __sig_mask(int, const sigset_t *, sigset_t *) hidden;
int __sig_raise(int, int) hidden;
void __sig_check_ignore(const int, const unsigned) hidden;
void __sig_pending(sigset_t *) hidden;
int __sig_is_applicable(struct Signal *) hidden;
COSMOPOLITAN_C_END_
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */

View file

@ -21,10 +21,10 @@
#include "libc/calls/internal.h"
#include "libc/calls/sig.internal.h"
#include "libc/calls/state.internal.h"
#include "libc/intrin/strace.internal.h"
#include "libc/calls/struct/siginfo.h"
#include "libc/calls/syscall_support-nt.internal.h"
#include "libc/dce.h"
#include "libc/intrin/strace.internal.h"
#include "libc/nt/enum/wait.h"
#include "libc/nt/runtime.h"
#include "libc/nt/synchronization.h"
@ -65,5 +65,5 @@ void _check_sigchld(void) {
__fds_lock();
g_fds.p[pids[i]].zombie = true;
__fds_unlock();
__sig_add(SIGCHLD, CLD_EXITED);
__sig_add(0, SIGCHLD, CLD_EXITED);
}

View file

@ -18,4 +18,4 @@
*/
#include "libc/calls/sig.internal.h"
long __sig_count;
atomic_long __sig_count;

View file

@ -19,17 +19,18 @@
#include "libc/assert.h"
#include "libc/calls/calls.h"
#include "libc/calls/sig.internal.h"
#include "libc/intrin/strace.internal.h"
#include "libc/calls/struct/fd.internal.h"
#include "libc/calls/struct/sigaction.h"
#include "libc/calls/struct/winsize.h"
#include "libc/calls/struct/winsize.internal.h"
#include "libc/dce.h"
#include "libc/errno.h"
#include "libc/intrin/strace.internal.h"
#include "libc/nt/struct/consolescreenbufferinfoex.h"
#include "libc/str/str.h"
#include "libc/sysv/consts/sicode.h"
#include "libc/sysv/consts/sig.h"
#include "libc/thread/tls.h"
static struct winsize __ws;
@ -38,6 +39,7 @@ textwindows void _check_sigwinch(struct Fd *fd) {
siginfo_t si;
struct winsize ws, old;
struct NtConsoleScreenBufferInfoEx sbinfo;
if (__tls_enabled && __threaded != gettid()) return;
old = __ws;
e = errno;
if (old.ws_row != 0xffff) {
@ -45,7 +47,7 @@ textwindows void _check_sigwinch(struct Fd *fd) {
if (old.ws_col != ws.ws_col || old.ws_row != ws.ws_row) {
__ws = ws;
if (old.ws_col | old.ws_row) {
__sig_add(SIGWINCH, SI_KERNEL);
__sig_add(0, SIGWINCH, SI_KERNEL);
}
}
} else {

View file

@ -0,0 +1,13 @@
#ifndef COSMOPOLITAN_LIBC_CALLS_STRUCT_FLOCK_INTERNAL_H_
#define COSMOPOLITAN_LIBC_CALLS_STRUCT_FLOCK_INTERNAL_H_
#include "libc/calls/struct/flock.h"
#include "libc/mem/alloca.h"
#if !(__ASSEMBLER__ + __LINKER__ + 0)
COSMOPOLITAN_C_START_
const char *DescribeFlock(char[300], int, const struct flock *);
#define DescribeFlock(c, l) DescribeFlock(alloca(300), c, l)
COSMOPOLITAN_C_END_
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
#endif /* COSMOPOLITAN_LIBC_CALLS_STRUCT_FLOCK_INTERNAL_H_ */

View file

@ -17,30 +17,11 @@
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/calls/calls.h"
#include "libc/calls/sig.internal.h"
#include "libc/calls/syscall-sysv.internal.h"
#include "libc/calls/syscall_support-nt.internal.h"
#include "libc/dce.h"
#include "libc/intrin/strace.internal.h"
#include "libc/nt/enum/threadaccess.h"
#include "libc/nt/runtime.h"
#include "libc/nt/thread.h"
#include "libc/sysv/errfuns.h"
static textwindows int sys_tkill_nt(int tid, int sig) {
int rc;
int64_t hand;
if ((hand = OpenThread(kNtThreadTerminate, false, tid))) {
if (TerminateThread(hand, 128 + sig)) {
rc = 0;
} else {
rc = __winerr();
}
CloseHandle(hand);
} else {
rc = esrch();
}
return rc;
}
#include "libc/sysv/consts/sicode.h"
/**
* Kills thread.
@ -56,10 +37,10 @@ static textwindows int sys_tkill_nt(int tid, int sig) {
*/
int tkill(int tid, int sig) {
int rc;
if (!IsWindows()) {
if (!IsWindows() && !IsMetal()) {
rc = sys_tkill(tid, sig, 0);
} else {
rc = sys_tkill_nt(tid, sig);
rc = __sig_add(tid, sig, SI_TKILL);
}
STRACE("tkill(%d, %G) → %d% m", tid, sig, rc);
return rc;