mirror of
https://github.com/jart/cosmopolitan.git
synced 2025-05-23 13:52:28 +00:00
Use futexes on OpenBSD and improve threading
This commit is contained in:
parent
5b11033d4d
commit
4f4889ddf7
17 changed files with 114 additions and 63 deletions
|
@ -27,6 +27,7 @@ const char *DescribeFlags(char *, size_t, struct DescribeFlags *, size_t,
|
||||||
const char *DescribeClockName(char[32], int);
|
const char *DescribeClockName(char[32], int);
|
||||||
const char *DescribeDirfd(char[12], int);
|
const char *DescribeDirfd(char[12], int);
|
||||||
const char *DescribeFrame(char[32], int);
|
const char *DescribeFrame(char[32], int);
|
||||||
|
const char *DescribeFutexResult(char[12], int);
|
||||||
const char *DescribeHow(char[12], int);
|
const char *DescribeHow(char[12], int);
|
||||||
const char *DescribeMapFlags(char[64], int);
|
const char *DescribeMapFlags(char[64], int);
|
||||||
const char *DescribeMapping(char[8], int, int);
|
const char *DescribeMapping(char[8], int, int);
|
||||||
|
@ -76,6 +77,7 @@ void DescribeIovNt(const struct NtIovec *, uint32_t, ssize_t);
|
||||||
#define DescribeClockName(x) DescribeClockName(alloca(32), x)
|
#define DescribeClockName(x) DescribeClockName(alloca(32), x)
|
||||||
#define DescribeDirfd(dirfd) DescribeDirfd(alloca(12), dirfd)
|
#define DescribeDirfd(dirfd) DescribeDirfd(alloca(12), dirfd)
|
||||||
#define DescribeFrame(x) DescribeFrame(alloca(32), x)
|
#define DescribeFrame(x) DescribeFrame(alloca(32), x)
|
||||||
|
#define DescribeFutexResult(x) DescribeFutexResult(alloca(12), x)
|
||||||
#define DescribeHow(x) DescribeHow(alloca(12), x)
|
#define DescribeHow(x) DescribeHow(alloca(12), x)
|
||||||
#define DescribeMapFlags(dirfd) DescribeMapFlags(alloca(64), dirfd)
|
#define DescribeMapFlags(dirfd) DescribeMapFlags(alloca(64), dirfd)
|
||||||
#define DescribeMapping(x, y) DescribeMapping(alloca(8), x, y)
|
#define DescribeMapping(x, y) DescribeMapping(alloca(8), x, y)
|
||||||
|
|
31
libc/intrin/describefutexresult.c
Normal file
31
libc/intrin/describefutexresult.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 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/fmt/itoa.h"
|
||||||
|
#include "libc/intrin/describeflags.internal.h"
|
||||||
|
#include "libc/str/str.h"
|
||||||
|
|
||||||
|
const char *(DescribeFutexResult)(char buf[12], int ax) {
|
||||||
|
const char *s;
|
||||||
|
if (ax > -4095u && (s = strerrno(-ax))) {
|
||||||
|
return s;
|
||||||
|
} else {
|
||||||
|
FormatInt32(buf, ax);
|
||||||
|
return buf;
|
||||||
|
}
|
||||||
|
}
|
|
@ -20,7 +20,8 @@
|
||||||
#include "libc/macros.internal.h"
|
#include "libc/macros.internal.h"
|
||||||
.privileged
|
.privileged
|
||||||
|
|
||||||
_futex: mov __NR_futex,%eax
|
_futex: mov %rcx,%r10
|
||||||
|
mov __NR_futex,%eax
|
||||||
clc
|
clc
|
||||||
syscall
|
syscall
|
||||||
jnc 1f
|
jnc 1f
|
||||||
|
|
|
@ -4,7 +4,6 @@
|
||||||
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||||
COSMOPOLITAN_C_START_
|
COSMOPOLITAN_C_START_
|
||||||
|
|
||||||
int _futex(void *, int, int, struct timespec *, int *) hidden;
|
|
||||||
int _futex_wait(void *, int, struct timespec *) hidden;
|
int _futex_wait(void *, int, struct timespec *) hidden;
|
||||||
int _futex_wake(void *, int) hidden;
|
int _futex_wake(void *, int) hidden;
|
||||||
|
|
||||||
|
|
|
@ -18,28 +18,16 @@
|
||||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||||
#include "libc/calls/strace.internal.h"
|
#include "libc/calls/strace.internal.h"
|
||||||
#include "libc/calls/struct/timespec.h"
|
#include "libc/calls/struct/timespec.h"
|
||||||
#include "libc/errno.h"
|
#include "libc/dce.h"
|
||||||
#include "libc/fmt/itoa.h"
|
|
||||||
#include "libc/intrin/describeflags.internal.h"
|
#include "libc/intrin/describeflags.internal.h"
|
||||||
#include "libc/intrin/futex.internal.h"
|
#include "libc/intrin/futex.internal.h"
|
||||||
#include "libc/mem/alloca.h"
|
|
||||||
#include "libc/str/str.h"
|
|
||||||
#include "libc/sysv/consts/futex.h"
|
#include "libc/sysv/consts/futex.h"
|
||||||
|
|
||||||
static const char *DescribeFutexWaitResult(char buf[12], int ax) {
|
int _futex(void *, int, int, struct timespec *) hidden;
|
||||||
const char *s;
|
|
||||||
if (ax && ((s = strerrno(ax)) || (s = strerrno(-ax)))) {
|
|
||||||
return s;
|
|
||||||
} else {
|
|
||||||
FormatInt32(buf, ax);
|
|
||||||
return buf;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int _futex_wait(void *addr, int expect, struct timespec *timeout) {
|
int _futex_wait(void *addr, int expect, struct timespec *timeout) {
|
||||||
int ax;
|
int ax = _futex(addr, FUTEX_WAIT, expect, timeout);
|
||||||
ax = _futex(addr, FUTEX_WAIT, expect, timeout, 0);
|
if (IsOpenbsd() && ax > 0) ax = -ax; // yes openbsd does this w/o cf
|
||||||
STRACE("futex(%t[%p], FUTEX_WAIT, %d, %s) → %s", addr, addr, expect,
|
STRACE("futex(%t, FUTEX_WAIT, %d, %s) → %s", addr, expect,
|
||||||
DescribeTimespec(0, timeout), DescribeFutexWaitResult(alloca(12), ax));
|
DescribeTimespec(0, timeout), DescribeFutexResult(ax));
|
||||||
return ax;
|
return ax;
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,30 +16,15 @@
|
||||||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||||
#include "libc/bits/asmflag.h"
|
|
||||||
#include "libc/calls/strace.internal.h"
|
#include "libc/calls/strace.internal.h"
|
||||||
#include "libc/fmt/itoa.h"
|
|
||||||
#include "libc/intrin/describeflags.internal.h"
|
#include "libc/intrin/describeflags.internal.h"
|
||||||
#include "libc/intrin/futex.internal.h"
|
#include "libc/intrin/futex.internal.h"
|
||||||
#include "libc/mem/alloca.h"
|
|
||||||
#include "libc/str/str.h"
|
|
||||||
#include "libc/sysv/consts/futex.h"
|
#include "libc/sysv/consts/futex.h"
|
||||||
#include "libc/sysv/consts/nr.h"
|
|
||||||
|
|
||||||
static const char *DescribeFutexWakeResult(char buf[12], int ax) {
|
|
||||||
const char *s;
|
|
||||||
if (ax < 0 && (s = strerrno(ax))) {
|
|
||||||
return s;
|
|
||||||
} else {
|
|
||||||
FormatInt32(buf, ax);
|
|
||||||
return buf;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
int _futex(void *, int, int) hidden;
|
||||||
int _futex_wake(void *addr, int count) {
|
int _futex_wake(void *addr, int count) {
|
||||||
int ax;
|
int ax = _futex(addr, FUTEX_WAKE, count);
|
||||||
ax = _futex(addr, FUTEX_WAKE, count, 0, 0);
|
STRACE("futex(%t, FUTEX_WAKE, %d) → %s", addr, count,
|
||||||
STRACE("futex(%t[%p], FUTEX_WAKE, %d) → %s", addr, addr, count,
|
DescribeFutexResult(ax));
|
||||||
DescribeFutexWakeResult(alloca(12), ax));
|
|
||||||
return ax;
|
return ax;
|
||||||
}
|
}
|
||||||
|
|
|
@ -137,11 +137,10 @@ void *pthread_getspecific(pthread_key_t);
|
||||||
!atomic_exchange(&(mutex)->lock, 1)) \
|
!atomic_exchange(&(mutex)->lock, 1)) \
|
||||||
? 0 \
|
? 0 \
|
||||||
: pthread_mutex_lock(mutex))
|
: pthread_mutex_lock(mutex))
|
||||||
|
|
||||||
#define pthread_mutex_unlock(mutex) \
|
#define pthread_mutex_unlock(mutex) \
|
||||||
((mutex)->attr == PTHREAD_MUTEX_NORMAL \
|
((mutex)->attr == PTHREAD_MUTEX_NORMAL \
|
||||||
? (atomic_store_explicit(&(mutex)->lock, 0, memory_order_relaxed), \
|
? (atomic_store_explicit(&(mutex)->lock, 0, memory_order_relaxed), \
|
||||||
((IsLinux() /* || IsOpenbsd() */) && \
|
((IsLinux() || IsOpenbsd()) && \
|
||||||
atomic_load_explicit(&(mutex)->waits, memory_order_relaxed) && \
|
atomic_load_explicit(&(mutex)->waits, memory_order_relaxed) && \
|
||||||
_pthread_mutex_wake(mutex)), \
|
_pthread_mutex_wake(mutex)), \
|
||||||
0) \
|
0) \
|
||||||
|
|
|
@ -32,12 +32,12 @@
|
||||||
|
|
||||||
static int pthread_mutex_lock_spin(pthread_mutex_t *mutex, int expect,
|
static int pthread_mutex_lock_spin(pthread_mutex_t *mutex, int expect,
|
||||||
int tries) {
|
int tries) {
|
||||||
volatile int i;
|
|
||||||
if (tries < 7) {
|
if (tries < 7) {
|
||||||
|
volatile int i;
|
||||||
for (i = 0; i != 1 << tries; i++) {
|
for (i = 0; i != 1 << tries; i++) {
|
||||||
}
|
}
|
||||||
tries++;
|
tries++;
|
||||||
} else if (IsLinux() /* || IsOpenbsd() */) {
|
} else if (IsLinux() || IsOpenbsd()) {
|
||||||
atomic_fetch_add(&mutex->waits, 1);
|
atomic_fetch_add(&mutex->waits, 1);
|
||||||
_futex_wait(&mutex->lock, expect, &(struct timespec){1});
|
_futex_wait(&mutex->lock, expect, &(struct timespec){1});
|
||||||
atomic_fetch_sub(&mutex->waits, 1);
|
atomic_fetch_sub(&mutex->waits, 1);
|
||||||
|
|
|
@ -44,7 +44,7 @@ int(pthread_mutex_unlock)(pthread_mutex_t *mutex) {
|
||||||
// fallthrough
|
// fallthrough
|
||||||
case PTHREAD_MUTEX_NORMAL:
|
case PTHREAD_MUTEX_NORMAL:
|
||||||
atomic_store_explicit(&mutex->lock, 0, memory_order_relaxed);
|
atomic_store_explicit(&mutex->lock, 0, memory_order_relaxed);
|
||||||
if ((IsLinux() /* || IsOpenbsd() */) &&
|
if ((IsLinux() || IsOpenbsd()) &&
|
||||||
atomic_load_explicit(&mutex->waits, memory_order_relaxed) > 0) {
|
atomic_load_explicit(&mutex->waits, memory_order_relaxed) > 0) {
|
||||||
_pthread_mutex_wake(mutex);
|
_pthread_mutex_wake(mutex);
|
||||||
}
|
}
|
||||||
|
|
|
@ -36,10 +36,14 @@ void _wait0(const int *ctid) {
|
||||||
for (;;) {
|
for (;;) {
|
||||||
if (!(x = atomic_load_explicit(ctid, memory_order_acquire))) {
|
if (!(x = atomic_load_explicit(ctid, memory_order_acquire))) {
|
||||||
break;
|
break;
|
||||||
} else if (IsLinux() /* || IsOpenbsd() */) {
|
} else if (IsLinux() || IsOpenbsd()) {
|
||||||
_futex_wait(ctid, x, &(struct timespec){2});
|
_futex_wait(ctid, x, &(struct timespec){2});
|
||||||
} else {
|
} else {
|
||||||
sched_yield();
|
sched_yield();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (IsOpenbsd()) {
|
||||||
|
// TODO(jart): whyyyy do we need it
|
||||||
|
sched_yield();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -306,11 +306,14 @@ noasan static wontreturn void OpenbsdThreadMain(void *p) {
|
||||||
// although ideally there should be a better solution.
|
// although ideally there should be a better solution.
|
||||||
//
|
//
|
||||||
// void __threxit(%rdi = int32_t *notdead);
|
// void __threxit(%rdi = int32_t *notdead);
|
||||||
asm volatile("mov\t%2,%%rsp\n\t" // set stack
|
asm volatile("mov\t%2,%%rsp\n\t"
|
||||||
"movl\t$0,(%%rdi)\n\t" // *wt->ztid = 0
|
"movl\t$0,(%%rdi)\n\t" // *wt->ztid = 0
|
||||||
"syscall" // __threxit()
|
"syscall\n\t" // futex()
|
||||||
|
"mov\t$302,%%eax\n\t" // threxit()
|
||||||
|
"syscall"
|
||||||
: "=m"(*wt->ztid)
|
: "=m"(*wt->ztid)
|
||||||
: "a"(302), "m"(oldrsp), "D"(wt->ztid)
|
: "a"(83), "m"(oldrsp), "D"(wt->ztid), "S"(FUTEX_WAKE),
|
||||||
|
"d"(INT_MAX)
|
||||||
: "rcx", "r11", "memory");
|
: "rcx", "r11", "memory");
|
||||||
unreachable;
|
unreachable;
|
||||||
}
|
}
|
||||||
|
|
|
@ -48,10 +48,6 @@ STATIC_YOINK("libc/testlib/hyperion.txt");
|
||||||
|
|
||||||
#define THREADS 8
|
#define THREADS 8
|
||||||
|
|
||||||
__attribute__((__constructor__)) static void init(void) {
|
|
||||||
if (IsOpenbsd()) exit(0); // TODO(jart): flakes :'(
|
|
||||||
}
|
|
||||||
|
|
||||||
void PullSomeZipFilesIntoLinkage(void) {
|
void PullSomeZipFilesIntoLinkage(void) {
|
||||||
gmtime(0);
|
gmtime(0);
|
||||||
}
|
}
|
||||||
|
@ -121,12 +117,8 @@ TEST(reservefd, tortureTest) {
|
||||||
.sa_flags = 0 /* SA_NODEFER */};
|
.sa_flags = 0 /* SA_NODEFER */};
|
||||||
// ASSERT_SYS(0, 0, sigaction(SIGALRM, &sa, &oldsa));
|
// ASSERT_SYS(0, 0, sigaction(SIGALRM, &sa, &oldsa));
|
||||||
// ASSERT_SYS(0, 0, setitimer(ITIMER_REAL, &it, &oldit));
|
// ASSERT_SYS(0, 0, setitimer(ITIMER_REAL, &it, &oldit));
|
||||||
for (i = 0; i < THREADS; ++i) {
|
for (i = 0; i < THREADS; ++i) _spawn(Worker, 0, th + i);
|
||||||
_spawn(Worker, 0, th + i);
|
for (i = 0; i < THREADS; ++i) _join(th + i);
|
||||||
}
|
|
||||||
for (i = 0; i < THREADS; ++i) {
|
|
||||||
_join(th + i);
|
|
||||||
}
|
|
||||||
// EXPECT_SYS(0, 0, sigaction(SIGALRM, &oldsa, 0));
|
// EXPECT_SYS(0, 0, sigaction(SIGALRM, &oldsa, 0));
|
||||||
// EXPECT_SYS(0, 0, setitimer(ITIMER_REAL, &oldit, 0));
|
// EXPECT_SYS(0, 0, setitimer(ITIMER_REAL, &oldit, 0));
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,6 +17,7 @@
|
||||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||||
#include "libc/calls/calls.h"
|
#include "libc/calls/calls.h"
|
||||||
|
#include "libc/calls/struct/sched_param.h"
|
||||||
#include "libc/dce.h"
|
#include "libc/dce.h"
|
||||||
#include "libc/fmt/fmt.h"
|
#include "libc/fmt/fmt.h"
|
||||||
#include "libc/intrin/spinlock.h"
|
#include "libc/intrin/spinlock.h"
|
||||||
|
@ -29,6 +30,7 @@
|
||||||
#include "libc/sysv/consts/clone.h"
|
#include "libc/sysv/consts/clone.h"
|
||||||
#include "libc/sysv/consts/map.h"
|
#include "libc/sysv/consts/map.h"
|
||||||
#include "libc/sysv/consts/prot.h"
|
#include "libc/sysv/consts/prot.h"
|
||||||
|
#include "libc/sysv/consts/sched.h"
|
||||||
#include "libc/testlib/testlib.h"
|
#include "libc/testlib/testlib.h"
|
||||||
#include "libc/thread/spawn.h"
|
#include "libc/thread/spawn.h"
|
||||||
#include "libc/x/x.h"
|
#include "libc/x/x.h"
|
||||||
|
@ -61,7 +63,6 @@ int Worker(void *p, int tid) {
|
||||||
TEST(dtoa, locks) {
|
TEST(dtoa, locks) {
|
||||||
int i, n = 32;
|
int i, n = 32;
|
||||||
struct spawn *t = gc(malloc(sizeof(struct spawn) * n));
|
struct spawn *t = gc(malloc(sizeof(struct spawn) * n));
|
||||||
if (IsOpenbsd()) return; // TODO(jart): OpenBSD flakes :'(
|
|
||||||
for (i = 0; i < n; ++i) ASSERT_SYS(0, 0, _spawn(Worker, 0, t + i));
|
for (i = 0; i < n; ++i) ASSERT_SYS(0, 0, _spawn(Worker, 0, 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));
|
||||||
}
|
}
|
||||||
|
|
47
test/libc/stdio/memory_test.c
Normal file
47
test/libc/stdio/memory_test.c
Normal file
|
@ -0,0 +1,47 @@
|
||||||
|
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
|
||||||
|
│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│
|
||||||
|
╞══════════════════════════════════════════════════════════════════════════════╡
|
||||||
|
│ Copyright 2022 Justine Alexandra Roberts Tunney │
|
||||||
|
│ │
|
||||||
|
│ Permission to use, copy, modify, and/or distribute this software for │
|
||||||
|
│ any purpose with or without fee is hereby granted, provided that the │
|
||||||
|
│ above copyright notice and this permission notice appear in all copies. │
|
||||||
|
│ │
|
||||||
|
│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │
|
||||||
|
│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │
|
||||||
|
│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │
|
||||||
|
│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │
|
||||||
|
│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │
|
||||||
|
│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │
|
||||||
|
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||||
|
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||||
|
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||||
|
#include "libc/calls/calls.h"
|
||||||
|
#include "libc/mem/mem.h"
|
||||||
|
#include "libc/runtime/gc.internal.h"
|
||||||
|
#include "libc/stdio/stdio.h"
|
||||||
|
#include "libc/testlib/testlib.h"
|
||||||
|
#include "libc/thread/spawn.h"
|
||||||
|
|
||||||
|
int Worker(void *arg, int tid) {
|
||||||
|
int i;
|
||||||
|
char *volatile p;
|
||||||
|
char *volatile q;
|
||||||
|
for (i = 0; i < 256; ++i) {
|
||||||
|
p = malloc(17);
|
||||||
|
free(p);
|
||||||
|
p = malloc(17);
|
||||||
|
q = malloc(17);
|
||||||
|
sched_yield();
|
||||||
|
free(p);
|
||||||
|
free(q);
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(memory, test) {
|
||||||
|
int i, n = 32;
|
||||||
|
struct spawn *t = gc(malloc(sizeof(struct spawn) * n));
|
||||||
|
for (i = 0; i < n; ++i) ASSERT_SYS(0, 0, _spawn(Worker, 0, t + i));
|
||||||
|
for (i = 0; i < n; ++i) EXPECT_SYS(0, 0, _join(t + i));
|
||||||
|
}
|
1
third_party/dlmalloc/dlmalloc.c
vendored
1
third_party/dlmalloc/dlmalloc.c
vendored
|
@ -23,6 +23,7 @@
|
||||||
#define HAVE_MMAP 1
|
#define HAVE_MMAP 1
|
||||||
#define HAVE_MREMAP 0
|
#define HAVE_MREMAP 0
|
||||||
#define HAVE_MORECORE 0
|
#define HAVE_MORECORE 0
|
||||||
|
#define USE_LOCKS 1
|
||||||
#define USE_SPIN_LOCKS 1
|
#define USE_SPIN_LOCKS 1
|
||||||
#define MORECORE_CONTIGUOUS 0
|
#define MORECORE_CONTIGUOUS 0
|
||||||
#define MALLOC_INSPECT_ALL 1
|
#define MALLOC_INSPECT_ALL 1
|
||||||
|
|
3
third_party/dlmalloc/platform.inc
vendored
3
third_party/dlmalloc/platform.inc
vendored
|
@ -250,12 +250,9 @@ extern void* sbrk(ptrdiff_t);
|
||||||
#if USE_LOCKS
|
#if USE_LOCKS
|
||||||
#ifndef WIN32
|
#ifndef WIN32
|
||||||
#if defined (__SVR4) && defined (__sun) /* solaris */
|
#if defined (__SVR4) && defined (__sun) /* solaris */
|
||||||
#include <thread.h>
|
|
||||||
#elif !defined(LACKS_SCHED_H)
|
#elif !defined(LACKS_SCHED_H)
|
||||||
#include <sched.h>
|
|
||||||
#endif /* solaris or LACKS_SCHED_H */
|
#endif /* solaris or LACKS_SCHED_H */
|
||||||
#if (defined(USE_RECURSIVE_LOCKS) && USE_RECURSIVE_LOCKS != 0) || !USE_SPIN_LOCKS
|
#if (defined(USE_RECURSIVE_LOCKS) && USE_RECURSIVE_LOCKS != 0) || !USE_SPIN_LOCKS
|
||||||
#include <pthread.h>
|
|
||||||
#endif /* USE_RECURSIVE_LOCKS ... */
|
#endif /* USE_RECURSIVE_LOCKS ... */
|
||||||
#elif defined(_MSC_VER)
|
#elif defined(_MSC_VER)
|
||||||
#ifndef _M_AMD64
|
#ifndef _M_AMD64
|
||||||
|
|
3
third_party/gdtoa/misc.c
vendored
3
third_party/gdtoa/misc.c
vendored
|
@ -29,7 +29,6 @@
|
||||||
│ THIS SOFTWARE. │
|
│ THIS SOFTWARE. │
|
||||||
│ │
|
│ │
|
||||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||||
#include "libc/assert.h"
|
|
||||||
#include "libc/calls/calls.h"
|
#include "libc/calls/calls.h"
|
||||||
#include "libc/macros.internal.h"
|
#include "libc/macros.internal.h"
|
||||||
#include "libc/runtime/runtime.h"
|
#include "libc/runtime/runtime.h"
|
||||||
|
@ -54,7 +53,9 @@ __gdtoa_Bclear(void)
|
||||||
__gdtoa_lock();
|
__gdtoa_lock();
|
||||||
for (i = 0; i < ARRAYLEN(TI0.Freelist); ++i)
|
for (i = 0; i < ARRAYLEN(TI0.Freelist); ++i)
|
||||||
__gdtoa_Brelease(TI0.Freelist[i]);
|
__gdtoa_Brelease(TI0.Freelist[i]);
|
||||||
|
__gdtoa_lock1();
|
||||||
__gdtoa_Brelease(TI0.P5s);
|
__gdtoa_Brelease(TI0.P5s);
|
||||||
|
__gdtoa_unlock1();
|
||||||
bzero(&TI0, sizeof(TI0));
|
bzero(&TI0, sizeof(TI0));
|
||||||
__gdtoa_unlock();
|
__gdtoa_unlock();
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue