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) {
x = *mask;
y = neu->__bits[0];
if (how == SIG_BLOCK) {
__sig.mask.__bits[i] |= neu->__bits[i];
x |= y;
} else if (how == SIG_UNBLOCK) {
__sig.mask.__bits[i] &= ~neu->__bits[i];
x &= ~y;
} else {
__sig.mask.__bits[i] = neu->__bits[i];
x = y;
}
x &= ~(GetSigBit(SIGKILL) | GetSigBit(SIGSTOP) | GetSigBit(SIGABRT));
*mask = x;
}
__sig.mask.__bits[0] &= ~(GetSigBit(SIGKILL) | GetSigBit(SIGSTOP));
}
__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,10 +98,13 @@ 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 (cmd >= 0) {
if (fd < g_fds.n && g_fds.p[fd].kind == kFdZip) {
rc = _weaken(__zipos_fcntl)(fd, cmd, arg);
} else if (!IsWindows()) {
@ -68,6 +115,41 @@ int fcntl(int fd, int cmd, ...) {
} else {
rc = einval();
}
STRACE("fcntl(%d, %d, %p) → %#x% m", fd, cmd, arg, rc);
} else {
rc = ebadf();
}
#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;

View file

@ -19,6 +19,7 @@ struct MagnumStr {
hidden extern const struct MagnumStr kClockNames[];
hidden extern const struct MagnumStr kErrnoDocs[];
hidden extern const struct MagnumStr kErrnoNames[];
hidden extern const struct MagnumStr kFcntlCmds[];
hidden extern const struct MagnumStr kIpOptnames[];
hidden extern const struct MagnumStr kOpenFlags[];
hidden extern const struct MagnumStr kRlimitNames[];

View file

@ -0,0 +1,37 @@
/*-*- 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/intrin/describeflags.internal.h"
#include "libc/macros.internal.h"
#include "libc/nt/enum/processaccess.h"
#include "libc/sysv/consts/dn.h"
static const struct DescribeFlags kDnotifyFlags[] = {
{DN_ACCESS, "ACCESS"}, //
{DN_MODIFY, "MODIFY"}, //
{DN_CREATE, "CREATE"}, //
{DN_DELETE, "DELETE"}, //
{DN_RENAME, "RENAME"}, //
{DN_ATTRIB, "ATTRIB"}, //
{DN_MULTISHOT, "MULTISHOT"}, //
};
const char *(DescribeDnotifyFlags)(char buf[80], int x) {
return DescribeFlags(buf, 80, kDnotifyFlags, ARRAYLEN(kDnotifyFlags), "DN_",
x);
}

View file

@ -0,0 +1,34 @@
/*-*- 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/fmt/itoa.h"
#include "libc/fmt/magnumstrs.internal.h"
#include "libc/intrin/describeflags.internal.h"
#include "libc/str/str.h"
const char *(DescribeFcntlCmd)(char buf[20], int x) {
const char *s;
if (x >= 0 && (s = GetMagnumStr(kFcntlCmds, x))) {
buf[0] = 'F';
buf[1] = '_';
strcpy(buf + 2, s);
} else {
FormatInt32(buf, x);
}
return buf;
}

View file

@ -16,8 +16,11 @@ const char *DescribeArchPrctlCode(char[12], int);
const char *DescribeCapability(char[20], int);
const char *DescribeClockName(char[32], int);
const char *DescribeDirfd(char[12], int);
const char *DescribeDnotifyFlags(char[80], int);
const char *DescribeErrno(char[12], int);
const char *DescribeErrnoResult(char[12], int);
const char *DescribeFcntlCmd(char[20], int);
const char *DescribeFlockType(char[12], int);
const char *DescribeFrame(char[32], int);
const char *DescribeFutexOp(char[64], int);
const char *DescribeHow(char[12], int);
@ -68,6 +71,8 @@ const char *DescribeWhichPrio(char[12], int);
#define DescribeDirfd(x) DescribeDirfd(alloca(12), x)
#define DescribeErrno(x) DescribeErrno(alloca(12), x)
#define DescribeErrnoResult(x) DescribeErrnoResult(alloca(12), x)
#define DescribeFcntlCmd(x) DescribeFcntlCmd(alloca(20), x)
#define DescribeFlockType(x) DescribeFlockType(alloca(12), x)
#define DescribeFrame(x) DescribeFrame(alloca(32), x)
#define DescribeFutexOp(x) DescribeFutexOp(alloca(64), x)
#define DescribeHow(x) DescribeHow(alloca(12), x)
@ -108,6 +113,7 @@ const char *DescribeWhichPrio(char[12], int);
#define DescribeStdioState(x) DescribeStdioState(alloca(12), x)
#define DescribeWhence(x) DescribeWhence(alloca(12), x)
#define DescribeWhichPrio(x) DescribeWhichPrio(alloca(12), x)
#define DescribeDnotifyFlags(x) DescribeDnotifyFlags(alloca(80), x)
COSMOPOLITAN_C_END_
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */

View file

@ -0,0 +1,66 @@
/*-*- 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 2021 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/struct/flock.h"
#include "libc/calls/struct/flock.internal.h"
#include "libc/dce.h"
#include "libc/intrin/asan.internal.h"
#include "libc/intrin/describeflags.internal.h"
#include "libc/intrin/kprintf.h"
#include "libc/sysv/consts/f.h"
#define N 300
#define append(...) o += ksnprintf(buf + o, N - o, __VA_ARGS__)
const char *(DescribeFlock)(char buf[N], int cmd, const struct flock *l) {
int o = 0;
if (!l) return "NULL";
if ((!IsAsan() && kisdangerous(l)) ||
(IsAsan() && !__asan_is_valid(l, sizeof(*l)))) {
ksnprintf(buf, N, "%p", l);
return buf;
}
append("{.l_type=%s", DescribeFlockType(l->l_type));
if (l->l_whence) {
append(", .l_whence=%s", DescribeWhence(l->l_whence));
}
if (l->l_start) {
append(", .l_start=%#lx", l->l_start);
}
if (l->l_len) {
append(", .l_len=%'ld", l->l_len);
}
if (l->l_pid && (cmd == F_GETLK || cmd == F_OFD_GETLK)) {
append(", .l_pid=%d", l->l_pid);
}
if (l->l_sysid) {
append(", .l_sysid=%d", l->l_sysid);
}
append("}");
return buf;
}

View file

@ -0,0 +1,28 @@
/*-*- 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/fmt/itoa.h"
#include "libc/sysv/consts/f.h"
const char *(DescribeFlockType)(char buf[12], int x) {
if (x == F_RDLCK) return "F_RDLCK";
if (x == F_WRLCK) return "F_WRLCK";
if (x == F_UNLCK) return "F_UNLCK";
FormatInt32(buf, x);
return buf;
}

View file

@ -32,6 +32,7 @@ const char *(DescribeOpenFlags)(char buf[128], int x) {
char *s;
int i, n;
struct DescribeFlags d[N];
if (x == -1) return "-1";
// TODO(jart): unify DescribeFlags and MagnumStr data structures
for (n = 0; kOpenFlags[n].x != MAGNUM_TERMINATOR; ++n) {
if (n == N) notpossible;

View file

@ -19,6 +19,7 @@
#include "libc/calls/calls.h"
#include "libc/calls/state.internal.h"
#include "libc/calls/syscall-sysv.internal.h"
#include "libc/intrin/atomic.h"
#include "libc/thread/tls.h"
/**
@ -36,7 +37,7 @@
int gettid(void) {
int tid;
if (__tls_enabled && !__vforked) {
tid = __get_tls()->tib_tid;
tid = atomic_load_explicit(&__get_tls()->tib_tid, memory_order_relaxed);
if (tid > 0) {
return tid;
}

57
libc/intrin/kfcntlcmds.S Normal file
View file

@ -0,0 +1,57 @@
/*-*- mode:unix-assembly; indent-tabs-mode:t; tab-width:8; coding:utf-8 -*-│
vi: set et ft=asm ts=8 tw=8 fenc=utf-8 :vi
Copyright 2021 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/fmt/magnumstrs.internal.h"
#include "libc/macros.internal.h"
.macro .e e s
.long \e - kFcntlCmds
.long .L\@ - kFcntlCmds
.rodata.str1.1
.L\@: .string "\s"
.previous
.endm
.section .rodata,"a",@progbits
.align 4
.underrun
kFcntlCmds:
.e F_GETFD,"GETFD"
.e F_SETFD,"SETFD"
.e F_GETFL,"GETFL"
.e F_SETFL,"SETFL"
.e F_DUPFD,"DUPFD"
.e F_DUPFD_CLOEXEC,"DUPFD_CLOEXEC"
.e F_GETLK,"GETLK"
.e F_SETLK,"SETLK"
.e F_SETLKW,"SETLKW"
.e F_GETOWN,"GETOWN"
.e F_SETOWN,"SETOWN"
.e F_GETPATH,"GETPATH"
.e F_NOCACHE,"NOCACHE"
.e F_FULLFSYNC,"FULLFSYNC"
.e F_OFD_GETLK,"OFD_GETLK"
.e F_OFD_SETLK,"OFD_SETLK"
.e F_OFD_SETLKW,"OFD_SETLKW"
.e F_BARRIERFSYNC,"BARRIERFSYNC"
.e F_SETNOSIGPIPE,"SETNOSIGPIPE"
.e F_GETNOSIGPIPE,"GETNOSIGPIPE"
.e F_MAXFD,"MAXFD"
.long MAGNUM_TERMINATOR
.endobj kFcntlCmds,globl,hidden
.overrun

View file

@ -26,6 +26,7 @@
#include "libc/fmt/fmt.h"
#include "libc/intrin/asan.internal.h"
#include "libc/intrin/asancodes.h"
#include "libc/intrin/atomic.h"
#include "libc/intrin/bits.h"
#include "libc/intrin/cmpxchg.h"
#include "libc/intrin/kprintf.h"
@ -326,7 +327,8 @@ privileged static size_t kformat(char *b, size_t n, const char *fmt,
if (!__tls_enabled) {
x = __pid;
} else {
x = __get_tls_privileged()->tib_tid;
x = atomic_load_explicit(&__get_tls_privileged()->tib_tid,
memory_order_relaxed);
}
if (!__nocolor && p + 7 <= e) {
*p++ = '\e';

View file

@ -20,6 +20,7 @@
#include "libc/intrin/describeflags.internal.h"
#include "libc/intrin/describentoverlapped.internal.h"
#include "libc/intrin/strace.internal.h"
#include "libc/nt/enum/filelockflags.h"
#include "libc/nt/files.h"
__msabi extern typeof(LockFileEx) *const __imp_LockFileEx;
@ -35,14 +36,16 @@ bool32 LockFileEx(int64_t hFile, uint32_t dwFlags, uint32_t dwReserved,
uint32_t nNumberOfBytesToLockHigh,
struct NtOverlapped *lpOverlapped) {
bool32 ok;
STRACE("LockFileEx(%ld, %s, %#x, %'zu, %s) → ...", hFile,
if (~dwFlags & kNtLockfileFailImmediately) {
NTTRACE("LockFileEx(%ld, %s, %#x, %'zu, %s) → ...", hFile,
DescribeNtLockFileFlags(dwFlags), dwReserved,
(uint64_t)nNumberOfBytesToLockHigh << 32 | nNumberOfBytesToLockLow,
DescribeNtOverlapped(lpOverlapped));
}
ok = __imp_LockFileEx(hFile, dwFlags, dwReserved, nNumberOfBytesToLockLow,
nNumberOfBytesToLockHigh, lpOverlapped);
if (!ok) __winerr();
STRACE("LockFileEx(%ld, %s, %#x, %'zu, [%s]) → %hhhd% m", hFile,
NTTRACE("LockFileEx(%ld, %s, %#x, %'zu, [%s]) → %hhhd% m", hFile,
DescribeNtLockFileFlags(dwFlags), dwReserved,
(uint64_t)nNumberOfBytesToLockHigh << 32 | nNumberOfBytesToLockLow,
DescribeNtOverlapped(lpOverlapped), ok);

View file

@ -37,13 +37,11 @@ bool32 UnlockFileEx(int64_t hFile, uint32_t dwReserved,
uint32_t nNumberOfBytesToUnlockHigh,
struct NtOverlapped *lpOverlapped) {
bool32 ok;
STRACE("UnlockFileEx(%ld, %#x, %'zu, %s) → ...", hFile, dwReserved,
(uint64_t)nNumberOfBytesToUnlockHigh << 32 | nNumberOfBytesToUnlockLow,
DescribeNtOverlapped(lpOverlapped));
ok = __imp_UnlockFileEx(hFile, dwReserved, nNumberOfBytesToUnlockLow,
nNumberOfBytesToUnlockHigh, lpOverlapped);
if (!ok) __winerr();
STRACE("UnlockFileEx(%ld, %#x, %'zu, [%s]) → %hhhd% m", hFile, dwReserved,
NTTRACE(
"UnlockFileEx(%ld, %#x, %'zu, [%s]) → %hhhd% m", hFile, dwReserved,
(uint64_t)nNumberOfBytesToUnlockHigh << 32 | nNumberOfBytesToUnlockLow,
DescribeNtOverlapped(lpOverlapped), ok);
return ok;

View file

@ -2,5 +2,7 @@
#define COSMOPOLITAN_LIBC_ISYSTEM_SYS_FCNTL_H_
#include "libc/calls/calls.h"
#include "libc/sysv/consts/at.h"
#include "libc/sysv/consts/dn.h"
#include "libc/sysv/consts/f.h"
#include "third_party/musl/lockf.h"
#endif /* COSMOPOLITAN_LIBC_ISYSTEM_SYS_FCNTL_H_ */

View file

@ -12,4 +12,5 @@
#include "libc/time/time.h"
#include "third_party/getopt/getopt.h"
#include "third_party/musl/crypt.h"
#include "third_party/musl/lockf.h"
#endif

View file

@ -21,6 +21,7 @@
#include "libc/calls/struct/sigaction.h"
#include "libc/calls/struct/utsname.h"
#include "libc/calls/syscall-sysv.internal.h"
#include "libc/dce.h"
#include "libc/errno.h"
#include "libc/fmt/itoa.h"
#include "libc/intrin/asan.internal.h"
@ -229,7 +230,7 @@ relegated void ShowCrashReport(int err, int sig, struct siginfo *si,
ShowFunctionCalls(ctx);
}
kprintf("\n");
__print_maps();
if (!IsWindows()) __print_maps();
/* PrintSystemMappings(2); */
if (__argv) {
for (i = 0; i < __argc; ++i) {

View file

@ -80,7 +80,7 @@
#define kNtErrorSemIsSet 102
#define kNtErrorTooManySemRequests 103
#define kNtErrorInvalidAtInterruptTime 104
#define kNtErrorSemOwnerDied 105
#define kNtErrorSemOwnerDied 105 /* EOWNERDEAD */
#define kNtErrorSemUserLimit 106
#define kNtErrorDiskChange 107
#define kNtErrorDriveLocked 108
@ -336,7 +336,7 @@
#define kNtErrorVrfCfgEnabled 1183
#define kNtErrorPartitionTerminating 1184
#define kNtErrorUserProfileLoad 500
#define kNtErrorArithmeticOverflow 534
#define kNtErrorArithmeticOverflow 534 /* EOVERFLOW */
#define kNtErrorPipeConnected 535
#define kNtErrorPipeListening 536
#define kNtErrorVerifierStop 537
@ -383,7 +383,7 @@
#define kNtErrorIllegalFloatContext 579
#define kNtErrorNoEventPair 580
#define kNtErrorDomainCtrlrConfigError 581
#define kNtErrorIllegalCharacter 582
#define kNtErrorIllegalCharacter 582 /* EILSEQ */
#define kNtErrorUndefinedCharacter 583
#define kNtErrorFloppyVolume 584
#define kNtErrorBiosFailedToConnectInterrupt 585
@ -761,7 +761,7 @@
#define kNtErrorRemoteSessionLimitExceeded 1220
#define kNtErrorDupDomainname 1221
#define kNtErrorNoNetwork 1222
#define kNtErrorCancelled 1223
#define kNtErrorCancelled 1223 /* ECANCELED */
#define kNtErrorUserMappedFile 1224
#define kNtErrorConnectionRefused 1225
#define kNtErrorGracefulDisconnect 1226
@ -1217,7 +1217,7 @@
#define kNtErrorDriveMediaMismatch 4303
#define kNtErrorMediaOffline 4304
#define kNtErrorLibraryOffline 4305
#define kNtErrorEmpty 4306
#define kNtErrorEmpty 4306 /* ENOMSG */
#define kNtErrorNotEmpty 4307
#define kNtErrorMediaUnavailable 4308
#define kNtErrorResourceDisabled 4309

View file

@ -43,6 +43,7 @@
#include "libc/thread/openbsd.internal.h"
#include "libc/thread/thread.h"
#include "libc/thread/tls.h"
#include "libc/thread/tls2.h"
#include "libc/thread/xnu.internal.h"
#define __NR_thr_new 455
@ -97,11 +98,7 @@ WinThreadEntry(int rdi, // rcx
int rdx, // r8
struct CloneArgs *wt) { // r9
int rc;
if (wt->tls) {
asm("mov\t%1,%%gs:%0"
: "=m"(*((long *)0x1480 + __tls_index))
: "r"(wt->tls));
}
if (wt->tls) __set_tls_win32(wt->tls);
*wt->ptid = wt->tid;
*wt->ctid = wt->tid;
rc = WinThreadLaunch(wt->arg, wt->tid, wt->func, (intptr_t)wt & -16);

View file

@ -48,7 +48,7 @@
#define STATE_QUOTED_VAR 4
#define STATE_WHITESPACE 5
#define READ24LE(s) READ32LE(s "\0")
#define READ24(s) READ32LE(s "\0")
struct Env {
char *s;
@ -333,16 +333,16 @@ static int Test(void) {
if (n == 4) {
w = READ32LE(args[2]) & 0x00ffffff;
if ((w & 65535) == READ16LE("=")) return !!strcmp(args[1], args[3]);
if (w == READ24LE("==")) return !!strcmp(args[1], args[3]);
if (w == READ24LE("!=")) return !strcmp(args[1], args[3]);
if (w == READ24("==")) return !!strcmp(args[1], args[3]);
if (w == READ24("!=")) return !strcmp(args[1], args[3]);
} else if (n == 3) {
w = READ32LE(args[1]) & 0x00ffffff;
if (w == READ24LE("-n")) return !(strlen(args[2]) > 0);
if (w == READ24LE("-z")) return !(strlen(args[2]) == 0);
if (w == READ24LE("-e")) return !!stat(args[2], &st);
if (w == READ24LE("-f")) return !stat(args[2], &st) && S_ISREG(st.st_mode);
if (w == READ24LE("-d")) return !stat(args[2], &st) && S_ISDIR(st.st_mode);
if (w == READ24LE("-h")) return !stat(args[2], &st) && S_ISLNK(st.st_mode);
if (w == READ24("-n")) return !(strlen(args[2]) > 0);
if (w == READ24("-z")) return !(strlen(args[2]) == 0);
if (w == READ24("-e")) return !!stat(args[2], &st);
if (w == READ24("-f")) return !(!stat(args[2], &st) && S_ISREG(st.st_mode));
if (w == READ24("-d")) return !(!stat(args[2], &st) && S_ISDIR(st.st_mode));
if (w == READ24("-h")) return !(!stat(args[2], &st) && S_ISLNK(st.st_mode));
}
return 1;
}

View file

@ -19,17 +19,15 @@
#include "libc/assert.h"
#include "libc/calls/calls.h"
#include "libc/intrin/strace.internal.h"
#include "libc/thread/tls.h"
#include "libc/runtime/runtime.h"
#include "libc/thread/tls.h"
extern int __threadcalls_end[];
extern int __threadcalls_start[];
#pragma weak __threadcalls_start
#pragma weak __threadcalls_end
privileged void __enable_threads(void) {
if (__threaded) return;
STRACE("__enable_threads()");
static privileged dontinline void FixupLocks(void) {
__morph_begin();
/*
* _NOPL("__threadcalls", func)
@ -55,5 +53,11 @@ privileged void __enable_threads(void) {
_base[*p + 2] = 0xe8;
}
__morph_end();
}
void __enable_threads(void) {
if (__threaded) return;
STRACE("__enable_threads()");
FixupLocks();
__threaded = gettid();
}

View file

@ -23,6 +23,7 @@
#include "libc/errno.h"
#include "libc/intrin/asan.internal.h"
#include "libc/intrin/asancodes.h"
#include "libc/intrin/atomic.h"
#include "libc/intrin/bits.h"
#include "libc/intrin/weaken.h"
#include "libc/log/libfatal.internal.h"
@ -99,6 +100,7 @@ _Alignas(TLS_ALIGNMENT) static char __static_tls[5008];
* and your `errno` variable also won't be thread safe anymore.
*/
privileged void __enable_tls(void) {
int tid;
size_t siz;
struct CosmoTib *tib;
char *mem, *tls;
@ -133,12 +135,13 @@ privileged void __enable_tls(void) {
if (IsLinux()) {
// gnu/systemd guarantees pid==tid for the main thread so we can
// avoid issuing a superfluous system call at startup in program
tib->tib_tid = __pid;
tid = __pid;
} else {
tib->tib_tid = sys_gettid();
tid = sys_gettid();
}
atomic_store_explicit(&tib->tib_tid, tid, memory_order_relaxed);
_pthread_main.tib = tib;
_pthread_main.tid = tib->tib_tid;
_pthread_main.tid = tid;
_pthread_main.flags = PT_MAINTHREAD;
__repmovsb(tls, _tdata_start, _TLDZ);

View file

@ -23,6 +23,7 @@
#include "libc/calls/syscall-sysv.internal.h"
#include "libc/calls/syscall_support-sysv.internal.h"
#include "libc/dce.h"
#include "libc/intrin/atomic.h"
#include "libc/intrin/strace.internal.h"
#include "libc/nt/process.h"
#include "libc/runtime/internal.h"
@ -56,7 +57,9 @@ int _fork(uint32_t dwCreationFlags) {
parent = __pid;
__pid = dx;
if (__tls_enabled) {
__get_tls()->tib_tid = IsLinux() ? dx : sys_gettid();
atomic_store_explicit(&__get_tls()->tib_tid,
IsLinux() ? dx : sys_gettid(),
memory_order_relaxed);
}
if (!IsWindows()) sys_sigprocmask(SIG_SETMASK, &old, 0);
STRACE("fork() → 0 (child of %d)", parent);

View file

@ -64,11 +64,11 @@ syscon errno ENAMETOOLONG 36 63 63 63 63 10063 # filename too lon
syscon errno ENOLCK 37 77 77 77 77 158 # no locks available; kNtErrorNotLocked; bsd consensus; raised by fcntl(2), flock(2)
syscon errno ENOTEMPTY 39 66 66 66 66 145 # directory not empty; bsd consensus; kNtErrorDirNotEmpty (TODO: What is WSAENOTEMPTY? 10066); raised by rmdir(2)
syscon errno ELOOP 40 62 62 62 62 1921 # too many levels of symbolic links; bsd consensus; kNtErrorCantResolveFilename; raised by access(2), acct(2), bind(2), chdir(2), chmod(2), chown(2), chroot(2), epoll_ctl(2), execve(2), execveat(2), keyctl(2), link(2), mkdir(2), mknod(2), mount(2), open(2), open_by_handle_at(2), openat2(2), readlink(2), rename(2), rmdir(2), spu_create(2), stat(2), statfs(2), statx(2), symlink(2), truncate(2), unlink(2), utimensat(2)
syscon errno ENOMSG 42 91 83 90 83 0 # raised by msgop(2)
syscon errno ENOMSG 42 91 83 90 83 4306 # kNtErrorEmpty; raised by msgop(2)
syscon errno EIDRM 43 90 82 89 82 0 # identifier removed; raised by msgctl(2), msgget(2), msgop(2), semctl(2), semop(2), shmctl(2), shmget(2), shmop(2)
syscon errno EPROTO 71 100 92 95 96 0 # raised by accept(2), connect(2), socket(2), socketpair(2)
syscon errno EOVERFLOW 75 84 84 87 84 0 # raised by aio_read(2), copy_file_range(2), ctime(2), fanotify_init(2), lseek(2), mmap(2), open(2), open_by_handle_at(2), sem_post(2), sendfile(2), shmctl(2), stat(2), statfs(2), statvfs(2), time(2), timegm(2)
syscon errno EILSEQ 84 92 86 84 85 0 # returned by fgetwc(3), fputwc(3), getwchar(3), putwchar(3), scanf(3), ungetwc(3)
syscon errno EOVERFLOW 75 84 84 87 84 534 # kNtErrorArithmeticOverflow; raised by aio_read(2), copy_file_range(2), ctime(2), fanotify_init(2), lseek(2), mmap(2), open(2), open_by_handle_at(2), sem_post(2), sendfile(2), shmctl(2), stat(2), statfs(2), statvfs(2), time(2), timegm(2)
syscon errno EILSEQ 84 92 86 84 85 582 # kNtErrorIllegalCharacter; returned by fgetwc(3), fputwc(3), getwchar(3), putwchar(3), scanf(3), ungetwc(3)
syscon errno EUSERS 87 68 68 68 68 10068 # too many users; bsd consensus; WSAEUSERS; raised by acct(2)
syscon errno ENOTSOCK 88 38 38 38 38 10038 # not a socket; bsd consensus; WSAENOTSOCK; raised by accept(2), bind(2), connect(2), getpeername(2), getsockname(2), getsockopt(2), listen(2), recv(2), send(2), shutdown(2)
syscon errno EDESTADDRREQ 89 39 39 39 39 10039 # destination address required; bsd consensus; WSAEDESTADDRREQ; raised by send(2), write(2)
@ -94,7 +94,7 @@ syscon errno ENOTCONN 107 57 57 57 57 10057 # socket is not conne
syscon errno ESHUTDOWN 108 58 58 58 58 10058 # cannot send after transport endpoint shutdown; note that shutdown write is an EPIPE; bsd consensus; WSAESHUTDOWN
syscon errno ETOOMANYREFS 109 59 59 59 59 10059 # too many references: cannot splice; bsd consensus; WSAETOOMANYREFS; raised by sendmsg(2), unix(7)
syscon errno ETIMEDOUT 110 60 60 60 60 1460 # connection timed out; kNtErrorTimeout; bsd consensus; WSAETIMEDOUT; raised by connect(2), futex(2), keyctl(2), tcp(7)
syscon errno ETIME 62 101 60 60 92 0 # timer expired (POSIX.1 XSI STREAMS)
syscon errno ETIME 62 101 60 60 92 1460 # timer expired (POSIX.1 XSI STREAMS)
syscon errno ECONNREFUSED 111 61 61 61 61 10061 # bsd consensus; WSAECONNREFUSED; raised by connect(2), listen(2), recv(2), unix(7), udp(7)system-imposed limit on the number of threads was encountered.
syscon errno EHOSTDOWN 112 64 64 64 64 10064 # bsd consensus; WSAEHOSTDOWN; raised by accept(2)
syscon errno EHOSTUNREACH 113 65 65 65 65 10065 # bsd consensus; WSAEHOSTUNREACH; raised by accept(2), ip(7)
@ -120,8 +120,8 @@ syscon errno ESHLIBVERS 0 87 0 0 0 0 # shiver me timbers
syscon errno EBADMACHO 0 88 0 0 0 0 #
syscon errno ENOPOLICY 0 103 0 0 0 0 #
syscon errno EBADMSG 74 94 89 92 88 0 # raised by ioctl_getfsmap(2)
syscon errno ECANCELED 125 89 85 88 87 0 # raised by timerfd_create(2)
syscon errno EOWNERDEAD 130 105 96 94 97 0 # raised by pthread_cond_timedwait(3), pthread_mutex_consistent(3), pthread_mutex_getprioceiling(3), pthread_mutex_lock(3), pthread_mutex_timedlock(3), pthread_mutexattr_getrobust(3), pthread_mutexattr_setrobust(3)
syscon errno ECANCELED 125 89 85 88 87 1223 # kNtErrorCancelled; raised by timerfd_create(2)
syscon errno EOWNERDEAD 130 105 96 94 97 105 # kNtErrorSemOwnerDied; raised by pthread_cond_timedwait(3), pthread_mutex_consistent(3), pthread_mutex_getprioceiling(3), pthread_mutex_lock(3), pthread_mutex_timedlock(3), pthread_mutexattr_getrobust(3), pthread_mutexattr_setrobust(3)
syscon errno ENOTRECOVERABLE 131 104 95 93 98 0 # raised by pthread_cond_timedwait(3), pthread_mutex_consistent(3), pthread_mutex_getprioceiling(3), pthread_mutex_lock(3), pthread_mutex_timedlock(3), pthread_mutexattr_getrobust(3), pthread_mutexattr_setrobust(3)
syscon errno ENONET 64 0 0 0 0 0 # unilateral; raised by accept(2)
syscon errno ERESTART 85 -1 -1 -1 -3 0 # should only be seen in ptrace()
@ -356,15 +356,22 @@ syscon fcntl2 F_GETFD 1 1 1 1 1 1 # unix consensus & faked nt
syscon fcntl2 F_SETFD 2 2 2 2 2 2 # unix consensus & faked nt
syscon fcntl2 F_GETFL 3 3 3 3 3 3 # unix consensus & faked nt
syscon fcntl2 F_SETFL 4 4 4 4 4 4 # unix consensus & faked nt
syscon fcntl2 F_SETOWN 8 6 6 6 6 0 # bsd consensus
syscon fcntl2 F_GETOWN 9 5 5 5 5 0 # bsd consensus
syscon fcntl2 F_FULLFSYNC 0 51 0 0 0 0 #
syscon fcntl2 F_NOCACHE 0 48 0 0 0 0 #
syscon fcntl2 F_SETOWN 8 6 6 6 6 -1 # bsd consensus
syscon fcntl2 F_GETOWN 9 5 5 5 5 -1 # bsd consensus
syscon fcntl2 F_FULLFSYNC -1 51 -1 -1 -1 -1 #
syscon fcntl2 F_BARRIERFSYNC -1 85 -1 -1 -1 -1 #
syscon fcntl2 F_NOCACHE -1 48 -1 -1 -1 -1 #
syscon fcntl3 F_SETNOSIGPIPE -1 73 -1 -1 14 -1 #
syscon fcntl3 F_GETNOSIGPIPE -1 74 -1 -1 13 -1 #
syscon fcntl3 F_GETPATH -1 50 -1 -1 15 -1 # geth path associated with fd into buffer with PATH_MAX (1024) bytes
syscon fcntl3 FD_CLOEXEC 1 1 1 1 1 1 # unix consensus & faked nt
syscon fcntl F_DUPFD_CLOEXEC 0x0406 67 17 10 12 0x0406 # Linux 2.6.24+; faked nt
syscon fcntl F_MAXFD 0 0 0 0 11 0 #
syscon fcntl FREAD 0 1 1 1 1 0 #
syscon fcntl FWRITE 0 2 2 2 2 0 #
syscon fcntl F_MAXFD -1 -1 -1 -1 11 -1 #
syscon fcntl F_NOTIFY 0x0402 -1 -1 -1 -1 -1
syscon fcntl F_SETPIPE_SZ 0x0407 -1 -1 -1 -1 -1
syscon fcntl F_GETPIPE_SZ 0x0408 -1 -1 -1 -1 -1
syscon fcntl FREAD 0 1 1 1 1 0 # wut is it
syscon fcntl FWRITE 0 2 2 2 2 0 # wut is it
# fcntl3 O_NONBLOCK
# fcntl3 O_APPEND
@ -376,31 +383,24 @@ syscon fcntl FWRITE 0 2 2 2 2 0 #
#
# group name GNU/Systemd XNU's Not UNIX! FreeBSD OpenBSD NetBSD The New Technology Commentary
syscon fcntl F_SETLK 6 8 12 8 8 6 # polyfilled nt
syscon compat F_SETLK64 6 8 12 8 8 6 # polyfilled nt
syscon fcntl F_SETLKW 7 9 13 9 9 7
syscon compat F_SETLKW64 7 9 13 9 9 7
syscon fcntl F_SETLKW 7 9 13 9 9 7 # polyfilled nt
syscon fcntl F_GETLK 5 7 11 7 7 5 # polyfilled nt
syscon compat F_GETLK64 5 7 11 7 7 5 # polyfilled nt
syscon fcntl F_OFD_SETLK 37 90 -1 -1 -1 6
syscon fcntl F_OFD_SETLKW 38 91 -1 -1 -1 7
syscon fcntl F_OFD_GETLK 36 92 -1 -1 -1 5
syscon fcntl F_RDLCK 0 1 1 1 1 0 # polyfilled nt; bsd consensus
syscon fcntl F_WRLCK 1 3 3 3 3 1 # polyfilled nt; bsd consensus
syscon fcntl F_UNLCK 2 2 2 2 2 2 # polyfilled nt; unix consensus
syscon compat F_SETLK64 6 8 12 8 8 6 # polyfilled nt
syscon compat F_SETLKW64 7 9 13 9 9 7
syscon compat F_GETLK64 5 7 11 7 7 5 # polyfilled nt
syscon fcntl F_ULOCK 0 0 0 0 0 0 # TODO: specified by posix but not kernels?
syscon fcntl F_LOCK 1 1 1 1 1 0 # unix consensus
syscon fcntl F_TLOCK 2 2 2 2 2 0 # unix consensus
syscon fcntl F_TEST 3 3 3 3 3 0 # unix consensus
syscon fcntl F_SETSIG 10 0 0 0 0 0
syscon fcntl F_GETSIG 11 0 0 0 0 0
syscon fcntl F_SETOWN_EX 15 0 0 0 0 0
syscon fcntl F_GETOWN_EX 0x10 0 0 0 0 0
syscon fcntl F_OFD_GETLK 36 0 0 0 0 0
syscon fcntl F_OFD_SETLK 37 0 0 0 0 0
syscon fcntl F_OFD_SETLKW 38 0 0 0 0 0
syscon fcntl F_SETLEASE 0x0400 0 0 0 0 0
syscon fcntl F_GETLEASE 0x0401 0 0 0 0 0
syscon fcntl F_NOTIFY 0x0402 0 0 0 0 0
syscon fcntl F_SETPIPE_SZ 0x0407 0 0 0 0 0
syscon fcntl F_GETPIPE_SZ 0x0408 0 0 0 0 0
syscon fcntl F_SETSIG 10 -1 -1 -1 -1 -1
syscon fcntl F_GETSIG 11 -1 -1 -1 -1 -1
syscon fcntl F_SETOWN_EX 15 -1 -1 -1 -1 -1
syscon fcntl F_GETOWN_EX 0x10 -1 -1 -1 -1 -1
syscon fcntl F_SETLEASE 0x0400 -1 -1 -1 -1 -1
syscon fcntl F_GETLEASE 0x0401 -1 -1 -1 -1 -1
syscon ioctl FIONBIO 0x5421 0x8004667e 0x8004667e 0x8004667e 0x8004667e 0x8004667e # BSD-The New Technology consensus; FIONBIO is traditional O_NONBLOCK; see F_SETFL for re-imagined api
syscon ioctl FIOASYNC 0x5452 0x8004667d 0x8004667d 0x8004667d 0x8004667d 0x8004667d # BSD-The New Technology consensus
@ -763,9 +763,9 @@ syscon tcp TCP_CORK 3 4 4 16 4 0 # nagle's algorithm strikes agai
syscon tcp TCP_MAXSEG 2 2 2 2 2 0 # reduces tcp segment size; see also tcp offloading
syscon tcp TCP_FASTOPEN 23 0 0x0401 0 0 15 # reduces roundtrips; for listener; Linux 3.7+ (c. 2012) / or is windows it 0x22? /proc/sys/net/ipv4/tcp_fastopen TODO(jart): MSG_FASTOPEN; XNU sources say 261 but not sure if that's true
syscon tcp TCP_FASTOPEN_CONNECT 30 0 0 0 0 0 # reduces roundtrips; for listener; Linux 3.7+ (c. 2012) / or is windows it 0x22? /proc/sys/net/ipv4/tcp_fastopen TODO(jart): MSG_FASTOPEN; XNU sources say 261 but not sure if that's true
syscon tcp TCP_KEEPIDLE 4 0 0x100 0 3 0 # keepalives
syscon tcp TCP_KEEPINTVL 5 0x101 0x200 0 5 0 # keepalives
syscon tcp TCP_KEEPCNT 6 0x102 0x400 0 6 0 # keepalives
syscon tcp TCP_KEEPIDLE 4 0 0x100 0 3 0 # start keepalives after this period
syscon tcp TCP_KEEPINTVL 5 0x101 0x200 0 5 0 # interval between keepalives
syscon tcp TCP_KEEPCNT 6 0x102 0x400 0 6 0 # number of keepalives before death
syscon tcp TCP_SYNCNT 7 0 0 0 0 0 # how hard to syn packet the enemy
syscon tcp TCP_ULP 31 0 0 0 0 0 # setsockopt(sock, IPPROTO_TCP, TCP_ULP, "tls", 4)
syscon tcp TCP_COOKIE_TRANSACTIONS 15 0 0 0 0 0 # defense against the syn packets
@ -778,7 +778,7 @@ syscon tcp TCP_MD5SIG 14 0 0x10 4 16 0 # what is it (rfc2385)
syscon tcp TCP_MD5SIG_MAXKEYLEN 80 0 0 0 0 0 # what is it
syscon tcp TCP_TIMESTAMP 24 0 0 0 0 0 # what is it
syscon tcp TCP_USER_TIMEOUT 18 0 0 0 0 0 # what is it
syscon tcp TCP_QUICKACK 12 0 0 0 0 0 # what is it
syscon tcp TCP_QUICKACK 12 0 0 0 0 0 # disables optimization that lets kernel merge response data into ack packets
syscon tcp TCP_SAVE_SYN 27 0 0 0 0 0 # record syn packets
syscon tcp TCP_SAVED_SYN 28 0 0 0 0 0 # get recorded syn packets
syscon tcp TCP_THIN_DUPACK 17 0 0 0 0 0 # what is it

View file

@ -1,2 +1,2 @@
.include "o/libc/sysv/consts/syscon.internal.inc"
.syscon errno,ECANCELED,125,89,85,88,87,0
.syscon errno,ECANCELED,125,89,85,88,87,1223

View file

@ -1,2 +1,2 @@
.include "o/libc/sysv/consts/syscon.internal.inc"
.syscon errno,EILSEQ,84,92,86,84,85,0
.syscon errno,EILSEQ,84,92,86,84,85,582

View file

@ -1,2 +1,2 @@
.include "o/libc/sysv/consts/syscon.internal.inc"
.syscon errno,ENOMSG,42,91,83,90,83,0
.syscon errno,ENOMSG,42,91,83,90,83,4306

View file

@ -1,2 +1,2 @@
.include "o/libc/sysv/consts/syscon.internal.inc"
.syscon errno,EOVERFLOW,75,84,84,87,84,0
.syscon errno,EOVERFLOW,75,84,84,87,84,534

View file

@ -1,2 +1,2 @@
.include "o/libc/sysv/consts/syscon.internal.inc"
.syscon errno,EOWNERDEAD,130,105,96,94,97,0
.syscon errno,EOWNERDEAD,130,105,96,94,97,105

View file

@ -1,2 +1,2 @@
.include "o/libc/sysv/consts/syscon.internal.inc"
.syscon errno,ETIME,62,101,60,60,92,0
.syscon errno,ETIME,62,101,60,60,92,1460

View file

@ -1,2 +1,2 @@
.include "o/libc/sysv/consts/syscon.internal.inc"
.syscon fcntl,F_ULOCK,0,0,0,0,0,0
.syscon fcntl2,F_BARRIERFSYNC,-1,85,-1,-1,-1,-1

View file

@ -1,2 +1,2 @@
.include "o/libc/sysv/consts/syscon.internal.inc"
.syscon fcntl2,F_FULLFSYNC,0,51,0,0,0,0
.syscon fcntl2,F_FULLFSYNC,-1,51,-1,-1,-1,-1

View file

@ -1,2 +1,2 @@
.include "o/libc/sysv/consts/syscon.internal.inc"
.syscon fcntl,F_GETLEASE,0x0401,0,0,0,0,0
.syscon fcntl,F_GETLEASE,0x0401,-1,-1,-1,-1,-1

View file

@ -1,2 +1,2 @@
.include "o/libc/sysv/consts/syscon.internal.inc"
.syscon fcntl,F_LOCK,1,1,1,1,1,0
.syscon fcntl3,F_GETNOSIGPIPE,-1,74,-1,-1,13,-1

View file

@ -1,2 +1,2 @@
.include "o/libc/sysv/consts/syscon.internal.inc"
.syscon fcntl2,F_GETOWN,9,5,5,5,5,0
.syscon fcntl2,F_GETOWN,9,5,5,5,5,-1

View file

@ -1,2 +1,2 @@
.include "o/libc/sysv/consts/syscon.internal.inc"
.syscon fcntl,F_GETOWN_EX,0x10,0,0,0,0,0
.syscon fcntl,F_GETOWN_EX,0x10,-1,-1,-1,-1,-1

View file

@ -1,2 +1,2 @@
.include "o/libc/sysv/consts/syscon.internal.inc"
.syscon fcntl,F_TLOCK,2,2,2,2,2,0
.syscon fcntl3,F_GETPATH,-1,50,-1,-1,15,-1

View file

@ -1,2 +1,2 @@
.include "o/libc/sysv/consts/syscon.internal.inc"
.syscon fcntl,F_GETPIPE_SZ,0x0408,0,0,0,0,0
.syscon fcntl,F_GETPIPE_SZ,0x0408,-1,-1,-1,-1,-1

View file

@ -1,2 +1,2 @@
.include "o/libc/sysv/consts/syscon.internal.inc"
.syscon fcntl,F_GETSIG,11,0,0,0,0,0
.syscon fcntl,F_GETSIG,11,-1,-1,-1,-1,-1

View file

@ -1,2 +1,2 @@
.include "o/libc/sysv/consts/syscon.internal.inc"
.syscon fcntl,F_MAXFD,0,0,0,0,11,0
.syscon fcntl,F_MAXFD,-1,-1,-1,-1,11,-1

View file

@ -1,2 +1,2 @@
.include "o/libc/sysv/consts/syscon.internal.inc"
.syscon fcntl2,F_NOCACHE,0,48,0,0,0,0
.syscon fcntl2,F_NOCACHE,-1,48,-1,-1,-1,-1

View file

@ -1,2 +1,2 @@
.include "o/libc/sysv/consts/syscon.internal.inc"
.syscon fcntl,F_NOTIFY,0x0402,0,0,0,0,0
.syscon fcntl,F_NOTIFY,0x0402,-1,-1,-1,-1,-1

View file

@ -1,2 +1,2 @@
.include "o/libc/sysv/consts/syscon.internal.inc"
.syscon fcntl,F_OFD_GETLK,36,0,0,0,0,0
.syscon fcntl,F_OFD_GETLK,36,92,-1,-1,-1,5

View file

@ -1,2 +1,2 @@
.include "o/libc/sysv/consts/syscon.internal.inc"
.syscon fcntl,F_OFD_SETLK,37,0,0,0,0,0
.syscon fcntl,F_OFD_SETLK,37,90,-1,-1,-1,6

View file

@ -1,2 +1,2 @@
.include "o/libc/sysv/consts/syscon.internal.inc"
.syscon fcntl,F_OFD_SETLKW,38,0,0,0,0,0
.syscon fcntl,F_OFD_SETLKW,38,91,-1,-1,-1,7

View file

@ -1,2 +1,2 @@
.include "o/libc/sysv/consts/syscon.internal.inc"
.syscon fcntl,F_SETLEASE,0x0400,0,0,0,0,0
.syscon fcntl,F_SETLEASE,0x0400,-1,-1,-1,-1,-1

View file

@ -1,2 +1,2 @@
.include "o/libc/sysv/consts/syscon.internal.inc"
.syscon fcntl,F_TEST,3,3,3,3,3,0
.syscon fcntl3,F_SETNOSIGPIPE,-1,73,-1,-1,14,-1

View file

@ -1,2 +1,2 @@
.include "o/libc/sysv/consts/syscon.internal.inc"
.syscon fcntl2,F_SETOWN,8,6,6,6,6,0
.syscon fcntl2,F_SETOWN,8,6,6,6,6,-1

View file

@ -1,2 +1,2 @@
.include "o/libc/sysv/consts/syscon.internal.inc"
.syscon fcntl,F_SETOWN_EX,15,0,0,0,0,0
.syscon fcntl,F_SETOWN_EX,15,-1,-1,-1,-1,-1

View file

@ -1,2 +1,2 @@
.include "o/libc/sysv/consts/syscon.internal.inc"
.syscon fcntl,F_SETPIPE_SZ,0x0407,0,0,0,0,0
.syscon fcntl,F_SETPIPE_SZ,0x0407,-1,-1,-1,-1,-1

View file

@ -1,2 +1,2 @@
.include "o/libc/sysv/consts/syscon.internal.inc"
.syscon fcntl,F_SETSIG,10,0,0,0,0,0
.syscon fcntl,F_SETSIG,10,-1,-1,-1,-1,-1

12
libc/sysv/consts/dn.h Normal file
View file

@ -0,0 +1,12 @@
#ifndef COSMOPOLITAN_LIBC_SYSV_CONSTS_DN_H_
#define COSMOPOLITAN_LIBC_SYSV_CONSTS_DN_H_
#define DN_ACCESS 0x00000001 /* file accessed */
#define DN_MODIFY 0x00000002 /* file modified */
#define DN_CREATE 0x00000004 /* file created */
#define DN_DELETE 0x00000008 /* file removed */
#define DN_RENAME 0x00000010 /* file renamed */
#define DN_ATTRIB 0x00000020 /* file changed attibutes */
#define DN_MULTISHOT 0x80000000 /* don't remove notifier */
#endif /* COSMOPOLITAN_LIBC_SYSV_CONSTS_DN_H_ */

View file

@ -4,6 +4,7 @@
#if !(__ASSEMBLER__ + __LINKER__ + 0)
COSMOPOLITAN_C_START_
extern const int F_BARRIERFSYNC;
extern const int F_DUPFD;
extern const int F_DUPFD_CLOEXEC;
extern const int F_FULLFSYNC;
@ -12,11 +13,14 @@ extern const int F_GETFL;
extern const int F_GETLEASE;
extern const int F_GETLK64;
extern const int F_GETLK;
extern const int F_GETNOSIGPIPE;
extern const int F_GETOWN;
extern const int F_GETOWN_EX;
extern const int F_GETPATH;
extern const int F_GETPIPE_SZ;
extern const int F_GETSIG;
extern const int F_LOCK;
extern const int F_MAXFD;
extern const int F_NOCACHE;
extern const int F_NOTIFY;
extern const int F_OFD_GETLK;
@ -30,13 +34,11 @@ extern const int F_SETLK64;
extern const int F_SETLK;
extern const int F_SETLKW64;
extern const int F_SETLKW;
extern const int F_SETNOSIGPIPE;
extern const int F_SETOWN;
extern const int F_SETOWN_EX;
extern const int F_SETPIPE_SZ;
extern const int F_SETSIG;
extern const int F_TEST;
extern const int F_TLOCK;
extern const int F_ULOCK;
extern const int F_UNLCK;
extern const int F_WRLCK;
@ -50,20 +52,17 @@ COSMOPOLITAN_C_END_
#define F_SETFL LITERALLY(4)
#define F_DUPFD_CLOEXEC SYMBOLIC(F_DUPFD_CLOEXEC)
#define F_FULLFSYNC SYMBOLIC(F_FULLFSYNC)
#define F_GETLEASE SYMBOLIC(F_GETLEASE)
#define F_GETLK SYMBOLIC(F_GETLK)
#define F_GETLK64 SYMBOLIC(F_GETLK64)
#define F_GETOWN SYMBOLIC(F_GETOWN)
#define F_GETOWN_EX SYMBOLIC(F_GETOWN_EX)
#define F_GETPATH SYMBOLIC(F_GETPATH)
#define F_GETPIPE_SZ SYMBOLIC(F_GETPIPE_SZ)
#define F_GETSIG SYMBOLIC(F_GETSIG)
#define F_LOCK SYMBOLIC(F_LOCK)
#define F_MAXFD SYMBOLIC(F_MAXFD)
#define F_NOCACHE SYMBOLIC(F_NOCACHE)
#define F_NOTIFY SYMBOLIC(F_NOTIFY)
#define F_OFD_GETLK SYMBOLIC(F_OFD_GETLK)
#define F_OFD_SETLK SYMBOLIC(F_OFD_SETLK)
#define F_OFD_SETLKW SYMBOLIC(F_OFD_SETLKW)
#define F_RDLCK SYMBOLIC(F_RDLCK)
#define F_SETLEASE SYMBOLIC(F_SETLEASE)
#define F_SETLK SYMBOLIC(F_SETLK)
@ -74,10 +73,16 @@ COSMOPOLITAN_C_END_
#define F_SETOWN_EX SYMBOLIC(F_SETOWN_EX)
#define F_SETPIPE_SZ SYMBOLIC(F_SETPIPE_SZ)
#define F_SETSIG SYMBOLIC(F_SETSIG)
#define F_TEST SYMBOLIC(F_TEST)
#define F_TLOCK SYMBOLIC(F_TLOCK)
#define F_ULOCK SYMBOLIC(F_ULOCK)
#define F_UNLCK SYMBOLIC(F_UNLCK)
#define F_WRLCK SYMBOLIC(F_WRLCK)
/* avoid leading #ifdef astray */
/* #define F_FULLFSYNC SYMBOLIC(F_FULLFSYNC) */
/* #define F_BARRIERFSYNC SYMBOLIC(F_BARRIERFSYNC) */
/* #define F_OFD_GETLK SYMBOLIC(F_OFD_GETLK) */
/* #define F_OFD_SETLK SYMBOLIC(F_OFD_SETLK) */
/* #define F_OFD_SETLKW SYMBOLIC(F_OFD_SETLKW) */
/* #define F_SETNOSIGPIPE SYMBOLIC(F_SETNOSIGPIPE) */
/* #define F_GETNOSIGPIPE SYMBOLIC(F_GETNOSIGPIPE) */
#endif /* COSMOPOLITAN_LIBC_SYSV_CONSTS_F_H_ */

View file

@ -19,6 +19,7 @@
#include "libc/dce.h"
#include "libc/intrin/asan.internal.h"
#include "libc/intrin/asancodes.h"
#include "libc/intrin/atomic.h"
#include "libc/macros.internal.h"
#include "libc/mem/mem.h"
#include "libc/runtime/internal.h"
@ -57,7 +58,8 @@ char *_mktls(struct CosmoTib **out_tib) {
tib = (struct CosmoTib *)(tls + I(_tls_size));
tib->tib_self = tib;
tib->tib_self2 = tib;
tib->tib_tid = -1;
tib->tib_sigmask = __get_tls()->tib_sigmask;
atomic_store_explicit(&tib->tib_tid, -1, memory_order_relaxed);
if (out_tib) {
*out_tib = tib;

View file

@ -26,7 +26,7 @@ struct CosmoTib {
int32_t tib_errno; /* 0x3c */
void *tib_nsync;
uint64_t tib_flags;
void *tib_reserved2;
uint64_t tib_sigmask;
void *tib_reserved3;
void *tib_reserved4;
void *tib_reserved5;

View file

@ -4,8 +4,8 @@
#include "libc/thread/tls.h"
#if !(__ASSEMBLER__ + __LINKER__ + 0)
COSMOPOLITAN_C_START_
#if defined(__GNUC__) && defined(__x86_64__) && !defined(__STRICT_ANSI__)
/**
* Returns location of thread information block.
*
@ -24,8 +24,19 @@ static noasan inline struct CosmoTib *__get_tls_privileged(void) {
}
return (struct CosmoTib *)tib;
}
#endif /* GNU x86-64 */
static noasan inline struct CosmoTib *__get_tls_win32(void) {
char *tib, *lin = (char *)0x30;
asm("mov\t%%gs:(%1),%0" : "=a"(tib) : "r"(lin) : "memory");
tib = *(char **)(tib + 0x1480 + __tls_index * 8);
return (struct CosmoTib *)tib;
}
static noasan inline void __set_tls_win32(void *tls) {
asm("mov\t%1,%%gs:%0" : "=m"(*((long *)0x1480 + __tls_index)) : "r"(tls));
}
#endif /* GNU x86-64 */
COSMOPOLITAN_C_END_
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
#endif /* COSMOPOLITAN_LIBC_THREAD_TLS2_H_ */

View file

@ -19,62 +19,64 @@
#include "libc/intrin/atomic.h"
#include "net/http/tokenbucket.h"
/**
* Returns byte comparison mask w/ 0xff if equal otherwise 0x00.
*/
static inline uint64_t CompareEq(uint64_t x, uint64_t y) {
uint64_t mask, zoro = x ^ y;
mask = ((((zoro >> 1) | 0x8080808080808080) - zoro) & 0x8080808080808080);
return (mask << 1) - (mask >> 7);
}
/**
* Atomically increments all signed bytes in array without overflow.
*
* This function should be called periodically so buckets have tokens.
* While many threads can consumes tokens, only a single thread can use
* the replenish operation.
*
* This function implements a SWAR algorithm offering the best possible
* performance under the constraint that operations happen atomically.
* This function should take 2ms to add a token to 2**22 buckets which
* need a 4mb array that has one bucket for every 1024 IPv4 addresses.
* However that doesn't matter since no locks are held during that 2ms
* therefore replenishing doesn't block threads that acquire tokens.
* Under the token bucket model, operations are denied by default unless
* tokens exist to allow them. This function must be called periodically
* from a single background thread to replenish the buckets with tokens.
* For example, this function may be called once per second which allows
* one operation per second on average with bursts up to 127 per second.
* This policy needn't be applied uniformly. For example, you might find
* out that a large corporation funnels all their traffic through one ip
* address, so you could replenish their tokens multiple times a second.
*
* @param w is word array that aliases byte token array
* @param n is number of 64-bit words in `w` array
*/
void ReplenishTokens(atomic_uint_fast64_t *w, size_t n) {
for (size_t i = 0; i < n; ++i) {
uint64_t x = atomic_load_explicit(w + i, memory_order_relaxed);
atomic_fetch_add_explicit(
w + i, 0x0101010101010101 & ~CompareEq(x, 0x7f7f7f7f7f7f7f7f),
memory_order_acq_rel);
uint64_t a = atomic_load_explicit(w + i, memory_order_relaxed);
if (a == 0x7f7f7f7f7f7f7f7f) continue;
uint64_t b = 0x8080808080808080;
uint64_t c = a ^ 0x7f7f7f7f7f7f7f7f;
uint64_t d = ((c >> 1 | b) - c & b ^ b) >> 7;
atomic_fetch_add_explicit(w + i, d, memory_order_relaxed);
}
}
/**
* Atomically decrements signed byte index if it's positive.
*
* This function should be called to take a token from the right bucket
* whenever a client wants to use some type of resource. This routine
* discriminates based on `c` which is the netmask bit count. There must
* exist `1 << c` signed bytes (or buckets) in the `b` array.
* Multiple threads may call this method to determine if sufficient
* tokens exist to perform an operation. Return values greater than zero
* mean a token was atomically acquired. Values less than or equal zero
* means the bucket is empty. There must exist `1 << c` signed bytes (or
* buckets) in the `b` array.
*
* Tokens are considered available if the bucket corresponding `x` has a
* positive number. This function returns true of a token was atomically
* acquired using a lockeless spinless algorithm. Buckets are allowed to
* drift into a slightly negative state, but overflow is impractical.
* Since this design uses signed bytes, the returned number may be used
* to control how much burstiness is allowed. For example:
*
* int t = AcquireToken(tok.b, ip, 22);
* if (t < 64) {
* if (t > 8) write(client, "HTTP/1.1 429 \r\n\r\n", 17);
* close(client);
* return;
* }
*
* May be used to send a rejection to clients who've exceeded their
* tokens whereas clients who've grossly exceeded their tokens will
* simply be dropped.
*
* @param w is array of token buckets
* @param n is ipv4 address
* @param c is cidr
*/
bool AcquireToken(atomic_schar *b, uint32_t x, int c) {
int AcquireToken(atomic_schar *b, uint32_t x, int c) {
uint32_t i = x >> (32 - c);
return atomic_load_explicit(b + i, memory_order_relaxed) > 0 &&
atomic_fetch_add_explicit(b + i, -1, memory_order_acq_rel) > 0;
int t = atomic_load_explicit(b + i, memory_order_relaxed);
if (t <= 0) return t;
return atomic_fetch_add_explicit(b + i, -1, memory_order_relaxed);
}
/**

View file

@ -5,7 +5,7 @@
COSMOPOLITAN_C_START_
void ReplenishTokens(atomic_uint_fast64_t *, size_t);
bool AcquireToken(atomic_schar *, uint32_t, int);
int AcquireToken(atomic_schar *, uint32_t, int);
int CountTokens(atomic_schar *, uint32_t, int);
COSMOPOLITAN_C_END_

View file

@ -729,7 +729,9 @@ void ServeStatusz(int client, char *outbuf) {
void *ListenWorker(void *arg) {
int server;
int no = 0;
int yes = 1;
int fastopen = 5;
struct Client client;
struct timeval timeo = {g_keepalive / 1000, g_keepalive % 1000};
struct sockaddr_in addr = {.sin_family = AF_INET, .sin_port = htons(g_port)};
@ -740,10 +742,11 @@ void *ListenWorker(void *arg) {
setsockopt(server, SOL_SOCKET, SO_RCVTIMEO, &timeo, sizeof(timeo));
setsockopt(server, SOL_SOCKET, SO_SNDTIMEO, &timeo, sizeof(timeo));
setsockopt(server, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(yes));
setsockopt(server, SOL_TCP, TCP_FASTOPEN, &yes, sizeof(yes));
setsockopt(server, SOL_TCP, TCP_QUICKACK, &yes, sizeof(yes));
setsockopt(server, SOL_TCP, TCP_FASTOPEN, &fastopen, sizeof(fastopen));
setsockopt(server, SOL_TCP, TCP_QUICKACK, &no, sizeof(no));
setsockopt(server, SOL_TCP, TCP_CORK, &no, sizeof(no));
setsockopt(server, SOL_TCP, TCP_NODELAY, &yes, sizeof(yes));
CHECK_NE(-1, bind(server, (struct sockaddr *)&addr, sizeof(addr)));
bind(server, (struct sockaddr *)&addr, sizeof(addr));
CHECK_NE(-1, listen(server, 1));
while (!nsync_note_is_notified(g_shutdown[0])) {
client.size = sizeof(client.addr);
@ -791,7 +794,7 @@ void *HttpWorker(void *arg) {
struct Url url;
ssize_t got, sent;
uint32_t ip, clientip;
int inmsglen, outmsglen;
int tok, inmsglen, outmsglen;
char ipbuf[32], *p, *q, cashbuf[64];
clientip = ntohl(client.addr.sin_addr.s_addr);
@ -861,6 +864,19 @@ void *HttpWorker(void *arg) {
ksnprintf(ipbuf, sizeof(ipbuf), "%hhu.%hhu.%hhu.%hhu", ip >> 24, ip >> 16,
ip >> 8, ip);
if ((tok = AcquireToken(g_tok.b, ip, TB_CIDR)) < 64) {
if (tok > 8) {
LOG("%s rate limiting client\n", ipbuf, msg->version);
Write(client.sock, "HTTP/1.1 429 Too Many Requests\r\n"
"Content-Type: text/plain\r\n"
"Connection: close\r\n"
"\r\n"
"429 Too Many Requests\n");
}
++g_ratelimits;
break;
}
// we don't support http/1.0 and http/0.9 right now
if (msg->version != 11) {
LOG("%s used unsupported http/%d version\n", ipbuf, msg->version);
@ -873,19 +889,8 @@ void *HttpWorker(void *arg) {
break;
}
if (!AcquireToken(g_tok.b, ip, TB_CIDR)) {
LOG("%s rate limiting client\n", ipbuf, msg->version);
Write(client.sock, "HTTP/1.1 429 Too Many Requests\r\n"
"Content-Type: text/plain\r\n"
"Connection: close\r\n"
"\r\n"
"429 Too Many Requests\n");
++g_ratelimits;
break;
}
// access log
LOG("%16s %.*s %.*s %.*s %.*s %#.*s\n", ipbuf,
LOG("%6P %16s %.*s %.*s %.*s %.*s %#.*s\n", ipbuf,
msg->xmethod.b - msg->xmethod.a, inbuf + msg->xmethod.a,
msg->uri.b - msg->uri.a, inbuf + msg->uri.a,
HeaderLength(kHttpCfIpcountry), HeaderData(kHttpCfIpcountry),
@ -1765,7 +1770,12 @@ OnError:
}
int main(int argc, char *argv[]) {
// ShowCrashReports();
ShowCrashReports();
if (IsLinux()) {
Write(2, "Enabling TCP_FASTOPEN for server sockets...\n");
system("sudo sh -c 'echo 2 >/proc/sys/net/ipv4/tcp_fastopen'");
}
// we don't have proper futexes on these platforms
// we'll be somewhat less aggressive about workers

View file

@ -250,7 +250,7 @@ TEST(pledge, stdio_fcntl_allowsSomeFirstArgs) {
ASSERT_SYS(0, 3, fcntl(2, F_DUPFD_CLOEXEC, 3));
ASSERT_SYS(0, 0, ioctl(0, FIOCLEX, 0));
ASSERT_SYS(EPERM, 0, isatty(0));
ASSERT_SYS(EPERM, -1, fcntl(0, -1));
ASSERT_SYS(EPERM, -1, fcntl(0, 777));
ASSERT_SYS(EPERM, -1, fcntl(0, F_GETLK, &lk));
ASSERT_SYS(EPERM, -1, fcntl(0, F_NOTIFY));
ASSERT_SYS(EPERM, -1, socket(AF_INET, SOCK_STREAM, IPPROTO_TCP));

View file

@ -0,0 +1,32 @@
/*-*- 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/struct/sigaction.h"
#include "libc/intrin/intrin.h"
#include "libc/intrin/kprintf.h"
#include "libc/sysv/consts/sig.h"
#include "libc/testlib/testlib.h"
void OnSig(int sig) {
kprintf("got sig\n");
}
TEST(gettid, test) {
signal(SIGTRAP, OnSig);
DebugBreak();
}

View file

@ -0,0 +1,54 @@
/*-*- 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/struct/sigaction.h"
#include "libc/errno.h"
#include "libc/sysv/consts/sig.h"
#include "libc/testlib/testlib.h"
#include "libc/thread/thread.h"
int fds[2];
_Thread_local sig_atomic_t gotsig;
void OnSig(int sig) {
gotsig = 1;
}
void *ReadWorker(void *arg) {
char buf[8];
ASSERT_SYS(EINTR, -1, read(fds[0], buf, 8));
ASSERT_TRUE(gotsig);
return 0;
}
TEST(pthread_kill, canCancelReadOperation) {
pthread_t t;
struct sigaction oldsa;
struct sigaction sa = {.sa_handler = OnSig};
ASSERT_SYS(0, 0, sigaction(SIGUSR1, &sa, &oldsa));
ASSERT_SYS(0, 0, pipe(fds));
ASSERT_EQ(0, pthread_create(&t, 0, ReadWorker, 0));
ASSERT_SYS(0, 0, usleep(100000)); // potentially flaky
ASSERT_EQ(0, pthread_kill(t, SIGUSR1));
ASSERT_EQ(0, pthread_join(t, 0));
ASSERT_FALSE(gotsig);
ASSERT_SYS(0, 0, close(fds[0]));
ASSERT_SYS(0, 0, close(fds[1]));
ASSERT_SYS(0, 0, sigaction(SIGUSR1, &oldsa, 0));
}

View file

@ -21,7 +21,6 @@
#include "libc/log/check.h"
#include "libc/mem/gc.internal.h"
#include "libc/mem/mem.h"
#include "libc/stdio/stdio.h"
#include "libc/str/str.h"
#include "libc/testlib/ezbench.h"
#include "libc/testlib/testlib.h"
@ -147,6 +146,14 @@ TEST(ParseHttpMessage, testHttp09) {
EXPECT_EQ(9, req->version);
}
TEST(ParseHttpMessage, testTinyResponse) {
static const char m[] = "HTTP/1.1 429 \r\n\r\n";
InitHttpMessage(req, kHttpResponse);
EXPECT_EQ(strlen(m), ParseHttpMessage(req, m, strlen(m)));
EXPECT_EQ(429, req->status);
EXPECT_STREQ("", gc(slice(m, req->message)));
}
TEST(ParseHttpMessage, testLeadingLineFeeds_areIgnored) {
static const char m[] = "\
\r\n\

View file

@ -24,6 +24,7 @@
#include "libc/limits.h"
#include "libc/mem/mem.h"
#include "libc/stdio/stdio.h"
#include "libc/str/str.h"
#include "libc/testlib/ezbench.h"
#include "libc/testlib/testlib.h"
#include "net/http/http.h"
@ -47,27 +48,52 @@ void TearDown(void) {
}
TEST(tokenbucket, test) {
ASSERT_FALSE(AcquireToken(tok.b, 0x7f000001, TB_CIDR));
ASSERT_FALSE(AcquireToken(tok.b, 0x7f000002, TB_CIDR));
ASSERT_EQ(0, AcquireToken(tok.b, 0x7f000001, TB_CIDR));
ASSERT_EQ(0, AcquireToken(tok.b, 0x7f000002, TB_CIDR));
ReplenishTokens(tok.w, TB_WORDS);
ReplenishTokens(tok.w, TB_WORDS);
ASSERT_TRUE(AcquireToken(tok.b, 0x7f000001, TB_CIDR));
ASSERT_TRUE(AcquireToken(tok.b, 0x7f000002, TB_CIDR));
ASSERT_FALSE(AcquireToken(tok.b, 0x7f000001, TB_CIDR));
ASSERT_TRUE(AcquireToken(tok.b, 0x08080808, TB_CIDR));
ASSERT_EQ(2, AcquireToken(tok.b, 0x7f000001, TB_CIDR));
ASSERT_EQ(1, AcquireToken(tok.b, 0x7f000002, TB_CIDR));
ASSERT_EQ(0, AcquireToken(tok.b, 0x7f000001, TB_CIDR));
ASSERT_EQ(0, AcquireToken(tok.b, 0x7f000001, TB_CIDR));
ASSERT_EQ(2, AcquireToken(tok.b, 0x08080808, TB_CIDR));
ReplenishTokens(tok.w, TB_WORDS);
ASSERT_EQ(1, AcquireToken(tok.b, 0x7f000001, TB_CIDR));
ReplenishTokens(tok.w, TB_WORDS);
ASSERT_TRUE(AcquireToken(tok.b, 0x7f000001, TB_CIDR));
ASSERT_TRUE(AcquireToken(tok.b, 0x7f000001, TB_CIDR));
ASSERT_FALSE(AcquireToken(tok.b, 0x7f000002, TB_CIDR));
ASSERT_TRUE(AcquireToken(tok.b, 0x08080808, TB_CIDR));
ASSERT_EQ(1, AcquireToken(tok.b, 0x7f000001, TB_CIDR));
ASSERT_EQ(0, AcquireToken(tok.b, 0x7f000002, TB_CIDR));
ASSERT_EQ(3, AcquireToken(tok.b, 0x08080808, TB_CIDR));
for (int i = 0; i < 130; ++i) ReplenishTokens(tok.w, TB_WORDS);
ASSERT_EQ(127, AcquireToken(tok.b, 0x08080808, TB_CIDR));
}
void NaiveReplenishTokens(atomic_schar *b, size_t n) {
for (size_t i = 0; i < n; ++i) {
int x = atomic_load_explicit(b + i, memory_order_relaxed);
if (x == 127) continue;
atomic_fetch_add_explicit(b + i, 1, memory_order_acq_rel);
}
}
BENCH(tokenbucket, bench) {
struct timespec t1, t2;
clock_gettime(0, &t1);
NaiveReplenishTokens(tok.b, TB_BYTES);
clock_gettime(0, &t2);
kprintf("NaiveReplenishTokens took %'ld us\n",
_timespec_tomicros(_timespec_sub(t2, t1)));
clock_gettime(0, &t1);
ReplenishTokens(tok.w, TB_WORDS);
clock_gettime(0, &t2);
kprintf("token bucket replenish took %'ld us\n",
kprintf("ReplenishTokens empty took %'ld us\n",
_timespec_tomicros(_timespec_sub(t2, t1)));
memset(tok.b, 127, TB_BYTES);
clock_gettime(0, &t1);
ReplenishTokens(tok.w, TB_WORDS);
clock_gettime(0, &t2);
kprintf("ReplenishTokens full took %'ld us\n",
_timespec_tomicros(_timespec_sub(t2, t1)));
}

View file

@ -30,6 +30,8 @@
#include "libc/calls/weirdtypes.h"
#include "libc/errno.h"
#include "libc/sysv/consts/f.h"
#include "libc/sysv/errfuns.h"
#include "third_party/musl/lockf.h"
asm(".ident\t\"\\n\\n\
Musl libc (MIT License)\\n\
@ -44,25 +46,20 @@ int lockf(int fd, int op, off_t size)
.l_whence = SEEK_CUR,
.l_len = size,
};
if (op == F_TEST){
switch (op) {
case F_TEST:
l.l_type = F_RDLCK;
if (fcntl(fd, F_GETLK, &l) < 0)
return -1;
if (l.l_type == F_UNLCK || l.l_pid == getpid())
return 0;
errno = EACCES;
return -1;
}
if (op == F_ULOCK) {
return eacces();
case F_ULOCK:
l.l_type = F_UNLCK;
case F_TLOCK:
return fcntl(fd, F_SETLK, &l);
}
if (op == F_TLOCK) {
return fcntl(fd, F_SETLK, &l);
}
if (op == F_LOCK) {
case F_LOCK:
return fcntl(fd, F_SETLKW, &l);
}
errno = EINVAL;
return -1;
return einval();
}

16
third_party/musl/lockf.h vendored Normal file
View file

@ -0,0 +1,16 @@
#ifndef COSMOPOLITAN_THIRD_PARTY_MUSL_LOCKF_H_
#define COSMOPOLITAN_THIRD_PARTY_MUSL_LOCKF_H_
#define F_ULOCK 0
#define F_LOCK 1
#define F_TLOCK 2
#define F_TEST 3
#if !(__ASSEMBLER__ + __LINKER__ + 0)
COSMOPOLITAN_C_START_
int lockf(int, int, int64_t);
COSMOPOLITAN_C_END_
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
#endif /* COSMOPOLITAN_THIRD_PARTY_MUSL_LOCKF_H_ */

View file

@ -18,6 +18,7 @@
*/
#include "libc/atomic.h"
#include "libc/calls/calls.h"
#include "libc/calls/internal.h"
#include "libc/calls/sig.internal.h"
#include "libc/calls/state.internal.h"
#include "libc/calls/struct/timespec.h"
@ -166,6 +167,9 @@ int nsync_futex_wait_ (int *p, int expect, char pshare, struct timespec *timeout
if (pshare) {
goto Polyfill;
}
if (_check_interrupts (false, 0)) {
rc = -EINTR;
} else {
if (timeout) {
ms = _timespec_tomillis (*timeout);
} else {
@ -176,6 +180,7 @@ int nsync_futex_wait_ (int *p, int expect, char pshare, struct timespec *timeout
} else {
rc = -GetLastError ();
}
}
} else if (IsFreebsd ()) {
rc = sys_umtx_timedwait_uint (
p, expect, pshare, timeout);
@ -193,7 +198,7 @@ int nsync_futex_wait_ (int *p, int expect, char pshare, struct timespec *timeout
__get_tls()->tib_flags &= ~TIB_FLAG_TIME_CRITICAL;
}
STRACE ("futex(%t, %s, %d, %s) → %s",
STRACE ("futex(%t, %s, %#x, %s) → %s",
p, DescribeFutexOp (op), expect,
DescribeTimespec (0, timeout),
DescribeErrnoResult (rc));

View file

@ -16,6 +16,7 @@
limitations under the License.
*/
#include "libc/errno.h"
#include "libc/runtime/runtime.h"
#include "third_party/nsync/atomic.h"
#include "third_party/nsync/atomic.internal.h"
#include "third_party/nsync/common.internal.h"
@ -81,5 +82,3 @@ int nsync_sem_wait_with_cancel_ (waiter *w, nsync_time abs_deadline,
}
return (sem_outcome);
}

View file

@ -1,33 +0,0 @@
/*-*- mode:c;indent-tabs-mode:t;c-basic-offset:8;tab-width:8;coding:utf-8 -*-│
vi: set et ft=c ts=8 tw=8 fenc=utf-8 :vi
Copyright 2016 Google Inc.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0 │
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
#include "third_party/nsync/common.internal.h"
#include "third_party/nsync/mu_semaphore.h"
asm(".ident\t\"\\n\\n\
*NSYNC (Apache 2.0)\\n\
Copyright 2016 Google, Inc.\\n\
https://github.com/google/nsync\"");
// clang-format off
/* Wait until one of:
w->sem is non-zero----decrement it and return 0.
abs_deadline expires---return ETIMEDOUT.
Ignores cancel_note. */
int nsync_sem_wait_with_cancel_ (waiter *w, nsync_time abs_deadline, nsync_note cancel_note) {
return (nsync_mu_semaphore_p_with_deadline (&w->sem, abs_deadline));
}

View file

@ -62,6 +62,7 @@
#include "libc/time/struct/utimbuf.h"
#include "libc/time/time.h"
#include "libc/x/x.h"
#include "third_party/musl/lockf.h"
#include "third_party/musl/passwd.h"
#include "third_party/python/Include/abstract.h"
#include "third_party/python/Include/boolobject.h"
@ -11894,10 +11895,10 @@ all_ins(PyObject *m)
if (PyModule_AddIntMacro(m, CLD_CONTINUED)) return -1;
/* constants for lockf */
if (F_LOCK && PyModule_AddIntMacro(m, F_LOCK)) return -1;
if (F_TLOCK && PyModule_AddIntMacro(m, F_TLOCK)) return -1;
if (PyModule_AddIntMacro(m, F_LOCK)) return -1;
if (PyModule_AddIntMacro(m, F_TLOCK)) return -1;
if (PyModule_AddIntMacro(m, F_ULOCK)) return -1;
if (F_TEST && PyModule_AddIntMacro(m, F_TEST)) return -1;
if (PyModule_AddIntMacro(m, F_TEST)) return -1;
#ifdef HAVE_SPAWNV
if (PyModule_AddIntConstant(m, "P_WAIT", _P_WAIT)) return -1;

View file

@ -227,7 +227,7 @@
/* #undef HAVE_LINUX_CAN_RAW_FD_FRAMES */
/* Define to 1 if you have the 'lockf' function and the F_LOCK macro. */
/* #undef HAVE_LOCKF */
#define HAVE_LOCKF 1
/* #define HAVE_DEVICE_MACROS 1 */
#define HAVE_MAKEDEV 1

View file

@ -10,3 +10,7 @@ ORIGIN
LICENSE
Public Domain or MIT
LOCAL CHANGES
- Changed the fsync() code to be configured at runtime.

View file

@ -3105,10 +3105,6 @@ static int openDatabase(
char *zErrMsg = 0; /* Error message from sqlite3ParseUri() */
int i; /* Loop counter */
// TODO(jart): Fix SQLite.
extern bool __force_sqlite_to_work_until_we_can_fix_it;
__force_sqlite_to_work_until_we_can_fix_it = true;
#ifdef SQLITE_ENABLE_API_ARMOR
if( ppDb==0 ) return SQLITE_MISUSE_BKPT;
#endif

View file

@ -53,6 +53,8 @@
#include "third_party/sqlite3/sqlite3.h"
#include "third_party/sqlite3/mutex.internal.h"
#include "third_party/sqlite3/mutex.internal.h"
#include "libc/sysv/consts/f.h"
#include "libc/dce.h"
#include "third_party/sqlite3/sqliteInt.inc"
#if SQLITE_OS_UNIX /* This file is used on unix only */
@ -3612,8 +3614,9 @@ static int full_fsync(int fd, int fullSync, int dataOnly){
struct stat buf;
rc = osFstat(fd, &buf);
}
#elif HAVE_FULLFSYNC
if( fullSync ){
#elif HAVE_FULLFSYNC || defined(__COSMOPOLITAN__)
/* [jart] use runtime os detection */
if( fullSync && F_FULLFSYNC != -1 ){
rc = osFcntl(fd, F_FULLFSYNC, 0);
}else{
rc = 1;
@ -3626,7 +3629,13 @@ static int full_fsync(int fd, int fullSync, int dataOnly){
** It'd be better to detect fullfsync support once and avoid
** the fcntl call every time sync is called.
*/
if( rc ) rc = fsync(fd);
if( rc ) {
if( IsXnu() ){
rc = fsync(fd);
}else{
rc = fdatasync(fd);
}
}
#elif defined(__APPLE__)
/* fdatasync() on HFS+ doesn't yet flush the file size if it changed correctly

View file

@ -59,6 +59,7 @@
#include "libc/sysv/consts/rusage.h"
#include "libc/time/time.h"
#include "libc/runtime/runtime.h"
#include "libc/errno.h"
#if SQLITE_USER_AUTHENTICATION
#include "third_party/sqlite3/sqlite3userauth.inc"
#endif
@ -10573,6 +10574,7 @@ static void process_sqliterc(
p->in = inSaved;
p->lineno = savedLineno;
sqlite3_free(zBuf);
errno = 0; /* [jart] clear error */
}
/*