mirror of
https://github.com/jart/cosmopolitan.git
synced 2025-05-23 05:42:29 +00:00
Make some minor fixups to bug reporting, etc.
This commit is contained in:
parent
84764ce7b8
commit
3f015b1e51
31 changed files with 244 additions and 134 deletions
|
@ -73,7 +73,8 @@ static bool ExtendMemoryIntervals(struct MemoryIntervals *mm) {
|
||||||
flags = MAP_ANONYMOUS | MAP_PRIVATE | MAP_FIXED;
|
flags = MAP_ANONYMOUS | MAP_PRIVATE | MAP_FIXED;
|
||||||
// TODO(jart): These map handles should not leak across NT fork()
|
// TODO(jart): These map handles should not leak across NT fork()
|
||||||
if (mm->p == mm->s) {
|
if (mm->p == mm->s) {
|
||||||
if (IsAsan()) {
|
// TODO(jart): How can we detect ASAN mode under GREG?
|
||||||
|
if (1 || IsAsan()) {
|
||||||
shad = (char *)(((intptr_t)base >> 3) + 0x7fff8000);
|
shad = (char *)(((intptr_t)base >> 3) + 0x7fff8000);
|
||||||
dm = sys_mmap(shad, gran >> 3, prot, flags, -1, 0);
|
dm = sys_mmap(shad, gran >> 3, prot, flags, -1, 0);
|
||||||
if (!dm.addr) return false;
|
if (!dm.addr) return false;
|
||||||
|
|
|
@ -19,13 +19,6 @@
|
||||||
#include "libc/fmt/itoa.h"
|
#include "libc/fmt/itoa.h"
|
||||||
#include "libc/nexgen32e/nexgen32e.h"
|
#include "libc/nexgen32e/nexgen32e.h"
|
||||||
|
|
||||||
static const unsigned char kTensIndex[] = {
|
|
||||||
0, 0, 0, 1, 1, 1, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, //
|
|
||||||
5, 5, 5, 6, 6, 6, 6, 7, 7, 7, 8, 8, 8, 9, 9, 9, //
|
|
||||||
10, 10, 10, 11, 11, 11, 12, 12, 12, 12, 13, 13, 13, 14, 14, 14, //
|
|
||||||
15, 15, 15, 15, 16, 16, 16, 17, 17, 17, 18, 18, 18, 18, 19, 19, //
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns `len(str(x))` where x is an unsigned 64-bit integer.
|
* Returns `len(str(x))` where x is an unsigned 64-bit integer.
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -195,7 +195,8 @@ static uint64_t __asan_roundup2pow(uint64_t x) {
|
||||||
static char *__asan_utf8cpy(char *p, unsigned c) {
|
static char *__asan_utf8cpy(char *p, unsigned c) {
|
||||||
uint64_t z;
|
uint64_t z;
|
||||||
z = tpenc(c);
|
z = tpenc(c);
|
||||||
do *p++ = z;
|
do
|
||||||
|
*p++ = z;
|
||||||
while ((z >>= 8));
|
while ((z >>= 8));
|
||||||
return p;
|
return p;
|
||||||
}
|
}
|
||||||
|
@ -946,7 +947,8 @@ static void __asan_trace(struct AsanTrace *bt, const struct StackFrame *bp) {
|
||||||
if (!__asan_checka(SHADOW(bp), sizeof(*bp) >> 3).kind) {
|
if (!__asan_checka(SHADOW(bp), sizeof(*bp) >> 3).kind) {
|
||||||
addr = bp->addr;
|
addr = bp->addr;
|
||||||
if (addr == weakaddr("__gc") && weakaddr("__gc")) {
|
if (addr == weakaddr("__gc") && weakaddr("__gc")) {
|
||||||
do --gi;
|
do
|
||||||
|
--gi;
|
||||||
while ((addr = garbage->p[gi].ret) == weakaddr("__gc"));
|
while ((addr = garbage->p[gi].ret) == weakaddr("__gc"));
|
||||||
}
|
}
|
||||||
bt->p[i] = addr;
|
bt->p[i] = addr;
|
||||||
|
@ -1197,7 +1199,7 @@ void __asan_stack_free(char *p, size_t size, int classid) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void __asan_handle_no_return(void) {
|
void __asan_handle_no_return(void) {
|
||||||
__asan_unpoison(GetStackAddr(0), GetStackSize());
|
__asan_unpoison((void *)GetStackAddr(), GetStackSize());
|
||||||
}
|
}
|
||||||
|
|
||||||
void __asan_register_globals(struct AsanGlobal g[], int n) {
|
void __asan_register_globals(struct AsanGlobal g[], int n) {
|
||||||
|
@ -1379,8 +1381,8 @@ static textstartup void __asan_shadow_mapping(struct MemoryIntervals *m,
|
||||||
|
|
||||||
static textstartup void __asan_shadow_existing_mappings(void) {
|
static textstartup void __asan_shadow_existing_mappings(void) {
|
||||||
__asan_shadow_mapping(&_mmi, 0);
|
__asan_shadow_mapping(&_mmi, 0);
|
||||||
__asan_map_shadow((intptr_t)GetStackAddr(0), GetStackSize());
|
__asan_map_shadow(GetStackAddr(), GetStackSize());
|
||||||
__asan_poison(GetStackAddr(0), PAGESIZE, kAsanStackOverflow);
|
__asan_poison((void *)GetStackAddr(), PAGESIZE, kAsanStackOverflow);
|
||||||
}
|
}
|
||||||
|
|
||||||
textstartup void __asan_init(int argc, char **argv, char **envp,
|
textstartup void __asan_init(int argc, char **argv, char **envp,
|
||||||
|
|
|
@ -79,6 +79,8 @@ o/$(MODE)/libc/intrin/futex_wake.o \
|
||||||
o/$(MODE)/libc/intrin/gettid.greg.o \
|
o/$(MODE)/libc/intrin/gettid.greg.o \
|
||||||
o/$(MODE)/libc/intrin/sys_gettid.greg.o \
|
o/$(MODE)/libc/intrin/sys_gettid.greg.o \
|
||||||
o/$(MODE)/libc/intrin/pthread_mutex_lock.o \
|
o/$(MODE)/libc/intrin/pthread_mutex_lock.o \
|
||||||
|
o/$(MODE)/libc/intrin/pthread_mutex_wait.o \
|
||||||
|
o/$(MODE)/libc/intrin/pthread_mutex_wake.o \
|
||||||
o/$(MODE)/libc/intrin/pthread_mutex_unlock.o \
|
o/$(MODE)/libc/intrin/pthread_mutex_unlock.o \
|
||||||
o/$(MODE)/libc/intrin/pthread_mutex_trylock.o \
|
o/$(MODE)/libc/intrin/pthread_mutex_trylock.o \
|
||||||
o/$(MODE)/libc/intrin/_trylock_debug_4.o \
|
o/$(MODE)/libc/intrin/_trylock_debug_4.o \
|
||||||
|
@ -108,7 +110,6 @@ o/$(MODE)/libc/intrin/describeprotflags.o: \
|
||||||
OVERRIDE_CFLAGS += \
|
OVERRIDE_CFLAGS += \
|
||||||
-fno-sanitize=address
|
-fno-sanitize=address
|
||||||
|
|
||||||
o/$(MODE)/libc/intrin/exit.greg.o \
|
|
||||||
o/$(MODE)/libc/intrin/exit1.greg.o \
|
o/$(MODE)/libc/intrin/exit1.greg.o \
|
||||||
o/$(MODE)/libc/intrin/getenv.greg.o \
|
o/$(MODE)/libc/intrin/getenv.greg.o \
|
||||||
o/$(MODE)/libc/intrin/wsarecv.o \
|
o/$(MODE)/libc/intrin/wsarecv.o \
|
||||||
|
|
|
@ -36,6 +36,7 @@
|
||||||
#include "libc/limits.h"
|
#include "libc/limits.h"
|
||||||
#include "libc/log/internal.h"
|
#include "libc/log/internal.h"
|
||||||
#include "libc/macros.internal.h"
|
#include "libc/macros.internal.h"
|
||||||
|
#include "libc/nexgen32e/gettls.h"
|
||||||
#include "libc/nexgen32e/rdtsc.h"
|
#include "libc/nexgen32e/rdtsc.h"
|
||||||
#include "libc/nexgen32e/threaded.h"
|
#include "libc/nexgen32e/threaded.h"
|
||||||
#include "libc/nexgen32e/uart.internal.h"
|
#include "libc/nexgen32e/uart.internal.h"
|
||||||
|
@ -154,6 +155,7 @@ privileged bool kisdangerous(const void *p) {
|
||||||
|
|
||||||
privileged static void klog(const char *b, size_t n) {
|
privileged static void klog(const char *b, size_t n) {
|
||||||
int e;
|
int e;
|
||||||
|
bool cf;
|
||||||
size_t i;
|
size_t i;
|
||||||
uint16_t dx;
|
uint16_t dx;
|
||||||
uint32_t wrote;
|
uint32_t wrote;
|
||||||
|
@ -309,19 +311,15 @@ privileged static size_t kformat(char *b, size_t n, const char *fmt,
|
||||||
|
|
||||||
case 'P':
|
case 'P':
|
||||||
if (!__vforked) {
|
if (!__vforked) {
|
||||||
if (!__threaded) {
|
if (!__tls_enabled) {
|
||||||
x = __pid;
|
x = __pid;
|
||||||
} else {
|
} else {
|
||||||
// clone() is linked and it yoinks gettid()
|
x = *(int *)(__get_tls_inline() + 0x38);
|
||||||
x = weaken(gettid)();
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
asm volatile("syscall"
|
x = 666;
|
||||||
: "=a"(x)
|
|
||||||
: "0"(__NR_getpid)
|
|
||||||
: "rcx", "rdx", "r11", "memory", "cc");
|
|
||||||
}
|
}
|
||||||
goto FormatUnsigned;
|
goto FormatDecimal;
|
||||||
|
|
||||||
case 'u':
|
case 'u':
|
||||||
case 'd':
|
case 'd':
|
||||||
|
@ -397,7 +395,8 @@ privileged static size_t kformat(char *b, size_t n, const char *fmt,
|
||||||
i = 0;
|
i = 0;
|
||||||
m = (1 << base) - 1;
|
m = (1 << base) - 1;
|
||||||
if (hash && x) sign = hash;
|
if (hash && x) sign = hash;
|
||||||
do z[i++ & 127] = abet[x & m];
|
do
|
||||||
|
z[i++ & 127] = abet[x & m];
|
||||||
while ((x >>= base) || (pdot && i < prec));
|
while ((x >>= base) || (pdot && i < prec));
|
||||||
goto EmitNumber;
|
goto EmitNumber;
|
||||||
|
|
||||||
|
@ -806,7 +805,7 @@ privileged void kvprintf(const char *fmt, va_list v) {
|
||||||
* - `X` uppercase
|
* - `X` uppercase
|
||||||
* - `T` timestamp
|
* - `T` timestamp
|
||||||
* - `x` hexadecimal
|
* - `x` hexadecimal
|
||||||
* - `P` pid (or tid if threaded)
|
* - `P` PID (or TID if TLS is enabled)
|
||||||
*
|
*
|
||||||
* Types:
|
* Types:
|
||||||
*
|
*
|
||||||
|
|
|
@ -119,6 +119,17 @@ void *pthread_getspecific(pthread_key_t);
|
||||||
#define pthread_mutexattr_gettype(pAttr, pType) (*(pType) = (pAttr)->attr, 0)
|
#define pthread_mutexattr_gettype(pAttr, pType) (*(pType) = (pAttr)->attr, 0)
|
||||||
#define pthread_mutexattr_settype(pAttr, type) ((pAttr)->attr = type, 0)
|
#define pthread_mutexattr_settype(pAttr, type) ((pAttr)->attr = type, 0)
|
||||||
|
|
||||||
|
#ifdef __GNUC__
|
||||||
|
#define pthread_mutex_init(mutex, pAttr) \
|
||||||
|
({ \
|
||||||
|
pthread_mutexattr_t *_pAttr = (pAttr); \
|
||||||
|
*(mutex) = (pthread_mutex_t){ \
|
||||||
|
(_pAttr) ? (_pAttr)->attr : PTHREAD_MUTEX_DEFAULT, \
|
||||||
|
}; \
|
||||||
|
0; \
|
||||||
|
})
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef __GNUC__
|
#ifdef __GNUC__
|
||||||
#define pthread_mutex_lock(mutex) \
|
#define pthread_mutex_lock(mutex) \
|
||||||
(((mutex)->attr == PTHREAD_MUTEX_NORMAL && \
|
(((mutex)->attr == PTHREAD_MUTEX_NORMAL && \
|
||||||
|
|
|
@ -24,8 +24,8 @@
|
||||||
* @param attr may be NULL
|
* @param attr may be NULL
|
||||||
* @return 0 on success, or error number on failure
|
* @return 0 on success, or error number on failure
|
||||||
*/
|
*/
|
||||||
int pthread_mutex_init(pthread_mutex_t *mutex,
|
int(pthread_mutex_init)(pthread_mutex_t *mutex,
|
||||||
const pthread_mutexattr_t *attr) {
|
const pthread_mutexattr_t *attr) {
|
||||||
bzero(mutex, sizeof(*mutex));
|
bzero(mutex, sizeof(*mutex));
|
||||||
mutex->attr = attr ? attr->attr : PTHREAD_MUTEX_DEFAULT;
|
mutex->attr = attr ? attr->attr : PTHREAD_MUTEX_DEFAULT;
|
||||||
return 0;
|
return 0;
|
||||||
|
|
|
@ -16,7 +16,6 @@
|
||||||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||||
#include "libc/calls/strace.internal.h"
|
|
||||||
#include "libc/dce.h"
|
#include "libc/dce.h"
|
||||||
#include "libc/nt/console.h"
|
#include "libc/nt/console.h"
|
||||||
#include "libc/nt/process.h"
|
#include "libc/nt/process.h"
|
||||||
|
@ -34,10 +33,9 @@ const char kConsoleHandles[3] = {
|
||||||
/**
|
/**
|
||||||
* Puts cmd.exe gui back the way it was.
|
* Puts cmd.exe gui back the way it was.
|
||||||
*/
|
*/
|
||||||
void __restorewintty(void) {
|
noinstrument void __restorewintty(void) {
|
||||||
int i;
|
int i;
|
||||||
if (!IsWindows()) return;
|
if (!IsWindows()) return;
|
||||||
NTTRACE("__restorewintty()");
|
|
||||||
if (GetCurrentProcessId() == __winmainpid) {
|
if (GetCurrentProcessId() == __winmainpid) {
|
||||||
for (i = 0; i < 3; ++i) {
|
for (i = 0; i < 3; ++i) {
|
||||||
SetConsoleMode(GetStdHandle(kConsoleHandles[i]), __ntconsolemode[i]);
|
SetConsoleMode(GetStdHandle(kConsoleHandles[i]), __ntconsolemode[i]);
|
||||||
|
|
|
@ -28,8 +28,8 @@
|
||||||
* Blocks until memory location becomes zero.
|
* Blocks until memory location becomes zero.
|
||||||
*
|
*
|
||||||
* This is intended to be used on the child thread id, which is updated
|
* This is intended to be used on the child thread id, which is updated
|
||||||
* by the clone() system call when a thread terminates. The purpose of
|
* by the _spawn() system call when a thread terminates. The purpose of
|
||||||
* this operation is to know when it's safe to munmap() a thread stack.
|
* this operation is to know when it's safe to munmap() a threads stack
|
||||||
*/
|
*/
|
||||||
void _wait0(const int *ctid) {
|
void _wait0(const int *ctid) {
|
||||||
int x;
|
int x;
|
||||||
|
|
|
@ -24,6 +24,7 @@
|
||||||
#include "libc/calls/struct/utsname.h"
|
#include "libc/calls/struct/utsname.h"
|
||||||
#include "libc/calls/syscall-sysv.internal.h"
|
#include "libc/calls/syscall-sysv.internal.h"
|
||||||
#include "libc/errno.h"
|
#include "libc/errno.h"
|
||||||
|
#include "libc/fmt/itoa.h"
|
||||||
#include "libc/intrin/asan.internal.h"
|
#include "libc/intrin/asan.internal.h"
|
||||||
#include "libc/intrin/kprintf.h"
|
#include "libc/intrin/kprintf.h"
|
||||||
#include "libc/intrin/lockcmpxchg.h"
|
#include "libc/intrin/lockcmpxchg.h"
|
||||||
|
@ -31,13 +32,13 @@
|
||||||
#include "libc/log/backtrace.internal.h"
|
#include "libc/log/backtrace.internal.h"
|
||||||
#include "libc/log/gdb.h"
|
#include "libc/log/gdb.h"
|
||||||
#include "libc/log/internal.h"
|
#include "libc/log/internal.h"
|
||||||
#include "libc/log/libfatal.internal.h"
|
|
||||||
#include "libc/log/log.h"
|
#include "libc/log/log.h"
|
||||||
#include "libc/macros.internal.h"
|
#include "libc/macros.internal.h"
|
||||||
#include "libc/nexgen32e/stackframe.h"
|
#include "libc/nexgen32e/stackframe.h"
|
||||||
#include "libc/runtime/internal.h"
|
#include "libc/runtime/internal.h"
|
||||||
#include "libc/runtime/pc.internal.h"
|
#include "libc/runtime/pc.internal.h"
|
||||||
#include "libc/runtime/runtime.h"
|
#include "libc/runtime/runtime.h"
|
||||||
|
#include "libc/str/str.h"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @fileoverview Abnormal termination handling & GUI debugging.
|
* @fileoverview Abnormal termination handling & GUI debugging.
|
||||||
|
@ -76,7 +77,7 @@ relegated static void ShowFunctionCalls(ucontext_t *ctx) {
|
||||||
|
|
||||||
relegated static char *AddFlag(char *p, int b, const char *s) {
|
relegated static char *AddFlag(char *p, int b, const char *s) {
|
||||||
if (b) {
|
if (b) {
|
||||||
p = __stpcpy(p, s);
|
p = stpcpy(p, s);
|
||||||
} else {
|
} else {
|
||||||
*p = 0;
|
*p = 0;
|
||||||
}
|
}
|
||||||
|
@ -109,6 +110,12 @@ relegated static char *DescribeCpuFlags(char *p, int flags, int x87sw,
|
||||||
return p;
|
return p;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static char *HexCpy(char p[hasatleast 17], uint64_t x, uint8_t k) {
|
||||||
|
while (k > 0) *p++ = "0123456789abcdef"[(x >> (k -= 4)) & 15];
|
||||||
|
*p = '\0';
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
|
||||||
relegated static void ShowGeneralRegisters(ucontext_t *ctx) {
|
relegated static void ShowGeneralRegisters(ucontext_t *ctx) {
|
||||||
int64_t x;
|
int64_t x;
|
||||||
const char *s;
|
const char *s;
|
||||||
|
@ -120,8 +127,8 @@ relegated static void ShowGeneralRegisters(ucontext_t *ctx) {
|
||||||
for (i = 0, j = 0, k = 0; i < ARRAYLEN(kGregNames); ++i) {
|
for (i = 0, j = 0, k = 0; i < ARRAYLEN(kGregNames); ++i) {
|
||||||
if (j > 0) *p++ = ' ';
|
if (j > 0) *p++ = ' ';
|
||||||
if (!(s = kGregNames[(unsigned)kGregOrder[i]])[2]) *p++ = ' ';
|
if (!(s = kGregNames[(unsigned)kGregOrder[i]])[2]) *p++ = ' ';
|
||||||
p = __stpcpy(p, s), *p++ = ' ';
|
p = stpcpy(p, s), *p++ = ' ';
|
||||||
p = __fixcpy(p, ctx->uc_mcontext.gregs[(unsigned)kGregOrder[i]], 64);
|
p = HexCpy(p, ctx->uc_mcontext.gregs[(unsigned)kGregOrder[i]], 64);
|
||||||
if (++j == 3) {
|
if (++j == 3) {
|
||||||
j = 0;
|
j = 0;
|
||||||
if (ctx->uc_mcontext.fpregs) {
|
if (ctx->uc_mcontext.fpregs) {
|
||||||
|
@ -129,13 +136,13 @@ relegated static void ShowGeneralRegisters(ucontext_t *ctx) {
|
||||||
} else {
|
} else {
|
||||||
bzero(&st, sizeof(st));
|
bzero(&st, sizeof(st));
|
||||||
}
|
}
|
||||||
p = __stpcpy(p, " ST(");
|
p = stpcpy(p, " ST(");
|
||||||
p = __uintcpy(p, k++);
|
p = FormatUint64(p, k++);
|
||||||
p = __stpcpy(p, ") ");
|
p = stpcpy(p, ") ");
|
||||||
x = st * 1000;
|
x = st * 1000;
|
||||||
if (x < 0) x = -x, *p++ = '-';
|
if (x < 0) x = -x, *p++ = '-';
|
||||||
p = __uintcpy(p, x / 1000), *p++ = '.';
|
p = FormatUint64(p, x / 1000), *p++ = '.';
|
||||||
p = __uintcpy(p, x % 1000);
|
p = FormatUint64(p, x % 1000);
|
||||||
*p = 0;
|
*p = 0;
|
||||||
kprintf("%s\n", buf);
|
kprintf("%s\n", buf);
|
||||||
p = buf;
|
p = buf;
|
||||||
|
@ -163,9 +170,9 @@ relegated static void ShowSseRegisters(ucontext_t *ctx) {
|
||||||
*p++ = ' ';
|
*p++ = ' ';
|
||||||
}
|
}
|
||||||
*p++ = ' ';
|
*p++ = ' ';
|
||||||
p = __fixcpy(p, ctx->uc_mcontext.fpregs->xmm[i + 0].u64[1], 64);
|
p = HexCpy(p, ctx->uc_mcontext.fpregs->xmm[i + 0].u64[1], 64);
|
||||||
p = __fixcpy(p, ctx->uc_mcontext.fpregs->xmm[i + 0].u64[0], 64);
|
p = HexCpy(p, ctx->uc_mcontext.fpregs->xmm[i + 0].u64[0], 64);
|
||||||
p = __stpcpy(p, " XMM");
|
p = stpcpy(p, " XMM");
|
||||||
if (i + 8 >= 10) {
|
if (i + 8 >= 10) {
|
||||||
*p++ = (i + 8) / 10 + '0';
|
*p++ = (i + 8) / 10 + '0';
|
||||||
*p++ = (i + 8) % 10 + '0';
|
*p++ = (i + 8) % 10 + '0';
|
||||||
|
@ -174,8 +181,8 @@ relegated static void ShowSseRegisters(ucontext_t *ctx) {
|
||||||
*p++ = ' ';
|
*p++ = ' ';
|
||||||
}
|
}
|
||||||
*p++ = ' ';
|
*p++ = ' ';
|
||||||
p = __fixcpy(p, ctx->uc_mcontext.fpregs->xmm[i + 8].u64[1], 64);
|
p = HexCpy(p, ctx->uc_mcontext.fpregs->xmm[i + 8].u64[1], 64);
|
||||||
p = __fixcpy(p, ctx->uc_mcontext.fpregs->xmm[i + 8].u64[0], 64);
|
p = HexCpy(p, ctx->uc_mcontext.fpregs->xmm[i + 8].u64[0], 64);
|
||||||
*p = 0;
|
*p = 0;
|
||||||
kprintf("XMM%s\n", buf);
|
kprintf("XMM%s\n", buf);
|
||||||
}
|
}
|
||||||
|
@ -198,7 +205,7 @@ relegated void ShowCrashReport(int err, int sig, struct siginfo *si,
|
||||||
names.release[0] = 0;
|
names.release[0] = 0;
|
||||||
names.version[0] = 0;
|
names.version[0] = 0;
|
||||||
names.nodename[0] = 0;
|
names.nodename[0] = 0;
|
||||||
__stpcpy(host, "unknown");
|
stpcpy(host, "unknown");
|
||||||
gethostname(host, sizeof(host));
|
gethostname(host, sizeof(host));
|
||||||
uname(&names);
|
uname(&names);
|
||||||
p = buf;
|
p = buf;
|
||||||
|
@ -208,9 +215,8 @@ relegated void ShowCrashReport(int err, int sig, struct siginfo *si,
|
||||||
" %m\n"
|
" %m\n"
|
||||||
" %s %s %s %s\n",
|
" %s %s %s %s\n",
|
||||||
!__nocolor ? "\e[30;101m" : "", !__nocolor ? "\e[0m" : "", sig,
|
!__nocolor ? "\e[30;101m" : "", !__nocolor ? "\e[0m" : "", sig,
|
||||||
(ctx &&
|
(ctx && (ctx->uc_mcontext.rsp >= GetStaticStackAddr(0) &&
|
||||||
(ctx->uc_mcontext.rsp >= (intptr_t)GetStaticStackAddr(0) &&
|
ctx->uc_mcontext.rsp <= GetStaticStackAddr(0) + PAGESIZE))
|
||||||
ctx->uc_mcontext.rsp <= (intptr_t)GetStaticStackAddr(0) + PAGESIZE))
|
|
||||||
? "Stack Overflow"
|
? "Stack Overflow"
|
||||||
: GetSiCodeName(sig, si->si_code),
|
: GetSiCodeName(sig, si->si_code),
|
||||||
host, getpid(), gettid(), program_invocation_name, names.sysname,
|
host, getpid(), gettid(), program_invocation_name, names.sysname,
|
||||||
|
|
31
libc/nexgen32e/ktensindex.S
Normal file
31
libc/nexgen32e/ktensindex.S
Normal file
|
@ -0,0 +1,31 @@
|
||||||
|
/*-*- mode:unix-assembly; indent-tabs-mode:t; tab-width:8; coding:utf-8 -*-│
|
||||||
|
│vi: set et ft=asm ts=8 tw=8 fenc=utf-8 :vi│
|
||||||
|
╞══════════════════════════════════════════════════════════════════════════════╡
|
||||||
|
│ Copyright 2022 Justine Alexandra Roberts Tunney │
|
||||||
|
│ │
|
||||||
|
│ Permission to use, copy, modify, and/or distribute this software for │
|
||||||
|
│ any purpose with or without fee is hereby granted, provided that the │
|
||||||
|
│ above copyright notice and this permission notice appear in all copies. │
|
||||||
|
│ │
|
||||||
|
│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │
|
||||||
|
│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │
|
||||||
|
│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │
|
||||||
|
│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │
|
||||||
|
│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │
|
||||||
|
│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │
|
||||||
|
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||||
|
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||||
|
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||||
|
#include "libc/macros.internal.h"
|
||||||
|
|
||||||
|
.rodata
|
||||||
|
kTensIndex:
|
||||||
|
.byte 0, 0, 0, 1, 1, 1, 2, 2
|
||||||
|
.byte 2, 3, 3, 3, 3, 4, 4, 4
|
||||||
|
.byte 5, 5, 5, 6, 6, 6, 6, 7
|
||||||
|
.byte 7, 7, 8, 8, 8, 9, 9, 9
|
||||||
|
.byte 10, 10, 10, 11, 11, 11, 12, 12
|
||||||
|
.byte 12, 12, 13, 13, 13, 14, 14, 14
|
||||||
|
.byte 15, 15, 15, 15, 16, 16, 16, 17
|
||||||
|
.byte 17, 17, 18, 18, 18, 18, 19, 19
|
||||||
|
.endfn kTensIndex,globl
|
|
@ -5,6 +5,7 @@ COSMOPOLITAN_C_START_
|
||||||
|
|
||||||
extern long kHalfCache3;
|
extern long kHalfCache3;
|
||||||
extern const uint64_t kTens[20];
|
extern const uint64_t kTens[20];
|
||||||
|
extern const unsigned char kTensIndex[64];
|
||||||
|
|
||||||
void imapxlatab(void *);
|
void imapxlatab(void *);
|
||||||
void insertionsort(int32_t *, size_t);
|
void insertionsort(int32_t *, size_t);
|
||||||
|
|
|
@ -43,8 +43,6 @@
|
||||||
#include "libc/thread/openbsd.internal.h"
|
#include "libc/thread/openbsd.internal.h"
|
||||||
#include "libc/thread/xnu.internal.h"
|
#include "libc/thread/xnu.internal.h"
|
||||||
|
|
||||||
STATIC_YOINK("gettid"); // for kprintf()
|
|
||||||
|
|
||||||
#define __NR_thr_new 455
|
#define __NR_thr_new 455
|
||||||
#define __NR_clone_linux 56
|
#define __NR_clone_linux 56
|
||||||
#define __NR__lwp_create 309
|
#define __NR__lwp_create 309
|
||||||
|
@ -84,6 +82,7 @@ int WinThreadLaunch(void *arg, // rdi
|
||||||
// we can't log this function because:
|
// we can't log this function because:
|
||||||
// 1. windows owns the backtrace pointer right now
|
// 1. windows owns the backtrace pointer right now
|
||||||
// 2. ftrace unwinds rbp to determine depth
|
// 2. ftrace unwinds rbp to determine depth
|
||||||
|
// 3. tid in tls for ftrace isn't set yet
|
||||||
// we can't use address sanitizer because:
|
// we can't use address sanitizer because:
|
||||||
// 1. __asan_handle_no_return wipes stack
|
// 1. __asan_handle_no_return wipes stack
|
||||||
// 2. windows owns the stack memory right now
|
// 2. windows owns the stack memory right now
|
||||||
|
@ -293,7 +292,9 @@ __attribute__((__constructor__)) static void OpenbsdGetSafeRsp(void) {
|
||||||
oldrsp = __builtin_frame_address(0);
|
oldrsp = __builtin_frame_address(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
static wontreturn void OpenbsdThreadMain(void *p) {
|
// we can't use address sanitizer because:
|
||||||
|
// 1. __asan_handle_no_return wipes stack [todo?]
|
||||||
|
noasan static wontreturn void OpenbsdThreadMain(void *p) {
|
||||||
struct CloneArgs *wt = p;
|
struct CloneArgs *wt = p;
|
||||||
*wt->ptid = wt->tid;
|
*wt->ptid = wt->tid;
|
||||||
*wt->ctid = wt->tid;
|
*wt->ctid = wt->tid;
|
||||||
|
@ -643,7 +644,7 @@ int clone(void *func, void *stk, size_t stksz, int flags, void *arg, int *ptid,
|
||||||
*ptid = rc;
|
*ptid = rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
STRACE("clone(%p, %p, %'zu, %#x, %p, %p, %p, %'zu, %p) → %d% m", func, stk,
|
STRACE("clone(%t, %p, %'zu, %#x, %p, %p, %p, %'zu, %p) → %d% m", func, stk,
|
||||||
stksz, flags, arg, ptid, tls, tlssz, ctid, rc);
|
stksz, flags, arg, ptid, tls, tlssz, ctid, rc);
|
||||||
|
|
||||||
return rc;
|
return rc;
|
||||||
|
|
|
@ -24,11 +24,12 @@
|
||||||
|
|
||||||
extern int __threadcalls_end[];
|
extern int __threadcalls_end[];
|
||||||
extern int __threadcalls_start[];
|
extern int __threadcalls_start[];
|
||||||
|
#pragma weak __threadcalls_start
|
||||||
|
#pragma weak __threadcalls_end
|
||||||
|
|
||||||
privileged void __enable_threads(void) {
|
privileged void __enable_threads(void) {
|
||||||
if (__threaded) return;
|
if (__threaded) return;
|
||||||
STRACE("__enable_threads()");
|
STRACE("__enable_threads()");
|
||||||
__threaded = gettid();
|
|
||||||
__morph_begin();
|
__morph_begin();
|
||||||
/*
|
/*
|
||||||
* _NOPL("__threadcalls", func)
|
* _NOPL("__threadcalls", func)
|
||||||
|
@ -54,4 +55,5 @@ privileged void __enable_threads(void) {
|
||||||
_base[*p + 2] = 0xe8;
|
_base[*p + 2] = 0xe8;
|
||||||
}
|
}
|
||||||
__morph_end();
|
__morph_end();
|
||||||
|
__threaded = gettid();
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,6 +21,8 @@
|
||||||
#include "libc/intrin/cmpxchg.h"
|
#include "libc/intrin/cmpxchg.h"
|
||||||
#include "libc/intrin/kprintf.h"
|
#include "libc/intrin/kprintf.h"
|
||||||
#include "libc/intrin/lockcmpxchg.h"
|
#include "libc/intrin/lockcmpxchg.h"
|
||||||
|
#include "libc/intrin/nopl.h"
|
||||||
|
#include "libc/intrin/pthread.h"
|
||||||
#include "libc/macros.internal.h"
|
#include "libc/macros.internal.h"
|
||||||
#include "libc/nexgen32e/stackframe.h"
|
#include "libc/nexgen32e/stackframe.h"
|
||||||
#include "libc/nexgen32e/threaded.h"
|
#include "libc/nexgen32e/threaded.h"
|
||||||
|
@ -43,9 +45,22 @@ static struct Ftrace {
|
||||||
int skew;
|
int skew;
|
||||||
int stackdigs;
|
int stackdigs;
|
||||||
int64_t lastaddr;
|
int64_t lastaddr;
|
||||||
volatile bool busy;
|
pthread_mutex_t lock;
|
||||||
|
volatile bool noreentry;
|
||||||
} g_ftrace;
|
} g_ftrace;
|
||||||
|
|
||||||
|
static void __ftrace_lock(void) {
|
||||||
|
if (__threaded) {
|
||||||
|
pthread_mutex_lock(&g_ftrace.lock);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void __ftrace_unlock(void) {
|
||||||
|
if (__threaded) {
|
||||||
|
pthread_mutex_unlock(&g_ftrace.lock);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static privileged inline int GetNestingLevelImpl(struct StackFrame *frame) {
|
static privileged inline int GetNestingLevelImpl(struct StackFrame *frame) {
|
||||||
int nesting = -2;
|
int nesting = -2;
|
||||||
while (frame) {
|
while (frame) {
|
||||||
|
@ -63,18 +78,6 @@ static privileged inline int GetNestingLevel(struct StackFrame *frame) {
|
||||||
return MIN(MAX_NESTING, nesting);
|
return MIN(MAX_NESTING, nesting);
|
||||||
}
|
}
|
||||||
|
|
||||||
static privileged inline void ReleaseFtraceLock(void) {
|
|
||||||
g_ftrace.busy = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
static privileged inline bool AcquireFtraceLock(void) {
|
|
||||||
if (!__threaded) {
|
|
||||||
return _cmpxchg(&g_ftrace.busy, false, true);
|
|
||||||
} else {
|
|
||||||
return _lockcmpxchg(&g_ftrace.busy, false, true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Prints name of function being called.
|
* Prints name of function being called.
|
||||||
*
|
*
|
||||||
|
@ -85,20 +88,26 @@ static privileged inline bool AcquireFtraceLock(void) {
|
||||||
privileged void ftracer(void) {
|
privileged void ftracer(void) {
|
||||||
long stackuse;
|
long stackuse;
|
||||||
struct StackFrame *frame;
|
struct StackFrame *frame;
|
||||||
if (AcquireFtraceLock()) {
|
__ftrace_lock();
|
||||||
|
if (_cmpxchg(&g_ftrace.noreentry, false, true)) {
|
||||||
frame = __builtin_frame_address(0);
|
frame = __builtin_frame_address(0);
|
||||||
frame = frame->next;
|
frame = frame->next;
|
||||||
if (frame->addr != g_ftrace.lastaddr) {
|
if (frame->addr != g_ftrace.lastaddr) {
|
||||||
stackuse = (intptr_t)GetStackAddr(0) + GetStackSize() - (intptr_t)frame;
|
stackuse = GetStackAddr() + GetStackSize() - (intptr_t)frame;
|
||||||
kprintf("%rFUN %6P %'13T %'*ld %*s%t\n", g_ftrace.stackdigs, stackuse,
|
kprintf("%rFUN %6P %'13T %'*ld %*s%t\n", g_ftrace.stackdigs, stackuse,
|
||||||
GetNestingLevel(frame) * 2, "", frame->addr);
|
GetNestingLevel(frame) * 2, "", frame->addr);
|
||||||
g_ftrace.lastaddr = frame->addr;
|
g_ftrace.lastaddr = frame->addr;
|
||||||
}
|
}
|
||||||
ReleaseFtraceLock();
|
g_ftrace.noreentry = false;
|
||||||
}
|
}
|
||||||
|
__ftrace_unlock();
|
||||||
}
|
}
|
||||||
|
|
||||||
textstartup int ftrace_install(void) {
|
textstartup int ftrace_install(void) {
|
||||||
|
pthread_mutexattr_t attr;
|
||||||
|
pthread_mutexattr_init(&attr);
|
||||||
|
pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
|
||||||
|
pthread_mutex_init(&g_ftrace.lock, &attr);
|
||||||
if (GetSymbolTable()) {
|
if (GetSymbolTable()) {
|
||||||
g_ftrace.lastaddr = -1;
|
g_ftrace.lastaddr = -1;
|
||||||
g_ftrace.stackdigs = LengthInt64Thousands(GetStackSize());
|
g_ftrace.stackdigs = LengthInt64Thousands(GetStackSize());
|
||||||
|
|
|
@ -16,19 +16,48 @@
|
||||||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||||
|
#include "libc/calls/calls.h"
|
||||||
|
#include "libc/dce.h"
|
||||||
|
#include "libc/intrin/asan.internal.h"
|
||||||
|
#include "libc/intrin/asancodes.h"
|
||||||
|
#include "libc/runtime/memtrack.internal.h"
|
||||||
#include "libc/runtime/runtime.h"
|
#include "libc/runtime/runtime.h"
|
||||||
#include "libc/runtime/stack.h"
|
#include "libc/runtime/stack.h"
|
||||||
#include "libc/sysv/consts/map.h"
|
#include "libc/sysv/consts/map.h"
|
||||||
#include "libc/sysv/consts/prot.h"
|
#include "libc/sysv/consts/prot.h"
|
||||||
|
|
||||||
|
static char *_stkbase;
|
||||||
|
|
||||||
|
__attribute__((__constructor__)) static void init(void) {
|
||||||
|
_stkbase = (char *)kFixedmapStart;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Allocates stack.
|
* Allocates stack.
|
||||||
*
|
*
|
||||||
|
* The size of your returned stack is always GetStackSize().
|
||||||
|
*
|
||||||
|
* The bottom 4096 bytes of your stack can't be used, since it's always
|
||||||
|
* reserved for a read-only guard page. With ASAN it'll be poisoned too.
|
||||||
|
*
|
||||||
|
* The top 16 bytes of a stack can't be used due to openbsd:stackbound
|
||||||
|
* and those bytes are also poisoned under ASAN build modes.
|
||||||
|
*
|
||||||
* @return stack bottom address on success, or null w/ errrno
|
* @return stack bottom address on success, or null w/ errrno
|
||||||
*/
|
*/
|
||||||
void *_mapstack(void) {
|
void *_mapstack(void) {
|
||||||
return mmap(0, GetStackSize(), PROT_READ | PROT_WRITE,
|
char *p;
|
||||||
MAP_STACK | MAP_ANONYMOUS, -1, 0);
|
if ((p = mmap(_stkbase, GetStackSize(), PROT_READ | PROT_WRITE,
|
||||||
|
MAP_STACK | MAP_ANONYMOUS | MAP_FIXED, -1, 0)) != MAP_FAILED) {
|
||||||
|
if (IsAsan()) {
|
||||||
|
__asan_poison(p + GetStackSize() - 16, 16, kAsanStackOverflow);
|
||||||
|
__asan_poison(p, 4096, kAsanStackOverflow);
|
||||||
|
}
|
||||||
|
_stkbase += GetStackSize() * 4;
|
||||||
|
return p;
|
||||||
|
} else {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -106,25 +106,25 @@ forceinline pureconst bool IsShadowFrame(int x) {
|
||||||
}
|
}
|
||||||
|
|
||||||
forceinline pureconst bool IsKernelFrame(int x) {
|
forceinline pureconst bool IsKernelFrame(int x) {
|
||||||
intptr_t stack = (intptr_t)GetStaticStackAddr(0);
|
intptr_t stack = GetStaticStackAddr(0);
|
||||||
return (int)(stack >> 16) <= x &&
|
return (int)(stack >> 16) <= x &&
|
||||||
x <= (int)((stack + (GetStackSize() - FRAMESIZE)) >> 16);
|
x <= (int)((stack + (GetStackSize() - FRAMESIZE)) >> 16);
|
||||||
}
|
}
|
||||||
|
|
||||||
forceinline pureconst bool IsStaticStackFrame(int x) {
|
forceinline pureconst bool IsStaticStackFrame(int x) {
|
||||||
intptr_t stack = (intptr_t)GetStaticStackAddr(0);
|
intptr_t stack = GetStaticStackAddr(0);
|
||||||
return (int)(stack >> 16) <= x &&
|
return (int)(stack >> 16) <= x &&
|
||||||
x <= (int)((stack + (GetStackSize() - FRAMESIZE)) >> 16);
|
x <= (int)((stack + (GetStackSize() - FRAMESIZE)) >> 16);
|
||||||
}
|
}
|
||||||
|
|
||||||
forceinline pureconst bool IsStackFrame(int x) {
|
forceinline pureconst bool IsStackFrame(int x) {
|
||||||
intptr_t stack = (intptr_t)GetStackAddr(0);
|
intptr_t stack = GetStackAddr();
|
||||||
return (int)(stack >> 16) <= x &&
|
return (int)(stack >> 16) <= x &&
|
||||||
x <= (int)((stack + (GetStackSize() - FRAMESIZE)) >> 16);
|
x <= (int)((stack + (GetStackSize() - FRAMESIZE)) >> 16);
|
||||||
}
|
}
|
||||||
|
|
||||||
forceinline pureconst bool IsSigAltStackFrame(int x) {
|
forceinline pureconst bool IsSigAltStackFrame(int x) {
|
||||||
intptr_t stack = (intptr_t)GetStackAddr(0);
|
intptr_t stack = GetStackAddr();
|
||||||
return (int)(stack >> 16) <= x &&
|
return (int)(stack >> 16) <= x &&
|
||||||
x <= (int)((stack + (SIGSTKSZ - FRAMESIZE)) >> 16);
|
x <= (int)((stack + (SIGSTKSZ - FRAMESIZE)) >> 16);
|
||||||
}
|
}
|
||||||
|
|
|
@ -223,9 +223,8 @@ textstartup void __printargs(const char *prologue) {
|
||||||
PRINT(" L%d%s%s %u-way %,u byte cache w/%s "
|
PRINT(" L%d%s%s %u-way %,u byte cache w/%s "
|
||||||
"%,u sets of %,u byte lines shared across %u threads%s",
|
"%,u sets of %,u byte lines shared across %u threads%s",
|
||||||
CPUID4_CACHE_LEVEL,
|
CPUID4_CACHE_LEVEL,
|
||||||
CPUID4_CACHE_TYPE == 1 ? " data"
|
CPUID4_CACHE_TYPE == 1 ? " data"
|
||||||
: CPUID4_CACHE_TYPE == 2 ? " code"
|
: CPUID4_CACHE_TYPE == 2 ? " code" : "",
|
||||||
: "",
|
|
||||||
CPUID4_IS_FULLY_ASSOCIATIVE ? " fully-associative" : "",
|
CPUID4_IS_FULLY_ASSOCIATIVE ? " fully-associative" : "",
|
||||||
CPUID4_WAYS_OF_ASSOCIATIVITY, CPUID4_CACHE_SIZE_IN_BYTES,
|
CPUID4_WAYS_OF_ASSOCIATIVITY, CPUID4_CACHE_SIZE_IN_BYTES,
|
||||||
CPUID4_PHYSICAL_LINE_PARTITIONS > 1 ? " physically partitioned" : "",
|
CPUID4_PHYSICAL_LINE_PARTITIONS > 1 ? " physically partitioned" : "",
|
||||||
|
@ -358,7 +357,7 @@ textstartup void __printargs(const char *prologue) {
|
||||||
PRINT(" ☼ %s = %#s", "GetInterpreterExecutableName",
|
PRINT(" ☼ %s = %#s", "GetInterpreterExecutableName",
|
||||||
GetInterpreterExecutableName(u.path, sizeof(u.path)));
|
GetInterpreterExecutableName(u.path, sizeof(u.path)));
|
||||||
PRINT(" ☼ %s = %p", "RSP", __builtin_frame_address(0));
|
PRINT(" ☼ %s = %p", "RSP", __builtin_frame_address(0));
|
||||||
PRINT(" ☼ %s = %p", "GetStackAddr()", GetStackAddr(0));
|
PRINT(" ☼ %s = %p", "GetStackAddr()", GetStackAddr());
|
||||||
PRINT(" ☼ %s = %p", "GetStaticStackAddr(0)", GetStaticStackAddr(0));
|
PRINT(" ☼ %s = %p", "GetStaticStackAddr(0)", GetStaticStackAddr(0));
|
||||||
PRINT(" ☼ %s = %p", "GetStackSize()", GetStackSize());
|
PRINT(" ☼ %s = %p", "GetStackSize()", GetStackSize());
|
||||||
|
|
||||||
|
|
|
@ -78,9 +78,8 @@ extern char ape_stack_align[] __attribute__((__weak__));
|
||||||
* and (2) the mmap() address picker will choose aligned addresses when
|
* and (2) the mmap() address picker will choose aligned addresses when
|
||||||
* the provided size is a two power.
|
* the provided size is a two power.
|
||||||
*/
|
*/
|
||||||
#define GetStackAddr(ADDEND) \
|
#define GetStackAddr() \
|
||||||
((void *)((((intptr_t)__builtin_frame_address(0) - 1) & -GetStackSize()) + \
|
(((intptr_t)__builtin_frame_address(0) - 1) & -GetStackSize())
|
||||||
(ADDEND)))
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns preferred bottom address of stack.
|
* Returns preferred bottom address of stack.
|
||||||
|
@ -102,7 +101,7 @@ extern char ape_stack_align[] __attribute__((__weak__));
|
||||||
} else { \
|
} else { \
|
||||||
vAddr = 0x100000000 - GetStackSize(); \
|
vAddr = 0x100000000 - GetStackSize(); \
|
||||||
} \
|
} \
|
||||||
(void *)vAddr; \
|
vAddr; \
|
||||||
})
|
})
|
||||||
|
|
||||||
COSMOPOLITAN_C_END_
|
COSMOPOLITAN_C_END_
|
||||||
|
|
|
@ -52,7 +52,7 @@ static textexit void LogStackUse(void) {
|
||||||
bool quote;
|
bool quote;
|
||||||
char *p, *q;
|
char *p, *q;
|
||||||
size_t n, usage;
|
size_t n, usage;
|
||||||
usage = GetStackUsage(GetStackAddr(0), GetStackSize());
|
usage = GetStackUsage((char *)GetStackAddr(), GetStackSize());
|
||||||
fd = open(stacklog, O_APPEND | O_CREAT | O_WRONLY, 0644);
|
fd = open(stacklog, O_APPEND | O_CREAT | O_WRONLY, 0644);
|
||||||
p = FormatUint64(stacklog, usage);
|
p = FormatUint64(stacklog, usage);
|
||||||
for (i = 0; i < __argc; ++i) {
|
for (i = 0; i < __argc; ++i) {
|
||||||
|
|
|
@ -194,7 +194,7 @@ __msabi static textwindows wontreturn void WinMainNew(const char16_t *cmdline) {
|
||||||
_mmi.p = _mmi.s;
|
_mmi.p = _mmi.s;
|
||||||
_mmi.n = ARRAYLEN(_mmi.s);
|
_mmi.n = ARRAYLEN(_mmi.s);
|
||||||
argsize = ROUNDUP(sizeof(struct WinArgs), FRAMESIZE);
|
argsize = ROUNDUP(sizeof(struct WinArgs), FRAMESIZE);
|
||||||
stackaddr = (intptr_t)GetStaticStackAddr(0);
|
stackaddr = GetStaticStackAddr(0);
|
||||||
stacksize = GetStackSize();
|
stacksize = GetStackSize();
|
||||||
allocsize = argsize + stacksize;
|
allocsize = argsize + stacksize;
|
||||||
allocaddr = stackaddr - argsize;
|
allocaddr = stackaddr - argsize;
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
|
/*-*- 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│
|
│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│
|
||||||
╞══════════════════════════════════════════════════════════════════════════════╡
|
╞══════════════════════════════════════════════════════════════════════════════╡
|
||||||
│ Copyright (C) 2022 Justine Alexandra Roberts Tunney │
|
|
||||||
│ Copyright (C) 1997, 1999, 2001 Lucent Technologies │
|
│ Copyright (C) 1997, 1999, 2001 Lucent Technologies │
|
||||||
│ All Rights Reserved │
|
│ All Rights Reserved │
|
||||||
│ │
|
│ │
|
||||||
|
@ -294,10 +293,12 @@ int __fmt_dtoa(int (*out)(const char *, void *, size_t), void *arg, int d,
|
||||||
if ((flags & FLAGS_ZEROPAD)) {
|
if ((flags & FLAGS_ZEROPAD)) {
|
||||||
if (sign) __FMT_PUT(sign);
|
if (sign) __FMT_PUT(sign);
|
||||||
sign = 0;
|
sign = 0;
|
||||||
do __FMT_PUT('0');
|
do
|
||||||
|
__FMT_PUT('0');
|
||||||
while (--width > 0);
|
while (--width > 0);
|
||||||
} else
|
} else
|
||||||
do __FMT_PUT(' ');
|
do
|
||||||
|
__FMT_PUT(' ');
|
||||||
while (--width > 0);
|
while (--width > 0);
|
||||||
}
|
}
|
||||||
if (sign) __FMT_PUT(sign);
|
if (sign) __FMT_PUT(sign);
|
||||||
|
@ -409,10 +410,12 @@ int __fmt_dtoa(int (*out)(const char *, void *, size_t), void *arg, int d,
|
||||||
if ((flags & FLAGS_ZEROPAD)) {
|
if ((flags & FLAGS_ZEROPAD)) {
|
||||||
if (sign) __FMT_PUT(sign);
|
if (sign) __FMT_PUT(sign);
|
||||||
sign = 0;
|
sign = 0;
|
||||||
do __FMT_PUT('0');
|
do
|
||||||
|
__FMT_PUT('0');
|
||||||
while (--width > 0);
|
while (--width > 0);
|
||||||
} else
|
} else
|
||||||
do __FMT_PUT(' ');
|
do
|
||||||
|
__FMT_PUT(' ');
|
||||||
while (--width > 0);
|
while (--width > 0);
|
||||||
}
|
}
|
||||||
if (sign) __FMT_PUT(sign);
|
if (sign) __FMT_PUT(sign);
|
||||||
|
@ -482,14 +485,16 @@ int __fmt_dtoa(int (*out)(const char *, void *, size_t), void *arg, int d,
|
||||||
}
|
}
|
||||||
if ((width -= prec1) > 0 && !(flags & FLAGS_LEFT) &&
|
if ((width -= prec1) > 0 && !(flags & FLAGS_LEFT) &&
|
||||||
!(flags & FLAGS_ZEROPAD)) {
|
!(flags & FLAGS_ZEROPAD)) {
|
||||||
do __FMT_PUT(' ');
|
do
|
||||||
|
__FMT_PUT(' ');
|
||||||
while (--width > 0);
|
while (--width > 0);
|
||||||
}
|
}
|
||||||
if (sign) __FMT_PUT(sign);
|
if (sign) __FMT_PUT(sign);
|
||||||
__FMT_PUT('0');
|
__FMT_PUT('0');
|
||||||
__FMT_PUT(alphabet[17]);
|
__FMT_PUT(alphabet[17]);
|
||||||
if ((flags & FLAGS_ZEROPAD) && width > 0 && !(flags & FLAGS_LEFT)) {
|
if ((flags & FLAGS_ZEROPAD) && width > 0 && !(flags & FLAGS_LEFT)) {
|
||||||
do __FMT_PUT('0');
|
do
|
||||||
|
__FMT_PUT('0');
|
||||||
while (--width > 0);
|
while (--width > 0);
|
||||||
}
|
}
|
||||||
i1 = prec1 & 7;
|
i1 = prec1 & 7;
|
||||||
|
@ -507,7 +512,8 @@ int __fmt_dtoa(int (*out)(const char *, void *, size_t), void *arg, int d,
|
||||||
--prec1;
|
--prec1;
|
||||||
}
|
}
|
||||||
if ((flags & FLAGS_HASH) && prec > 0) {
|
if ((flags & FLAGS_HASH) && prec > 0) {
|
||||||
do __FMT_PUT(0);
|
do
|
||||||
|
__FMT_PUT(0);
|
||||||
while (--prec > 0);
|
while (--prec > 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,7 +26,7 @@
|
||||||
*
|
*
|
||||||
* @see __get_tls_inline()
|
* @see __get_tls_inline()
|
||||||
* @see __install_tls()
|
* @see __install_tls()
|
||||||
* @see clone()
|
* @see _spawn()
|
||||||
*/
|
*/
|
||||||
optimizespeed char *__get_tls(void) {
|
optimizespeed char *__get_tls(void) {
|
||||||
return __get_tls_inline();
|
return __get_tls_inline();
|
||||||
|
|
|
@ -91,7 +91,7 @@ int _spawn(int fun(void *, int), void *arg, struct spawn *opt_out_thread) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (clone(fun, th->stk, GetStackSize(),
|
if (clone(fun, th->stk, GetStackSize() - 16 /* openbsd:stackbound */,
|
||||||
CLONE_VM | CLONE_THREAD | CLONE_FS | CLONE_FILES | CLONE_SIGHAND |
|
CLONE_VM | CLONE_THREAD | CLONE_FS | CLONE_FILES | CLONE_SIGHAND |
|
||||||
CLONE_SETTLS | CLONE_PARENT_SETTID | CLONE_CHILD_SETTID |
|
CLONE_SETTLS | CLONE_PARENT_SETTID | CLONE_CHILD_SETTID |
|
||||||
CLONE_CHILD_CLEARTID,
|
CLONE_CHILD_CLEARTID,
|
||||||
|
@ -117,6 +117,7 @@ int _join(struct spawn *th) {
|
||||||
// free thread memory
|
// free thread memory
|
||||||
free(th->tls);
|
free(th->tls);
|
||||||
rc = munmap(th->stk, GetStackSize());
|
rc = munmap(th->stk, GetStackSize());
|
||||||
|
rc = 0;
|
||||||
} else {
|
} else {
|
||||||
rc = 0;
|
rc = 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -161,23 +161,10 @@ TEST(clone, tlsSystemCallsErrno_wontClobberMainThreadBecauseTls) {
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
// BENCHMARK
|
// BENCHMARK
|
||||||
|
|
||||||
void LaunchThread(void) {
|
|
||||||
char *tls, *stack;
|
|
||||||
tls = __initialize_tls(malloc(64));
|
|
||||||
__cxa_atexit(free, tls, 0);
|
|
||||||
stack = mmap(0, GetStackSize(), PROT_READ | PROT_WRITE,
|
|
||||||
MAP_STACK | MAP_ANONYMOUS, -1, 0);
|
|
||||||
clone(DoNothing, stack, GetStackSize(),
|
|
||||||
CLONE_THREAD | CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_SIGHAND |
|
|
||||||
CLONE_CHILD_SETTID | CLONE_CHILD_CLEARTID | CLONE_SETTLS,
|
|
||||||
0, 0, tls, 64, (int *)(tls + 0x38));
|
|
||||||
}
|
|
||||||
|
|
||||||
BENCH(clone, bench) {
|
BENCH(clone, bench) {
|
||||||
char *volatile tp;
|
char *volatile tp;
|
||||||
errno_t *volatile ep;
|
errno_t *volatile ep;
|
||||||
EZBENCH2("__errno_location", donothing, (ep = __errno_location()));
|
EZBENCH2("__errno_location", donothing, (ep = __errno_location()));
|
||||||
EZBENCH2("__get_tls_inline", donothing, (tp = __get_tls_inline()));
|
EZBENCH2("__get_tls_inline", donothing, (tp = __get_tls_inline()));
|
||||||
EZBENCH2("__get_tls", donothing, (tp = __get_tls()));
|
EZBENCH2("__get_tls", donothing, (tp = __get_tls()));
|
||||||
EZBENCH2("clone()", donothing, LaunchThread());
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -31,8 +31,6 @@
|
||||||
#include "libc/thread/spawn.h"
|
#include "libc/thread/spawn.h"
|
||||||
#include "libc/x/x.h"
|
#include "libc/x/x.h"
|
||||||
|
|
||||||
#define THREADS 32
|
|
||||||
|
|
||||||
#define DUB(i) (union Dub){i}.x
|
#define DUB(i) (union Dub){i}.x
|
||||||
|
|
||||||
#define DUBBLE(a, b, c, d, e) \
|
#define DUBBLE(a, b, c, d, e) \
|
||||||
|
@ -47,8 +45,6 @@ union Dub {
|
||||||
double x;
|
double x;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct spawn th[THREADS];
|
|
||||||
|
|
||||||
int Worker(void *p, int tid) {
|
int Worker(void *p, int tid) {
|
||||||
int i;
|
int i;
|
||||||
char str[64];
|
char str[64];
|
||||||
|
@ -60,14 +56,12 @@ int Worker(void *p, int tid) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(dtoa, test) {
|
TEST(dtoa, locks) {
|
||||||
int i;
|
int i, n = 32;
|
||||||
for (i = 0; i < THREADS; ++i) {
|
struct spawn th[n];
|
||||||
_spawn(Worker, 0, th + i);
|
if (IsOpenbsd()) return; // TODO(jart): OpenBSD flakes :'(
|
||||||
}
|
for (i = 0; i < n; ++i) ASSERT_SYS(0, 0, _spawn(Worker, 0, th + i));
|
||||||
for (i = 0; i < THREADS; ++i) {
|
for (i = 0; i < n; ++i) EXPECT_SYS(0, 0, _join(th + i));
|
||||||
_join(th + i);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static const struct {
|
static const struct {
|
||||||
|
|
|
@ -26,9 +26,6 @@
|
||||||
#include "libc/thread/spawn.h"
|
#include "libc/thread/spawn.h"
|
||||||
#include "libc/thread/thread.h"
|
#include "libc/thread/thread.h"
|
||||||
|
|
||||||
#define N 128
|
|
||||||
|
|
||||||
struct spawn t[N];
|
|
||||||
_Atomic(int) itworked;
|
_Atomic(int) itworked;
|
||||||
_Thread_local int var;
|
_Thread_local int var;
|
||||||
|
|
||||||
|
@ -44,11 +41,12 @@ int Worker(void *arg, int tid) {
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(_spawn, test) {
|
TEST(_spawn, test) {
|
||||||
long i;
|
long i, n = 128;
|
||||||
for (i = 0; i < N; ++i) EXPECT_SYS(0, 0, _spawn(Worker, (void *)i, t + i));
|
struct spawn t[n];
|
||||||
for (i = 0; i < N; ++i) EXPECT_SYS(0, 0, _join(t + i));
|
for (i = 0; i < n; ++i) ASSERT_SYS(0, 0, _spawn(Worker, (void *)i, t + i));
|
||||||
for (i = 0; i < N; ++i) EXPECT_SYS(0, 0, _join(t + i));
|
for (i = 0; i < n; ++i) EXPECT_SYS(0, 0, _join(t + i));
|
||||||
EXPECT_EQ(N, itworked);
|
for (i = 0; i < n; ++i) EXPECT_SYS(0, 0, _join(t + i));
|
||||||
|
EXPECT_EQ(n, itworked);
|
||||||
}
|
}
|
||||||
|
|
||||||
__attribute__((__constructor__)) static void init(void) {
|
__attribute__((__constructor__)) static void init(void) {
|
||||||
|
|
4
third_party/python/Include/ceval.h
vendored
4
third_party/python/Include/ceval.h
vendored
|
@ -112,14 +112,14 @@ int _Py_CheckRecursiveCall(const char *);
|
||||||
#define Py_EnterRecursiveCall(where) \
|
#define Py_EnterRecursiveCall(where) \
|
||||||
({ \
|
({ \
|
||||||
int rc = 0; \
|
int rc = 0; \
|
||||||
intptr_t rsp, bot; \
|
intptr_t rsp, bot; \
|
||||||
if (!IsTiny()) { \
|
if (!IsTiny()) { \
|
||||||
if (IsModeDbg()) { \
|
if (IsModeDbg()) { \
|
||||||
PyThreadState_GET()->recursion_depth++; \
|
PyThreadState_GET()->recursion_depth++; \
|
||||||
rc = _Py_CheckRecursiveCall(where); \
|
rc = _Py_CheckRecursiveCall(where); \
|
||||||
} else { \
|
} else { \
|
||||||
rsp = (intptr_t)__builtin_frame_address(0); \
|
rsp = (intptr_t)__builtin_frame_address(0); \
|
||||||
bot = (intptr_t)GetStackAddr(32768); \
|
bot = GetStackAddr() + 32768; \
|
||||||
if (UNLIKELY(rsp < bot)) { \
|
if (UNLIKELY(rsp < bot)) { \
|
||||||
PyErr_Format(PyExc_MemoryError, "Stack overflow%s", where); \
|
PyErr_Format(PyExc_MemoryError, "Stack overflow%s", where); \
|
||||||
rc = -1; \
|
rc = -1; \
|
||||||
|
|
|
@ -309,7 +309,7 @@ void LoadRelationships(int argc, char *argv[]) {
|
||||||
for (i = 0; i < threads; ++i) {
|
for (i = 0; i < threads; ++i) {
|
||||||
if (_spawn(LoadRelationshipsWorker, (void *)(intptr_t)i, th + i) == -1) {
|
if (_spawn(LoadRelationshipsWorker, (void *)(intptr_t)i, th + i) == -1) {
|
||||||
pthread_mutex_lock(&reportlock);
|
pthread_mutex_lock(&reportlock);
|
||||||
kprintf("error: clone(%d) failed %m\n", i);
|
kprintf("error: _spawn(%d) failed %m\n", i);
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -420,7 +420,7 @@ void Explore(void) {
|
||||||
for (i = 0; i < threads; ++i) {
|
for (i = 0; i < threads; ++i) {
|
||||||
if (_spawn(Diver, (void *)(intptr_t)i, th + i) == -1) {
|
if (_spawn(Diver, (void *)(intptr_t)i, th + i) == -1) {
|
||||||
pthread_mutex_lock(&reportlock);
|
pthread_mutex_lock(&reportlock);
|
||||||
kprintf("error: clone(%d) failed %m\n", i);
|
kprintf("error: _spawn(%d) failed %m\n", i);
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2015,6 +2015,48 @@ UNIX MODULE
|
||||||
This system call returns twice. The parent process gets the nonzero
|
This system call returns twice. The parent process gets the nonzero
|
||||||
pid. The child gets zero.
|
pid. The child gets zero.
|
||||||
|
|
||||||
|
Here's a simple usage example of creating subprocesses, where we
|
||||||
|
fork off a child worker from a main process hook callback to do some
|
||||||
|
independent chores, such as sending an HTTP request back to redbean.
|
||||||
|
|
||||||
|
-- as soon as server starts, make a fetch to the server
|
||||||
|
-- then signal redbean to shutdown when fetch is complete
|
||||||
|
local onServerStart = function()
|
||||||
|
if assert(unix.fork()) == 0 then
|
||||||
|
local ok, headers, body = Fetch('http://127.0.0.1:8080/test')
|
||||||
|
unix.kill(unix.getppid(), unix.SIGTERM)
|
||||||
|
unix.exit(0)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
OnServerStart = onServerStart
|
||||||
|
|
||||||
|
We didn't need to use wait() here, because (a) we want redbean to go
|
||||||
|
back to what it was doing before as the Fetch() completes, and (b)
|
||||||
|
redbean's main process already has a zombie collector. However it's
|
||||||
|
a moot point, since once the fetch is done, the child process then
|
||||||
|
asks redbean to gracefully shutdown by sending SIGTERM its parent.
|
||||||
|
|
||||||
|
This is actually a situation where we *must* use fork, because the
|
||||||
|
purpose of the main redbean process is to call accept() and create
|
||||||
|
workers. So if we programmed redbean to use the main process to send
|
||||||
|
a blocking request to itself instead, then redbean would deadlock
|
||||||
|
and never be able to accept() the client.
|
||||||
|
|
||||||
|
While deadlocking is an extreme example, the truth is that latency
|
||||||
|
issues can crop up for the same reason that just cause jitter
|
||||||
|
instead, and as such, can easily go unnoticed. For example, if you
|
||||||
|
do something that takes longer than a few milliseconds from inside
|
||||||
|
your redbean heartbeat, then that's a few milliseconds in which
|
||||||
|
redbean is no longer concurrent, and tail latency is being added to
|
||||||
|
its ability to accept new connections. fork() does a great job at
|
||||||
|
solving this.
|
||||||
|
|
||||||
|
If you're not sure how long something will take, then when in doubt,
|
||||||
|
fork off a process. You can then report its completion to something
|
||||||
|
like SQLite. Redbean makes having lots of processes cheap. On Linux
|
||||||
|
they're about as lightweight as what heavyweight environments call
|
||||||
|
greenlets. You can easily have 10,000 Redbean workers on one PC.
|
||||||
|
|
||||||
Here's some benchmarks for fork() performance across platforms:
|
Here's some benchmarks for fork() performance across platforms:
|
||||||
|
|
||||||
Linux 5.4 fork l: 97,200𝑐 31,395𝑛𝑠 [metal]
|
Linux 5.4 fork l: 97,200𝑐 31,395𝑛𝑠 [metal]
|
||||||
|
|
|
@ -82,7 +82,7 @@ int main(int argc, char *argv[]) {
|
||||||
if (IsWindows() && !IsAtLeastWindows10()) {
|
if (IsWindows() && !IsAtLeastWindows10()) {
|
||||||
plan(0x50000000, 0x7ffdffff, "arena");
|
plan(0x50000000, 0x7ffdffff, "arena");
|
||||||
}
|
}
|
||||||
x = (intptr_t)GetStaticStackAddr(0);
|
x = GetStaticStackAddr(0);
|
||||||
y = ROUNDUP(sizeof(struct WinArgs), FRAMESIZE);
|
y = ROUNDUP(sizeof(struct WinArgs), FRAMESIZE);
|
||||||
plan(x - y, x - 1, "winargs");
|
plan(x - y, x - 1, "winargs");
|
||||||
plan(x, x + GetStackSize() - 1, "stack");
|
plan(x, x + GetStackSize() - 1, "stack");
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue