Fix bugs and make improvements

- Get clone() working on FreeBSD
- Increase some Python build quotas
- Add more atomic builtins to chibicc
- Fix ASAN poisoning of alloca() memory
- Make MODE= mandatory link path tinier
- Improve the examples folder a little bit
- Start working on some more resource limits
- Make the linenoise auto-complete UI as good as GNU readline
- Update compile.com, avoiding AVX codegen on non-AVX systems
- Make sure empty path to syscalls like opendir raises ENOENT
- Correctly polyfill ENOENT vs. ENOTDIR on the New Technology
- Port bestline's paredit features to //third_party/linenoise
- Remove workarounds for RHEL 5.0 bugs that were fixed in 5.1
This commit is contained in:
Justine Tunney 2022-04-20 09:56:53 -07:00
parent c3fb624647
commit ae638c0850
181 changed files with 2994 additions and 1367 deletions

View file

@ -36,6 +36,7 @@ TEST(access, efault) {
}
TEST(access, enoent) {
ASSERT_SYS(ENOENT, -1, access("", F_OK));
ASSERT_SYS(ENOENT, -1, access("doesnotexist", F_OK));
ASSERT_SYS(ENOENT, -1, access("o/doesnotexist", F_OK));
}

View file

@ -30,6 +30,7 @@ TEST(chdir, efault) {
}
TEST(chdir, enoent) {
ASSERT_SYS(ENOENT, -1, chdir(""));
ASSERT_SYS(ENOENT, -1, chdir("doesnotexist"));
ASSERT_SYS(ENOENT, -1, chdir("o/doesnotexist"));
}

View file

@ -22,6 +22,7 @@
#include "libc/sysv/consts/map.h"
#include "libc/sysv/consts/msync.h"
#include "libc/sysv/consts/prot.h"
#include "libc/testlib/ezbench.h"
#include "libc/testlib/testlib.h"
TEST(fork, testPipes) {
@ -77,3 +78,16 @@ TEST(fork, testSharedMemory) {
EXPECT_NE(-1, munmap(sharedvar, FRAMESIZE));
EXPECT_NE(-1, munmap(privatevar, FRAMESIZE));
}
void ForkInSerial(void) {
int pid, ws;
ASSERT_NE(-1, (pid = fork()));
if (!pid) _Exit(0);
ASSERT_NE(-1, waitpid(pid, &ws, 0));
ASSERT_TRUE(WIFEXITED(ws));
ASSERT_EQ(0, WEXITSTATUS(ws));
}
BENCH(fork, bench) {
EZBENCH2("fork", donothing, ForkInSerial());
}

View file

@ -31,6 +31,7 @@ TEST(open, efault) {
}
TEST(open, enoent) {
ASSERT_SYS(ENOENT, -1, open("", O_RDONLY));
ASSERT_SYS(ENOENT, -1, open("doesnotexist", O_RDONLY));
ASSERT_SYS(ENOENT, -1, open("o/doesnotexist", O_RDONLY));
}

View file

@ -0,0 +1,75 @@
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi
Copyright 2022 Justine Alexandra Roberts Tunney
Permission to use, copy, modify, and/or distribute this software for
any purpose with or without fee is hereby granted, provided that the
above copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/calls/calls.h"
#include "libc/dce.h"
#include "libc/errno.h"
#include "libc/sysv/consts/rlimit.h"
#include "libc/testlib/testlib.h"
int ws, pid, f[2];
char buf[6] = {0};
struct rlimit rlim = {0, 10};
TEST(pipe, efault) {
EXPECT_SYS(EFAULT, -1, pipe(0));
}
TEST(pipe, einval) {
EXPECT_SYS(EINVAL, -1, pipe2(f, -1));
}
TEST(pipe, ebadf) {
if (IsFreebsd()) return; // somehow succeeds
if (IsOpenbsd()) return; // somehow succeeds
EXPECT_SYS(0, 0, pipe(f));
EXPECT_SYS(EBADF, -1, write(f[0], "h", 1));
EXPECT_SYS(EBADF, -1, read(f[1], buf, 1));
EXPECT_SYS(0, 0, close(f[0]));
EXPECT_SYS(0, 0, close(f[1]));
}
TEST(pipe, emfile) {
if (IsWindows()) return; // TODO
ASSERT_NE(-1, (pid = fork()));
if (!pid) {
ASSERT_EQ(0, setrlimit(RLIMIT_NOFILE, &rlim));
ASSERT_SYS(EMFILE, -1, pipe(f));
_exit(0);
}
EXPECT_NE(-1, waitpid(pid, &ws, 0));
EXPECT_TRUE(WIFEXITED(ws));
EXPECT_EQ(0, WEXITSTATUS(ws));
}
TEST(pipe, usesLowestFileNumbers) {
EXPECT_SYS(0, 0, pipe(f));
EXPECT_SYS(0, 3, f[0]);
EXPECT_SYS(0, 4, f[1]);
EXPECT_SYS(0, 0, close(f[0]));
EXPECT_SYS(0, 0, close(f[1]));
}
TEST(pipe, doesBuffering) {
EXPECT_SYS(0, 0, pipe(f));
EXPECT_SYS(0, 5, write(f[1], "hello", 5));
EXPECT_SYS(0, 5, read(f[0], buf, 5));
EXPECT_STREQ("hello", buf);
EXPECT_SYS(0, 0, close(f[0]));
EXPECT_SYS(0, 0, close(f[1]));
}

View file

@ -52,6 +52,7 @@ TEST(readansi, test) {
EXPECT_STREQ("\xc2\x9bM", b);
EXPECT_EQ(0, readansi(fds[0], b, sizeof(b)));
EXPECT_STREQ("", b);
close(fds[0]);
ASSERT_NE(-1, wait(&ws));
ASSERT_TRUE(WIFEXITED(ws));
ASSERT_EQ(0, WEXITSTATUS(ws));
@ -73,6 +74,7 @@ TEST(readansi, testOperatingSystemCommand) {
EXPECT_STREQ(s, b);
EXPECT_EQ(0, readansi(fds[0], b, sizeof(b)));
EXPECT_STREQ("", b);
close(fds[0]);
ASSERT_NE(-1, wait(&ws));
ASSERT_TRUE(WIFEXITED(ws));
ASSERT_EQ(0, WEXITSTATUS(ws));

View file

@ -31,6 +31,18 @@
char testlib_enable_tmp_setup_teardown;
TEST(readlink, enoent) {
char buf[32];
ASSERT_SYS(ENOENT, -1, readlink("doesnotexist", buf, 32));
ASSERT_SYS(ENOENT, -1, readlink("o/doesnotexist", buf, 32));
}
TEST(readlink, enotdir) {
char buf[32];
ASSERT_SYS(0, 0, touch("o", 0644));
ASSERT_SYS(ENOTDIR, -1, readlink("o/doesnotexist", buf, 32));
}
TEST(readlinkat, test) {
char buf[128], *p, *q;
memset(buf, -1, sizeof(buf));

View file

@ -24,6 +24,20 @@
char testlib_enable_tmp_setup_teardown;
TEST(rename, enoent) {
EXPECT_SYS(ENOENT, -1, rename("foo", ""));
EXPECT_SYS(ENOENT, -1, rename("", "foo"));
EXPECT_SYS(ENOENT, -1, rename("foo", "o/bar"));
EXPECT_SYS(ENOENT, -1, rename("o/bar", "foo"));
}
TEST(renameat, enotdir) {
EXPECT_SYS(0, 0, close(creat("yo", 0644)));
EXPECT_SYS(ENOTDIR, -1, rename("yo/there", "hrcue"));
// this test makes platforms crazy
// EXPECT_SYS(ENOTDIR, -1, rename("zoo", "yo/there"));
}
TEST(renameat, testNull_returnsEfault) {
ASSERT_SYS(0, 0, close(creat("hello", 0644)));
EXPECT_SYS(EFAULT, -1, renameat(AT_FDCWD, 0, AT_FDCWD, 0));

View file

@ -43,6 +43,7 @@ TEST(stat_010, testEmptyFile_sizeIsZero) {
TEST(stat, enoent) {
ASSERT_SYS(ENOENT, -1, stat("hi", 0));
ASSERT_SYS(ENOENT, -1, stat("o/doesnotexist", 0));
}
TEST(stat, enotdir) {

View file

@ -29,6 +29,16 @@ char testlib_enable_tmp_setup_teardown;
char p[2][PATH_MAX];
struct stat st;
TEST(symlink, enoent) {
ASSERT_SYS(ENOENT, -1, symlink("o/foo", ""));
ASSERT_SYS(ENOENT, -1, symlink("o/foo", "o/bar"));
}
TEST(symlinkat, enotdir) {
ASSERT_SYS(0, 0, close(creat("yo", 0644)));
ASSERT_SYS(ENOTDIR, -1, symlink("hrcue", "yo/there"));
}
TEST(symlinkat, test) {
sprintf(p[0], "%s.%d", program_invocation_short_name, rand());
sprintf(p[1], "%s.%d", program_invocation_short_name, rand());

View file

@ -17,11 +17,29 @@
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/calls/calls.h"
#include "libc/dce.h"
#include "libc/sysv/consts/at.h"
#include "libc/testlib/testlib.h"
char testlib_enable_tmp_setup_teardown;
TEST(unlink, efault) {
ASSERT_SYS(EFAULT, -1, unlink(0));
if (IsWindows() && !IsAsan()) return; // not possible
ASSERT_SYS(EFAULT, -1, unlink((void *)77));
}
TEST(unlink, enoent) {
ASSERT_SYS(ENOENT, -1, unlink(""));
ASSERT_SYS(ENOENT, -1, unlink("doesnotexist"));
ASSERT_SYS(ENOENT, -1, unlink("o/doesnotexist"));
}
TEST(unlink, enotdir) {
ASSERT_SYS(0, 0, touch("o", 0644));
ASSERT_SYS(ENOTDIR, -1, unlink("o/doesnotexist"));
}
TEST(unlinkat, test) {
int i, fd;
EXPECT_EQ(0, touch("mytmp", 0644));

View file

@ -196,6 +196,7 @@ TEST(ShowCrashReports, testMemoryLeakCrash) {
break;
}
}
close(fds[0]);
ASSERT_NE(-1, wait(&ws));
EXPECT_TRUE(WIFEXITED(ws));
EXPECT_EQ(78, WEXITSTATUS(ws));
@ -273,6 +274,7 @@ TEST(ShowCrashReports, testStackOverrunCrash) {
break;
}
}
close(fds[0]);
ASSERT_NE(-1, wait(&ws));
EXPECT_TRUE(WIFEXITED(ws));
EXPECT_EQ(77, WEXITSTATUS(ws));
@ -381,6 +383,7 @@ TEST(ShowCrashReports, testDivideByZero) {
break;
}
}
close(fds[0]);
ASSERT_NE(-1, wait(&ws));
EXPECT_TRUE(WIFEXITED(ws));
assert(128 + SIGFPE == WEXITSTATUS(ws) || 77 == WEXITSTATUS(ws));
@ -502,6 +505,7 @@ TEST(ShowCrashReports, testBssOverrunCrash) {
break;
}
}
close(fds[0]);
ASSERT_NE(-1, wait(&ws));
EXPECT_TRUE(WIFEXITED(ws));
EXPECT_EQ(77, WEXITSTATUS(ws));
@ -580,6 +584,7 @@ TEST(ShowCrashReports, testNpeCrash) {
break;
}
}
close(fds[0]);
ASSERT_NE(-1, wait(&ws));
EXPECT_TRUE(WIFEXITED(ws));
EXPECT_EQ(77, WEXITSTATUS(ws));
@ -639,6 +644,7 @@ TEST(ShowCrashReports, testDataOverrunCrash) {
break;
}
}
close(fds[0]);
ASSERT_NE(-1, wait(&ws));
EXPECT_TRUE(WIFEXITED(ws));
EXPECT_EQ(77, WEXITSTATUS(ws));
@ -693,6 +699,7 @@ TEST(ShowCrashReports, testNpeCrashAfterFinalize) {
break;
}
}
close(fds[0]);
ASSERT_NE(-1, wait(&ws));
EXPECT_TRUE(WIFEXITED(ws));
EXPECT_EQ(IsAsan() ? 77 : 128 + SIGSEGV, WEXITSTATUS(ws));

View file

@ -22,8 +22,10 @@
#include "libc/calls/struct/sigset.h"
#include "libc/dce.h"
#include "libc/errno.h"
#include "libc/intrin/spinlock.h"
#include "libc/macros.internal.h"
#include "libc/rand/rand.h"
#include "libc/runtime/stack.h"
#include "libc/str/str.h"
#include "libc/sysv/consts/clone.h"
#include "libc/sysv/consts/sa.h"
@ -33,6 +35,7 @@
#define THREADS 8
#define ENTRIES 256
char locks[THREADS];
volatile bool ready;
volatile uint64_t A[THREADS * ENTRIES];
@ -48,6 +51,7 @@ int Thrasher(void *arg) {
for (i = 0; i < ENTRIES; ++i) {
A[id * ENTRIES + i] = rand64();
}
_spunlock(locks + id);
return 0;
}
@ -69,8 +73,10 @@ TEST(rand64, testLcg_doesntProduceIdenticalValues) {
TEST(rand64, testThreadSafety_doesntProduceIdenticalValues) {
char *stack;
sigset_t ss, oldss;
int i, j, rc, ws, tid[THREADS], ptid[THREADS], ctid[THREADS], tls[THREADS];
if (!IsLinux() && !IsNetbsd()) return;
int i, j, rc, ws, tid[THREADS];
if (IsXnu()) return;
if (IsNetbsd()) return; // still flaky :'(
if (IsOpenbsd()) return; // still flaky :'(
struct sigaction oldsa;
struct sigaction sa = {.sa_handler = OnChld, .sa_flags = SA_RESTART};
EXPECT_NE(-1, sigaction(SIGCHLD, &sa, &oldsa));
@ -78,22 +84,23 @@ TEST(rand64, testThreadSafety_doesntProduceIdenticalValues) {
sigemptyset(&ss);
sigaddset(&ss, SIGCHLD);
EXPECT_EQ(0, sigprocmask(SIG_BLOCK, &ss, &oldss));
for (i = 0; i < THREADS; ++i) {
locks[i] = 1;
}
ready = false;
for (i = 0; i < THREADS; ++i) {
stack = gc(malloc(FRAMESIZE));
tid[i] = clone(Thrasher, stack + FRAMESIZE,
CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_SIGHAND | SIGCHLD,
(void *)(intptr_t)i, ptid + i, tls + i, ctid + i);
EXPECT_NE(-1, tid[i]);
stack = gc(malloc(GetStackSize()));
tid[i] = clone(Thrasher, stack, GetStackSize(),
CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_SIGHAND,
(void *)(intptr_t)i, 0, 0, 0, 0);
ASSERT_NE(-1, tid[i]);
}
ready = true;
for (i = 0; i < THREADS; ++i) {
EXPECT_NE(-1, (rc = waitpid(0, &ws, 0)));
EXPECT_TRUE(WIFEXITED(ws));
EXPECT_EQ(0, WEXITSTATUS(ws));
_spinlock(locks + i);
}
EXPECT_EQ(0, sigaction(SIGCHLD, &oldsa, 0));
EXPECT_EQ(0, sigprocmask(SIG_BLOCK, &oldss, 0));
sigaction(SIGCHLD, &oldsa, 0);
sigprocmask(SIG_BLOCK, &oldss, 0);
for (i = 0; i < ARRAYLEN(A); ++i) {
EXPECT_NE(0, A[i], "i=%d", i);
for (j = 0; j < ARRAYLEN(A); ++j) {

View file

@ -30,6 +30,7 @@ TEST_LIBC_RAND_DIRECTDEPS = \
LIBC_STR \
LIBC_STUBS \
LIBC_CALLS \
LIBC_THREAD \
LIBC_LOG \
LIBC_SYSV \
LIBC_TESTLIB \

View file

@ -196,6 +196,7 @@ TEST(mmap, cowFileMapReadonlyFork) {
}
EXPECT_STREQN("hello", p, 5);
EXPECT_NE(-1, munmap(p, 6));
EXPECT_NE(-1, close(fd));
EXPECT_NE(-1, unlink(path));
}

View file

@ -18,11 +18,13 @@
*/
#include "libc/calls/calls.h"
#include "libc/calls/struct/dirent.h"
#include "libc/dce.h"
#include "libc/errno.h"
#include "libc/rand/rand.h"
#include "libc/runtime/gc.internal.h"
#include "libc/runtime/runtime.h"
#include "libc/str/str.h"
#include "libc/sysv/consts/dt.h"
#include "libc/testlib/testlib.h"
#include "libc/x/x.h"
@ -31,6 +33,44 @@ STATIC_YOINK("usr/share/zoneinfo/New_York");
char testlib_enable_tmp_setup_teardown;
TEST(opendir, efault) {
ASSERT_SYS(EFAULT, NULL, opendir(0));
if (!IsAsan()) return; // not possible
ASSERT_SYS(EFAULT, NULL, opendir((void *)77));
}
TEST(opendir, enoent) {
ASSERT_SYS(ENOENT, NULL, opendir(""));
ASSERT_SYS(ENOENT, NULL, opendir("o/foo"));
}
TEST(opendir, enotdir) {
ASSERT_SYS(0, 0, close(creat("yo", 0644)));
ASSERT_SYS(ENOTDIR, NULL, opendir("yo/there"));
}
TEST(dirstream, testDots) {
DIR *dir;
int hasdot = 0;
int hasdotdot = 0;
struct dirent *ent;
ASSERT_SYS(0, 0, close(creat("foo", 0644)));
ASSERT_NE(NULL, (dir = opendir(".")));
while ((ent = readdir(dir))) {
if (!strcmp(ent->d_name, ".")) {
++hasdot;
EXPECT_EQ(DT_DIR, ent->d_type);
}
if (!strcmp(ent->d_name, "..")) {
++hasdotdot;
EXPECT_EQ(DT_DIR, ent->d_type);
}
}
EXPECT_EQ(1, hasdot);
EXPECT_EQ(1, hasdotdot);
EXPECT_SYS(0, 0, closedir(dir));
}
TEST(dirstream, test) {
DIR *dir;
struct dirent *ent;
@ -45,8 +85,14 @@ TEST(dirstream, test) {
EXPECT_NE(-1, touch(file2, 0644));
EXPECT_TRUE(NULL != (dir = opendir(dpath)));
while ((ent = readdir(dir))) {
if (strcmp(ent->d_name, "foo")) hasfoo = true;
if (strcmp(ent->d_name, "bar")) hasbar = true;
if (!strcmp(ent->d_name, "foo")) {
EXPECT_EQ(DT_REG, ent->d_type);
hasfoo = true;
}
if (!strcmp(ent->d_name, "bar")) {
EXPECT_EQ(DT_REG, ent->d_type);
hasbar = true;
}
}
EXPECT_TRUE(hasfoo);
EXPECT_TRUE(hasbar);

View file

@ -19,6 +19,7 @@
#include "libc/calls/calls.h"
#include "libc/calls/struct/stat.h"
#include "libc/errno.h"
#include "libc/intrin/kprintf.h"
#include "libc/log/check.h"
#include "libc/macros.internal.h"
#include "libc/mem/mem.h"
@ -38,6 +39,7 @@
#include "libc/testlib/testlib.h"
#include "libc/x/x.h"
#include "libc/zip.h"
#include "libc/zipos/zipos.internal.h"
#include "third_party/zlib/zlib.h"
STATIC_YOINK("zip_uri_support");
@ -89,7 +91,7 @@ TEST(undeflate, testEmbeddedCompressedZipFile_theHardWay) {
ASSERT_NE(-1, fstat(fd, &st));
ASSERT_NE(MAP_FAILED,
(map = mmap(NULL, st.st_size, PROT_READ, MAP_SHARED, fd, 0)));
ASSERT_NE(NULL, (cd = zipfindcentraldir(map, st.st_size)));
ASSERT_NE(NULL, (cd = GetZipCdir(map, st.st_size)));
ASSERT_GE(ZIP_CDIR_RECORDS(cd), 1);
for (i = 0, cf = map + ZIP_CDIR_OFFSET(cd); i < ZIP_CDIR_RECORDS(cd);
++i, cf += ZIP_CFILE_HDRSIZE(cf)) {
@ -113,8 +115,6 @@ TEST(undeflate, testEmbeddedCompressedZipFile_theHardWay) {
ASSERT_TRUE(found);
}
#if 0 /* todo: don't rely on __zip_end */
uint8_t *buf_;
size_t bufsize_;
uint8_t *data_;
@ -141,29 +141,20 @@ void Undeflate(void) {
undeflate(buf_, uncompressedsize_, data_, compressedsize_, &ds_);
}
static size_t GetLocalFile(const char *name) {
size_t i, cf, namesize;
namesize = strlen(name);
for (i = 0, cf = ZIP_CDIR_OFFSET(__zip_end); i < ZIP_CDIR_RECORDS(__zip_end);
++i, cf += ZIP_CFILE_HDRSIZE(cf)) {
if (namesize == ZIP_CFILE_NAMESIZE(&_base[0] + cf) &&
memcmp(name, ZIP_CFILE_NAME(&_base[0] + cf), namesize) == 0) {
return ZIP_CFILE_OFFSET(&_base[0] + cf);
}
}
abort();
}
BENCH(undeflate, bench) {
size_t lf;
lf = GetLocalFile("libc/testlib/hyperion.txt");
data_ = ZIP_LFILE_CONTENT(&_base[0] + lf);
compressedsize_ = ZIP_LFILE_COMPRESSEDSIZE(&_base[0] + lf);
uncompressedsize_ = ZIP_LFILE_UNCOMPRESSEDSIZE(&_base[0] + lf);
size_t cf, lf;
struct Zipos *zipos;
struct ZiposUri path;
zipos = __zipos_get();
path.path = "libc/testlib/hyperion.txt";
path.len = strlen(path.path);
cf = __zipos_find(zipos, &path);
lf = GetZipCfileOffset(zipos->map + cf);
data_ = ZIP_LFILE_CONTENT(zipos->map + lf);
compressedsize_ = ZIP_LFILE_COMPRESSEDSIZE(zipos->map + lf);
uncompressedsize_ = ZIP_LFILE_UNCOMPRESSEDSIZE(zipos->map + lf);
bufsize_ = ROUNDUP(uncompressedsize_, FRAMESIZE / 2);
buf_ = gc(malloc(bufsize_));
EZBENCH(donothing, Inflate());
EZBENCH(donothing, Undeflate());
}
#endif

View file

@ -18,6 +18,7 @@ o/$(MODE)/test/libc: \
o/$(MODE)/test/libc/sock \
o/$(MODE)/test/libc/stdio \
o/$(MODE)/test/libc/str \
o/$(MODE)/test/libc/thread \
o/$(MODE)/test/libc/time \
o/$(MODE)/test/libc/tinymath \
o/$(MODE)/test/libc/unicode \

View file

@ -16,35 +16,42 @@
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/assert.h"
#include "libc/calls/calls.h"
#include "libc/dce.h"
#include "libc/log/backtrace.internal.h"
#include "libc/mem/mem.h"
#include "libc/runtime/gc.internal.h"
#include "libc/runtime/symbols.internal.h"
#include "libc/intrin/spinlock.h"
#include "libc/sysv/consts/clone.h"
#include "libc/testlib/testlib.h"
#include "libc/time/time.h"
volatile int x;
int x, thechilde;
_Alignas(64) volatile char lock;
void SetUp(void) {
x = 0;
lock = 0;
thechilde = 0;
}
int thread(void *arg) {
return (x = 42);
x = 42;
ASSERT_EQ(23, (intptr_t)arg);
thechilde = gettid();
_spunlock(&lock);
return 0;
}
TEST(clone, test) {
if (!IsLinux() && !IsNetbsd() && !IsWindows()) return;
if (IsXnu()) return;
if (IsOpenbsd()) return; // still flaky :'(
int me, tid;
char *stack;
long double t;
int tid, ptid, ctid, tls;
t = nowl();
stack = gc(malloc(FRAMESIZE));
EXPECT_NE(-1, (tid = clone(thread, stack + FRAMESIZE,
me = gettid();
_spinlock(&lock);
stack = _gc(valloc(STACKSIZE));
ASSERT_NE(-1, (tid = clone(thread, stack, STACKSIZE,
CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_SIGHAND,
0, &ptid, &tls, &ctid)));
while ((nowl() - t) < 1 && !x) {
__builtin_ia32_pause();
}
(void *)23, 0, 0, 0, 0)));
_spinlock(&lock);
ASSERT_EQ(42, x);
ASSERT_NE(me, tid);
ASSERT_EQ(tid, thechilde);
}

71
test/libc/thread/test.mk Normal file
View file

@ -0,0 +1,71 @@
#-*-mode:makefile-gmake;indent-tabs-mode:t;tab-width:8;coding:utf-8-*-┐
#───vi: set et ft=make ts=8 tw=8 fenc=utf-8 :vi───────────────────────┘
PKGS += TEST_LIBC_THREAD
TEST_LIBC_THREAD_SRCS := $(wildcard test/libc/thread/*.c)
TEST_LIBC_THREAD_SRCS_TEST = $(filter %_test.c,$(TEST_LIBC_THREAD_SRCS))
TEST_LIBC_THREAD_OBJS = \
$(TEST_LIBC_THREAD_SRCS:%.c=o/$(MODE)/%.o)
TEST_LIBC_THREAD_COMS = \
$(TEST_LIBC_THREAD_SRCS:%.c=o/$(MODE)/%.com)
TEST_LIBC_THREAD_BINS = \
$(TEST_LIBC_THREAD_COMS) \
$(TEST_LIBC_THREAD_COMS:%=%.dbg)
TEST_LIBC_THREAD_TESTS = \
$(TEST_LIBC_THREAD_SRCS_TEST:%.c=o/$(MODE)/%.com.ok)
TEST_LIBC_THREAD_CHECKS = \
$(TEST_LIBC_THREAD_SRCS_TEST:%.c=o/$(MODE)/%.com.runs)
TEST_LIBC_THREAD_DIRECTDEPS = \
LIBC_CALLS \
LIBC_FMT \
LIBC_INTRIN \
LIBC_MEM \
LIBC_NEXGEN32E \
LIBC_RUNTIME \
LIBC_STR \
LIBC_STUBS \
LIBC_SYSV \
LIBC_THREAD \
LIBC_TESTLIB
TEST_LIBC_THREAD_DEPS := \
$(call uniq,$(foreach x,$(TEST_LIBC_THREAD_DIRECTDEPS),$($(x))))
o/$(MODE)/test/libc/thread/thread.pkg: \
$(TEST_LIBC_THREAD_OBJS) \
$(foreach x,$(TEST_LIBC_THREAD_DIRECTDEPS),$($(x)_A).pkg)
o/$(MODE)/test/libc/thread/%.com.dbg: \
$(TEST_LIBC_THREAD_DEPS) \
o/$(MODE)/test/libc/thread/%.o \
o/$(MODE)/test/libc/thread/thread.pkg \
$(LIBC_TESTMAIN) \
$(CRT) \
$(APE)
@$(APELINK)
$(TEST_LIBC_THREAD_OBJS): \
DEFAULT_CCFLAGS += \
-fno-builtin
o/$(MODE)/test/libc/thread/getenv_test.com.runs: \
o/$(MODE)/test/libc/thread/getenv_test.com
@HELLO=THERE build/runit $@ $<
o/$(MODE)/test/libc/thread/fun_test.o \
o/$(MODE)/test/libc/thread/itsatrap_test.o: \
OVERRIDE_CFLAGS += \
-fno-sanitize=all \
-ftrapv
.PHONY: o/$(MODE)/test/libc/thread
o/$(MODE)/test/libc/thread: \
$(TEST_LIBC_THREAD_BINS) \
$(TEST_LIBC_THREAD_CHECKS)

View file

@ -26,6 +26,9 @@
#include "libc/testlib/testlib.h"
#include "libc/x/x.h"
// TODO: This test flakes occasionally on Windows.
#if 0
#define N (72 * 1024)
char p[N];
@ -59,3 +62,5 @@ BENCH(filecmp, bench) {
EXPECT_EQ(0, xbarf("b", p, N));
EZBENCH2("filecmp", donothing, filecmp("a", "b"));
}
#endif