mirror of
https://github.com/jart/cosmopolitan.git
synced 2025-03-03 07:29:23 +00:00
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:
parent
909e54510d
commit
425ff5dff0
61 changed files with 529 additions and 382 deletions
|
@ -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));
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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))
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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) {
|
|
@ -1,6 +1,5 @@
|
|||
#ifndef LIBC_ISYSTEM_PTHREAD_H_
|
||||
#define LIBC_ISYSTEM_PTHREAD_H_
|
||||
|
||||
#include "libc/calls/calls.h"
|
||||
|
||||
#define PTHREAD_ONCE_INIT 0
|
||||
|
|
|
@ -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 \
|
||||
|
|
|
@ -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;
|
||||
}
|
|
@ -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");
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
|
|
38
libc/stdio/fputc_unlocked.c
Normal file
38
libc/stdio/fputc_unlocked.c
Normal 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;
|
||||
}
|
||||
}
|
|
@ -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.
|
||||
*
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
}
|
|
@ -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 \
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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_ */
|
|
@ -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;
|
||||
|
|
|
@ -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_ */
|
|
@ -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_ */
|
|
@ -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.
|
||||
|
|
|
@ -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_ */
|
||||
|
|
@ -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.
|
||||
|
|
|
@ -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_ */
|
|
@ -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_ */
|
||||
|
|
|
@ -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 = {
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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_ */
|
|
@ -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();
|
||||
}
|
||||
|
|
|
@ -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_ */
|
|
@ -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");
|
||||
|
||||
|
|
|
@ -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
80
libc/thread/thread.h
Normal 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_ */
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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_ */
|
|
@ -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.
|
||||
|
|
|
@ -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_ */
|
|
@ -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;
|
||||
|
|
|
@ -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_ */
|
|
@ -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
|
||||
|
|
|
@ -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());
|
||||
}
|
||||
|
|
|
@ -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]);
|
||||
}
|
||||
|
|
|
@ -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());
|
||||
}
|
||||
|
|
100
test/libc/thread/create_test.c
Normal file
100
test/libc/thread/create_test.c
Normal 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);
|
||||
}
|
|
@ -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) \
|
||||
|
|
1
third_party/mbedtls/test/lib.c
vendored
1
third_party/mbedtls/test/lib.c
vendored
|
@ -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"
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)));
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue