diff --git a/examples/greenbean.c b/examples/greenbean.c index 3698fcf45..275bab40b 100644 --- a/examples/greenbean.c +++ b/examples/greenbean.c @@ -18,6 +18,7 @@ #include "libc/fmt/conv.h" #include "libc/fmt/itoa.h" #include "libc/intrin/kprintf.h" +#include "libc/limits.h" #include "libc/log/check.h" #include "libc/log/log.h" #include "libc/macros.internal.h" @@ -96,11 +97,12 @@ "Referrer-Policy: origin\r\n" \ "Cache-Control: private; max-age=0\r\n" -int workers; -int messages; -int connections; -const char *status; +_Atomic(int) workers; +_Atomic(int) messages; +_Atomic(int) listening; +_Atomic(int) connections; _Atomic(int) closingtime; +const char *volatile status; int Worker(void *id) { int server, yes = 1; @@ -132,6 +134,7 @@ int Worker(void *id) { listen(server, 1); // connection loop + ++listening; while (!closingtime) { struct tm tm; int64_t unixts; @@ -167,7 +170,7 @@ int Worker(void *id) { continue; } - asm volatile("lock incl\t%0" : "+m"(connections)); + ++connections; // message loop do { @@ -177,12 +180,12 @@ int Worker(void *id) { if ((got = read(client, inbuf, sizeof(inbuf))) <= 0) break; // check that client message wasn't fragmented into more reads if (!(inmsglen = ParseHttpMessage(&msg, inbuf, got))) break; - asm volatile("lock incl\t%0" : "+m"(messages)); + ++messages; #if LOGGING // log the incoming http message clientip = ntohl(clientaddr.sin_addr.s_addr); - kprintf("#%.4x get some %d.%d.%d.%d:%d %#.*s\n", (intptr_t)id, + kprintf("%6P get some %d.%d.%d.%d:%d %#.*s\n", (clientip & 0xff000000) >> 030, (clientip & 0x00ff0000) >> 020, (clientip & 0x0000ff00) >> 010, (clientip & 0x000000ff) >> 000, ntohs(clientaddr.sin_port), msg.uri.b - msg.uri.a, @@ -200,7 +203,7 @@ int Worker(void *id) { p = stpcpy(outbuf, "HTTP/1.1 200 OK\r\n" STANDARD_RESPONSE_HEADERS "Content-Type: text/html; charset=utf-8\r\n" "Date: "); - clock_gettime(CLOCK_REALTIME, &ts), unixts = ts.tv_sec; + clock_gettime(0, &ts), unixts = ts.tv_sec; p = FormatHttpDateTime(p, gmtime_r(&unixts, &tm)); p = stpcpy(p, "\r\nContent-Length: "); p = FormatInt32(p, strlen(q)); @@ -218,7 +221,7 @@ int Worker(void *id) { "HTTP/1.1 404 Not Found\r\n" STANDARD_RESPONSE_HEADERS "Content-Type: text/html; charset=utf-8\r\n" "Date: "); - clock_gettime(CLOCK_REALTIME, &ts), unixts = ts.tv_sec; + clock_gettime(0, &ts), unixts = ts.tv_sec; p = FormatHttpDateTime(p, gmtime_r(&unixts, &tm)); p = stpcpy(p, "\r\nContent-Length: "); p = FormatInt32(p, strlen(q)); @@ -238,13 +241,14 @@ int Worker(void *id) { (msg.method == kHttpGet || msg.method == kHttpHead)); DestroyHttpMessage(&msg); close(client); - asm volatile("lock decl\t%0" : "+m"(connections)); + --connections; } + --listening; // inform the parent that this clone has finished WorkerFinished: close(server); - asm volatile("lock decl\t%0" : "+m"(workers)); + --workers; return 0; } @@ -253,35 +257,85 @@ void OnCtrlC(int sig) { status = " shutting down..."; } +void PrintStatus(void) { + kprintf("\r\e[K\e[32mgreenbean\e[0m " + "workers=%d " + "listening=%d " + "connections=%d " + "messages=%d%s ", + workers, listening, connections, messages, status); +} + int main(int argc, char *argv[]) { + char **tls; + char **stack; int i, threads; uint32_t *hostips; // ShowCrashReports(); - sigaction(SIGINT, &(struct sigaction){.sa_handler = OnCtrlC}, 0); + + // listen for ctrl-c, hangup, and kill which shut down greenbean + status = ""; + struct sigaction sa = {.sa_handler = OnCtrlC}; + sigaction(SIGHUP, &sa, 0); + sigaction(SIGINT, &sa, 0); + sigaction(SIGTERM, &sa, 0); + + // print all the ips that 0.0.0.0 will bind for (hostips = GetHostIps(), i = 0; hostips[i]; ++i) { kprintf("listening on http://%d.%d.%d.%d:%d\n", (hostips[i] & 0xff000000) >> 030, (hostips[i] & 0x00ff0000) >> 020, (hostips[i] & 0x0000ff00) >> 010, (hostips[i] & 0x000000ff) >> 000, PORT); } - threads = argc > 1 ? atoi(argv[1]) : 0; - if (!threads) threads = GetCpuCount(); - workers = threads; - for (i = 0; i < threads; ++i) { - char *tls = __initialize_tls(malloc(64)); - void *stack = mmap(0, GetStackSize(), PROT_READ | PROT_WRITE, - 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, - (void *)(intptr_t)i, 0, tls, 64, 0)); + + // spawn over 9,000 worker threads + tls = 0; + stack = 0; + threads = argc > 1 ? atoi(argv[1]) : GetCpuCount(); + if ((1 <= threads && threads <= INT_MAX) && + (tls = malloc(threads * sizeof(*tls))) && + (stack = malloc(threads * sizeof(*stack)))) { + if (!threads) threads = GetCpuCount(); + for (i = 0; i < threads; ++i) { + if ((tls[i] = __initialize_tls(malloc(64))) && + (stack[i] = mmap(0, GetStackSize(), PROT_READ | PROT_WRITE, + MAP_STACK | MAP_ANONYMOUS, -1, 0)) != MAP_FAILED) { + ++workers; + if (clone(Worker, stack[i], GetStackSize(), + CLONE_THREAD | CLONE_VM | CLONE_FS | CLONE_FILES | + CLONE_SIGHAND | CLONE_SETTLS | CLONE_CHILD_SETTID | + CLONE_CHILD_CLEARTID, + (void *)(intptr_t)i, 0, tls[i], 64, + (int *)(tls[i] + 0x38)) == -1) { + --workers; + kprintf("error: clone(%d) failed %m\n", i); + } + } else { + kprintf("error: mmap(%d) failed %m\n", i); + } + if (!(i % 500)) { + PrintStatus(); + } + } + } else { + kprintf("error: invalid number of threads\n"); } - status = ""; + + // wait for workers to terminate while (workers) { - kprintf( - "\r\e[K\e[32mgreenbean\e[0m workers=%d connections=%d messages=%d%s ", - workers, connections, messages, status); + PrintStatus(); usleep(HEARTBEAT * 1000); } + + // clean up terminal line kprintf("\r\e[K"); + + // clean up memory + for (i = 0; i < threads; ++i) { + if (stack) munmap(stack[i], GetStackSize()); + if (tls) free(tls[i]); + } + free(hostips); + free(stack); + free(tls); } diff --git a/libc/calls/calls.h b/libc/calls/calls.h index 5d29a9a98..455136d21 100644 --- a/libc/calls/calls.h +++ b/libc/calls/calls.h @@ -130,18 +130,18 @@ int geteuid(void) nosideeffect; int getgid(void) nosideeffect; int gethostname(char *, size_t); int getloadavg(double *, int); -int getpgid(int); +int getpgid(int) nosideeffect libcesque; int getpgrp(void) nosideeffect; -int getpid(void); +int getpid(void) nosideeffect libcesque; int getppid(void); int getpriority(int, unsigned); int getresgid(uint32_t *, uint32_t *, uint32_t *); int getresuid(uint32_t *, uint32_t *, uint32_t *); int getrlimit(int, struct rlimit *); int getrusage(int, struct rusage *); -int getsid(int) nosideeffect; -int gettid(void); -int getuid(void) nosideeffect; +int getsid(int) nosideeffect libcesque; +int gettid(void) libcesque; +int getuid(void) nosideeffect libcesque; int kill(int, int); int killpg(int, int); int link(const char *, const char *) dontthrow; diff --git a/libc/calls/clock_gettime.c b/libc/calls/clock_gettime.c index 0ccd93dc2..f7deab6e6 100644 --- a/libc/calls/clock_gettime.c +++ b/libc/calls/clock_gettime.c @@ -80,8 +80,6 @@ noinstrument int clock_gettime(int clockid, struct timespec *ts) { * Returns fast system clock_gettime() if it exists. */ void *__get_clock_gettime(void) { - // TODO(jart): Re-enable this. - return 0; void *vdso; static bool once; static void *result; diff --git a/libc/calls/ioctl_tcsets-nt.c b/libc/calls/ioctl_tcsets-nt.c index 9eb023cad..126b57d2f 100644 --- a/libc/calls/ioctl_tcsets-nt.c +++ b/libc/calls/ioctl_tcsets-nt.c @@ -24,6 +24,7 @@ #include "libc/nt/console.h" #include "libc/nt/enum/consolemodeflags.h" #include "libc/nt/enum/version.h" +#include "libc/nt/version.h" #include "libc/sysv/consts/o.h" #include "libc/sysv/consts/termios.h" #include "libc/sysv/errfuns.h" @@ -57,7 +58,7 @@ textwindows int ioctl_tcsets_nt(int ignored, uint64_t request, if (tio->c_lflag & (IEXTEN | ISIG)) { inmode |= kNtEnableProcessedInput; } - if (NtGetVersion() >= kNtVersionWindows10) { + if (IsAtLeastWindows10()) { inmode |= kNtEnableVirtualTerminalInput; } ok = SetConsoleMode(in, inmode); @@ -71,7 +72,7 @@ textwindows int ioctl_tcsets_nt(int ignored, uint64_t request, if (!(tio->c_oflag & ONLCR)) { outmode |= kNtDisableNewlineAutoReturn; } - if (NtGetVersion() >= kNtVersionWindows10) { + if (IsAtLeastWindows10()) { outmode |= kNtEnableVirtualTerminalProcessing; } ok = SetConsoleMode(out, outmode); diff --git a/libc/calls/ischardev.c b/libc/calls/ischardev.c index 82fbe7d51..a310e958f 100644 --- a/libc/calls/ischardev.c +++ b/libc/calls/ischardev.c @@ -16,17 +16,13 @@ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ -#include "libc/bits/weaken.h" #include "libc/calls/calls.h" #include "libc/calls/internal.h" #include "libc/calls/struct/metastat.internal.h" -#include "libc/calls/struct/stat.h" #include "libc/dce.h" #include "libc/errno.h" #include "libc/nt/enum/filetype.h" #include "libc/nt/files.h" -#include "libc/sysv/errfuns.h" -#include "libc/zipos/zipos.internal.h" /** * Returns true if file descriptor is backed by character i/o. @@ -44,15 +40,7 @@ bool32 ischardev(int fd) { int e; union metastat st; if (__isfdkind(fd, kFdZip)) { - e = errno; - if (weaken(__zipos_fstat)( - (struct ZiposHandle *)(intptr_t)g_fds.p[fd].handle, &st.cosmo) != - -1) { - return S_ISCHR(st.cosmo.st_mode); - } else { - errno = e; - return false; - } + return false; } else if (IsMetal()) { return true; } else if (!IsWindows()) { diff --git a/libc/calls/now.c b/libc/calls/now.c index a7ec88b88..e32879fd5 100644 --- a/libc/calls/now.c +++ b/libc/calls/now.c @@ -97,7 +97,8 @@ static long double nowl_vdso(void) { long double nowl_setup(void) { uint64_t ticks; - if ((g_now.clock_gettime = __get_clock_gettime())) { + if (0 && (g_now.clock_gettime = __get_clock_gettime())) { + // TODO(jart): Re-enable this. nowl = nowl_vdso; } else if (X86_HAVE(INVTSC)) { RefreshTime(); @@ -107,5 +108,3 @@ long double nowl_setup(void) { } return nowl(); } - -long double (*nowl)(void) = nowl_setup; diff --git a/libc/calls/virtualmax.c b/libc/calls/nowl.S similarity index 82% rename from libc/calls/virtualmax.c rename to libc/calls/nowl.S index 92df148c7..d83b1f59d 100644 --- a/libc/calls/virtualmax.c +++ b/libc/calls/nowl.S @@ -1,5 +1,5 @@ -/*-*- 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│ +/*-*- mode:unix-assembly; indent-tabs-mode:t; tab-width:8; coding:utf-8 -*-│ +│vi: set et ft=asm ts=8 tw=8 fenc=utf-8 :vi│ ╞══════════════════════════════════════════════════════════════════════════════╡ │ Copyright 2022 Justine Alexandra Roberts Tunney │ │ │ @@ -16,13 +16,14 @@ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ -#include "libc/calls/calls.h" +#include "libc/macros.internal.h" -/** - * Maximum amount of virtual memory in bytes. - * - * mmap() will return ENOMEM once this is reached. - * - * By default no limit is imposed. - */ -size_t __virtualmax = -1; + .initbss 201,_init_nowl +nowl: .quad 0 + .endobj nowl,globl + .previous + + .init.start 201,_init_nowl + ezlea nowl_setup,ax + stosq + .init.end 201,_init_nowl diff --git a/libc/calls/setitimer-nt.c b/libc/calls/setitimer-nt.c index 52272b2e2..3dd838e30 100644 --- a/libc/calls/setitimer-nt.c +++ b/libc/calls/setitimer-nt.c @@ -81,7 +81,13 @@ textwindows void _check_sigalrm(void) { textwindows int sys_setitimer_nt(int which, const struct itimerval *newvalue, struct itimerval *out_opt_oldvalue) { long double elapsed, untilnext; - if (which != ITIMER_REAL) return einval(); + if (which != ITIMER_REAL || + (newvalue && (!(0 <= newvalue->it_value.tv_usec && + newvalue->it_value.tv_usec < 1000000) || + !(0 <= newvalue->it_interval.tv_usec && + newvalue->it_interval.tv_usec < 1000000)))) { + return einval(); + } if (out_opt_oldvalue) { if (__hastimer) { elapsed = nowl() - __lastalrm; diff --git a/libc/calls/uname.c b/libc/calls/uname.c index fa187db12..a7b22023e 100644 --- a/libc/calls/uname.c +++ b/libc/calls/uname.c @@ -48,7 +48,7 @@ static inline textwindows noasan int NtGetBuildNumber(void) { * @return 0 on success, or -1 w/ errno */ int uname(struct utsname *lool) { - int rc, v; + int rc; char *out, *p; size_t i, j, len; char tmp[sizeof(struct utsname)]; @@ -87,7 +87,6 @@ int uname(struct utsname *lool) { rc = enosys(); } } else { - v = NtGetVersion(); p = lool->release; p = FormatUint32(p, NtGetMajorVersion()), *p++ = '.'; p = FormatUint32(p, NtGetMinorVersion()), *p++ = '-'; diff --git a/libc/stdio/unlocked/fflush_unlocked.S b/libc/calls/virtualmax.S similarity index 82% rename from libc/stdio/unlocked/fflush_unlocked.S rename to libc/calls/virtualmax.S index 8463f2876..655ecba25 100644 --- a/libc/stdio/unlocked/fflush_unlocked.S +++ b/libc/calls/virtualmax.S @@ -1,7 +1,7 @@ /*-*- mode:unix-assembly; indent-tabs-mode:t; tab-width:8; coding:utf-8 -*-│ │vi: set et ft=asm ts=8 tw=8 fenc=utf-8 :vi│ ╞══════════════════════════════════════════════════════════════════════════════╡ -│ Copyright 2020 Justine Alexandra Roberts Tunney │ +│ 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 │ @@ -18,16 +18,20 @@ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/macros.internal.h" -// Blocks until data from stream buffer is written out. + .initbss 201,_init___virtualmax + +// Maximum amount of virtual memory in bytes. // -// @param rdi is the stream handle, or 0 for all streams -// @return 0 on success or -1 w/ errno -// @see fflush_unlocked() -// @threadsafe -fflush: ezlea fflush_unlocked,ax - test %rdi,%rdi - jz 1f - mov %rdi,%r11 - jmp stdio_unlock -1: jmp *%rax - .endfn fflush,globl +// mmap() will return ENOMEM once this is reached. +// +// By default no limit is imposed. +__virtualmax: + .quad 0 + .endobj __virtualmax,globl + .previous + + .init.start 201,_init___virtualmax + push $-1 + pop %rax + stosq + .init.end 201,_init___virtualmax diff --git a/libc/intrin/asan.c b/libc/intrin/asan.c index d8bf1bd89..93f63602a 100644 --- a/libc/intrin/asan.c +++ b/libc/intrin/asan.c @@ -199,7 +199,7 @@ static char *__asan_utf8cpy(char *p, unsigned c) { return p; } -static void *__asan_memset(void *p, char c, size_t n) { +static void __asan_memset(void *p, char c, size_t n) { char *b; size_t i; uint64_t x; @@ -207,29 +207,29 @@ static void *__asan_memset(void *p, char c, size_t n) { x = 0x0101010101010101ul * (c & 255); switch (n) { case 0: - return p; + break; case 1: __builtin_memcpy(b, &x, 1); - return p; + break; case 2: __builtin_memcpy(b, &x, 2); - return p; + break; case 3: __builtin_memcpy(b, &x, 2); __builtin_memcpy(b + 1, &x, 2); - return p; + break; case 4: __builtin_memcpy(b, &x, 4); - return p; + break; case 5: case 6: case 7: __builtin_memcpy(b, &x, 4); __builtin_memcpy(b + n - 4, &x, 4); - return p; + break; case 8: __builtin_memcpy(b, &x, 8); - return p; + break; case 9: case 10: case 11: @@ -240,7 +240,7 @@ static void *__asan_memset(void *p, char c, size_t n) { case 16: __builtin_memcpy(b, &x, 8); __builtin_memcpy(b + n - 8, &x, 8); - return p; + break; default: if (n <= 64) { i = 0; @@ -253,83 +253,10 @@ static void *__asan_memset(void *p, char c, size_t n) { } else { __repstosb(p, c, n); } - return p; + break; } } -static void *__asan_mempcpy(void *dst, const void *src, size_t n) { - size_t i; - char *d; - const char *s; - uint64_t a, b; - d = dst; - s = src; - switch (n) { - case 0: - return d; - case 1: - *d = *s; - return d + 1; - case 2: - __builtin_memcpy(&a, s, 2); - __builtin_memcpy(d, &a, 2); - return d + 2; - case 3: - __builtin_memcpy(&a, s, 2); - __builtin_memcpy(&b, s + 1, 2); - __builtin_memcpy(d, &a, 2); - __builtin_memcpy(d + 1, &b, 2); - return d + 3; - case 4: - __builtin_memcpy(&a, s, 4); - __builtin_memcpy(d, &a, 4); - return d + 4; - case 5: - case 6: - case 7: - __builtin_memcpy(&a, s, 4); - __builtin_memcpy(&b, s + n - 4, 4); - __builtin_memcpy(d, &a, 4); - __builtin_memcpy(d + n - 4, &b, 4); - return d + n; - case 8: - __builtin_memcpy(&a, s, 8); - __builtin_memcpy(d, &a, 8); - return d + 8; - case 9: - case 10: - case 11: - case 12: - case 13: - case 14: - case 15: - case 16: - __builtin_memcpy(&a, s, 8); - __builtin_memcpy(&b, s + n - 8, 8); - __builtin_memcpy(d, &a, 8); - __builtin_memcpy(d + n - 8, &b, 8); - return d + n; - default: - if (n <= 64) { - i = 0; - do { - __builtin_memcpy(&a, s + i, 8); - asm volatile("" ::: "memory"); - __builtin_memcpy(d + i, &a, 8); - } while ((i += 8) + 8 <= n); - for (; i < n; ++i) d[i] = s[i]; - return d + i; - } else { - return __repmovsb(d, s, n); - } - } -} - -static void *__asan_memcpy(void *dst, const void *src, size_t n) { - __asan_mempcpy(dst, src, n); - return dst; -} - static char *__asan_hexcpy(char *p, uint64_t x, uint8_t k) { while (k) *p++ = "0123456789abcdef"[(x >> (k -= 4)) & 15]; return p; @@ -736,7 +663,7 @@ static void __asan_report_memory_origin(const unsigned char *addr, int size, if (_base <= addr && addr < _end) { __asan_report_memory_origin_image((intptr_t)addr, size); } else if (IsAutoFrame((intptr_t)addr >> 16)) { - /* __asan_report_memory_origin_heap(addr, size); */ + __asan_report_memory_origin_heap(addr, size); } } @@ -946,8 +873,8 @@ static void __asan_trace(struct AsanTrace *bt, const struct StackFrame *bp) { #define __asan_trace __asan_rawtrace -static void *__asan_allocate(size_t a, size_t n, int underrun, int overrun, - struct AsanTrace *bt) { +void *__asan_allocate(size_t a, size_t n, int underrun, int overrun, + struct AsanTrace *bt) { char *p; size_t c; struct AsanExtra *e; @@ -960,7 +887,7 @@ static void *__asan_allocate(size_t a, size_t n, int underrun, int overrun, __asan_poison(p + n, c - n, overrun); __asan_memset(p, 0xF9, n); __asan_write48(&e->size, n); - __asan_memcpy(&e->bt, bt, sizeof(*bt)); + __builtin_memcpy(&e->bt, bt, sizeof(*bt)); } return p; } @@ -1082,7 +1009,7 @@ static void *__asan_realloc_grow(void *p, size_t n, size_t m, struct AsanTrace *bt) { char *q; if ((q = __asan_allocate(16, n, kAsanHeapUnderrun, kAsanHeapOverrun, bt))) { - __asan_memcpy(q, p, m); + __builtin_memcpy(q, p, m); __asan_deallocate(p, kAsanHeapRelocated); } return q; diff --git a/libc/intrin/assertfail.greg.c b/libc/intrin/assertfail.greg.c index ceaa381db..7ee853936 100644 --- a/libc/intrin/assertfail.greg.c +++ b/libc/intrin/assertfail.greg.c @@ -46,7 +46,6 @@ relegated wontreturn void __assert_fail(const char *expr, const char *file, } else { rc = 24; } - if (weaken(__die)) weaken(__die)(); __restorewintty(); _Exit(rc); } diff --git a/libc/intrin/describeflags.internal.h b/libc/intrin/describeflags.internal.h index 189dc829f..e797abc9a 100644 --- a/libc/intrin/describeflags.internal.h +++ b/libc/intrin/describeflags.internal.h @@ -23,6 +23,7 @@ const char *DescribeMapFlags(int); const char *DescribeProtFlags(int); const char *DescribeRemapFlags(int); const char *DescribeRlimitName(int); +const char *DescribePersonalityFlags(int); const char *DescribeSeccompOperationFlags(int); const char *DescribePollFlags(char *, size_t, int); const char *DescribeStat(int, const struct stat *); diff --git a/libc/intrin/describepersonalityflags.c b/libc/intrin/describepersonalityflags.c new file mode 100644 index 000000000..5e09fde70 --- /dev/null +++ b/libc/intrin/describepersonalityflags.c @@ -0,0 +1,43 @@ +/*-*- 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/intrin/describeflags.internal.h" +#include "libc/macros.internal.h" +#include "libc/nt/enum/accessmask.h" +#include "libc/nt/enum/filesharemode.h" +#include "libc/sysv/consts/personality.h" + +static const struct DescribeFlags kPersonalityFlags[] = { + {ADDR_COMPAT_LAYOUT, "ADDR_COMPAT_LAYOUT"}, // + {READ_IMPLIES_EXEC, "READ_IMPLIES_EXEC"}, // + {ADDR_LIMIT_3GB, "ADDR_LIMIT_3GB"}, // + {FDPIC_FUNCPTRS, "FDPIC_FUNCPTRS"}, // + {STICKY_TIMEOUTS, "STICKY_TIMEOUTS"}, // + {MMAP_PAGE_ZERO, "MMAP_PAGE_ZERO"}, // + {ADDR_LIMIT_32BIT, "ADDR_LIMIT_32BIT"}, // + {WHOLE_SECONDS, "WHOLE_SECONDS"}, // + {ADDR_NO_RANDOMIZE, "ADDR_NO_RANDOMIZE"}, // + {SHORT_INODE, "SHORT_INODE"}, // + {UNAME26, "UNAME26"}, // +}; + +const char *DescribePersonalityFlags(int x) { + _Alignas(char) static char personalityflags[128]; + return DescribeFlags(personalityflags, sizeof(personalityflags), + kPersonalityFlags, ARRAYLEN(kPersonalityFlags), "", x); +} diff --git a/libc/intrin/getpid.c b/libc/intrin/getpid.c index 0d8113aed..d45b03254 100644 --- a/libc/intrin/getpid.c +++ b/libc/intrin/getpid.c @@ -22,7 +22,17 @@ /** * Returns process id. + * + * This function does not need to issue a system call. The PID is + * tracked by a global variable which is updated atfork(). The only + * exception is when the process is vfork()'d in which case a system + * call shall be issued. + * + * On Linux, and only Linux, the process id is guaranteed to be the same + * as gettid() for the main thread. + * * @asyncsignalsafe + * @threadsafe * @vforksafe */ int getpid(void) { diff --git a/libc/intrin/gettid.greg.c b/libc/intrin/gettid.greg.c index 4cc21ca3f..9e3cc2802 100644 --- a/libc/intrin/gettid.greg.c +++ b/libc/intrin/gettid.greg.c @@ -32,8 +32,25 @@ __msabi extern typeof(GetCurrentThreadId) *const __imp_GetCurrentThreadId; * if this is the main thread. On NetBSD, gettid() for the main thread * is always 1. * + * This function issues a system call. That stops being the case as soon + * as __install_tls() is called. That'll happen automatically, when you + * call clone() and provide the TLS parameter. We assume that when a TLS + * block exists, then + * + * *(int *)(__get_tls() + 0x38) + * + * will contain the thread id. Therefore when issuing clone() calls, the + * `CLONE_CHILD_SETTID` and `CLONE_CHILD_CLEARTID` flags should use that + * index as its `ctid` memory. + * + * gettid (single threaded) l: 126𝑐 41𝑛𝑠 + * gettid (tls enabled) l: 2𝑐 1𝑛𝑠 + * + * The TLS convention is important for reentrant lock performance. + * * @return thread id greater than zero or -1 w/ errno * @asyncsignalsafe + * @threadsafe */ privileged int gettid(void) { int rc; @@ -42,9 +59,7 @@ privileged int gettid(void) { if (__tls_enabled) { rc = *(int *)(__get_tls() + 0x38); - if (rc && rc != -1) { - return rc; - } + return rc; } if (IsWindows()) { diff --git a/libc/intrin/intrin.mk b/libc/intrin/intrin.mk index e7b05d974..6978c7ce2 100644 --- a/libc/intrin/intrin.mk +++ b/libc/intrin/intrin.mk @@ -46,9 +46,14 @@ $(LIBC_INTRIN_A_OBJS): \ OVERRIDE_CFLAGS += \ -foptimize-sibling-calls +# we can't use asan and ubsan because: +# this is asan and ubsan +# we need -ffreestanding because: +# we don't want __builtin_memcpy() calling memcpy() o/$(MODE)/libc/intrin/asan.o \ o/$(MODE)/libc/intrin/ubsan.o: \ OVERRIDE_CFLAGS += \ + -ffreestanding \ -fno-sanitize=all \ -fno-stack-protector @@ -145,12 +150,6 @@ o/$(MODE)/libc/intrin/describeopenflags.greg.o: \ OVERRIDE_CPPFLAGS += \ -DSTACK_FRAME_UNLIMITED -o/$(MODE)/libc/intrin/asan.o \ -o/$(MODE)/libc/intrin/ubsan.o: \ - OVERRIDE_CFLAGS += \ - -fno-sanitize=all \ - -fno-stack-protector - o//libc/intrin/memmove.o: \ OVERRIDE_CFLAGS += \ -fno-toplevel-reorder diff --git a/libc/intrin/kprintf.greg.c b/libc/intrin/kprintf.greg.c index f3340e947..bf7b7021e 100644 --- a/libc/intrin/kprintf.greg.c +++ b/libc/intrin/kprintf.greg.c @@ -857,7 +857,6 @@ privileged void kvprintf(const char *fmt, va_list v) { * * Specifiers: * - * - `P` pid * - `c` char * - `o` octal * - `b` binary @@ -873,6 +872,7 @@ privileged void kvprintf(const char *fmt, va_list v) { * - `X` uppercase * - `T` timestamp * - `x` hexadecimal + * - `P` pid (or tid if threaded) * * Types: * diff --git a/libc/intrin/ntgetversion.c b/libc/intrin/ntgetversion.c index 57c7ea551..d458b68b2 100644 --- a/libc/intrin/ntgetversion.c +++ b/libc/intrin/ntgetversion.c @@ -22,9 +22,9 @@ /** * Returns New Technology version, e.g. * - * if (IsWindows() && NtGetVersion() >=k NtVersionWindows10) {...} - * * This can only be called on Windows. + * + * @see IsAtLeastWindows10() */ textwindows noasan int NtGetVersion(void) { return (NtGetPeb()->OSMajorVersion & 0xff) << 8 | NtGetPeb()->OSMinorVersion; diff --git a/libc/intrin/sched_yield.S b/libc/intrin/sched_yield.S index 1060780c4..c0a7d80bd 100644 --- a/libc/intrin/sched_yield.S +++ b/libc/intrin/sched_yield.S @@ -25,16 +25,8 @@ // // @return 0 on success, or -1 w/ errno sched_yield: - push %rbp - mov %rsp,%rbp - testb IsWindows() - jnz 1f - -// UNIX Support - mov __NR_sched_yield,%eax - syscall - jmp 2f +#if SupportsWindows() // Windows Support // // A value of zero, together with the bAlertable parameter set to @@ -44,12 +36,34 @@ sched_yield: // threads ready to run and no user APCs are queued, the function // returns immediately, and the thread continues execution. // ──Quoth MSDN -1: xor %ecx,%ecx + testb IsWindows() + jz 1f + push %rbp + mov %rsp,%rbp + xor %ecx,%ecx xor %edx,%edx ntcall __imp_SleepEx xor %eax,%eax - -2: pop %rbp + pop %rbp ret +#endif + +#if SupportsSystemv() +// UNIX Support +1: mov __NR_sched_yield,%eax +#if SupportsBsd() && SupportsLinux() + clc +#endif + syscall +#if SupportsBsd() + jc systemfive_errno +#endif +#if SupportsLinux() + cmp $-4095,%rax + jae systemfive_error +#endif +#endif + +2: ret .endfn sched_yield,globl .previous diff --git a/libc/intrin/tls.greg.c b/libc/intrin/tls.greg.c index 52366662c..e3250d190 100644 --- a/libc/intrin/tls.greg.c +++ b/libc/intrin/tls.greg.c @@ -44,23 +44,28 @@ * 0x003c 0x04 errno * */ -privileged void *__initialize_tls(char tib[hasatleast 64]) { - *(intptr_t *)tib = (intptr_t)tib; - *(intptr_t *)(tib + 0x08) = 0; - *(int *)(tib + 0x10) = -1; // exit code - *(intptr_t *)(tib + 0x30) = (intptr_t)tib; - *(int *)(tib + 0x38) = -1; // tid - *(int *)(tib + 0x3c) = __errno; +privileged void *__initialize_tls(char tib[64]) { + if (tib) { + *(intptr_t *)tib = (intptr_t)tib; + *(intptr_t *)(tib + 0x08) = 0; + *(int *)(tib + 0x10) = -1; // exit code + *(intptr_t *)(tib + 0x30) = (intptr_t)tib; + *(int *)(tib + 0x38) = -1; // tid + *(int *)(tib + 0x3c) = 0; + } return tib; } /** * Installs thread information block on main process. */ -privileged void __install_tls(char tib[hasatleast 64]) { +privileged void __install_tls(char tib[64]) { int ax, dx; uint64_t magic; unsigned char *p; + assert(tib); + assert(!__tls_enabled); + assert(*(int *)(tib + 0x38) != -1); if (IsWindows()) { if (!__tls_index) { __tls_index = TlsAlloc(); diff --git a/libc/nexgen32e/threaded.h b/libc/nexgen32e/threaded.h index 778da129d..868aab33e 100644 --- a/libc/nexgen32e/threaded.h +++ b/libc/nexgen32e/threaded.h @@ -8,8 +8,8 @@ extern bool __threaded; extern bool __tls_enabled; extern unsigned __tls_index; -void *__initialize_tls(char[hasatleast 64]); -void __install_tls(char[hasatleast 64]); +void *__initialize_tls(char[64]); +void __install_tls(char[64]); #if defined(__GNUC__) && defined(__x86_64__) && !defined(__STRICT_ANSI__) /** diff --git a/libc/nt/enum/version.h b/libc/nt/enum/version.h index c6f67f1fc..48a45834f 100644 --- a/libc/nt/enum/version.h +++ b/libc/nt/enum/version.h @@ -4,17 +4,18 @@ /** * Known versions of the New Technology executive. + * @see IsAtLeastWindows10() * @see NtGetVersion() */ -#define kNtVersionWindows10 0x0a00 -#define kNtVersionWindows81 0x0603 -#define kNtVersionWindows8 0x0602 -#define kNtVersionWindows7 0x0601 +#define kNtVersionWindows10 0x0a00 +#define kNtVersionWindows81 0x0603 +#define kNtVersionWindows8 0x0602 +#define kNtVersionWindows7 0x0601 #define kNtVersionWindowsVista 0x0600 /* intended baseline */ -#define kNtVersionWindowsXp64 0x0502 /* end of the road */ -#define kNtVersionWindowsXp 0x0501 /* snowball's chance */ -#define kNtVersionWindows2000 0x0500 /* the golden age */ -#define kNtVersionFuture 0x0b00 +#define kNtVersionWindowsXp64 0x0502 /* end of the road */ +#define kNtVersionWindowsXp 0x0501 /* snowball's chance */ +#define kNtVersionWindows2000 0x0500 /* the golden age */ +#define kNtVersionFuture 0x0b00 #endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */ #endif /* COSMOPOLITAN_LIBC_NT_ENUM_VERSION_H_ */ diff --git a/libc/nt/version.h b/libc/nt/version.h index f7ade11de..c7da8aab0 100644 --- a/libc/nt/version.h +++ b/libc/nt/version.h @@ -8,16 +8,14 @@ bool IsAtLeastWindows10(void) pureconst; bool32 GetVersionEx(struct NtOsVersionInfo *lpVersionInformation); #if defined(__GCC_ASM_FLAG_OUTPUTS__) && !defined(__STRICT_ANSI__) -#define IsAtLeastWindows10() \ - ({ \ - long ReG; \ - bool NoTbelow; \ - asm("mov\t%%gs:96,%1\r\n" \ - "cmpb\t%2,280(%1)" \ - : "=@ccnb"(NoTbelow), "=l"(ReG) \ - : "i"(10)); \ - NoTbelow; \ - }) +#define IsAtLeastWindows10() (GetNtMajorVersion() >= 10) +static pureconst inline unsigned char GetNtMajorVersion(void) { + uintptr_t _x; + asm("mov\t%%gs:96,%q0\r\n" + "mov\t280(%q0),%b0" + : "=q"(_x)); + return _x; +} #endif COSMOPOLITAN_C_END_ diff --git a/libc/runtime/clone-linux.S b/libc/runtime/clone-linux.S new file mode 100644 index 000000000..131e60592 --- /dev/null +++ b/libc/runtime/clone-linux.S @@ -0,0 +1,55 @@ +/*-*- mode:unix-assembly; indent-tabs-mode:t; tab-width:8; coding:utf-8 -*-│ +│vi: set et ft=asm ts=8 tw=8 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/macros.internal.h" + +// Invokes clone() system call on GNU/Systemd. +// +// @param rdi is flags +// @param rsi is top of stack +// @param rdx is ptid +// @param rcx is ctid +// @param r8 is tls +// @param r9 is func +// @param 8(rsp) is arg +// @return tid of child on success, or -1 w/ errno +sys_clone_linux: + push %rbp + mov %rsp,%rbp + .profilable + push %rbx + mov %rcx,%r10 + mov 16(%rbp),%rbx + mov $56,%eax # __NR_clone + syscall + test %rax,%rax + jz 2f + cmp $-4095,%rax + jae 1f +0: pop %rbx + pop %rbp + ret +1: call systemfive_error + jmp 0b +2: xor %ebp,%ebp # child thread + mov %rbx,%rdi # arg + call *%r9 # func(arg) + xchg %eax,%edi # func(arg) → exitcode + mov $60,%eax # __NR_exit(exitcode) + syscall + .endfn sys_clone_linux,globl,hidden diff --git a/libc/runtime/clone.c b/libc/runtime/clone.c index 779a12bf7..e15daea30 100644 --- a/libc/runtime/clone.c +++ b/libc/runtime/clone.c @@ -419,40 +419,8 @@ static int CloneNetbsd(int (*func)(void *), char *stk, size_t stksz, int flags, //////////////////////////////////////////////////////////////////////////////// // GNU/SYSTEMD -int CloneLinux(int (*func)(void *), char *stk, size_t stksz, int flags, - void *arg, int *ptid, void *tls, size_t tlssz, int *ctid) { -#ifdef __chibicc__ - return -1; // TODO -#else - int ax; - intptr_t *stack = (intptr_t *)(stk + stksz); - *--stack = (intptr_t)arg; - // %rax = syscall(%rax = __NR_clone, - // %rdi = flags, - // %rsi = child_stack, - // %rdx = parent_tidptr, - // %r10 = child_tidptr, - // %r8 = new_tls); - asm volatile("mov\t%4,%%r10\n\t" // ctid - "mov\t%5,%%r8\n\t" // tls - "mov\t%6,%%r9\n\t" // func - "syscall\n\t" - "test\t%0,%0\n\t" - "jnz\t1f\n\t" - "xor\t%%ebp,%%ebp\n\t" - "pop\t%%rdi\n\t" // arg - "call\t*%%r9\n\t" // func - "xchg\t%%eax,%%edi\n\t" - "mov\t$0x3c,%%eax\n\t" - "syscall\n1:" - : "=a"(ax) - : "0"(__NR_clone_linux), "D"(flags), "S"(stack), "g"(ctid), - "g"(tls), "g"(func), "d"(ptid) - : "rcx", "r8", "r9", "r10", "r11", "memory"); - if (ax > -4096u) errno = -ax, ax = -1; - return ax; -#endif -} +int sys_clone_linux(int flags, char *stk, int *ptid, int *ctid, void *tls, + int (*func)(void *), void *arg); //////////////////////////////////////////////////////////////////////////////// // COSMOPOLITAN @@ -542,13 +510,23 @@ int clone(int (*func)(void *), void *stk, size_t stksz, int flags, void *arg, int rc; struct CloneArgs *wt; - if (flags & CLONE_THREAD) { - __threaded = true; - } - + // transition program to threaded state if ((flags & CLONE_SETTLS) && !__tls_enabled) { + if (~flags & CLONE_THREAD) { + STRACE("clone() tls w/o thread"); + return einval(); + } + if (__threaded) { + STRACE("clone() tls/non-tls mixed order"); + return einval(); + } __initialize_tls(tibdefault); + *(int *)((char *)tibdefault + 0x38) = gettid(); + *(int *)((char *)tibdefault + 0x3c) = __errno; __install_tls(tibdefault); + __threaded = true; + } else if (flags & CLONE_THREAD) { + __threaded = true; } if (IsAsan() && @@ -566,7 +544,8 @@ int clone(int (*func)(void *), void *stk, size_t stksz, int flags, void *arg, ((flags & CLONE_SETTLS) && (tlssz < 64 || (tlssz & 7))))) { rc = einval(); } else if (IsLinux()) { - rc = CloneLinux(func, stk, stksz, flags, arg, ptid, tls, tlssz, ctid); + rc = + sys_clone_linux(flags, (char *)stk + stksz, ptid, ctid, tls, func, arg); } else if (!IsTiny() && (flags & ~(CLONE_SETTLS | CLONE_PARENT_SETTID | CLONE_CHILD_SETTID | CLONE_CHILD_CLEARTID)) != diff --git a/libc/runtime/isheap.c b/libc/runtime/isheap.c index a532b4380..6d3796e43 100644 --- a/libc/runtime/isheap.c +++ b/libc/runtime/isheap.c @@ -26,7 +26,9 @@ * @assume stack addresses are always greater than heap addresses * @assume stack memory isn't stored beneath %rsp (-mno-red-zone) */ -noasan bool _isheap(void *p) { - return kAutomapStart <= (intptr_t)p && - (intptr_t)p < kAutomapStart + kAutomapSize; +optimizesize noasan bool _isheap(void *p) { + intptr_t x, y; + x = kAutomapStart; + y = x + kAutomapSize; + return x <= (intptr_t)p && (intptr_t)p < y; } diff --git a/libc/runtime/memtrack.internal.h b/libc/runtime/memtrack.internal.h index 43e9efacd..ea64eaec6 100644 --- a/libc/runtime/memtrack.internal.h +++ b/libc/runtime/memtrack.internal.h @@ -4,8 +4,7 @@ #include "libc/bits/midpoint.h" #include "libc/dce.h" #include "libc/macros.internal.h" -#include "libc/nt/enum/version.h" -#include "libc/runtime/runtime.h" +#include "libc/nt/version.h" #include "libc/runtime/stack.h" #include "libc/sysv/consts/ss.h" #if !(__ASSEMBLER__ + __LINKER__ + 0) @@ -29,7 +28,7 @@ COSMOPOLITAN_C_START_ ROUNDUP(VSPACE / FRAMESIZE * (intptr_t)sizeof(struct MemoryInterval), \ FRAMESIZE) #define _kMem(NORMAL, WIN7) \ - (!(IsWindows() && NtGetVersion() < kNtVersionWindows10) ? NORMAL : WIN7) + (!IsWindows() || IsAtLeastWindows10() ? NORMAL : WIN7) struct MemoryInterval { int x; diff --git a/libc/runtime/stackchkfail.c b/libc/runtime/stackchkfail.c index ad42a392d..29caaeb51 100644 --- a/libc/runtime/stackchkfail.c +++ b/libc/runtime/stackchkfail.c @@ -16,59 +16,11 @@ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ -#include "libc/bits/pushpop.h" -#include "libc/nt/enum/version.h" -#include "libc/nt/runtime.h" +#include "libc/intrin/kprintf.h" #include "libc/runtime/internal.h" -#include "libc/sysv/consts/fileno.h" -#include "libc/sysv/consts/nr.h" -#define STACK_SMASH_MESSAGE "stack smashed\n" - -/** - * Aborts program under enemy fire to avoid being taken alive. - */ -privileged noasan void __stack_chk_fail(void) { - size_t len; - const char *msg; - int64_t ax, cx, si; - if (!IsWindows()) { - msg = STACK_SMASH_MESSAGE; - len = pushpop(sizeof(STACK_SMASH_MESSAGE) - 1); - if (!IsMetal()) { - asm volatile("syscall" - : "=a"(ax) - : "0"(__NR_write), "D"(pushpop(STDERR_FILENO)), "S"(msg), - "d"(len) - : "rcx", "r11", "cc", "memory"); - asm volatile("syscall" - : "=a"(ax) - : "0"(__NR_exit_group), "D"(pushpop(23)) - : "rcx", "r11", "cc", "memory"); - } - asm volatile("rep outsb" - : "=S"(si), "=c"(cx) - : "0"(msg), "1"(len), "d"(0x3F8 /* COM1 */) - : "memory"); - asm("push\t$0\n\t" - "push\t$0\n\t" - "cli\n\t" - "lidt\t(%rsp)"); - for (;;) asm("ud2"); - } - if (NtGetVersion() < kNtVersionFuture) { - do { - asm volatile("syscall" - : "=a"(ax), "=c"(cx) - : "0"(NtGetVersion() < kNtVersionWindows8 ? 0x0029 - : NtGetVersion() < kNtVersionWindows81 ? 0x002a - : NtGetVersion() < kNtVersionWindows10 ? 0x002b - : 0x002c), - "1"(pushpop(-1L)), "d"(42) - : "r11", "cc", "memory"); - } while (!ax); - } - for (;;) { - TerminateProcess(GetCurrentProcess(), 42); - } +privileged noasan noinstrument void __stack_chk_fail(void) { + kprintf("stack smashed\n"); + __restorewintty(); + _Exit(207); } diff --git a/libc/stdio/fclose.c b/libc/stdio/fclose.c index cd75a500e..ebb7b6e65 100644 --- a/libc/stdio/fclose.c +++ b/libc/stdio/fclose.c @@ -39,6 +39,7 @@ int fclose(FILE *f) { if (!f) return 0; __fflush_unregister(f); fflush(f); + free_s(&f->getln); if (!f->nofree) { free_s(&f->buf); } diff --git a/libc/stdio/fflush.c b/libc/stdio/fflush.c index b9411a5bc..5618a8ae4 100644 --- a/libc/stdio/fflush.c +++ b/libc/stdio/fflush.c @@ -1,7 +1,7 @@ /*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│ -│vi: set net ft=c ts=8 sts=2 sw=2 fenc=utf-8 :vi│ +│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│ ╞══════════════════════════════════════════════════════════════════════════════╡ -│ Copyright 2020 Justine Alexandra Roberts Tunney │ +│ 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 │ @@ -16,83 +16,19 @@ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ -#include "libc/alg/arraylist.internal.h" -#include "libc/bits/bits.h" -#include "libc/bits/pushpop.h" -#include "libc/calls/calls.h" -#include "libc/errno.h" -#include "libc/intrin/spinlock.h" -#include "libc/macros.internal.h" -#include "libc/mem/mem.h" -#include "libc/runtime/runtime.h" -#include "libc/stdio/fflush.internal.h" -#include "libc/stdio/internal.h" #include "libc/stdio/stdio.h" -#include "libc/sysv/consts/o.h" /** * Blocks until data from stream buffer is written out. * * @param f is the stream handle, or 0 for all streams * @return is 0 on success or -1 on error + * @threadsafe */ -int fflush_unlocked(FILE *f) { - int rc = 0; - size_t i; - if (!f) { - _spinlock(&__fflush.lock); - for (i = __fflush.handles.i; i; --i) { - if ((f = __fflush.handles.p[i - 1])) { - if (fflush(f) == -1) { - rc = -1; - } - } - } - _spunlock(&__fflush.lock); - } else if (f->fd != -1) { - if (__fflush_impl(f) == -1) { - rc = -1; - } - } else if (f->beg && f->beg < f->size) { - f->buf[f->beg] = 0; - } - return rc; -} - -textstartup int __fflush_register(FILE *f) { +int fflush(FILE *f) { int rc; - size_t i; - struct StdioFlush *sf; - _spinlock(&__fflush.lock); - sf = &__fflush; - if (!sf->handles.p) { - sf->handles.p = sf->handles_initmem; - pushmov(&sf->handles.n, ARRAYLEN(sf->handles_initmem)); - __cxa_atexit(fflush_unlocked, 0, 0); - } - for (i = sf->handles.i; i; --i) { - if (!sf->handles.p[i - 1]) { - sf->handles.p[i - 1] = f; - _spunlock(&__fflush.lock); - return 0; - } - } - rc = append(&sf->handles, &f); - _spunlock(&__fflush.lock); + if (f) flockfile(f); + rc = fflush_unlocked(f); + if (f) funlockfile(f); return rc; } - -void __fflush_unregister(FILE *f) { - size_t i; - struct StdioFlush *sf; - _spinlock(&__fflush.lock); - sf = &__fflush; - sf = pushpop(sf); - for (i = sf->handles.i; i; --i) { - if (sf->handles.p[i - 1] == f) { - pushmov(&sf->handles.p[i - 1], 0); - break; - } - } - _spunlock(&__fflush.lock); -} diff --git a/libc/stdio/fflush_unlocked.c b/libc/stdio/fflush_unlocked.c new file mode 100644 index 000000000..b9411a5bc --- /dev/null +++ b/libc/stdio/fflush_unlocked.c @@ -0,0 +1,98 @@ +/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│ +│vi: set net ft=c ts=8 sts=2 sw=2 fenc=utf-8 :vi│ +╞══════════════════════════════════════════════════════════════════════════════╡ +│ Copyright 2020 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/alg/arraylist.internal.h" +#include "libc/bits/bits.h" +#include "libc/bits/pushpop.h" +#include "libc/calls/calls.h" +#include "libc/errno.h" +#include "libc/intrin/spinlock.h" +#include "libc/macros.internal.h" +#include "libc/mem/mem.h" +#include "libc/runtime/runtime.h" +#include "libc/stdio/fflush.internal.h" +#include "libc/stdio/internal.h" +#include "libc/stdio/stdio.h" +#include "libc/sysv/consts/o.h" + +/** + * Blocks until data from stream buffer is written out. + * + * @param f is the stream handle, or 0 for all streams + * @return is 0 on success or -1 on error + */ +int fflush_unlocked(FILE *f) { + int rc = 0; + size_t i; + if (!f) { + _spinlock(&__fflush.lock); + for (i = __fflush.handles.i; i; --i) { + if ((f = __fflush.handles.p[i - 1])) { + if (fflush(f) == -1) { + rc = -1; + } + } + } + _spunlock(&__fflush.lock); + } else if (f->fd != -1) { + if (__fflush_impl(f) == -1) { + rc = -1; + } + } else if (f->beg && f->beg < f->size) { + f->buf[f->beg] = 0; + } + return rc; +} + +textstartup int __fflush_register(FILE *f) { + int rc; + size_t i; + struct StdioFlush *sf; + _spinlock(&__fflush.lock); + sf = &__fflush; + if (!sf->handles.p) { + sf->handles.p = sf->handles_initmem; + pushmov(&sf->handles.n, ARRAYLEN(sf->handles_initmem)); + __cxa_atexit(fflush_unlocked, 0, 0); + } + for (i = sf->handles.i; i; --i) { + if (!sf->handles.p[i - 1]) { + sf->handles.p[i - 1] = f; + _spunlock(&__fflush.lock); + return 0; + } + } + rc = append(&sf->handles, &f); + _spunlock(&__fflush.lock); + return rc; +} + +void __fflush_unregister(FILE *f) { + size_t i; + struct StdioFlush *sf; + _spinlock(&__fflush.lock); + sf = &__fflush; + sf = pushpop(sf); + for (i = sf->handles.i; i; --i) { + if (sf->handles.p[i - 1] == f) { + pushmov(&sf->handles.p[i - 1], 0); + break; + } + } + _spunlock(&__fflush.lock); +} diff --git a/libc/stdio/fflushimpl.c b/libc/stdio/fflushimpl.c index 9d6ecea49..8805b9a76 100644 --- a/libc/stdio/fflushimpl.c +++ b/libc/stdio/fflushimpl.c @@ -18,12 +18,14 @@ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/calls/calls.h" #include "libc/errno.h" +#include "libc/runtime/runtime.h" #include "libc/stdio/internal.h" #include "libc/sysv/consts/o.h" int __fflush_impl(FILE *f) { size_t i; ssize_t rc; + free_s(&f->getln); if (f->beg && !f->end && (f->iomode & O_ACCMODE) != O_RDONLY) { for (i = 0; i < f->beg; i += rc) { if ((rc = write(f->fd, f->buf + i, f->beg - i)) == -1) { diff --git a/libc/stdio/fgetln.c b/libc/stdio/fgetln.c index 6749197e3..94c5643c9 100644 --- a/libc/stdio/fgetln.c +++ b/libc/stdio/fgetln.c @@ -18,13 +18,35 @@ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/stdio/stdio.h" +/** + * Retrieves line from stream, e.g. + * + * char *line; + * while ((line = _chomp(fgetln(stdin, 0)))) { + * printf("%s\n", line); + * } + * + * The returned memory is owned by the stream. It'll be reused when + * fgetln() is called again. It's free()'d upon fclose() / fflush() + * + * @param stream specifies non-null open input stream + * @param len optionally receives byte length of line + * @return nul-terminated line string, including the `\n` character + * unless a line happened before EOF without `\n`, otherwise it + * returns `NULL` and feof() and ferror() can examine the state + * @see getdelim() + */ char *fgetln(FILE *stream, size_t *len) { + char *res; ssize_t rc; size_t n = 0; - if ((rc = getdelim(&stream->getln, &n, '\n', stream)) > 0) { - *len = rc; - return stream->getln; + flockfile(stream); + if ((rc = getdelim_unlocked(&stream->getln, &n, '\n', stream)) > 0) { + if (len) *len = rc; + res = stream->getln; } else { - return 0; + res = 0; } + funlockfile(stream); + return res; } diff --git a/libc/stdio/flockfile.c b/libc/stdio/flockfile.c index 223ead118..7a575904b 100644 --- a/libc/stdio/flockfile.c +++ b/libc/stdio/flockfile.c @@ -28,16 +28,18 @@ void flockfile(FILE *f) { int me, owner; unsigned tries; - if (!__threaded) return; - for (tries = 0, me = gettid();;) { - owner = 0; - if (_lockcmpxchgp(&f->lock, &owner, me) || owner == me) { - return; - } - if (++tries & 7) { - __builtin_ia32_pause(); - } else { - sched_yield(); + if (__threaded) { + for (tries = 0, me = gettid();;) { + owner = 0; + if (_lockcmpxchgp(&f->lock, &owner, me) || owner == me) { + break; + } + if (++tries & 7) { + __builtin_ia32_pause(); + } else { + sched_yield(); + } } } + ++f->reent; } diff --git a/libc/stdio/fputc.c b/libc/stdio/fputc.c index 9b432718d..8aa5e1494 100644 --- a/libc/stdio/fputc.c +++ b/libc/stdio/fputc.c @@ -29,7 +29,7 @@ int fputc_unlocked(int c, FILE *f) { unsigned char b; if (c != '\n' && f->beg < f->size && f->bufmode != _IONBF) { f->buf[f->beg++] = c; - return c & 0xff; + return c & 255; } else { b = c; if (!fwrite_unlocked(&b, 1, 1, f)) return -1; diff --git a/libc/stdio/ftrylockfile.c b/libc/stdio/ftrylockfile.c index 20bffd3ca..eeed1e490 100644 --- a/libc/stdio/ftrylockfile.c +++ b/libc/stdio/ftrylockfile.c @@ -34,5 +34,8 @@ int ftrylockfile(FILE *f) { owner = 0; } } + if (!owner) { + ++f->reent; + } return owner; } diff --git a/libc/stdio/funlockfile.c b/libc/stdio/funlockfile.c index 46d68d0fd..0e1601a1c 100644 --- a/libc/stdio/funlockfile.c +++ b/libc/stdio/funlockfile.c @@ -16,12 +16,24 @@ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ -#include "libc/intrin/spinlock.h" +#include "libc/assert.h" +#include "libc/calls/calls.h" +#include "libc/nexgen32e/threaded.h" #include "libc/stdio/stdio.h" /** * Releases lock on stdio object. */ void funlockfile(FILE *f) { - _spunlock(&f->lock); + int owner; + bool shouldunlock; + assert(f->reent > 0); + shouldunlock = --f->reent <= 0; + if (__threaded) { + assert(f->lock == gettid()); + if (shouldunlock) { + owner = 0; + __atomic_store(&f->lock, &owner, __ATOMIC_RELAXED); + } + } } diff --git a/libc/stdio/getdelim.c b/libc/stdio/getdelim.c index fa29af049..1bfffabfb 100644 --- a/libc/stdio/getdelim.c +++ b/libc/stdio/getdelim.c @@ -16,64 +16,18 @@ │ 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/errno.h" -#include "libc/macros.internal.h" -#include "libc/mem/mem.h" -#include "libc/runtime/runtime.h" #include "libc/stdio/stdio.h" -#include "libc/str/str.h" -#include "libc/sysv/consts/o.h" - -static ssize_t getdelim_unlocked(char **s, size_t *n, int delim, FILE *f) { - char *p; - ssize_t rc; - size_t i, m; - if ((f->iomode & O_ACCMODE) == O_WRONLY) { - f->state = errno = EBADF; - return -1; - } - if (f->beg > f->end) { - f->state = errno = EINVAL; - return -1; - } - if (!*s) *n = 0; - for (i = 0;; i += m) { - m = f->end - f->beg; - if ((p = memchr(f->buf + f->beg, delim, m))) m = p + 1 - (f->buf + f->beg); - if (i + m + 1 > *n) { - *n = i + m + 1; - *s = realloc(*s, *n); - if (!*s) { - abort(); - } - } - memcpy(*s + i, f->buf + f->beg, m); - (*s)[i + m] = '\0'; - if ((f->beg += m) == f->end) f->beg = f->end = 0; - if (p) { - return i + m; - } else if (f->fd == -1) { - break; - } else if ((rc = read(f->fd, f->buf, f->size)) != -1) { - if (!rc) break; - f->end = rc; - } else if (errno != EINTR) { - f->state = errno; - return -1; - } - } - f->state = -1; - if (i + m) { - return i + m; - } else { - return -1; - } -} /** - * Reads string from stream. + * Reads string from stream, e.g. + * + * char *line = NULL; + * size_t linesize = 0; + * while (getdelim(&line, &linesize, '\n', stdin) > 0) { + * _chomp(line); + * printf("%s\n", line); + * } + * free(line); * * @param s is the caller's buffer (in/out) which is extended or * allocated automatically, also NUL-terminated is guaranteed @@ -81,8 +35,9 @@ static ssize_t getdelim_unlocked(char **s, size_t *n, int delim, FILE *f) { * @param delim is the stop char (and NUL is implicitly too) * @return number of bytes read >0, including delim, excluding NUL, * or -1 w/ errno on EOF or error; see ferror() and feof() - * @note this function can't punt EINTR to caller - * @see getline(), _chomp(), gettok_r() + * @note this function will ignore EINTR if it occurs mid-line + * @raises EBADF if stream isn't open for reading + * @see fgetln(), getline(), _chomp(), gettok_r() */ ssize_t getdelim(char **s, size_t *n, int delim, FILE *f) { ssize_t rc; diff --git a/libc/stdio/getdelim_unlocked.c b/libc/stdio/getdelim_unlocked.c new file mode 100644 index 000000000..3314c4379 --- /dev/null +++ b/libc/stdio/getdelim_unlocked.c @@ -0,0 +1,81 @@ +/*-*- 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/errno.h" +#include "libc/stdio/stdio.h" +#include "libc/str/str.h" +#include "libc/sysv/consts/o.h" + +/** + * Reads string from unlocked stream. + * @see getdelim() for documentation + */ +ssize_t getdelim_unlocked(char **s, size_t *n, int delim, FILE *f) { + ssize_t rc; + char *p, *s2; + size_t i, m, n2; + if ((f->iomode & O_ACCMODE) == O_WRONLY) { + f->state = errno = EBADF; + return -1; + } + if (f->beg > f->end) { + f->state = errno = EINVAL; + return -1; + } + if (!*s) *n = 0; + for (i = 0;; i += m) { + m = f->end - f->beg; + if ((p = memchr(f->buf + f->beg, delim, m))) { + m = p + 1 - (f->buf + f->beg); + } + if (i + m + 1 > *n) { + n2 = i + m + 1; + s2 = realloc(*s, n2); + if (s2) { + *s = s2; + *n = n2; + } else { + f->state = errno; + return -1; + } + } + memcpy(*s + i, f->buf + f->beg, m); + (*s)[i + m] = '\0'; + if ((f->beg += m) == f->end) { + f->beg = f->end = 0; + } + if (p) { + return i + m; + } else if (f->fd == -1) { + break; + } else if ((rc = read(f->fd, f->buf, f->size)) != -1) { + if (!rc) break; + f->end = rc; + } else if (errno != EINTR) { + f->state = errno; + return -1; + } + } + f->state = -1; + if (i + m) { + return i + m; + } else { + return -1; + } +} diff --git a/libc/stdio/getline.c b/libc/stdio/getline.c index 6f0fd43b8..88f17836e 100644 --- a/libc/stdio/getline.c +++ b/libc/stdio/getline.c @@ -19,7 +19,15 @@ #include "libc/stdio/stdio.h" /** - * Reads line from stream. + * Reads line from stream, e.g. + * + * char *line = NULL; + * size_t linesize = 0; + * while (getline(&line, &linesize, stdin) > 0) { + * _chomp(line); + * printf("%s\n", line); + * } + * free(line); * * This function delegates to getdelim(), which provides further * documentation. Concerning lines, please note the \n or \r\n are @@ -30,7 +38,7 @@ * NUL-termination is guaranteed FTMP * @return number of bytes read, including delim, excluding NUL, or -1 * w/ errno on EOF or error; see ferror() and feof() - * @see xgetline(), getdelim(), gettok_r() + * @see fgetln(), xgetline(), getdelim(), gettok_r() */ ssize_t getline(char **line, size_t *n, FILE *f) { return getdelim(line, n, '\n', f); diff --git a/libc/stdio/stdio.h b/libc/stdio/stdio.h index 9a903e999..f39c53b41 100644 --- a/libc/stdio/stdio.h +++ b/libc/stdio/stdio.h @@ -25,7 +25,8 @@ typedef struct FILE { uint32_t nofree; /* 0x24 */ int pid; /* 0x28 */ int lock; /* 0x2c */ - char *getln; /* 0x30 */ + int reent; /* 0x30 */ + char *getln; /* 0x38 */ } FILE; extern FILE *stdin; @@ -39,6 +40,7 @@ int getc(FILE *) paramsnonnull(); int putc(int, FILE *) paramsnonnull(); int fflush(FILE *); int fgetc(FILE *) paramsnonnull(); +char *fgetln(FILE *, size_t *) paramsnonnull((1)); int ungetc(int, FILE *) paramsnonnull(); int fileno(FILE *) paramsnonnull() nosideeffect; int fputc(int, FILE *) paramsnonnull(); @@ -120,9 +122,9 @@ int fwide(FILE *, int); │ cosmopolitan § standard i/o » without mutexes ─╬─│┼ ╚────────────────────────────────────────────────────────────────────────────│*/ -void flockfile(FILE *); -void funlockfile(FILE *); -int ftrylockfile(FILE *); +void flockfile(FILE *) paramsnonnull(); +void funlockfile(FILE *) paramsnonnull(); +int ftrylockfile(FILE *) paramsnonnull(); int getc_unlocked(FILE *) paramsnonnull(); int getchar_unlocked(void); int putc_unlocked(int, FILE *) paramsnonnull(); @@ -149,6 +151,7 @@ int fputws_unlocked(const wchar_t *, FILE *); wint_t ungetwc_unlocked(wint_t, FILE *) paramsnonnull(); int ungetc_unlocked(int, FILE *) paramsnonnull(); int fseeko_unlocked(FILE *, int64_t, int) paramsnonnull(); +ssize_t getdelim_unlocked(char **, size_t *, int, FILE *) paramsnonnull(); int fprintf_unlocked(FILE *, const char *, ...) printfesque(2) paramsnonnull((1, 2)) dontthrow nocallback; int vfprintf_unlocked(FILE *, const char *, va_list) diff --git a/libc/sysv/consts.sh b/libc/sysv/consts.sh index cd2ffc2a6..c2bab986f 100755 --- a/libc/sysv/consts.sh +++ b/libc/sysv/consts.sh @@ -1573,18 +1573,6 @@ syscon sock SOCK_NONBLOCK 0x0800 0x0800 0x20000000 0x4000 0x20000000 syscon sock SOCK_DCCP 6 0 0 0 0 0 # what is it? syscon sock SOCK_PACKET 10 0 0 0 0 0 # what is it? -syscon prsnlty ADDR_COMPAT_LAYOUT 0x0200000 0 0 0 0 0 # linux only -syscon prsnlty READ_IMPLIES_EXEC 0x0400000 0 0 0 0 0 # linux only -syscon prsnlty ADDR_LIMIT_3GB 0x8000000 0 0 0 0 0 # linux only -syscon prsnlty FDPIC_FUNCPTRS 0x0080000 0 0 0 0 0 # linux only -syscon prsnlty STICKY_TIMEOUTS 0x4000000 0 0 0 0 0 # linux only -syscon prsnlty MMAP_PAGE_ZERO 0x0100000 0 0 0 0 0 # linux only -syscon prsnlty ADDR_LIMIT_32BIT 0x0800000 0 0 0 0 0 # linux only -syscon prsnlty WHOLE_SECONDS 0x2000000 0 0 0 0 0 # linux only -syscon prsnlty ADDR_NO_RANDOMIZE 0x0040000 0 0 0 0 0 # linux only -syscon prsnlty SHORT_INODE 0x1000000 0 0 0 0 0 # linux only -syscon prsnlty UNAME26 0x0020000 0 0 0 0 0 # linux only - syscon misc TH_FIN 1 1 1 1 1 1 # consensus syscon misc TH_SYN 2 2 2 2 2 2 # consensus syscon misc TH_RST 4 4 4 4 4 4 # consensus diff --git a/libc/sysv/consts/ADDR_COMPAT_LAYOUT.S b/libc/sysv/consts/ADDR_COMPAT_LAYOUT.S deleted file mode 100644 index a2613bfd9..000000000 --- a/libc/sysv/consts/ADDR_COMPAT_LAYOUT.S +++ /dev/null @@ -1,2 +0,0 @@ -#include "libc/sysv/consts/syscon.internal.h" -.syscon prsnlty,ADDR_COMPAT_LAYOUT,0x0200000,0,0,0,0,0 diff --git a/libc/sysv/consts/ADDR_LIMIT_32BIT.S b/libc/sysv/consts/ADDR_LIMIT_32BIT.S deleted file mode 100644 index 6ad2491dd..000000000 --- a/libc/sysv/consts/ADDR_LIMIT_32BIT.S +++ /dev/null @@ -1,2 +0,0 @@ -#include "libc/sysv/consts/syscon.internal.h" -.syscon prsnlty,ADDR_LIMIT_32BIT,0x0800000,0,0,0,0,0 diff --git a/libc/sysv/consts/ADDR_LIMIT_3GB.S b/libc/sysv/consts/ADDR_LIMIT_3GB.S deleted file mode 100644 index 6e29ba87c..000000000 --- a/libc/sysv/consts/ADDR_LIMIT_3GB.S +++ /dev/null @@ -1,2 +0,0 @@ -#include "libc/sysv/consts/syscon.internal.h" -.syscon prsnlty,ADDR_LIMIT_3GB,0x8000000,0,0,0,0,0 diff --git a/libc/sysv/consts/ADDR_NO_RANDOMIZE.S b/libc/sysv/consts/ADDR_NO_RANDOMIZE.S deleted file mode 100644 index 3a076ae64..000000000 --- a/libc/sysv/consts/ADDR_NO_RANDOMIZE.S +++ /dev/null @@ -1,2 +0,0 @@ -#include "libc/sysv/consts/syscon.internal.h" -.syscon prsnlty,ADDR_NO_RANDOMIZE,0x0040000,0,0,0,0,0 diff --git a/libc/sysv/consts/FDPIC_FUNCPTRS.S b/libc/sysv/consts/FDPIC_FUNCPTRS.S deleted file mode 100644 index 4140c78ca..000000000 --- a/libc/sysv/consts/FDPIC_FUNCPTRS.S +++ /dev/null @@ -1,2 +0,0 @@ -#include "libc/sysv/consts/syscon.internal.h" -.syscon prsnlty,FDPIC_FUNCPTRS,0x0080000,0,0,0,0,0 diff --git a/libc/sysv/consts/MMAP_PAGE_ZERO.S b/libc/sysv/consts/MMAP_PAGE_ZERO.S deleted file mode 100644 index 44a90993a..000000000 --- a/libc/sysv/consts/MMAP_PAGE_ZERO.S +++ /dev/null @@ -1,2 +0,0 @@ -#include "libc/sysv/consts/syscon.internal.h" -.syscon prsnlty,MMAP_PAGE_ZERO,0x0100000,0,0,0,0,0 diff --git a/libc/sysv/consts/READ_IMPLIES_EXEC.S b/libc/sysv/consts/READ_IMPLIES_EXEC.S deleted file mode 100644 index c2a749151..000000000 --- a/libc/sysv/consts/READ_IMPLIES_EXEC.S +++ /dev/null @@ -1,2 +0,0 @@ -#include "libc/sysv/consts/syscon.internal.h" -.syscon prsnlty,READ_IMPLIES_EXEC,0x0400000,0,0,0,0,0 diff --git a/libc/sysv/consts/SHORT_INODE.S b/libc/sysv/consts/SHORT_INODE.S deleted file mode 100644 index 4605ea47e..000000000 --- a/libc/sysv/consts/SHORT_INODE.S +++ /dev/null @@ -1,2 +0,0 @@ -#include "libc/sysv/consts/syscon.internal.h" -.syscon prsnlty,SHORT_INODE,0x1000000,0,0,0,0,0 diff --git a/libc/sysv/consts/STICKY_TIMEOUTS.S b/libc/sysv/consts/STICKY_TIMEOUTS.S deleted file mode 100644 index e15c5f294..000000000 --- a/libc/sysv/consts/STICKY_TIMEOUTS.S +++ /dev/null @@ -1,2 +0,0 @@ -#include "libc/sysv/consts/syscon.internal.h" -.syscon prsnlty,STICKY_TIMEOUTS,0x4000000,0,0,0,0,0 diff --git a/libc/sysv/consts/UNAME26.S b/libc/sysv/consts/UNAME26.S deleted file mode 100644 index 7288894b2..000000000 --- a/libc/sysv/consts/UNAME26.S +++ /dev/null @@ -1,2 +0,0 @@ -#include "libc/sysv/consts/syscon.internal.h" -.syscon prsnlty,UNAME26,0x0020000,0,0,0,0,0 diff --git a/libc/sysv/consts/WHOLE_SECONDS.S b/libc/sysv/consts/WHOLE_SECONDS.S deleted file mode 100644 index 161ad743f..000000000 --- a/libc/sysv/consts/WHOLE_SECONDS.S +++ /dev/null @@ -1,2 +0,0 @@ -#include "libc/sysv/consts/syscon.internal.h" -.syscon prsnlty,WHOLE_SECONDS,0x2000000,0,0,0,0,0 diff --git a/libc/sysv/consts/personality.h b/libc/sysv/consts/personality.h index 432f53a0e..00b60d6c6 100644 --- a/libc/sysv/consts/personality.h +++ b/libc/sysv/consts/personality.h @@ -1,34 +1,17 @@ #ifndef COSMOPOLITAN_LIBC_SYSV_CONSTS_PERSONALITY_H_ #define COSMOPOLITAN_LIBC_SYSV_CONSTS_PERSONALITY_H_ #include "libc/runtime/symbolic.h" -#if !(__ASSEMBLER__ + __LINKER__ + 0) -COSMOPOLITAN_C_START_ -extern const long ADDR_COMPAT_LAYOUT; -extern const long READ_IMPLIES_EXEC; -extern const long ADDR_LIMIT_3GB; -extern const long FDPIC_FUNCPTRS; -extern const long STICKY_TIMEOUTS; -extern const long MMAP_PAGE_ZERO; -extern const long ADDR_LIMIT_32BIT; -extern const long WHOLE_SECONDS; -extern const long ADDR_NO_RANDOMIZE; -extern const long SHORT_INODE; -extern const long UNAME26; - -COSMOPOLITAN_C_END_ -#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */ - -#define ADDR_COMPAT_LAYOUT SYMBOLIC(ADDR_COMPAT_LAYOUT) -#define READ_IMPLIES_EXEC SYMBOLIC(READ_IMPLIES_EXEC) -#define ADDR_LIMIT_3GB SYMBOLIC(ADDR_LIMIT_3GB) -#define FDPIC_FUNCPTRS SYMBOLIC(FDPIC_FUNCPTRS) -#define STICKY_TIMEOUTS SYMBOLIC(STICKY_TIMEOUTS) -#define MMAP_PAGE_ZERO SYMBOLIC(MMAP_PAGE_ZERO) -#define ADDR_LIMIT_32BIT SYMBOLIC(ADDR_LIMIT_32BIT) -#define WHOLE_SECONDS SYMBOLIC(WHOLE_SECONDS) -#define ADDR_NO_RANDOMIZE SYMBOLIC(ADDR_NO_RANDOMIZE) -#define SHORT_INODE SYMBOLIC(SHORT_INODE) -#define UNAME26 SYMBOLIC(UNAME26) +#define ADDR_COMPAT_LAYOUT 0x0200000 +#define READ_IMPLIES_EXEC 0x0400000 +#define ADDR_LIMIT_3GB 0x8000000 +#define FDPIC_FUNCPTRS 0x0080000 +#define STICKY_TIMEOUTS 0x4000000 +#define MMAP_PAGE_ZERO 0x0100000 +#define ADDR_LIMIT_32BIT 0x0800000 +#define WHOLE_SECONDS 0x2000000 +#define ADDR_NO_RANDOMIZE 0x0040000 +#define SHORT_INODE 0x1000000 +#define UNAME26 0x0020000 #endif /* COSMOPOLITAN_LIBC_SYSV_CONSTS_PERSONALITY_H_ */ diff --git a/test/libc/calls/open_test.c b/test/libc/calls/open_test.c index 6362619f0..afec87b92 100644 --- a/test/libc/calls/open_test.c +++ b/test/libc/calls/open_test.c @@ -55,6 +55,18 @@ TEST(open, enametoolong) { ASSERT_SYS(ENAMETOOLONG, -1, creat(s, 0644)); } +TEST(open, testSpaceInFilename) { + char buf[8] = {0}; + ASSERT_SYS(0, 0, xbarf("hello txt", "hello", -1)); + ASSERT_SYS(0, 3, open("hello txt", O_WRONLY)); + EXPECT_SYS(0, 1, write(3, "H", 1)); + EXPECT_SYS(0, 0, close(3)); + ASSERT_SYS(0, 3, open("hello txt", O_RDONLY)); + EXPECT_SYS(0, 5, read(3, buf, 7)); + EXPECT_STREQ("Hello", buf); + EXPECT_SYS(0, 0, close(3)); +} + TEST(open, testOpenExistingForWriteOnly_seeksToStart) { char buf[8] = {0}; ASSERT_SYS(0, 0, xbarf("hello.txt", "hello", -1)); diff --git a/test/libc/intrin/asan_test.c b/test/libc/intrin/asan_test.c index 46bb2c0ea..1caf76766 100644 --- a/test/libc/intrin/asan_test.c +++ b/test/libc/intrin/asan_test.c @@ -46,6 +46,27 @@ TEST(asan, test) { EXPECT_FALSE(__asan_is_valid(p, 64 + 4)); EXPECT_TRUE(__asan_is_valid(p + 1, 64 + 2)); EXPECT_FALSE(__asan_is_valid(p + 1, 64 + 3)); + EXPECT_FALSE(__asan_is_valid(p - 1, 64)); +} + +TEST(asan, test2) { + char *p; + if (!IsAsan()) return; + p = gc(memalign(16, 64)); + // asan design precludes this kind of poisoning + __asan_poison(p + 1, 1, kAsanProtected); + EXPECT_TRUE(__asan_is_valid(p, 2)); + EXPECT_TRUE(__asan_is_valid(p + 1, 2)); + // but we can do this + __asan_poison(p + 7, 1, kAsanProtected); + EXPECT_TRUE(__asan_is_valid(p + 6, 1)); + EXPECT_FALSE(__asan_is_valid(p + 7, 1)); + EXPECT_TRUE(__asan_is_valid(p + 8, 1)); + EXPECT_FALSE(__asan_is_valid(p + 6, 2)); + EXPECT_FALSE(__asan_is_valid(p + 7, 2)); + EXPECT_FALSE(__asan_is_valid(p + 6, 3)); + __asan_unpoison(p + 7, 1); + EXPECT_TRUE(__asan_is_valid(p + 6, 3)); } TEST(asan, testEmptySize_isAlwaysValid) { diff --git a/test/libc/intrin/gettid_test.c b/test/libc/intrin/gettid_test.c index e69de29bb..5f7bde5b8 100644 --- a/test/libc/intrin/gettid_test.c +++ b/test/libc/intrin/gettid_test.c @@ -0,0 +1,37 @@ +/*-*- 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/nexgen32e/threaded.h" +#include "libc/testlib/ezbench.h" +#include "libc/testlib/testlib.h" + +char tib[64]; + +TEST(gettid, test) { + if (IsLinux()) EXPECT_EQ(getpid(), gettid()); + if (IsNetbsd()) EXPECT_EQ(1, gettid()); +} + +BENCH(gettid, bench) { + int gettid_(void) asm("gettid"); + EZBENCH2("gettid (single threaded)", donothing, gettid()); + __install_tls(__initialize_tls(tib)); + EZBENCH2("gettid (tls enabled)", donothing, gettid()); +} diff --git a/test/libc/intrin/tls_test.c b/test/libc/intrin/tls_test.c index 42d1136c4..00d64c73a 100644 --- a/test/libc/intrin/tls_test.c +++ b/test/libc/intrin/tls_test.c @@ -28,6 +28,8 @@ TEST(tls, test) { EXPECT_EQ(31337, errno); EXPECT_EQ(&__errno, __errno_location()); __initialize_tls(tib); + *(int *)((char *)tib + 0x38) = gettid(); + *(int *)((char *)tib + 0x3c) = __errno; __install_tls(tib); EXPECT_EQ(31337, errno); EXPECT_EQ(tib, __get_tls()); diff --git a/test/libc/rand/rand64_test.c b/test/libc/rand/rand64_test.c index f57b7d516..d406a6abc 100644 --- a/test/libc/rand/rand64_test.c +++ b/test/libc/rand/rand64_test.c @@ -80,10 +80,10 @@ TEST(rand64, testLcg_doesntProduceIdenticalValues) { } TEST(rand64, testThreadSafety_doesntProduceIdenticalValues) { - char *tls[THREADS]; + int i, j, rc, ws; sigset_t ss, oldss; + char *tls[THREADS]; void *stacks[THREADS]; - int i, j, rc, ws, tid[THREADS]; struct sigaction oldsa; struct sigaction sa = {.sa_handler = OnChld, .sa_flags = SA_RESTART}; EXPECT_NE(-1, sigaction(SIGCHLD, &sa, &oldsa)); @@ -92,19 +92,20 @@ TEST(rand64, testThreadSafety_doesntProduceIdenticalValues) { sigaddset(&ss, SIGCHLD); EXPECT_EQ(0, sigprocmask(SIG_BLOCK, &ss, &oldss)); ready = false; - memset(tid, -1, sizeof(tid)); for (i = 0; i < THREADS; ++i) { tls[i] = __initialize_tls(calloc(1, 64)); stacks[i] = mmap(0, GetStackSize(), PROT_READ | PROT_WRITE, MAP_STACK | MAP_ANONYMOUS, -1, 0); - ASSERT_NE(-1, clone(Thrasher, stacks[i], GetStackSize(), - CLONE_THREAD | CLONE_VM | CLONE_FS | CLONE_FILES | - CLONE_SIGHAND | CLONE_SETTLS | CLONE_CHILD_CLEARTID, - (void *)(intptr_t)i, 0, tls[i], 64, tid + i)); + ASSERT_NE( + -1, + clone(Thrasher, stacks[i], GetStackSize(), + CLONE_THREAD | CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_SIGHAND | + CLONE_SETTLS | CLONE_CHILD_SETTID | CLONE_CHILD_CLEARTID, + (void *)(intptr_t)i, 0, tls[i], 64, (int *)(tls[i] + 0x38))); } ready = true; for (i = 0; i < THREADS; ++i) { - _spinlock(tid + i); + _spinlock((int *)(tls[i] + 0x38)); EXPECT_SYS(0, 0, munmap(stacks[i], GetStackSize())); free(tls[i]); } diff --git a/test/libc/runtime/ape_test.c b/test/libc/runtime/ape_test.c index 9f07cd69f..fb140b008 100644 --- a/test/libc/runtime/ape_test.c +++ b/test/libc/runtime/ape_test.c @@ -41,6 +41,12 @@ void Extract(const char *from, const char *to, int mode) { } void SetUpOnce(void) { + + // nothing to do if we're using elf + if (~SUPPORT_VECTOR & (WINDOWS | XNU)) { + exit(0); + } + ASSERT_SYS(0, 0, mkdir("bin", 0755)); Extract("/zip/apetest.com", "bin/apetest.com", 0755); Extract("/zip/apetest2.com", "bin/apetest2.com", 0755); diff --git a/test/libc/runtime/clone_test.c b/test/libc/runtime/clone_test.c index fda45026a..8c92f9ec6 100644 --- a/test/libc/runtime/clone_test.c +++ b/test/libc/runtime/clone_test.c @@ -45,7 +45,7 @@ void SetUp(void) { tls = calloc(1, 64); __initialize_tls(tls); *(int *)(tls + 0x3c) = 31337; - childetid = (int *)(tls + 0x0038); + childetid = (int *)(tls + 0x38); ASSERT_NE(MAP_FAILED, (stack = mmap(0, GetStackSize(), PROT_READ | PROT_WRITE, MAP_STACK | MAP_ANONYMOUS, -1, 0))); } @@ -95,6 +95,7 @@ TEST(clone, test1) { CLONE_SETTLS, (void *)23, &ptid, tls, 64, childetid))); _spinlock(childetid); // CLONE_CHILD_CLEARTID + ASSERT_NE(gettid(), tid); ASSERT_EQ(tid, ptid); ASSERT_EQ(42, x); ASSERT_NE(me, tid); @@ -130,6 +131,6 @@ TEST(clone, tlsSystemCallsErrno_wontClobberMainThreadBecauseTls) { BENCH(clone, bench) { errno_t *volatile ep; char *volatile tp; - EZBENCH2("__errno_location", donothing, (ep = (__errno_location()))); + EZBENCH2("__errno_location", donothing, (ep = __errno_location())); EZBENCH2("__get_tls", donothing, (tp = __get_tls())); } diff --git a/test/libc/stdio/fgetln_test.c b/test/libc/stdio/fgetln_test.c new file mode 100644 index 000000000..7cba463c6 --- /dev/null +++ b/test/libc/stdio/fgetln_test.c @@ -0,0 +1,87 @@ +/*-*- 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/mem/mem.h" +#include "libc/runtime/gc.internal.h" +#include "libc/stdio/stdio.h" +#include "libc/str/str.h" +#include "libc/testlib/ezbench.h" +#include "libc/testlib/hyperion.h" +#include "libc/testlib/testlib.h" +#include "libc/x/x.h" + +TEST(fgetln, test) { + FILE *f; + f = fmemopen(gc(strdup(kHyperion)), kHyperionSize, "r+"); + EXPECT_STREQ("The fall of Hyperion - a Dream\n", fgetln(f, 0)); + EXPECT_STREQ("John Keats\n", fgetln(f, 0)); + EXPECT_STREQ("\n", fgetln(f, 0)); + fclose(f); +} + +TEST(fgetln, testGoodLastLine) { + FILE *f; + size_t n; + f = fmemopen("foo\nbar\n", 8, "r"); + EXPECT_STREQ("foo\n", fgetln(f, &n)); + EXPECT_EQ(4, n); + EXPECT_STREQ("bar\n", fgetln(f, &n)); + EXPECT_EQ(4, n); + EXPECT_EQ(NULL, fgetln(f, 0)); + EXPECT_FALSE(ferror(f)); + EXPECT_TRUE(feof(f)); + fclose(f); +} + +TEST(fgetln, testEvilLastLine) { + FILE *f; + f = fmemopen("foo\nbar", 7, "r"); + EXPECT_STREQ("foo\n", fgetln(f, 0)); + EXPECT_STREQ("bar", fgetln(f, 0)); + EXPECT_EQ(NULL, fgetln(f, 0)); + EXPECT_FALSE(ferror(f)); + EXPECT_TRUE(feof(f)); + fclose(f); +} + +TEST(fgetln, testReadingFromStdin_doesntLeakMemory) { + FILE *f; + int oldstdin, pfds[2]; + oldstdin = dup(0); + EXPECT_SYS(0, 0, pipe(pfds)); + EXPECT_SYS(0, 8, write(pfds[1], "foo\nbar\n", 8)); + EXPECT_SYS(0, 0, close(pfds[1])); + EXPECT_SYS(0, 0, close(0)); + EXPECT_SYS(0, 0, dup(pfds[0])); + EXPECT_SYS(0, 0, close(pfds[0])); + EXPECT_STREQ("foo\n", fgetln(stdin, 0)); + EXPECT_STREQ("bar\n", fgetln(stdin, 0)); + EXPECT_EQ(NULL, fgetln(stdin, 0)); + EXPECT_FALSE(ferror(stdin)); + EXPECT_TRUE(feof(stdin)); + EXPECT_SYS(0, 0, close(0)); + EXPECT_SYS(0, 0, dup(oldstdin)); + clearerr(stdin); +} + +BENCH(fgetln, bench) { + FILE *f = fmemopen(gc(strdup(kHyperion)), kHyperionSize, "r+"); + EZBENCH2("fgetln", donothing, fgetln(f, 0)); + EZBENCH2("xgetline", donothing, free(xgetline(f))); + fclose(f); +} diff --git a/third_party/libcxx/errno.h b/third_party/libcxx/errno.h index 00d7f7f83..1dfe334b6 100644 --- a/third_party/libcxx/errno.h +++ b/third_party/libcxx/errno.h @@ -78,320 +78,6 @@ static const int __elast2 = 105; // supply errno values likely to be missing, particularly on Windows -#ifndef EAFNOSUPPORT -#define EAFNOSUPPORT 9901 -#endif - -#ifndef EADDRINUSE -#define EADDRINUSE 9902 -#endif - -#ifndef EADDRNOTAVAIL -#define EADDRNOTAVAIL 9903 -#endif - -#ifndef EISCONN -#define EISCONN 9904 -#endif - -#ifndef EBADMSG -#define EBADMSG 9905 -#endif - -#ifndef ECONNABORTED -#define ECONNABORTED 9906 -#endif - -#ifndef EALREADY -#define EALREADY 9907 -#endif - -#ifndef ECONNREFUSED -#define ECONNREFUSED 9908 -#endif - -#ifndef ECONNRESET -#define ECONNRESET 9909 -#endif - -#ifndef EDESTADDRREQ -#define EDESTADDRREQ 9910 -#endif - -#ifndef EHOSTUNREACH -#define EHOSTUNREACH 9911 -#endif - -#ifndef EIDRM -#define EIDRM 9912 -#endif - -#ifndef EMSGSIZE -#define EMSGSIZE 9913 -#endif - -#ifndef ENETDOWN -#define ENETDOWN 9914 -#endif - -#ifndef ENETRESET -#define ENETRESET 9915 -#endif - -#ifndef ENETUNREACH -#define ENETUNREACH 9916 -#endif - -#ifndef ENOBUFS -#define ENOBUFS 9917 -#endif - -#ifndef ENOLINK -#define ENOLINK 9918 -#endif - -#ifndef ENODATA -#define ENODATA 9919 -#endif - -#ifndef ENOMSG -#define ENOMSG 9920 -#endif - -#ifndef ENOPROTOOPT -#define ENOPROTOOPT 9921 -#endif - -#ifndef ENOSR -#define ENOSR 9922 -#endif - -#ifndef ENOTSOCK -#define ENOTSOCK 9923 -#endif - -#ifndef ENOSTR -#define ENOSTR 9924 -#endif - -#ifndef ENOTCONN -#define ENOTCONN 9925 -#endif - -#ifndef ENOTSUP -#define ENOTSUP 9926 -#endif - -#ifndef ECANCELED -#define ECANCELED 9927 -#endif - -#ifndef EINPROGRESS -#define EINPROGRESS 9928 -#endif - -#ifndef EOPNOTSUPP -#define EOPNOTSUPP 9929 -#endif - -#ifndef EWOULDBLOCK -#define EWOULDBLOCK 9930 -#endif - -#ifndef EOWNERDEAD -#define EOWNERDEAD 9931 -#endif - -#ifndef EPROTO -#define EPROTO 9932 -#endif - -#ifndef EPROTONOSUPPORT -#define EPROTONOSUPPORT 9933 -#endif - -#ifndef ENOTRECOVERABLE -#define ENOTRECOVERABLE 9934 -#endif - -#ifndef ETIME -#define ETIME 9935 -#endif - -#ifndef ETXTBSY -#define ETXTBSY 9936 -#endif - -#ifndef ETIMEDOUT -#define ETIMEDOUT 9938 -#endif - -#ifndef ELOOP -#define ELOOP 9939 -#endif - -#ifndef EOVERFLOW -#define EOVERFLOW 9940 -#endif - -#ifndef EPROTOTYPE -#define EPROTOTYPE 9941 -#endif - -#ifndef ENOSYS -#define ENOSYS 9942 -#endif - -#ifndef EINVAL -#define EINVAL 9943 -#endif - -#ifndef ERANGE -#define ERANGE 9944 -#endif - -#ifndef EILSEQ -#define EILSEQ 9945 -#endif - -// Windows Mobile doesn't appear to define these: - -#ifndef E2BIG -#define E2BIG 9946 -#endif - -#ifndef EDOM -#define EDOM 9947 -#endif - -#ifndef EFAULT -#define EFAULT 9948 -#endif - -#ifndef EBADF -#define EBADF 9949 -#endif - -#ifndef EPIPE -#define EPIPE 9950 -#endif - -#ifndef EXDEV -#define EXDEV 9951 -#endif - -#ifndef EBUSY -#define EBUSY 9952 -#endif - -#ifndef ENOTEMPTY -#define ENOTEMPTY 9953 -#endif - -#ifndef ENOEXEC -#define ENOEXEC 9954 -#endif - -#ifndef EEXIST -#define EEXIST 9955 -#endif - -#ifndef EFBIG -#define EFBIG 9956 -#endif - -#ifndef ENAMETOOLONG -#define ENAMETOOLONG 9957 -#endif - -#ifndef ENOTTY -#define ENOTTY 9958 -#endif - -#ifndef EINTR -#define EINTR 9959 -#endif - -#ifndef ESPIPE -#define ESPIPE 9960 -#endif - -#ifndef EIO -#define EIO 9961 -#endif - -#ifndef EISDIR -#define EISDIR 9962 -#endif - -#ifndef ECHILD -#define ECHILD 9963 -#endif - -#ifndef ENOLCK -#define ENOLCK 9964 -#endif - -#ifndef ENOSPC -#define ENOSPC 9965 -#endif - -#ifndef ENXIO -#define ENXIO 9966 -#endif - -#ifndef ENODEV -#define ENODEV 9967 -#endif - -#ifndef ENOENT -#define ENOENT 9968 -#endif - -#ifndef ESRCH -#define ESRCH 9969 -#endif - -#ifndef ENOTDIR -#define ENOTDIR 9970 -#endif - -#ifndef ENOMEM -#define ENOMEM 9971 -#endif - -#ifndef EPERM -#define EPERM 9972 -#endif - -#ifndef EACCES -#define EACCES 9973 -#endif - -#ifndef EROFS -#define EROFS 9974 -#endif - -#ifndef EDEADLK -#define EDEADLK 9975 -#endif - -#ifndef EAGAIN -#define EAGAIN 9976 -#endif - -#ifndef ENFILE -#define ENFILE 9977 -#endif - -#ifndef EMFILE -#define EMFILE 9978 -#endif - -#ifndef EMLINK -#define EMLINK 9979 -#endif - #endif // __cplusplus #endif // _LIBCPP_ERRNO_H diff --git a/third_party/lua/lrepl.c b/third_party/lua/lrepl.c index 33eb69ac4..c579add12 100644 --- a/third_party/lua/lrepl.c +++ b/third_party/lua/lrepl.c @@ -234,9 +234,9 @@ static ssize_t pushline (lua_State *L, int firstline) { ssize_t rc; char *prmt; globalL = L; + prmt = strdup(get_prompt(L, firstline)); + lua_pop(L, 1); /* remove prompt */ if (lua_repl_isterminal) { - prmt = strdup(get_prompt(L, firstline)); - lua_pop(L, 1); /* remove prompt */ LUA_REPL_UNLOCK; rc = linenoiseEdit(lua_repl_linenoise, prmt, &b, !firstline || lua_repl_blocking); free(prmt); @@ -250,9 +250,17 @@ static ssize_t pushline (lua_State *L, int firstline) { LUA_REPL_LOCK; } else { LUA_REPL_UNLOCK; + fputs(prmt, stdout); + fflush(stdout); b = linenoiseGetLine(stdin); + if (b) { + rc = 1; + } else if (ferror(stdin)) { + rc = -1; + } else { + rc = 0; + } LUA_REPL_LOCK; - rc = b ? 1 : -1; } if (!(rc == -1 && errno == EAGAIN)) { write(1, "\n", 1); diff --git a/third_party/lua/lua.main.c b/third_party/lua/lua.main.c index 73818ea0f..9a0ed28fc 100644 --- a/third_party/lua/lua.main.c +++ b/third_party/lua/lua.main.c @@ -307,7 +307,8 @@ static void doREPL (lua_State *L) { progname = NULL; /* no 'progname' on errors in interactive mode */ lua_initrepl(L, LUA_PROGNAME); for (;;) { - linenoiseEnableRawMode(0); + if (lua_repl_isterminal) + linenoiseEnableRawMode(0); TryAgain: status = lua_loadline(L); if (status == -2 && errno == EAGAIN) { @@ -315,7 +316,8 @@ static void doREPL (lua_State *L) { poll(&(struct pollfd){0, POLLIN}, 1, -1); goto TryAgain; } - linenoiseDisableRawMode(); + if (lua_repl_isterminal) + linenoiseDisableRawMode(); if (status == -1) { break; } else if (status == -2) { diff --git a/third_party/make/error.c b/third_party/make/error.c index 07bb08918..5fe39d0cc 100644 --- a/third_party/make/error.c +++ b/third_party/make/error.c @@ -57,48 +57,9 @@ void (*error_print_progname) (void); /* This variable is incremented each time 'error' is called. */ unsigned int error_message_count; -#ifdef _LIBC -/* In the GNU C library, there is a predefined variable for this. */ - -# define program_name program_invocation_name - -/* In GNU libc we want do not want to use the common name 'error' directly. - Instead make it a weak alias. */ -extern void __error (int status, int errnum, const char *message, ...) - __attribute__ ((__format__ (__printf__, 3, 4))); -extern void __error_at_line (int status, int errnum, const char *file_name, - unsigned int line_number, const char *message, - ...) - __attribute__ ((__format__ (__printf__, 5, 6))); -# define error __error -# define error_at_line __error_at_line - -# define fflush(s) _IO_fflush (s) -# undef putc -# define putc(c, fp) _IO_putc (c, fp) - - -#else /* not _LIBC */ - -# if defined _WIN32 && ! defined __CYGWIN__ -/* Get declarations of the native Windows API functions. */ -# define WIN32_LEAN_AND_MEAN -/* Get _get_osfhandle. */ -# if GNULIB_MSVC_NOTHROW -# include "msvc-nothrow.h" -# else -# endif -# endif - -/* The gnulib override of fcntl is not needed in this file. */ -# undef fcntl - -# define program_name getprogname () - -# if GNULIB_STRERROR_R_POSIX || HAVE_STRERROR_R || defined strerror_r -# define __strerror_r strerror_r -# endif /* GNULIB_STRERROR_R_POSIX || HAVE_STRERROR_R || defined strerror_r */ -#endif /* not _LIBC */ +#undef fcntl +#define program_name getprogname () +#define __strerror_r strerror_r /* Return non-zero if FD is open. */ static int diff --git a/third_party/python/Lib/test/test_doctest.py b/third_party/python/Lib/test/test_doctest.py index 6c870f0b9..d20718c4b 100644 --- a/third_party/python/Lib/test/test_doctest.py +++ b/third_party/python/Lib/test/test_doctest.py @@ -2921,7 +2921,7 @@ Invalid file name: >>> print(normalize(err)) # doctest: +ELLIPSIS Traceback (most recent call last): ... - FileNotFoundError: [Errno 2] ENOENT/2/No such file or directory: 'nosuchfile' + FileNotFoundError: [Errno 2] ENOENT... Invalid doctest option: diff --git a/third_party/python/Lib/test/test_module.py b/third_party/python/Lib/test/test_module.py index 2fbe9f1ce..81dccd2e8 100644 --- a/third_party/python/Lib/test/test_module.py +++ b/third_party/python/Lib/test/test_module.py @@ -29,7 +29,7 @@ class ModuleTests(unittest.TestCase): self.fail("__name__ = %s" % repr(s)) except AttributeError: pass - if cosmo.MODE != 'tiny': + if 'tiny' not in cosmo.MODE: self.assertEqual(foo.__doc__, ModuleType.__doc__) def test_uninitialized_missing_getattr(self): diff --git a/third_party/python/Modules/socketmodule.c b/third_party/python/Modules/socketmodule.c index 81bef83d5..4f5234fa1 100644 --- a/third_party/python/Modules/socketmodule.c +++ b/third_party/python/Modules/socketmodule.c @@ -12,6 +12,7 @@ #include "libc/dns/ent.h" #include "libc/errno.h" #include "libc/nt/enum/version.h" +#include "libc/nt/version.h" #include "libc/runtime/runtime.h" #include "libc/sock/sock.h" #include "libc/sysv/consts/af.h" @@ -7146,9 +7147,9 @@ PyInit__socket(void) if (TCP_USER_TIMEOUT) PyModule_AddIntMacro(m, TCP_USER_TIMEOUT); if (TCP_SAVE_SYN) PyModule_AddIntMacro(m, TCP_SAVE_SYN); if (TCP_SAVED_SYN) PyModule_AddIntMacro(m, TCP_SAVED_SYN); - if (TCP_KEEPCNT && (!IsWindows() || NtGetVersion() >= kNtVersionWindows10)) + if (TCP_KEEPCNT && (!IsWindows() || IsAtLeastWindows10())) PyModule_AddIntMacro(m, TCP_KEEPCNT); - if (TCP_FASTOPEN && (!IsWindows() || NtGetVersion() >= kNtVersionWindows10)) + if (TCP_FASTOPEN && (!IsWindows() || IsAtLeastWindows10())) PyModule_AddIntMacro(m, TCP_FASTOPEN); if (TCP_FASTOPEN_CONNECT) PyModule_AddIntMacro(m, TCP_FASTOPEN_CONNECT); diff --git a/tool/net/help.txt b/tool/net/help.txt index 15814bd41..5a2630317 100644 --- a/tool/net/help.txt +++ b/tool/net/help.txt @@ -2791,6 +2791,9 @@ UNIX MODULE unix.sigaction(unix.SIGALRM, MyOnSigAlrm, unix.SA_RESETHAND) unix.setitimer(unix.ITIMER_REAL, 0, 0, 1, 0) + `intns` needs to be on the interval `[0,1000000000)` + `valuens` needs to be on the interval `[0,1000000000)` + unix.strsignal(sig:int) → str Turns platform-specific `sig` code into its symbolic name. diff --git a/tool/net/redbean.c b/tool/net/redbean.c index bf44a8800..03967ce58 100644 --- a/tool/net/redbean.c +++ b/tool/net/redbean.c @@ -16,151 +16,92 @@ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ -#include "dsp/scale/cdecimate2xuint8x8.h" #include "libc/bits/atomic.h" -#include "libc/bits/bits.h" -#include "libc/bits/likely.h" -#include "libc/bits/popcnt.h" #include "libc/bits/safemacros.internal.h" #include "libc/calls/calls.h" #include "libc/calls/ioctl.h" #include "libc/calls/math.h" #include "libc/calls/sigbits.h" -#include "libc/calls/strace.internal.h" -#include "libc/calls/struct/dirent.h" #include "libc/calls/struct/filter.h" #include "libc/calls/struct/flock.h" +#include "libc/calls/struct/iovec.h" #include "libc/calls/struct/rusage.h" #include "libc/calls/struct/sigaction.h" #include "libc/calls/struct/stat.h" #include "libc/calls/struct/termios.h" -#include "libc/calls/ttydefaults.h" -#include "libc/dce.h" #include "libc/dns/dns.h" #include "libc/dns/hoststxt.h" #include "libc/dos.h" -#include "libc/errno.h" #include "libc/fmt/conv.h" -#include "libc/fmt/fmt.h" #include "libc/fmt/itoa.h" -#include "libc/intrin/kprintf.h" #include "libc/intrin/nomultics.internal.h" -#include "libc/intrin/spinlock.h" -#include "libc/log/backtrace.internal.h" #include "libc/log/check.h" #include "libc/log/log.h" -#include "libc/macros.internal.h" #include "libc/math.h" #include "libc/mem/alloca.h" -#include "libc/mem/fmt.h" -#include "libc/mem/mem.h" -#include "libc/nexgen32e/bsf.h" #include "libc/nexgen32e/bsr.h" #include "libc/nexgen32e/crc32.h" #include "libc/nexgen32e/nt2sysv.h" #include "libc/nexgen32e/rdtsc.h" -#include "libc/nexgen32e/rdtscp.h" #include "libc/nexgen32e/threaded.h" +#include "libc/nexgen32e/x86feature.h" #include "libc/nt/enum/fileflagandattributes.h" -#include "libc/nt/runtime.h" #include "libc/nt/thread.h" -#include "libc/nt/version.h" #include "libc/rand/rand.h" #include "libc/runtime/clktck.h" -#include "libc/runtime/directmap.internal.h" #include "libc/runtime/gc.h" #include "libc/runtime/gc.internal.h" -#include "libc/runtime/internal.h" -#include "libc/runtime/memtrack.internal.h" -#include "libc/runtime/runtime.h" #include "libc/runtime/stack.h" -#include "libc/runtime/symbols.internal.h" #include "libc/sock/goodsocket.internal.h" #include "libc/sock/sock.h" #include "libc/stdio/append.internal.h" #include "libc/stdio/hex.internal.h" -#include "libc/stdio/stdio.h" #include "libc/str/slice.h" -#include "libc/str/str.h" #include "libc/str/undeflate.h" #include "libc/sysv/consts/af.h" -#include "libc/sysv/consts/audit.h" -#include "libc/sysv/consts/auxv.h" #include "libc/sysv/consts/clone.h" #include "libc/sysv/consts/dt.h" #include "libc/sysv/consts/ex.h" #include "libc/sysv/consts/exit.h" #include "libc/sysv/consts/f.h" -#include "libc/sysv/consts/grnd.h" #include "libc/sysv/consts/inaddr.h" #include "libc/sysv/consts/ipproto.h" -#include "libc/sysv/consts/lock.h" -#include "libc/sysv/consts/madv.h" #include "libc/sysv/consts/map.h" -#include "libc/sysv/consts/msync.h" -#include "libc/sysv/consts/nr.h" #include "libc/sysv/consts/o.h" #include "libc/sysv/consts/poll.h" #include "libc/sysv/consts/pr.h" #include "libc/sysv/consts/prot.h" #include "libc/sysv/consts/rusage.h" -#include "libc/sysv/consts/s.h" #include "libc/sysv/consts/sa.h" -#include "libc/sysv/consts/shut.h" #include "libc/sysv/consts/sig.h" -#include "libc/sysv/consts/so.h" #include "libc/sysv/consts/sock.h" -#include "libc/sysv/consts/sol.h" -#include "libc/sysv/consts/tcp.h" #include "libc/sysv/consts/termios.h" #include "libc/sysv/consts/w.h" #include "libc/sysv/errfuns.h" -#include "libc/testlib/testlib.h" -#include "libc/time/time.h" #include "libc/x/x.h" #include "libc/zip.h" #include "net/http/escape.h" #include "net/http/http.h" #include "net/http/ip.h" -#include "net/http/url.h" #include "net/https/https.h" #include "third_party/getopt/getopt.h" -#include "third_party/linenoise/linenoise.h" #include "third_party/lua/cosmo.h" #include "third_party/lua/lauxlib.h" #include "third_party/lua/lrepl.h" -#include "third_party/lua/ltests.h" -#include "third_party/lua/lua.h" -#include "third_party/lua/luaconf.h" #include "third_party/lua/lualib.h" -#include "third_party/mbedtls/asn1.h" -#include "third_party/mbedtls/asn1write.h" -#include "third_party/mbedtls/cipher.h" -#include "third_party/mbedtls/config.h" #include "third_party/mbedtls/ctr_drbg.h" #include "third_party/mbedtls/debug.h" -#include "third_party/mbedtls/ecp.h" -#include "third_party/mbedtls/entropy.h" -#include "third_party/mbedtls/entropy_poll.h" -#include "third_party/mbedtls/error.h" #include "third_party/mbedtls/iana.h" -#include "third_party/mbedtls/md.h" -#include "third_party/mbedtls/md5.h" #include "third_party/mbedtls/net_sockets.h" #include "third_party/mbedtls/oid.h" -#include "third_party/mbedtls/pk.h" -#include "third_party/mbedtls/rsa.h" #include "third_party/mbedtls/san.h" -#include "third_party/mbedtls/sha1.h" #include "third_party/mbedtls/ssl.h" #include "third_party/mbedtls/ssl_ticket.h" #include "third_party/mbedtls/x509.h" #include "third_party/mbedtls/x509_crt.h" -#include "third_party/regex/regex.h" #include "third_party/zlib/zlib.h" #include "tool/args/args.h" #include "tool/build/lib/case.h" -#include "tool/build/lib/psk.h" #include "tool/net/lfuncs.h" #include "tool/net/luacheck.h" #include "tool/net/sandbox.h" @@ -441,12 +382,14 @@ static int mainpid; static int sandboxed; static int changeuid; static int changegid; -static int monitortid; static int isyielding; static int statuscode; static int shutdownsig; static int sslpskindex; static int oldloglevel; +static int *monitortid; +static char *monitortls; +static char *monitorstack; static int maxpayloadsize; static int messageshandled; static int sslticketlifetime; @@ -6393,7 +6336,7 @@ static int ExitWorker(void) { } if (monitortty) { terminatemonitor = true; - _spinlock(&monitortid); + _spinlock(monitortid); } _Exit(0); } @@ -6649,19 +6592,23 @@ static int MemoryMonitor(void *arg) { } static void MonitorMemory(void) { - char *tls; - monitortid = -1; - tls = __initialize_tls(malloc(64)); - __cxa_atexit(free, tls, 0); - if (clone(MemoryMonitor, - mmap(0, GetStackSize(), PROT_READ | PROT_WRITE, - MAP_STACK | MAP_ANONYMOUS, -1, 0), - GetStackSize(), - CLONE_VM | CLONE_THREAD | CLONE_FS | CLONE_FILES | CLONE_SIGHAND | - CLONE_SETTLS | CLONE_CHILD_SETTID | CLONE_CHILD_CLEARTID, - 0, 0, tls, 64, &monitortid) == -1) { - monitortid = 0; + if ((monitortls = __initialize_tls(malloc(64)))) { + if ((monitorstack = mmap(0, GetStackSize(), PROT_READ | PROT_WRITE, + MAP_STACK | MAP_ANONYMOUS, -1, 0)) != MAP_FAILED) { + monitortid = (int *)(monitortls + 0x38); + if ((*monitortid = + clone(MemoryMonitor, monitorstack, GetStackSize(), + CLONE_VM | CLONE_THREAD | CLONE_FS | CLONE_FILES | + CLONE_SIGHAND | CLONE_SETTLS | CLONE_CHILD_CLEARTID, + 0, 0, monitortls, 64, monitortid)) != -1) { + return; + } + munmap(monitorstack, GetStackSize()); + } + free(monitortls); } + WARNF("(memv) failed to start memory monitor %m"); + monitortty = 0; } static int HandleConnection(size_t i) { @@ -7327,7 +7274,9 @@ void RedBean(int argc, char *argv[]) { } if (monitortty) { terminatemonitor = true; - _spinlock(&monitortid); + _spinlock(monitortid); + munmap(monitorstack, GetStackSize()); + free(monitortls); } INFOF("(srvr) shutdown complete"); }