Refactor some code

- Write tests for cthreads
- Fix bugs in pe2.com tool
- Fix ASAN issue with GetDosEnviron()
- Consolidate the cthread header files
- Some code size optimizations for MODE=
- Attempted to squash a tls linker warning
- Attempted to get futexes working on FreeBSD
This commit is contained in:
Justine Tunney 2022-05-28 05:50:01 -07:00
parent 909e54510d
commit 425ff5dff0
61 changed files with 529 additions and 382 deletions

View file

@ -389,6 +389,7 @@ SECTIONS {
_tdata_end = .;
. = ALIGN(PAGESIZE);
} :Tls
. = ALIGN(PAGESIZE);
/*END: file content that's loaded by o/s */
/*BEGIN: bss memory void */
@ -531,8 +532,8 @@ HIDDEN(ape_text_rva = RVA(ape_text_vaddr));
HIDDEN(ape_data_offset = ape_ram_offset + LOADADDR(.data) - ape_ram_paddr);
HIDDEN(ape_data_paddr = LOADADDR(.data));
HIDDEN(ape_data_vaddr = ADDR(.data));
HIDDEN(ape_data_filesz = SIZEOF(.data));
HIDDEN(ape_data_memsz = SIZEOF(.data));
HIDDEN(ape_data_filesz = SIZEOF(.data) + SIZEOF(.tdata));
HIDDEN(ape_data_memsz = SIZEOF(.data) + SIZEOF(.tdata));
HIDDEN(ape_data_align = PAGESIZE);
HIDDEN(ape_data_rva = RVA(ape_data_vaddr));

View file

@ -8,15 +8,12 @@
*/
#endif
#include "libc/calls/calls.h"
#include "libc/dce.h"
#include "libc/intrin/kprintf.h"
#include "libc/log/log.h"
#include "libc/runtime/runtime.h"
#include "libc/stdio/stdio.h"
#include "libc/thread/create.h"
#include "libc/thread/detach.h"
#include "libc/thread/join.h"
#include "libc/thread/self.h"
#include "libc/thread/sem.h"
#include "libc/thread/thread.h"
#include "libc/time/time.h"
cthread_sem_t semaphore;
@ -39,6 +36,14 @@ int main() {
int rc, tid;
void *exitcode;
cthread_t self, thread;
if (IsWindows() || IsXnu()) {
fprintf(stderr,
"error: can't run example\n"
"_Thread_local only works on Linux/FreeBSD/NetBSD/OpenBSD\n");
return 1;
}
self = cthread_self();
tid = self->tid;
printf("[%p] %d -> %#x\n", self, tid, test_tls);

View file

@ -164,6 +164,14 @@ o//libc/calls/fcntl.o: \
OVERRIDE_CFLAGS += \
-Os
# we always want -Os because:
# it's early runtime mandatory and quite huge without it
o//libc/calls/getcwd.greg.o \
o//libc/calls/getcwd-nt.greg.o \
o//libc/calls/getcwd-xnu.greg.o: \
OVERRIDE_CFLAGS += \
-Os
LIBC_CALLS_LIBS = $(foreach x,$(LIBC_CALLS_ARTIFACTS),$($(x)))
LIBC_CALLS_SRCS = $(foreach x,$(LIBC_CALLS_ARTIFACTS),$($(x)_SRCS))
LIBC_CALLS_HDRS = $(foreach x,$(LIBC_CALLS_ARTIFACTS),$($(x)_HDRS))

View file

@ -28,18 +28,28 @@
#define XNU_F_GETPATH 50
#define XNU_MAXPATHLEN 1024
static inline bool CopyString(char *d, const char *s, size_t n) {
size_t i;
for (i = 0; i < n; ++i) {
if (!(d[i] = s[i])) {
return true;
}
}
return false;
}
char *sys_getcwd_xnu(char *res, size_t size) {
int fd;
union metastat st[2];
char buf[XNU_MAXPATHLEN], *ret = NULL;
if ((fd = sys_openat(AT_FDCWD, ".", O_RDONLY | O_DIRECTORY, 0)) != -1) {
if (__sys_fstat(fd, &st[0]) != -1) {
if (METASTAT(st[0], st_dev) && METASTAT(st[0], st_ino)) {
if (st[0].xnu.st_dev && st[0].xnu.st_ino) {
if (__sys_fcntl(fd, XNU_F_GETPATH, (uintptr_t)buf) != -1) {
if (__sys_fstatat(AT_FDCWD, buf, &st[1], 0) != -1) {
if (METASTAT(st[0], st_dev) == METASTAT(st[1], st_dev) &&
METASTAT(st[0], st_ino) == METASTAT(st[1], st_ino)) {
if (memccpy(res, buf, '\0', size)) {
if (st[0].xnu.st_dev == st[1].xnu.st_dev &&
st[0].xnu.st_ino == st[1].xnu.st_ino) {
if (CopyString(res, buf, size)) {
ret = res;
} else {
erange();

View file

@ -753,7 +753,7 @@ dontdiscard static __asan_die_f *__asan_report(const void *addr, int size,
p = __fatalbuf;
kprintf("\n\e[J\e[1;31masan error\e[0m: %s %d-byte %s at %p shadow %p\n",
__asan_describe_access_poison(kind), size, message, addr,
SHADOW(addr), __argv[0]);
SHADOW(addr));
if (0 < size && size < 80) {
base = (char *)addr - ((80 >> 1) - (size >> 1));
for (i = 0; i < 80; ++i) {

View file

@ -58,7 +58,7 @@ privileged int gettid(void) {
struct WinThread *wt;
if (__tls_enabled) {
rc = *(int *)(__get_tls() + 0x38);
rc = *(int *)(__get_tls_inline() + 0x38);
return rc;
}

View file

@ -21,23 +21,28 @@
#include "libc/log/log.h"
#include "libc/nexgen32e/vendor.internal.h"
#include "libc/nt/struct/teb.h"
#include "libc/runtime/runtime.h"
#include "libc/sysv/consts/o.h"
#define kBufSize 1024
#define kPid "TracerPid:\t"
static textwindows noasan bool IsBeingDebugged(void) {
return !!NtGetPeb()->BeingDebugged;
}
/**
* Determines if gdb, strace, windbg, etc. is controlling process.
* @return non-zero if attached, otherwise 0
*/
noasan noubsan int IsDebuggerPresent(bool force) {
int IsDebuggerPresent(bool force) {
/* asan runtime depends on this function */
int fd, res;
ssize_t got;
char *p, buf[1024];
if (!force && IsGenuineCosmo()) return 0;
if (!force && getenv("HEISENDEBUG")) return 0;
if (IsWindows()) return NtGetPeb()->BeingDebugged; /* needs noasan */
if (!force && __getenv(environ, "HEISENDEBUG")) return 0;
if (IsWindows()) return IsBeingDebugged();
if (__isworker) return false;
res = 0;
if ((fd = __sysv_open("/proc/self/status", O_RDONLY, 0)) >= 0) {

View file

@ -1,6 +1,5 @@
#ifndef LIBC_ISYSTEM_PTHREAD_H_
#define LIBC_ISYSTEM_PTHREAD_H_
#include "libc/calls/calls.h"
#define PTHREAD_ONCE_INIT 0

View file

@ -59,8 +59,8 @@ $(LIBC_LOG_A).pkg: \
$(LIBC_LOG_A_OBJS) \
$(foreach x,$(LIBC_LOG_A_DIRECTDEPS),$($(x)_A).pkg)
o/$(MODE)/libc/log/backtrace2.greg.o \
o/$(MODE)/libc/log/backtrace3.greg.o: \
o/$(MODE)/libc/log/backtrace2.o \
o/$(MODE)/libc/log/backtrace3.o: \
OVERRIDE_CFLAGS += \
-fno-sanitize=all
@ -68,10 +68,7 @@ o/$(MODE)/libc/log/checkfail.o: \
OVERRIDE_CFLAGS += \
-mgeneral-regs-only
o/$(MODE)/libc/log/restoretty.greg.o \
o/$(MODE)/libc/log/attachdebugger.o \
o/$(MODE)/libc/log/backtrace2.o \
o/$(MODE)/libc/log/backtrace3.o \
o/$(MODE)/libc/log/checkaligned.o \
o/$(MODE)/libc/log/checkfail.o \
o/$(MODE)/libc/log/checkfail_ndebug.o \

View file

@ -25,6 +25,7 @@
#include "libc/errno.h"
#include "libc/log/color.internal.h"
#include "libc/log/internal.h"
#include "libc/log/libfatal.internal.h"
#include "libc/runtime/internal.h"
#include "libc/sysv/consts/termios.h"
@ -60,7 +61,7 @@ void __restore_tty(void) {
int e;
if (__isrestorable && !__isworker && !__nocolor) {
e = errno;
sys_write(0, ANSI_RESTORE, strlen(ANSI_RESTORE));
sys_write(0, ANSI_RESTORE, __strlen(ANSI_RESTORE));
sys_ioctl(0, TCSETSF, &__oldtermios);
errno = e;
}

View file

@ -8,19 +8,12 @@ extern int __threaded;
extern bool __tls_enabled;
extern unsigned __tls_index;
char *__get_tls(void) libcesque nosideeffect;
void *__initialize_tls(char[64]);
void __install_tls(char[64]);
#if defined(__GNUC__) && defined(__x86_64__) && !defined(__STRICT_ANSI__)
/**
* 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) {
static noasan inline char *__get_tls_inline(void) {
char *tib, *lin = (char *)0x30;
if (IsLinux() || IsFreebsd() || IsNetbsd() || IsOpenbsd()) {
asm("mov\t%%fs:(%1),%0" : "=a"(tib) : "r"(lin) : "memory");

View file

@ -27,7 +27,6 @@
#include "libc/runtime/internal.h"
#include "libc/runtime/runtime.h"
#include "libc/sysv/consts/auxv.h"
#include "libc/thread/create.h"
static int thepid;
static uint128_t thepool;

View file

@ -468,7 +468,8 @@ int sys_clone_linux(int flags, char *stk, int *ptid, int *ctid, void *tls,
* effectively work around libc features like atfork(), so that means
* other calls like getpid() may return incorrect values.
*
* @param func is your callback function
* @param func is your callback function, which this wrapper requires
* not be null, otherwise EINVAL is raised
* @param stk points to the bottom of a caller allocated stack, which
* must be allocated via mmap() using the MAP_STACK flag, or else
* you won't get optimal performance and it won't work on OpenBSD
@ -532,7 +533,13 @@ int clone(int (*func)(void *), void *stk, size_t stksz, int flags, void *arg,
__threaded = gettid();
}
if (IsAsan() &&
if (!func) {
rc = einval();
} else if (!IsTiny() &&
(((flags & CLONE_VM) && (stksz < PAGESIZE || (stksz & 15))) ||
((flags & CLONE_SETTLS) && (tlssz < 64 || (tlssz & 7))))) {
rc = einval();
} else if (IsAsan() &&
((stksz > PAGESIZE &&
!__asan_is_valid((char *)stk + PAGESIZE, stksz - PAGESIZE)) ||
((flags & CLONE_SETTLS) && !__asan_is_valid(tls, tlssz)) ||
@ -542,10 +549,6 @@ int clone(int (*func)(void *), void *stk, size_t stksz, int flags, void *arg,
((flags & CLONE_CHILD_SETTID) &&
!__asan_is_valid(ctid, sizeof(*ctid))))) {
rc = efault();
} else if (!IsTiny() &&
(((flags & CLONE_VM) && (stksz < PAGESIZE || (stksz & 15))) ||
((flags & CLONE_SETTLS) && (tlssz < 64 || (tlssz & 7))))) {
rc = einval();
} else if (IsLinux()) {
rc =
sys_clone_linux(flags, (char *)stk + stksz, ptid, ctid, tls, func, arg);

View file

@ -125,7 +125,7 @@ textwindows noasan noinstrument int GetDosEnviron(const char16_t *env,
while (*env) {
if (i + 1 < max) envp[i++] = buf;
r = Recode16to8(buf, size, env);
if ((p = memchr(buf, '=', r.ax)) && IsAlpha(p[1]) && p[2] == ':' &&
if ((p = MemChr(buf, '=', r.ax)) && IsAlpha(p[1]) && p[2] == ':' &&
(p[3] == '\\' || p[3] == '/')) {
FixPath(p + 1);
}

View file

@ -16,29 +16,56 @@
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/bits/atomic.h"
#include "libc/calls/calls.h"
#include "libc/errno.h"
#include "libc/intrin/lockcmpxchg.h"
#include "libc/intrin/spinlock.h"
#include "libc/runtime/runtime.h"
typedef void *pthread_t;
typedef bool pthread_once_t;
typedef int pthread_once_t;
typedef int pthread_mutex_t;
int pthread_once(pthread_once_t *once, void init(void)) {
if (_lockcmpxchg(once, 0, 1)) init();
int x;
unsigned tries;
switch ((x = atomic_load(once))) {
case 0:
if (atomic_compare_exchange_strong(once, &x, 1)) {
init();
atomic_store(once, 2);
break;
}
// fallthrough
case 1:
tries = 0;
do {
if (++tries & 7) {
__builtin_ia32_pause();
} else {
sched_yield();
}
} while (atomic_load(once) == 1);
break;
default:
break;
}
return 0;
}
int pthread_mutex_lock(pthread_mutex_t *mutex) {
return EINVAL;
_spinlock(mutex);
return 0;
}
int pthread_mutex_trylock(pthread_mutex_t *mutex) {
return EINVAL;
return _trylock(mutex);
}
int pthread_mutex_unlock(pthread_mutex_t *mutex) {
return EPERM;
_spunlock(mutex);
return 0;
}
int pthread_cancel(pthread_t thread) {

View file

@ -21,11 +21,15 @@
/**
* Returns file descriptor associated with stream.
*
* @param f is file stream object pointer
* @return fd on success or -1 w/ errno;
* @threadsafe
*/
int fileno_unlocked(FILE *f) {
if (f->fd != -1) {
return f->fd;
} else {
return ebadf();
}
int fileno(FILE *f) {
int rc;
flockfile(f);
rc = fileno_unlocked(f);
funlockfile(f);
return rc;
}

View file

@ -1,5 +1,5 @@
/*-*- 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
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
vi: set net ft=c ts=8 sts=2 sw=2 fenc=utf-8 :vi
Copyright 2020 Justine Alexandra Roberts Tunney
@ -16,14 +16,19 @@
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/macros.internal.h"
#include "libc/stdio/stdio.h"
#include "libc/sysv/errfuns.h"
// Returns file descriptor associated with stream.
//
// @param rdi has file stream object pointer
// @see fileno_unlocked()
// @threadsafe
fileno: mov %rdi,%r11
ezlea fileno_unlocked,ax
jmp stdio_unlock
.endfn fileno,globl
/**
* Returns file descriptor associated with stream.
*
* @param f is file stream object pointer
* @return fd on success or -1 w/ errno;
*/
int fileno_unlocked(FILE *f) {
if (f->fd != -1) {
return f->fd;
} else {
return ebadf();
}
}

View file

@ -16,7 +16,6 @@
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/calls/calls.h"
#include "libc/stdio/stdio.h"
/**
@ -24,15 +23,12 @@
*
* @param c is byte to buffer or write, which is masked
* @return c as unsigned char if written or -1 w/ errno
* @threadsafe
*/
int fputc_unlocked(int c, FILE *f) {
unsigned char b;
if (c != '\n' && f->beg < f->size && f->bufmode != _IONBF) {
f->buf[f->beg++] = c;
return c & 255;
} else {
b = c;
if (!fwrite_unlocked(&b, 1, 1, f)) return -1;
return b;
}
int fputc(int c, FILE *f) {
int rc;
flockfile(f);
rc = fputc_unlocked(c, f);
funlockfile(f);
return rc;
}

View file

@ -0,0 +1,38 @@
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
vi: set net ft=c ts=8 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/stdio/stdio.h"
/**
* Writes byte to stream.
*
* @param c is byte to buffer or write, which is masked
* @return c as unsigned char if written or -1 w/ errno
*/
int fputc_unlocked(int c, FILE *f) {
unsigned char b;
if (c != '\n' && f->beg < f->size && f->bufmode != _IONBF) {
f->buf[f->beg++] = c;
return c & 255;
} else {
b = c;
if (!fwrite_unlocked(&b, 1, 1, f)) return -1;
return b;
}
}

View file

@ -19,13 +19,6 @@
#include "libc/bits/bits.h"
#include "libc/str/str.h"
static inline noasan uint64_t UncheckedAlignedRead64(unsigned char *p) {
return (uint64_t)(255 & p[7]) << 070 | (uint64_t)(255 & p[6]) << 060 |
(uint64_t)(255 & p[5]) << 050 | (uint64_t)(255 & p[4]) << 040 |
(uint64_t)(255 & p[3]) << 030 | (uint64_t)(255 & p[2]) << 020 |
(uint64_t)(255 & p[1]) << 010 | (uint64_t)(255 & p[0]) << 000;
}
/**
* Copies at most N bytes from SRC to DST until 𝑐 is encountered.
*

View file

@ -27,5 +27,5 @@
*/
privileged nocallersavedregisters errno_t *(__errno_location)(void) {
if (!__tls_enabled) return &__errno;
return (errno_t *)(__get_tls() + 0x3c);
return (errno_t *)(__get_tls_inline() + 0x3c);
}

View file

@ -1,7 +1,7 @@
/*-*- 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
/*-*- 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
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
@ -16,16 +16,17 @@
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/macros.internal.h"
#include "libc/nexgen32e/threaded.h"
// Writes character to stream.
//
// @param rdi c is byte to buffer or write, which is masked
// @param rsi has stream object pointer
// @return c as unsigned char if written or -1 w/ errno
// @see fputc_unlocked()
// @threadsafe
fputc: mov %rsi,%r11
ezlea fputc_unlocked,ax
jmp stdio_unlock
.endfn fputc,globl
/**
* Returns address of thread information block.
*
* This function must not be called until TLS is initialized.
*
* @see __get_tls_inline()
* @see __install_tls()
* @see clone()
*/
optimizespeed char *__get_tls(void) {
return __get_tls_inline();
}

View file

@ -39,6 +39,7 @@ LIBC_SYSV_A_FILES := \
libc/sysv/systemfive.S \
libc/sysv/errno_location.greg.c \
libc/sysv/errno.c \
libc/sysv/gettls.greg.c \
libc/sysv/errfun.S \
libc/sysv/strace.greg.c \
libc/sysv/describeos.greg.c \

View file

@ -18,7 +18,7 @@
*/
#include "libc/errno.h"
#include "libc/runtime/stack.h"
#include "libc/thread/attr.h"
#include "libc/thread/thread.h"
#define MIN_STACKSIZE (8 * PAGESIZE) // includes guard, rounds up to FRAMESIZE
#define MIN_GUARDSIZE PAGESIZE

View file

@ -1,30 +0,0 @@
#ifndef COSMOPOLITAN_LIBC_THREAD_ATTR_H_
#define COSMOPOLITAN_LIBC_THREAD_ATTR_H_
#define CTHREAD_CREATE_DETACHED 1
#define CTHREAD_CREATE_JOINABLE 0
#if !(__ASSEMBLER__ + __LINKER__ + 0)
COSMOPOLITAN_C_START_
/**
* @fileoverview cosmopolitan thread attributes
*/
typedef struct cthread_attr_t {
size_t stacksize, guardsize;
int mode;
} cthread_attr_t;
int cthread_attr_init(cthread_attr_t*);
int cthread_attr_destroy(cthread_attr_t*);
int cthread_attr_setstacksize(cthread_attr_t*, size_t);
size_t thread_attr_getstacksize(const cthread_attr_t*);
int cthread_attr_setguardsize(cthread_attr_t*, size_t);
size_t cthread_attr_getguardsize(const cthread_attr_t*);
int cthread_attr_setdetachstate(cthread_attr_t*, int);
int cthread_attr_getdetachstate(const cthread_attr_t*);
COSMOPOLITAN_C_END_
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
#endif /* COSMOPOLITAN_LIBC_THREAD_ATTR_H_ */

View file

@ -28,10 +28,7 @@
#include "libc/sysv/consts/clone.h"
#include "libc/sysv/consts/map.h"
#include "libc/sysv/consts/prot.h"
#include "libc/thread/attr.h"
#include "libc/thread/create.h"
#include "libc/thread/descriptor.h"
#include "libc/thread/zombie.h"
#include "libc/thread/thread.h"
STATIC_YOINK("_main_thread_ctor");
@ -99,8 +96,8 @@ static int cthread_start(void *arg) {
* @return 0 on success, or error number on failure
* @threadsafe
*/
int cthread_create(cthread_t *restrict ptd, const cthread_attr_t *restrict attr,
void *(*func)(void *), void *restrict arg) {
int cthread_create(cthread_t *ptd, const cthread_attr_t *attr,
void *(*func)(void *), void *arg) {
int rc, tid;
cthread_t td;
cthread_attr_t default_attr;

View file

@ -1,17 +0,0 @@
#ifndef COSMOPOLITAN_LIBC_THREAD_CREATE_H_
#define COSMOPOLITAN_LIBC_THREAD_CREATE_H_
#include "libc/thread/attr.h"
#include "libc/thread/descriptor.h"
#if !(__ASSEMBLER__ + __LINKER__ + 0)
COSMOPOLITAN_C_START_
/**
* @fileoverview Create a cosmopolitan thread
*/
int cthread_create(cthread_t *restrict, const cthread_attr_t *restrict,
void *(*)(void *), void *restrict);
COSMOPOLITAN_C_END_
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
#endif /* COSMOPOLITAN_LIBC_THREAD_CREATE_H_ */

View file

@ -1,41 +0,0 @@
#ifndef COSMOPOLITAN_LIBC_THREAD_DESCRIPTOR_H_
#define COSMOPOLITAN_LIBC_THREAD_DESCRIPTOR_H_
#if !(__ASSEMBLER__ + __LINKER__ + 0)
COSMOPOLITAN_C_START_
#include "libc/runtime/runtime.h"
/**
* @fileoverview thread types
*/
enum cthread_state {
cthread_started = 0,
cthread_joining = 1,
cthread_finished = 2,
cthread_detached = 4,
cthread_main = 127,
};
struct cthread_descriptor_t {
struct cthread_descriptor_t *self; /* 0x00 */
void *(*func)(void *); /* 0x08 */
int32_t __pad0; /* 0x10 */
int32_t state; /* 0x14 */
void *arg; /* 0x18 */
void *pthread_ret_ptr; /* 0x20 */
int64_t __pad1; /* 0x28 */
struct cthread_descriptor_t *self2; /* 0x30 */
int32_t tid; /* 0x38 */
int32_t err; /* 0x3c */
void *exitcode;
struct {
char *top, *bottom;
} stack, alloc;
jmp_buf exiter;
};
typedef struct cthread_descriptor_t *cthread_t;
COSMOPOLITAN_C_END_
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
#endif /* COSMOPOLITAN_LIBC_THREAD_DESCRIPTOR_H_ */

View file

@ -22,8 +22,7 @@
#include "libc/errno.h"
#include "libc/intrin/asan.internal.h"
#include "libc/str/str.h"
#include "libc/thread/descriptor.h"
#include "libc/thread/detach.h"
#include "libc/thread/thread.h"
/**
* Detaches thread.

View file

@ -1,16 +0,0 @@
#ifndef COSMOPOLITAN_LIBC_THREAD_DETACH_H_
#define COSMOPOLITAN_LIBC_THREAD_DETACH_H_
#include "libc/thread/descriptor.h"
#if !(__ASSEMBLER__ + __LINKER__ + 0)
COSMOPOLITAN_C_START_
/**
* @fileoverview detach a thread
*/
int cthread_detach(cthread_t);
COSMOPOLITAN_C_END_
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
#endif /* COSMOPOLITAN_LIBC_THREAD_DETACH_H_ */

View file

@ -18,8 +18,7 @@
*/
#include "libc/calls/strace.internal.h"
#include "libc/runtime/runtime.h"
#include "libc/thread/exit.h"
#include "libc/thread/self.h"
#include "libc/thread/thread.h"
/**
* Exits cosmopolitan thread.

View file

@ -1,10 +0,0 @@
#ifndef COSMOPOLITAN_LIBC_THREAD_EXIT_H_
#define COSMOPOLITAN_LIBC_THREAD_EXIT_H_
#if !(__ASSEMBLER__ + __LINKER__ + 0)
COSMOPOLITAN_C_START_
wontreturn void cthread_exit(void *);
COSMOPOLITAN_C_END_
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
#endif /* COSMOPOLITAN_LIBC_THREAD_EXIT_H_ */

View file

@ -3,8 +3,6 @@
#include "libc/bits/asmflag.h"
#include "libc/calls/struct/timespec.h"
#include "libc/errno.h"
#if !(__ASSEMBLER__ + __LINKER__ + 0)
COSMOPOLITAN_C_START_
/**
* @fileoverview FreeBSD Threading
@ -13,6 +11,13 @@ COSMOPOLITAN_C_START_
* maximum legal range is PID_MAX + 2 (100001) through INT_MAX
*/
#define UMTX_OP_MUTEX_WAIT 17
#define UMTX_OP_MUTEX_WAKE 18
#define UMTX_ABSTIME 1
#if !(__ASSEMBLER__ + __LINKER__ + 0)
COSMOPOLITAN_C_START_
struct rtprio {
uint16_t type; /* scheduling class */
uint16_t prio;
@ -31,6 +36,14 @@ struct thr_param {
struct rtprio *rtp;
};
struct _umtx_time {
struct timespec _timeout;
uint32_t _flags;
uint32_t _clockid;
};
int _umtx_op(void *, int, unsigned long, void *, void *);
COSMOPOLITAN_C_END_
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
#endif /* COSMOPOLITAN_LIBC_THREAD_FREEBSD_INTERNAL_H_ */

View file

@ -27,8 +27,7 @@
#include "libc/str/str.h"
#include "libc/sysv/consts/map.h"
#include "libc/sysv/consts/prot.h"
#include "libc/thread/descriptor.h"
#include "libc/thread/self.h"
#include "libc/thread/thread.h"
static textstartup void _main_thread_init(void) {
_Static_assert(offsetof(struct cthread_descriptor_t, self) == 0x00, "");
@ -67,6 +66,7 @@ static textstartup void _main_thread_init(void) {
// Set FS
__install_tls((char *)td);
assert(cthread_self()->tid == gettid());
__threaded = true;
}
const void *const _main_thread_ctor[] initarray = {

View file

@ -27,8 +27,7 @@
#include "libc/str/str.h"
#include "libc/sysv/consts/futex.h"
#include "libc/sysv/consts/nr.h"
#include "libc/thread/descriptor.h"
#include "libc/thread/join.h"
#include "libc/thread/thread.h"
/**
* Waits for thread to terminate and frees its memory.
@ -43,7 +42,7 @@
* @threadsafe
*/
int cthread_join(cthread_t td, void **exitcode) {
int rc, tid;
int x, rc, tid;
// otherwise, tid could be set to 0 even though `state` is not
// finished mark thread as joining
if (!td || (IsAsan() && !__asan_is_valid(td, sizeof(*td)))) {
@ -55,11 +54,10 @@ int cthread_join(cthread_t td, void **exitcode) {
rc = EINVAL;
} else {
if (~atomic_fetch_add(&td->state, cthread_joining) & cthread_finished) {
if (IsLinux() || IsOpenbsd()) {
while ((x = atomic_load(&td->tid))) {
// FUTEX_WAIT_PRIVATE makes it hang
futex((uint32_t *)&td->tid, FUTEX_WAIT, tid, 0, 0);
cthread_memory_wait32((uint32_t *)&td->tid, x, 0);
}
_spinlock(&td->tid);
}
if (exitcode) {
*exitcode = td->exitcode;

View file

@ -1,11 +0,0 @@
#ifndef COSMOPOLITAN_LIBC_THREAD_JOIN_H_
#define COSMOPOLITAN_LIBC_THREAD_JOIN_H_
#include "libc/thread/descriptor.h"
#if !(__ASSEMBLER__ + __LINKER__ + 0)
COSMOPOLITAN_C_START_
int cthread_join(cthread_t, void **);
COSMOPOLITAN_C_END_
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
#endif /* COSMOPOLITAN_LIBC_THREAD_JOIN_H_ */

View file

@ -16,7 +16,8 @@
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/thread/self.h"
#include "libc/nexgen32e/threaded.h"
#include "libc/thread/thread.h"
STATIC_YOINK("_main_thread_ctor");
@ -24,5 +25,5 @@ STATIC_YOINK("_main_thread_ctor");
* Returns thread descriptor of the current thread.
*/
cthread_t(cthread_self)(void) {
return cthread_self();
return (cthread_t)__get_tls_inline();
}

View file

@ -1,22 +0,0 @@
#ifndef COSMOPOLITAN_LIBC_THREAD_SELF_H_
#define COSMOPOLITAN_LIBC_THREAD_SELF_H_
#include "libc/nexgen32e/threaded.h"
#include "libc/thread/descriptor.h"
#if !(__ASSEMBLER__ + __LINKER__ + 0)
COSMOPOLITAN_C_START_
extern const void *const _main_thread_ctor[];
#if defined(__GNUC__) && !defined(__STRICT_ANSI__)
#define cthread_self() \
({ \
YOINK(_main_thread_ctor); \
((cthread_t)__get_tls()); \
})
#else
cthread_t cthread_self(void);
#endif
COSMOPOLITAN_C_END_
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
#endif /* COSMOPOLITAN_LIBC_THREAD_SELF_H_ */

View file

@ -17,9 +17,7 @@
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/bits/atomic.h"
#include "libc/thread/sem.h"
#include "libc/thread/wait.h"
#include "libc/thread/yield.h"
#include "libc/thread/thread.h"
STATIC_YOINK("_main_thread_ctor");

View file

@ -1,24 +0,0 @@
#ifndef COSMOPOLITAN_LIBC_THREAD_NATIVESEM_H_
#define COSMOPOLITAN_LIBC_THREAD_NATIVESEM_H_
#include "libc/calls/struct/timespec.h"
#if !(__ASSEMBLER__ + __LINKER__ + 0)
COSMOPOLITAN_C_START_
/**
* @fileoverview native semaphore for implementation details
*/
typedef union cthread_sem_t {
struct {
uint64_t count;
} linux;
} cthread_sem_t;
int cthread_sem_init(cthread_sem_t *, int);
int cthread_sem_destroy(cthread_sem_t *);
int cthread_sem_wait(cthread_sem_t *, int, const struct timespec *);
int cthread_sem_signal(cthread_sem_t *);
COSMOPOLITAN_C_END_
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
#endif /* COSMOPOLITAN_LIBC_THREAD_SELF_H_ */

80
libc/thread/thread.h Normal file
View file

@ -0,0 +1,80 @@
#ifndef COSMOPOLITAN_LIBC_THREAD_THREAD_H_
#define COSMOPOLITAN_LIBC_THREAD_THREAD_H_
#include "libc/calls/struct/timespec.h"
#include "libc/runtime/runtime.h"
#define CTHREAD_CREATE_DETACHED 1
#define CTHREAD_CREATE_JOINABLE 0
#if !(__ASSEMBLER__ + __LINKER__ + 0)
COSMOPOLITAN_C_START_
enum cthread_state {
cthread_started = 0,
cthread_joining = 1,
cthread_finished = 2,
cthread_detached = 4,
cthread_main = 127,
};
struct cthread_descriptor_t {
struct cthread_descriptor_t *self; /* 0x00 */
void *(*func)(void *); /* 0x08 */
int32_t __pad0; /* 0x10 */
int32_t state; /* 0x14 */
void *arg; /* 0x18 */
void *pthread_ret_ptr; /* 0x20 */
int64_t __pad1; /* 0x28 */
struct cthread_descriptor_t *self2; /* 0x30 */
int32_t tid; /* 0x38 */
int32_t err; /* 0x3c */
void *exitcode;
struct {
char *top, *bottom;
} stack, alloc;
jmp_buf exiter;
};
typedef struct cthread_descriptor_t *cthread_t;
typedef union cthread_sem_t {
struct {
uint64_t count;
} linux;
} cthread_sem_t;
typedef struct cthread_attr_t {
size_t stacksize, guardsize;
int mode;
} cthread_attr_t;
extern const void *const _main_thread_ctor[];
int cthread_create(cthread_t *, const cthread_attr_t *, void *(*)(void *),
void *);
int cthread_yield(void);
cthread_t cthread_self(void);
int cthread_join(cthread_t, void **);
void cthread_exit(void *) wontreturn;
int cthread_detach(cthread_t);
int cthread_attr_init(cthread_attr_t *);
int cthread_attr_destroy(cthread_attr_t *);
int cthread_attr_setstacksize(cthread_attr_t *, size_t);
size_t thread_attr_getstacksize(const cthread_attr_t *);
int cthread_attr_setguardsize(cthread_attr_t *, size_t);
size_t cthread_attr_getguardsize(const cthread_attr_t *);
int cthread_attr_setdetachstate(cthread_attr_t *, int);
int cthread_attr_getdetachstate(const cthread_attr_t *);
int cthread_sem_init(cthread_sem_t *, int);
int cthread_sem_destroy(cthread_sem_t *);
int cthread_sem_wait(cthread_sem_t *, int, const struct timespec *);
int cthread_sem_signal(cthread_sem_t *);
int cthread_memory_wait32(uint32_t *, uint32_t, const struct timespec *);
int cthread_memory_wake32(uint32_t *, int);
void cthread_zombies_add(cthread_t);
void cthread_zombies_reap(void);
COSMOPOLITAN_C_END_
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
#endif /* COSMOPOLITAN_LIBC_THREAD_THREAD_H_ */

View file

@ -19,12 +19,33 @@
#include "libc/bits/atomic.h"
#include "libc/calls/calls.h"
#include "libc/dce.h"
#include "libc/sysv/consts/clock.h"
#include "libc/sysv/consts/futex.h"
#include "libc/thread/freebsd.internal.h"
#include "libc/thread/thread.h"
int cthread_memory_wait32(uint32_t* addr, uint32_t val,
const struct timespec* timeout) {
size_t size;
struct _umtx_time *put, ut;
if (IsLinux() || IsOpenbsd()) {
return futex(addr, FUTEX_WAIT, val, timeout, 0);
#if 0
} else if (IsFreebsd()) {
if (!timeout) {
put = 0;
size = 0;
} else {
ut._flags = 0;
ut._clockid = CLOCK_REALTIME;
ut._timeout = *timeout;
put = &ut;
size = sizeof(ut);
}
return _umtx_op(addr, UMTX_OP_MUTEX_WAIT, 0, &size, put);
#endif
} else {
unsigned tries;
for (tries = 1; atomic_load(addr) == val; ++tries) {
@ -41,6 +62,10 @@ int cthread_memory_wait32(uint32_t* addr, uint32_t val,
int cthread_memory_wake32(uint32_t* addr, int n) {
if (IsLinux() || IsOpenbsd()) {
return futex(addr, FUTEX_WAKE, n, 0, 0);
#if 0
} else if (IsFreebsd()) {
return _umtx_op(addr, UMTX_OP_MUTEX_WAKE, n, 0, 0);
#endif
}
return -1;
}

View file

@ -1,16 +0,0 @@
#ifndef COSMOPOLITAN_LIBC_THREAD_WAIT_H_
#define COSMOPOLITAN_LIBC_THREAD_WAIT_H_
#if !(__ASSEMBLER__ + __LINKER__ + 0)
COSMOPOLITAN_C_START_
/**
* @fileoverview wait on memory
*/
struct timespec;
int cthread_memory_wait32(uint32_t*, uint32_t, const struct timespec*);
int cthread_memory_wake32(uint32_t*, int);
COSMOPOLITAN_C_END_
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
#endif /* COSMOPOLITAN_LIBC_THREAD_WAIT_H_ */

View file

@ -17,7 +17,7 @@
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/calls/calls.h"
#include "libc/thread/yield.h"
#include "libc/thread/thread.h"
/**
* Asks operating system to handoff remaining time slice.

View file

@ -1,14 +0,0 @@
#ifndef COSMOPOLITAN_LIBC_THREAD_YIELD_H_
#define COSMOPOLITAN_LIBC_THREAD_YIELD_H_
#if !(__ASSEMBLER__ + __LINKER__ + 0)
COSMOPOLITAN_C_START_
/**
* @fileoverview yield thread to OS scheduler
*/
int cthread_yield(void);
COSMOPOLITAN_C_END_
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
#endif /* COSMOPOLITAN_LIBC_THREAD_YIELD_H_ */

View file

@ -19,7 +19,7 @@
#include "libc/bits/atomic.h"
#include "libc/mem/mem.h"
#include "libc/runtime/runtime.h"
#include "libc/thread/zombie.h"
#include "libc/thread/thread.h"
static struct Zombie {
struct Zombie *next;

View file

@ -1,12 +0,0 @@
#ifndef COSMOPOLITAN_LIBC_THREAD_ZOMBIE_H_
#define COSMOPOLITAN_LIBC_THREAD_ZOMBIE_H_
#include "libc/thread/descriptor.h"
#if !(__ASSEMBLER__ + __LINKER__ + 0)
COSMOPOLITAN_C_START_
void cthread_zombies_add(cthread_t);
void cthread_zombies_reap(void);
COSMOPOLITAN_C_END_
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
#endif /* COSMOPOLITAN_LIBC_THREAD_ZOMBIE_H_ */

View file

@ -36,7 +36,6 @@ STATIC_YOINK("zip_uri_support");
char testlib_enable_tmp_setup_teardown;
#if 0
TEST(stat_010, testEmptyFile_sizeIsZero) {
struct stat st;
memset(&st, -1, sizeof(st));
@ -54,7 +53,6 @@ TEST(stat, enotdir) {
ASSERT_SYS(0, 0, close(creat("yo", 0644)));
ASSERT_SYS(ENOTDIR, -1, stat("yo/there", 0));
}
#endif
TEST(stat, zipos) {
struct stat st;
@ -64,7 +62,6 @@ TEST(stat, zipos) {
&st));
}
#if 0
static long Stat(const char *path, struct stat *st) {
long ax, di, si, dx;
asm volatile("syscall"
@ -112,4 +109,3 @@ BENCH(stat, bench) {
"tokenize_tests-latin1-coding-cookie-and-utf8-bom-sig.txt",
&st));
}
#endif

View file

@ -33,5 +33,6 @@ TEST(tls, test) {
__install_tls(tib);
EXPECT_EQ(31337, errno);
EXPECT_EQ(tib, __get_tls());
EXPECT_EQ(tib, __get_tls_inline());
EXPECT_EQ(tib + 0x3c, (char *)__errno_location());
}

View file

@ -16,6 +16,7 @@
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/bits/atomic.h"
#include "libc/calls/calls.h"
#include "libc/calls/sigbits.h"
#include "libc/calls/struct/sigaction.h"
@ -24,6 +25,7 @@
#include "libc/errno.h"
#include "libc/intrin/kprintf.h"
#include "libc/intrin/spinlock.h"
#include "libc/limits.h"
#include "libc/macros.internal.h"
#include "libc/nexgen32e/threaded.h"
#include "libc/rand/rand.h"
@ -35,29 +37,28 @@
#include "libc/sysv/consts/sa.h"
#include "libc/sysv/consts/sig.h"
#include "libc/testlib/testlib.h"
#include "libc/thread/thread.h"
#include "libc/time/time.h"
#define THREADS 8
#define ENTRIES 1024
_Atomic(bool) ready;
uint32_t ready;
volatile uint64_t A[THREADS * ENTRIES];
void OnChld(int sig) {
// do nothing
}
dontinline void Pause(void) {
// when ftrace is enabled
}
dontinline void Generate(int i) {
A[i] = rand64();
}
int Thrasher(void *arg) {
int i, id = (intptr_t)arg;
while (!ready) Pause();
while (!atomic_load(&ready)) {
cthread_memory_wait32(&ready, 0, 0);
}
for (i = 0; i < ENTRIES; ++i) {
Generate(id * ENTRIES + i);
}
@ -103,9 +104,13 @@ TEST(rand64, testThreadSafety_doesntProduceIdenticalValues) {
CLONE_SETTLS | CLONE_CHILD_SETTID | CLONE_CHILD_CLEARTID,
(void *)(intptr_t)i, 0, tls[i], 64, (int *)(tls[i] + 0x38)));
}
ready = true;
atomic_store(&ready, 1);
cthread_memory_wake32(&ready, INT_MAX);
for (i = 0; i < THREADS; ++i) {
_spinlock((int *)(tls[i] + 0x38));
while ((j = atomic_load((uint32_t *)(tls[i] + 0x38)))) {
// FUTEX_WAIT_PRIVATE makes it hang
cthread_memory_wait32((uint32_t *)(tls[i] + 0x38), j, 0);
}
EXPECT_SYS(0, 0, munmap(stacks[i], GetStackSize()));
free(tls[i]);
}

View file

@ -57,6 +57,21 @@ void TearDown(void) {
free(tls);
}
int DoNothing(void *arg) {
return 0;
}
////////////////////////////////////////////////////////////////////////////////
// TEST ERROR NUMBERS
TEST(clone, testNullFunc_raisesEinval) {
EXPECT_SYS(EINVAL, -1,
clone(0, stack, GetStackSize(),
CLONE_THREAD | CLONE_VM | CLONE_FS | CLONE_FILES |
CLONE_SIGHAND | CLONE_SETTLS,
0, 0, tls, 64, 0));
}
////////////////////////////////////////////////////////////////////////////////
// TEST THREADS WORK
@ -169,10 +184,6 @@ TEST(clone, tlsSystemCallsErrno_wontClobberMainThreadBecauseTls) {
////////////////////////////////////////////////////////////////////////////////
// BENCHMARK
int DoNothing(void *arg) {
return 0;
}
void LaunchThread(void) {
char *tls, *stack;
tls = __initialize_tls(malloc(64));
@ -189,6 +200,7 @@ BENCH(clone, bench) {
char *volatile tp;
errno_t *volatile ep;
EZBENCH2("__errno_location", donothing, (ep = __errno_location()));
EZBENCH2("__get_tls_inline", donothing, (tp = __get_tls_inline()));
EZBENCH2("__get_tls", donothing, (tp = __get_tls()));
EZBENCH2("clone()", donothing, LaunchThread());
}

View file

@ -0,0 +1,100 @@
/*-*- 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/dce.h"
#include "libc/errno.h"
#include "libc/runtime/internal.h"
#include "libc/runtime/runtime.h"
#include "libc/testlib/testlib.h"
#include "libc/thread/thread.h"
#include "libc/time/time.h"
static _Thread_local int tdata = 31337;
static _Thread_local int tbss;
static void *ReturnArg(void *arg) {
return arg;
}
TEST(cthread_create, testJoinDeadlock) {
ASSERT_SYS(0, EDEADLK, cthread_join(cthread_self(), 0));
}
TEST(cthread_create, testCreateReturnJoin) {
if (IsOpenbsd()) return; // TODO(jart): we've getting flakes
void *exitcode;
cthread_t thread;
ASSERT_EQ(0, cthread_create(&thread, 0, ReturnArg, ReturnArg));
ASSERT_EQ(0, cthread_join(thread, &exitcode));
ASSERT_EQ(ReturnArg, exitcode);
}
static void *ExitArg(void *arg) {
cthread_exit(arg);
}
TEST(cthread_create, testCreateExitJoin) {
if (IsOpenbsd()) return; // TODO(jart): we've getting flakes
void *exitcode;
cthread_t thread;
ASSERT_EQ(0, cthread_create(&thread, 0, ExitArg, (void *)-31337));
ASSERT_EQ(0, cthread_join(thread, &exitcode));
ASSERT_EQ((void *)-31337, exitcode);
}
TEST(gcctls, size) {
if (IsXnu()) return; // TODO(jart): codemorph
if (IsWindows()) return; // TODO(jart): codemorph
if (IsOpenbsd()) return; // TODO(jart): we've getting flakes
// schlep in .zip section too
// make sure executable isn't too huge
size_t size;
int64_t x = 0;
gmtime(&x);
ASSERT_LT((uintptr_t)_tls_size, 8192);
size = GetFileSize(GetProgramExecutableName());
if (IsTiny()) {
ASSERT_LT(size, 200 * 1024);
} else if (IsModeDbg()) {
ASSERT_LT(size, 4 * 1024 * 1024);
} else {
ASSERT_LT(size, 500 * 1024);
}
}
static void *TlsWorker(void *arg) {
ASSERT_EQ(31337, tdata);
ASSERT_EQ(0, tbss);
return 0;
}
TEST(gcctls, worksAndIsNonInheritable) {
if (IsXnu()) return; // TODO(jart): codemorph
if (IsWindows()) return; // TODO(jart): codemorph
if (IsOpenbsd()) return; // TODO(jart): we've getting flakes
void *exitcode;
cthread_t thread;
ASSERT_EQ(tdata, 31337);
ASSERT_EQ(tbss, 0);
tdata = 1337;
tbss = 1337;
ASSERT_EQ(0, cthread_create(&thread, 0, TlsWorker, (void *)-31337));
ASSERT_EQ(0, cthread_join(thread, &exitcode));
ASSERT_EQ(NULL, exitcode);
}

View file

@ -33,6 +33,7 @@ TEST_LIBC_THREAD_DIRECTDEPS = \
LIBC_STUBS \
LIBC_SYSV \
LIBC_THREAD \
LIBC_TIME \
LIBC_TESTLIB
TEST_LIBC_THREAD_DEPS := \
@ -51,20 +52,6 @@ o/$(MODE)/test/libc/thread/%.com.dbg: \
$(APE_NO_MODIFY_SELF)
@$(APELINK)
$(TEST_LIBC_THREAD_OBJS): \
DEFAULT_CCFLAGS += \
-fno-builtin
o/$(MODE)/test/libc/thread/getenv_test.com.runs: \
o/$(MODE)/test/libc/thread/getenv_test.com
@HELLO=THERE build/runit $@ $<
o/$(MODE)/test/libc/thread/fun_test.o \
o/$(MODE)/test/libc/thread/itsatrap_test.o: \
OVERRIDE_CFLAGS += \
-fno-sanitize=all \
-ftrapv
.PHONY: o/$(MODE)/test/libc/thread
o/$(MODE)/test/libc/thread: \
$(TEST_LIBC_THREAD_BINS) \

View file

@ -21,6 +21,7 @@
#include "libc/dce.h"
#include "libc/fmt/conv.h"
#include "libc/fmt/fmt.h"
#include "libc/intrin/kprintf.h"
#include "libc/log/backtrace.internal.h"
#include "libc/log/check.h"
#include "libc/log/libfatal.internal.h"

View file

@ -19,6 +19,7 @@
#include "libc/bits/bits.h"
#include "libc/calls/calls.h"
#include "libc/calls/sigbits.h"
#include "libc/calls/struct/timeval.h"
#include "libc/dce.h"
#include "libc/errno.h"
#include "libc/fmt/conv.h"
@ -206,6 +207,10 @@ void StartTcpServer(void) {
CHECK_NE(-1, (g_servfd =
socket(AF_INET, SOCK_STREAM | SOCK_CLOEXEC, IPPROTO_TCP)));
struct timeval timeo = {30};
setsockopt(g_servfd, SOL_SOCKET, SO_RCVTIMEO, &timeo, sizeof(timeo));
setsockopt(g_servfd, SOL_SOCKET, SO_SNDTIMEO, &timeo, sizeof(timeo));
LOGIFNEG1(setsockopt(g_servfd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(yes)));
if (bind(g_servfd, &g_servaddr, sizeof(g_servaddr)) == -1) {
if (g_servaddr.sin_port != 0) {
@ -271,7 +276,7 @@ void Recv(void *output, size_t outputsize) {
ssize_t tx, chunk, received;
static bool once;
static int zstatus;
static char buf[4096];
static char buf[32768];
static z_stream zs;
static struct {
size_t off;
@ -298,12 +303,12 @@ void Recv(void *output, size_t outputsize) {
return;
}
if (zstatus == Z_STREAM_END) {
close(g_clifd);
FATALF("recv zlib unexpected eof");
}
// get another fixed-size data packet from network
// pass along error conditions to caller
// pass along eof condition to zlib
INFOF("mbedtls_ssl_read");
received = mbedtls_ssl_read(&ezssl, buf, sizeof(buf));
if (!received) TlsDie("got unexpected eof", received);
if (received < 0) TlsDie("read failed", received);
@ -330,6 +335,7 @@ void Recv(void *output, size_t outputsize) {
// fallthrough
case Z_DATA_ERROR:
case Z_MEM_ERROR:
close(g_clifd);
FATALF("tls recv zlib hard error %d", zstatus);
case Z_BUF_ERROR:
zstatus = Z_OK; // harmless? nothing for inflate to do
@ -359,7 +365,10 @@ void HandleClient(void) {
/* read request to run program */
addrsize = sizeof(addr);
INFOF("accept");
CHECK_NE(-1, (g_clifd = accept4(g_servfd, &addr, &addrsize, SOCK_CLOEXEC)));
do {
g_clifd = accept4(g_servfd, &addr, &addrsize, SOCK_CLOEXEC);
} while (g_clifd == -1 && errno == EAGAIN);
CHECK_NE(-1, g_clifd);
if (fork()) {
close(g_clifd);
return;

View file

@ -18,6 +18,7 @@
*/
#include "libc/bits/safemacros.internal.h"
#include "libc/fmt/fmt.h"
#include "libc/intrin/kprintf.h"
#include "libc/mem/mem.h"
#include "libc/runtime/gc.internal.h"
#include "libc/stdio/stdio.h"

View file

@ -8,8 +8,8 @@ COSMOPOLITAN_C_START_
#define showint(x) show(".long", format(b1, "%d", x), #x)
#define showint64(x) show(".quad", format(b1, "%ld", x), #x)
#define showbyte(x) show(".byte", format(b1, "%hhn", x), #x)
#define showshort(x) show(".short", format(b1, "%hn", x), #x)
#define showbyte(x) show(".byte", format(b1, "%hhu", x), #x)
#define showshort(x) show(".short", format(b1, "%hu", x), #x)
#define showshorthex(x) show(".short", format(b1, "%#-6hX", x), #x)
#define showinthex(x) show(".long", format(b1, "%#X", x), #x)
#define showint64hex(x) show(".quad", format(b1, "%#lX", x), #x)

View file

@ -23,10 +23,12 @@
#include "libc/nt/struct/imagedosheader.internal.h"
#include "libc/nt/struct/imagentheaders.internal.h"
#include "libc/nt/struct/imageoptionalheader.internal.h"
#include "libc/runtime/gc.internal.h"
#include "libc/stdio/stdio.h"
#include "libc/sysv/consts/map.h"
#include "libc/sysv/consts/o.h"
#include "libc/sysv/consts/prot.h"
#include "libc/x/x.h"
#include "third_party/xed/x86.h"
#include "tool/decode/lib/asmcodegen.h"
#include "tool/decode/lib/flagger.h"
@ -70,7 +72,7 @@ static void *pecheckaddress(struct NtImageDosHeader *mz, size_t mzsize,
return addr;
}
static void *pecomputerva(struct NtImageDosHeader *mz, size_t mzsize,
static void *PeComputeRva(struct NtImageDosHeader *mz, size_t mzsize,
uint32_t reladdr, uint32_t addrsize) {
return pecheckaddress(mz, mzsize, (void *)((intptr_t)mz + reladdr), addrsize);
}
@ -109,13 +111,13 @@ static void showmzheader(void) {
showshorthex(mz->e_lfarlc);
showshorthex(mz->e_ovno);
show(".short",
format(b1, "%hn,%hn,%hn,%hn", mz->e_res[0], mz->e_res[1], mz->e_res[2],
format(b1, "%hu,%hu,%hu,%hu", mz->e_res[0], mz->e_res[1], mz->e_res[2],
mz->e_res[3]),
"mz->e_res");
showshorthex(mz->e_oemid);
showshorthex(mz->e_oeminfo);
show(".short",
format(b1, "%hn,%hn,%hn,%hn,%hn,%hn,%hn,%hn,%hn,%hn", mz->e_res2[0],
format(b1, "%hu,%hu,%hu,%hu,%hu,%hu,%hu,%hu,%hu,%hu", mz->e_res2[0],
mz->e_res2[1], mz->e_res2[2], mz->e_res2[3], mz->e_res2[4],
mz->e_res2[5], mz->e_res2[6], mz->e_res2[7], mz->e_res2[8],
mz->e_res2[9]),
@ -128,6 +130,7 @@ static void showdosstub(void) {
}
static void showpeoptionalheader(struct NtImageOptionalHeader *opt) {
int i;
showtitle(basename(path), "windows", "pe \"optional\" header", NULL, NULL);
printf("\n");
show(".short",
@ -169,6 +172,49 @@ static void showpeoptionalheader(struct NtImageOptionalHeader *opt) {
showint64hex(opt->SizeOfHeapCommit);
showinthex(opt->LoaderFlags);
showinthex(opt->NumberOfRvaAndSizes);
i = 0;
#define DATA_DIRECTORY(x) \
do { \
if (i++ < opt->NumberOfRvaAndSizes) { \
show(".long", \
format(b1, "%#X,%u", opt->DataDirectory[x].VirtualAddress, \
opt->DataDirectory[x].Size), \
gc(xasprintf("opt->DataDirectory[%s]", #x))); \
} \
} while (0)
DATA_DIRECTORY(kNtImageDirectoryEntryExport);
DATA_DIRECTORY(kNtImageDirectoryEntryImport);
DATA_DIRECTORY(kNtImageDirectoryEntryResource);
DATA_DIRECTORY(kNtImageDirectoryEntryException);
DATA_DIRECTORY(kNtImageDirectoryEntrySecurity);
DATA_DIRECTORY(kNtImageDirectoryEntryBasereloc);
DATA_DIRECTORY(kNtImageDirectoryEntryDebug);
DATA_DIRECTORY(kNtImageDirectoryEntryArchitecture);
DATA_DIRECTORY(kNtImageDirectoryEntryGlobalptr);
DATA_DIRECTORY(kNtImageDirectoryEntryTls);
DATA_DIRECTORY(kNtImageDirectoryEntryLoadConfig);
DATA_DIRECTORY(kNtImageDirectoryEntryBoundImport);
DATA_DIRECTORY(kNtImageDirectoryEntryIat);
DATA_DIRECTORY(kNtImageDirectoryEntryDelayImport);
DATA_DIRECTORY(kNtImageDirectoryEntryComDescriptor);
for (; i < opt->NumberOfRvaAndSizes; ++i) {
showint64hex(opt->DataDirectory[i]);
}
}
static void ShowIat(struct NtImageNtHeaders *pe, int64_t *iat, size_t n) {
printf("\n");
showtitle(basename(path), "windows", "import address table (iat)", NULL,
NULL);
printf("\n");
size_t i;
for (i = 0; i < n; ++i) {
show(".quad", format(b1, "%#lX", iat[i]),
gc(xasprintf("iat[%zu] @%#x", i, (intptr_t)(iat + i) - (intptr_t)pe)));
}
}
static void showpeheader(struct NtImageNtHeaders *pe) {
@ -195,6 +241,12 @@ static void showpeheader(struct NtImageNtHeaders *pe) {
printf("\n");
showpeoptionalheader(pecheckaddress(mz, mzsize, &pe->OptionalHeader,
pe->FileHeader.SizeOfOptionalHeader));
ShowIat(
pe,
(void *)((intptr_t)pe +
pe->OptionalHeader.DataDirectory[kNtImageDirectoryEntryImport]
.VirtualAddress),
pe->OptionalHeader.DataDirectory[kNtImageDirectoryEntryImport].Size / 8);
}
static void showall(void) {
@ -202,7 +254,7 @@ static void showall(void) {
showmzheader();
showdosstub();
if (mz->e_lfanew) {
showpeheader(pecomputerva(mz, mzsize, mz->e_lfanew,
showpeheader(PeComputeRva(mz, mzsize, mz->e_lfanew,
sizeof(struct NtImageFileHeader)));
}
}