mirror of
https://github.com/jart/cosmopolitan.git
synced 2025-07-27 21:10:29 +00:00
Make improvements
- Every unit test now passes on Apple Silicon. The final piece of this puzzle was porting our POSIX threads cancelation support, since that works differently on ARM64 XNU vs. AMD64. Our semaphore support on Apple Silicon is also superior now compared to AMD64, thanks to the grand central dispatch library which lets *NSYNC locks go faster. - The Cosmopolitan runtime is now more stable, particularly on Windows. To do this, thread local storage is mandatory at all runtime levels, and the innermost packages of the C library is no longer being built using ASAN. TLS is being bootstrapped with a 128-byte TIB during the process startup phase, and then later on the runtime re-allocates it either statically or dynamically to support code using _Thread_local. fork() and execve() now do a better job cooperating with threads. We can now check how much stack memory is left in the process or thread when functions like kprintf() / execve() etc. call alloca(), so that ENOMEM can be raised, reduce a buffer size, or just print a warning. - POSIX signal emulation is now implemented the same way kernels do it with pthread_kill() and raise(). Any thread can interrupt any other thread, regardless of what it's doing. If it's blocked on read/write then the killer thread will cancel its i/o operation so that EINTR can be returned in the mark thread immediately. If it's doing a tight CPU bound operation, then that's also interrupted by the signal delivery. Signal delivery works now by suspending a thread and pushing context data structures onto its stack, and redirecting its execution to a trampoline function, which calls SetThreadContext(GetCurrentThread()) when it's done. - We're now doing a better job managing locks and handles. On NetBSD we now close semaphore file descriptors in forked children. Semaphores on Windows can now be canceled immediately, which means mutexes/condition variables will now go faster. Apple Silicon semaphores can be canceled too. We're now using Apple's pthread_yield() funciton. Apple _nocancel syscalls are now used on XNU when appropriate to ensure pthread_cancel requests aren't lost. The MbedTLS library has been updated to support POSIX thread cancelations. See tool/build/runitd.c for an example of how it can be used for production multi-threaded tls servers. Handles on Windows now leak less often across processes. All i/o operations on Windows are now overlapped, which means file pointers can no longer be inherited across dup() and fork() for the time being. - We now spawn a thread on Windows to deliver SIGCHLD and wakeup wait4() which means, for example, that posix_spawn() now goes 3x faster. POSIX spawn is also now more correct. Like Musl, it's now able to report the failure code of execve() via a pipe although our approach favors using shared memory to do that on systems that have a true vfork() function. - We now spawn a thread to deliver SIGALRM to threads when setitimer() is used. This enables the most precise wakeups the OS makes possible. - The Cosmopolitan runtime now uses less memory. On NetBSD for example, it turned out the kernel would actually commit the PT_GNU_STACK size which caused RSS to be 6mb for every process. Now it's down to ~4kb. On Apple Silicon, we reduce the mandatory upstream thread size to the smallest possible size to reduce the memory overhead of Cosmo threads. The examples directory has a program called greenbean which can spawn a web server on Linux with 10,000 worker threads and have the memory usage of the process be ~77mb. The 1024 byte overhead of POSIX-style thread-local storage is now optional; it won't be allocated until the pthread_setspecific/getspecific functions are called. On Windows, the threads that get spawned which are internal to the libc implementation use reserve rather than commit memory, which shaves a few hundred kb. - sigaltstack() is now supported on Windows, however it's currently not able to be used to handle stack overflows, since crash signals are still generated by WIN32. However the crash handler will still switch to the alt stack, which is helpful in environments with tiny threads. - Test binaries are now smaller. Many of the mandatory dependencies of the test runner have been removed. This ensures many programs can do a better job only linking the the thing they're testing. This caused the test binaries for LIBC_FMT for example, to decrease from 200kb to 50kb - long double is no longer used in the implementation details of libc, except in the APIs that define it. The old code that used long double for time (instead of struct timespec) has now been thoroughly removed. - ShowCrashReports() is now much tinier in MODE=tiny. Instead of doing backtraces itself, it'll just print a command you can run on the shell using our new `cosmoaddr2line` program to view the backtrace. - Crash report signal handling now works in a much better way. Instead of terminating the process, it now relies on SA_RESETHAND so that the default SIG_IGN behavior can terminate the process if necessary. - Our pledge() functionality has now been fully ported to AARCH64 Linux.
This commit is contained in:
parent
c4eb838516
commit
ec480f5aa0
638 changed files with 7925 additions and 8282 deletions
|
@ -26,6 +26,7 @@
|
|||
#include "libc/intrin/atomic.h"
|
||||
#include "libc/intrin/bits.h"
|
||||
#include "libc/intrin/cmpxchg.h"
|
||||
#include "libc/intrin/describebacktrace.internal.h"
|
||||
#include "libc/intrin/directmap.internal.h"
|
||||
#include "libc/intrin/kprintf.h"
|
||||
#include "libc/intrin/leaky.internal.h"
|
||||
|
@ -830,12 +831,17 @@ static void __asan_report_memory_origin(const unsigned char *addr, int size,
|
|||
static __wur __asan_die_f *__asan_report(const void *addr, int size,
|
||||
const char *message,
|
||||
signed char kind) {
|
||||
#pragma GCC push_options
|
||||
#pragma GCC diagnostic ignored "-Wframe-larger-than="
|
||||
char buf[8192];
|
||||
CheckLargeStackAllocation(buf, sizeof(buf));
|
||||
#pragma GCC pop_options
|
||||
int i;
|
||||
wint_t c;
|
||||
signed char t;
|
||||
uint64_t x, y, z;
|
||||
char *base, *q, *p = buf;
|
||||
struct MemoryIntervals *m;
|
||||
char buf[8192], *base, *q, *p = buf;
|
||||
ftrace_enabled(-1);
|
||||
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,
|
||||
|
@ -1389,7 +1395,8 @@ void __asan_map_shadow(uintptr_t p, size_t n) {
|
|||
struct DirectMap sm;
|
||||
struct MemoryIntervals *m;
|
||||
if (OverlapsShadowSpace((void *)p, n)) {
|
||||
kprintf("error: %p size %'zu overlaps shadow space\n", p, n);
|
||||
kprintf("error: %p size %'zu overlaps shadow space: %s\n", p, n,
|
||||
DescribeBacktrace(__builtin_frame_address(0)));
|
||||
_Exit(1);
|
||||
}
|
||||
m = &_mmi;
|
||||
|
@ -1423,12 +1430,6 @@ void __asan_map_shadow(uintptr_t p, size_t n) {
|
|||
__asan_unpoison((char *)p, n);
|
||||
}
|
||||
|
||||
static size_t __asan_strlen(const char *s) {
|
||||
size_t i = 0;
|
||||
while (s[i]) ++i;
|
||||
return i;
|
||||
}
|
||||
|
||||
static textstartup void __asan_shadow_mapping(struct MemoryIntervals *m,
|
||||
size_t i) {
|
||||
uintptr_t x, y;
|
||||
|
@ -1440,87 +1441,22 @@ static textstartup void __asan_shadow_mapping(struct MemoryIntervals *m,
|
|||
}
|
||||
}
|
||||
|
||||
static textstartup char *__asan_get_last_string(char **list) {
|
||||
char *res = 0;
|
||||
for (int i = 0; list[i]; ++i) {
|
||||
res = list[i];
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
static textstartup uintptr_t __asan_get_stack_top(int argc, char **argv,
|
||||
char **envp,
|
||||
unsigned long *auxv,
|
||||
long pagesz) {
|
||||
uintptr_t top;
|
||||
const char *s;
|
||||
if ((s = __asan_get_last_string(envp)) ||
|
||||
(s = __asan_get_last_string(argv))) {
|
||||
top = (uintptr_t)s + __asan_strlen(s);
|
||||
} else {
|
||||
unsigned long *xp = auxv;
|
||||
while (*xp) xp += 2;
|
||||
top = (uintptr_t)xp;
|
||||
}
|
||||
return (top + (pagesz - 1)) & -pagesz;
|
||||
}
|
||||
|
||||
static textstartup void __asan_shadow_existing_mappings(int argc, char **argv,
|
||||
char **envp,
|
||||
unsigned long *auxv) {
|
||||
static textstartup void __asan_shadow_existing_mappings(void) {
|
||||
__asan_shadow_mapping(&_mmi, 0);
|
||||
|
||||
// WinMain() maps its own stack and its shadow too
|
||||
if (IsWindows()) {
|
||||
return;
|
||||
if (!IsWindows()) {
|
||||
int guard;
|
||||
void *addr;
|
||||
size_t size;
|
||||
__get_main_stack(&addr, &size, &guard);
|
||||
__asan_map_shadow((uintptr_t)addr, size);
|
||||
__asan_poison(addr, guard, kAsanStackOverflow);
|
||||
}
|
||||
}
|
||||
|
||||
// get microprocessor page size
|
||||
long pagesz = 4096;
|
||||
for (int i = 0; auxv[i]; i += 2) {
|
||||
if (auxv[i] == AT_PAGESZ) {
|
||||
pagesz = auxv[i + 1];
|
||||
}
|
||||
}
|
||||
|
||||
// get configured stack size of main thread
|
||||
// supported platforms use defaults ranging from 4mb to 512mb
|
||||
struct rlimit rlim;
|
||||
uintptr_t stack_size = 4 * 1024 * 1024;
|
||||
if (!sys_getrlimit(RLIMIT_STACK, &rlim) && //
|
||||
rlim.rlim_cur > 0 && rlim.rlim_cur < RLIM_INFINITY) {
|
||||
stack_size = (rlim.rlim_cur + (pagesz - 1)) & -pagesz;
|
||||
}
|
||||
|
||||
// Every UNIX system in our support vector creates arg blocks like:
|
||||
//
|
||||
// <HIGHEST-STACK-ADDRESS>
|
||||
// last environ string
|
||||
// ...
|
||||
// first environ string
|
||||
// ...
|
||||
// auxiliary value pointers
|
||||
// environ pointers
|
||||
// argument pointers
|
||||
// argument count
|
||||
// --- %rsp _start()
|
||||
// ...
|
||||
// ...
|
||||
// ... program's stack
|
||||
// ...
|
||||
// ...
|
||||
// <LOWEST-STACK-ADDRESS>
|
||||
//
|
||||
// The region of memory between highest and lowest can be computed
|
||||
// across all supported platforms ±1 page accuracy as the distance
|
||||
// between the last character of the last environ variable rounded
|
||||
// up to the microprocessor page size (this computes the top addr)
|
||||
// and the bottom is computed by subtracting RLIMIT_STACK rlim_cur
|
||||
// It's simple but gets tricky if we consider environ can be empty
|
||||
uintptr_t stack_top = __asan_get_stack_top(argc, argv, envp, auxv, pagesz);
|
||||
uintptr_t stack_bot = stack_top - stack_size;
|
||||
__asan_map_shadow(stack_bot, stack_top - stack_bot);
|
||||
__asan_poison((void *)stack_bot, GetGuardSize(), kAsanStackOverflow);
|
||||
static size_t __asan_strlen(const char *s) {
|
||||
size_t i = 0;
|
||||
while (s[i]) ++i;
|
||||
return i;
|
||||
}
|
||||
|
||||
forceinline ssize_t __write_str(const char *s) {
|
||||
|
@ -1541,7 +1477,7 @@ void __asan_init(int argc, char **argv, char **envp, unsigned long *auxv) {
|
|||
REQUIRE(dlmemalign);
|
||||
REQUIRE(dlmalloc_usable_size);
|
||||
}
|
||||
__asan_shadow_existing_mappings(argc, argv, envp, auxv);
|
||||
__asan_shadow_existing_mappings();
|
||||
__asan_map_shadow((uintptr_t)__executable_start, _end - __executable_start);
|
||||
__asan_map_shadow(0, 4096);
|
||||
__asan_poison((void *)__veil("r", 0L), getauxval(AT_PAGESZ), kAsanNullPage);
|
||||
|
|
|
@ -38,7 +38,7 @@
|
|||
*/
|
||||
errno_t cosmo_once(atomic_uint *once, void init(void)) {
|
||||
uint32_t old;
|
||||
switch ((old = atomic_load_explicit(once, memory_order_relaxed))) {
|
||||
switch ((old = atomic_load_explicit(once, memory_order_acquire))) {
|
||||
case INIT:
|
||||
if (atomic_compare_exchange_strong_explicit(once, &old, CALLING,
|
||||
memory_order_acquire,
|
||||
|
|
|
@ -31,8 +31,8 @@ int begin_cancellation_point(void) {
|
|||
if (__tls_enabled) {
|
||||
tib = __get_tls();
|
||||
if ((pt = (struct PosixThread *)tib->tib_pthread)) {
|
||||
state = pt->flags & PT_INCANCEL;
|
||||
pt->flags |= PT_INCANCEL;
|
||||
state = pt->pt_flags & PT_INCANCEL;
|
||||
pt->pt_flags |= PT_INCANCEL;
|
||||
}
|
||||
}
|
||||
return state;
|
||||
|
@ -44,8 +44,8 @@ void end_cancellation_point(int state) {
|
|||
if (__tls_enabled) {
|
||||
tib = __get_tls();
|
||||
if ((pt = (struct PosixThread *)tib->tib_pthread)) {
|
||||
pt->flags &= ~PT_INCANCEL;
|
||||
pt->flags |= state;
|
||||
pt->pt_flags &= ~PT_INCANCEL;
|
||||
pt->pt_flags |= state;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -56,7 +56,7 @@ TryAgain:
|
|||
switch (__imp_GetLastError()) {
|
||||
case kNtErrorPipeBusy:
|
||||
if (micros >= 1024) __imp_Sleep(micros / 1024);
|
||||
if (micros / 1024 < __SIG_POLLING_INTERVAL_MS) micros <<= 1;
|
||||
if (micros / 1024 < __SIG_IO_INTERVAL_MS) micros <<= 1;
|
||||
goto TryAgain;
|
||||
case kNtErrorAccessDenied:
|
||||
// GetNtOpenFlags() always greedily requests execute permissions
|
||||
|
|
|
@ -43,12 +43,10 @@ textwindows int64_t CreateFileMapping(
|
|||
flProtect, dwMaximumSizeHigh,
|
||||
dwMaximumSizeLow, opt_lpName);
|
||||
if (!hHandle) __winerr();
|
||||
#if 1
|
||||
NTTRACE("CreateFileMapping(%ld, %s, %s, %'zu, %#hs) → %ld% m", opt_hFile,
|
||||
DescribeNtSecurityAttributes(opt_lpFileMappingAttributes),
|
||||
DescribeNtPageFlags(flProtect),
|
||||
(uint64_t)dwMaximumSizeHigh << 32 | dwMaximumSizeLow, opt_lpName,
|
||||
hHandle);
|
||||
#endif
|
||||
return hHandle;
|
||||
}
|
||||
|
|
|
@ -50,7 +50,7 @@ TryAgain:
|
|||
nDefaultTimeOutMs, opt_lpSecurityAttributes);
|
||||
if (hServer == -1 && __imp_GetLastError() == kNtErrorPipeBusy) {
|
||||
if (micros >= 1024) __imp_Sleep(micros / 1024);
|
||||
if (micros / 1024 < __SIG_POLLING_INTERVAL_MS) micros <<= 1;
|
||||
if (micros / 1024 < __SIG_IO_INTERVAL_MS) micros <<= 1;
|
||||
goto TryAgain;
|
||||
}
|
||||
if (hServer == -1) __winerr();
|
||||
|
|
|
@ -28,6 +28,9 @@ __msabi extern typeof(CreateThread) *const __imp_CreateThread;
|
|||
* Opens file on the New Technology.
|
||||
*
|
||||
* @param dwStackSize may be 0 for default per executable
|
||||
* @param dwCreationFlags is a bitmask that may consist of:
|
||||
* - kNtCreateSuspended
|
||||
* - kNtStackSizeParamIsAReservation
|
||||
* @return thread handle, or 0 on failure
|
||||
* @note this wrapper takes care of ABI, STRACE()
|
||||
*/
|
||||
|
@ -38,9 +41,9 @@ CreateThread(const struct NtSecurityAttributes *lpThreadAttributes,
|
|||
int64_t hHandle;
|
||||
hHandle = __imp_CreateThread(lpThreadAttributes, dwStackSize, lpStartAddress,
|
||||
lpParameter, dwCreationFlags, opt_lpThreadId);
|
||||
NTTRACE("CreateThread(%s, %'zu, %p, %p, %s, %p) → %ld% m",
|
||||
NTTRACE("CreateThread(%s, %'zu, %t, %p, %s, %p) → %ld% m",
|
||||
DescribeNtSecurityAttributes(lpThreadAttributes), dwStackSize,
|
||||
lpStartAddress, lpParameter, dwCreationFlags, opt_lpThreadId,
|
||||
hHandle);
|
||||
lpStartAddress, lpParameter,
|
||||
DescribeThreadCreateFlags(dwCreationFlags), opt_lpThreadId, hHandle);
|
||||
return hHandle;
|
||||
}
|
||||
|
|
|
@ -42,7 +42,7 @@ __static_yoink("__cxa_finalize");
|
|||
* @return 0 on success or nonzero w/ errno
|
||||
* @note folks have forked libc in past just to unbloat atexit()
|
||||
*/
|
||||
dontasan int __cxa_atexit(void *fp, void *arg, void *pred) {
|
||||
int __cxa_atexit(void *fp, void *arg, void *pred) {
|
||||
/* asan runtime depends on this function */
|
||||
unsigned i;
|
||||
struct CxaAtexitBlock *b, *b2;
|
||||
|
|
|
@ -21,18 +21,19 @@
|
|||
|
||||
static pthread_mutex_t __cxa_lock_obj;
|
||||
|
||||
void(__cxa_lock)(void) {
|
||||
pthread_mutex_lock(&__cxa_lock_obj);
|
||||
}
|
||||
|
||||
void(__cxa_unlock)(void) {
|
||||
pthread_mutex_unlock(&__cxa_lock_obj);
|
||||
}
|
||||
|
||||
void(__cxa_funlock)(void) {
|
||||
void __cxa_wipe(void) {
|
||||
pthread_mutex_init(&__cxa_lock_obj, 0);
|
||||
}
|
||||
|
||||
__attribute__((__constructor__)) static void __cxa_init(void) {
|
||||
pthread_atfork(__cxa_lock, __cxa_unlock, __cxa_funlock);
|
||||
void __cxa_lock(void) {
|
||||
pthread_mutex_lock(&__cxa_lock_obj);
|
||||
}
|
||||
|
||||
void __cxa_unlock(void) {
|
||||
pthread_mutex_unlock(&__cxa_lock_obj);
|
||||
}
|
||||
|
||||
__attribute__((__constructor__)) static void __cxa_init(void) {
|
||||
__cxa_wipe();
|
||||
pthread_atfork(__cxa_lock, __cxa_unlock, __cxa_wipe);
|
||||
}
|
||||
|
|
|
@ -17,14 +17,11 @@
|
|||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/intrin/describebacktrace.internal.h"
|
||||
#include "libc/intrin/kprintf.h"
|
||||
#include "libc/log/libfatal.internal.h"
|
||||
#include "libc/nexgen32e/stackframe.h"
|
||||
|
||||
#define N 100
|
||||
|
||||
#define append(...) o += ksnprintf(buf + o, N - o, __VA_ARGS__)
|
||||
|
||||
dontinstrument const char *(DescribeBacktrace)(char buf[N],
|
||||
struct StackFrame *fr) {
|
||||
bool gotsome = false;
|
||||
|
@ -44,5 +41,6 @@ dontinstrument const char *(DescribeBacktrace)(char buf[N],
|
|||
}
|
||||
fr = fr->next;
|
||||
}
|
||||
*p = 0;
|
||||
return buf;
|
||||
}
|
||||
|
|
31
libc/intrin/describecancelstate.c
Normal file
31
libc/intrin/describecancelstate.c
Normal file
|
@ -0,0 +1,31 @@
|
|||
/*-*- 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 2023 Justine Alexandra Roberts Tunney │
|
||||
│ │
|
||||
│ Permission to use, copy, modify, and/or distribute this software for │
|
||||
│ any purpose with or without fee is hereby granted, provided that the │
|
||||
│ above copyright notice and this permission notice appear in all copies. │
|
||||
│ │
|
||||
│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │
|
||||
│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │
|
||||
│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │
|
||||
│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │
|
||||
│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │
|
||||
│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │
|
||||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/fmt/itoa.h"
|
||||
#include "libc/intrin/describeflags.internal.h"
|
||||
#include "libc/thread/thread.h"
|
||||
|
||||
const char *(DescribeCancelState)(char buf[12], int err, int *state) {
|
||||
if (err) return "n/a";
|
||||
if (!state) return "NULL";
|
||||
if (*state == PTHREAD_CANCEL_ENABLE) return "PTHREAD_CANCEL_ENABLE";
|
||||
if (*state == PTHREAD_CANCEL_DISABLE) return "PTHREAD_CANCEL_DISABLE";
|
||||
if (*state == PTHREAD_CANCEL_MASKED) return "PTHREAD_CANCEL_MASKED";
|
||||
FormatInt32(buf, *state);
|
||||
return buf;
|
||||
}
|
|
@ -13,6 +13,7 @@ const char *DescribeFlags(char *, size_t, const struct DescribeFlags *, size_t,
|
|||
const char *, unsigned);
|
||||
|
||||
const char *DescribeArchPrctlCode(char[12], int);
|
||||
const char *DescribeCancelState(char[12], int, int *);
|
||||
const char *DescribeCapability(char[32], int);
|
||||
const char *DescribeClockName(char[32], int);
|
||||
const char *DescribeDirfd(char[12], int);
|
||||
|
@ -43,6 +44,7 @@ const char *DescribeNtPipeOpenFlags(char[64], uint32_t);
|
|||
const char *DescribeNtProcAccessFlags(char[256], uint32_t);
|
||||
const char *DescribeNtStartFlags(char[128], uint32_t);
|
||||
const char *DescribeNtSymlinkFlags(char[64], uint32_t);
|
||||
const char *DescribeThreadCreateFlags(char[64], uint32_t);
|
||||
const char *DescribeOpenFlags(char[128], int);
|
||||
const char *DescribeOpenMode(char[15], int, int);
|
||||
const char *DescribePersonalityFlags(char[128], int);
|
||||
|
@ -68,6 +70,7 @@ const char *DescribeWhence(char[12], int);
|
|||
const char *DescribeWhichPrio(char[12], int);
|
||||
|
||||
#define DescribeArchPrctlCode(x) DescribeArchPrctlCode(alloca(12), x)
|
||||
#define DescribeCancelState(x, y) DescribeCancelState(alloca(12), x, y)
|
||||
#define DescribeCapability(x) DescribeCapability(alloca(32), x)
|
||||
#define DescribeClockName(x) DescribeClockName(alloca(32), x)
|
||||
#define DescribeDirfd(x) DescribeDirfd(alloca(12), x)
|
||||
|
@ -116,6 +119,7 @@ const char *DescribeWhichPrio(char[12], int);
|
|||
#define DescribeSocketType(x) DescribeSocketType(alloca(64), x)
|
||||
#define DescribeStdioState(x) DescribeStdioState(alloca(12), x)
|
||||
#define DescribeStringList(x) DescribeStringList(alloca(300), x)
|
||||
#define DescribeThreadCreateFlags(x) DescribeThreadCreateFlags(alloca(64), x)
|
||||
#define DescribeWhence(x) DescribeWhence(alloca(12), x)
|
||||
#define DescribeWhichPrio(x) DescribeWhichPrio(alloca(12), x)
|
||||
|
||||
|
|
|
@ -16,32 +16,16 @@
|
|||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/bo.internal.h"
|
||||
#include "libc/thread/posixthread.internal.h"
|
||||
#include "libc/thread/tls.h"
|
||||
#include "libc/intrin/describeflags.internal.h"
|
||||
#include "libc/macros.internal.h"
|
||||
#include "libc/nt/enum/processcreationflags.h"
|
||||
|
||||
int begin_blocking_operation(void) {
|
||||
int state = 0;
|
||||
struct CosmoTib *tib;
|
||||
struct PosixThread *pt;
|
||||
if (__tls_enabled) {
|
||||
tib = __get_tls();
|
||||
if ((pt = (struct PosixThread *)tib->tib_pthread)) {
|
||||
state = pt->flags & PT_BLOCKED;
|
||||
pt->flags |= PT_BLOCKED;
|
||||
}
|
||||
}
|
||||
return state;
|
||||
}
|
||||
static const struct DescribeFlags kThreadCreationFlags[] = {
|
||||
{kNtCreateSuspended, "kNtCreateSuspended"}, //
|
||||
{kNtStackSizeParamIsAReservation, "kNtStackSizeParamIsAReservation"}, //
|
||||
};
|
||||
|
||||
void end_blocking_operation(int state) {
|
||||
struct CosmoTib *tib;
|
||||
struct PosixThread *pt;
|
||||
if (__tls_enabled) {
|
||||
tib = __get_tls();
|
||||
if ((pt = (struct PosixThread *)tib->tib_pthread)) {
|
||||
pt->flags &= ~PT_BLOCKED;
|
||||
pt->flags |= state;
|
||||
}
|
||||
}
|
||||
const char *(DescribeThreadCreateFlags)(char buf[64], uint32_t x) {
|
||||
return DescribeFlags(buf, 64, kThreadCreationFlags,
|
||||
ARRAYLEN(kThreadCreationFlags), "", x);
|
||||
}
|
|
@ -20,6 +20,10 @@ static inline void dll_init(struct Dll *e) {
|
|||
e->prev = e;
|
||||
}
|
||||
|
||||
static inline int dll_is_alone(struct Dll *e) {
|
||||
return e->next == e && e->prev == e;
|
||||
}
|
||||
|
||||
static inline int dll_is_empty(struct Dll *list) {
|
||||
return !list;
|
||||
}
|
||||
|
|
|
@ -16,11 +16,9 @@
|
|||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/intrin/strace.internal.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/thread/tls.h"
|
||||
|
||||
void __require_tls(void) {
|
||||
if (!__tls_enabled) {
|
||||
notpossible;
|
||||
}
|
||||
void __enable_threads(void) {
|
||||
__threaded = 1;
|
||||
}
|
|
@ -23,9 +23,11 @@
|
|||
#include "libc/nexgen32e/vendor.internal.h"
|
||||
#include "libc/nt/enum/status.h"
|
||||
#include "libc/nt/runtime.h"
|
||||
#include "libc/nt/thunk/msabi.h"
|
||||
#include "libc/runtime/internal.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/sysv/consts/nr.h"
|
||||
#include "libc/sysv/consts/sig.h"
|
||||
|
||||
/**
|
||||
* Terminates process, ignoring destructors and atexit() handlers.
|
||||
|
@ -101,7 +103,7 @@ wontreturn void _Exit(int exitcode) {
|
|||
if (waitstatus == kNtStillActive) {
|
||||
waitstatus = 0xc9af3d51u;
|
||||
}
|
||||
ExitProcess(waitstatus);
|
||||
TerminateThisProcess(waitstatus);
|
||||
}
|
||||
#ifdef __x86_64__
|
||||
asm("push\t$0\n\t"
|
||||
|
|
|
@ -83,7 +83,7 @@ privileged wontreturn void _Exit1(int rc) {
|
|||
: "i"(93), "r"(r0)
|
||||
: "x8", "memory");
|
||||
} else if (IsXnu()) {
|
||||
__syslib->pthread_exit(0);
|
||||
__syslib->__pthread_exit(0);
|
||||
}
|
||||
notpossible;
|
||||
#else
|
||||
|
|
|
@ -17,18 +17,12 @@
|
|||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/state.internal.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "libc/thread/thread.h"
|
||||
|
||||
void(__fds_lock)(void) {
|
||||
void __fds_lock(void) {
|
||||
pthread_mutex_lock(&__fds_lock_obj);
|
||||
}
|
||||
|
||||
void(__fds_unlock)(void) {
|
||||
void __fds_unlock(void) {
|
||||
pthread_mutex_unlock(&__fds_lock_obj);
|
||||
}
|
||||
|
||||
void __fds_funlock(void) {
|
||||
bzero(&__fds_lock_obj, sizeof(__fds_lock_obj));
|
||||
__fds_lock_obj._type = PTHREAD_MUTEX_RECURSIVE;
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
|
||||
│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│
|
||||
╞══════════════════════════════════════════════════════════════════════════════╡
|
||||
│ Copyright 2022 Justine Alexandra Roberts Tunney │
|
||||
│ Copyright 2021 Justine Alexandra Roberts Tunney │
|
||||
│ │
|
||||
│ Permission to use, copy, modify, and/or distribute this software for │
|
||||
│ any purpose with or without fee is hereby granted, provided that the │
|
||||
|
@ -16,26 +16,49 @@
|
|||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/assert.h"
|
||||
#include "libc/errno.h"
|
||||
#include "libc/intrin/atomic.h"
|
||||
#include "libc/thread/posixthread.internal.h"
|
||||
#include "libc/thread/thread.h"
|
||||
#include "libc/fmt/itoa.h"
|
||||
#include "libc/intrin/bsr.h"
|
||||
#include "libc/macros.internal.h"
|
||||
|
||||
static inline int PickGoodWidth(unsigned x, char z) {
|
||||
if (z) {
|
||||
if (x < 16) {
|
||||
if (x < 8) return 8;
|
||||
return 16;
|
||||
} else {
|
||||
if (x < 32) return 32;
|
||||
return 64;
|
||||
}
|
||||
} else {
|
||||
return ROUNDUP(x + 1, 4);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes TLS slot.
|
||||
* Converts unsigned 64-bit integer to hex string.
|
||||
*
|
||||
* This function should only be called if all threads have finished
|
||||
* using the key registration. If a key is used after being deleted
|
||||
* then the behavior is undefined. If `k` was not registered by the
|
||||
* pthread_key_create() function then the behavior is undefined.
|
||||
*
|
||||
* @param key was created by pthread_key_create()
|
||||
* @return 0 on success, or errno on error
|
||||
* @param p needs at least 19 bytes
|
||||
* @param z is 0 for DIGITS, 1 for 0xDIGITS, 2 for 0xDIGITS if ≠0
|
||||
* @return pointer to nul byte
|
||||
*/
|
||||
int pthread_key_delete(pthread_key_t k) {
|
||||
unassert(0 <= k && k < PTHREAD_KEYS_MAX);
|
||||
unassert(atomic_load_explicit(_pthread_key_dtor + k, memory_order_acquire));
|
||||
atomic_store_explicit(_pthread_key_dtor + k, 0, memory_order_release);
|
||||
return 0;
|
||||
char *FormatHex64(char p[hasatleast 19], uint64_t x, char z) {
|
||||
int i;
|
||||
if (x) {
|
||||
if (z) {
|
||||
*p++ = '0';
|
||||
*p++ = 'x';
|
||||
}
|
||||
i = PickGoodWidth(_bsrl(x), z);
|
||||
do {
|
||||
*p++ = "0123456789abcdef"[(x >> (i -= 4)) & 15];
|
||||
} while (i);
|
||||
} else {
|
||||
if (z == 1) {
|
||||
*p++ = '0';
|
||||
*p++ = 'x';
|
||||
}
|
||||
*p++ = '0';
|
||||
}
|
||||
*p = 0;
|
||||
return p;
|
||||
}
|
120
libc/intrin/getmainstack.c
Normal file
120
libc/intrin/getmainstack.c
Normal file
|
@ -0,0 +1,120 @@
|
|||
/*-*- 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 2023 Justine Alexandra Roberts Tunney │
|
||||
│ │
|
||||
│ Permission to use, copy, modify, and/or distribute this software for │
|
||||
│ any purpose with or without fee is hereby granted, provided that the │
|
||||
│ 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/assert.h"
|
||||
#include "libc/calls/struct/rlimit.h"
|
||||
#include "libc/calls/struct/rlimit.internal.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/intrin/kprintf.h"
|
||||
#include "libc/macros.internal.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/runtime/stack.h"
|
||||
#include "libc/sysv/consts/auxv.h"
|
||||
#include "libc/sysv/consts/rlim.h"
|
||||
#include "libc/sysv/consts/rlimit.h"
|
||||
|
||||
// Every UNIX system in our support vector creates arg blocks like:
|
||||
//
|
||||
// <HIGHEST-STACK-ADDRESS>
|
||||
// last environ string
|
||||
// ...
|
||||
// first environ string
|
||||
// ...
|
||||
// auxiliary value pointers
|
||||
// environ pointers
|
||||
// argument pointers
|
||||
// argument count
|
||||
// --- %rsp _start()
|
||||
// ...
|
||||
// ...
|
||||
// ... program's stack
|
||||
// ...
|
||||
// ...
|
||||
// <LOWEST-STACK-ADDRESS>
|
||||
//
|
||||
// The region of memory between highest and lowest can be computed
|
||||
// across all supported platforms ±1 page accuracy as the distance
|
||||
// between the last character of the last environ variable rounded
|
||||
// up to the microprocessor page size (this computes the top addr)
|
||||
// and the bottom is computed by subtracting RLIMIT_STACK rlim_cur
|
||||
// It's simple but gets tricky if we consider environ can be empty
|
||||
|
||||
static char *__get_last(char **list) {
|
||||
char *res = 0;
|
||||
for (int i = 0; list[i]; ++i) {
|
||||
res = list[i];
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
static int __get_length(const char *s) {
|
||||
int n = 0;
|
||||
while (*s++) ++n;
|
||||
return n;
|
||||
}
|
||||
|
||||
static uintptr_t __get_main_top(int pagesz) {
|
||||
uintptr_t top;
|
||||
const char *s;
|
||||
if ((s = __get_last(__envp)) || (s = __get_last(__argv))) {
|
||||
top = (uintptr_t)s + __get_length(s);
|
||||
} else {
|
||||
unsigned long *xp = __auxv;
|
||||
while (*xp) xp += 2;
|
||||
top = (uintptr_t)xp;
|
||||
}
|
||||
return ROUNDUP(top, pagesz);
|
||||
}
|
||||
|
||||
static size_t __get_stack_size(int pagesz, uintptr_t start, uintptr_t top) {
|
||||
size_t size, max = 8 * 1024 * 1024;
|
||||
struct rlimit rlim = {RLIM_INFINITY};
|
||||
sys_getrlimit(RLIMIT_STACK, &rlim);
|
||||
if ((size = rlim.rlim_cur) > max) size = max;
|
||||
return MAX(ROUNDUP(size, pagesz), ROUNDUP(top - start, pagesz));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns approximate boundaries of main thread stack.
|
||||
*/
|
||||
void __get_main_stack(void **out_addr, size_t *out_size, int *out_guardsize) {
|
||||
if (IsWindows()) {
|
||||
*out_addr = (void *)GetStaticStackAddr(0);
|
||||
*out_size = GetStaticStackSize();
|
||||
*out_guardsize = 4096;
|
||||
return;
|
||||
}
|
||||
int pagesz = getauxval(AT_PAGESZ);
|
||||
uintptr_t start = (uintptr_t)__argv;
|
||||
uintptr_t top = __get_main_top(pagesz);
|
||||
uintptr_t bot = top - __get_stack_size(pagesz, start, top);
|
||||
uintptr_t vdso = getauxval(AT_SYSINFO_EHDR);
|
||||
if (vdso) {
|
||||
if (vdso > start && vdso < top) {
|
||||
top = vdso;
|
||||
} else if (vdso < start && vdso >= bot) {
|
||||
bot += vdso + pagesz * 2;
|
||||
}
|
||||
}
|
||||
unassert(bot < top);
|
||||
unassert(bot < start);
|
||||
unassert(top > start);
|
||||
*out_addr = (void *)bot;
|
||||
*out_size = top - bot;
|
||||
*out_guardsize = pagesz;
|
||||
}
|
33
libc/intrin/getminsigstksz.c
Normal file
33
libc/intrin/getminsigstksz.c
Normal file
|
@ -0,0 +1,33 @@
|
|||
/*-*- 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 2023 Justine Alexandra Roberts Tunney │
|
||||
│ │
|
||||
│ Permission to use, copy, modify, and/or distribute this software for │
|
||||
│ any purpose with or without fee is hereby granted, provided that the │
|
||||
│ above copyright notice and this permission notice appear in all copies. │
|
||||
│ │
|
||||
│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │
|
||||
│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │
|
||||
│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │
|
||||
│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │
|
||||
│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │
|
||||
│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │
|
||||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/intrin/getauxval.internal.h"
|
||||
#include "libc/macros.internal.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/sysv/consts/auxv.h"
|
||||
#include "libc/sysv/consts/ss.h"
|
||||
|
||||
long __get_minsigstksz(void) {
|
||||
struct AuxiliaryValue x;
|
||||
x = __getauxval(AT_MINSIGSTKSZ);
|
||||
if (x.isfound) {
|
||||
return MAX(_MINSIGSTKSZ, x.value);
|
||||
} else {
|
||||
return _MINSIGSTKSZ;
|
||||
}
|
||||
}
|
|
@ -1,7 +1,7 @@
|
|||
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
|
||||
│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│
|
||||
╞══════════════════════════════════════════════════════════════════════════════╡
|
||||
│ Copyright 2022 Justine Alexandra Roberts Tunney │
|
||||
│ Copyright 2023 Justine Alexandra Roberts Tunney │
|
||||
│ │
|
||||
│ Permission to use, copy, modify, and/or distribute this software for │
|
||||
│ any purpose with or without fee is hereby granted, provided that the │
|
||||
|
@ -16,26 +16,34 @@
|
|||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/assert.h"
|
||||
#include "libc/intrin/atomic.h"
|
||||
#include "libc/runtime/stack.h"
|
||||
#include "libc/thread/posixthread.internal.h"
|
||||
#include "libc/thread/thread.h"
|
||||
#include "libc/thread/tls.h"
|
||||
#include "libc/thread/tls2.internal.h"
|
||||
|
||||
/**
|
||||
* Gets value of TLS slot for current thread.
|
||||
* Computes safer buffer size for alloca().
|
||||
*
|
||||
* If `k` wasn't created by pthread_key_create() then the behavior is
|
||||
* undefined. If `k` was unregistered earlier by pthread_key_delete()
|
||||
* then the behavior is undefined.
|
||||
* @param want defines an upper limit on the return value
|
||||
* @param extraspace is how much stack caller needs that isn't buffer
|
||||
* @return number of bytes to use for your buffer, or negative if the
|
||||
* allocation would likely cause a stack overflow
|
||||
*/
|
||||
void *pthread_getspecific(pthread_key_t k) {
|
||||
// "The effect of calling pthread_getspecific() or
|
||||
// pthread_setspecific() with a key value not obtained from
|
||||
// pthread_key_create() or after key has been deleted with
|
||||
// pthread_key_delete() is undefined."
|
||||
// ──Quoth POSIX.1-2017
|
||||
unassert(0 <= k && k < PTHREAD_KEYS_MAX);
|
||||
unassert(atomic_load_explicit(_pthread_key_dtor + k, memory_order_acquire));
|
||||
return __get_tls()->tib_keys[k];
|
||||
privileged long __get_safe_size(long want, long extraspace) {
|
||||
if (!__tls_enabled) return want;
|
||||
struct PosixThread *pt;
|
||||
struct CosmoTib *tib = __get_tls_privileged();
|
||||
long bottom, sp = GetStackPointer();
|
||||
if ((char *)sp >= tib->tib_sigstack_addr &&
|
||||
(char *)sp <= tib->tib_sigstack_addr + tib->tib_sigstack_size) {
|
||||
bottom = (long)tib->tib_sigstack_addr;
|
||||
} else if ((pt = (struct PosixThread *)tib->tib_pthread) &&
|
||||
pt->attr.__stacksize) {
|
||||
bottom = (long)pt->attr.__stackaddr + pt->attr.__guardsize;
|
||||
} else {
|
||||
return want;
|
||||
}
|
||||
long size = sp - bottom - extraspace;
|
||||
if (size > want) size = want;
|
||||
return size;
|
||||
}
|
|
@ -19,8 +19,10 @@
|
|||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/state.internal.h"
|
||||
#include "libc/calls/syscall-sysv.internal.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/intrin/atomic.h"
|
||||
#include "libc/intrin/likely.h"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
#include "libc/thread/tls.h"
|
||||
|
||||
/**
|
||||
|
@ -43,5 +45,9 @@ int gettid(void) {
|
|||
return tid;
|
||||
}
|
||||
}
|
||||
return sys_gettid();
|
||||
if (IsXnuSilicon()) {
|
||||
return enosys();
|
||||
} else {
|
||||
return sys_gettid();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -28,7 +28,7 @@
|
|||
|
||||
static nsync_mu __hand_mu;
|
||||
|
||||
void __hand_init(void) {
|
||||
void __hand_wipe(void) {
|
||||
if (!SupportsWindows()) return;
|
||||
bzero(&__hand_mu, sizeof(__hand_mu));
|
||||
}
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||
COSMOPOLITAN_C_START_
|
||||
|
||||
void __hand_init(void);
|
||||
void __hand_wipe(void);
|
||||
void __hand_rlock(void);
|
||||
void __hand_runlock(void);
|
||||
void __hand_lock(void);
|
||||
|
|
|
@ -49,17 +49,25 @@ $(LIBC_INTRIN_A).pkg: \
|
|||
o/$(MODE)/libc/intrin/mman.greg.o: private COPTS += -Os
|
||||
|
||||
$(LIBC_INTRIN_A_OBJS): private \
|
||||
CFLAGS += \
|
||||
COPTS += \
|
||||
-x-no-pg \
|
||||
-ffreestanding \
|
||||
-fno-sanitize=all \
|
||||
-fno-stack-protector
|
||||
-fno-stack-protector \
|
||||
-Wframe-larger-than=4096 \
|
||||
-Walloca-larger-than=4096
|
||||
|
||||
o/$(MODE)/libc/intrin/kprintf.o: private \
|
||||
CFLAGS += \
|
||||
-Wframe-larger-than=128 \
|
||||
-Walloca-larger-than=128
|
||||
|
||||
o/$(MODE)/libc/intrin/asan.o: private \
|
||||
CFLAGS += \
|
||||
-O2 \
|
||||
-finline \
|
||||
-finline-functions
|
||||
-finline-functions \
|
||||
-fpatchable-function-entry=0,0
|
||||
|
||||
o//libc/intrin/memmove.o: private \
|
||||
CFLAGS += \
|
||||
|
@ -113,6 +121,8 @@ o/$(MODE)/libc/intrin/ktcpoptnames.o: libc/intrin/ktcpoptnames.S
|
|||
@$(COMPILE) -AOBJECTIFY.S $(OBJECTIFY.S) $(OUTPUT_OPTION) -c $<
|
||||
o/$(MODE)/libc/intrin/sched_yield.o: libc/intrin/sched_yield.S
|
||||
@$(COMPILE) -AOBJECTIFY.S $(OBJECTIFY.S) $(OUTPUT_OPTION) -c $<
|
||||
o/$(MODE)/libc/intrin/stackcall.o: libc/intrin/stackcall.S
|
||||
@$(COMPILE) -AOBJECTIFY.S $(OBJECTIFY.S) $(OUTPUT_OPTION) -c $<
|
||||
|
||||
LIBC_INTRIN_LIBS = $(foreach x,$(LIBC_INTRIN_ARTIFACTS),$($(x)))
|
||||
LIBC_INTRIN_HDRS = $(foreach x,$(LIBC_INTRIN_ARTIFACTS),$($(x)_HDRS))
|
||||
|
|
|
@ -16,7 +16,7 @@
|
|||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/cp.internal.h"
|
||||
#include "libc/calls/blockcancel.internal.h"
|
||||
#include "libc/calls/syscall-sysv.internal.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/errno.h"
|
||||
|
@ -52,7 +52,7 @@ int IsDebuggerPresent(bool force) {
|
|||
if (!PLEDGED(RPATH)) return false;
|
||||
res = 0;
|
||||
e = errno;
|
||||
BEGIN_CANCELLATION_POINT;
|
||||
BLOCK_CANCELLATIONS;
|
||||
if ((fd = __sys_openat(AT_FDCWD, "/proc/self/status", O_RDONLY, 0)) >= 0) {
|
||||
if ((got = sys_read(fd, buf, sizeof(buf) - 1)) > 0) {
|
||||
buf[got] = '\0';
|
||||
|
@ -63,7 +63,7 @@ int IsDebuggerPresent(bool force) {
|
|||
}
|
||||
sys_close(fd);
|
||||
}
|
||||
END_CANCELLATION_POINT;
|
||||
ALLOW_CANCELLATIONS;
|
||||
errno = e;
|
||||
return res;
|
||||
}
|
||||
|
|
|
@ -43,6 +43,7 @@
|
|||
#include "libc/limits.h"
|
||||
#include "libc/log/internal.h"
|
||||
#include "libc/macros.internal.h"
|
||||
#include "libc/mem/alloca.h"
|
||||
#include "libc/nexgen32e/rdtsc.h"
|
||||
#include "libc/nexgen32e/uart.internal.h"
|
||||
#include "libc/nt/createfile.h"
|
||||
|
@ -73,10 +74,13 @@
|
|||
#include "libc/sysv/consts/nr.h"
|
||||
#include "libc/sysv/consts/o.h"
|
||||
#include "libc/sysv/consts/prot.h"
|
||||
#include "libc/thread/posixthread.internal.h"
|
||||
#include "libc/thread/tls.h"
|
||||
#include "libc/thread/tls2.internal.h"
|
||||
#include "libc/vga/vga.internal.h"
|
||||
|
||||
#define STACK_ERROR "kprintf error: stack is about to overflow\n"
|
||||
|
||||
#define KGETINT(x, va, t, s) \
|
||||
switch (t) { \
|
||||
case -3: \
|
||||
|
@ -123,7 +127,6 @@
|
|||
// clang-format off
|
||||
__msabi extern typeof(CreateFile) *const __imp_CreateFileW;
|
||||
__msabi extern typeof(DuplicateHandle) *const __imp_DuplicateHandle;
|
||||
__msabi extern typeof(GetCurrentProcess) *const __imp_GetCurrentProcess;
|
||||
__msabi extern typeof(GetEnvironmentVariable) *const __imp_GetEnvironmentVariableW;
|
||||
__msabi extern typeof(GetLastError) *const __imp_GetLastError;
|
||||
__msabi extern typeof(GetStdHandle) *const __imp_GetStdHandle;
|
||||
|
@ -322,10 +325,8 @@ privileged long kloghandle(void) {
|
|||
e = __imp_GetLastError();
|
||||
n = __imp_GetEnvironmentVariableW(u"KPRINTF_LOG", path, 512);
|
||||
if (!n && __imp_GetLastError() == kNtErrorEnvvarNotFound) {
|
||||
long proc;
|
||||
proc = __imp_GetCurrentProcess();
|
||||
hand = __imp_GetStdHandle(kNtStdErrorHandle);
|
||||
__imp_DuplicateHandle(proc, hand, proc, &hand, 0, false,
|
||||
__imp_DuplicateHandle(-1, hand, -1, &hand, 0, false,
|
||||
kNtDuplicateSameAccess);
|
||||
} else if (n && n < 512) {
|
||||
hand = __imp_CreateFileW(
|
||||
|
@ -423,6 +424,8 @@ privileged void klog(const char *b, size_t n) {
|
|||
: "rcx", "r8", "r9", "r10", "r11", "memory", "cc");
|
||||
}
|
||||
#elif defined(__aarch64__)
|
||||
// this isn't a cancellation point because we don't acknowledge eintr
|
||||
// on xnu we use the "nocancel" version of the system call for safety
|
||||
register long r0 asm("x0") = kloghandle();
|
||||
register long r1 asm("x1") = (long)b;
|
||||
register long r2 asm("x2") = (long)n;
|
||||
|
@ -740,11 +743,8 @@ privileged static size_t kformat(char *b, size_t n, const char *fmt,
|
|||
|
||||
case 'G':
|
||||
x = va_arg(va, int);
|
||||
if (_weaken(strsignal_r) && (s = _weaken(strsignal_r)(x, z))) {
|
||||
goto FormatString;
|
||||
} else {
|
||||
goto FormatDecimal;
|
||||
}
|
||||
s = strsignal_r(x, z);
|
||||
goto FormatString;
|
||||
|
||||
case 't': {
|
||||
// %t will print the &symbol associated with an address. this
|
||||
|
@ -1032,10 +1032,18 @@ privileged size_t kvsnprintf(char *b, size_t n, const char *fmt, va_list v) {
|
|||
* @vforksafe
|
||||
*/
|
||||
privileged void kvprintf(const char *fmt, va_list v) {
|
||||
size_t n;
|
||||
char b[4000];
|
||||
n = kformat(b, sizeof(b), fmt, v);
|
||||
klog(b, MIN(n, sizeof(b) - 1));
|
||||
#pragma GCC push_options
|
||||
#pragma GCC diagnostic ignored "-Walloca-larger-than="
|
||||
long size = __get_safe_size(8000, 3000);
|
||||
if (size < 80) {
|
||||
klog(STACK_ERROR, sizeof(STACK_ERROR) - 1);
|
||||
return;
|
||||
}
|
||||
char *buf = alloca(size);
|
||||
CheckLargeStackAllocation(buf, size);
|
||||
#pragma GCC pop_options
|
||||
size_t count = kformat(buf, size, fmt, v);
|
||||
klog(buf, MIN(count, size - 1));
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -67,7 +67,6 @@ static bool __extend_memory(struct MemoryIntervals *mm) {
|
|||
base = (char *)kMemtrackStart;
|
||||
prot = PROT_READ | PROT_WRITE;
|
||||
flags = MAP_ANONYMOUS | MAP_PRIVATE | MAP_FIXED;
|
||||
// TODO(jart): These map handles should not leak across NT fork()
|
||||
if (mm->p == mm->s) {
|
||||
// TODO(jart): How can we detect ASAN mode under GREG?
|
||||
if (1 || IsAsan()) {
|
||||
|
|
|
@ -47,6 +47,13 @@
|
|||
#define INVERT(x) (BANE + PHYSICAL(x))
|
||||
#define NOPAGE ((uint64_t)-1)
|
||||
|
||||
#define ABS64(x) \
|
||||
({ \
|
||||
int64_t vAddr; \
|
||||
__asm__("movabs\t%1,%0" : "=r"(vAddr) : "i"(x)); \
|
||||
vAddr; \
|
||||
})
|
||||
|
||||
struct ReclaimedPage {
|
||||
uint64_t next;
|
||||
};
|
||||
|
@ -252,37 +259,56 @@ textreal void __setup_mman(struct mman *mm, uint64_t *pml4t, uint64_t top) {
|
|||
__invert_memory(mm, pml4t);
|
||||
}
|
||||
|
||||
static textreal uint64_t __map_phdr(struct mman *mm, uint64_t *pml4t,
|
||||
uint64_t b, uint64_t m,
|
||||
struct Elf64_Phdr *p) {
|
||||
uint64_t i, f, v;
|
||||
f = PAGE_RSRV | PAGE_U;
|
||||
if (p->p_flags & PF_W)
|
||||
f |= PAGE_V | PAGE_RW;
|
||||
else if (p->p_flags & (PF_R | PF_X))
|
||||
f |= PAGE_V;
|
||||
if (!(p->p_flags & PF_X)) f |= PAGE_XD;
|
||||
for (i = 0; i < p->p_memsz; i += 4096) {
|
||||
if (i < p->p_filesz) {
|
||||
v = b + p->p_offset + i;
|
||||
m = MAX(m, v);
|
||||
} else {
|
||||
v = __clear_page(BANE + __new_page(mm));
|
||||
}
|
||||
*__get_virtual(mm, pml4t, p->p_vaddr + i, true) = (v & PAGE_TA) | f;
|
||||
__ref_page(mm, pml4t, v & PAGE_TA);
|
||||
}
|
||||
return m;
|
||||
}
|
||||
|
||||
/**
|
||||
* Maps APE-defined ELF program headers into memory and clears BSS.
|
||||
*/
|
||||
textreal void __map_phdrs(struct mman *mm, uint64_t *pml4t, uint64_t b,
|
||||
uint64_t top) {
|
||||
uint64_t i, f, v, m;
|
||||
uint64_t m;
|
||||
struct Elf64_Phdr *p;
|
||||
extern char ape_phdrs[] __attribute__((__weak__));
|
||||
extern char ape_phdrs_end[] __attribute__((__weak__));
|
||||
extern char ape_stack_pf[] __attribute__((__weak__));
|
||||
extern char ape_stack_offset[] __attribute__((__weak__));
|
||||
extern char ape_stack_vaddr[] __attribute__((__weak__));
|
||||
extern char ape_stack_filesz[] __attribute__((__weak__));
|
||||
extern char ape_stack_memsz[] __attribute__((__weak__));
|
||||
__setup_mman(mm, pml4t, top);
|
||||
for (p = (struct Elf64_Phdr *)INVERT(ape_phdrs), m = 0;
|
||||
p < (struct Elf64_Phdr *)INVERT(ape_phdrs_end); ++p) {
|
||||
if (p->p_type == PT_LOAD || p->p_type == PT_GNU_STACK) {
|
||||
f = PAGE_RSRV | PAGE_U;
|
||||
if (p->p_flags & PF_W)
|
||||
f |= PAGE_V | PAGE_RW;
|
||||
else if (p->p_flags & (PF_R | PF_X))
|
||||
f |= PAGE_V;
|
||||
if (!(p->p_flags & PF_X)) f |= PAGE_XD;
|
||||
for (i = 0; i < p->p_memsz; i += 4096) {
|
||||
if (i < p->p_filesz) {
|
||||
v = b + p->p_offset + i;
|
||||
m = MAX(m, v);
|
||||
} else {
|
||||
v = __clear_page(BANE + __new_page(mm));
|
||||
}
|
||||
*__get_virtual(mm, pml4t, p->p_vaddr + i, true) = (v & PAGE_TA) | f;
|
||||
__ref_page(mm, pml4t, v & PAGE_TA);
|
||||
}
|
||||
}
|
||||
m = __map_phdr(mm, pml4t, b, m, p);
|
||||
}
|
||||
m = __map_phdr(mm, pml4t, b, m,
|
||||
&(struct Elf64_Phdr){
|
||||
.p_flags = (uintptr_t)ape_stack_pf,
|
||||
.p_offset = (uintptr_t)ape_stack_offset,
|
||||
.p_vaddr = ABS64(ape_stack_vaddr),
|
||||
.p_filesz = (uintptr_t)ape_stack_filesz,
|
||||
.p_memsz = (uintptr_t)ape_stack_memsz,
|
||||
});
|
||||
mm->pdp = MAX(mm->pdp, m);
|
||||
}
|
||||
|
||||
|
|
|
@ -17,17 +17,14 @@
|
|||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/runtime/memtrack.internal.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "libc/thread/thread.h"
|
||||
|
||||
// this lock currently needs to be (1) recursive and (2) not nsync
|
||||
|
||||
extern pthread_mutex_t __mmi_lock_obj;
|
||||
|
||||
void(__mmi_lock)(void) {
|
||||
void __mmi_lock(void) {
|
||||
pthread_mutex_lock(&__mmi_lock_obj);
|
||||
}
|
||||
|
||||
void(__mmi_unlock)(void) {
|
||||
void __mmi_unlock(void) {
|
||||
pthread_mutex_unlock(&__mmi_lock_obj);
|
||||
}
|
||||
|
|
79
libc/intrin/ntcontext2linux.c
Normal file
79
libc/intrin/ntcontext2linux.c
Normal file
|
@ -0,0 +1,79 @@
|
|||
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
|
||||
│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│
|
||||
╞══════════════════════════════════════════════════════════════════════════════╡
|
||||
│ Copyright 2020 Justine Alexandra Roberts Tunney │
|
||||
│ │
|
||||
│ Permission to use, copy, modify, and/or distribute this software for │
|
||||
│ any purpose with or without fee is hereby granted, provided that the │
|
||||
│ above copyright notice and this permission notice appear in all copies. │
|
||||
│ │
|
||||
│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │
|
||||
│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │
|
||||
│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │
|
||||
│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │
|
||||
│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │
|
||||
│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │
|
||||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/ucontext.h"
|
||||
#include "libc/log/libfatal.internal.h"
|
||||
#include "libc/nt/struct/context.h"
|
||||
#include "libc/str/str.h"
|
||||
|
||||
#ifdef __x86_64__
|
||||
|
||||
textwindows void _ntcontext2linux(ucontext_t *ctx, const struct NtContext *cr) {
|
||||
if (!cr) return;
|
||||
ctx->uc_mcontext.eflags = cr->EFlags;
|
||||
ctx->uc_mcontext.rax = cr->Rax;
|
||||
ctx->uc_mcontext.rbx = cr->Rbx;
|
||||
ctx->uc_mcontext.rcx = cr->Rcx;
|
||||
ctx->uc_mcontext.rdx = cr->Rdx;
|
||||
ctx->uc_mcontext.rdi = cr->Rdi;
|
||||
ctx->uc_mcontext.rsi = cr->Rsi;
|
||||
ctx->uc_mcontext.rbp = cr->Rbp;
|
||||
ctx->uc_mcontext.rsp = cr->Rsp;
|
||||
ctx->uc_mcontext.rip = cr->Rip;
|
||||
ctx->uc_mcontext.r8 = cr->R8;
|
||||
ctx->uc_mcontext.r9 = cr->R9;
|
||||
ctx->uc_mcontext.r10 = cr->R10;
|
||||
ctx->uc_mcontext.r11 = cr->R11;
|
||||
ctx->uc_mcontext.r12 = cr->R12;
|
||||
ctx->uc_mcontext.r13 = cr->R13;
|
||||
ctx->uc_mcontext.r14 = cr->R14;
|
||||
ctx->uc_mcontext.r15 = cr->R15;
|
||||
ctx->uc_mcontext.cs = cr->SegCs;
|
||||
ctx->uc_mcontext.gs = cr->SegGs;
|
||||
ctx->uc_mcontext.fs = cr->SegFs;
|
||||
ctx->uc_mcontext.fpregs = &ctx->__fpustate;
|
||||
__repmovsb(&ctx->__fpustate, &cr->FltSave, sizeof(ctx->__fpustate));
|
||||
}
|
||||
|
||||
textwindows void _ntlinux2context(struct NtContext *cr, const ucontext_t *ctx) {
|
||||
if (!cr) return;
|
||||
cr->EFlags = ctx->uc_mcontext.eflags;
|
||||
cr->Rax = ctx->uc_mcontext.rax;
|
||||
cr->Rbx = ctx->uc_mcontext.rbx;
|
||||
cr->Rcx = ctx->uc_mcontext.rcx;
|
||||
cr->Rdx = ctx->uc_mcontext.rdx;
|
||||
cr->Rdi = ctx->uc_mcontext.rdi;
|
||||
cr->Rsi = ctx->uc_mcontext.rsi;
|
||||
cr->Rbp = ctx->uc_mcontext.rbp;
|
||||
cr->Rsp = ctx->uc_mcontext.rsp;
|
||||
cr->Rip = ctx->uc_mcontext.rip;
|
||||
cr->R8 = ctx->uc_mcontext.r8;
|
||||
cr->R9 = ctx->uc_mcontext.r9;
|
||||
cr->R10 = ctx->uc_mcontext.r10;
|
||||
cr->R11 = ctx->uc_mcontext.r11;
|
||||
cr->R12 = ctx->uc_mcontext.r12;
|
||||
cr->R13 = ctx->uc_mcontext.r13;
|
||||
cr->R14 = ctx->uc_mcontext.r14;
|
||||
cr->R15 = ctx->uc_mcontext.r15;
|
||||
cr->SegCs = ctx->uc_mcontext.cs;
|
||||
cr->SegGs = ctx->uc_mcontext.gs;
|
||||
cr->SegFs = ctx->uc_mcontext.fs;
|
||||
__repmovsb(&cr->FltSave, &ctx->__fpustate, sizeof(ctx->__fpustate));
|
||||
}
|
||||
|
||||
#endif /* __x86_64__ */
|
|
@ -34,6 +34,10 @@
|
|||
* // data structures...
|
||||
* } g_lib;
|
||||
*
|
||||
* static void lib_wipe(void) {
|
||||
* pthread_mutex_init(&g_lib.lock, 0);
|
||||
* }
|
||||
*
|
||||
* static void lib_lock(void) {
|
||||
* pthread_mutex_lock(&g_lib.lock);
|
||||
* }
|
||||
|
@ -42,13 +46,9 @@
|
|||
* pthread_mutex_unlock(&g_lib.lock);
|
||||
* }
|
||||
*
|
||||
* static void lib_funlock(void) {
|
||||
* pthread_mutex_init(&g_lib.lock, 0);
|
||||
* }
|
||||
*
|
||||
* static void lib_setup(void) {
|
||||
* lib_funlock();
|
||||
* pthread_atfork(lib_lock, lib_unlock, lib_funlock);
|
||||
* lib_wipe();
|
||||
* pthread_atfork(lib_lock, lib_unlock, lib_wipe);
|
||||
* }
|
||||
*
|
||||
* static void lib_init(void) {
|
||||
|
@ -62,14 +62,6 @@
|
|||
* lib_unlock();
|
||||
* }
|
||||
*
|
||||
* This won't actually aspect fork() until pthread_create() is called,
|
||||
* since we don't want normal non-threaded programs to have to acquire
|
||||
* exclusive locks on every resource in the entire app just to fork().
|
||||
*
|
||||
* The vfork() function is *never* aspected. What happens instead is a
|
||||
* global variable named `__vforked` is set to true in the child which
|
||||
* causes lock functions to do nothing. So far, it works like a charm.
|
||||
*
|
||||
* @param prepare is run by fork() before forking happens
|
||||
* @param parent is run by fork() after forking happens in parent process
|
||||
* @param child is run by fork() after forking happens in childe process
|
||||
|
|
|
@ -23,7 +23,7 @@
|
|||
|
||||
void(pthread_cleanup_pop)(struct _pthread_cleanup_buffer *cb, int execute) {
|
||||
struct PosixThread *pt;
|
||||
if (__tls_enabled && (pt = (struct PosixThread *)__get_tls()->tib_pthread)) {
|
||||
if (__tls_enabled && (pt = _pthread_self())) {
|
||||
unassert(cb == pt->cleanup);
|
||||
pt->cleanup = cb->__prev;
|
||||
}
|
||||
|
|
|
@ -25,7 +25,7 @@ void(pthread_cleanup_push)(struct _pthread_cleanup_buffer *cb,
|
|||
struct PosixThread *pt;
|
||||
cb->__routine = routine;
|
||||
cb->__arg = arg;
|
||||
if (__tls_enabled && (pt = (struct PosixThread *)__get_tls()->tib_pthread)) {
|
||||
if (__tls_enabled && (pt = _pthread_self())) {
|
||||
cb->__prev = pt->cleanup;
|
||||
pt->cleanup = cb;
|
||||
}
|
||||
|
|
|
@ -1,60 +0,0 @@
|
|||
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
|
||||
│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│
|
||||
╞══════════════════════════════════════════════════════════════════════════════╡
|
||||
│ Copyright 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/errno.h"
|
||||
#include "libc/intrin/atomic.h"
|
||||
#include "libc/thread/posixthread.internal.h"
|
||||
#include "libc/thread/thread.h"
|
||||
|
||||
/**
|
||||
* Allocates TLS slot.
|
||||
*
|
||||
* This function creates a thread-local storage registration, that will
|
||||
* apply to all threads. The new identifier is written to `key`, and it
|
||||
* can be passed to the pthread_setspecific() and pthread_getspecific()
|
||||
* functions to set and get its associated value. Each thread will have
|
||||
* its key value initialized to zero upon creation. It is also possible
|
||||
* to use pthread_key_delete() to unregister a key.
|
||||
*
|
||||
* If `dtor` is non-null, then it'll be called upon pthread_exit() when
|
||||
* the key's value is nonzero. The key's value is set to zero before it
|
||||
* is called. The ordering of multiple destructor calls is unspecified.
|
||||
* The same key can be destroyed `PTHREAD_DESTRUCTOR_ITERATIONS` times,
|
||||
* in cases where it gets set again by a destructor.
|
||||
*
|
||||
* @param key is set to the allocated key on success
|
||||
* @param dtor specifies an optional destructor callback
|
||||
* @return 0 on success, or errno on error
|
||||
* @raise EAGAIN if `PTHREAD_KEYS_MAX` keys exist
|
||||
*/
|
||||
int pthread_key_create(pthread_key_t *key, pthread_key_dtor dtor) {
|
||||
int i;
|
||||
pthread_key_dtor expect;
|
||||
if (!dtor) dtor = (pthread_key_dtor)-1;
|
||||
for (i = 0; i < PTHREAD_KEYS_MAX; ++i) {
|
||||
if (!(expect = atomic_load_explicit(_pthread_key_dtor + i,
|
||||
memory_order_acquire)) &&
|
||||
atomic_compare_exchange_strong_explicit(_pthread_key_dtor + i, &expect,
|
||||
dtor, memory_order_release,
|
||||
memory_order_relaxed)) {
|
||||
*key = i;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return EAGAIN;
|
||||
}
|
|
@ -1,7 +1,7 @@
|
|||
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
|
||||
│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│
|
||||
╞══════════════════════════════════════════════════════════════════════════════╡
|
||||
│ Copyright 2022 Justine Alexandra Roberts Tunney │
|
||||
│ Copyright 2023 Justine Alexandra Roberts Tunney │
|
||||
│ │
|
||||
│ Permission to use, copy, modify, and/or distribute this software for │
|
||||
│ any purpose with or without fee is hereby granted, provided that the │
|
||||
|
@ -17,6 +17,5 @@
|
|||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/thread/posixthread.internal.h"
|
||||
#include "libc/thread/thread.h"
|
||||
|
||||
_Atomic(pthread_key_dtor) _pthread_key_dtor[PTHREAD_KEYS_MAX];
|
||||
struct PosixThread _pthread_static;
|
|
@ -67,14 +67,13 @@
|
|||
int pthread_mutex_lock(pthread_mutex_t *mutex) {
|
||||
int t;
|
||||
|
||||
if ((!__threaded && mutex->_pshared != PTHREAD_PROCESS_SHARED) || __vforked) {
|
||||
LOCKTRACE("pthread_mutex_lock(%t)", mutex);
|
||||
|
||||
if (__vforked) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
LOCKTRACE("pthread_mutex_lock(%t)", mutex);
|
||||
|
||||
if (__tls_enabled && //
|
||||
mutex->_type == PTHREAD_MUTEX_NORMAL && //
|
||||
if (mutex->_type == PTHREAD_MUTEX_NORMAL && //
|
||||
mutex->_pshared == PTHREAD_PROCESS_PRIVATE && //
|
||||
_weaken(nsync_mu_lock)) {
|
||||
_weaken(nsync_mu_lock)((nsync_mu *)mutex);
|
||||
|
|
|
@ -39,14 +39,9 @@
|
|||
int pthread_mutex_unlock(pthread_mutex_t *mutex) {
|
||||
int t;
|
||||
|
||||
if ((!__threaded && mutex->_pshared != PTHREAD_PROCESS_SHARED) || __vforked) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
LOCKTRACE("pthread_mutex_unlock(%t)", mutex);
|
||||
|
||||
if (__tls_enabled && //
|
||||
mutex->_type == PTHREAD_MUTEX_NORMAL && //
|
||||
if (mutex->_type == PTHREAD_MUTEX_NORMAL && //
|
||||
mutex->_pshared == PTHREAD_PROCESS_PRIVATE && //
|
||||
_weaken(nsync_mu_unlock)) {
|
||||
_weaken(nsync_mu_unlock)((nsync_mu *)mutex);
|
||||
|
|
32
libc/intrin/pthread_next.c
Normal file
32
libc/intrin/pthread_next.c
Normal file
|
@ -0,0 +1,32 @@
|
|||
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
|
||||
│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│
|
||||
╞══════════════════════════════════════════════════════════════════════════════╡
|
||||
│ Copyright 2023 Justine Alexandra Roberts Tunney │
|
||||
│ │
|
||||
│ Permission to use, copy, modify, and/or distribute this software for │
|
||||
│ any purpose with or without fee is hereby granted, provided that the │
|
||||
│ 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/assert.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/intrin/atomic.h"
|
||||
#include "libc/thread/posixthread.internal.h"
|
||||
|
||||
intptr_t _pthread_syshand(struct PosixThread *pt) {
|
||||
intptr_t syshand;
|
||||
unassert(IsWindows() || IsXnuSilicon());
|
||||
for (;;) {
|
||||
syshand = atomic_load_explicit(&pt->tib->tib_syshand, memory_order_acquire);
|
||||
if (syshand) return syshand;
|
||||
pthread_yield();
|
||||
}
|
||||
}
|
|
@ -16,8 +16,10 @@
|
|||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/blockcancel.internal.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/errno.h"
|
||||
#include "libc/intrin/describeflags.internal.h"
|
||||
#include "libc/intrin/strace.internal.h"
|
||||
#include "libc/thread/posixthread.internal.h"
|
||||
#include "libc/thread/thread.h"
|
||||
#include "libc/thread/tls.h"
|
||||
|
@ -45,37 +47,46 @@
|
|||
* @asyncsignalsafe
|
||||
*/
|
||||
errno_t pthread_setcancelstate(int state, int *oldstate) {
|
||||
errno_t err;
|
||||
struct PosixThread *pt;
|
||||
if (__tls_enabled && (pt = (struct PosixThread *)__get_tls()->tib_pthread)) {
|
||||
if (__tls_enabled && (pt = _pthread_self())) {
|
||||
switch (state) {
|
||||
case PTHREAD_CANCEL_ENABLE:
|
||||
case PTHREAD_CANCEL_DISABLE:
|
||||
case PTHREAD_CANCEL_MASKED:
|
||||
if (oldstate) {
|
||||
if (pt->flags & PT_NOCANCEL) {
|
||||
if (pt->pt_flags & PT_NOCANCEL) {
|
||||
*oldstate = PTHREAD_CANCEL_DISABLE;
|
||||
} else if (pt->flags & PT_MASKED) {
|
||||
} else if (pt->pt_flags & PT_MASKED) {
|
||||
*oldstate = PTHREAD_CANCEL_MASKED;
|
||||
} else {
|
||||
*oldstate = PTHREAD_CANCEL_ENABLE;
|
||||
}
|
||||
}
|
||||
pt->flags &= ~(PT_NOCANCEL | PT_MASKED);
|
||||
pt->pt_flags &= ~(PT_NOCANCEL | PT_MASKED);
|
||||
if (state == PTHREAD_CANCEL_MASKED) {
|
||||
pt->flags |= PT_MASKED;
|
||||
pt->pt_flags |= PT_MASKED;
|
||||
} else if (state == PTHREAD_CANCEL_DISABLE) {
|
||||
pt->flags |= PT_NOCANCEL;
|
||||
pt->pt_flags |= PT_NOCANCEL;
|
||||
}
|
||||
return 0;
|
||||
err = 0;
|
||||
break;
|
||||
default:
|
||||
return EINVAL;
|
||||
err = EINVAL;
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
if (oldstate) {
|
||||
*oldstate = 0;
|
||||
}
|
||||
return 0;
|
||||
err = 0;
|
||||
}
|
||||
#if IsModeDbg()
|
||||
STRACE("pthread_setcancelstate(%s, [%s]) → %s",
|
||||
DescribeCancelState(0, &state), DescribeCancelState(err, oldstate),
|
||||
DescribeErrno(err));
|
||||
#endif
|
||||
return err;
|
||||
}
|
||||
|
||||
int _pthread_block_cancellations(void) {
|
||||
|
|
|
@ -1,42 +0,0 @@
|
|||
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
|
||||
│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│
|
||||
╞══════════════════════════════════════════════════════════════════════════════╡
|
||||
│ Copyright 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/assert.h"
|
||||
#include "libc/intrin/atomic.h"
|
||||
#include "libc/thread/posixthread.internal.h"
|
||||
#include "libc/thread/thread.h"
|
||||
#include "libc/thread/tls.h"
|
||||
|
||||
/**
|
||||
* Sets value of TLS slot for current thread.
|
||||
*
|
||||
* If `k` wasn't created by pthread_key_create() then the behavior is
|
||||
* undefined. If `k` was unregistered earlier by pthread_key_delete()
|
||||
* then the behavior is undefined.
|
||||
*/
|
||||
int pthread_setspecific(pthread_key_t k, const void *val) {
|
||||
// "The effect of calling pthread_getspecific() or
|
||||
// pthread_setspecific() with a key value not obtained from
|
||||
// pthread_key_create() or after key has been deleted with
|
||||
// pthread_key_delete() is undefined."
|
||||
// ──Quoth POSIX.1-2017
|
||||
unassert(0 <= k && k < PTHREAD_KEYS_MAX);
|
||||
unassert(atomic_load_explicit(_pthread_key_dtor + k, memory_order_acquire));
|
||||
__get_tls()->tib_keys[k] = (void *)val;
|
||||
return 0;
|
||||
}
|
|
@ -1,7 +1,7 @@
|
|||
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
|
||||
│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│
|
||||
╞══════════════════════════════════════════════════════════════════════════════╡
|
||||
│ Copyright 2022 Justine Alexandra Roberts Tunney │
|
||||
│ Copyright 2023 Justine Alexandra Roberts Tunney │
|
||||
│ │
|
||||
│ Permission to use, copy, modify, and/or distribute this software for │
|
||||
│ any purpose with or without fee is hereby granted, provided that the │
|
||||
|
@ -16,15 +16,13 @@
|
|||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/struct/sigset.h"
|
||||
#include "libc/sysv/consts/sig.h"
|
||||
#include "libc/intrin/atomic.h"
|
||||
#include "libc/thread/posixthread.internal.h"
|
||||
|
||||
/**
|
||||
* Returns true if you're not authorized to block this signal.
|
||||
*/
|
||||
int sigisprecious(int sig) {
|
||||
return 0
|
||||
#define M(x) || sig == x
|
||||
#include "libc/intrin/sigisprecious.inc"
|
||||
;
|
||||
int _pthread_tid(struct PosixThread *pt) {
|
||||
int tid = 0;
|
||||
while (pt && !(tid = atomic_load_explicit(&pt->ptid, memory_order_acquire))) {
|
||||
pthread_yield();
|
||||
}
|
||||
return tid;
|
||||
}
|
|
@ -17,7 +17,9 @@
|
|||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/intrin/strace.internal.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/runtime/syslib.internal.h"
|
||||
#include "libc/thread/thread.h"
|
||||
|
||||
/**
|
||||
|
@ -26,7 +28,10 @@
|
|||
* @return 0 on success, or error number on failure
|
||||
*/
|
||||
int pthread_yield(void) {
|
||||
sched_yield();
|
||||
STRACE("pthread_yield()");
|
||||
if (IsXnuSilicon()) {
|
||||
__syslib->__pthread_yield_np();
|
||||
} else {
|
||||
sched_yield();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -48,6 +48,8 @@ static char **GrowEnviron(char **a) {
|
|||
for (p = b; *a;) {
|
||||
*p++ = *a++;
|
||||
}
|
||||
} else {
|
||||
b[0] = 0;
|
||||
}
|
||||
environ = b;
|
||||
expected = b;
|
||||
|
|
|
@ -29,8 +29,8 @@
|
|||
* Copies variable to environment.
|
||||
*
|
||||
* @return 0 on success, or -1 w/ errno and environment is unchanged
|
||||
* @raise ENOMEM if out of memory or malloc() wasn't linked
|
||||
* @raise EINVAL if `name` is empty or contains `'='`
|
||||
* @raise ENOMEM if we require more vespene gas
|
||||
* @see putenv(), getenv()
|
||||
* @threadunsafe
|
||||
*/
|
||||
|
|
23
libc/intrin/sighandrvas.c
Normal file
23
libc/intrin/sighandrvas.c
Normal file
|
@ -0,0 +1,23 @@
|
|||
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
|
||||
│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│
|
||||
╞══════════════════════════════════════════════════════════════════════════════╡
|
||||
│ Copyright 2020 Justine Alexandra Roberts Tunney │
|
||||
│ │
|
||||
│ Permission to use, copy, modify, and/or distribute this software for │
|
||||
│ any purpose with or without fee is hereby granted, provided that the │
|
||||
│ above copyright notice and this permission notice appear in all copies. │
|
||||
│ │
|
||||
│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │
|
||||
│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │
|
||||
│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │
|
||||
│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │
|
||||
│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │
|
||||
│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │
|
||||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/state.internal.h"
|
||||
#include "libc/thread/thread.h"
|
||||
|
||||
unsigned __sighandrvas[NSIG + 1];
|
||||
unsigned __sighandflags[NSIG + 1];
|
58
libc/intrin/stackcall.S
Normal file
58
libc/intrin/stackcall.S
Normal file
|
@ -0,0 +1,58 @@
|
|||
/*-*- mode:unix-assembly; indent-tabs-mode:t; tab-width:8; coding:utf-8 -*-│
|
||||
│vi: set et ft=asm ts=8 tw=8 fenc=utf-8 :vi│
|
||||
╞══════════════════════════════════════════════════════════════════════════════╡
|
||||
│ Copyright 2023 Justine Alexandra Roberts Tunney │
|
||||
│ │
|
||||
│ Permission to use, copy, modify, and/or distribute this software for │
|
||||
│ any purpose with or without fee is hereby granted, provided that the │
|
||||
│ above copyright notice and this permission notice appear in all copies. │
|
||||
│ │
|
||||
│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │
|
||||
│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │
|
||||
│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │
|
||||
│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │
|
||||
│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │
|
||||
│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │
|
||||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/macros.internal.h"
|
||||
|
||||
// Calls function on different stack.
|
||||
//
|
||||
// @param %rdi is arg1
|
||||
// @param %rsi is arg2
|
||||
// @param %rdx is arg3
|
||||
// @param %rcx is arg4
|
||||
// @param %r8 is func
|
||||
// @param %r9 is stack
|
||||
// @return %rax is res
|
||||
__stack_call:
|
||||
#ifdef __x86_64__
|
||||
push %rbx
|
||||
push %r15
|
||||
mov %rbp,%r15
|
||||
mov %rsp,%rbx
|
||||
mov %r9,%rsp
|
||||
xor %rbp,%rbp
|
||||
call *%r8
|
||||
mov %r15,%rbp
|
||||
mov %rbx,%rsp
|
||||
pop %r15
|
||||
pop %rbx
|
||||
ret
|
||||
#elif defined(__aarch64__)
|
||||
stp x29,x30,[sp,#-32]!
|
||||
str x27,[sp,16]
|
||||
mov x27,sp
|
||||
and sp,x5,#-16
|
||||
mov x29,0
|
||||
blr x4
|
||||
mov sp,x27
|
||||
ldr x27,[sp,16]
|
||||
ldp x29,x30,[sp],#32
|
||||
ret
|
||||
#else
|
||||
#error "unsupported architecture"
|
||||
#endif
|
||||
.endfn __stack_call,globl
|
|
@ -53,7 +53,7 @@ COSMOPOLITAN_C_START_
|
|||
#endif
|
||||
|
||||
#if defined(SYSDEBUG) && _NTTRACE
|
||||
#define NTTRACE(FMT, ...) STRACE(FMT, ##__VA_ARGS__)
|
||||
#define NTTRACE(FMT, ...) STRACE("\e[2m" FMT "\e[0m", ##__VA_ARGS__)
|
||||
#else
|
||||
#define NTTRACE(FMT, ...) (void)0
|
||||
#endif
|
||||
|
|
|
@ -64,7 +64,6 @@ int sys_gettid(void) {
|
|||
return tid;
|
||||
#elif defined(__aarch64__)
|
||||
// this can't be used on xnu
|
||||
if (!IsLinux()) notpossible;
|
||||
register long res asm("x0");
|
||||
asm volatile("mov\tx8,%1\n\t"
|
||||
"svc\t0"
|
||||
|
|
32
libc/intrin/terminatethisprocess.c
Normal file
32
libc/intrin/terminatethisprocess.c
Normal file
|
@ -0,0 +1,32 @@
|
|||
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
|
||||
│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│
|
||||
╞══════════════════════════════════════════════════════════════════════════════╡
|
||||
│ Copyright 2022 Justine Alexandra Roberts Tunney │
|
||||
│ │
|
||||
│ Permission to use, copy, modify, and/or distribute this software for │
|
||||
│ any purpose with or without fee is hereby granted, provided that the │
|
||||
│ above copyright notice and this permission notice appear in all copies. │
|
||||
│ │
|
||||
│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │
|
||||
│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │
|
||||
│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │
|
||||
│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │
|
||||
│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │
|
||||
│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │
|
||||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/nt/runtime.h"
|
||||
#include "libc/nt/thunk/msabi.h"
|
||||
|
||||
__msabi extern typeof(TerminateProcess) *const __imp_TerminateProcess;
|
||||
|
||||
/**
|
||||
* Terminates the calling process and all of its threads.
|
||||
*/
|
||||
textwindows dontinstrument void TerminateThisProcess(uint32_t dwWaitStatus) {
|
||||
// "When a process terminates itself, TerminateProcess stops execution
|
||||
// of the calling thread and does not return." -Quoth MSDN
|
||||
__imp_TerminateProcess(-1, dwWaitStatus);
|
||||
__builtin_unreachable();
|
||||
}
|
|
@ -25,12 +25,11 @@ __msabi extern typeof(WaitForSingleObject) *const __imp_WaitForSingleObject;
|
|||
|
||||
/**
|
||||
* Waits for handle to change status.
|
||||
* @note this wrapper takes care of ABI, STRACE(), and __winerr()
|
||||
* @return -1u on error w/ GetLastError()
|
||||
*/
|
||||
uint32_t WaitForSingleObject(int64_t hHandle, uint32_t dwMilliseconds) {
|
||||
uint32_t rc;
|
||||
rc = __imp_WaitForSingleObject(hHandle, dwMilliseconds);
|
||||
if (rc == -1u) __winerr();
|
||||
POLLTRACE("WaitForSingleObject(%ld, %'d) → %d% m", hHandle, dwMilliseconds,
|
||||
rc);
|
||||
return rc;
|
||||
|
|
40
libc/intrin/wintlsinit.c
Normal file
40
libc/intrin/wintlsinit.c
Normal file
|
@ -0,0 +1,40 @@
|
|||
/*-*- 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 2023 Justine Alexandra Roberts Tunney │
|
||||
│ │
|
||||
│ Permission to use, copy, modify, and/or distribute this software for │
|
||||
│ any purpose with or without fee is hereby granted, provided that the │
|
||||
│ 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/log/libfatal.internal.h"
|
||||
#include "libc/nt/thread.h"
|
||||
#include "libc/nt/thunk/msabi.h"
|
||||
#include "libc/thread/tls.h"
|
||||
#include "libc/thread/tls2.internal.h"
|
||||
|
||||
__msabi extern typeof(GetCurrentThreadId) *const __imp_GetCurrentThreadId;
|
||||
|
||||
/**
|
||||
* Initializes bare minimum TLS for Windows thread.
|
||||
*/
|
||||
textwindows dontinstrument void __bootstrap_tls(struct CosmoTib *tib,
|
||||
char *bp) {
|
||||
__repstosb(tib, 0, sizeof(*tib));
|
||||
tib->tib_self = tib;
|
||||
tib->tib_self2 = tib;
|
||||
tib->tib_sigmask = -1;
|
||||
tib->tib_sigstack_size = 57344;
|
||||
tib->tib_sigstack_addr = bp - 57344;
|
||||
tib->tib_tid = __imp_GetCurrentThreadId();
|
||||
__set_tls_win32(tib);
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue