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 TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE. PERFORMANCE OF THIS SOFTWARE.
*/ */
#include "libc/assert.h"
#include "libc/calls/calls.h" #include "libc/calls/calls.h"
#include "libc/calls/sig.internal.h" #include "libc/calls/sig.internal.h"
#include "libc/calls/state.internal.h" #include "libc/calls/state.internal.h"
#include "libc/calls/struct/sigaction.h" #include "libc/calls/struct/sigaction.h"
#include "libc/calls/struct/siginfo.h" #include "libc/calls/struct/siginfo.h"
#include "libc/intrin/cmpxchg.h" #include "libc/calls/struct/sigset.h"
#include "libc/intrin/lockcmpxchg.h"
#include "libc/intrin/strace.internal.h" #include "libc/intrin/strace.internal.h"
#include "libc/log/libfatal.internal.h"
#include "libc/macros.internal.h" #include "libc/macros.internal.h"
#include "libc/runtime/internal.h" #include "libc/runtime/internal.h"
#include "libc/runtime/runtime.h" #include "libc/runtime/runtime.h"
#include "libc/str/str.h"
#include "libc/sysv/consts/sa.h" #include "libc/sysv/consts/sa.h"
#include "libc/sysv/consts/sig.h" #include "libc/sysv/consts/sig.h"
#include "libc/sysv/errfuns.h" #include "libc/sysv/errfuns.h"
#include "libc/thread/tls.h"
/**
* @fileoverview UNIX signals for the New Technology, Part 2.
* @threadsafe
*/
/** /**
* Allocates piece of memory for storing pending signal. * Allocates piece of memory for storing pending signal.
@ -61,16 +57,30 @@ static textwindows void __sig_free(struct Signal *mem) {
mem->used = false; 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. * Dequeues signal that isn't masked.
* @return signal or null if empty or none unmasked * @return signal or null if empty or none unmasked
*/ */
static textwindows struct Signal *__sig_remove(void) { static textwindows struct Signal *__sig_remove(void) {
int tid;
struct Signal *prev, *res; struct Signal *prev, *res;
if (__sig.queue) { if (__sig.queue) {
tid = gettid();
__sig_lock(); __sig_lock();
for (prev = 0, res = __sig.queue; res; prev = res, res = res->next) { 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) { if (res == __sig.queue) {
__sig.queue = res->next; __sig.queue = res->next;
} else if (prev) { } else if (prev) {
@ -78,8 +88,6 @@ static textwindows struct Signal *__sig_remove(void) {
} }
res->next = 0; res->next = 0;
break; break;
} else {
STRACE("%G is masked", res->sig);
} }
} }
__sig_unlock(); __sig_unlock();
@ -117,7 +125,7 @@ static bool __sig_deliver(bool restartable, int sig, int si_code,
// setup the somewhat expensive information args // setup the somewhat expensive information args
// only if they're requested by the user in sigaction() // only if they're requested by the user in sigaction()
if (flags & SA_SIGINFO) { if (flags & SA_SIGINFO) {
__repstosb(&info, 0, sizeof(info)); bzero(&info, sizeof(info));
info.si_signo = sig; info.si_signo = sig;
info.si_code = si_code; info.si_code = si_code;
infop = &info; 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 // since sigaction() is @asyncsignalsafe we only restore it if the
// user didn't change it during the signal handler. we also don't // 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. // 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) { 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. * 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) { if (sig == SIGCHLD || sig == SIGURG || sig == SIGWINCH) {
return false; return false;
} else { } else {
@ -168,7 +180,7 @@ bool __sig_handle(bool restartable, int sig, int si_code, ucontext_t *ctx) {
bool delivered; bool delivered;
switch (__sighandrvas[sig]) { switch (__sighandrvas[sig]) {
case (intptr_t)SIG_DFL: case (intptr_t)SIG_DFL:
if (__sig_isfatal(sig)) { if (__sig_is_fatal(sig)) {
STRACE("terminating on %G", sig); STRACE("terminating on %G", sig);
_Exitr(128 + sig); _Exitr(128 + sig);
} }
@ -194,20 +206,17 @@ bool __sig_handle(bool restartable, int sig, int si_code, ucontext_t *ctx) {
* @threadsafe * @threadsafe
*/ */
textwindows int __sig_raise(int sig, int si_code) { textwindows int __sig_raise(int sig, int si_code) {
int rc; if (1 <= sig && sig <= 64) {
int candeliver; if (!__sig_is_masked(sig)) {
__sig_lock(); ++__sig_count;
candeliver = !sigismember(&__sig.mask, sig);
__sig_unlock();
switch (candeliver) {
case 1:
__sig_handle(false, sig, si_code, 0); __sig_handle(false, sig, si_code, 0);
return 0; return 0;
case 0: } else {
STRACE("%G is masked", sig); STRACE("%G is masked", sig);
return __sig_add(sig, si_code); return __sig_add(gettid(), sig, si_code);
default: }
return -1; // sigismember() validates `sig` } else {
return einval();
} }
} }
@ -216,10 +225,10 @@ textwindows int __sig_raise(int sig, int si_code) {
* @return 0 on success, otherwise -1 w/ errno * @return 0 on success, otherwise -1 w/ errno
* @threadsafe * @threadsafe
*/ */
textwindows int __sig_add(int sig, int si_code) { textwindows int __sig_add(int tid, int sig, int si_code) {
int rc; int rc;
struct Signal *mem; struct Signal *mem;
if (1 <= sig && sig <= NSIG) { if (1 <= sig && sig <= 64) {
__sig_lock(); __sig_lock();
if (__sighandrvas[sig] == (unsigned)(intptr_t)SIG_IGN) { if (__sighandrvas[sig] == (unsigned)(intptr_t)SIG_IGN) {
STRACE("ignoring %G", sig); STRACE("ignoring %G", sig);
@ -228,6 +237,7 @@ textwindows int __sig_add(int sig, int si_code) {
STRACE("enqueuing %G", sig); STRACE("enqueuing %G", sig);
++__sig_count; ++__sig_count;
if ((mem = __sig_alloc())) { if ((mem = __sig_alloc())) {
mem->tid = tid;
mem->sig = sig; mem->sig = sig;
mem->si_code = si_code; mem->si_code = si_code;
mem->next = __sig.queue; 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) { textwindows void __sig_check_ignore(const int sig, const unsigned rva) {
struct Signal *cur, *prev, *next; struct Signal *cur, *prev, *next;
if (rva != (unsigned)(intptr_t)SIG_IGN && 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; return;
} }
if (__sig.queue) { if (__sig.queue) {
@ -298,25 +308,3 @@ textwindows void __sig_check_ignore(const int sig, const unsigned rva) {
__sig_unlock(); __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. PERFORMANCE OF THIS SOFTWARE.
*/ */
#include "libc/calls/sig.internal.h" #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/consts/sig.h"
#include "libc/sysv/errfuns.h" #include "libc/sysv/errfuns.h"
#include "libc/thread/tls.h"
/** #define GetSigBit(x) (1ull << (((x)-1) & 63))
* @fileoverview UNIX signals for the New Technology, Part 1.
* @threadsafe
*/
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) { textwindows int __sig_mask(int how, const sigset_t *neu, sigset_t *old) {
int i; uint64_t x, y, *mask;
uint64_t a, b;
if (how == SIG_BLOCK || how == SIG_UNBLOCK || how == SIG_SETMASK) { 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) { if (old) {
*old = __sig.mask; old->__bits[0] = *mask;
old->__bits[1] = 0;
} }
if (neu) { if (neu) {
for (i = 0; i < ARRAYLEN(__sig.mask.__bits); ++i) { x = *mask;
if (how == SIG_BLOCK) { y = neu->__bits[0];
__sig.mask.__bits[i] |= neu->__bits[i]; if (how == SIG_BLOCK) {
} else if (how == SIG_UNBLOCK) { x |= y;
__sig.mask.__bits[i] &= ~neu->__bits[i]; } else if (how == SIG_UNBLOCK) {
} else { x &= ~y;
__sig.mask.__bits[i] = neu->__bits[i]; } else {
} x = y;
} }
__sig.mask.__bits[0] &= ~(GetSigBit(SIGKILL) | GetSigBit(SIGSTOP)); x &= ~(GetSigBit(SIGKILL) | GetSigBit(SIGSTOP) | GetSigBit(SIGABRT));
*mask = x;
} }
__sig_unlock();
return 0; return 0;
} else { } else {
return einval(); 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 fcntl(int, int, ...);
int fdatasync(int); int fdatasync(int);
int flock(int, int); int flock(int, int);
int lockf(int, int, int64_t);
int fork(void); int fork(void);
int fsync(int); int fsync(int);
int ftruncate(int, int64_t); int ftruncate(int, int64_t);

View file

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

View file

@ -37,8 +37,6 @@
#include "libc/sysv/consts/o.h" #include "libc/sysv/consts/o.h"
#include "libc/sysv/errfuns.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) { static textwindows int sys_fcntl_nt_dupfd(int fd, int cmd, int start) {
if (start < 0) return einval(); if (start < 0) return einval();
return sys_dup_nt(fd, -1, (cmd == F_DUPFD_CLOEXEC ? O_CLOEXEC : 0), start); 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; ok = true;
} }
} }
if (ok || __force_sqlite_to_work_until_we_can_fix_it) { return ok ? 0 : -1;
return 0;
} else {
return -1;
}
} }
if (l->l_type == F_UNLCK) { if (l->l_type == F_UNLCK) {

View file

@ -18,11 +18,15 @@
*/ */
#include "libc/calls/calls.h" #include "libc/calls/calls.h"
#include "libc/calls/internal.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-nt.internal.h"
#include "libc/calls/syscall-sysv.internal.h" #include "libc/calls/syscall-sysv.internal.h"
#include "libc/dce.h" #include "libc/dce.h"
#include "libc/intrin/describeflags.internal.h"
#include "libc/intrin/strace.internal.h" #include "libc/intrin/strace.internal.h"
#include "libc/intrin/weaken.h" #include "libc/intrin/weaken.h"
#include "libc/sysv/consts/f.h"
#include "libc/sysv/errfuns.h" #include "libc/sysv/errfuns.h"
#include "libc/zipos/zipos.internal.h" #include "libc/zipos/zipos.internal.h"
@ -44,9 +48,49 @@
* Please be warned that locks currently do nothing on Windows since * Please be warned that locks currently do nothing on Windows since
* figuring out how to polyfill them correctly is a work in progress. * 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 * @param arg can be FD_CLOEXEC, etc. depending
* @return 0 on success, or -1 w/ errno * @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 * @asyncsignalsafe
* @restartable * @restartable
*/ */
@ -54,20 +98,58 @@ int fcntl(int fd, int cmd, ...) {
int rc; int rc;
va_list va; va_list va;
uintptr_t arg; uintptr_t arg;
va_start(va, cmd); va_start(va, cmd);
arg = va_arg(va, uintptr_t); arg = va_arg(va, uintptr_t);
va_end(va); va_end(va);
if (fd >= 0) { if (fd >= 0) {
if (fd < g_fds.n && g_fds.p[fd].kind == kFdZip) { if (cmd >= 0) {
rc = _weaken(__zipos_fcntl)(fd, cmd, arg); if (fd < g_fds.n && g_fds.p[fd].kind == kFdZip) {
} else if (!IsWindows()) { rc = _weaken(__zipos_fcntl)(fd, cmd, arg);
rc = sys_fcntl(fd, cmd, arg); } else if (!IsWindows()) {
rc = sys_fcntl(fd, cmd, arg);
} else {
rc = sys_fcntl_nt(fd, cmd, arg);
}
} else { } else {
rc = sys_fcntl_nt(fd, cmd, arg); rc = einval();
} }
} else { } 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; return rc;
} }

View file

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

View file

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

View file

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

View file

@ -31,9 +31,8 @@
textwindows bool _check_interrupts(bool restartable, struct Fd *fd) { textwindows bool _check_interrupts(bool restartable, struct Fd *fd) {
bool res; bool res;
if (__threaded && __threaded != gettid()) return false;
if (_weaken(_check_sigalrm)) _weaken(_check_sigalrm)(); 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 (_weaken(_check_sigchld)) _weaken(_check_sigchld)();
if (fd && _weaken(_check_sigwinch)) _weaken(_check_sigwinch)(fd); if (fd && _weaken(_check_sigwinch)) _weaken(_check_sigwinch)(fd);
} }

View file

@ -17,25 +17,44 @@
PERFORMANCE OF THIS SOFTWARE. PERFORMANCE OF THIS SOFTWARE.
*/ */
#include "libc/calls/sig.internal.h" #include "libc/calls/sig.internal.h"
#include "libc/intrin/atomic.h"
#include "libc/intrin/strace.internal.h" #include "libc/intrin/strace.internal.h"
#include "libc/nexgen32e/nt2sysv.h" #include "libc/nexgen32e/nt2sysv.h"
#include "libc/nt/enum/ctrlevent.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/sicode.h"
#include "libc/sysv/consts/sig.h" #include "libc/sysv/consts/sig.h"
#include "libc/thread/tls.h"
#include "libc/thread/tls2.h"
textwindows bool32 __onntconsoleevent(uint32_t dwCtrlType) { 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); STRACE("__onntconsoleevent(%u)", dwCtrlType);
switch (dwCtrlType) { switch (dwCtrlType) {
case kNtCtrlCEvent: case kNtCtrlCEvent:
__sig_add(SIGINT, SI_KERNEL); __sig_add(0, SIGINT, SI_KERNEL);
return true; return true;
case kNtCtrlBreakEvent: case kNtCtrlBreakEvent:
__sig_add(SIGQUIT, SI_KERNEL); __sig_add(0, SIGQUIT, SI_KERNEL);
return true; return true;
case kNtCtrlCloseEvent: case kNtCtrlCloseEvent:
case kNtCtrlLogoffEvent: // only received by services case kNtCtrlLogoffEvent: // only received by services
case kNtCtrlShutdownEvent: // only received by services case kNtCtrlShutdownEvent: // only received by services
__sig_add(SIGHUP, SI_KERNEL); __sig_add(0, SIGHUP, SI_KERNEL);
return true; return true;
default: default:
return false; return false;

View file

@ -1256,16 +1256,18 @@ static privileged void AllowIoctlTty(struct Filter *f) {
// - TCP_FASTOPEN (0x17) // - TCP_FASTOPEN (0x17)
// - TCP_FASTOPEN_CONNECT (0x1e) // - TCP_FASTOPEN_CONNECT (0x1e)
// - IPV6_V6ONLY (0x1a) // - IPV6_V6ONLY (0x1a)
// - TCP_QUICKACK (0x0c)
// //
static privileged void AllowSetsockoptRestrict(struct Filter *f) { static privileged void AllowSetsockoptRestrict(struct Filter *f) {
static const struct sock_filter fragment[] = { 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_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, 41, 3, 0),
BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, 0, 2, 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, 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_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, 0x1a, 15, 0),
BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, 0x06, 14, 0), BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, 0x06, 14, 0),
BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, 0x0f, 13, 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/calls.h"
#include "libc/calls/sig.internal.h" #include "libc/calls/sig.internal.h"
#include "libc/intrin/strace.internal.h"
#include "libc/calls/syscall-sysv.internal.h" #include "libc/calls/syscall-sysv.internal.h"
#include "libc/dce.h" #include "libc/dce.h"
#include "libc/thread/tls.h" #include "libc/intrin/strace.internal.h"
#include "libc/runtime/internal.h" #include "libc/runtime/internal.h"
#include "libc/sysv/consts/sicode.h" #include "libc/sysv/consts/sicode.h"
#include "libc/sysv/consts/sig.h" #include "libc/sysv/consts/sig.h"
#include "libc/thread/tls.h"
#include "libc/thread/xnu.internal.h" #include "libc/thread/xnu.internal.h"
static textwindows inline bool HasWorkingConsole(void) { static textwindows inline bool HasWorkingConsole(void) {
@ -59,7 +59,7 @@ static noubsan void RaiseSigFpe(void) {
* @asyncsignalsafe * @asyncsignalsafe
*/ */
int raise(int sig) { int raise(int sig) {
int rc, event; int rc, tid, event;
STRACE("raise(%G) → ...", sig); STRACE("raise(%G) → ...", sig);
if (sig == SIGTRAP) { if (sig == SIGTRAP) {
DebugBreak(); DebugBreak();
@ -67,7 +67,7 @@ int raise(int sig) {
} else if (sig == SIGFPE) { } else if (sig == SIGFPE) {
RaiseSigFpe(); RaiseSigFpe();
rc = 0; rc = 0;
} else if (!IsWindows()) { } else if (!IsWindows() && !IsMetal()) {
rc = sys_tkill(gettid(), sig, 0); rc = sys_tkill(gettid(), sig, 0);
} else { } else {
rc = __sig_raise(sig, SI_TKILL); rc = __sig_raise(sig, SI_TKILL);

View file

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

View file

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

View file

@ -21,10 +21,10 @@
#include "libc/calls/internal.h" #include "libc/calls/internal.h"
#include "libc/calls/sig.internal.h" #include "libc/calls/sig.internal.h"
#include "libc/calls/state.internal.h" #include "libc/calls/state.internal.h"
#include "libc/intrin/strace.internal.h"
#include "libc/calls/struct/siginfo.h" #include "libc/calls/struct/siginfo.h"
#include "libc/calls/syscall_support-nt.internal.h" #include "libc/calls/syscall_support-nt.internal.h"
#include "libc/dce.h" #include "libc/dce.h"
#include "libc/intrin/strace.internal.h"
#include "libc/nt/enum/wait.h" #include "libc/nt/enum/wait.h"
#include "libc/nt/runtime.h" #include "libc/nt/runtime.h"
#include "libc/nt/synchronization.h" #include "libc/nt/synchronization.h"
@ -65,5 +65,5 @@ void _check_sigchld(void) {
__fds_lock(); __fds_lock();
g_fds.p[pids[i]].zombie = true; g_fds.p[pids[i]].zombie = true;
__fds_unlock(); __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" #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/assert.h"
#include "libc/calls/calls.h" #include "libc/calls/calls.h"
#include "libc/calls/sig.internal.h" #include "libc/calls/sig.internal.h"
#include "libc/intrin/strace.internal.h"
#include "libc/calls/struct/fd.internal.h" #include "libc/calls/struct/fd.internal.h"
#include "libc/calls/struct/sigaction.h" #include "libc/calls/struct/sigaction.h"
#include "libc/calls/struct/winsize.h" #include "libc/calls/struct/winsize.h"
#include "libc/calls/struct/winsize.internal.h" #include "libc/calls/struct/winsize.internal.h"
#include "libc/dce.h" #include "libc/dce.h"
#include "libc/errno.h" #include "libc/errno.h"
#include "libc/intrin/strace.internal.h"
#include "libc/nt/struct/consolescreenbufferinfoex.h" #include "libc/nt/struct/consolescreenbufferinfoex.h"
#include "libc/str/str.h" #include "libc/str/str.h"
#include "libc/sysv/consts/sicode.h" #include "libc/sysv/consts/sicode.h"
#include "libc/sysv/consts/sig.h" #include "libc/sysv/consts/sig.h"
#include "libc/thread/tls.h"
static struct winsize __ws; static struct winsize __ws;
@ -38,6 +39,7 @@ textwindows void _check_sigwinch(struct Fd *fd) {
siginfo_t si; siginfo_t si;
struct winsize ws, old; struct winsize ws, old;
struct NtConsoleScreenBufferInfoEx sbinfo; struct NtConsoleScreenBufferInfoEx sbinfo;
if (__tls_enabled && __threaded != gettid()) return;
old = __ws; old = __ws;
e = errno; e = errno;
if (old.ws_row != 0xffff) { 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) { if (old.ws_col != ws.ws_col || old.ws_row != ws.ws_row) {
__ws = ws; __ws = ws;
if (old.ws_col | old.ws_row) { if (old.ws_col | old.ws_row) {
__sig_add(SIGWINCH, SI_KERNEL); __sig_add(0, SIGWINCH, SI_KERNEL);
} }
} }
} else { } 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. PERFORMANCE OF THIS SOFTWARE.
*/ */
#include "libc/calls/calls.h" #include "libc/calls/calls.h"
#include "libc/calls/sig.internal.h"
#include "libc/calls/syscall-sysv.internal.h" #include "libc/calls/syscall-sysv.internal.h"
#include "libc/calls/syscall_support-nt.internal.h"
#include "libc/dce.h" #include "libc/dce.h"
#include "libc/intrin/strace.internal.h" #include "libc/intrin/strace.internal.h"
#include "libc/nt/enum/threadaccess.h" #include "libc/sysv/consts/sicode.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;
}
/** /**
* Kills thread. * Kills thread.
@ -56,10 +37,10 @@ static textwindows int sys_tkill_nt(int tid, int sig) {
*/ */
int tkill(int tid, int sig) { int tkill(int tid, int sig) {
int rc; int rc;
if (!IsWindows()) { if (!IsWindows() && !IsMetal()) {
rc = sys_tkill(tid, sig, 0); rc = sys_tkill(tid, sig, 0);
} else { } else {
rc = sys_tkill_nt(tid, sig); rc = __sig_add(tid, sig, SI_TKILL);
} }
STRACE("tkill(%d, %G) → %d% m", tid, sig, rc); STRACE("tkill(%d, %G) → %d% m", tid, sig, rc);
return rc; return rc;

View file

@ -19,6 +19,7 @@ struct MagnumStr {
hidden extern const struct MagnumStr kClockNames[]; hidden extern const struct MagnumStr kClockNames[];
hidden extern const struct MagnumStr kErrnoDocs[]; hidden extern const struct MagnumStr kErrnoDocs[];
hidden extern const struct MagnumStr kErrnoNames[]; hidden extern const struct MagnumStr kErrnoNames[];
hidden extern const struct MagnumStr kFcntlCmds[];
hidden extern const struct MagnumStr kIpOptnames[]; hidden extern const struct MagnumStr kIpOptnames[];
hidden extern const struct MagnumStr kOpenFlags[]; hidden extern const struct MagnumStr kOpenFlags[];
hidden extern const struct MagnumStr kRlimitNames[]; 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 *DescribeCapability(char[20], int);
const char *DescribeClockName(char[32], int); const char *DescribeClockName(char[32], int);
const char *DescribeDirfd(char[12], int); const char *DescribeDirfd(char[12], int);
const char *DescribeDnotifyFlags(char[80], int);
const char *DescribeErrno(char[12], int); const char *DescribeErrno(char[12], int);
const char *DescribeErrnoResult(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 *DescribeFrame(char[32], int);
const char *DescribeFutexOp(char[64], int); const char *DescribeFutexOp(char[64], int);
const char *DescribeHow(char[12], 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 DescribeDirfd(x) DescribeDirfd(alloca(12), x)
#define DescribeErrno(x) DescribeErrno(alloca(12), x) #define DescribeErrno(x) DescribeErrno(alloca(12), x)
#define DescribeErrnoResult(x) DescribeErrnoResult(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 DescribeFrame(x) DescribeFrame(alloca(32), x)
#define DescribeFutexOp(x) DescribeFutexOp(alloca(64), x) #define DescribeFutexOp(x) DescribeFutexOp(alloca(64), x)
#define DescribeHow(x) DescribeHow(alloca(12), 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 DescribeStdioState(x) DescribeStdioState(alloca(12), x)
#define DescribeWhence(x) DescribeWhence(alloca(12), x) #define DescribeWhence(x) DescribeWhence(alloca(12), x)
#define DescribeWhichPrio(x) DescribeWhichPrio(alloca(12), x) #define DescribeWhichPrio(x) DescribeWhichPrio(alloca(12), x)
#define DescribeDnotifyFlags(x) DescribeDnotifyFlags(alloca(80), x)
COSMOPOLITAN_C_END_ COSMOPOLITAN_C_END_
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */ #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; char *s;
int i, n; int i, n;
struct DescribeFlags d[N]; struct DescribeFlags d[N];
if (x == -1) return "-1";
// TODO(jart): unify DescribeFlags and MagnumStr data structures // TODO(jart): unify DescribeFlags and MagnumStr data structures
for (n = 0; kOpenFlags[n].x != MAGNUM_TERMINATOR; ++n) { for (n = 0; kOpenFlags[n].x != MAGNUM_TERMINATOR; ++n) {
if (n == N) notpossible; if (n == N) notpossible;

View file

@ -19,6 +19,7 @@
#include "libc/calls/calls.h" #include "libc/calls/calls.h"
#include "libc/calls/state.internal.h" #include "libc/calls/state.internal.h"
#include "libc/calls/syscall-sysv.internal.h" #include "libc/calls/syscall-sysv.internal.h"
#include "libc/intrin/atomic.h"
#include "libc/thread/tls.h" #include "libc/thread/tls.h"
/** /**
@ -36,7 +37,7 @@
int gettid(void) { int gettid(void) {
int tid; int tid;
if (__tls_enabled && !__vforked) { if (__tls_enabled && !__vforked) {
tid = __get_tls()->tib_tid; tid = atomic_load_explicit(&__get_tls()->tib_tid, memory_order_relaxed);
if (tid > 0) { if (tid > 0) {
return tid; 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/fmt/fmt.h"
#include "libc/intrin/asan.internal.h" #include "libc/intrin/asan.internal.h"
#include "libc/intrin/asancodes.h" #include "libc/intrin/asancodes.h"
#include "libc/intrin/atomic.h"
#include "libc/intrin/bits.h" #include "libc/intrin/bits.h"
#include "libc/intrin/cmpxchg.h" #include "libc/intrin/cmpxchg.h"
#include "libc/intrin/kprintf.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) { if (!__tls_enabled) {
x = __pid; x = __pid;
} else { } else {
x = __get_tls_privileged()->tib_tid; x = atomic_load_explicit(&__get_tls_privileged()->tib_tid,
memory_order_relaxed);
} }
if (!__nocolor && p + 7 <= e) { if (!__nocolor && p + 7 <= e) {
*p++ = '\e'; *p++ = '\e';

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -43,6 +43,7 @@
#include "libc/thread/openbsd.internal.h" #include "libc/thread/openbsd.internal.h"
#include "libc/thread/thread.h" #include "libc/thread/thread.h"
#include "libc/thread/tls.h" #include "libc/thread/tls.h"
#include "libc/thread/tls2.h"
#include "libc/thread/xnu.internal.h" #include "libc/thread/xnu.internal.h"
#define __NR_thr_new 455 #define __NR_thr_new 455
@ -97,11 +98,7 @@ WinThreadEntry(int rdi, // rcx
int rdx, // r8 int rdx, // r8
struct CloneArgs *wt) { // r9 struct CloneArgs *wt) { // r9
int rc; int rc;
if (wt->tls) { if (wt->tls) __set_tls_win32(wt->tls);
asm("mov\t%1,%%gs:%0"
: "=m"(*((long *)0x1480 + __tls_index))
: "r"(wt->tls));
}
*wt->ptid = wt->tid; *wt->ptid = wt->tid;
*wt->ctid = wt->tid; *wt->ctid = wt->tid;
rc = WinThreadLaunch(wt->arg, wt->tid, wt->func, (intptr_t)wt & -16); 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_QUOTED_VAR 4
#define STATE_WHITESPACE 5 #define STATE_WHITESPACE 5
#define READ24LE(s) READ32LE(s "\0") #define READ24(s) READ32LE(s "\0")
struct Env { struct Env {
char *s; char *s;
@ -333,16 +333,16 @@ static int Test(void) {
if (n == 4) { if (n == 4) {
w = READ32LE(args[2]) & 0x00ffffff; w = READ32LE(args[2]) & 0x00ffffff;
if ((w & 65535) == READ16LE("=")) return !!strcmp(args[1], args[3]); if ((w & 65535) == READ16LE("=")) 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 == READ24LE("!=")) return !strcmp(args[1], args[3]); if (w == READ24("!=")) return !strcmp(args[1], args[3]);
} else if (n == 3) { } else if (n == 3) {
w = READ32LE(args[1]) & 0x00ffffff; w = READ32LE(args[1]) & 0x00ffffff;
if (w == READ24LE("-n")) return !(strlen(args[2]) > 0); if (w == READ24("-n")) return !(strlen(args[2]) > 0);
if (w == READ24LE("-z")) return !(strlen(args[2]) == 0); if (w == READ24("-z")) return !(strlen(args[2]) == 0);
if (w == READ24LE("-e")) return !!stat(args[2], &st); if (w == READ24("-e")) return !!stat(args[2], &st);
if (w == READ24LE("-f")) return !stat(args[2], &st) && S_ISREG(st.st_mode); if (w == READ24("-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 == READ24("-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("-h")) return !(!stat(args[2], &st) && S_ISLNK(st.st_mode));
} }
return 1; return 1;
} }

View file

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

View file

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

View file

@ -23,6 +23,7 @@
#include "libc/calls/syscall-sysv.internal.h" #include "libc/calls/syscall-sysv.internal.h"
#include "libc/calls/syscall_support-sysv.internal.h" #include "libc/calls/syscall_support-sysv.internal.h"
#include "libc/dce.h" #include "libc/dce.h"
#include "libc/intrin/atomic.h"
#include "libc/intrin/strace.internal.h" #include "libc/intrin/strace.internal.h"
#include "libc/nt/process.h" #include "libc/nt/process.h"
#include "libc/runtime/internal.h" #include "libc/runtime/internal.h"
@ -56,7 +57,9 @@ int _fork(uint32_t dwCreationFlags) {
parent = __pid; parent = __pid;
__pid = dx; __pid = dx;
if (__tls_enabled) { 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); if (!IsWindows()) sys_sigprocmask(SIG_SETMASK, &old, 0);
STRACE("fork() → 0 (child of %d)", parent); 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 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 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 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 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 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 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 0 # returned by fgetwc(3), fputwc(3), getwchar(3), putwchar(3), scanf(3), ungetwc(3) 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 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 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) 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 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 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 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 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 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) 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 EBADMACHO 0 88 0 0 0 0 #
syscon errno ENOPOLICY 0 103 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 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 ECANCELED 125 89 85 88 87 1223 # kNtErrorCancelled; 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 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 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 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() 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_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_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_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_SETOWN 8 6 6 6 6 -1 # bsd consensus
syscon fcntl2 F_GETOWN 9 5 5 5 5 0 # bsd consensus syscon fcntl2 F_GETOWN 9 5 5 5 5 -1 # bsd consensus
syscon fcntl2 F_FULLFSYNC 0 51 0 0 0 0 # syscon fcntl2 F_FULLFSYNC -1 51 -1 -1 -1 -1 #
syscon fcntl2 F_NOCACHE 0 48 0 0 0 0 # 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 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_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 F_MAXFD -1 -1 -1 -1 11 -1 #
syscon fcntl FREAD 0 1 1 1 1 0 # syscon fcntl F_NOTIFY 0x0402 -1 -1 -1 -1 -1
syscon fcntl FWRITE 0 2 2 2 2 0 # 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_NONBLOCK
# fcntl3 O_APPEND # 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 # 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 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 # 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_GETLK 5 7 11 7 7 5 # 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_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_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 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_SETSIG 10 -1 -1 -1 -1 -1
syscon fcntl F_LOCK 1 1 1 1 1 0 # unix consensus syscon fcntl F_GETSIG 11 -1 -1 -1 -1 -1
syscon fcntl F_TLOCK 2 2 2 2 2 0 # unix consensus syscon fcntl F_SETOWN_EX 15 -1 -1 -1 -1 -1
syscon fcntl F_TEST 3 3 3 3 3 0 # unix consensus syscon fcntl F_GETOWN_EX 0x10 -1 -1 -1 -1 -1
syscon fcntl F_SETSIG 10 0 0 0 0 0 syscon fcntl F_SETLEASE 0x0400 -1 -1 -1 -1 -1
syscon fcntl F_GETSIG 11 0 0 0 0 0 syscon fcntl F_GETLEASE 0x0401 -1 -1 -1 -1 -1
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 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 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 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_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 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_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_KEEPIDLE 4 0 0x100 0 3 0 # start keepalives after this period
syscon tcp TCP_KEEPINTVL 5 0x101 0x200 0 5 0 # keepalives syscon tcp TCP_KEEPINTVL 5 0x101 0x200 0 5 0 # interval between keepalives
syscon tcp TCP_KEEPCNT 6 0x102 0x400 0 6 0 # 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_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_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 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_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_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_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_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_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 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" .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" .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" .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" .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" .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" .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" .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" .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" .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" .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" .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" .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" .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" .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" .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" .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" .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" .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" .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" .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" .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" .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" .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" .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" .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" .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" .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) #if !(__ASSEMBLER__ + __LINKER__ + 0)
COSMOPOLITAN_C_START_ COSMOPOLITAN_C_START_
extern const int F_BARRIERFSYNC;
extern const int F_DUPFD; extern const int F_DUPFD;
extern const int F_DUPFD_CLOEXEC; extern const int F_DUPFD_CLOEXEC;
extern const int F_FULLFSYNC; extern const int F_FULLFSYNC;
@ -12,11 +13,14 @@ extern const int F_GETFL;
extern const int F_GETLEASE; extern const int F_GETLEASE;
extern const int F_GETLK64; extern const int F_GETLK64;
extern const int F_GETLK; extern const int F_GETLK;
extern const int F_GETNOSIGPIPE;
extern const int F_GETOWN; extern const int F_GETOWN;
extern const int F_GETOWN_EX; extern const int F_GETOWN_EX;
extern const int F_GETPATH;
extern const int F_GETPIPE_SZ; extern const int F_GETPIPE_SZ;
extern const int F_GETSIG; extern const int F_GETSIG;
extern const int F_LOCK; extern const int F_LOCK;
extern const int F_MAXFD;
extern const int F_NOCACHE; extern const int F_NOCACHE;
extern const int F_NOTIFY; extern const int F_NOTIFY;
extern const int F_OFD_GETLK; extern const int F_OFD_GETLK;
@ -30,13 +34,11 @@ extern const int F_SETLK64;
extern const int F_SETLK; extern const int F_SETLK;
extern const int F_SETLKW64; extern const int F_SETLKW64;
extern const int F_SETLKW; extern const int F_SETLKW;
extern const int F_SETNOSIGPIPE;
extern const int F_SETOWN; extern const int F_SETOWN;
extern const int F_SETOWN_EX; extern const int F_SETOWN_EX;
extern const int F_SETPIPE_SZ; extern const int F_SETPIPE_SZ;
extern const int F_SETSIG; 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_UNLCK;
extern const int F_WRLCK; extern const int F_WRLCK;
@ -50,20 +52,17 @@ COSMOPOLITAN_C_END_
#define F_SETFL LITERALLY(4) #define F_SETFL LITERALLY(4)
#define F_DUPFD_CLOEXEC SYMBOLIC(F_DUPFD_CLOEXEC) #define F_DUPFD_CLOEXEC SYMBOLIC(F_DUPFD_CLOEXEC)
#define F_FULLFSYNC SYMBOLIC(F_FULLFSYNC)
#define F_GETLEASE SYMBOLIC(F_GETLEASE) #define F_GETLEASE SYMBOLIC(F_GETLEASE)
#define F_GETLK SYMBOLIC(F_GETLK) #define F_GETLK SYMBOLIC(F_GETLK)
#define F_GETLK64 SYMBOLIC(F_GETLK64) #define F_GETLK64 SYMBOLIC(F_GETLK64)
#define F_GETOWN SYMBOLIC(F_GETOWN) #define F_GETOWN SYMBOLIC(F_GETOWN)
#define F_GETOWN_EX SYMBOLIC(F_GETOWN_EX) #define F_GETOWN_EX SYMBOLIC(F_GETOWN_EX)
#define F_GETPATH SYMBOLIC(F_GETPATH)
#define F_GETPIPE_SZ SYMBOLIC(F_GETPIPE_SZ) #define F_GETPIPE_SZ SYMBOLIC(F_GETPIPE_SZ)
#define F_GETSIG SYMBOLIC(F_GETSIG) #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_NOCACHE SYMBOLIC(F_NOCACHE)
#define F_NOTIFY SYMBOLIC(F_NOTIFY) #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_RDLCK SYMBOLIC(F_RDLCK)
#define F_SETLEASE SYMBOLIC(F_SETLEASE) #define F_SETLEASE SYMBOLIC(F_SETLEASE)
#define F_SETLK SYMBOLIC(F_SETLK) #define F_SETLK SYMBOLIC(F_SETLK)
@ -74,10 +73,16 @@ COSMOPOLITAN_C_END_
#define F_SETOWN_EX SYMBOLIC(F_SETOWN_EX) #define F_SETOWN_EX SYMBOLIC(F_SETOWN_EX)
#define F_SETPIPE_SZ SYMBOLIC(F_SETPIPE_SZ) #define F_SETPIPE_SZ SYMBOLIC(F_SETPIPE_SZ)
#define F_SETSIG SYMBOLIC(F_SETSIG) #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_UNLCK SYMBOLIC(F_UNLCK)
#define F_WRLCK SYMBOLIC(F_WRLCK) #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_ */ #endif /* COSMOPOLITAN_LIBC_SYSV_CONSTS_F_H_ */

View file

@ -19,6 +19,7 @@
#include "libc/dce.h" #include "libc/dce.h"
#include "libc/intrin/asan.internal.h" #include "libc/intrin/asan.internal.h"
#include "libc/intrin/asancodes.h" #include "libc/intrin/asancodes.h"
#include "libc/intrin/atomic.h"
#include "libc/macros.internal.h" #include "libc/macros.internal.h"
#include "libc/mem/mem.h" #include "libc/mem/mem.h"
#include "libc/runtime/internal.h" #include "libc/runtime/internal.h"
@ -57,7 +58,8 @@ char *_mktls(struct CosmoTib **out_tib) {
tib = (struct CosmoTib *)(tls + I(_tls_size)); tib = (struct CosmoTib *)(tls + I(_tls_size));
tib->tib_self = tib; tib->tib_self = tib;
tib->tib_self2 = 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) { if (out_tib) {
*out_tib = tib; *out_tib = tib;

View file

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

View file

@ -4,8 +4,8 @@
#include "libc/thread/tls.h" #include "libc/thread/tls.h"
#if !(__ASSEMBLER__ + __LINKER__ + 0) #if !(__ASSEMBLER__ + __LINKER__ + 0)
COSMOPOLITAN_C_START_ COSMOPOLITAN_C_START_
#if defined(__GNUC__) && defined(__x86_64__) && !defined(__STRICT_ANSI__) #if defined(__GNUC__) && defined(__x86_64__) && !defined(__STRICT_ANSI__)
/** /**
* Returns location of thread information block. * Returns location of thread information block.
* *
@ -24,8 +24,19 @@ static noasan inline struct CosmoTib *__get_tls_privileged(void) {
} }
return (struct CosmoTib *)tib; 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_ COSMOPOLITAN_C_END_
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */ #endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
#endif /* COSMOPOLITAN_LIBC_THREAD_TLS2_H_ */ #endif /* COSMOPOLITAN_LIBC_THREAD_TLS2_H_ */

View file

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

View file

@ -729,7 +729,9 @@ void ServeStatusz(int client, char *outbuf) {
void *ListenWorker(void *arg) { void *ListenWorker(void *arg) {
int server; int server;
int no = 0;
int yes = 1; int yes = 1;
int fastopen = 5;
struct Client client; struct Client client;
struct timeval timeo = {g_keepalive / 1000, g_keepalive % 1000}; struct timeval timeo = {g_keepalive / 1000, g_keepalive % 1000};
struct sockaddr_in addr = {.sin_family = AF_INET, .sin_port = htons(g_port)}; 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_RCVTIMEO, &timeo, sizeof(timeo));
setsockopt(server, SOL_SOCKET, SO_SNDTIMEO, &timeo, sizeof(timeo)); setsockopt(server, SOL_SOCKET, SO_SNDTIMEO, &timeo, sizeof(timeo));
setsockopt(server, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(yes)); setsockopt(server, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(yes));
setsockopt(server, SOL_TCP, TCP_FASTOPEN, &yes, sizeof(yes)); setsockopt(server, SOL_TCP, TCP_FASTOPEN, &fastopen, sizeof(fastopen));
setsockopt(server, SOL_TCP, TCP_QUICKACK, &yes, sizeof(yes)); 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)); 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)); CHECK_NE(-1, listen(server, 1));
while (!nsync_note_is_notified(g_shutdown[0])) { while (!nsync_note_is_notified(g_shutdown[0])) {
client.size = sizeof(client.addr); client.size = sizeof(client.addr);
@ -791,7 +794,7 @@ void *HttpWorker(void *arg) {
struct Url url; struct Url url;
ssize_t got, sent; ssize_t got, sent;
uint32_t ip, clientip; uint32_t ip, clientip;
int inmsglen, outmsglen; int tok, inmsglen, outmsglen;
char ipbuf[32], *p, *q, cashbuf[64]; char ipbuf[32], *p, *q, cashbuf[64];
clientip = ntohl(client.addr.sin_addr.s_addr); 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, ksnprintf(ipbuf, sizeof(ipbuf), "%hhu.%hhu.%hhu.%hhu", ip >> 24, ip >> 16,
ip >> 8, ip); 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 // we don't support http/1.0 and http/0.9 right now
if (msg->version != 11) { if (msg->version != 11) {
LOG("%s used unsupported http/%d version\n", ipbuf, msg->version); LOG("%s used unsupported http/%d version\n", ipbuf, msg->version);
@ -873,19 +889,8 @@ void *HttpWorker(void *arg) {
break; 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 // 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->xmethod.b - msg->xmethod.a, inbuf + msg->xmethod.a,
msg->uri.b - msg->uri.a, inbuf + msg->uri.a, msg->uri.b - msg->uri.a, inbuf + msg->uri.a,
HeaderLength(kHttpCfIpcountry), HeaderData(kHttpCfIpcountry), HeaderLength(kHttpCfIpcountry), HeaderData(kHttpCfIpcountry),
@ -1765,7 +1770,12 @@ OnError:
} }
int main(int argc, char *argv[]) { 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 don't have proper futexes on these platforms
// we'll be somewhat less aggressive about workers // 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, 3, fcntl(2, F_DUPFD_CLOEXEC, 3));
ASSERT_SYS(0, 0, ioctl(0, FIOCLEX, 0)); ASSERT_SYS(0, 0, ioctl(0, FIOCLEX, 0));
ASSERT_SYS(EPERM, 0, isatty(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_GETLK, &lk));
ASSERT_SYS(EPERM, -1, fcntl(0, F_NOTIFY)); ASSERT_SYS(EPERM, -1, fcntl(0, F_NOTIFY));
ASSERT_SYS(EPERM, -1, socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)); 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/log/check.h"
#include "libc/mem/gc.internal.h" #include "libc/mem/gc.internal.h"
#include "libc/mem/mem.h" #include "libc/mem/mem.h"
#include "libc/stdio/stdio.h"
#include "libc/str/str.h" #include "libc/str/str.h"
#include "libc/testlib/ezbench.h" #include "libc/testlib/ezbench.h"
#include "libc/testlib/testlib.h" #include "libc/testlib/testlib.h"
@ -147,6 +146,14 @@ TEST(ParseHttpMessage, testHttp09) {
EXPECT_EQ(9, req->version); 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) { TEST(ParseHttpMessage, testLeadingLineFeeds_areIgnored) {
static const char m[] = "\ static const char m[] = "\
\r\n\ \r\n\

View file

@ -24,6 +24,7 @@
#include "libc/limits.h" #include "libc/limits.h"
#include "libc/mem/mem.h" #include "libc/mem/mem.h"
#include "libc/stdio/stdio.h" #include "libc/stdio/stdio.h"
#include "libc/str/str.h"
#include "libc/testlib/ezbench.h" #include "libc/testlib/ezbench.h"
#include "libc/testlib/testlib.h" #include "libc/testlib/testlib.h"
#include "net/http/http.h" #include "net/http/http.h"
@ -47,27 +48,52 @@ void TearDown(void) {
} }
TEST(tokenbucket, test) { TEST(tokenbucket, test) {
ASSERT_FALSE(AcquireToken(tok.b, 0x7f000001, TB_CIDR)); ASSERT_EQ(0, AcquireToken(tok.b, 0x7f000001, TB_CIDR));
ASSERT_FALSE(AcquireToken(tok.b, 0x7f000002, TB_CIDR)); ASSERT_EQ(0, AcquireToken(tok.b, 0x7f000002, TB_CIDR));
ReplenishTokens(tok.w, TB_WORDS); ReplenishTokens(tok.w, TB_WORDS);
ReplenishTokens(tok.w, TB_WORDS); ReplenishTokens(tok.w, TB_WORDS);
ASSERT_TRUE(AcquireToken(tok.b, 0x7f000001, TB_CIDR)); ASSERT_EQ(2, AcquireToken(tok.b, 0x7f000001, TB_CIDR));
ASSERT_TRUE(AcquireToken(tok.b, 0x7f000002, TB_CIDR)); ASSERT_EQ(1, AcquireToken(tok.b, 0x7f000002, TB_CIDR));
ASSERT_FALSE(AcquireToken(tok.b, 0x7f000001, TB_CIDR)); ASSERT_EQ(0, AcquireToken(tok.b, 0x7f000001, TB_CIDR));
ASSERT_TRUE(AcquireToken(tok.b, 0x08080808, 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); ReplenishTokens(tok.w, TB_WORDS);
ASSERT_EQ(1, AcquireToken(tok.b, 0x7f000001, TB_CIDR));
ReplenishTokens(tok.w, TB_WORDS); ReplenishTokens(tok.w, TB_WORDS);
ASSERT_TRUE(AcquireToken(tok.b, 0x7f000001, TB_CIDR)); ASSERT_EQ(1, AcquireToken(tok.b, 0x7f000001, TB_CIDR));
ASSERT_TRUE(AcquireToken(tok.b, 0x7f000001, TB_CIDR)); ASSERT_EQ(0, AcquireToken(tok.b, 0x7f000002, TB_CIDR));
ASSERT_FALSE(AcquireToken(tok.b, 0x7f000002, TB_CIDR)); ASSERT_EQ(3, AcquireToken(tok.b, 0x08080808, TB_CIDR));
ASSERT_TRUE(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) { BENCH(tokenbucket, bench) {
struct timespec t1, t2; 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); clock_gettime(0, &t1);
ReplenishTokens(tok.w, TB_WORDS); ReplenishTokens(tok.w, TB_WORDS);
clock_gettime(0, &t2); 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))); _timespec_tomicros(_timespec_sub(t2, t1)));
} }

View file

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

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/atomic.h"
#include "libc/calls/calls.h" #include "libc/calls/calls.h"
#include "libc/calls/internal.h"
#include "libc/calls/sig.internal.h" #include "libc/calls/sig.internal.h"
#include "libc/calls/state.internal.h" #include "libc/calls/state.internal.h"
#include "libc/calls/struct/timespec.h" #include "libc/calls/struct/timespec.h"
@ -166,15 +167,19 @@ int nsync_futex_wait_ (int *p, int expect, char pshare, struct timespec *timeout
if (pshare) { if (pshare) {
goto Polyfill; goto Polyfill;
} }
if (timeout) { if (_check_interrupts (false, 0)) {
ms = _timespec_tomillis (*timeout); rc = -EINTR;
} else { } else {
ms = -1; if (timeout) {
} ms = _timespec_tomillis (*timeout);
if (WaitOnAddress (p, &expect, sizeof(int), ms)) { } else {
rc = 0; ms = -1;
} else { }
rc = -GetLastError (); if (WaitOnAddress (p, &expect, sizeof(int), ms)) {
rc = 0;
} else {
rc = -GetLastError ();
}
} }
} else if (IsFreebsd ()) { } else if (IsFreebsd ()) {
rc = sys_umtx_timedwait_uint ( rc = sys_umtx_timedwait_uint (
@ -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; __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, p, DescribeFutexOp (op), expect,
DescribeTimespec (0, timeout), DescribeTimespec (0, timeout),
DescribeErrnoResult (rc)); DescribeErrnoResult (rc));

View file

@ -16,6 +16,7 @@
limitations under the License. limitations under the License.
*/ */
#include "libc/errno.h" #include "libc/errno.h"
#include "libc/runtime/runtime.h"
#include "third_party/nsync/atomic.h" #include "third_party/nsync/atomic.h"
#include "third_party/nsync/atomic.internal.h" #include "third_party/nsync/atomic.internal.h"
#include "third_party/nsync/common.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); 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/struct/utimbuf.h"
#include "libc/time/time.h" #include "libc/time/time.h"
#include "libc/x/x.h" #include "libc/x/x.h"
#include "third_party/musl/lockf.h"
#include "third_party/musl/passwd.h" #include "third_party/musl/passwd.h"
#include "third_party/python/Include/abstract.h" #include "third_party/python/Include/abstract.h"
#include "third_party/python/Include/boolobject.h" #include "third_party/python/Include/boolobject.h"
@ -11894,10 +11895,10 @@ all_ins(PyObject *m)
if (PyModule_AddIntMacro(m, CLD_CONTINUED)) return -1; if (PyModule_AddIntMacro(m, CLD_CONTINUED)) return -1;
/* constants for lockf */ /* constants for lockf */
if (F_LOCK && PyModule_AddIntMacro(m, F_LOCK)) return -1; if (PyModule_AddIntMacro(m, F_LOCK)) return -1;
if (F_TLOCK && PyModule_AddIntMacro(m, F_TLOCK)) return -1; if (PyModule_AddIntMacro(m, F_TLOCK)) return -1;
if (PyModule_AddIntMacro(m, F_ULOCK)) 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 #ifdef HAVE_SPAWNV
if (PyModule_AddIntConstant(m, "P_WAIT", _P_WAIT)) return -1; if (PyModule_AddIntConstant(m, "P_WAIT", _P_WAIT)) return -1;

View file

@ -227,7 +227,7 @@
/* #undef HAVE_LINUX_CAN_RAW_FD_FRAMES */ /* #undef HAVE_LINUX_CAN_RAW_FD_FRAMES */
/* Define to 1 if you have the 'lockf' function and the F_LOCK macro. */ /* 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_DEVICE_MACROS 1 */
#define HAVE_MAKEDEV 1 #define HAVE_MAKEDEV 1

View file

@ -10,3 +10,7 @@ ORIGIN
LICENSE LICENSE
Public Domain or MIT 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() */ char *zErrMsg = 0; /* Error message from sqlite3ParseUri() */
int i; /* Loop counter */ 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 #ifdef SQLITE_ENABLE_API_ARMOR
if( ppDb==0 ) return SQLITE_MISUSE_BKPT; if( ppDb==0 ) return SQLITE_MISUSE_BKPT;
#endif #endif

View file

@ -53,6 +53,8 @@
#include "third_party/sqlite3/sqlite3.h" #include "third_party/sqlite3/sqlite3.h"
#include "third_party/sqlite3/mutex.internal.h" #include "third_party/sqlite3/mutex.internal.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" #include "third_party/sqlite3/sqliteInt.inc"
#if SQLITE_OS_UNIX /* This file is used on unix only */ #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; struct stat buf;
rc = osFstat(fd, &buf); rc = osFstat(fd, &buf);
} }
#elif HAVE_FULLFSYNC #elif HAVE_FULLFSYNC || defined(__COSMOPOLITAN__)
if( fullSync ){ /* [jart] use runtime os detection */
if( fullSync && F_FULLFSYNC != -1 ){
rc = osFcntl(fd, F_FULLFSYNC, 0); rc = osFcntl(fd, F_FULLFSYNC, 0);
}else{ }else{
rc = 1; 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 ** It'd be better to detect fullfsync support once and avoid
** the fcntl call every time sync is called. ** 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__) #elif defined(__APPLE__)
/* fdatasync() on HFS+ doesn't yet flush the file size if it changed correctly /* 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/sysv/consts/rusage.h"
#include "libc/time/time.h" #include "libc/time/time.h"
#include "libc/runtime/runtime.h" #include "libc/runtime/runtime.h"
#include "libc/errno.h"
#if SQLITE_USER_AUTHENTICATION #if SQLITE_USER_AUTHENTICATION
#include "third_party/sqlite3/sqlite3userauth.inc" #include "third_party/sqlite3/sqlite3userauth.inc"
#endif #endif
@ -10573,6 +10574,7 @@ static void process_sqliterc(
p->in = inSaved; p->in = inSaved;
p->lineno = savedLineno; p->lineno = savedLineno;
sqlite3_free(zBuf); sqlite3_free(zBuf);
errno = 0; /* [jart] clear error */
} }
/* /*