Clean up the clone() code a bit

This commit is contained in:
Justine Tunney 2022-05-17 07:40:00 -07:00
parent ce71677156
commit 2743f3d012
20 changed files with 252 additions and 150 deletions

View file

@ -18,11 +18,11 @@
#include "libc/fmt/conv.h" #include "libc/fmt/conv.h"
#include "libc/fmt/itoa.h" #include "libc/fmt/itoa.h"
#include "libc/intrin/kprintf.h" #include "libc/intrin/kprintf.h"
#include "libc/intrin/threaded.h"
#include "libc/log/check.h" #include "libc/log/check.h"
#include "libc/log/log.h" #include "libc/log/log.h"
#include "libc/macros.internal.h" #include "libc/macros.internal.h"
#include "libc/mem/mem.h" #include "libc/mem/mem.h"
#include "libc/nexgen32e/threaded.h"
#include "libc/runtime/runtime.h" #include "libc/runtime/runtime.h"
#include "libc/runtime/sysconf.h" #include "libc/runtime/sysconf.h"
#include "libc/sock/sock.h" #include "libc/sock/sock.h"

View file

@ -35,12 +35,11 @@ privileged wontreturn void _Exit1(int rc) {
struct WinThread *wt; struct WinThread *wt;
STRACE("_Exit1(%d)", rc); STRACE("_Exit1(%d)", rc);
if (!IsWindows() && !IsMetal()) { if (!IsWindows() && !IsMetal()) {
register long r10 asm("r10") = 0; asm volatile("xor\t%%r10d,%%r10d\n\t"
asm volatile("syscall" "syscall"
: /* no outputs */ : /* no outputs */
: "a"(__NR_exit), "D"(IsLinux() ? rc : 0), "S"(0), "d"(0), : "a"(__NR_exit), "D"(IsLinux() ? rc : 0), "S"(0), "d"(0)
"r"(r10) : "rcx", "r10", "r11", "memory");
: "rcx", "r11", "memory");
} else if (IsWindows()) { } else if (IsWindows()) {
ExitThread(rc); ExitThread(rc);
} }

View file

@ -18,7 +18,7 @@
*/ */
#include "libc/calls/calls.h" #include "libc/calls/calls.h"
#include "libc/dce.h" #include "libc/dce.h"
#include "libc/intrin/threaded.h" #include "libc/nexgen32e/threaded.h"
#include "libc/nt/thread.h" #include "libc/nt/thread.h"
/** /**

View file

@ -31,11 +31,11 @@
#include "libc/intrin/lockcmpxchg.h" #include "libc/intrin/lockcmpxchg.h"
#include "libc/intrin/nomultics.internal.h" #include "libc/intrin/nomultics.internal.h"
#include "libc/intrin/spinlock.h" #include "libc/intrin/spinlock.h"
#include "libc/intrin/threaded.h"
#include "libc/limits.h" #include "libc/limits.h"
#include "libc/log/internal.h" #include "libc/log/internal.h"
#include "libc/macros.internal.h" #include "libc/macros.internal.h"
#include "libc/nexgen32e/rdtsc.h" #include "libc/nexgen32e/rdtsc.h"
#include "libc/nexgen32e/threaded.h"
#include "libc/nexgen32e/uart.internal.h" #include "libc/nexgen32e/uart.internal.h"
#include "libc/nt/process.h" #include "libc/nt/process.h"
#include "libc/nt/runtime.h" #include "libc/nt/runtime.h"

View file

@ -1,16 +0,0 @@
#ifndef COSMOPOLITAN_LIBC_INTRIN_THREADED_H_
#define COSMOPOLITAN_LIBC_INTRIN_THREADED_H_
#if !(__ASSEMBLER__ + __LINKER__ + 0)
COSMOPOLITAN_C_START_
extern bool __threaded;
extern bool __tls_enabled;
extern unsigned __tls_index;
void *__initialize_tls(char[hasatleast 64]);
void __install_tls(char[hasatleast 64]);
char *__get_tls(void);
COSMOPOLITAN_C_END_
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
#endif /* COSMOPOLITAN_LIBC_INTRIN_THREADED_H_ */

View file

@ -20,7 +20,7 @@
#include "libc/calls/calls.h" #include "libc/calls/calls.h"
#include "libc/dce.h" #include "libc/dce.h"
#include "libc/errno.h" #include "libc/errno.h"
#include "libc/intrin/threaded.h" #include "libc/nexgen32e/threaded.h"
#include "libc/nt/thread.h" #include "libc/nt/thread.h"
#include "libc/nt/thunk/msabi.h" #include "libc/nt/thunk/msabi.h"
#include "libc/sysv/consts/nrlinux.h" #include "libc/sysv/consts/nrlinux.h"

View file

@ -0,0 +1,38 @@
/*-*- 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 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/macros.internal.h"
// Checks that stack is 16-byte aligned.
//
// This function crashes if called with a misaligned stack.
_checkstackalign:
push %rbp
mov %rsp,%rbp
/ allocate sixteen bytes
push %rax
push %rax
/ put a value in it
xorps %xmm0,%xmm0
movaps %xmm0,-16(%rbp)
leave
ret
.endfn _checkstackalign,globl

View file

@ -7,6 +7,7 @@ extern long kHalfCache3;
void imapxlatab(void *); void imapxlatab(void *);
void insertionsort(int32_t *, size_t); void insertionsort(int32_t *, size_t);
void _checkstackalign(void);
int64_t div10int64(int64_t) libcesque pureconst; int64_t div10int64(int64_t) libcesque pureconst;
int64_t div100int64(int64_t) libcesque pureconst; int64_t div100int64(int64_t) libcesque pureconst;

View file

@ -16,7 +16,7 @@
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/intrin/threaded.h" #include "libc/nexgen32e/threaded.h"
bool __threaded; bool __threaded;
bool __tls_enabled; bool __tls_enabled;

39
libc/nexgen32e/threaded.h Normal file
View file

@ -0,0 +1,39 @@
#ifndef COSMOPOLITAN_LIBC_NEXGEN32E_THREADED_H_
#define COSMOPOLITAN_LIBC_NEXGEN32E_THREADED_H_
#include "libc/dce.h"
#if !(__ASSEMBLER__ + __LINKER__ + 0)
COSMOPOLITAN_C_START_
extern bool __threaded;
extern bool __tls_enabled;
extern unsigned __tls_index;
void *__initialize_tls(char[hasatleast 64]);
void __install_tls(char[hasatleast 64]);
#if defined(__GNUC__) && defined(__x86_64__)
/**
* Returns address of thread information block.
*
* This function must not be called until TLS is initialized.
*
* @see __install_tls()
* @see clone()
*/
static noasan inline char *__get_tls(void) {
char *tib, *lin = (char *)0x30;
if (IsLinux() || IsFreebsd() || IsNetbsd() || IsOpenbsd()) {
asm("mov\t%%fs:(%1),%0" : "=a"(tib) : "r"(lin));
} else {
asm("mov\t%%gs:(%1),%0" : "=a"(tib) : "r"(lin));
if (IsWindows()) {
tib = *(char **)(tib + 0x1480 + __tls_index * 8);
}
}
return tib;
}
#endif /* GNU x86-64 */
COSMOPOLITAN_C_END_
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
#endif /* COSMOPOLITAN_LIBC_NEXGEN32E_THREADED_H_ */

View file

@ -26,7 +26,7 @@
#include "libc/intrin/asan.internal.h" #include "libc/intrin/asan.internal.h"
#include "libc/intrin/kprintf.h" #include "libc/intrin/kprintf.h"
#include "libc/intrin/spinlock.h" #include "libc/intrin/spinlock.h"
#include "libc/intrin/threaded.h" #include "libc/nexgen32e/threaded.h"
#include "libc/nt/runtime.h" #include "libc/nt/runtime.h"
#include "libc/nt/thread.h" #include "libc/nt/thread.h"
#include "libc/nt/thunk/msabi.h" #include "libc/nt/thunk/msabi.h"
@ -50,17 +50,32 @@ STATIC_YOINK("gettid"); // for kprintf()
#define LWP_DETACHED 0x00000040 #define LWP_DETACHED 0x00000040
#define LWP_SUSPENDED 0x00000080 #define LWP_SUSPENDED 0x00000080
static char tibdefault[64]; struct CloneArgs {
union {
struct WinThread { int tid;
uint32_t tid; uint32_t utid;
int64_t tid64;
};
int lock;
int flags; int flags;
int *ctid; int *ctid;
void *tls; char *tls;
int (*func)(void *); int (*func)(void *);
void *arg; void *arg;
void *pad; // TODO: Why does FreeBSD clobber this?
}; };
struct __tfork {
void *tf_tcb;
int32_t *tf_tid;
void *tf_stack;
};
static char tibdefault[64];
////////////////////////////////////////////////////////////////////////////////
// THE NEW TECHNOLOGY
uint32_t WinThreadThunk(void *warg); uint32_t WinThreadThunk(void *warg);
asm(".section\t.text.windows,\"ax\",@progbits\n\t" asm(".section\t.text.windows,\"ax\",@progbits\n\t"
".local\tWinThreadThunk\n" ".local\tWinThreadThunk\n"
@ -69,13 +84,14 @@ asm(".section\t.text.windows,\"ax\",@progbits\n\t"
"mov\t%rcx,%rdi\n\t" "mov\t%rcx,%rdi\n\t"
"mov\t%rcx,%rsp\n\t" "mov\t%rcx,%rsp\n\t"
"and\t$-16,%rsp\n\t" "and\t$-16,%rsp\n\t"
"call\tWinThreadMain\n\t" "push\t%rax\n\t"
"jmp\tWinThreadMain\n\t"
".size\tWinThreadThunk,.-WinThreadThunk\n\t" ".size\tWinThreadThunk,.-WinThreadThunk\n\t"
".previous"); ".previous");
__attribute__((__used__, __no_reorder__)) __attribute__((__used__, __no_reorder__))
static textwindows wontreturn void static textwindows wontreturn void
WinThreadMain(struct WinThread *wt) { WinThreadMain(struct CloneArgs *wt) {
int rc; int rc;
if (wt->flags & CLONE_SETTLS) { if (wt->flags & CLONE_SETTLS) {
TlsSetValue(__tls_index, wt->tls); TlsSetValue(__tls_index, wt->tls);
@ -91,16 +107,16 @@ static textwindows int CloneWindows(int (*func)(void *), char *stk,
size_t stksz, int flags, void *arg, size_t stksz, int flags, void *arg,
void *tls, size_t tlssz, int *ctid) { void *tls, size_t tlssz, int *ctid) {
int64_t h; int64_t h;
struct WinThread *wt; struct CloneArgs *wt;
wt = (struct WinThread *)(((intptr_t)(stk + stksz) - wt = (struct CloneArgs *)(((intptr_t)(stk + stksz) -
sizeof(struct WinThread)) & sizeof(struct CloneArgs)) &
-alignof(struct WinThread)); -alignof(struct CloneArgs));
wt->flags = flags; wt->flags = flags;
wt->ctid = ctid; wt->ctid = ctid;
wt->func = func; wt->func = func;
wt->arg = arg; wt->arg = arg;
wt->tls = tls; wt->tls = tls;
if ((h = CreateThread(0, 0, WinThreadThunk, wt, 0, &wt->tid))) { if ((h = CreateThread(0, 0, WinThreadThunk, wt, 0, &wt->utid))) {
CloseHandle(h); CloseHandle(h);
return wt->tid; return wt->tid;
} else { } else {
@ -108,45 +124,49 @@ static textwindows int CloneWindows(int (*func)(void *), char *stk,
} }
} }
////////////////////////////////////////////////////////////////////////////////
// XNU'S NOT UNIX
void XnuThreadThunk(void *pthread, int machport, void *(*func)(void *), void XnuThreadThunk(void *pthread, int machport, void *(*func)(void *),
void *arg, intptr_t *stack, unsigned flags); void *arg, intptr_t *stack, unsigned flags);
asm(".local\tXnuThreadThunk\n" asm(".local\tXnuThreadThunk\n"
"XnuThreadThunk:\n\t" "XnuThreadThunk:\n\t"
"xor\t%ebp,%ebp\n\t" "xor\t%ebp,%ebp\n\t"
"mov\t%r8,%rsp\n\t" "mov\t%r8,%rsp\n\t"
"and\t$-16,%rsp\n\t"
"push\t%rax\n\t"
"jmp\tXnuThreadMain\n\t" "jmp\tXnuThreadMain\n\t"
".size\tXnuThreadThunk,.-XnuThreadThunk"); ".size\tXnuThreadThunk,.-XnuThreadThunk");
__attribute__((__used__, __no_reorder__)) __attribute__((__used__, __no_reorder__))
static wontreturn void static wontreturn void
XnuThreadMain(void *pthread, int tid, int (*func)(void *arg), void *arg, XnuThreadMain(void *pthread, int tid, int (*func)(void *arg), void *arg,
intptr_t *sp, unsigned flags) { struct CloneArgs *wt, unsigned flags) {
int rc; int ax;
sp[1] = tid; wt->tid = tid;
_spunlock(sp); _spunlock(&wt->lock);
if (sp[4] & CLONE_SETTLS) { if (wt->flags & CLONE_SETTLS) {
// XNU uses the same 0x30 offset as the WIN32 TIB x64. They told the // XNU uses the same 0x30 offset as the WIN32 TIB x64. They told the
// Go team at Google that they Apply stands by our ability to use it // Go team at Google that they Apply stands by our ability to use it
// https://github.com/golang/go/issues/23617#issuecomment-376662373 // https://github.com/golang/go/issues/23617#issuecomment-376662373
asm volatile("syscall" asm volatile("syscall"
: "=a"(rc) : "=a"(ax)
: "0"(__NR_thread_fast_set_cthread_self), "D"(sp[3] - 0x30) : "0"(__NR_thread_fast_set_cthread_self), "D"(wt->tls - 0x30)
: "rcx", "r11", "memory", "cc"); : "rcx", "r11", "memory", "cc");
} }
if (sp[4] & CLONE_CHILD_SETTID) { if (wt->flags & CLONE_CHILD_SETTID) {
*(int *)sp[2] = tid; *wt->ctid = tid;
} }
rc = func(arg); _Exit1(func(arg));
_Exit1(rc);
} }
static int CloneXnu(int (*fn)(void *), char *stk, size_t stksz, int flags, static int CloneXnu(int (*fn)(void *), char *stk, size_t stksz, int flags,
void *arg, void *tls, size_t tlssz, int *ctid) { void *arg, void *tls, size_t tlssz, int *ctid) {
int rc; int rc;
bool failed; bool failed;
intptr_t *sp;
static bool once; static bool once;
static int broken; static int broken;
struct CloneArgs *wt;
if (!once) { if (!once) {
if (bsdthread_register(XnuThreadThunk, 0, 0, 0, 0, 0, 0) == -1) { if (bsdthread_register(XnuThreadThunk, 0, 0, 0, 0, 0, 0) == -1) {
broken = errno; broken = errno;
@ -157,38 +177,40 @@ static int CloneXnu(int (*fn)(void *), char *stk, size_t stksz, int flags,
errno = broken; errno = broken;
return -1; return -1;
} }
sp = (intptr_t *)(stk + stksz); wt = (struct CloneArgs *)(((intptr_t)(stk + stksz) -
*--sp = 0; // 5 padding sizeof(struct CloneArgs)) &
*--sp = flags; // 4 clone() flags -alignof(struct CloneArgs));
*--sp = (intptr_t)tls; // 3 thread local storage wt->flags = flags;
*--sp = (intptr_t)ctid; // 2 child tid api wt->ctid = ctid;
*--sp = 0; // 1 receives tid wt->tls = tls;
*--sp = 0; // 0 lock _seizelock(&wt->lock); // TODO: How can we get the tid without locking?
_seizelock(sp); // TODO: How can we get the tid without locking? if ((rc = bsdthread_create(fn, arg, wt, 0, PTHREAD_START_CUSTOM_XNU)) != -1) {
if ((rc = bsdthread_create(fn, arg, sp, 0, PTHREAD_START_CUSTOM_XNU)) != -1) { _spinlock(&wt->lock);
_spinlock(sp); rc = wt->tid;
rc = sp[1];
} }
return rc; return rc;
} }
void FreebsdThreadThunk(void *sp) wontreturn; ////////////////////////////////////////////////////////////////////////////////
// FREE BESIYATA DISHMAYA
void FreebsdThreadThunk(void *) wontreturn;
asm(".local\tFreebsdThreadThunk\n" asm(".local\tFreebsdThreadThunk\n"
"FreebsdThreadThunk:\n\t" "FreebsdThreadThunk:\n\t"
"xor\t%ebp,%ebp\n\t" "xor\t%ebp,%ebp\n\t"
"mov\t%rdi,%rsp\n\t" "mov\t%rdi,%rsp\n\t"
"and\t$-16,%rsp\n\t"
"push\t%rax\n\t"
"jmp\tFreebsdThreadMain\n\t" "jmp\tFreebsdThreadMain\n\t"
".size\tFreebsdThreadThunk,.-FreebsdThreadThunk"); ".size\tFreebsdThreadThunk,.-FreebsdThreadThunk");
__attribute__((__used__, __no_reorder__)) __attribute__((__used__, __no_reorder__))
static wontreturn void static wontreturn void
FreebsdThreadMain(intptr_t *sp) { FreebsdThreadMain(struct CloneArgs *wt) {
int rc; if (wt->flags & CLONE_CHILD_SETTID) {
if (sp[3] & CLONE_CHILD_SETTID) { *wt->ctid = wt->tid;
*(int *)sp[2] = sp[4];
} }
rc = ((int (*)(intptr_t))sp[0])(sp[1]); _Exit1(wt->func(wt->arg));
_Exit1(rc);
} }
static int CloneFreebsd(int (*func)(void *), char *stk, size_t stksz, int flags, static int CloneFreebsd(int (*func)(void *), char *stk, size_t stksz, int flags,
@ -196,22 +218,23 @@ static int CloneFreebsd(int (*func)(void *), char *stk, size_t stksz, int flags,
int ax; int ax;
bool failed; bool failed;
int64_t tid; int64_t tid;
intptr_t *sp; struct CloneArgs *wt;
sp = (intptr_t *)(stk + stksz); wt = (struct CloneArgs *)(((intptr_t)(stk + stksz) -
*--sp = 0; // 5 [padding] sizeof(struct CloneArgs)) &
*--sp = 0; // 4 [child_tid] -alignof(struct CloneArgs));
*--sp = flags; // 3 wt->flags = flags;
*--sp = (intptr_t)ctid; // 2 wt->ctid = ctid;
*--sp = (intptr_t)arg; // 1 wt->tls = tls;
*--sp = (intptr_t)func; // 0 wt->func = func;
wt->arg = arg;
struct thr_param params = { struct thr_param params = {
.start_func = FreebsdThreadThunk, .start_func = FreebsdThreadThunk,
.arg = sp, .arg = wt,
.stack_base = stk, .stack_base = stk,
.stack_size = stksz, .stack_size = stksz,
.tls_base = flags & CLONE_SETTLS ? tls : 0, .tls_base = flags & CLONE_SETTLS ? tls : 0,
.tls_size = flags & CLONE_SETTLS ? tlssz : 0, .tls_size = flags & CLONE_SETTLS ? tlssz : 0,
.child_tid = sp + 4, .child_tid = &wt->tid64,
.parent_tid = &tid, .parent_tid = &tid,
}; };
asm volatile(CFLAG_ASM("syscall") asm volatile(CFLAG_ASM("syscall")
@ -225,13 +248,10 @@ static int CloneFreebsd(int (*func)(void *), char *stk, size_t stksz, int flags,
return tid; return tid;
} }
struct __tfork { ////////////////////////////////////////////////////////////////////////////////
void *tf_tcb; // OPEN BESIYATA DISHMAYA
int32_t *tf_tid;
void *tf_stack;
};
int __tfork(struct __tfork *params, size_t psize, intptr_t *stack); int __tfork(struct __tfork *params, size_t psize, struct CloneArgs *wt);
asm(".section\t.privileged,\"ax\",@progbits\n\t" asm(".section\t.privileged,\"ax\",@progbits\n\t"
".local\t__tfork\n" ".local\t__tfork\n"
"__tfork:\n\t" "__tfork:\n\t"
@ -248,46 +268,50 @@ asm(".section\t.privileged,\"ax\",@progbits\n\t"
"xor\t%ebp,%ebp\n\t" "xor\t%ebp,%ebp\n\t"
"mov\t%r8,%rsp\n\t" "mov\t%r8,%rsp\n\t"
"mov\t%r8,%rdi\n\t" "mov\t%r8,%rdi\n\t"
"and\t$-16,%rsp\n\t"
"push\t%rax\n\t"
"jmp\tOpenbsdThreadMain\n\t" "jmp\tOpenbsdThreadMain\n\t"
".size\t__tfork,.-__tfork\n\t" ".size\t__tfork,.-__tfork\n\t"
".previous"); ".previous");
__attribute__((__used__, __no_reorder__)) __attribute__((__used__, __no_reorder__))
static privileged wontreturn void static privileged wontreturn void
OpenbsdThreadMain(intptr_t *sp) { OpenbsdThreadMain(struct CloneArgs *wt) {
int rc; _Exit1(wt->func(wt->arg));
rc = ((int (*)(intptr_t))sp[0])(sp[1]);
_Exit1(rc);
} }
static int CloneOpenbsd(int (*func)(void *), char *stk, size_t stksz, int flags, static int CloneOpenbsd(int (*func)(void *), char *stk, size_t stksz, int flags,
void *arg, void *tls, size_t tlssz, int *ctid) { void *arg, void *tls, size_t tlssz, int *ctid) {
int tid; int tid;
intptr_t *sp; struct CloneArgs *wt;
struct __tfork params; struct __tfork params;
sp = (intptr_t *)(stk + stksz); wt = (struct CloneArgs *)(((intptr_t)(stk + stksz) -
*--sp = flags; // 3 sizeof(struct CloneArgs)) &
*--sp = (intptr_t)ctid; // 2 -alignof(struct CloneArgs));
*--sp = (intptr_t)arg; // 1 wt->flags = flags;
*--sp = (intptr_t)func; // 0 wt->ctid = ctid;
params.tf_stack = sp; wt->func = func;
wt->arg = arg;
params.tf_stack = wt;
params.tf_tcb = flags & CLONE_SETTLS ? tls : 0; params.tf_tcb = flags & CLONE_SETTLS ? tls : 0;
params.tf_tid = flags & CLONE_CHILD_SETTID ? ctid : 0; params.tf_tid = flags & CLONE_CHILD_SETTID ? ctid : 0;
if ((tid = __tfork(&params, sizeof(params), sp)) < 0) { if ((tid = __tfork(&params, sizeof(params), wt)) < 0) {
errno = -tid; errno = -tid;
tid = -1; tid = -1;
} }
return tid; return tid;
} }
////////////////////////////////////////////////////////////////////////////////
// NET BESIYATA DISHMAYA
static wontreturn void NetbsdThreadMain(void *arg, int (*func)(void *arg), static wontreturn void NetbsdThreadMain(void *arg, int (*func)(void *arg),
int *tid, int *ctid, int flags) { int *tid, int *ctid, int flags) {
int rc; int rc;
if (flags & CLONE_CHILD_SETTID) { if (flags & CLONE_CHILD_SETTID) {
*ctid = *tid; *ctid = *tid;
} }
rc = func(arg); _Exit1(func(arg));
_Exit1(rc);
} }
static int CloneNetbsd(int (*func)(void *), char *stk, size_t stksz, int flags, static int CloneNetbsd(int (*func)(void *), char *stk, size_t stksz, int flags,
@ -353,16 +377,21 @@ static int CloneNetbsd(int (*func)(void *), char *stk, size_t stksz, int flags,
} }
} }
static int CloneLinux(int (*func)(void *), char *stk, size_t stksz, int flags, ////////////////////////////////////////////////////////////////////////////////
void *arg, int *ptid, void *tls, size_t tlssz, // GNU/SYSTEMD
int *ctid) {
int CloneLinux(int (*func)(void *), char *stk, size_t stksz, int flags,
void *arg, int *ptid, void *tls, size_t tlssz, int *ctid) {
#ifdef __chibicc__
return -1; // TODO
#else
int ax; int ax;
register int *r8 asm("r8") = tls;
register int *r10 asm("r10") = ctid;
register void *r9 asm("r9") = func;
intptr_t *stack = (intptr_t *)(stk + stksz); intptr_t *stack = (intptr_t *)(stk + stksz);
*--stack = (intptr_t)arg; *--stack = (intptr_t)arg;
asm volatile("syscall\n\t" asm volatile("mov\t%4,%%r10\n\t" // ctid
"mov\t%5,%%r8\n\t" // tls
"mov\t%6,%%r9\n\t" // func
"syscall\n\t"
"test\t%0,%0\n\t" "test\t%0,%0\n\t"
"jnz\t1f\n\t" "jnz\t1f\n\t"
"xor\t%%ebp,%%ebp\n\t" "xor\t%%ebp,%%ebp\n\t"
@ -371,13 +400,17 @@ static int CloneLinux(int (*func)(void *), char *stk, size_t stksz, int flags,
"xchg\t%%eax,%%edi\n\t" "xchg\t%%eax,%%edi\n\t"
"jmp\t_Exit1\n1:" "jmp\t_Exit1\n1:"
: "=a"(ax) : "=a"(ax)
: "0"(__NR_clone_linux), "D"(flags), "S"(stack), "r"(r10), : "0"(__NR_clone_linux), "D"(flags), "S"(stack), "g"(ctid),
"r"(r8), "r"(r9) "g"(tls), "g"(func)
: "rcx", "r11", "memory"); : "rcx", "r8", "r9", "r10", "r11", "memory");
if (ax > -4096u) errno = -ax, ax = -1; if (ax > -4096u) errno = -ax, ax = -1;
return ax; return ax;
#endif
} }
////////////////////////////////////////////////////////////////////////////////
// COSMOPOLITAN
/** /**
* Creates thread. * Creates thread.
* *
@ -446,9 +479,13 @@ static int CloneLinux(int (*func)(void *), char *stk, size_t stksz, int flags,
int clone(int (*func)(void *), void *stk, size_t stksz, int flags, void *arg, int clone(int (*func)(void *), void *stk, size_t stksz, int flags, void *arg,
int *ptid, void *tls, size_t tlssz, int *ctid) { int *ptid, void *tls, size_t tlssz, int *ctid) {
int rc; int rc;
struct CloneArgs *wt;
__threaded = true; if (flags & CLONE_THREAD) {
if (tls && !__tls_enabled) { __threaded = true;
}
if ((flags & CLONE_SETTLS) && !__tls_enabled) {
__initialize_tls(tibdefault); __initialize_tls(tibdefault);
__install_tls(tibdefault); __install_tls(tibdefault);
} }

View file

@ -16,11 +16,8 @@
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/bits/weaken.h" #include "libc/errno.h"
#include "libc/calls/calls.h" #include "libc/nexgen32e/threaded.h"
#include "libc/dce.h"
#include "libc/intrin/threaded.h"
#include "libc/nt/thread.h"
/** /**
* Global variable for last error. * Global variable for last error.
@ -36,24 +33,9 @@
*/ */
errno_t __errno; errno_t __errno;
/**
* Returns address of thread information block.
* @see __install_tls()
* @see clone()
*/
privileged nocallersavedregisters char *__get_tls(void) {
char *tib, *linear = (char *)0x30;
if (IsLinux() || IsFreebsd() || IsNetbsd() || IsOpenbsd()) {
asm("mov\t%%fs:(%1),%0" : "=a"(tib) : "r"(linear));
} else {
asm("mov\t%%gs:(%1),%0" : "=a"(tib) : "r"(linear));
if (IsWindows()) tib = *(char **)(tib + 0x1480 + __tls_index * 8);
}
return tib;
}
/** /**
* Returns address of errno variable. * Returns address of errno variable.
*
* @see __initialize_tls() * @see __initialize_tls()
* @see __install_tls() * @see __install_tls()
*/ */

View file

@ -34,13 +34,15 @@ int cthread_join(cthread_t td, int* rc) {
: "cc"); : "cc");
if (!(state & cthread_finished)) { if (!(state & cthread_finished)) {
int ax;
int flags = FUTEX_WAIT; // PRIVATE makes it hang int flags = FUTEX_WAIT; // PRIVATE makes it hang
register struct timespec* timeout asm("r10") = NULL; struct timespec* timeout = NULL;
asm volatile("syscall" asm volatile("mov\t%5,%%r10\n\t" // timeout
: /* no outputs */ "syscall"
: "a"(__NR_futex), "D"(&td->tid), "S"(flags), "d"(tid), : "=a"(ax)
"r"(timeout) : "0"(__NR_futex), "D"(&td->tid), "S"(flags), "d"(tid),
: "rcx", "r11", "cc", "memory"); "g"(timeout)
: "rcx", "r10", "r11", "cc", "memory");
} }
*rc = td->rc; *rc = td->rc;

View file

@ -25,12 +25,12 @@ int cthread_memory_wait32(uint32_t* addr, uint32_t val,
if (__NR_futex != 0xfff) { if (__NR_futex != 0xfff) {
int flags = FUTEX_WAIT; int flags = FUTEX_WAIT;
int rc; int rc;
register struct timespec* timeout_ asm("r10") = timeout; asm volatile("mov\t%5,%%r10\n\t" // timeout
asm volatile("syscall" "syscall"
: "=a"(rc) : "=a"(rc)
: "0"(__NR_futex), "D"(addr), "S"(flags), "d"(val), : "0"(__NR_futex), "D"(addr), "S"(flags), "d"(val),
"r"(timeout_) "g"(timeout)
: "rcx", "r11", "cc", "memory"); : "rcx", "r10", "r11", "cc", "memory");
return rc; return rc;
} }
return -1; return -1;

View file

@ -17,7 +17,7 @@
PERFORMANCE OF THIS SOFTWARE. PERFORMANCE OF THIS SOFTWARE.
*/ */
#include "libc/errno.h" #include "libc/errno.h"
#include "libc/intrin/threaded.h" #include "libc/nexgen32e/threaded.h"
#include "libc/runtime/runtime.h" #include "libc/runtime/runtime.h"
#include "libc/testlib/testlib.h" #include "libc/testlib/testlib.h"

View file

@ -23,8 +23,8 @@
#include "libc/dce.h" #include "libc/dce.h"
#include "libc/errno.h" #include "libc/errno.h"
#include "libc/intrin/spinlock.h" #include "libc/intrin/spinlock.h"
#include "libc/intrin/threaded.h"
#include "libc/macros.internal.h" #include "libc/macros.internal.h"
#include "libc/nexgen32e/threaded.h"
#include "libc/rand/rand.h" #include "libc/rand/rand.h"
#include "libc/runtime/stack.h" #include "libc/runtime/stack.h"
#include "libc/str/str.h" #include "libc/str/str.h"

View file

@ -21,13 +21,15 @@
#include "libc/errno.h" #include "libc/errno.h"
#include "libc/intrin/kprintf.h" #include "libc/intrin/kprintf.h"
#include "libc/intrin/spinlock.h" #include "libc/intrin/spinlock.h"
#include "libc/intrin/threaded.h"
#include "libc/mem/mem.h" #include "libc/mem/mem.h"
#include "libc/nexgen32e/nexgen32e.h"
#include "libc/nexgen32e/threaded.h"
#include "libc/runtime/stack.h" #include "libc/runtime/stack.h"
#include "libc/sysv/consts/clone.h" #include "libc/sysv/consts/clone.h"
#include "libc/sysv/consts/map.h" #include "libc/sysv/consts/map.h"
#include "libc/sysv/consts/prot.h" #include "libc/sysv/consts/prot.h"
#include "libc/sysv/consts/sig.h" #include "libc/sysv/consts/sig.h"
#include "libc/testlib/ezbench.h"
#include "libc/testlib/testlib.h" #include "libc/testlib/testlib.h"
#include "libc/time/time.h" #include "libc/time/time.h"
@ -48,15 +50,11 @@ void SetUp(void) {
} }
void TearDown(void) { void TearDown(void) {
if (thechilde) {
tkill(thechilde, SIGKILL);
errno = 0;
}
sched_yield();
free(tls); free(tls);
} }
int CloneTest1(void *arg) { int CloneTest1(void *arg) {
_checkstackalign();
x = 42; x = 42;
if (!IsWindows()) { if (!IsWindows()) {
ASSERT_EQ(31337, errno); ASSERT_EQ(31337, errno);
@ -72,6 +70,7 @@ int CloneTest1(void *arg) {
} }
int DoNothing(void *arg) { int DoNothing(void *arg) {
_checkstackalign();
return 0; return 0;
} }
@ -92,6 +91,7 @@ TEST(clone, test1) {
} }
int CloneTestSys(void *arg) { int CloneTestSys(void *arg) {
_checkstackalign();
thechilde = gettid(); thechilde = gettid();
ASSERT_EQ(31337, errno); ASSERT_EQ(31337, errno);
open(0, 0); open(0, 0);
@ -112,3 +112,10 @@ TEST(clone, tlsSystemCallsErrno_wontClobberMainThreadBecauseTls) {
ASSERT_EQ(0, errno); ASSERT_EQ(0, errno);
ASSERT_EQ(EFAULT, *(int *)(tls + 0x3c)); ASSERT_EQ(EFAULT, *(int *)(tls + 0x3c));
} }
BENCH(clone, bench) {
errno_t *volatile ep;
char *volatile tp;
EZBENCH2("__errno_location", donothing, (ep = (__errno_location())));
EZBENCH2("__get_tls", donothing, (tp = __get_tls()));
}

View file

@ -559,6 +559,7 @@ static Token *thing_attributes(Token *tok, void *arg) {
consume_attribute(&tok, tok, "warn_unused_result") || consume_attribute(&tok, tok, "warn_unused_result") ||
consume_attribute(&tok, tok, "flatten") || consume_attribute(&tok, tok, "flatten") ||
consume_attribute(&tok, tok, "leaf") || consume_attribute(&tok, tok, "leaf") ||
consume_attribute(&tok, tok, "no_reorder") ||
consume_attribute(&tok, tok, "dontthrow") || consume_attribute(&tok, tok, "dontthrow") ||
consume_attribute(&tok, tok, "optnone") || consume_attribute(&tok, tok, "optnone") ||
consume_attribute(&tok, tok, "returns_twice") || consume_attribute(&tok, tok, "returns_twice") ||

View file

@ -1174,6 +1174,14 @@ __INT_FAST32_TYPE__\000\
int\000\ int\000\
__UINT_FAST32_TYPE__\000\ __UINT_FAST32_TYPE__\000\
unsigned\000\ unsigned\000\
__INT_FAST8_MAX__\000\
0x7f\000\
__INT_FAST16_MAX__\000\
0x7fffffff\000\
__INT_FAST32_MAX__\000\
0x7fffffff\000\
__INT_FAST64_MAX__\000\
0x7fffffffffffffffl\000\
__INT_FAST64_TYPE__\000\ __INT_FAST64_TYPE__\000\
long\000\ long\000\
__UINT_FAST64_TYPE__\000\ __UINT_FAST64_TYPE__\000\

View file

@ -1,3 +1,4 @@
#include "libc/assert.h"
#include "third_party/chibicc/chibicc.h" #include "third_party/chibicc/chibicc.h"
/* TODO(jart): Why can't these be const? */ /* TODO(jart): Why can't these be const? */
@ -144,6 +145,9 @@ static Type *get_common_type(Type *ty1, Type *ty2) {
// //
// This operation is called the "usual arithmetic conversion". // This operation is called the "usual arithmetic conversion".
static void usual_arith_conv(Node **lhs, Node **rhs) { static void usual_arith_conv(Node **lhs, Node **rhs) {
if (!(*lhs)->ty || !(*rhs)->ty) {
error_tok((*lhs)->tok, "internal npe error");
}
Type *ty = get_common_type((*lhs)->ty, (*rhs)->ty); Type *ty = get_common_type((*lhs)->ty, (*rhs)->ty);
*lhs = new_cast(*lhs, ty); *lhs = new_cast(*lhs, ty);
*rhs = new_cast(*rhs, ty); *rhs = new_cast(*rhs, ty);