mirror of
https://github.com/jart/cosmopolitan.git
synced 2025-05-23 13:52:28 +00:00
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:
parent
c3fb624647
commit
ae638c0850
181 changed files with 2994 additions and 1367 deletions
|
@ -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));
|
||||
}
|
||||
|
|
|
@ -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"));
|
||||
}
|
||||
|
|
|
@ -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());
|
||||
}
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
|
|
75
test/libc/calls/pipe_test.c
Normal file
75
test/libc/calls/pipe_test.c
Normal 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]));
|
||||
}
|
|
@ -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));
|
||||
|
|
|
@ -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));
|
||||
|
|
|
@ -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));
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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());
|
||||
|
|
|
@ -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));
|
||||
|
|
|
@ -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));
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -30,6 +30,7 @@ TEST_LIBC_RAND_DIRECTDEPS = \
|
|||
LIBC_STR \
|
||||
LIBC_STUBS \
|
||||
LIBC_CALLS \
|
||||
LIBC_THREAD \
|
||||
LIBC_LOG \
|
||||
LIBC_SYSV \
|
||||
LIBC_TESTLIB \
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 \
|
||||
|
|
|
@ -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
71
test/libc/thread/test.mk
Normal 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)
|
|
@ -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
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue