mirror of
https://github.com/jart/cosmopolitan.git
synced 2025-05-28 00:02:28 +00:00
Make improvements to locking
This change makes pthread_mutex_lock() as fast as _spinlock() by default. Thread instability issues on NetBSD have been resolved. Improvements made to gdtoa thread code. Crash reporting will now synchronize between threads in a slightly better way.
This commit is contained in:
parent
25041b8026
commit
d5312b60f7
60 changed files with 890 additions and 629 deletions
|
@ -56,7 +56,7 @@ void SetUp(void) {
|
|||
ASSERT_SYS(0, 0, mkdir("tmp", 0755));
|
||||
ASSERT_SYS(0, 0, mkdir("bin", 0755));
|
||||
Extract("/zip/tiny64.elf", "bin/tiny64.elf", 0755);
|
||||
Extract("/zip/pylife.com", "bin/pylife.com", 0755);
|
||||
// Extract("/zip/pylife.com", "bin/pylife.com", 0755);
|
||||
Extract("/zip/life-nomod.com", "bin/life-nomod.com", 0755);
|
||||
Extract("/zip/life-classic.com", "bin/life-classic.com", 0755);
|
||||
setenv("TMPDIR", "tmp", true);
|
||||
|
@ -190,6 +190,7 @@ TEST(execve, vfork_apeClassic) {
|
|||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
#if 0 // not worth depending on THIRD_PARTY_PYTHON for this test
|
||||
|
||||
TEST(execve, system_apeNoMod3mb) {
|
||||
if (IsWindows()) return; // todo(jart): wut
|
||||
|
@ -229,6 +230,7 @@ TEST(execve, vfork_apeNoMod3mb) {
|
|||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void SystemElf(void) {
|
||||
|
|
22
test/libc/calls/life.c
Normal file
22
test/libc/calls/life.c
Normal file
|
@ -0,0 +1,22 @@
|
|||
/*-*- 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. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
return 42;
|
||||
}
|
|
@ -3,74 +3,95 @@
|
|||
|
||||
PKGS += TEST_LIBC_CALLS
|
||||
|
||||
TEST_LIBC_CALLS_SRCS := \
|
||||
TEST_LIBC_CALLS_SRCS := \
|
||||
$(wildcard test/libc/calls/*.c)
|
||||
TEST_LIBC_CALLS_SRCS_TEST = $(filter %_test.c,$(TEST_LIBC_CALLS_SRCS))
|
||||
|
||||
TEST_LIBC_CALLS_OBJS = \
|
||||
TEST_LIBC_CALLS_SRCS_TEST = \
|
||||
$(filter %_test.c,$(TEST_LIBC_CALLS_SRCS))
|
||||
|
||||
TEST_LIBC_CALLS_OBJS = \
|
||||
$(TEST_LIBC_CALLS_SRCS:%.c=o/$(MODE)/%.o)
|
||||
|
||||
TEST_LIBC_CALLS_COMS = \
|
||||
$(TEST_LIBC_CALLS_SRCS:%.c=o/$(MODE)/%.com)
|
||||
TEST_LIBC_CALLS_COMS = \
|
||||
$(TEST_LIBC_CALLS_SRCS_TEST:%.c=o/$(MODE)/%.com)
|
||||
|
||||
TEST_LIBC_CALLS_BINS = \
|
||||
$(TEST_LIBC_CALLS_COMS) \
|
||||
TEST_LIBC_CALLS_BINS = \
|
||||
$(TEST_LIBC_CALLS_COMS) \
|
||||
$(TEST_LIBC_CALLS_COMS:%=%.dbg)
|
||||
|
||||
TEST_LIBC_CALLS_TESTS = \
|
||||
TEST_LIBC_CALLS_TESTS = \
|
||||
$(TEST_LIBC_CALLS_SRCS_TEST:%.c=o/$(MODE)/%.com.ok)
|
||||
|
||||
TEST_LIBC_CALLS_CHECKS = \
|
||||
TEST_LIBC_CALLS_CHECKS = \
|
||||
$(TEST_LIBC_CALLS_SRCS_TEST:%.c=o/$(MODE)/%.com.runs)
|
||||
|
||||
TEST_LIBC_CALLS_DIRECTDEPS = \
|
||||
DSP_CORE \
|
||||
LIBC_CALLS \
|
||||
LIBC_TINYMATH \
|
||||
LIBC_SOCK \
|
||||
LIBC_FMT \
|
||||
LIBC_INTRIN \
|
||||
LIBC_LOG \
|
||||
LIBC_MEM \
|
||||
LIBC_NEXGEN32E \
|
||||
LIBC_RAND \
|
||||
LIBC_STDIO \
|
||||
LIBC_SYSV_CALLS \
|
||||
LIBC_RUNTIME \
|
||||
LIBC_STR \
|
||||
LIBC_STUBS \
|
||||
LIBC_SYSV \
|
||||
LIBC_TIME \
|
||||
LIBC_TESTLIB \
|
||||
LIBC_UNICODE \
|
||||
LIBC_X \
|
||||
LIBC_ZIPOS \
|
||||
TEST_LIBC_CALLS_DIRECTDEPS = \
|
||||
DSP_CORE \
|
||||
LIBC_CALLS \
|
||||
LIBC_TINYMATH \
|
||||
LIBC_SOCK \
|
||||
LIBC_FMT \
|
||||
LIBC_INTRIN \
|
||||
LIBC_LOG \
|
||||
LIBC_MEM \
|
||||
LIBC_NEXGEN32E \
|
||||
LIBC_RAND \
|
||||
LIBC_STDIO \
|
||||
LIBC_SYSV_CALLS \
|
||||
LIBC_RUNTIME \
|
||||
LIBC_STR \
|
||||
LIBC_STUBS \
|
||||
LIBC_SYSV \
|
||||
LIBC_TIME \
|
||||
LIBC_TESTLIB \
|
||||
LIBC_UNICODE \
|
||||
LIBC_X \
|
||||
LIBC_ZIPOS \
|
||||
THIRD_PARTY_XED
|
||||
|
||||
TEST_LIBC_CALLS_DEPS := \
|
||||
TEST_LIBC_CALLS_DEPS := \
|
||||
$(call uniq,$(foreach x,$(TEST_LIBC_CALLS_DIRECTDEPS),$($(x))))
|
||||
|
||||
o/$(MODE)/test/libc/calls/calls.pkg: \
|
||||
$(TEST_LIBC_CALLS_OBJS) \
|
||||
o/$(MODE)/test/libc/calls/calls.pkg: \
|
||||
$(TEST_LIBC_CALLS_OBJS) \
|
||||
$(foreach x,$(TEST_LIBC_CALLS_DIRECTDEPS),$($(x)_A).pkg)
|
||||
|
||||
o/$(MODE)/test/libc/calls/%.com.dbg: \
|
||||
$(TEST_LIBC_CALLS_DEPS) \
|
||||
o/$(MODE)/test/libc/calls/%.o \
|
||||
o/$(MODE)/examples/life-nomod.com.zip.o \
|
||||
o/$(MODE)/examples/life-classic.com.zip.o \
|
||||
o/$(MODE)/examples/pylife/pylife.com.zip.o \
|
||||
o/$(MODE)/test/libc/calls/tiny64.elf.zip.o \
|
||||
o/$(MODE)/test/libc/calls/%.com.dbg: \
|
||||
$(TEST_LIBC_CALLS_DEPS) \
|
||||
o/$(MODE)/test/libc/calls/%.o \
|
||||
o/$(MODE)/test/libc/calls/life-nomod.com.zip.o \
|
||||
o/$(MODE)/test/libc/calls/life-classic.com.zip.o \
|
||||
o/$(MODE)/test/libc/calls/tiny64.elf.zip.o \
|
||||
o/$(MODE)/third_party/python/Lib/test/tokenize_tests-latin1-coding-cookie-and-utf8-bom-sig.txt.zip.o \
|
||||
o/$(MODE)/test/libc/calls/calls.pkg \
|
||||
$(LIBC_TESTMAIN) \
|
||||
$(CRT) \
|
||||
o/$(MODE)/test/libc/calls/calls.pkg \
|
||||
$(LIBC_TESTMAIN) \
|
||||
$(CRT) \
|
||||
$(APE_NO_MODIFY_SELF)
|
||||
@$(APELINK)
|
||||
|
||||
o/$(MODE)/test/libc/calls/tiny64.elf.zip.o: ZIPOBJ_FLAGS += -B
|
||||
|
||||
o/$(MODE)/test/libc/calls/life-nomod.com.zip.o: o/$(MODE)/test/libc/calls/life-nomod.com
|
||||
@$(COMPILE) -AZIPOBJ $(ZIPOBJ) $(ZIPOBJ_FLAGS) -B $(OUTPUT_OPTION) $<
|
||||
|
||||
o/$(MODE)/test/libc/calls/life-classic.com.zip.o: o/$(MODE)/test/libc/calls/life-classic.com
|
||||
@$(COMPILE) -AZIPOBJ $(ZIPOBJ) $(ZIPOBJ_FLAGS) -B $(OUTPUT_OPTION) $<
|
||||
|
||||
o/$(MODE)/test/libc/calls/life-classic.com.dbg: \
|
||||
$(LIBC_RUNTIME) \
|
||||
o/$(MODE)/test/libc/calls/life.o \
|
||||
$(CRT) \
|
||||
$(APE)
|
||||
@$(APELINK)
|
||||
|
||||
o/$(MODE)/test/libc/calls/life-nomod.com.dbg: \
|
||||
$(LIBC_RUNTIME) \
|
||||
o/$(MODE)/test/libc/calls/life.o \
|
||||
$(CRT) \
|
||||
$(APE_NO_MODIFY_SELF)
|
||||
@$(APELINK)
|
||||
|
||||
.PHONY: o/$(MODE)/test/libc/calls
|
||||
o/$(MODE)/test/libc/calls: \
|
||||
$(TEST_LIBC_CALLS_BINS) \
|
||||
o/$(MODE)/test/libc/calls: \
|
||||
$(TEST_LIBC_CALLS_BINS) \
|
||||
$(TEST_LIBC_CALLS_CHECKS)
|
||||
|
|
|
@ -91,6 +91,7 @@ TEST(memcmp, fuzz) {
|
|||
int buncmp(const void *, const void *, size_t) asm("bcmp");
|
||||
int funcmp(const void *, const void *, size_t) asm("memcmp");
|
||||
|
||||
#if 0
|
||||
BENCH(bcmp, bench) {
|
||||
volatile int v;
|
||||
const char *volatile a;
|
||||
|
@ -135,7 +136,9 @@ BENCH(bcmp, bench) {
|
|||
memcpy(b, a, 128 * 1024);
|
||||
EZBENCH_N("bcmp", 131072, v = buncmp(a, b, 131072));
|
||||
}
|
||||
#endif
|
||||
|
||||
#if 0
|
||||
BENCH(memcmp, bench) {
|
||||
volatile int v;
|
||||
const char *volatile a;
|
||||
|
@ -180,7 +183,9 @@ BENCH(memcmp, bench) {
|
|||
memcpy(b, a, 128 * 1024);
|
||||
EZBENCH_N("memcmp", 131072, v = funcmp(a, b, 131072));
|
||||
}
|
||||
#endif
|
||||
|
||||
#if 0
|
||||
BENCH(timingsafe_memcmp, bench) {
|
||||
volatile int v;
|
||||
const char *volatile a;
|
||||
|
@ -225,7 +230,9 @@ BENCH(timingsafe_memcmp, bench) {
|
|||
memcpy(b, a, 128 * 1024);
|
||||
EZBENCH_N("timingsafe_memcmp", 131072, v = timingsafe_memcmp(a, b, 131072));
|
||||
}
|
||||
#endif
|
||||
|
||||
#if 0
|
||||
BENCH(timingsafe_bcmp, bench) {
|
||||
volatile int v;
|
||||
const char *volatile a;
|
||||
|
@ -270,7 +277,9 @@ BENCH(timingsafe_bcmp, bench) {
|
|||
memcpy(b, a, 128 * 1024);
|
||||
EZBENCH_N("timingsafe_bcmp", 131072, v = timingsafe_bcmp(a, b, 131072));
|
||||
}
|
||||
#endif
|
||||
|
||||
#if 0
|
||||
BENCH(memcasecmp, bench) {
|
||||
volatile int v;
|
||||
const char *volatile a;
|
||||
|
@ -315,7 +324,9 @@ BENCH(memcasecmp, bench) {
|
|||
memcpy(b, a, 128 * 1024);
|
||||
EZBENCH_N("memcasecmp", 131072, v = memcasecmp(a, b, 131072));
|
||||
}
|
||||
#endif
|
||||
|
||||
#if 0
|
||||
BENCH(timingsafe_memcmp, demonstration) {
|
||||
int bcmp_(const void *, const void *, size_t) asm("bcmp");
|
||||
int memcmp_(const void *, const void *, size_t) asm("memcmp");
|
||||
|
@ -339,3 +350,4 @@ BENCH(timingsafe_memcmp, demonstration) {
|
|||
a[0] = b[0];
|
||||
EZBENCH_N("timingsafe_memcmp eq", 256, timingsafe_memcmp(a, b, 256));
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -51,6 +51,7 @@ TEST(pthread_mutex_lock, normal) {
|
|||
ASSERT_EQ(0, pthread_mutexattr_init(&attr));
|
||||
ASSERT_EQ(0, pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_NORMAL));
|
||||
ASSERT_EQ(0, pthread_mutex_init(&lock, &attr));
|
||||
ASSERT_EQ(0, pthread_mutexattr_destroy(&attr));
|
||||
ASSERT_EQ(0, pthread_mutex_init(&lock, 0));
|
||||
ASSERT_EQ(0, pthread_mutex_lock(&lock));
|
||||
ASSERT_EQ(0, pthread_mutex_unlock(&lock));
|
||||
|
@ -65,6 +66,7 @@ TEST(pthread_mutex_lock, recursive) {
|
|||
ASSERT_EQ(0, pthread_mutexattr_init(&attr));
|
||||
ASSERT_EQ(0, pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE));
|
||||
ASSERT_EQ(0, pthread_mutex_init(&lock, &attr));
|
||||
ASSERT_EQ(0, pthread_mutexattr_destroy(&attr));
|
||||
ASSERT_EQ(0, pthread_mutex_lock(&lock));
|
||||
ASSERT_EQ(0, pthread_mutex_lock(&lock));
|
||||
ASSERT_EQ(0, pthread_mutex_unlock(&lock));
|
||||
|
@ -72,7 +74,6 @@ TEST(pthread_mutex_lock, recursive) {
|
|||
ASSERT_EQ(0, pthread_mutex_unlock(&lock));
|
||||
ASSERT_EQ(0, pthread_mutex_unlock(&lock));
|
||||
ASSERT_EQ(0, pthread_mutex_destroy(&lock));
|
||||
ASSERT_EQ(0, pthread_mutexattr_destroy(&attr));
|
||||
}
|
||||
|
||||
TEST(pthread_mutex_lock, errorcheck) {
|
||||
|
@ -81,13 +82,13 @@ TEST(pthread_mutex_lock, errorcheck) {
|
|||
ASSERT_EQ(0, pthread_mutexattr_init(&attr));
|
||||
ASSERT_EQ(0, pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_ERRORCHECK));
|
||||
ASSERT_EQ(0, pthread_mutex_init(&lock, &attr));
|
||||
ASSERT_EQ(0, pthread_mutexattr_destroy(&attr));
|
||||
ASSERT_EQ(EPERM, pthread_mutex_unlock(&lock));
|
||||
ASSERT_EQ(0, pthread_mutex_lock(&lock));
|
||||
ASSERT_EQ(EDEADLK, pthread_mutex_lock(&lock));
|
||||
ASSERT_EQ(0, pthread_mutex_unlock(&lock));
|
||||
ASSERT_EQ(EPERM, pthread_mutex_unlock(&lock));
|
||||
ASSERT_EQ(0, pthread_mutex_destroy(&lock));
|
||||
ASSERT_EQ(0, pthread_mutexattr_destroy(&attr));
|
||||
}
|
||||
|
||||
int count;
|
||||
|
@ -107,6 +108,11 @@ int MutexWorker(void *p) {
|
|||
|
||||
TEST(pthread_mutex_lock, contention) {
|
||||
int i;
|
||||
pthread_mutexattr_t attr;
|
||||
pthread_mutexattr_init(&attr);
|
||||
pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_NORMAL);
|
||||
pthread_mutex_init(&lock, &attr);
|
||||
pthread_mutexattr_destroy(&attr);
|
||||
count = 0;
|
||||
for (i = 0; i < THREADS; ++i) {
|
||||
clone(MutexWorker,
|
||||
|
@ -125,6 +131,63 @@ TEST(pthread_mutex_lock, contention) {
|
|||
for (i = 0; i < THREADS; ++i) {
|
||||
munmap(stack[i], GetStackSize());
|
||||
}
|
||||
pthread_mutex_destroy(&lock);
|
||||
}
|
||||
|
||||
TEST(pthread_mutex_lock, rcontention) {
|
||||
int i;
|
||||
pthread_mutexattr_t attr;
|
||||
pthread_mutexattr_init(&attr);
|
||||
pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
|
||||
pthread_mutex_init(&lock, &attr);
|
||||
pthread_mutexattr_destroy(&attr);
|
||||
count = 0;
|
||||
for (i = 0; i < THREADS; ++i) {
|
||||
clone(MutexWorker,
|
||||
(stack[i] = mmap(0, GetStackSize(), PROT_READ | PROT_WRITE,
|
||||
MAP_STACK | MAP_ANONYMOUS, -1, 0)),
|
||||
GetStackSize(),
|
||||
CLONE_THREAD | CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_SIGHAND |
|
||||
CLONE_CHILD_SETTID | CLONE_CHILD_CLEARTID | CLONE_SETTLS,
|
||||
0, 0, __initialize_tls(tls[i]), sizeof(tls[i]),
|
||||
(int *)(tls[i] + 0x38));
|
||||
}
|
||||
for (i = 0; i < THREADS; ++i) {
|
||||
_wait0((int *)(tls[i] + 0x38));
|
||||
}
|
||||
ASSERT_EQ(THREADS * ITERATIONS, count);
|
||||
for (i = 0; i < THREADS; ++i) {
|
||||
munmap(stack[i], GetStackSize());
|
||||
}
|
||||
pthread_mutex_destroy(&lock);
|
||||
}
|
||||
|
||||
TEST(pthread_mutex_lock, econtention) {
|
||||
int i;
|
||||
pthread_mutexattr_t attr;
|
||||
pthread_mutexattr_init(&attr);
|
||||
pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_ERRORCHECK);
|
||||
pthread_mutex_init(&lock, &attr);
|
||||
pthread_mutexattr_destroy(&attr);
|
||||
count = 0;
|
||||
for (i = 0; i < THREADS; ++i) {
|
||||
clone(MutexWorker,
|
||||
(stack[i] = mmap(0, GetStackSize(), PROT_READ | PROT_WRITE,
|
||||
MAP_STACK | MAP_ANONYMOUS, -1, 0)),
|
||||
GetStackSize(),
|
||||
CLONE_THREAD | CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_SIGHAND |
|
||||
CLONE_CHILD_SETTID | CLONE_CHILD_CLEARTID | CLONE_SETTLS,
|
||||
0, 0, __initialize_tls(tls[i]), sizeof(tls[i]),
|
||||
(int *)(tls[i] + 0x38));
|
||||
}
|
||||
for (i = 0; i < THREADS; ++i) {
|
||||
_wait0((int *)(tls[i] + 0x38));
|
||||
}
|
||||
ASSERT_EQ(THREADS * ITERATIONS, count);
|
||||
for (i = 0; i < THREADS; ++i) {
|
||||
munmap(stack[i], GetStackSize());
|
||||
}
|
||||
pthread_mutex_destroy(&lock);
|
||||
}
|
||||
|
||||
int SpinlockWorker(void *p) {
|
||||
|
@ -165,14 +228,8 @@ TEST(_spinlock, contention) {
|
|||
BENCH(pthread_mutex_lock, bench) {
|
||||
char schar = 0;
|
||||
pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
|
||||
EZBENCH2("pthread_mutex_lock", donothing,
|
||||
(pthread_mutex_lock(&lock), pthread_mutex_unlock(&lock)));
|
||||
EZBENCH2("__fds_lock", donothing, (__fds_lock(), __fds_unlock()));
|
||||
EZBENCH2("_spinlock", donothing, (_spinlock(&schar), _spunlock(&schar)));
|
||||
EZBENCH2("_spinlock_tiny", donothing,
|
||||
(_spinlock_tiny(&schar), _spunlock(&schar)));
|
||||
EZBENCH2("_spinlock_coop", donothing,
|
||||
(_spinlock_cooperative(&schar), _spunlock(&schar)));
|
||||
EZBENCH2("content mut", donothing, pthread_mutex_lock_contention());
|
||||
EZBENCH2("content spin", donothing, _spinlock_contention());
|
||||
EZBENCH2("_spinlock", donothing, _spinlock_contention());
|
||||
EZBENCH2("normal", donothing, pthread_mutex_lock_contention());
|
||||
EZBENCH2("recursive", donothing, pthread_mutex_lock_rcontention());
|
||||
EZBENCH2("errorcheck", donothing, pthread_mutex_lock_econtention());
|
||||
}
|
||||
|
|
|
@ -79,6 +79,7 @@ TEST(clone, testNullFunc_raisesEinval) {
|
|||
int CloneTest1(void *arg) {
|
||||
intptr_t rsp, top, bot;
|
||||
CheckStackIsAligned();
|
||||
PrintBacktraceUsingSymbols(2, __builtin_frame_address(0), GetSymbolTable());
|
||||
rsp = (intptr_t)__builtin_frame_address(0);
|
||||
bot = (intptr_t)stack;
|
||||
top = bot + GetStackSize();
|
||||
|
|
|
@ -30,7 +30,7 @@
|
|||
#include "libc/testlib/testlib.h"
|
||||
#include "libc/x/x.h"
|
||||
|
||||
#define THREADS 16
|
||||
#define THREADS 32
|
||||
|
||||
#define DUB(i) (union Dub){i}.x
|
||||
|
||||
|
@ -61,10 +61,6 @@ int Worker(void *p) {
|
|||
}
|
||||
|
||||
TEST(dtoa, test) {
|
||||
if (IsNetbsd()) {
|
||||
// TODO(jart): Why does this flake on NetBSD?!
|
||||
return;
|
||||
}
|
||||
int i;
|
||||
for (i = 0; i < THREADS; ++i) {
|
||||
clone(Worker,
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/runtime/internal.h"
|
||||
#include "libc/stdio/stdio.h"
|
||||
#include "libc/testlib/ezbench.h"
|
||||
#include "libc/testlib/testlib.h"
|
||||
|
@ -63,11 +64,15 @@ TEST(fgetc, testUnbuffered) {
|
|||
}
|
||||
|
||||
BENCH(fputc, bench) {
|
||||
__enable_tls();
|
||||
__enable_threads();
|
||||
FILE *f;
|
||||
ASSERT_NE(NULL, (f = fopen("/dev/null", "w")));
|
||||
EZBENCH2("fputc", donothing, fputc('E', f));
|
||||
flockfile(f);
|
||||
flockfile(f);
|
||||
EZBENCH2("fputc_unlocked", donothing, fputc_unlocked('E', f));
|
||||
funlockfile(f);
|
||||
funlockfile(f);
|
||||
fclose(f);
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue