mirror of
https://github.com/jart/cosmopolitan.git
synced 2025-05-27 15:52:28 +00:00
Make fixes and improvements
- Document more compiler flags - Expose new __print_maps() api - Better overflow checking in mmap() - Improve the shell example somewhat - Fix minor runtime bugs regarding stacks - Make kill() on fork()+execve()'d children work - Support CLONE_CHILD_CLEARTID for proper joining - Fix recent possible deadlock regression with --ftrace
This commit is contained in:
parent
6e52cba37a
commit
ec2cb88058
68 changed files with 1211 additions and 431 deletions
|
@ -9,6 +9,7 @@
|
|||
#endif
|
||||
#include "libc/assert.h"
|
||||
#include "libc/errno.h"
|
||||
#include "libc/fmt/conv.h"
|
||||
#include "libc/log/check.h"
|
||||
#include "libc/mem/mem.h"
|
||||
#include "libc/runtime/gc.internal.h"
|
||||
|
@ -16,13 +17,36 @@
|
|||
#include "libc/str/str.h"
|
||||
#include "third_party/zlib/zlib.h"
|
||||
|
||||
#define CHUNK 4096
|
||||
#define CHUNK 32768
|
||||
|
||||
// clang-format off
|
||||
// make -j8 o//examples && dd if=/dev/urandom count=100 | tee a | o//examples/compress.com | o//examples/decompress.com >b && sha1sum a b
|
||||
/*
|
||||
# data file is o/dbg/third_party/python/python.com
|
||||
# level 0 147517 compress 495 MB/s decompress 1.4 GB/s
|
||||
# level 1 80274 compress 29.2 MB/s decompress 303 MB/s
|
||||
# level 2 79384 compress 33.8 MB/s decompress 212 MB/s
|
||||
# level 3 78875 compress 28.9 MB/s decompress 224 MB/s
|
||||
# level 4 78010 compress 27.1 MB/s decompress 319 MB/s <-- sweet spot?
|
||||
# level 5 77107 compress 19.5 MB/s decompress 273 MB/s
|
||||
# level 6 75081 compress 10.0 MB/s decompress 99.3 MB/s
|
||||
# level 7 75022 compress 7.5 MB/s decompress 287 MB/s
|
||||
# level 8 75016 compress 5.4 MB/s decompress 109 MB/s
|
||||
# level 9 75016 compress 5.4 MB/s decompress 344 MB/s
|
||||
m=
|
||||
make -j8 MODE=$m o/$m/examples || exit
|
||||
for level in $(seq 0 9); do
|
||||
o/$m/examples/compress.com $level <o/dbg/third_party/python/python.com | dd count=10000 2>/tmp/info >/tmp/comp
|
||||
compspeed=$(grep -Po '[.\d]+ \w+/s' /tmp/info)
|
||||
o/$m/examples/decompress.com $level </tmp/comp | dd count=10000 2>/tmp/info >/dev/null
|
||||
decompspeed=$(grep -Po '[.\d]+ \w+/s' /tmp/info)
|
||||
size=$(o/$m/examples/compress.com $level <o/$m/examples/compress.com | wc -c)
|
||||
echo "level $level $size compress $compspeed decompress $decompspeed"
|
||||
done
|
||||
*/
|
||||
// clang-format on
|
||||
|
||||
int compressor(int infd, int outfd) {
|
||||
int compressor(int infd, int outfd, int level) {
|
||||
z_stream zs;
|
||||
int rc, flush;
|
||||
unsigned have;
|
||||
|
@ -33,8 +57,8 @@ int compressor(int infd, int outfd) {
|
|||
zs.zalloc = 0;
|
||||
zs.zfree = 0;
|
||||
zs.opaque = 0;
|
||||
rc = deflateInit2(&zs, Z_DEFAULT_COMPRESSION, Z_DEFLATED, MAX_WBITS,
|
||||
DEF_MEM_LEVEL, Z_DEFAULT_STRATEGY);
|
||||
rc = deflateInit2(&zs, level, Z_DEFLATED, MAX_WBITS, DEF_MEM_LEVEL,
|
||||
Z_DEFAULT_STRATEGY);
|
||||
if (rc != Z_OK) return rc;
|
||||
do {
|
||||
rc = read(infd, inbuf, CHUNK);
|
||||
|
@ -81,8 +105,13 @@ const char *zerr(int rc) {
|
|||
}
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
int rc;
|
||||
rc = compressor(0, 1);
|
||||
int rc, level;
|
||||
if (argc > 1) {
|
||||
level = atoi(argv[1]);
|
||||
} else {
|
||||
level = Z_DEFAULT_COMPRESSION;
|
||||
}
|
||||
rc = compressor(0, 1, level);
|
||||
if (rc == Z_OK) {
|
||||
return 0;
|
||||
} else {
|
||||
|
|
|
@ -14,10 +14,33 @@
|
|||
#include "libc/stdio/stdio.h"
|
||||
#include "third_party/zlib/zlib.h"
|
||||
|
||||
#define CHUNK 4096
|
||||
#define CHUNK 32768
|
||||
|
||||
// clang-format off
|
||||
// make -j8 o//examples && dd if=/dev/urandom count=100 | tee a | o//examples/compress.com | o//examples/decompress.com >b && sha1sum a b
|
||||
/*
|
||||
# data file is o/dbg/third_party/python/python.com
|
||||
# level 0 147517 compress 495 MB/s decompress 1.4 GB/s
|
||||
# level 1 80274 compress 29.2 MB/s decompress 303 MB/s
|
||||
# level 2 79384 compress 33.8 MB/s decompress 212 MB/s
|
||||
# level 3 78875 compress 28.9 MB/s decompress 224 MB/s
|
||||
# level 4 78010 compress 27.1 MB/s decompress 319 MB/s <-- sweet spot?
|
||||
# level 5 77107 compress 19.5 MB/s decompress 273 MB/s
|
||||
# level 6 75081 compress 10.0 MB/s decompress 99.3 MB/s
|
||||
# level 7 75022 compress 7.5 MB/s decompress 287 MB/s
|
||||
# level 8 75016 compress 5.4 MB/s decompress 109 MB/s
|
||||
# level 9 75016 compress 5.4 MB/s decompress 344 MB/s
|
||||
m=
|
||||
make -j8 MODE=$m o/$m/examples || exit
|
||||
for level in $(seq 0 9); do
|
||||
o/$m/examples/compress.com $level <o/dbg/third_party/python/python.com | dd count=10000 2>/tmp/info >/tmp/comp
|
||||
compspeed=$(grep -Po '[.\d]+ \w+/s' /tmp/info)
|
||||
o/$m/examples/decompress.com $level </tmp/comp | dd count=10000 2>/tmp/info >/dev/null
|
||||
decompspeed=$(grep -Po '[.\d]+ \w+/s' /tmp/info)
|
||||
size=$(o/$m/examples/compress.com $level <o/$m/examples/compress.com | wc -c)
|
||||
echo "level $level $size compress $compspeed decompress $decompspeed"
|
||||
done
|
||||
*/
|
||||
// clang-format on
|
||||
|
||||
int decompressor(int infd, int outfd) {
|
||||
|
|
|
@ -99,8 +99,8 @@
|
|||
int workers;
|
||||
int messages;
|
||||
int connections;
|
||||
int closingtime;
|
||||
const char *status;
|
||||
volatile int closingtime;
|
||||
|
||||
int Worker(void *id) {
|
||||
int server, yes = 1;
|
||||
|
@ -273,7 +273,8 @@ int main(int argc, char *argv[]) {
|
|||
MAP_STACK | MAP_ANONYMOUS, -1, 0);
|
||||
CHECK_NE(-1, clone(Worker, stack, GetStackSize(),
|
||||
CLONE_THREAD | CLONE_VM | CLONE_FS | CLONE_FILES |
|
||||
CLONE_SIGHAND | CLONE_SETTLS,
|
||||
CLONE_SIGHAND | CLONE_SETTLS | CLONE_CHILD_SETTID |
|
||||
CLONE_CHILD_CLEARTID,
|
||||
(void *)(intptr_t)i, 0, tls, 64, 0));
|
||||
}
|
||||
status = "";
|
||||
|
|
145
examples/shell.c
145
examples/shell.c
|
@ -14,6 +14,7 @@
|
|||
#include "libc/calls/struct/timespec.h"
|
||||
#include "libc/fmt/fmt.h"
|
||||
#include "libc/fmt/itoa.h"
|
||||
#include "libc/intrin/kprintf.h"
|
||||
#include "libc/log/internal.h"
|
||||
#include "libc/log/log.h"
|
||||
#include "libc/macros.internal.h"
|
||||
|
@ -24,6 +25,7 @@
|
|||
#include "libc/str/str.h"
|
||||
#include "libc/sysv/consts/clock.h"
|
||||
#include "libc/sysv/consts/dt.h"
|
||||
#include "libc/sysv/consts/o.h"
|
||||
#include "libc/sysv/consts/sig.h"
|
||||
#include "libc/time/time.h"
|
||||
#include "libc/x/x.h"
|
||||
|
@ -40,6 +42,12 @@
|
|||
* very maintainable sadly.
|
||||
*/
|
||||
|
||||
volatile int gotint;
|
||||
|
||||
static void OnInterrupt(int sig) {
|
||||
gotint = sig;
|
||||
}
|
||||
|
||||
static void AddUniqueCompletion(linenoiseCompletions *c, char *s) {
|
||||
size_t i;
|
||||
if (!s) return;
|
||||
|
@ -106,20 +114,40 @@ static char *ShellHint(const char *p, const char **ansi1, const char **ansi2) {
|
|||
return h;
|
||||
}
|
||||
|
||||
static char *MakePrompt(char *p) {
|
||||
char *s, buf[256];
|
||||
if (!gethostname(buf, sizeof(buf))) {
|
||||
p = stpcpy(p, "\e[95m");
|
||||
if ((s = getenv("USER"))) {
|
||||
p = stpcpy(p, s);
|
||||
*p++ = '@';
|
||||
}
|
||||
p = stpcpy(p, buf);
|
||||
*p++ = ':';
|
||||
}
|
||||
p = stpcpy(p, "\e[96m");
|
||||
if ((s = getcwd(buf, sizeof(buf)))) {
|
||||
p = stpcpy(p, s);
|
||||
}
|
||||
return stpcpy(p, "\e[0m>: ");
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
bool timeit;
|
||||
int64_t nanos;
|
||||
int n, ws, pid;
|
||||
struct rusage ru;
|
||||
struct timespec ts1, ts2;
|
||||
char *prog, path[PATH_MAX];
|
||||
sigset_t chldmask, savemask;
|
||||
struct sigaction ignore, saveint, savequit;
|
||||
char *p, *line, **args, *arg, *start, *state, prompt[64];
|
||||
int stdoutflags, stderrflags;
|
||||
const char *stdoutpath, *stderrpath;
|
||||
int n, rc, ws, pid, child, killcount;
|
||||
struct sigaction sa, saveint, savequit;
|
||||
char *p, *line, **args, *arg, *start, *state, prompt[1024];
|
||||
linenoiseSetFreeHintsCallback(free);
|
||||
linenoiseSetHintsCallback(ShellHint);
|
||||
linenoiseSetCompletionCallback(ShellCompletion);
|
||||
stpcpy(prompt, "$ ");
|
||||
MakePrompt(prompt);
|
||||
while ((line = linenoiseWithHistory(prompt, "cmd"))) {
|
||||
n = 0;
|
||||
start = line;
|
||||
|
@ -129,35 +157,114 @@ int main(int argc, char *argv[]) {
|
|||
} else {
|
||||
timeit = false;
|
||||
}
|
||||
stdoutpath = 0;
|
||||
stderrpath = 0;
|
||||
stdoutflags = 0;
|
||||
stderrflags = 0;
|
||||
args = xcalloc(1, sizeof(*args));
|
||||
while ((arg = strtok_r(start, " \t\r\n", &state))) {
|
||||
args = xrealloc(args, (++n + 1) * sizeof(*args));
|
||||
args[n - 1] = arg;
|
||||
args[n - 0] = 0;
|
||||
start = 0;
|
||||
// cmd >>stdout.txt
|
||||
if (arg[0] == '>' && arg[1] == '>') {
|
||||
stdoutflags = O_WRONLY | O_APPEND | O_CREAT;
|
||||
stdoutpath = arg + 2;
|
||||
} else if (arg[0] == '>') {
|
||||
// cmd >stdout.txt
|
||||
stdoutflags = O_WRONLY | O_CREAT | O_TRUNC;
|
||||
stdoutpath = arg + 1;
|
||||
} else if (arg[0] == '2' && arg[1] == '>' && arg[2] == '>') {
|
||||
// cmd 2>>stderr.txt
|
||||
stderrflags = O_WRONLY | O_APPEND | O_CREAT;
|
||||
stderrpath = arg + 3;
|
||||
} else if (arg[0] == '2' && arg[1] == '>') {
|
||||
// cmd 2>stderr.txt
|
||||
stderrflags = O_WRONLY | O_CREAT | O_TRUNC;
|
||||
stderrpath = arg + 2;
|
||||
} else {
|
||||
// arg
|
||||
args = xrealloc(args, (++n + 1) * sizeof(*args));
|
||||
args[n - 1] = arg;
|
||||
args[n - 0] = 0;
|
||||
start = 0;
|
||||
}
|
||||
}
|
||||
if (n > 0) {
|
||||
if ((prog = commandv(args[0], path, sizeof(path)))) {
|
||||
ignore.sa_flags = 0;
|
||||
ignore.sa_handler = SIG_IGN;
|
||||
sigemptyset(&ignore.sa_mask);
|
||||
sigaction(SIGINT, &ignore, &saveint);
|
||||
sigaction(SIGQUIT, &ignore, &savequit);
|
||||
|
||||
// let keyboard interrupts kill child and not shell
|
||||
gotint = 0;
|
||||
killcount = 0;
|
||||
sa.sa_flags = 0;
|
||||
sa.sa_handler = SIG_IGN;
|
||||
sigemptyset(&sa.sa_mask);
|
||||
sigaction(SIGQUIT, &sa, &savequit);
|
||||
sa.sa_handler = OnInterrupt;
|
||||
sigaction(SIGINT, &sa, &saveint);
|
||||
sigemptyset(&chldmask);
|
||||
sigaddset(&chldmask, SIGCHLD);
|
||||
sigprocmask(SIG_BLOCK, &chldmask, &savemask);
|
||||
|
||||
// record timestamp
|
||||
if (timeit) {
|
||||
clock_gettime(CLOCK_REALTIME, &ts1);
|
||||
}
|
||||
if (!fork()) {
|
||||
|
||||
// launch process
|
||||
if (!(child = vfork())) {
|
||||
if (stdoutpath) {
|
||||
close(1);
|
||||
open(stdoutpath, stdoutflags, 0644);
|
||||
}
|
||||
if (stderrpath) {
|
||||
close(2);
|
||||
open(stderrpath, stderrflags, 0644);
|
||||
}
|
||||
sigaction(SIGINT, &saveint, 0);
|
||||
sigaction(SIGQUIT, &savequit, 0);
|
||||
sigprocmask(SIG_SETMASK, &savemask, 0);
|
||||
execv(prog, args);
|
||||
_Exit(127);
|
||||
}
|
||||
wait4(0, &ws, 0, &ru);
|
||||
|
||||
// wait for process
|
||||
for (;;) {
|
||||
if (gotint) {
|
||||
switch (killcount) {
|
||||
case 0:
|
||||
// ctrl-c
|
||||
// we do nothing
|
||||
// terminals broadcast sigint to process group
|
||||
rc = 0;
|
||||
break;
|
||||
case 1:
|
||||
// ctrl-c ctrl-c
|
||||
// we try sending sigterm
|
||||
rc = kill(child, SIGTERM);
|
||||
break;
|
||||
default:
|
||||
// ctrl-c ctrl-c ctrl-c ...
|
||||
// we use kill -9 as our last resort
|
||||
rc = kill(child, SIGKILL);
|
||||
break;
|
||||
}
|
||||
if (rc == -1) {
|
||||
fprintf(stderr, "kill failed: %m\n");
|
||||
exit(1);
|
||||
}
|
||||
++killcount;
|
||||
gotint = 0;
|
||||
}
|
||||
rc = wait4(0, &ws, 0, &ru);
|
||||
if (rc != -1) {
|
||||
break;
|
||||
} else if (errno == EINTR) {
|
||||
errno = 0;
|
||||
} else {
|
||||
fprintf(stderr, "wait failed: %m\n");
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
// print resource consumption for `time` pseudocommand
|
||||
if (timeit) {
|
||||
clock_gettime(CLOCK_REALTIME, &ts2);
|
||||
if (ts2.tv_sec == ts1.tv_sec) {
|
||||
|
@ -174,23 +281,27 @@ int main(int argc, char *argv[]) {
|
|||
free(p);
|
||||
}
|
||||
|
||||
// update prompt to reflect exit status
|
||||
p = prompt;
|
||||
if (WIFEXITED(ws)) {
|
||||
if (WEXITSTATUS(ws)) {
|
||||
if (!__nocolor) p = stpcpy(p, "\e[1;31m");
|
||||
p = stpcpy(p, "rc=");
|
||||
p = FormatInt32(p, WEXITSTATUS(ws));
|
||||
if (128 < WEXITSTATUS(ws) && WEXITSTATUS(ws) <= 128 + 32) {
|
||||
*p++ = ' ';
|
||||
p = stpcpy(p, strsignal(WEXITSTATUS(ws) - 128));
|
||||
}
|
||||
if (!__nocolor) p = stpcpy(p, "\e[0m");
|
||||
*p++ = ' ';
|
||||
}
|
||||
} else {
|
||||
if (!__nocolor) p = stpcpy(p, "\e[1;31m");
|
||||
p = stpcpy(p, "rc=");
|
||||
p = stpcpy(p, strsignal(WTERMSIG(ws)));
|
||||
if (!__nocolor) p = stpcpy(p, "\e[0m");
|
||||
*p++ = ' ';
|
||||
}
|
||||
p = stpcpy(p, "$ ");
|
||||
MakePrompt(p);
|
||||
|
||||
sigaction(SIGINT, &saveint, 0);
|
||||
sigaction(SIGQUIT, &savequit, 0);
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue