Make some more fixes

This change deletes mkfifo() so that GNU Make on Windows will work in
parallel mode using its pipe-based implementation. There's an example
called greenbean2 now, which shows how to build a scalable web server
for Windows with 10k+ threads. The accuracy of clock_nanosleep is now
significantly improved on Linux.
This commit is contained in:
Justine Tunney 2023-10-09 11:56:21 -07:00
parent 820c3599ed
commit 3b4dbc9fdd
No known key found for this signature in database
GPG key ID: BE714B4575D6E328
22 changed files with 870 additions and 330 deletions

View file

@ -129,8 +129,6 @@ int linkat(int, const char *, int, const char *, int);
int mincore(void *, size_t, unsigned char *);
int mkdir(const char *, unsigned);
int mkdirat(int, const char *, unsigned);
int mkfifo(const char *, unsigned);
int mkfifoat(int, const char *, unsigned);
int mknod(const char *, unsigned, uint64_t);
int nice(int);
int open(const char *, int, ...);

View file

@ -40,7 +40,7 @@ static dontinline int __clk_tck_init(void) {
size_t len;
struct clockinfo_netbsd clock;
if (IsWindows()) {
x = HECTONANOSECONDS;
x = 1000;
} else if (IsXnu() || IsOpenbsd()) {
x = 100;
} else if (IsFreebsd()) {

View file

@ -18,26 +18,22 @@
*/
#include "libc/assert.h"
#include "libc/calls/cp.internal.h"
#include "libc/calls/struct/timespec.h"
#include "libc/calls/struct/timespec.internal.h"
#include "libc/dce.h"
#include "libc/errno.h"
#include "libc/intrin/describeflags.internal.h"
#include "libc/intrin/strace.internal.h"
#include "libc/intrin/weaken.h"
#include "libc/nexgen32e/yield.h"
#include "libc/runtime/clktck.h"
#include "libc/str/str.h"
#include "libc/sysv/consts/clock.h"
#include "libc/sysv/consts/timer.h"
#include "libc/sysv/errfuns.h"
#include "libc/thread/thread.h"
static errno_t sys_clock_nanosleep(int clock, int flags,
const struct timespec *req,
struct timespec *rem) {
int e, rc;
static int sys_clock_nanosleep(int clock, int flags, //
const struct timespec *req,
struct timespec *rem) {
int rc;
BEGIN_CANCELATION_POINT;
e = errno;
if (IsLinux() || IsFreebsd() || IsNetbsd()) {
rc = __sys_clock_nanosleep(clock, flags, req, rem);
} else if (IsXnu()) {
@ -49,102 +45,59 @@ static errno_t sys_clock_nanosleep(int clock, int flags,
} else {
rc = enosys();
}
if (rc == -1) {
rc = errno;
errno = e;
}
END_CANCELATION_POINT;
#if 0
STRACE("sys_clock_nanosleep(%s, %s, %s, [%s]) → %d% m",
DescribeClockName(clock), DescribeSleepFlags(flags),
DescribeTimespec(0, req), DescribeTimespec(rc, rem), rc);
#endif
return rc;
}
// determine how many nanoseconds it takes before clock_nanosleep()
// starts sleeping with 90 percent accuracy; in other words when we
// ask it to sleep 1 second, it (a) must NEVER sleep for less time,
// and (b) does not sleep for longer than 1.1 seconds of time. what
// ever is below that, thanks but no thanks, we'll just spin yield,
static struct timespec GetNanosleepThreshold(void) {
return timespec_fromnanos(1000000000 / CLK_TCK);
}
static int cosmo_clock_nanosleep(int clock, int flags,
const struct timespec *req,
struct timespec *rem) {
static errno_t CheckCancel(void) {
if (_weaken(pthread_testcancel_np)) {
return _weaken(pthread_testcancel_np)();
// pick clocks
int time_clock;
int sleep_clock;
if (clock == CLOCK_REALTIME || //
clock == CLOCK_REALTIME_PRECISE) {
time_clock = clock;
sleep_clock = CLOCK_REALTIME_PRECISE;
} else if (clock == CLOCK_MONOTONIC || //
clock == CLOCK_MONOTONIC_PRECISE) {
time_clock = clock;
sleep_clock = CLOCK_MONOTONIC_PRECISE;
} else if (clock == CLOCK_REALTIME_COARSE || //
clock == CLOCK_REALTIME_FAST) {
return sys_clock_nanosleep(CLOCK_REALTIME, flags, req, rem);
} else if (clock == CLOCK_MONOTONIC_COARSE || //
clock == CLOCK_MONOTONIC_FAST) {
return sys_clock_nanosleep(CLOCK_MONOTONIC, flags, req, rem);
} else {
return 0;
return sys_clock_nanosleep(clock, flags, req, rem);
}
}
static errno_t SpinNanosleep(int clock, int flags, const struct timespec *req,
struct timespec *rem) {
errno_t rc;
struct timespec now, start, elapsed;
if ((rc = CheckCancel())) {
if (rc == EINTR && !flags && rem) {
*rem = *req;
}
return rc;
}
unassert(!clock_gettime(CLOCK_REALTIME, &start));
for (;;) {
spin_yield();
unassert(!clock_gettime(CLOCK_REALTIME, &now));
if (flags & TIMER_ABSTIME) {
if (timespec_cmp(now, *req) >= 0) {
return 0;
}
if ((rc = CheckCancel())) {
return rc;
}
} else {
if (timespec_cmp(now, start) < 0) continue;
elapsed = timespec_sub(now, start);
if ((rc = CheckCancel())) {
if (rc == EINTR && rem) {
if (timespec_cmp(elapsed, *req) >= 0) {
bzero(rem, sizeof(*rem));
} else {
*rem = elapsed;
}
}
return rc;
}
if (timespec_cmp(elapsed, *req) >= 0) {
return 0;
// sleep bulk of time in kernel
struct timespec start, deadline, remain, waitfor, now;
struct timespec quantum = timespec_fromnanos(1000000000 / CLK_TCK);
unassert(!clock_gettime(time_clock, &start));
deadline = flags & TIMER_ABSTIME ? *req : timespec_add(start, *req);
if (timespec_cmp(start, deadline) >= 0) return 0;
remain = timespec_sub(deadline, start);
if (timespec_cmp(remain, quantum) > 0) {
waitfor = timespec_sub(remain, quantum);
if (sys_clock_nanosleep(sleep_clock, 0, &waitfor, rem) == -1) {
if (rem && errno == EINTR) {
*rem = timespec_add(*rem, quantum);
}
return -1;
}
}
}
// clock_gettime() takes a few nanoseconds but sys_clock_nanosleep()
// is incapable of sleeping for less than a millisecond on platforms
// such as windows and it's not much prettior on unix systems either
static bool ShouldUseSpinNanosleep(int clock, int flags,
const struct timespec *req) {
errno_t e;
struct timespec now;
if (clock != CLOCK_REALTIME && //
clock != CLOCK_REALTIME_PRECISE && //
clock != CLOCK_MONOTONIC && //
clock != CLOCK_MONOTONIC_RAW && //
clock != CLOCK_MONOTONIC_PRECISE) {
return false;
}
if (!flags) {
return timespec_cmp(*req, GetNanosleepThreshold()) < 0;
}
e = errno;
if (clock_gettime(clock, &now)) {
// punt to the nanosleep system call
errno = e;
return false;
}
return timespec_cmp(*req, now) < 0 ||
timespec_cmp(timespec_sub(*req, now), GetNanosleepThreshold()) < 0;
// spin through final scheduling quantum
do unassert(!clock_gettime(time_clock, &now));
while (timespec_cmp(now, deadline) < 0);
return 0;
}
/**
@ -180,8 +133,11 @@ static bool ShouldUseSpinNanosleep(int clock, int flags,
* This function has first-class support on Linux, FreeBSD, and NetBSD;
* on OpenBSD it's good; on XNU it's bad; and on Windows it's ugly.
*
* @param clock should be `CLOCK_REALTIME` and you may consult the docs
* of your preferred platforms to see what other clocks might work
* @param clock may be
* - `CLOCK_REALTIME` to have nanosecond-accurate wall time sleeps
* - `CLOCK_REALTIME_COARSE` to not spin through scheduler quantum
* - `CLOCK_MONOTONIC` to base the sleep off the monotinic clock
* - `CLOCK_MONOTONIC_COARSE` to once again not do userspace spin
* @param flags can be 0 for relative and `TIMER_ABSTIME` for absolute
* @param req can be a relative or absolute time, depending on `flags`
* @param rem shall be updated with the remainder of unslept time when
@ -201,26 +157,21 @@ static bool ShouldUseSpinNanosleep(int clock, int flags,
* @returnserrno
* @norestart
*/
errno_t clock_nanosleep(int clock, int flags, const struct timespec *req,
errno_t clock_nanosleep(int clock, int flags, //
const struct timespec *req, //
struct timespec *rem) {
int rc;
// threads on win32 stacks call this so we can't asan check *ts
LOCKTRACE("clock_nanosleep(%s, %s, %s) → ...", DescribeClockName(clock),
DescribeSleepFlags(flags), DescribeTimespec(0, req));
if (IsMetal()) {
rc = ENOSYS;
} else if (clock == 127 || //
(flags & ~TIMER_ABSTIME) || //
req->tv_sec < 0 || //
!(0 <= req->tv_nsec && req->tv_nsec <= 999999999)) {
rc = EINVAL;
} else if (ShouldUseSpinNanosleep(clock, flags, req)) {
rc = SpinNanosleep(clock, flags, req, rem);
} else {
rc = sys_clock_nanosleep(clock, flags, req, rem);
return ENOSYS;
}
TIMETRACE("clock_nanosleep(%s, %s, %s, [%s]) → %s", DescribeClockName(clock),
DescribeSleepFlags(flags), DescribeTimespec(0, req),
DescribeTimespec(rc, rem), DescribeErrno(rc));
return rc;
if (clock == 127 || //
(flags & ~TIMER_ABSTIME) || //
req->tv_sec < 0 || //
!(0 <= req->tv_nsec && req->tv_nsec <= 999999999)) {
return EINVAL;
}
errno_t old = errno;
int rc = cosmo_clock_nanosleep(clock, flags, req, rem);
errno_t err = !rc ? 0 : errno;
errno = old;
return err;
}

View file

@ -1,62 +0,0 @@
/*-*- 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 2020 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/syscall-sysv.internal.h"
#include "libc/dce.h"
#include "libc/errno.h"
#include "libc/intrin/asan.internal.h"
#include "libc/intrin/strace.internal.h"
#include "libc/sysv/consts/at.h"
#include "libc/sysv/consts/s.h"
#include "libc/sysv/errfuns.h"
/**
* Creates filesystem inode.
*
* @param mode is octal mode, e.g. 0600; needs to be or'd with one of:
* S_IFDIR: directory
* S_IFIFO: named pipe
* S_IFREG: regular file
* S_IFSOCK: named socket
* S_IFBLK: block device (root has authorization)
* S_IFCHR: character device (root has authorization)
* @param dev it's complicated
* @return 0 on success, or -1 w/ errno
* @asyncsignalsafe
*/
int mknod(const char *path, uint32_t mode, uint64_t dev) {
int e, rc;
if (IsAsan() && !__asan_is_valid_str(path)) return efault();
if (mode & S_IFREG) return creat(path, mode & ~S_IFREG);
if (mode & S_IFDIR) return mkdir(path, mode & ~S_IFDIR);
if (mode & S_IFIFO) return mkfifo(path, mode & ~S_IFIFO);
if (!IsWindows()) {
/* TODO(jart): Whys there code out there w/ S_xxx passed via dev? */
e = errno;
rc = sys_mknod(path, mode, dev);
if (rc == -1 && rc == ENOSYS) {
errno = e;
rc = sys_mknodat(AT_FDCWD, path, mode, dev);
}
} else {
rc = enosys();
}
STRACE("mknod(%#s, %#o, %#lx) → %d% m", path, mode, dev, rc);
return rc;
}

View file

@ -16,52 +16,47 @@
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/assert.h"
#include "libc/calls/calls.h"
#include "libc/calls/internal.h"
#include "libc/calls/struct/sigset.internal.h"
#include "libc/errno.h"
#include "libc/intrin/atomic.h"
#include "libc/nt/enum/wait.h"
#include "libc/nt/runtime.h"
#include "libc/nt/synchronization.h"
#include "libc/sysv/errfuns.h"
#include "libc/thread/posixthread.internal.h"
#include "libc/thread/thread.h"
#include "libc/thread/tls.h"
#ifdef __x86_64__
// each thread has its own pt_futex which is used by both posix signals
// and posix thread cancelation to "park" blocking operations that dont
// need win32 overlapped i/o. the delay is advisory and may be -1 which
// means wait forever. these functions don't guarantee to wait the full
// duration. other threads wanting to deliver a signal, can wake parked
// futexes without releasing them, just to stir up activity. if a futex
// is both woken and released then the cancelation point shall generate
// an eintr. we also abstract checking for signals & thread cancelation
static textwindows int _park_wait(uint32_t msdelay, bool restartable,
struct PosixThread *pt) {
int got, expect = 0;
if (_check_cancel() == -1) return -1;
if (_check_signal(restartable) == -1) return -1;
WaitOnAddress(&pt->pt_futex, &expect, sizeof(expect), msdelay);
got = atomic_load_explicit(&pt->pt_futex, memory_order_acquire);
return got != expect ? eintr() : 0;
}
static textwindows int _park_thread(uint32_t msdelay, sigset_t waitmask,
bool restartable) {
int rc;
int64_t sem;
sigset_t om;
uint32_t wi;
struct PosixThread *pt;
pt = _pthread_self();
pt->pt_flags &= ~PT_RESTARTABLE;
if (restartable) pt->pt_flags |= PT_RESTARTABLE;
atomic_store_explicit(&pt->pt_futex, 0, memory_order_release);
atomic_store_explicit(&pt->pt_blocker, &pt->pt_futex, memory_order_release);
pt->pt_semaphore = sem = CreateSemaphore(0, 0, 1, 0);
pthread_cleanup_push((void *)CloseHandle, (void *)sem);
atomic_store_explicit(&pt->pt_blocker, PT_BLOCKER_SEM, memory_order_release);
om = __sig_beginwait(waitmask);
rc = _park_wait(msdelay, restartable, pt);
if (rc == -1 && errno == EINTR) _check_cancel();
if ((rc = _check_cancel()) != -1 && (rc = _check_signal(restartable)) != -1) {
unassert((wi = WaitForSingleObject(sem, msdelay)) != -1u);
if (wi != kNtWaitTimeout) {
rc = eintr();
_check_cancel();
}
}
__sig_finishwait(om);
atomic_store_explicit(&pt->pt_blocker, PT_BLOCKER_CPU, memory_order_release);
pt->pt_flags &= ~PT_RESTARTABLE;
pthread_cleanup_pop(true);
pt->pt_semaphore = 0;
return rc;
}

View file

@ -727,7 +727,6 @@ static textwindows int WaitForConsole(struct Fd *f, sigset_t waitmask) {
pt->pt_flags |= PT_RESTARTABLE;
pt->pt_semaphore = sem = CreateSemaphore(0, 0, 1, 0);
pthread_cleanup_push((void *)CloseHandle, (void *)sem);
atomic_store_explicit(&pt->pt_futex, 0, memory_order_release);
atomic_store_explicit(&pt->pt_blocker, PT_BLOCKER_SEM, memory_order_release);
m = __sig_beginwait(waitmask);
if ((rc = _check_cancel()) != -1 && (rc = _check_signal(true)) != -1) {

View file

@ -1,7 +1,7 @@
/*-*- 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
/*-*- 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 2020 Justine Alexandra Roberts Tunney
Copyright 2023 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
@ -16,36 +16,58 @@
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/calls/calls.h"
#include "libc/calls/syscall-sysv.internal.h"
#include "libc/dce.h"
#include "libc/errno.h"
#include "libc/intrin/asan.internal.h"
#include "libc/intrin/strace.internal.h"
#include "libc/nt/ipc.h"
#include "libc/sysv/consts/at.h"
#include "libc/sysv/consts/s.h"
#include "libc/sysv/errfuns.h"
#include "libc/macros.internal.h"
.text.windows
#define NT_PIPE_PATH_PREFIX u"\\\\.\\pipe\\"
// Restores thread to state before signal.
//
// @param rdi points to ucontext_t with machine state
// @noreturn
__sig_restore:
/**
* Creates named pipe.
*
* @param mode is octal, e.g. 0600 for owner-only read/write
* @return 0 on success, or -1 w/ errno
* @asyncsignalsafe
*/
int mkfifo(const char *pathname, unsigned mode) {
// TODO(jart): Windows?
int rc;
if (IsAsan() && !__asan_is_valid_str(pathname)) {
rc = efault();
} else if (IsLinux()) {
rc = sys_mknodat(AT_FDCWD, pathname, mode | S_IFIFO, 0);
} else {
rc = sys_mkfifo(pathname, mode);
}
STRACE("mkfifo(%#s, %#o) %d% m", pathname, mode, rc);
return rc;
}
// restore vector registers
lea 608(%rdi),%rax
movaps -0x80(%rax),%xmm0
movaps -0x70(%rax),%xmm1
movaps -0x60(%rax),%xmm2
movaps -0x50(%rax),%xmm3
movaps -0x40(%rax),%xmm4
movaps -0x30(%rax),%xmm5
movaps -0x20(%rax),%xmm6
movaps -0x10(%rax),%xmm7
movaps 0x00(%rax),%xmm8
movaps 0x10(%rax),%xmm9
movaps 0x20(%rax),%xmm10
movaps 0x30(%rax),%xmm11
movaps 0x40(%rax),%xmm12
movaps 0x50(%rax),%xmm13
movaps 0x60(%rax),%xmm14
movaps 0x70(%rax),%xmm15
// restore general registers
lea 80(%rdi),%rax
mov -40(%rax),%r8
mov -32(%rax),%r9
mov -24(%rax),%r10
mov -16(%rax),%r11
mov -8(%rax),%r12
mov 0(%rax),%r13
mov 8(%rax),%r14
mov 16(%rax),%r15
mov 24(%rax),%rdi
mov 32(%rax),%rsi
mov 48(%rax),%rbx
mov 56(%rax),%rdx
mov 72(%rax),%rcx
mov 40(%rax),%rbp
mov 80(%rax),%rsp
// this clobbers the red zone
push 88(%rax) // rip
push 64(%rax) // rax
push 96(%rax) // flags
popf
pop %rax
ret
.endfn __sig_restore,globl

View file

@ -32,6 +32,8 @@
#include "libc/errno.h"
#include "libc/fmt/itoa.h"
#include "libc/intrin/atomic.h"
#include "libc/intrin/bsf.h"
#include "libc/intrin/bsr.h"
#include "libc/intrin/describebacktrace.internal.h"
#include "libc/intrin/kprintf.h"
#include "libc/intrin/popcnt.h"
@ -64,16 +66,10 @@
*/
struct SignalFrame {
struct PosixThread *pt;
struct NtContext *nc;
unsigned rva;
unsigned flags;
siginfo_t si;
};
struct ContextFrame {
struct SignalFrame sf;
struct NtContext nc;
ucontext_t ctx;
};
static textwindows bool __sig_ignored_by_default(int sig) {
@ -94,8 +90,7 @@ textwindows void __sig_delete(int sig) {
__sig.pending &= ~(1ull << (sig - 1));
_pthread_lock();
for (e = dll_last(_pthread_list); e; e = dll_prev(_pthread_list, e)) {
struct PosixThread *pt = POSIXTHREAD_CONTAINER(e);
pt->tib->tib_sigpending &= ~(1ull << (sig - 1));
POSIXTHREAD_CONTAINER(e)->tib->tib_sigpending &= ~(1ull << (sig - 1));
}
_pthread_unlock();
}
@ -160,7 +155,7 @@ textwindows int __sig_raise(int sig, int sic) {
if (!__sig_start(pt, sig, &rva, &flags)) return 0;
siginfo_t si = {.si_signo = sig, .si_code = sic};
struct NtContext nc;
nc.ContextFlags = kNtContextAll;
nc.ContextFlags = kNtContextFull;
GetThreadContext(GetCurrentThread(), &nc);
_ntcontext2linux(&ctx, &nc);
pt->tib->tib_sigmask |= __sighandmask[sig];
@ -175,7 +170,8 @@ textwindows int __sig_raise(int sig, int sic) {
__sig_handler(rva),
DescribeSigset(0, (sigset_t *)&pt->tib->tib_sigmask),
DescribeSigset(0, &ctx.uc_sigmask));
pt->tib->tib_sigmask = ctx.uc_sigmask;
atomic_store_explicit(&pt->tib->tib_sigmask, ctx.uc_sigmask,
memory_order_release);
return (flags & SA_RESTART) ? 2 : 1;
}
@ -223,41 +219,17 @@ textwindows void __sig_cancel(struct PosixThread *pt, int sig, unsigned flags) {
WakeByAddressSingle(blocker);
}
static textwindows wontreturn void __sig_panic(const char *msg) {
#ifndef TINY
char s[128], *p = s;
p = stpcpy(p, "sig panic: ");
p = stpcpy(p, msg);
p = stpcpy(p, " failed w/ ");
p = FormatInt32(p, GetLastError());
*p++ = '\n';
WriteFile(GetStdHandle(kNtStdErrorHandle), s, p - s, 0, 0);
#endif
TerminateThisProcess(SIGVTALRM);
}
static textwindows wontreturn void __sig_tramp(struct SignalFrame *sf) {
ucontext_t ctx = {0};
int sig = sf->si.si_signo;
_ntcontext2linux(&ctx, sf->nc);
ctx.uc_sigmask = sf->pt->tib->tib_sigmask;
sf->pt->tib->tib_sigmask |= __sighandmask[sig];
if (!(sf->flags & SA_NODEFER)) {
sf->pt->tib->tib_sigmask |= 1ull << (sig - 1);
}
++__sig.count;
NTTRACE("entering __sig_tramp(%G, %t) with mask %s → %s", sig,
__sig_handler(sf->rva), DescribeSigset(0, &ctx.uc_sigmask),
DescribeSigset(0, (sigset_t *)&sf->pt->tib->tib_sigmask));
__sig_handler(sf->rva)(sig, &sf->si, &ctx);
NTTRACE("leaving __sig_tramp(%G, %t) with mask %s → %s", sig,
__sig_handler(sf->rva),
DescribeSigset(0, (sigset_t *)&sf->pt->tib->tib_sigmask),
DescribeSigset(0, &ctx.uc_sigmask));
sf->pt->tib->tib_sigmask = ctx.uc_sigmask;
_ntlinux2context(sf->nc, &ctx);
SetThreadContext(GetCurrentThread(), sf->nc);
__sig_panic("SetThreadContext(GetCurrentThread)");
int sig = sf->si.si_signo;
sigset_t blocksigs = __sighandmask[sig];
if (!(sf->flags & SA_NODEFER)) blocksigs |= 1ull << (sig - 1);
sf->ctx.uc_sigmask = atomic_fetch_or_explicit(
&__get_tls()->tib_sigmask, blocksigs, memory_order_acq_rel);
__sig_handler(sf->rva)(sig, &sf->si, &sf->ctx);
atomic_store_explicit(&__get_tls()->tib_sigmask, sf->ctx.uc_sigmask,
memory_order_release);
__sig_restore(&sf->ctx);
}
static textwindows int __sig_killer(struct PosixThread *pt, int sig, int sic) {
@ -278,7 +250,7 @@ static textwindows int __sig_killer(struct PosixThread *pt, int sig, int sic) {
return 0;
}
struct NtContext nc;
nc.ContextFlags = kNtContextAll;
nc.ContextFlags = kNtContextFull;
if (!GetThreadContext(th, &nc)) {
STRACE("GetThreadContext failed w/ %d", GetLastError());
return ESRCH;
@ -287,20 +259,18 @@ static textwindows int __sig_killer(struct PosixThread *pt, int sig, int sic) {
if (__sig_should_use_altstack(flags, pt->tib)) {
sp = (uintptr_t)pt->tib->tib_sigstack_addr + pt->tib->tib_sigstack_size;
} else {
sp = (nc.Rsp - 128 - sizeof(struct ContextFrame)) & -16;
sp = (nc.Rsp - 128 - sizeof(struct SignalFrame)) & -16;
}
struct ContextFrame *cf = (struct ContextFrame *)sp;
bzero(&cf->sf.si, sizeof(cf->sf.si));
memcpy(&cf->nc, &nc, sizeof(nc));
cf->sf.pt = pt;
cf->sf.rva = rva;
cf->sf.nc = &cf->nc;
cf->sf.flags = flags;
cf->sf.si.si_code = sic;
cf->sf.si.si_signo = sig;
struct SignalFrame *sf = (struct SignalFrame *)sp;
_ntcontext2linux(&sf->ctx, &nc);
bzero(&sf->si, sizeof(sf->si));
sf->rva = rva;
sf->flags = flags;
sf->si.si_code = sic;
sf->si.si_signo = sig;
*(uintptr_t *)(sp -= sizeof(uintptr_t)) = nc.Rip;
nc.Rip = (intptr_t)__sig_tramp;
nc.Rdi = (intptr_t)&cf->sf;
nc.Rdi = (intptr_t)sf;
nc.Rsp = sp;
if (!SetThreadContext(th, &nc)) {
STRACE("SetThreadContext failed w/ %d", GetLastError());
@ -473,7 +443,8 @@ static void __sig_unmaskable(struct NtExceptionPointers *ep, int code, int sig,
tib->tib_sigmask |= 1ull << (sig - 1);
}
__sig_handler(rva)(sig, &si, &ctx);
tib->tib_sigmask = ctx.uc_sigmask;
atomic_store_explicit(&tib->tib_sigmask, ctx.uc_sigmask,
memory_order_release);
_ntlinux2context(ep->ContextRecord, &ctx);
}
@ -482,10 +453,8 @@ void __stack_call(struct NtExceptionPointers *, int, int, struct CosmoTib *,
struct CosmoTib *),
void *);
//
// abashed the devil stood
// and felt how awful goodness is
//
// abashed the devil stood
// and felt how awful goodness is
__msabi dontinstrument unsigned __sig_crash(struct NtExceptionPointers *ep) {
// translate win32 to unix si_signo and si_code
@ -539,23 +508,20 @@ __msabi textwindows dontinstrument bool32 __sig_console(uint32_t dwCtrlType) {
return true;
}
static textwindows int __sig_checkem(atomic_ulong *sigs, struct CosmoTib *tib,
const char *thing, int id) {
int handler_was_called = 0;
uint64_t pending, masked, deliverable;
static textwindows int __sig_checker(atomic_ulong *sigs, struct CosmoTib *tib) {
int sig, handler_was_called = 0;
sigset_t bit, pending, masked, deliverable;
pending = atomic_load_explicit(sigs, memory_order_acquire);
masked = atomic_load_explicit(&tib->tib_sigmask, memory_order_acquire);
deliverable = pending & ~masked;
POLLTRACE("%s %d blocks %d sigs w/ %d pending and %d deliverable", thing, id,
popcnt(masked), popcnt(pending), popcnt(deliverable));
if (deliverable) {
for (int sig = 1; sig <= 64; ++sig) {
if ((deliverable & (1ull << (sig - 1))) &&
atomic_fetch_and(sigs, ~(1ull << (sig - 1))) & (1ull << (sig - 1))) {
if ((deliverable = pending & ~masked)) {
do {
sig = _bsf(deliverable) + 1;
bit = 1ull << (sig - 1);
if (atomic_fetch_and_explicit(sigs, ~bit, memory_order_acq_rel) & bit) {
STRACE("found pending %G we can raise now", sig);
handler_was_called |= __sig_raise(sig, SI_KERNEL);
}
}
} while ((deliverable &= ~bit));
}
return handler_was_called;
}
@ -567,10 +533,8 @@ static textwindows int __sig_checkem(atomic_ulong *sigs, struct CosmoTib *tib,
textwindows int __sig_check(void) {
int handler_was_called = false;
struct CosmoTib *tib = __get_tls();
handler_was_called |=
__sig_checkem(&tib->tib_sigpending, tib, "tid", tib->tib_tid);
handler_was_called |= __sig_checkem(&__sig.pending, tib, "pid", getpid());
POLLTRACE("__sig_check() → %d", handler_was_called);
handler_was_called |= __sig_checker(&tib->tib_sigpending, tib);
handler_was_called |= __sig_checker(&__sig.pending, tib);
return handler_was_called;
}

View file

@ -106,6 +106,7 @@ int getcontext(ucontext_t *) dontthrow;
int setcontext(const ucontext_t *) dontthrow;
int swapcontext(ucontext_t *, const ucontext_t *) dontthrow returnstwice;
void makecontext(ucontext_t *, void (*)(), int, ...) dontthrow nocallback;
void __sig_restore(const ucontext_t *) wontreturn;
COSMOPOLITAN_C_END_
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */

View file

@ -104,12 +104,8 @@ textwindows int sys_execve_nt(const char *program, char *const argv[],
// give child to libc/proc/proc.c worker thread in parent
int64_t handle;
if (!DuplicateHandle(GetCurrentProcess(), pi.hProcess, hParentProcess,
&handle, 0, false, kNtDuplicateSameAccess)) {
kprintf("failed to duplicate handle from %P into %d due to %s\n", ppid,
strerror(GetLastError()));
_Exit(1);
}
unassert(!DuplicateHandle(GetCurrentProcess(), pi.hProcess, hParentProcess,
&handle, 0, false, kNtDuplicateSameAccess));
unassert(!(handle & 0xFFFFFFFFFF000000));
TerminateThisProcess(0x23000000u | handle);
}

View file

@ -136,6 +136,7 @@ static abi wontreturn void WinInit(const char16_t *cmdline) {
m |= kNtEnableMouseInput | kNtEnableWindowInput |
kNtEnableProcessedInput;
} else {
m &= ~kNtDisableNewlineAutoReturn;
m |= kNtEnableProcessedOutput | kNtEnableVirtualTerminalProcessing;
}
__imp_SetConsoleMode(h, m);

View file

@ -17,13 +17,13 @@
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/assert.h"
#include "libc/errno.h"
#include "libc/intrin/bsr.h"
#include "libc/nt/winsock.h"
#include "libc/sock/internal.h"
#include "libc/sock/syscall_fd.internal.h"
#include "libc/sysv/errfuns.h"
#ifdef __x86_64__
#include "libc/errno.h"
#include "libc/sock/yoink.inc"
static textwindows int64_t __connect_block(int64_t fh, unsigned eventbit,

View file

@ -91,7 +91,6 @@ struct PosixThread {
struct Dll list; // list of threads
struct _pthread_cleanup_buffer *pt_cleanup;
_Atomic(_Atomic(int) *) pt_blocker;
_Atomic(int) pt_futex;
int64_t pt_semaphore;
intptr_t pt_iohandle;
void *pt_ioverlap;