Fix XNU / FreeBSD / OpenBSD / RHEL5 / NT bugs

For the first time ever, all tests in this codebase now pass, when
run automatically on macos, freebsd, openbsd, rhel5, rhel7, alpine
and windows via the network using the runit and runitd build tools

- Fix vfork exec path etc.
- Add XNU opendir() support
- Add OpenBSD opendir() support
- Add Linux history to syscalls.sh
- Use copy_file_range on FreeBSD 13+
- Fix system calls with 7+ arguments
- Fix Windows with greater than 16 FDs
- Fix RUNIT.COM and RUNITD.COM flakiness
- Fix OpenBSD munmap() when files are mapped
- Fix long double so it's actually long on Windows
- Fix OpenBSD truncate() and ftruncate() thunk typo
- Let Windows fcntl() be used on socket files descriptors
- Fix Windows fstat() which had an accidental printf statement
- Fix RHEL5 CLOCK_MONOTONIC by not aliasing to CLOCK_MONOTONIC_RAW

This is wonderful. I never could have dreamed it would be possible
to get it working so well on so many platforms with tiny binaries.

Fixes #31
Fixes #25
Fixes #14
This commit is contained in:
Justine Tunney 2021-01-25 13:08:05 -08:00
parent c20dad3534
commit 45b72485ad
1032 changed files with 6083 additions and 2348 deletions

View file

@ -1,102 +0,0 @@
#if 0
/*─────────────────────────────────────────────────────────────────╗
To the extent possible under law, Justine Tunney has waived
all copyright and related or neighboring rights to this file,
as it is written in the following disclaimers:
http://unlicense.org/ │
http://creativecommons.org/publicdomain/zero/1.0/ │
*/
#endif
#include "libc/calls/calls.h"
#include "libc/calls/hefty/copyfile.h"
#include "libc/calls/hefty/spawn.h"
#include "libc/calls/struct/stat.h"
#include "libc/log/check.h"
#include "libc/macros.h"
#include "libc/runtime/gc.h"
#include "libc/runtime/runtime.h"
#include "libc/stdio/stdio.h"
#include "libc/str/str.h"
#include "libc/sysv/consts/auxv.h"
#include "libc/sysv/consts/clock.h"
#include "libc/sysv/consts/fileno.h"
#include "libc/sysv/consts/madv.h"
#include "libc/sysv/consts/map.h"
#include "libc/sysv/consts/o.h"
#include "libc/sysv/consts/prot.h"
#include "libc/time/time.h"
#include "libc/x/x.h"
/**
* @fileoverview Overcommit tutorial.
* You can allocate memory like a central banker prints money.
*/
/* #define kHugeAmount (10LU * 1024LU * 1024LU * 1024LU * 1024LU) */
#define kHugeAmount (1LU * 1024LU * 1024LU * 1024LU)
int copyfile2(const char *frompath, const char *topath, bool dontoverwrite) {
struct stat st;
ssize_t transferred;
int rc, fromfd, tofd;
int64_t inoffset, outoffset;
rc = -1;
if ((fromfd = open(frompath, O_RDONLY | O_DIRECT, 0)) != -1) {
if (fstat(fromfd, &st) != -1 &&
(tofd =
open(topath,
O_WRONLY | O_CREAT | O_DIRECT | (dontoverwrite ? O_EXCL : 0),
st.st_mode & 0777)) != -1) {
inoffset = 0;
outoffset = 0;
while (st.st_size &&
(transferred = copy_file_range(fromfd, &inoffset, tofd, &outoffset,
st.st_size, 0)) != -1) {
st.st_size -= transferred;
}
if (!st.st_size) rc = 0;
rc |= close(tofd);
}
rc |= close(fromfd);
}
return rc;
}
int main(int argc, char *argv[]) {
int fd, pid;
size_t size;
long double t1, t2;
const char *core, *core2, *core3;
volatile unsigned char *mem;
size = ROUNDUP(kHugeAmount, PAGESIZE);
core = gc(xasprintf("%s.%s", getauxval(AT_EXECFN), "core"));
core2 = gc(xasprintf("%s.%s", getauxval(AT_EXECFN), "core2"));
core3 = gc(xasprintf("%s.%s", getauxval(AT_EXECFN), "core3"));
CHECK_NE(-1, (fd = open(core, O_RDWR | O_CREAT | O_TRUNC | O_CLOEXEC, 0600)));
CHECK_NE(-1, ftruncate(fd, size));
CHECK_NE(MAP_FAILED,
(mem = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0)));
strcpy(&mem[0], "hello\n\n\n\n\n\n\n\n\n\n");
strcpy(&mem[kHugeAmount / 2], "hello\n\n\n\n\n\n\n\n\n\n");
CHECK_NE(-1, munmap(mem, size));
CHECK_NE(-1,
(pid = spawnve(
0, (int[3]){STDIN_FILENO, STDOUT_FILENO, STDERR_FILENO},
"o/examples/stat.com",
(char *const[]){"o/examples/stat.com", core, NULL}, environ)));
CHECK_NE(-1, waitpid(pid, NULL, 0));
CHECK_NE(-1, close(fd));
t1 = dtime(CLOCK_REALTIME);
CHECK_NE(-1, copyfile(core, core2, 0));
t2 = dtime(CLOCK_REALTIME);
printf("%.6Lf\n", t2 - t1);
t1 = dtime(CLOCK_REALTIME);
CHECK_NE(-1, copyfile2(core, core3, false));
t2 = dtime(CLOCK_REALTIME);
printf("%.6Lf\n", t2 - t1);
/* CHECK_NE(-1, unlink(core)); */
return 0;
}

View file

@ -8,6 +8,7 @@
*/
#endif
#include "libc/bits/pushpop.h"
#include "libc/calls/calls.h"
#include "libc/calls/ucontext.h"
#include "libc/log/log.h"
#include "libc/math.h"
@ -42,48 +43,52 @@ int main(int argc, char *argv[]) {
showcrashreports();
res = 0;
asm volatile(
"mov\t$0x1111111111111111,%rax\n\t"
"mov\t$0x3333333333333333,%rcx\n\t"
"mov\t$0x4444444444444444,%rdx\n\t"
"mov\t$0x8888888888888888,%r8\n\t"
"mov\t$0x9999999999999999,%r9d\n\t"
"mov\t$0xaaaaaaaaaaaaaaaa,%r10d\n\t"
"mov\t$0xbbbbbbbbbbbbbbbb,%r11d\n\t"
"mov\t$0x0000000000000000,%rax\n\t"
"movd\t%rax,%xmm0\n\t"
"mov\t$0x1111111111111111,%rax\n\t"
"movd\t%rax,%xmm1\n\t"
"mov\t$0x2222222222222222,%rax\n\t"
"movd\t%rax,%xmm2\n\t"
"mov\t$0x3333333333333333,%rax\n\t"
"movd\t%rax,%xmm3\n\t"
"mov\t$0x4444444444444444,%rax\n\t"
"movd\t%rax,%xmm4\n\t"
"mov\t$0x5555555555555555,%rax\n\t"
"movd\t%rax,%xmm5\n\t"
"mov\t$0x6666666666666666,%rax\n\t"
"movd\t%rax,%xmm6\n\t"
"mov\t$0x7777777777777777,%rax\n\t"
"movd\t%rax,%xmm7\n\t"
"mov\t$0x8888888888888888,%rax\n\t"
"movd\t%rax,%xmm8\n\t"
"mov\t$0x9999999999999999,%rax\n\t"
"movd\t%rax,%xmm9\n\t"
"mov\t$0xaaaaaaaaaaaaaaaa,%rax\n\t"
"movd\t%rax,%xmm10\n\t"
"mov\t$0xbbbbbbbbbbbbbbbb,%rax\n\t"
"movd\t%rax,%xmm11\n\t"
"mov\t$0xcccccccccccccccc,%rax\n\t"
"movd\t%rax,%xmm12\n\t"
"mov\t$0xdddddddddddddddd,%rax\n\t"
"movd\t%rax,%xmm13\n\t"
"mov\t$0xeeeeeeeeeeeeeeee,%rax\n\t"
"movd\t%rax,%xmm14\n\t"
"mov\t$0xffffffffffffffff,%rax\n\t"
"movd\t%rax,%xmm15\n\t"
"fldlg2\n\t");
asm volatile("mov\t$0x1111111111111111,%rax\n\t"
"mov\t$0x3333333333333333,%rcx\n\t"
"mov\t$0x4444444444444444,%rdx\n\t"
"mov\t$0x8888888888888888,%r8\n\t"
"mov\t$0x9999999999999999,%r9d\n\t"
"mov\t$0xaaaaaaaaaaaaaaaa,%r10d\n\t"
"mov\t$0xbbbbbbbbbbbbbbbb,%r11d\n\t"
"mov\t$0x0000000000000000,%rax\n\t"
"movd\t%rax,%xmm0\n\t"
"mov\t$0x1111111111111111,%rax\n\t"
"push\t%rax\n\t"
"push\t%rax\n\t"
"movdqu\t(%rsp),%xmm1\n\t"
"pop\t%rax\n\t"
"pop\t%rax\n\t"
"mov\t$0x2222222222220022,%rax\n\t"
"movd\t%rax,%xmm2\n\t"
"mov\t$0x3333333333333333,%rax\n\t"
"movd\t%rax,%xmm3\n\t"
"mov\t$0x4444444444444444,%rax\n\t"
"movd\t%rax,%xmm4\n\t"
"mov\t$0x5555555555555555,%rax\n\t"
"movd\t%rax,%xmm5\n\t"
"mov\t$0x6666666666666666,%rax\n\t"
"movd\t%rax,%xmm6\n\t"
"mov\t$0x7777777777777777,%rax\n\t"
"movd\t%rax,%xmm7\n\t"
"mov\t$0x8888888888888888,%rax\n\t"
"movd\t%rax,%xmm8\n\t"
"mov\t$0x9999999999999999,%rax\n\t"
"movd\t%rax,%xmm9\n\t"
"mov\t$0xaaaaaaaaaaaaaaaa,%rax\n\t"
"movd\t%rax,%xmm10\n\t"
"mov\t$0xbbbbbbbbbbbbbbbb,%rax\n\t"
"movd\t%rax,%xmm11\n\t"
"mov\t$0xcccccccccccccccc,%rax\n\t"
"movd\t%rax,%xmm12\n\t"
"mov\t$0xdddddddddddddddd,%rax\n\t"
"movd\t%rax,%xmm13\n\t"
"mov\t$0xeeeeeeeeeeeeeeee,%rax\n\t"
"movd\t%rax,%xmm14\n\t"
"mov\t$0xffffffffffffffff,%rax\n\t"
"movd\t%rax,%xmm15\n\t"
"fldpi\n\t");
res = *(int *)(intptr_t)boo / boo;
return res;
}

29
examples/echo.c Normal file
View file

@ -0,0 +1,29 @@
#if 0
/*─────────────────────────────────────────────────────────────────╗
To the extent possible under law, Justine Tunney has waived
all copyright and related or neighboring rights to this file,
as it is written in the following disclaimers:
http://unlicense.org/ │
http://creativecommons.org/publicdomain/zero/1.0/ │
*/
#endif
#include "libc/stdio/stdio.h"
#include "libc/str/str.h"
int main(int argc, char *argv[]) {
int i, j;
bool wantnewline;
if (argc > 1 && !strcmp(argv[1], "-n")) {
i = 2;
wantnewline = false;
} else {
i = 1;
wantnewline = true;
}
for (j = 0; i + j < argc; ++j) {
if (j) fputc(' ', stdout);
fputs(argv[i + j], stdout);
}
if (wantnewline) fputc('\n', stdout);
return 0;
}

17
examples/exec.c Normal file
View file

@ -0,0 +1,17 @@
#if 0
/*─────────────────────────────────────────────────────────────────╗
To the extent possible under law, Justine Tunney has waived
all copyright and related or neighboring rights to this file,
as it is written in the following disclaimers:
http://unlicense.org/ │
http://creativecommons.org/publicdomain/zero/1.0/ │
*/
#endif
#include "libc/calls/calls.h"
#include "libc/runtime/runtime.h"
int main(int argc, char *argv[]) {
if (argc < 2) return 1;
execv(argv[1], argv + 1);
abort();
}

18
examples/fork.c Normal file
View file

@ -0,0 +1,18 @@
#if 0
/*─────────────────────────────────────────────────────────────────╗
To the extent possible under law, Justine Tunney has waived
all copyright and related or neighboring rights to this file,
as it is written in the following disclaimers:
http://unlicense.org/ │
http://creativecommons.org/publicdomain/zero/1.0/ │
*/
#endif
#include "libc/calls/calls.h"
#include "libc/stdio/stdio.h"
int main(int argc, char *argv[]) {
int pid;
pid = fork();
fprintf(stderr, "fork returned %d\n", pid);
return 0;
}

19
examples/hostname.c Normal file
View file

@ -0,0 +1,19 @@
#if 0
/*─────────────────────────────────────────────────────────────────╗
To the extent possible under law, Justine Tunney has waived
all copyright and related or neighboring rights to this file,
as it is written in the following disclaimers:
http://unlicense.org/ │
http://creativecommons.org/publicdomain/zero/1.0/ │
*/
#endif
#include "libc/calls/calls.h"
#include "libc/log/check.h"
#include "libc/stdio/stdio.h"
int main(int argc, char *argv[]) {
char hostname[254];
CHECK_NE(-1, gethostname(hostname, sizeof(hostname)));
puts(hostname);
return 0;
}

View file

@ -15,7 +15,6 @@
#include "libc/bits/bits.h"
#include "libc/bits/safemacros.h"
#include "libc/calls/calls.h"
#include "libc/calls/hefty/spawn.h"
#include "libc/calls/struct/itimerval.h"
#include "libc/calls/struct/winsize.h"
#include "libc/errno.h"
@ -148,7 +147,6 @@ struct ZipGames {
static int frame_;
static int drain_;
static int playfd_;
static int devnull_;
static int playpid_;
static bool exited_;
static bool timeout_;
@ -308,21 +306,6 @@ void GetTermSize(void) {
WriteStringNow("\e[0m\e[H\e[J");
}
bool TrySpeaker(const char* prog, char* const* args) {
int rc;
int fds[3];
fds[0] = -1;
fds[1] = devnull_;
fds[2] = devnull_;
if ((rc = spawnve(0, fds, prog, args, environ)) != -1) {
playpid_ = rc;
playfd_ = fds[0];
return true;
} else {
return false;
}
}
void IoInit(void) {
GetTermSize();
xsigaction(SIGINT, (void*)OnCtrlC, 0, 0, NULL);
@ -1700,6 +1683,8 @@ char* GetLine(void) {
int PlayGame(const char* romfile, const char* opt_tasfile) {
FILE* fp;
int devnull;
int pipefds[2];
inputfn_ = opt_tasfile;
if (!(fp = fopen(romfile, "rb"))) {
@ -1716,13 +1701,23 @@ int PlayGame(const char* romfile, const char* opt_tasfile) {
// open speaker
// todo: this needs plenty of work
devnull_ = open("/dev/null", O_WRONLY);
if ((ffplay_ = commandvenv("FFPLAY", "ffplay"))) {
const char* args[] = {
"ffplay", "-nodisp", "-loglevel", "quiet", "-fflags", "nobuffer", "-ac",
"1", "-ar", "1789773", "-f", "s16le", "pipe:", NULL,
};
TrySpeaker(ffplay_, (char* const*)args);
devnull = open("/dev/null", O_WRONLY | O_CLOEXEC);
pipe2(pipefds, O_CLOEXEC);
if (!(playpid_ = vfork())) {
const char* const args[] = {
"ffplay", "-nodisp", "-loglevel", "quiet", "-fflags",
"nobuffer", "-ac", "1", "-ar", "1789773",
"-f", "s16le", "pipe:", NULL,
};
dup2(pipefds[0], 0);
dup2(devnull, 1);
dup2(devnull, 2);
execv(ffplay_, (char* const*)args);
abort();
}
close(pipefds[0]);
playfd_ = pipefds[1];
} else {
fputs("\nWARNING\n\
\n\

View file

@ -8,7 +8,6 @@
*/
#endif
#include "libc/calls/calls.h"
#include "libc/calls/hefty/spawn.h"
#include "libc/calls/struct/rusage.h"
#include "libc/log/check.h"
#include "libc/log/log.h"
@ -23,26 +22,30 @@ void Show(const char *name, long measurement, const char *unit) {
fprintf(stderr, "%-*s%,*d %s\n", 32, name, 32, measurement, unit);
}
long TvToUs(struct timeval tv) {
return 1000000l * tv.tv_usec + tv.tv_sec;
long TvToNs(struct timeval tv) {
return tv.tv_sec * 1000000000 + tv.tv_usec * 1000;
}
int main(int argc, char *argv[]) {
const char *exe;
int pid, wstatus;
long double ts1, ts2;
struct rusage rusage;
char pathbuf[PATH_MAX];
if (argc < 2) {
fprintf(stderr, "Usage: %s PROG [ARGS...]\n", argv[0]);
return 1;
}
memset(&rusage, -1, sizeof(rusage));
CHECK_GT(argc, 1);
CHECK_NOTNULL((exe = commandv(argv[1], pathbuf)));
ts1 = nowl();
CHECK_NE(-1, (pid = spawnve(0, NULL, exe, &argv[1], environ)));
if (!(pid = vfork())) {
execvp(argv[1], argv + 1);
abort();
}
CHECK_NE(-1, wait4(pid, &wstatus, 0, &rusage));
ts2 = nowl();
Show("wall time", lroundl((ts2 - ts1) * 1e9l), "ns");
Show("user time", TvToUs(rusage.ru_utime), "µs");
Show("sys time", TvToUs(rusage.ru_stime), "µs");
Show("user time", TvToNs(rusage.ru_utime), "ns");
Show("sys time", TvToNs(rusage.ru_stime), "ns");
Show("maximum resident set size", rusage.ru_maxrss, "");
Show("integral shared memory size", rusage.ru_ixrss, "");
Show("integral unshared data size", rusage.ru_idrss, "");
@ -57,5 +60,9 @@ int main(int argc, char *argv[]) {
Show("signals received", rusage.ru_nsignals, "");
Show("voluntary context switches", rusage.ru_nvcsw, "");
Show("involuntary context switches", rusage.ru_nivcsw, "");
return WEXITSTATUS(wstatus);
if (WIFEXITED(wstatus)) {
return WEXITSTATUS(wstatus);
} else {
return 128 + WTERMSIG(wstatus);
}
}

23
examples/spawn.c Normal file
View file

@ -0,0 +1,23 @@
#if 0
/*─────────────────────────────────────────────────────────────────╗
To the extent possible under law, Justine Tunney has waived
all copyright and related or neighboring rights to this file,
as it is written in the following disclaimers:
http://unlicense.org/ │
http://creativecommons.org/publicdomain/zero/1.0/ │
*/
#endif
#include "libc/calls/calls.h"
#include "libc/runtime/runtime.h"
int main(int argc, char *argv[]) {
int pid, wstatus;
if (argc < 2) return 1;
pid = fork();
if (!pid) {
execv(argv[1], argv + 1);
abort();
}
waitpid(pid, &wstatus, 0);
return WEXITSTATUS(wstatus);
}

View file

@ -1,60 +0,0 @@
#if 0
/*─────────────────────────────────────────────────────────────────╗
To the extent possible under law, Justine Tunney has waived
all copyright and related or neighboring rights to this file,
as it is written in the following disclaimers:
http://unlicense.org/ │
http://creativecommons.org/publicdomain/zero/1.0/ │
*/
#endif
#include "libc/alg/alg.h"
#include "libc/calls/calls.h"
#include "libc/calls/hefty/spawn.h"
#include "libc/fmt/conv.h"
#include "libc/limits.h"
#include "libc/log/check.h"
#include "libc/runtime/gc.h"
#include "libc/stdio/stdio.h"
#include "libc/sysv/consts/fileno.h"
#include "libc/x/x.h"
const char kProgram[] = "o/default/examples/hello.com";
int main(int argc, char *argv[]) {
/**
* Runs make if hello.com doesn't exist.
*
* 1. gc() automates calling free() on return.
* 2. xasprintf("foo %s", "bar") is our version of "foo %s" % ("bar")
* 3. Demonstrates correct escaping for bourne shell
*/
if (!fileexists(kProgram)) {
system(gc(xasprintf("%s '%s'", "make -j4",
gc(replacestr(kProgram, "'", "'\"'\"'")))));
}
/**
* Our version of subprocess.Popen
* 1. Doesn't require fork() so pain-free on NT
* 2. Google checks are like assert() but better
*/
ssize_t transferred;
int child, wstatus, procfds[3] = {STDIN_FILENO, -1, STDERR_FILENO};
CHECK_NE(-1,
(child = spawnve(0, procfds, /* run w/o shell */ kProgram,
(char *const[]){/* argv[0] */ basename(kProgram),
/* argv[1] */ "boop",
/* sentinel */ NULL},
environ)));
printf("%s %s: ", kProgram, "says");
fflush(stdout);
for (;;) {
transferred = copyfd(procfds[1], NULL, fileno(stdout), NULL, INT_MAX, 0);
CHECK_NE(-1, transferred);
if (!transferred) break;
}
CHECK_NE(-1, waitpid(child, &wstatus, 0));
CHECK_EQ(0, WEXITSTATUS(wstatus));
return 0;
}

15
examples/system.c Normal file
View file

@ -0,0 +1,15 @@
#if 0
/*─────────────────────────────────────────────────────────────────╗
To the extent possible under law, Justine Tunney has waived
all copyright and related or neighboring rights to this file,
as it is written in the following disclaimers:
http://unlicense.org/ │
http://creativecommons.org/publicdomain/zero/1.0/ │
*/
#endif
#include "libc/stdio/stdio.h"
int main(int argc, char *argv[]) {
system("notepad");
return 0;
}