From de5de19004d2888034b508e2958a9307036ef38b Mon Sep 17 00:00:00 2001 From: Justine Tunney Date: Fri, 27 May 2022 13:25:46 -0700 Subject: [PATCH] Make improvements - Document redbean's argon2 module - Fix regressions in cthreads library - Make testlib work better with threads - Give the cthreads library lots of love - Remove some of the stdio assembly code - Implement getloadavg() across platforms - Code size optimizations for errnos, etc. - Only check for signals in main thread on Windows - Make errnos for dup2 / dup3 consistent with posix This change also fixes a bug in the argon2 module, where the NUL terminator was being included in the hash encoded ascii string. This shouldn't require any database migrations to folks who found this module and productionized it, since the argon2 library treats it as a c string. --- ape/ape.lds | 53 +++-- examples/cosh.c | 2 +- examples/thread.c | 56 ++--- examples/tls.c | 15 ++ libc/calls/calls.h | 1 + libc/calls/close.c | 14 +- libc/calls/dup-nt.c | 3 +- libc/calls/dup.c | 23 +- libc/calls/dup2.c | 26 ++- libc/calls/dup3-sysv.c | 20 +- libc/calls/dup3.c | 18 +- libc/calls/g_sighandrvas.c | 2 +- libc/{runtime => calls}/getcpucount.c | 0 libc/calls/getloadavg-nt.c | 71 ++++++ libc/calls/getloadavg.c | 54 ++++- libc/calls/getrusage-nt.c | 4 +- libc/calls/interrupts-nt.c | 24 +- libc/calls/loadavg-nt.c | 97 -------- libc/calls/loadavg.internal.h | 10 - libc/calls/sig.c | 4 +- libc/calls/sig.internal.h | 2 + libc/calls/sig2.c | 39 ++-- libc/calls/sigaction.c | 5 +- libc/calls/siglock.c | 30 +++ libc/calls/state.internal.h | 2 +- libc/calls/syscall-nt.internal.h | 1 + libc/calls/sysinfo-nt.c | 4 - libc/intrin/exit1.greg.c | 8 +- libc/intrin/tls.greg.c | 23 +- .../longerjmp.S} | 26 ++- libc/nexgen32e/setlongerjmp.S | 41 ++++ libc/nexgen32e/threaded.c | 7 +- libc/nexgen32e/threaded.h | 2 +- libc/nt/accounting.h | 3 + libc/nt/kernel32/GetSystemTimes.s | 10 + libc/nt/master.sh | 2 +- libc/runtime/clone.c | 34 +-- libc/runtime/internal.h | 7 + libc/runtime/mmap.c | 13 +- libc/runtime/runtime.h | 2 + libc/stdio/clearerr.c | 13 +- .../feof_unlocked.S => clearerr_unlocked.c} | 19 +- libc/stdio/feof.c | 12 +- .../ferror_unlocked.S => feof_unlocked.c} | 25 +- libc/stdio/ferror.c | 13 +- libc/stdio/ferror_unlocked.c | 31 +++ libc/stdio/fgetc.c | 18 +- libc/stdio/fgetc_unlocked.c | 36 +++ libc/stdio/fgets.c | 28 +-- libc/stdio/fgets_unlocked.c | 54 +++++ libc/stdio/fgetwc.c | 36 +-- libc/stdio/fgetwc_unlocked.c | 51 +++++ libc/stdio/unlocked/fgets_unlocked.S | 37 --- libc/stdio/unlocked/fgetwc_unlocked.S | 30 --- libc/stubs/ld.S | 18 +- libc/sysv/consts.sh | 18 +- libc/sysv/consts/FUTEX_PRIVATE_FLAG.S | 2 +- libc/sysv/consts/FUTEX_REQUEUE.S | 2 +- libc/sysv/consts/FUTEX_REQUEUE_PRIVATE.S | 2 - libc/sysv/consts/FUTEX_WAIT.S | 2 +- libc/sysv/consts/FUTEX_WAIT_PRIVATE.S | 2 - libc/sysv/consts/FUTEX_WAKE.S | 2 +- libc/sysv/consts/FUTEX_WAKE_PRIVATE.S | 2 - libc/sysv/consts/futex.h | 17 +- .../clearerr_unlocked.S => sysv/errfun.S} | 20 +- libc/sysv/errfuns/e2big.S | 9 +- libc/sysv/errfuns/eacces.S | 9 +- libc/sysv/errfuns/eaddrinuse.S | 9 +- libc/sysv/errfuns/eaddrnotavail.S | 9 +- libc/sysv/errfuns/eadv.S | 9 +- libc/sysv/errfuns/eafnosupport.S | 9 +- libc/sysv/errfuns/eagain.S | 9 +- libc/sysv/errfuns/ealready.S | 9 +- libc/sysv/errfuns/ebade.S | 9 +- libc/sysv/errfuns/ebadf.S | 9 +- libc/sysv/errfuns/ebadfd.S | 9 +- libc/sysv/errfuns/ebadmsg.S | 9 +- libc/sysv/errfuns/ebadr.S | 9 +- libc/sysv/errfuns/ebadrqc.S | 9 +- libc/sysv/errfuns/ebadslt.S | 9 +- libc/sysv/errfuns/ebusy.S | 9 +- libc/sysv/errfuns/ecanceled.S | 9 +- libc/sysv/errfuns/echild.S | 9 +- libc/sysv/errfuns/echrng.S | 9 +- libc/sysv/errfuns/ecomm.S | 9 +- libc/sysv/errfuns/econnaborted.S | 9 +- libc/sysv/errfuns/econnrefused.S | 9 +- libc/sysv/errfuns/econnreset.S | 9 +- libc/sysv/errfuns/edeadlk.S | 9 +- libc/sysv/errfuns/edestaddrreq.S | 9 +- libc/sysv/errfuns/edom.S | 9 +- libc/sysv/errfuns/edotdot.S | 9 +- libc/sysv/errfuns/edquot.S | 9 +- libc/sysv/errfuns/eexist.S | 9 +- libc/sysv/errfuns/efault.S | 9 +- libc/sysv/errfuns/efbig.S | 9 +- libc/sysv/errfuns/ehostdown.S | 9 +- libc/sysv/errfuns/ehostunreach.S | 9 +- libc/sysv/errfuns/ehwpoison.S | 9 +- libc/sysv/errfuns/eidrm.S | 9 +- libc/sysv/errfuns/eilseq.S | 9 +- libc/sysv/errfuns/einprogress.S | 9 +- libc/sysv/errfuns/eintr.S | 9 +- libc/sysv/errfuns/einval.S | 9 +- libc/sysv/errfuns/eio.S | 9 +- libc/sysv/errfuns/eisconn.S | 9 +- libc/sysv/errfuns/eisdir.S | 9 +- libc/sysv/errfuns/eisnam.S | 9 +- libc/sysv/errfuns/ekeyexpired.S | 9 +- libc/sysv/errfuns/ekeyrejected.S | 9 +- libc/sysv/errfuns/ekeyrevoked.S | 9 +- libc/sysv/errfuns/el2hlt.S | 9 +- libc/sysv/errfuns/el2nsync.S | 9 +- libc/sysv/errfuns/el3hlt.S | 9 +- libc/sysv/errfuns/el3rst.S | 9 +- libc/sysv/errfuns/elibacc.S | 9 +- libc/sysv/errfuns/elibbad.S | 9 +- libc/sysv/errfuns/elibexec.S | 9 +- libc/sysv/errfuns/elibmax.S | 9 +- libc/sysv/errfuns/elibscn.S | 9 +- libc/sysv/errfuns/elnrng.S | 9 +- libc/sysv/errfuns/eloop.S | 9 +- libc/sysv/errfuns/emediumtype.S | 9 +- libc/sysv/errfuns/emfile.S | 9 +- libc/sysv/errfuns/emlink.S | 9 +- libc/sysv/errfuns/emsgsize.S | 9 +- libc/sysv/errfuns/emultihop.S | 9 +- libc/sysv/errfuns/enametoolong.S | 9 +- libc/sysv/errfuns/enavail.S | 9 +- libc/sysv/errfuns/enetdown.S | 9 +- libc/sysv/errfuns/enetreset.S | 9 +- libc/sysv/errfuns/enetunreach.S | 9 +- libc/sysv/errfuns/enfile.S | 9 +- libc/sysv/errfuns/enoano.S | 9 +- libc/sysv/errfuns/enobufs.S | 9 +- libc/sysv/errfuns/enocsi.S | 9 +- libc/sysv/errfuns/enodata.S | 9 +- libc/sysv/errfuns/enodev.S | 9 +- libc/sysv/errfuns/enoent.S | 9 +- libc/sysv/errfuns/enoexec.S | 9 +- libc/sysv/errfuns/enokey.S | 9 +- libc/sysv/errfuns/enolck.S | 9 +- libc/sysv/errfuns/enolink.S | 9 +- libc/sysv/errfuns/enomedium.S | 9 +- libc/sysv/errfuns/enomem.S | 9 +- libc/sysv/errfuns/enomsg.S | 9 +- libc/sysv/errfuns/enonet.S | 9 +- libc/sysv/errfuns/enopkg.S | 9 +- libc/sysv/errfuns/enoprotoopt.S | 9 +- libc/sysv/errfuns/enospc.S | 9 +- libc/sysv/errfuns/enosr.S | 9 +- libc/sysv/errfuns/enostr.S | 9 +- libc/sysv/errfuns/enosys.S | 9 +- libc/sysv/errfuns/enotblk.S | 9 +- libc/sysv/errfuns/enotconn.S | 9 +- libc/sysv/errfuns/enotdir.S | 9 +- libc/sysv/errfuns/enotempty.S | 9 +- libc/sysv/errfuns/enotnam.S | 9 +- libc/sysv/errfuns/enotrecoverable.S | 9 +- libc/sysv/errfuns/enotsock.S | 9 +- libc/sysv/errfuns/enotsup.S | 9 +- libc/sysv/errfuns/enotty.S | 9 +- libc/sysv/errfuns/enotuniq.S | 9 +- libc/sysv/errfuns/enxio.S | 9 +- libc/sysv/errfuns/eopnotsupp.S | 9 +- libc/sysv/errfuns/eoverflow.S | 9 +- libc/sysv/errfuns/eownerdead.S | 9 +- libc/sysv/errfuns/eperm.S | 9 +- libc/sysv/errfuns/epfnosupport.S | 9 +- libc/sysv/errfuns/epipe.S | 9 +- libc/sysv/errfuns/eproto.S | 9 +- libc/sysv/errfuns/eprotonosupport.S | 9 +- libc/sysv/errfuns/eprototype.S | 9 +- libc/sysv/errfuns/erange.S | 9 +- libc/sysv/errfuns/eremchg.S | 9 +- libc/sysv/errfuns/eremote.S | 9 +- libc/sysv/errfuns/eremoteio.S | 9 +- libc/sysv/errfuns/erestart.S | 9 +- libc/sysv/errfuns/erfkill.S | 9 +- libc/sysv/errfuns/erofs.S | 9 +- libc/sysv/errfuns/eshutdown.S | 9 +- libc/sysv/errfuns/esocktnosupport.S | 9 +- libc/sysv/errfuns/espipe.S | 9 +- libc/sysv/errfuns/esrch.S | 9 +- libc/sysv/errfuns/esrmnt.S | 9 +- libc/sysv/errfuns/estale.S | 9 +- libc/sysv/errfuns/estrpipe.S | 9 +- libc/sysv/errfuns/etime.S | 9 +- libc/sysv/errfuns/etimedout.S | 9 +- libc/sysv/errfuns/etoomanyrefs.S | 9 +- libc/sysv/errfuns/etxtbsy.S | 9 +- libc/sysv/errfuns/euclean.S | 9 +- libc/sysv/errfuns/eunatch.S | 9 +- libc/sysv/errfuns/eusers.S | 9 +- libc/sysv/errfuns/exdev.S | 9 +- libc/sysv/errfuns/exfull.S | 9 +- libc/sysv/gen.sh | 8 +- libc/sysv/sysv.mk | 1 + libc/testlib/quota.c | 7 +- libc/testlib/showerror.c | 16 +- libc/testlib/testrunner.c | 4 +- libc/thread/attr.c | 7 +- libc/thread/create.c | 181 ++++++++------- libc/thread/create.h | 4 +- libc/thread/descriptor.h | 24 +- libc/thread/detach.c | 45 +++- libc/thread/exit.c | 20 +- libc/thread/exit.h | 6 +- libc/thread/init.c | 68 +++--- libc/thread/join.c | 77 ++++--- libc/thread/join.h | 6 +- libc/thread/self.c | 11 +- libc/thread/self.h | 15 +- libc/thread/sem.c | 33 ++- libc/thread/sem.h | 16 +- libc/thread/thread.mk | 44 ++-- libc/thread/wait.c | 38 ++- libc/thread/yield.c | 3 + libc/thread/zombie.c | 50 ++++ libc/thread/zombie.h | 12 + test/libc/calls/dup_test.c | 23 ++ test/libc/calls/stat_test.c | 4 + test/libc/runtime/clone_test.c | 94 ++++++-- test/libc/runtime/mmap_test.c | 6 - test/net/https/argon2_test.c | 49 +++- third_party/argon2/argon2.mk | 5 +- third_party/lua/lrepl.c | 5 +- third_party/lua/lua.main.c | 1 - third_party/make/dup2.c | 216 ------------------ third_party/make/make.mk | 1 - tool/build/wastecpu.c | 77 +++++++ tool/emacs/ld-script.el | 4 +- tool/net/help.txt | 67 ++++++ tool/net/largon2.c | 46 +--- 234 files changed, 1728 insertions(+), 1993 deletions(-) create mode 100644 examples/tls.c rename libc/{runtime => calls}/getcpucount.c (100%) create mode 100644 libc/calls/getloadavg-nt.c delete mode 100644 libc/calls/loadavg-nt.c delete mode 100644 libc/calls/loadavg.internal.h create mode 100644 libc/calls/siglock.c rename libc/{stdio/unlocked/fgetc_unlocked.S => nexgen32e/longerjmp.S} (83%) create mode 100644 libc/nexgen32e/setlongerjmp.S rename libc/stdio/{unlocked/feof_unlocked.S => clearerr_unlocked.c} (79%) rename libc/stdio/{unlocked/ferror_unlocked.S => feof_unlocked.c} (79%) create mode 100644 libc/stdio/ferror_unlocked.c create mode 100644 libc/stdio/fgetc_unlocked.c create mode 100644 libc/stdio/fgets_unlocked.c create mode 100644 libc/stdio/fgetwc_unlocked.c delete mode 100644 libc/stdio/unlocked/fgets_unlocked.S delete mode 100644 libc/stdio/unlocked/fgetwc_unlocked.S delete mode 100644 libc/sysv/consts/FUTEX_REQUEUE_PRIVATE.S delete mode 100644 libc/sysv/consts/FUTEX_WAIT_PRIVATE.S delete mode 100644 libc/sysv/consts/FUTEX_WAKE_PRIVATE.S rename libc/{stdio/unlocked/clearerr_unlocked.S => sysv/errfun.S} (87%) create mode 100644 libc/thread/zombie.c create mode 100644 libc/thread/zombie.h delete mode 100644 third_party/make/dup2.c create mode 100644 tool/build/wastecpu.c diff --git a/ape/ape.lds b/ape/ape.lds index e97b96058..54b449d75 100644 --- a/ape/ape.lds +++ b/ape/ape.lds @@ -185,10 +185,12 @@ ENTRY(_start) PHDRS { - Head PT_LOAD FLAGS(5); - Rom PT_LOAD FLAGS(5); - Ram PT_LOAD FLAGS(6); - stack PT_GNU_STACK FLAGS(6); + Head PT_LOAD FLAGS(PF_X|PF_R); + Rom PT_LOAD FLAGS(PF_X|PF_R); + Ram PT_LOAD FLAGS(PF_W|PF_R); + Tls PT_TLS FLAGS(PF_W|PF_R); + Bss PT_LOAD FLAGS(PF_W|PF_R); + stack PT_GNU_STACK FLAGS(PF_W|PF_R); } SECTIONS { @@ -348,20 +350,7 @@ SECTIONS { /*END: Read Only Data */ } :Rom - .tdata . : { - _tdata_start = .; - *(SORT_BY_ALIGNMENT(.tdata)) - *(SORT_BY_ALIGNMENT(.tdata.*)) - _tdata_end = .; - } - .tbss . : { - _tbss_start = .; - *(SORT_BY_ALIGNMENT(.tbss)) - *(SORT_BY_ALIGNMENT(.tbss.*)) - _tbss_end = .; - } - - .data . : { + .data ALIGN(PAGESIZE) : { /*BEGIN: Read/Write Data */ KEEP(*(SORT_BY_NAME(.piro.data.sort.iat.*))) /*BEGIN: NT FORK COPYING */ @@ -387,18 +376,29 @@ SECTIONS { KEEP(*(.piro.pad.data)) KEEP(*(.dataepilogue)) /*END: NT FORK COPYING */ - . = ALIGN(PAGESIZE); HIDDEN(_edata = .); PROVIDE_HIDDEN(edata = .); + KEEP(*(SORT_BY_NAME(.zip.*))) + HIDDEN(_ezip = .); } :Ram + .tdata . : { + _tdata_start = .; + *(SORT_BY_ALIGNMENT(.tdata)) + *(SORT_BY_ALIGNMENT(.tdata.*)) + _tdata_end = .; + . = ALIGN(PAGESIZE); + } :Tls + /*END: file content that's loaded by o/s */ /*BEGIN: bss memory void */ - .zip . : { - KEEP(*(SORT_BY_NAME(.zip.*))) - HIDDEN(_ezip = .); - } + .tbss . : { + _tbss_start = .; + *(SORT_BY_ALIGNMENT(.tbss)) + *(SORT_BY_ALIGNMENT(.tbss.*)) + _tbss_end = .; + } :Tls /*END: file content */ /*BEGIN: bss memory that's addressable */ @@ -425,7 +425,7 @@ SECTIONS { . = ALIGN(FRAMESIZE); /* for brk()/sbrk() allocation */ HIDDEN(_end = .); PROVIDE_HIDDEN(end = .); - } + } :Bss /*END: nt addressability guarantee */ /*END: bsd addressability guarantee */ @@ -481,6 +481,9 @@ PFSTUB4(ape_elf_phnum, (ape_phdrs_end - ape_phdrs) / 56); PFSTUB4(ape_elf_shnum, 0); PFSTUB4(ape_elf_shstrndx, 0); +HIDDEN(_tdata_size = _tdata_end - _tdata_start); +HIDDEN(_tls_size = _tbss_end - _tdata_start); + HIDDEN(__privileged_addr = ROUNDDOWN(__privileged_start, PAGESIZE)); HIDDEN(__privileged_size = (ROUNDUP(__privileged_end, PAGESIZE) - ROUNDDOWN(__privileged_start, PAGESIZE))); @@ -496,7 +499,7 @@ HIDDEN(ape_rom_rva = RVA(ape_rom_vaddr)); HIDDEN(ape_ram_offset = ape_rom_offset + ape_rom_filesz); HIDDEN(ape_ram_vaddr = ADDR(.data)); HIDDEN(ape_ram_paddr = LOADADDR(.data)); -HIDDEN(ape_ram_filesz = SIZEOF(.data)); +HIDDEN(ape_ram_filesz = SIZEOF(.data) + SIZEOF(.tdata)); HIDDEN(ape_ram_memsz = ADDR(.bss) + SIZEOF(.bss) - ape_ram_vaddr); HIDDEN(ape_ram_align = PAGESIZE); HIDDEN(ape_ram_rva = RVA(ape_ram_vaddr)); diff --git a/examples/cosh.c b/examples/cosh.c index 822fdb4d3..9e0126ab5 100644 --- a/examples/cosh.c +++ b/examples/cosh.c @@ -303,9 +303,9 @@ int main(int argc, char *argv[]) { } MakePrompt(p); + sigprocmask(SIG_SETMASK, &savemask, 0); sigaction(SIGINT, &saveint, 0); sigaction(SIGQUIT, &savequit, 0); - sigprocmask(SIG_SETMASK, &savemask, 0); } else { fprintf(stderr, "%s: %s: command not found\n", argv[0], args[0]); } diff --git a/examples/thread.c b/examples/thread.c index 2f9c55523..ed51bbdc4 100644 --- a/examples/thread.c +++ b/examples/thread.c @@ -8,56 +8,58 @@ ╚─────────────────────────────────────────────────────────────────*/ #endif #include "libc/calls/calls.h" +#include "libc/intrin/kprintf.h" +#include "libc/log/log.h" #include "libc/runtime/runtime.h" #include "libc/stdio/stdio.h" #include "libc/thread/create.h" -#include "libc/thread/self.h" #include "libc/thread/detach.h" #include "libc/thread/join.h" +#include "libc/thread/self.h" #include "libc/thread/sem.h" #include "libc/time/time.h" cthread_sem_t semaphore; +_Thread_local int test_tls = 0x12345678; -__thread int test_tls = 0x12345678; - -int worker(void* arg) { - void* p; - arch_prctl(ARCH_GET_FS, &p); +static void *worker(void *arg) { + int tid; + cthread_t self; cthread_sem_signal(&semaphore); - - cthread_t self = cthread_self(); - int tid = self->tid; - sleep(1); - //sleep(10000); - printf("[%p] %d -> 0x%x\n", self, tid, test_tls); - (void)arg; - return 4; + self = cthread_self(); + tid = self->tid; + printf("[%p] %d -> %#x\n", self, tid, test_tls); + if (test_tls != 0x12345678) { + printf(".tdata test #2 failed\n"); + } + return (void *)4; } int main() { - cthread_t self = cthread_self(); - int tid = self->tid; - printf("[%p] %d -> 0x%x\n", self, tid, test_tls); + int rc, tid; + void *exitcode; + cthread_t self, thread; + self = cthread_self(); + tid = self->tid; + printf("[%p] %d -> %#x\n", self, tid, test_tls); + if (test_tls != 0x12345678) { + printf(".tdata test #1 failed\n"); + } cthread_sem_init(&semaphore, 0); - - cthread_t thread; - int rc = cthread_create(&thread, NULL, &worker, NULL); + rc = cthread_create(&thread, NULL, &worker, NULL); if (rc == 0) { cthread_sem_wait(&semaphore, 0, NULL); - //printf("thread created: %p\n", thread); - sleep(1); + printf("thread created: %p\n", thread); #if 1 - cthread_join(thread, &rc); + cthread_join(thread, &exitcode); #else - rc = cthread_detach(thread); - sleep(2); + exitcode = cthread_detach(thread); #endif cthread_sem_signal(&semaphore); cthread_sem_wait(&semaphore, 0, NULL); - //printf("thread joined: %p -> %d\n", thread, rc); + printf("thread joined: %p -> %p\n", thread, exitcode); } else { - printf("ERROR: thread could not be started: %d\n", rc); + fprintf(stderr, "ERROR: thread could not be started: %d\n", rc); } return 0; } diff --git a/examples/tls.c b/examples/tls.c new file mode 100644 index 000000000..c0a350692 --- /dev/null +++ b/examples/tls.c @@ -0,0 +1,15 @@ +#if 0 +/*─────────────────────────────────────────────────────────────────╗ +│ To the extent possible under law, Justine Tunney has waived │ +│ all copyright and related or neighboring rights to this file, │ +│ as it is written in the following disclaimers: │ +│ • http://unlicense.org/ │ +│ • http://creativecommons.org/publicdomain/zero/1.0/ │ +╚─────────────────────────────────────────────────────────────────*/ +#endif + +_Thread_local int foo; + +int main(int argc, char *argv[]) { + foo = 1; +} diff --git a/libc/calls/calls.h b/libc/calls/calls.h index 455136d21..03868e354 100644 --- a/libc/calls/calls.h +++ b/libc/calls/calls.h @@ -248,6 +248,7 @@ void sync(void); int clone(int (*)(void *), void *, size_t, int, void *, int *, void *, size_t, int *); +int futex(uint32_t *, int, int, const struct timespec *, uint32_t *); /*───────────────────────────────────────────────────────────────────────────│─╗ │ cosmopolitan § system calls » formatting ─╬─│┼ diff --git a/libc/calls/close.c b/libc/calls/close.c index 1a241f007..c03d92f75 100644 --- a/libc/calls/close.c +++ b/libc/calls/close.c @@ -54,7 +54,7 @@ int close(int fd) { } else if (fd < 0) { rc = einval(); } else { - if (fd < g_fds.n && g_fds.p[fd].kind == kFdZip) { + if (__isfdkind(fd, kFdZip)) { rc = weaken(__zipos_close)(fd); } else { if (!IsWindows() && !IsMetal()) { @@ -62,16 +62,16 @@ int close(int fd) { } else if (IsMetal()) { rc = 0; } else { - if (fd < g_fds.n && g_fds.p[fd].kind == kFdEpoll) { + if (__isfdkind(fd, kFdEpoll)) { rc = weaken(sys_close_epoll_nt)(fd); - } else if (fd < g_fds.n && g_fds.p[fd].kind == kFdSocket) { + } else if (__isfdkind(fd, kFdSocket)) { rc = weaken(sys_closesocket_nt)(g_fds.p + fd); - } else if (fd < g_fds.n && (g_fds.p[fd].kind == kFdFile || - g_fds.p[fd].kind == kFdConsole || - g_fds.p[fd].kind == kFdProcess)) { + } else if (__isfdkind(fd, kFdFile) || // + __isfdkind(fd, kFdConsole) || // + __isfdkind(fd, kFdProcess)) { // rc = sys_close_nt(g_fds.p + fd); } else { - STRACE("close(%d) unknown kind: %d", fd, g_fds.p[fd].kind); + STRACE("close(%d) unknown kind", fd); rc = ebadf(); } } diff --git a/libc/calls/dup-nt.c b/libc/calls/dup-nt.c index 8e5894427..b3da0954d 100644 --- a/libc/calls/dup-nt.c +++ b/libc/calls/dup-nt.c @@ -22,6 +22,7 @@ #include "libc/calls/internal.h" #include "libc/calls/state.internal.h" #include "libc/calls/syscall_support-nt.internal.h" +#include "libc/intrin/kprintf.h" #include "libc/intrin/spinlock.h" #include "libc/mem/mem.h" #include "libc/nt/files.h" @@ -37,7 +38,7 @@ textwindows int sys_dup_nt(int oldfd, int newfd, int flags, int start) { int64_t rc, proc, handle; // validate the api usage - if (oldfd < 0) return einval(); + if (oldfd < 0) return ebadf(); if (flags & ~O_CLOEXEC) return einval(); _spinlock(&__fds_lock); diff --git a/libc/calls/dup.c b/libc/calls/dup.c index 4bcea1e12..4db6fb2b5 100644 --- a/libc/calls/dup.c +++ b/libc/calls/dup.c @@ -17,26 +17,35 @@ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/calls/calls.h" +#include "libc/calls/internal.h" #include "libc/calls/strace.internal.h" #include "libc/calls/syscall-nt.internal.h" #include "libc/calls/syscall-sysv.internal.h" #include "libc/dce.h" +#include "libc/sysv/errfuns.h" /** - * Duplicates file descriptor/handle. + * Duplicates file descriptor. + * + * The `O_CLOEXEC` flag shall be cleared from the resulting file + * descriptor; see dup3() to preserve it. * * @param fd remains open afterwards * @return some arbitrary new number for fd + * @raise EOPNOTSUPP if zipos file + * @raise EBADF if fd isn't open * @asyncsignalsafe * @vforksafe */ int dup(int fd) { - int fd2; - if (!IsWindows()) { - fd2 = sys_dup(fd); + int rc; + if (__isfdkind(fd, kFdZip)) { + rc = eopnotsupp(); + } else if (!IsWindows()) { + rc = sys_dup(fd); } else { - fd2 = sys_dup_nt(fd, -1, 0, -1); + rc = sys_dup_nt(fd, -1, 0, -1); } - STRACE("%s(%d) → %d% m", "dup", fd, fd2); - return fd2; + STRACE("%s(%d) → %d% m", "dup", fd, rc); + return rc; } diff --git a/libc/calls/dup2.c b/libc/calls/dup2.c index bb78e74dd..3dbae29c2 100644 --- a/libc/calls/dup2.c +++ b/libc/calls/dup2.c @@ -17,27 +17,47 @@ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/calls/calls.h" +#include "libc/calls/internal.h" #include "libc/calls/strace.internal.h" #include "libc/calls/syscall-nt.internal.h" #include "libc/calls/syscall-sysv.internal.h" #include "libc/dce.h" +#include "libc/sysv/errfuns.h" /** * Duplicates file descriptor, granting it specific number. * + * The `O_CLOEXEC` flag shall be cleared from the resulting file + * descriptor; see dup3() to preserve it. + * + * Unlike dup3(), the dup2() function permits oldfd and newfd to be the + * same, in which case the only thing this function does is test if + * oldfd is open. + * * @param oldfd isn't closed afterwards * @param newfd if already assigned, is silently closed beforehand; * unless it's equal to oldfd, in which case dup2() is a no-op * @return new file descriptor, or -1 w/ errno + * @raise EBADF is oldfd isn't open + * @raise EBADF is newfd negative or too big + * @raise EINTR if a signal handler was called * @asyncsignalsafe * @vforksafe */ int dup2(int oldfd, int newfd) { int rc; - if (oldfd == newfd) { - rc = newfd; + if (__isfdkind(oldfd, kFdZip)) { + rc = eopnotsupp(); } else if (!IsWindows()) { - rc = sys_dup3(oldfd, newfd, 0); + rc = sys_dup2(oldfd, newfd); + } else if (newfd < 0) { + rc = ebadf(); + } else if (oldfd == newfd) { + if (__isfdopen(oldfd)) { + rc = newfd; + } else { + rc = ebadf(); + } } else { rc = sys_dup_nt(oldfd, newfd, 0, -1); } diff --git a/libc/calls/dup3-sysv.c b/libc/calls/dup3-sysv.c index 2bbea134c..a336a2688 100644 --- a/libc/calls/dup3-sysv.c +++ b/libc/calls/dup3-sysv.c @@ -19,11 +19,18 @@ #include "libc/calls/strace.internal.h" #include "libc/calls/syscall-sysv.internal.h" #include "libc/calls/syscall_support-sysv.internal.h" +#include "libc/dce.h" #include "libc/errno.h" +#include "libc/sysv/consts/o.h" +#include "libc/sysv/errfuns.h" + +#define F_DUP2FD 10 +#define F_DUP2FD_CLOEXEC 18 int32_t sys_dup3(int32_t oldfd, int32_t newfd, int flags) { - static bool once, demodernize; - int olderr, fd; + static bool once; + static bool demodernize; + int olderr, how, fd; if (!once) { olderr = errno; fd = __sys_dup3(oldfd, newfd, flags); @@ -39,5 +46,12 @@ int32_t sys_dup3(int32_t oldfd, int32_t newfd, int flags) { } else if (!demodernize) { return __sys_dup3(oldfd, newfd, flags); } - return __fixupnewfd(sys_dup2(oldfd, newfd), flags); + if (oldfd == newfd) return einval(); + if (flags & ~O_CLOEXEC) return einval(); + if (IsFreebsd()) { + how = flags & O_CLOEXEC ? F_DUP2FD_CLOEXEC : F_DUP2FD; + return __sys_fcntl(oldfd, how, newfd); + } else { + return __fixupnewfd(sys_dup2(oldfd, newfd), flags); + } } diff --git a/libc/calls/dup3.c b/libc/calls/dup3.c index 05128a0a5..9adc452f3 100644 --- a/libc/calls/dup3.c +++ b/libc/calls/dup3.c @@ -17,6 +17,7 @@ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/calls/calls.h" +#include "libc/calls/internal.h" #include "libc/calls/strace.internal.h" #include "libc/calls/syscall-nt.internal.h" #include "libc/calls/syscall-sysv.internal.h" @@ -33,13 +34,26 @@ * @param oldfd isn't closed afterwards * @param newfd if already assigned, is silently closed beforehand; * unless it's equal to oldfd, in which case dup2() is a no-op - * @param flags can have O_CLOEXEC + * @param flags may have O_CLOEXEC which is needed to preserve the + * close-on-execve() state after file descriptor duplication + * @return newfd on success, or -1 w/ errno + * @raise EINVAL if flags has unsupported bits + * @raise EINVAL if newfd equals oldfd + * @raise EBADF is oldfd isn't open + * @raise EBADF is newfd negative or too big + * @raise EINTR if a signal handler was called * @see dup(), dup2() */ int dup3(int oldfd, int newfd, int flags) { int rc; - if (!IsWindows()) { + if (__isfdkind(oldfd, kFdZip)) { + rc = eopnotsupp(); + } else if (oldfd == newfd) { + rc = einval(); + } else if (!IsWindows()) { rc = sys_dup3(oldfd, newfd, flags); + } else if (newfd < 0) { + rc = ebadf(); } else { rc = sys_dup_nt(oldfd, newfd, flags, -1); } diff --git a/libc/calls/g_sighandrvas.c b/libc/calls/g_sighandrvas.c index e1da914a5..c3620f8c1 100644 --- a/libc/calls/g_sighandrvas.c +++ b/libc/calls/g_sighandrvas.c @@ -17,6 +17,6 @@ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ -_Alignas(64) int __sig_lock; unsigned __sighandrvas[NSIG]; unsigned __sighandflags[NSIG]; +_Alignas(64) int __sig_lock_obj; diff --git a/libc/runtime/getcpucount.c b/libc/calls/getcpucount.c similarity index 100% rename from libc/runtime/getcpucount.c rename to libc/calls/getcpucount.c diff --git a/libc/calls/getloadavg-nt.c b/libc/calls/getloadavg-nt.c new file mode 100644 index 000000000..aad45d409 --- /dev/null +++ b/libc/calls/getloadavg-nt.c @@ -0,0 +1,71 @@ +/*-*- 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/calls/syscall_support-nt.internal.h" +#include "libc/dce.h" +#include "libc/fmt/conv.h" +#include "libc/intrin/spinlock.h" +#include "libc/macros.internal.h" +#include "libc/nt/accounting.h" +#include "libc/runtime/sysconf.h" + +#define FT(x) (x.dwLowDateTime | (uint64_t)x.dwHighDateTime << 32) + +static int cpus; +static double load; +_Alignas(64) static int lock; +static struct NtFileTime idle1, kern1, user1; + +textwindows int sys_getloadavg_nt(double *a, int n) { + int i, rc; + uint64_t elapsed, used; + struct NtFileTime idle, kern, user; + _spinlock(&lock); + if (GetSystemTimes(&idle, &kern, &user)) { + elapsed = (FT(kern) - FT(kern1)) + (FT(user) - FT(user1)); + if (elapsed) { + used = elapsed - (FT(idle) - FT(idle1)); + load = (double)used / elapsed * cpus; + load = MIN(MAX(load, 0), cpus * 2); + idle1 = idle, kern1 = kern, user1 = user; + } + for (i = 0; i < n; ++i) { + a[i] = load; + } + rc = n; + } else { + rc = __winerr(); + } + _spunlock(&lock); + return rc; +} + +static textstartup void sys_getloadavg_nt_init(void) { + double a[3]; + if (IsWindows()) { + load = 1; + cpus = GetCpuCount() / 2; + cpus = MAX(1, cpus); + GetSystemTimes(&idle1, &kern1, &user1); + } +} + +const void *const sys_getloadavg_nt_ctor[] initarray = { + sys_getloadavg_nt_init, +}; diff --git a/libc/calls/getloadavg.c b/libc/calls/getloadavg.c index 5a896926e..9349b4425 100644 --- a/libc/calls/getloadavg.c +++ b/libc/calls/getloadavg.c @@ -17,24 +17,60 @@ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/calls/calls.h" +#include "libc/calls/strace.internal.h" #include "libc/calls/struct/sysinfo.h" +#include "libc/calls/syscall-nt.internal.h" #include "libc/dce.h" #include "libc/sysv/errfuns.h" +#define CTL_VM 2 +#define VM_LOADAVG 2 + +struct loadavg { + uint32_t ldavg[3]; + int64_t fscale; +}; + /** * Returns system load average. - * @note work in progress + * + * @param a should be array of 3 doubles + * @param n should be 3 + * @return number of items placed in `a` or -1 w/ errno + * @raise ENOSYS on metal */ int getloadavg(double *a, int n) { /* cat /proc/loadavg */ - int i; - struct sysinfo si; - if (!n) return 0; - if (n < 0) return einval(); - if (sysinfo(&si) == -1) return -1; + int i, rc; if (n > 3) n = 3; - for (i = 0; i < n; i++) { - a[i] = 1. / 65536 * si.loads[i]; + if (!n) { + rc = 0; + } else if (n < 0) { + rc = einval(); + } else if (IsWindows()) { + return sys_getloadavg_nt(a, n); + } else if (IsLinux()) { + struct sysinfo si; + if ((rc = sysinfo(&si)) != -1) { + for (i = 0; i < n; i++) { + a[i] = 1. / 65536 * si.loads[i]; + } + rc = n; + } + } else if (IsFreebsd() || IsNetbsd() || IsOpenbsd() || IsXnu()) { + size_t size; + struct loadavg loadinfo; + int mib[2] = {CTL_VM, VM_LOADAVG}; + size = sizeof(loadinfo); + if ((rc = sysctl(mib, 2, &loadinfo, &size, 0, 0)) != -1) { + for (i = 0; i < n; i++) { + a[i] = (double)loadinfo.ldavg[i] / loadinfo.fscale; + } + rc = n; + } + } else { + rc = enosys(); } - return n; + STRACE("getloadavg(%p, %d) → %d% m", a, n, rc); + return rc; } diff --git a/libc/calls/getrusage-nt.c b/libc/calls/getrusage-nt.c index 8c4fa79c8..2c2934503 100644 --- a/libc/calls/getrusage-nt.c +++ b/libc/calls/getrusage-nt.c @@ -49,9 +49,9 @@ textwindows int sys_getrusage_nt(int who, struct rusage *usage) { !GetProcessIoCounters(me, &iocount)) { return __winerr(); } - _spinlock(&__sig_lock); + __sig_lock(); nsignals = __sig_count; - _spunlock(&__sig_lock); + __sig_unlock(); *usage = (struct rusage){ .ru_utime = WindowsDurationToTimeVal(ReadFileTime(ftUser)), .ru_stime = WindowsDurationToTimeVal(ReadFileTime(ftKernel)), diff --git a/libc/calls/interrupts-nt.c b/libc/calls/interrupts-nt.c index 458f5a93a..a5563b813 100644 --- a/libc/calls/interrupts-nt.c +++ b/libc/calls/interrupts-nt.c @@ -29,35 +29,13 @@ #include "libc/intrin/lockcmpxchgp.h" #include "libc/nexgen32e/threaded.h" -_Alignas(64) static int rlock; - -// return 0 on success, or tid of other owner -static privileged inline int AcquireInterruptPollLock(void) { - // any thread can poll for interrupts - // but it's wasteful to have every single thread doing it - int me, owner = 0; - if (__threaded) { - me = gettid(); - if (!_lockcmpxchgp(&rlock, &owner, me) && owner == me) { - owner = 0; - } - } - return owner; -} - -static textwindows inline void ReleaseInterruptPollLock(void) { - int zero = 0; - __atomic_store(&rlock, &zero, __ATOMIC_RELAXED); -} - textwindows bool _check_interrupts(bool restartable, struct Fd *fd) { bool res; if (__time_critical) return false; - if (AcquireInterruptPollLock()) return false; + if (__threaded && __threaded != gettid()) return false; if (weaken(_check_sigalrm)) weaken(_check_sigalrm)(); if (weaken(_check_sigchld)) weaken(_check_sigchld)(); if (fd && weaken(_check_sigwinch)) weaken(_check_sigwinch)(fd); res = weaken(__sig_check) && weaken(__sig_check)(restartable); - ReleaseInterruptPollLock(); return res; } diff --git a/libc/calls/loadavg-nt.c b/libc/calls/loadavg-nt.c deleted file mode 100644 index 28671071e..000000000 --- a/libc/calls/loadavg-nt.c +++ /dev/null @@ -1,97 +0,0 @@ -/*-*- 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/loadavg.internal.h" -#include "libc/calls/strace.internal.h" -#include "libc/dce.h" -#include "libc/errno.h" -#include "libc/nexgen32e/nt2sysv.h" -#include "libc/nt/enum/accessmask.h" -#include "libc/nt/enum/pdh.h" -#include "libc/nt/enum/securityimpersonationlevel.h" -#include "libc/nt/enum/wt.h" -#include "libc/nt/errors.h" -#include "libc/nt/events.h" -#include "libc/nt/files.h" -#include "libc/nt/pdh.h" -#include "libc/nt/privilege.h" -#include "libc/nt/runtime.h" -#include "libc/nt/struct/luid.h" -#include "libc/nt/struct/pdhfmtcountervalue.h" -#include "libc/nt/struct/tokenprivileges.h" -#include "libc/nt/synchronization.h" -#include "libc/str/str.h" - -/** - * @fileoverview sysinfo() on the new technology - * @kudos Giampaolo Rodola for teaching how to do load average - */ - -#define LOAD_SAMPLING_INTERVAL 1 // in seconds - -// https://github.com/torvalds/linux/blob/345671ea0f9258f410eb057b9ced9cefbbe5dc78/include/linux/sched/loadavg.h#L20-L23 -#define LOAD1F .9200444146293232478931553241 -#define LOAD5F .9834714538216174894737477501 -#define LOAD15F .9944598480048967508795473394 - -double __ntloadavg[3]; - -static void LoadavgNtPoll(int64_t hCounter, bool32 timedOut) { - struct NtPdhFmtCountervalue c; - if (!PdhGetFormattedCounterValue(hCounter, kNtPdhFmtDouble, 0, &c)) { - __ntloadavg[0] = __ntloadavg[0] * LOAD1F + c.doubleValue * (1 - LOAD1F); - __ntloadavg[1] = __ntloadavg[1] * LOAD5F + c.doubleValue * (1 - LOAD5F); - __ntloadavg[2] = __ntloadavg[2] * LOAD15F + c.doubleValue * (1 - LOAD15F); - } else { - STRACE("PdhGetFormattedCounterValue(%ld) failed", hCounter); - } -} - -static textstartup void LoadavgNtInit(void) { - int64_t hQuery, hCounter, hEvent, hWaiter; - if (!IsWindows()) return; - STRACE("LoadavgNtInit()"); - if (PdhOpenQuery(0, 0, &hQuery)) { - STRACE("PdhOpenQuery failed"); - return; - } - if (PdhAddEnglishCounter(hQuery, u"\\System\\Processor Queue Length", 0, - &hCounter)) { - STRACE("PdhAddEnglishCounter() failed"); - return; - } - if (!(hEvent = CreateEvent(0, 0, 0, u"LoadUpdateEvent"))) { - STRACE("CreateEvent() failed"); - return; - } - if (PdhCollectQueryDataEx(hQuery, LOAD_SAMPLING_INTERVAL, hEvent)) { - STRACE("PdhCollectQueryDataEx() failed"); - return; - } - if (!RegisterWaitForSingleObject( - &hWaiter, hEvent, (void *)NT2SYSV(LoadavgNtPoll), - (void *)(intptr_t)hCounter, -1, kNtWtExecutedefault)) { - STRACE("RegisterWaitForSingleObject() failed"); - return; - } - LoadavgNtPoll(hCounter, 0); -} - -const void *const LoadavgNtCtor[] initarray = { - LoadavgNtInit, -}; diff --git a/libc/calls/loadavg.internal.h b/libc/calls/loadavg.internal.h deleted file mode 100644 index dbae0f1a0..000000000 --- a/libc/calls/loadavg.internal.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef COSMOPOLITAN_LIBC_CALLS_LOADAVG_INTERNAL_H_ -#define COSMOPOLITAN_LIBC_CALLS_LOADAVG_INTERNAL_H_ -#if !(__ASSEMBLER__ + __LINKER__ + 0) -COSMOPOLITAN_C_START_ - -extern double __ntloadavg[3]; - -COSMOPOLITAN_C_END_ -#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */ -#endif /* COSMOPOLITAN_LIBC_CALLS_LOADAVG_INTERNAL_H_ */ diff --git a/libc/calls/sig.c b/libc/calls/sig.c index 9c8717b6d..8027d73cc 100644 --- a/libc/calls/sig.c +++ b/libc/calls/sig.c @@ -38,7 +38,7 @@ textwindows int __sig_mask(int how, const sigset_t *neu, sigset_t *old) { int i; uint64_t a, b; if (how == SIG_BLOCK || how == SIG_UNBLOCK || how == SIG_SETMASK) { - _spinlock(&__sig_lock); + __sig_lock(); if (old) { *old = __sig.mask; } @@ -54,7 +54,7 @@ textwindows int __sig_mask(int how, const sigset_t *neu, sigset_t *old) { } __sig.mask.__bits[0] &= ~(SIGKILL | SIGSTOP); } - _spunlock(&__sig_lock); + __sig_unlock(); return 0; } else { return einval(); diff --git a/libc/calls/sig.internal.h b/libc/calls/sig.internal.h index 2f58b1d6f..1dedfc81c 100644 --- a/libc/calls/sig.internal.h +++ b/libc/calls/sig.internal.h @@ -26,6 +26,8 @@ struct Signals { extern struct Signals __sig; // TODO(jart): Need TLS extern long __sig_count; +void __sig_lock(void) hidden; +void __sig_unlock(void) hidden; bool __sig_check(bool) hidden; bool __sig_handle(bool, int, int, ucontext_t *) hidden; int __sig_add(int, int) hidden; diff --git a/libc/calls/sig2.c b/libc/calls/sig2.c index 2aba4946f..fb59bae12 100644 --- a/libc/calls/sig2.c +++ b/libc/calls/sig2.c @@ -66,7 +66,7 @@ static textwindows void __sig_free(struct Signal *mem) { static textwindows struct Signal *__sig_remove(void) { struct Signal *prev, *res; if (__sig.queue) { - _spinlock(&__sig_lock); + __sig_lock(); for (prev = 0, res = __sig.queue; res; prev = res, res = res->next) { if (!sigismember(&__sig.mask, res->sig)) { if (res == __sig.queue) { @@ -80,7 +80,7 @@ static textwindows struct Signal *__sig_remove(void) { STRACE("%G is masked", res->sig); } } - _spunlock(&__sig_lock); + __sig_unlock(); } else { res = 0; } @@ -99,7 +99,7 @@ static privileged bool __sig_deliver(bool restartable, int sig, int si_code, STRACE("delivering %G", sig); // enter the signal - _spinlock(&__sig_lock); + __sig_lock(); rva = __sighandrvas[sig]; flags = __sighandflags[sig]; if ((~flags & SA_NODEFER) || (flags & SA_RESETHAND)) { @@ -110,7 +110,7 @@ static privileged bool __sig_deliver(bool restartable, int sig, int si_code, // signal handler. in that case you must use SA_NODEFER. __sighandrvas[sig] = (int32_t)(intptr_t)SIG_DFL; } - _spunlock(&__sig_lock); + __sig_unlock(); // setup the somewhat expensive information args // only if they're requested by the user in sigaction() @@ -196,9 +196,9 @@ privileged bool __sig_handle(bool restartable, int sig, int si_code, textwindows int __sig_raise(int sig, int si_code) { int rc; int candeliver; - _spinlock(&__sig_lock); + __sig_lock(); candeliver = !sigismember(&__sig.mask, sig); - _spunlock(&__sig_lock); + __sig_unlock(); switch (candeliver) { case 1: __sig_handle(false, sig, si_code, 0); @@ -213,26 +213,31 @@ textwindows int __sig_raise(int sig, int si_code) { /** * Enqueues generic signal for delivery on New Technology. - * @return 0 if enqueued, otherwise -1 w/ errno + * @return 0 on success, otherwise -1 w/ errno * @threadsafe */ textwindows int __sig_add(int sig, int si_code) { int rc; struct Signal *mem; if (1 <= sig && sig <= NSIG) { - STRACE("enqueuing %G", sig); - _spinlock(&__sig_lock); - ++__sig_count; - if ((mem = __sig_alloc())) { - mem->sig = sig; - mem->si_code = si_code; - mem->next = __sig.queue; - __sig.queue = mem; + __sig_lock(); + if (__sighandrvas[sig] == (unsigned)(intptr_t)SIG_IGN) { + STRACE("ignoring %G", sig); rc = 0; } else { - rc = enomem(); + STRACE("enqueuing %G", sig); + ++__sig_count; + if ((mem = __sig_alloc())) { + mem->sig = sig; + mem->si_code = si_code; + mem->next = __sig.queue; + __sig.queue = mem; + rc = 0; + } else { + rc = enomem(); + } } - _spunlock(&__sig_lock); + __sig_unlock(); } else { rc = einval(); } diff --git a/libc/calls/sigaction.c b/libc/calls/sigaction.c index 0270839d6..9806ce460 100644 --- a/libc/calls/sigaction.c +++ b/libc/calls/sigaction.c @@ -21,6 +21,7 @@ #include "libc/bits/weaken.h" #include "libc/calls/calls.h" #include "libc/calls/internal.h" +#include "libc/calls/sig.internal.h" #include "libc/calls/sigbits.h" #include "libc/calls/state.internal.h" #include "libc/calls/strace.internal.h" @@ -448,9 +449,9 @@ int sigaction(int sig, const struct sigaction *act, struct sigaction *oldact) { if (sig == SIGKILL || sig == SIGSTOP) { rc = einval(); } else { - _spinlock(&__sig_lock); + __sig_lock(); rc = __sigaction(sig, act, oldact); - _spunlock(&__sig_lock); + __sig_unlock(); } STRACE("sigaction(%G, %s, [%s]) → %d% m", sig, DescribeSigaction(buf[0], sizeof(buf[0]), 0, act), diff --git a/libc/calls/siglock.c b/libc/calls/siglock.c new file mode 100644 index 000000000..767931ed1 --- /dev/null +++ b/libc/calls/siglock.c @@ -0,0 +1,30 @@ +/*-*- 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/calls/sig.internal.h" +#include "libc/calls/state.internal.h" +#include "libc/intrin/spinlock.h" + +void __sig_lock(void) { + _spinlock(&__sig_lock_obj); +} + +void __sig_unlock(void) { + _spunlock(&__sig_lock_obj); +} diff --git a/libc/calls/state.internal.h b/libc/calls/state.internal.h index b7a14781f..0a5d03ccf 100644 --- a/libc/calls/state.internal.h +++ b/libc/calls/state.internal.h @@ -5,7 +5,7 @@ COSMOPOLITAN_C_START_ hidden extern int __vforked; hidden extern int __fds_lock; -hidden extern int __sig_lock; +hidden extern int __sig_lock_obj; hidden extern bool __time_critical; hidden extern unsigned __sighandrvas[NSIG]; hidden extern unsigned __sighandflags[NSIG]; diff --git a/libc/calls/syscall-nt.internal.h b/libc/calls/syscall-nt.internal.h index 51bba6286..7410b5672 100644 --- a/libc/calls/syscall-nt.internal.h +++ b/libc/calls/syscall-nt.internal.h @@ -18,6 +18,7 @@ int sys_fdatasync_nt(int) hidden; int sys_flock_nt(int, int) hidden; int sys_fork_nt(void) hidden; int sys_ftruncate_nt(int64_t, uint64_t) hidden; +int sys_getloadavg_nt(double *, int) hidden; int sys_getppid_nt(void) hidden; int sys_getpriority_nt(int) hidden; int sys_getsetpriority_nt(int, int, int, int (*)(int)); diff --git a/libc/calls/sysinfo-nt.c b/libc/calls/sysinfo-nt.c index 2ee862ca9..7ad840ea9 100644 --- a/libc/calls/sysinfo-nt.c +++ b/libc/calls/sysinfo-nt.c @@ -16,7 +16,6 @@ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ -#include "libc/calls/loadavg.internal.h" #include "libc/calls/struct/sysinfo.h" #include "libc/calls/syscall_support-nt.internal.h" #include "libc/nt/accounting.h" @@ -33,9 +32,6 @@ textwindows int sys_sysinfo_nt(struct sysinfo *info) { info->totalram = memstat.ullTotalPhys; info->freeram = memstat.ullAvailPhys; info->procs = sysinfo.dwNumberOfProcessors; - info->loads[0] = __ntloadavg[0] * 65536; - info->loads[1] = __ntloadavg[1] * 65536; - info->loads[2] = __ntloadavg[2] * 65536; info->mem_unit = 1; return 0; } else { diff --git a/libc/intrin/exit1.greg.c b/libc/intrin/exit1.greg.c index 6f2a61b60..18953a224 100644 --- a/libc/intrin/exit1.greg.c +++ b/libc/intrin/exit1.greg.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=2 sts=2 sw=2 fenc=utf-8 :vi│ ╞══════════════════════════════════════════════════════════════════════════════╡ -│ Copyright 2021 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,8 +18,6 @@ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/calls/strace.internal.h" #include "libc/dce.h" -#include "libc/intrin/setjmp.internal.h" -#include "libc/nexgen32e/threaded.h" #include "libc/nt/thread.h" #include "libc/runtime/runtime.h" #include "libc/sysv/consts/nr.h" @@ -36,10 +34,6 @@ privileged wontreturn void _Exit1(int rc) { jmp_buf *jb; struct WinThread *wt; STRACE("_Exit1(%d)", rc); - if (__tls_enabled) { - jb = (jmp_buf *)(__get_tls() + 0x08); - longjmp(*jb, rc); - } if (!IsWindows() && !IsMetal()) { asm volatile("xor\t%%r10d,%%r10d\n\t" "syscall" diff --git a/libc/intrin/tls.greg.c b/libc/intrin/tls.greg.c index 3dc87cab7..e68f04914 100644 --- a/libc/intrin/tls.greg.c +++ b/libc/intrin/tls.greg.c @@ -25,7 +25,12 @@ #include "libc/nt/thunk/msabi.h" #include "libc/sysv/consts/nrlinux.h" -#define __NR_sysarch 0x000000a5 +#define __NR_sysarch 0x000000a5 // freebsd+netbsd +#define AMD64_SET_GSBASE 131 // freebsd +#define AMD64_SET_FSBASE 129 // freebsd +#define X86_SET_GSBASE 16 // netbsd +#define X86_SET_FSBASE 17 // netbsd + #define __NR___set_tcb 0x00000149 #define __NR__lwp_setprivate 0x0000013d #define __NR_thread_fast_set_cthread_self 0x03000003 @@ -37,8 +42,6 @@ * * offset size description * 0x0000 0x08 linear address pointer - * 0x0008 0x08 jmp_buf *exiter - * 0x0010 0x04 exit code * 0x0030 0x08 linear address pointer * 0x0038 0x04 tid * 0x003c 0x04 errno @@ -47,8 +50,6 @@ 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; @@ -72,7 +73,12 @@ privileged void __install_tls(char tib[64]) { } else if (IsFreebsd()) { asm volatile("syscall" : "=a"(ax) - : "0"(__NR_sysarch), "D"(129), "S"(tib) + : "0"(__NR_sysarch), "D"(AMD64_SET_FSBASE), "S"(tib) + : "rcx", "r11", "memory", "cc"); + } else if (IsNetbsd()) { + asm volatile("syscall" + : "=a"(ax), "=d"(dx) + : "0"(__NR_sysarch), "D"(X86_SET_FSBASE), "S"(tib) : "rcx", "r11", "memory", "cc"); } else if (IsXnu()) { asm volatile("syscall" @@ -85,11 +91,6 @@ privileged void __install_tls(char tib[64]) { : "=a"(ax) : "0"(__NR___set_tcb), "D"(tib) : "rcx", "r11", "memory", "cc"); - } else if (IsNetbsd()) { - asm volatile("syscall" - : "=a"(ax), "=d"(dx) - : "0"(__NR__lwp_setprivate), "D"(tib) - : "rcx", "r11", "memory", "cc"); } else { asm volatile("syscall" : "=a"(ax) diff --git a/libc/stdio/unlocked/fgetc_unlocked.S b/libc/nexgen32e/longerjmp.S similarity index 83% rename from libc/stdio/unlocked/fgetc_unlocked.S rename to libc/nexgen32e/longerjmp.S index ec857991c..3f219e370 100644 --- a/libc/stdio/unlocked/fgetc_unlocked.S +++ b/libc/nexgen32e/longerjmp.S @@ -17,14 +17,22 @@ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/macros.internal.h" +.privileged -// Reads byte from stream. +// Loads previously saved processor state. // -// @param rdi has stream object pointer -// @return byte in range 0..255, or -1 w/ errno -// @see fgetc_unlocked() -// @threadsafe -fgetc: mov %rdi,%r11 - ezlea fgetc_unlocked,ax - jmp stdio_unlock - .endfn fgetc,globl +// @param rdi points to the jmp_buf +// @param rsi is returned by setlongerjmp() invocation +// @noreturn +longerjmp: + mov $1,%eax + mov %rsi,%rdx + mov (%rdi),%rsp + mov 8(%rdi),%rbx + mov 16(%rdi),%rbp + mov 24(%rdi),%r12 + mov 32(%rdi),%r13 + mov 40(%rdi),%r14 + mov 48(%rdi),%r15 + jmp *56(%rdi) + .endfn longerjmp,globl diff --git a/libc/nexgen32e/setlongerjmp.S b/libc/nexgen32e/setlongerjmp.S new file mode 100644 index 000000000..7dfdcf318 --- /dev/null +++ b/libc/nexgen32e/setlongerjmp.S @@ -0,0 +1,41 @@ +/*-*- 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" + +// Saves caller CPU state to cacheline. +// +// @param rdi points to jmp_buf +// @return eax contains 0 when set, and 1 if jumped +// @return rdx contains value passed to longerjmp() +// @returnstwice +setlongerjmp: + lea 8(%rsp),%rax + mov %rax,(%rdi) + mov %rbx,8(%rdi) + mov %rbp,16(%rdi) + mov %r12,24(%rdi) + mov %r13,32(%rdi) + mov %r14,40(%rdi) + mov %r15,48(%rdi) + mov (%rsp),%rax + mov %rax,56(%rdi) + xor %eax,%eax + xor %edx,%edx + ret + .endfn setlongerjmp,globl diff --git a/libc/nexgen32e/threaded.c b/libc/nexgen32e/threaded.c index 7db3d662b..83c56b1a9 100644 --- a/libc/nexgen32e/threaded.c +++ b/libc/nexgen32e/threaded.c @@ -18,6 +18,11 @@ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/nexgen32e/threaded.h" -bool __threaded; +/** + * Contains TID of main thread or 0 if threading isn't enabled. + */ +int __threaded; + bool __tls_enabled; + unsigned __tls_index; diff --git a/libc/nexgen32e/threaded.h b/libc/nexgen32e/threaded.h index 868aab33e..5af710623 100644 --- a/libc/nexgen32e/threaded.h +++ b/libc/nexgen32e/threaded.h @@ -4,7 +4,7 @@ #if !(__ASSEMBLER__ + __LINKER__ + 0) COSMOPOLITAN_C_START_ -extern bool __threaded; +extern int __threaded; extern bool __tls_enabled; extern unsigned __tls_index; diff --git a/libc/nt/accounting.h b/libc/nt/accounting.h index 1b382873d..616adaac6 100644 --- a/libc/nt/accounting.h +++ b/libc/nt/accounting.h @@ -36,6 +36,9 @@ int GetUserName(char16_t (*buf)[257], uint32_t *in_out_size); bool32 GlobalMemoryStatusEx(struct NtMemoryStatusEx *lpBuffer); int32_t GetExitCodeProcess(int64_t hProcess, uint32_t *lpExitCode); int32_t GetProcessHandleCount(int64_t hProcess, uint32_t *pdwHandleCount); +bool32 GetSystemTimes(struct NtFileTime *opt_out_lpIdleTime, + struct NtFileTime *opt_out_lpKernelTime, + struct NtFileTime *opt_out_lpUserTime); bool32 GetProcessTimes(int64_t hProcess, struct NtFileTime *out_lpCreationFileTime, struct NtFileTime *out_lpExitFileTime, diff --git a/libc/nt/kernel32/GetSystemTimes.s b/libc/nt/kernel32/GetSystemTimes.s index 13ecfb835..100819cec 100644 --- a/libc/nt/kernel32/GetSystemTimes.s +++ b/libc/nt/kernel32/GetSystemTimes.s @@ -1,2 +1,12 @@ .include "o/libc/nt/codegen.inc" .imp kernel32,__imp_GetSystemTimes,GetSystemTimes,0 + + .text.windows +GetSystemTimes: + push %rbp + mov %rsp,%rbp + .profilable + mov __imp_GetSystemTimes(%rip),%rax + jmp __sysv2nt + .endfn GetSystemTimes,globl + .previous diff --git a/libc/nt/master.sh b/libc/nt/master.sh index a46644acf..1868b4af8 100755 --- a/libc/nt/master.sh +++ b/libc/nt/master.sh @@ -664,7 +664,7 @@ imp 'GetSystemTime' GetSystemTime kernel32 0 1 imp 'GetSystemTimeAdjustment' GetSystemTimeAdjustment kernel32 0 3 imp 'GetSystemTimeAsFileTime' GetSystemTimeAsFileTime kernel32 0 1 imp 'GetSystemTimePreciseAsFileTime' GetSystemTimePreciseAsFileTime kernel32 0 1 -imp 'GetSystemTimes' GetSystemTimes kernel32 0 +imp 'GetSystemTimes' GetSystemTimes kernel32 0 3 imp 'GetSystemWindowsDirectory' GetSystemWindowsDirectoryW kernel32 0 imp 'GetSystemWindowsDirectoryA' GetSystemWindowsDirectoryA kernel32 0 imp 'GetSystemWow64Directory' GetSystemWow64DirectoryW kernel32 0 diff --git a/libc/runtime/clone.c b/libc/runtime/clone.c index 797ccb9f3..62f990faa 100644 --- a/libc/runtime/clone.c +++ b/libc/runtime/clone.c @@ -23,13 +23,16 @@ #include "libc/dce.h" #include "libc/errno.h" #include "libc/intrin/asan.internal.h" +#include "libc/intrin/kprintf.h" #include "libc/intrin/spinlock.h" +#include "libc/limits.h" #include "libc/nexgen32e/threaded.h" #include "libc/nt/runtime.h" #include "libc/nt/thread.h" #include "libc/nt/thunk/msabi.h" #include "libc/runtime/runtime.h" #include "libc/sysv/consts/clone.h" +#include "libc/sysv/consts/futex.h" #include "libc/sysv/consts/nr.h" #include "libc/sysv/consts/nrlinux.h" #include "libc/sysv/errfuns.h" @@ -121,7 +124,7 @@ static textwindows int CloneWindows(int (*func)(void *), char *stk, wt->func = func; wt->arg = arg; wt->tls = flags & CLONE_SETTLS ? tls : 0; - if ((h = CreateThread(0, 0, (void *)WinThreadEntry, wt, 0, &wt->utid))) { + if ((h = CreateThread(0, 4096, (void *)WinThreadEntry, wt, 0, &wt->utid))) { CloseHandle(h); return wt->tid; } else { @@ -134,8 +137,7 @@ static textwindows int CloneWindows(int (*func)(void *), char *stk, void XnuThreadThunk(void *pthread, int machport, void *(*func)(void *), void *arg, intptr_t *stack, unsigned xnuflags); -asm(".local\tXnuThreadThunk\n" - "XnuThreadThunk:\n\t" +asm("XnuThreadThunk:\n\t" "xor\t%ebp,%ebp\n\t" "mov\t%r8,%rsp\n\t" "and\t$-16,%rsp\n\t" @@ -168,7 +170,7 @@ XnuThreadMain(void *pthread, int tid, int (*func)(void *arg), void *arg, // %r10 = uint32_t sem); asm volatile("movl\t$0,%0\n\t" // *wt->ztid = 0 "xor\t%%r10d,%%r10d\n\t" // sem = 0 - "syscall\n\t" // _Exit1() + "syscall\n\t" // __bsdthread_terminate() "ud2" : "=m"(*wt->ztid) : "a"(0x2000000 | 361), "D"(0), "S"(0), "d"(0) @@ -218,7 +220,7 @@ static wontreturn void FreebsdThreadMain(void *p) { // we no longer use the stack after this point // void thr_exit(%rdi = long *state); asm volatile("movl\t$0,%0\n\t" // *wt->ztid = 0 - "syscall" // _Exit1() + "syscall" // thr_exit() : "=m"(*wt->ztid) : "a"(431), "D"(0) : "rcx", "r11", "memory"); @@ -294,11 +296,14 @@ OpenbsdThreadMain(struct CloneArgs *wt) { // although ideally there should be a better solution. // // void __threxit(%rdi = int32_t *notdead); - asm volatile("mov\t%3,%%rsp\n\t" - "movl\t$0,%0\n\t" // *wt->ztid = 0 - "syscall" // _Exit1() + asm volatile("mov\t%2,%%rsp\n\t" + "movl\t$0,(%%rdi)\n\t" // *wt->ztid = 0 + "syscall\n\t" // futex() + "mov\t$302,%%eax\n\t" // __threxit() + "syscall" : "=m"(*wt->ztid) - : "a"(302), "D"(0), "r"(wt->pstack) + : "a"(83), "m"(wt->pstack), "D"(wt->ztid), "S"(FUTEX_WAKE), + "d"(INT_MAX) : "rcx", "r11", "memory"); unreachable; } @@ -337,7 +342,7 @@ static wontreturn void NetbsdThreadMain(void *arg, int (*func)(void *arg), // we no longer use the stack after this point // %eax = int __lwp_exit(void); asm volatile("movl\t$0,%2\n\t" // *wt->ztid = 0 - "syscall\n\t" // _Exit1() + "syscall\n\t" // __lwp_exit() "ud2" : "=a"(ax), "=d"(dx), "=m"(*ztid) : "0"(310) @@ -504,7 +509,7 @@ int sys_clone_linux(int flags, char *stk, int *ptid, int *ctid, void *tls, */ int clone(int (*func)(void *), void *stk, size_t stksz, int flags, void *arg, int *ptid, void *tls, size_t tlssz, int *ctid) { - int rc; + int rc, maintid; struct CloneArgs *wt; // transition program to threaded state @@ -517,13 +522,14 @@ int clone(int (*func)(void *), void *stk, size_t stksz, int flags, void *arg, STRACE("clone() tls/non-tls mixed order"); return einval(); } + maintid = gettid(); __initialize_tls(tibdefault); - *(int *)((char *)tibdefault + 0x38) = gettid(); + *(int *)((char *)tibdefault + 0x38) = maintid; *(int *)((char *)tibdefault + 0x3c) = __errno; __install_tls(tibdefault); - __threaded = true; + __threaded = maintid; } else if (flags & CLONE_THREAD) { - __threaded = true; + __threaded = gettid(); } if (IsAsan() && diff --git a/libc/runtime/internal.h b/libc/runtime/internal.h index 135130d48..880faeb12 100644 --- a/libc/runtime/internal.h +++ b/libc/runtime/internal.h @@ -18,6 +18,13 @@ extern const char v_ntsubsystem[] __attribute__((__weak__)); extern const uintptr_t __fini_array_end[] __attribute__((__weak__)); extern const uintptr_t __fini_array_start[] __attribute__((__weak__)); +extern unsigned char _tdata_start[]; +extern unsigned char _tdata_end[]; +extern unsigned char _tdata_size[]; +extern unsigned char _tbss_start[]; +extern unsigned char _tbss_end[]; +extern unsigned char _tls_size[]; + void _init(void) hidden; void __restorewintty(void) hidden; void *__cxa_finalize(void *) hidden; diff --git a/libc/runtime/mmap.c b/libc/runtime/mmap.c index ede99f154..285e6cb42 100644 --- a/libc/runtime/mmap.c +++ b/libc/runtime/mmap.c @@ -17,7 +17,9 @@ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/assert.h" +#include "libc/bits/bits.h" #include "libc/bits/likely.h" +#include "libc/bits/safemacros.internal.h" #include "libc/bits/weaken.h" #include "libc/calls/calls.h" #include "libc/calls/internal.h" @@ -84,6 +86,7 @@ static noasan inline bool OverlapsExistingMapping(char *p, size_t n) { } static noasan bool ChooseMemoryInterval(int x, int n, int align, int *res) { + // TODO: improve performance int i, start, end; assert(align > 0); if (_mmi.i) { @@ -327,15 +330,7 @@ static noasan inline void *Mmap(void *addr, size_t size, int prot, int flags, return VIP(einval()); } - // if size is a two power then automap will use it as alignment - if (IS2POW(size)) { - a = size >> 16; - if (!a) { - a = 1; - } - } else { - a = 1; - } + a = max(1, rounddown2pow(size) >> 16); f = (flags & ~MAP_FIXED_NOREPLACE) | MAP_FIXED; if (flags & MAP_FIXED) { diff --git a/libc/runtime/runtime.h b/libc/runtime/runtime.h index f486d4909..1ad50777c 100644 --- a/libc/runtime/runtime.h +++ b/libc/runtime/runtime.h @@ -48,6 +48,8 @@ unsigned long getauxval(unsigned long); void *mapanon(size_t) attributeallocsize((1)); int setjmp(jmp_buf) libcesque returnstwice paramsnonnull(); void longjmp(jmp_buf, int) libcesque wontreturn paramsnonnull(); +axdx_t setlongerjmp(jmp_buf) libcesque returnstwice paramsnonnull(); +void longerjmp(jmp_buf, intptr_t) libcesque wontreturn paramsnonnull(); int _setjmp(jmp_buf) libcesque returnstwice paramsnonnull(); void _longjmp(jmp_buf, int) libcesque wontreturn paramsnonnull(); void exit(int) wontreturn; diff --git a/libc/stdio/clearerr.c b/libc/stdio/clearerr.c index d06719d15..aa1aeed58 100644 --- a/libc/stdio/clearerr.c +++ b/libc/stdio/clearerr.c @@ -18,6 +18,15 @@ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/stdio/stdio.h" -void clearerr_unlocked(FILE *f) { - f->state = 0; +/** + * Clears error state on stream. + * + * @param f is file object stream pointer + * @see clearerr_unlocked() + * @threadsafe + */ +void clearerr(FILE *f) { + flockfile(f); + clearerr_unlocked(f); + funlockfile(f); } diff --git a/libc/stdio/unlocked/feof_unlocked.S b/libc/stdio/clearerr_unlocked.c similarity index 79% rename from libc/stdio/unlocked/feof_unlocked.S rename to libc/stdio/clearerr_unlocked.c index d60b6bfad..d06719d15 100644 --- a/libc/stdio/unlocked/feof_unlocked.S +++ b/libc/stdio/clearerr_unlocked.c @@ -1,5 +1,5 @@ -/*-*- 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│ +/*-*- 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 2020 Justine Alexandra Roberts Tunney │ │ │ @@ -16,15 +16,8 @@ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ -#include "libc/macros.internal.h" +#include "libc/stdio/stdio.h" -// Returns true if stream is in end-of-file state. -// -// @param rdi has file stream object pointer -// @note EOF doesn't count -// @see feof_unlocked() -// @threadsafe -feof: mov %rdi,%r11 - ezlea feof_unlocked,ax - jmp stdio_unlock - .endfn feof,globl +void clearerr_unlocked(FILE *f) { + f->state = 0; +} diff --git a/libc/stdio/feof.c b/libc/stdio/feof.c index 550abfc94..eeca17292 100644 --- a/libc/stdio/feof.c +++ b/libc/stdio/feof.c @@ -20,7 +20,15 @@ /** * Returns true if stream is in end-of-file state. + * + * @param f is file object stream pointer + * @see feof_unlocked() + * @threadsafe */ -int feof_unlocked(FILE *f) { - return f->state == -1; +int feof(FILE *f) { + int rc; + flockfile(f); + rc = feof_unlocked(f); + funlockfile(f); + return rc; } diff --git a/libc/stdio/unlocked/ferror_unlocked.S b/libc/stdio/feof_unlocked.c similarity index 79% rename from libc/stdio/unlocked/ferror_unlocked.S rename to libc/stdio/feof_unlocked.c index 9db9ce695..62aea2269 100644 --- a/libc/stdio/unlocked/ferror_unlocked.S +++ b/libc/stdio/feof_unlocked.c @@ -1,5 +1,5 @@ -/*-*- 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│ +/*-*- 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 │ │ │ @@ -16,15 +16,14 @@ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ -#include "libc/macros.internal.h" +#include "libc/stdio/stdio.h" -// Returns nonzero if stream is in error state. -// -// @param rdi has file stream object pointer -// @note EOF doesn't count -// @see ferror_unlocked() -// @threadsafe -ferror: mov %rdi,%r11 - ezlea ferror_unlocked,ax - jmp stdio_unlock - .endfn ferror,globl +/** + * Returns true if stream is in end-of-file state. + * + * @param f is file object stream pointer + * @see feof() + */ +int feof_unlocked(FILE *f) { + return f->state == -1; +} diff --git a/libc/stdio/ferror.c b/libc/stdio/ferror.c index d44c3a638..d11ef64f7 100644 --- a/libc/stdio/ferror.c +++ b/libc/stdio/ferror.c @@ -21,9 +21,16 @@ /** * Returns nonzero if stream is in error state. * + * @param f is file stream pointer + * @return non-zero if and only if it's an error state + * @see ferror_unlocked(), feof() * @note EOF doesn't count - * @see feof() + * @threadsafe */ -errno_t ferror_unlocked(FILE *f) { - return f->state > 0 ? f->state : 0; +errno_t ferror(FILE *f) { + int rc; + flockfile(f); + rc = ferror_unlocked(f); + funlockfile(f); + return rc; } diff --git a/libc/stdio/ferror_unlocked.c b/libc/stdio/ferror_unlocked.c new file mode 100644 index 000000000..46f2e988f --- /dev/null +++ b/libc/stdio/ferror_unlocked.c @@ -0,0 +1,31 @@ +/*-*- 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/stdio/stdio.h" + +/** + * Returns nonzero if stream is in error state. + * + * @param f is file stream pointer + * @return non-zero if and only if it's an error state + * @note EOF doesn't count + * @see ferror(), feof() + */ +errno_t ferror_unlocked(FILE *f) { + return f->state > 0 ? f->state : 0; +} diff --git a/libc/stdio/fgetc.c b/libc/stdio/fgetc.c index 9ed38a2fb..a1efa1de1 100644 --- a/libc/stdio/fgetc.c +++ b/libc/stdio/fgetc.c @@ -20,14 +20,16 @@ /** * Reads byte from stream. + * + * @param f is non-null file object stream pointer * @return byte in range 0..255, or -1 w/ errno + * @see fgetc_unlocked() + * @threadsafe */ -int fgetc_unlocked(FILE *f) { - unsigned char b[1]; - if (f->beg < f->end) { - return f->buf[f->beg++] & 0xff; - } else { - if (!fread_unlocked(b, 1, 1, f)) return -1; - return b[0]; - } +int fgetc(FILE *f) { + int rc; + flockfile(f); + rc = fgetc_unlocked(f); + funlockfile(f); + return rc; } diff --git a/libc/stdio/fgetc_unlocked.c b/libc/stdio/fgetc_unlocked.c new file mode 100644 index 000000000..51a299220 --- /dev/null +++ b/libc/stdio/fgetc_unlocked.c @@ -0,0 +1,36 @@ +/*-*- 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/stdio/stdio.h" + +/** + * Reads byte from stream. + * + * @param f is file object stream pointer + * @return byte in range 0..255, or -1 w/ errno + * @see fgetc() + */ +int fgetc_unlocked(FILE *f) { + unsigned char b[1]; + if (f->beg < f->end) { + return f->buf[f->beg++] & 0xff; + } else { + if (!fread_unlocked(b, 1, 1, f)) return -1; + return b[0]; + } +} diff --git a/libc/stdio/fgets.c b/libc/stdio/fgets.c index 85d7ebc57..7bcb05ada 100644 --- a/libc/stdio/fgets.c +++ b/libc/stdio/fgets.c @@ -16,7 +16,6 @@ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ -#include "libc/errno.h" #include "libc/stdio/stdio.h" /** @@ -31,24 +30,13 @@ * @param f is non-null file oject stream pointer * @return s on success, NULL on error, or NULL if EOF happens when * zero characters have been read + * @see fgets_unlocked() + * @threadsafe */ -char *fgets_unlocked(char *s, int size, FILE *f) { - int c; - char *p; - p = s; - if (size > 0) { - while (--size > 0) { - if ((c = fgetc_unlocked(f)) == -1) { - if (ferror_unlocked(f) == EINTR) { - continue; - } else { - break; - } - } - *p++ = c & 255; - if (c == '\n') break; - } - *p = '\0'; - } - return p > s ? s : NULL; +char *fgets(char *s, int size, FILE *f) { + char *res; + flockfile(f); + res = fgets_unlocked(s, size, f); + funlockfile(f); + return res; } diff --git a/libc/stdio/fgets_unlocked.c b/libc/stdio/fgets_unlocked.c new file mode 100644 index 000000000..85d7ebc57 --- /dev/null +++ b/libc/stdio/fgets_unlocked.c @@ -0,0 +1,54 @@ +/*-*- 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 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/errno.h" +#include "libc/stdio/stdio.h" + +/** + * Reads line from stream. + * + * This function is similar to getline() except it'll truncate lines + * exceeding size. The line ending marker is included and may be removed + * using _chomp(). + * + * @param s is output buffer + * @param size is capacity of s + * @param f is non-null file oject stream pointer + * @return s on success, NULL on error, or NULL if EOF happens when + * zero characters have been read + */ +char *fgets_unlocked(char *s, int size, FILE *f) { + int c; + char *p; + p = s; + if (size > 0) { + while (--size > 0) { + if ((c = fgetc_unlocked(f)) == -1) { + if (ferror_unlocked(f) == EINTR) { + continue; + } else { + break; + } + } + *p++ = c & 255; + if (c == '\n') break; + } + *p = '\0'; + } + return p > s ? s : NULL; +} diff --git a/libc/stdio/fgetwc.c b/libc/stdio/fgetwc.c index 7f5a421d5..ca5e7a8f6 100644 --- a/libc/stdio/fgetwc.c +++ b/libc/stdio/fgetwc.c @@ -17,35 +17,19 @@ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/stdio/stdio.h" -#include "libc/str/thompike.h" -#include "libc/str/tpdecodecb.internal.h" /** * Reads UTF-8 character from stream. + * + * @param f is non-null file object stream pointer * @return wide character or -1 on EOF or error + * @see fgetwc_unlocked() + * @threadsafe */ -wint_t fgetwc_unlocked(FILE *f) { - int c, n; - wint_t b, x, y; - if (f->beg < f->end) { - b = f->buf[f->beg++] & 0xff; - } else if ((c = fgetc_unlocked(f)) != -1) { - b = c; - } else { - return -1; - } - if (b < 0300) return b; - n = ThomPikeLen(b); - x = ThomPikeByte(b); - while (--n) { - if ((c = fgetc_unlocked(f)) == -1) return -1; - y = c; - if (ThomPikeCont(y)) { - x = ThomPikeMerge(x, y); - } else { - ungetc_unlocked(y, f); - return b; - } - } - return x; +wint_t fgetwc(FILE *f) { + wint_t wc; + flockfile(f); + wc = fgetwc_unlocked(f); + funlockfile(f); + return wc; } diff --git a/libc/stdio/fgetwc_unlocked.c b/libc/stdio/fgetwc_unlocked.c new file mode 100644 index 000000000..7f5a421d5 --- /dev/null +++ b/libc/stdio/fgetwc_unlocked.c @@ -0,0 +1,51 @@ +/*-*- 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 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/stdio/stdio.h" +#include "libc/str/thompike.h" +#include "libc/str/tpdecodecb.internal.h" + +/** + * Reads UTF-8 character from stream. + * @return wide character or -1 on EOF or error + */ +wint_t fgetwc_unlocked(FILE *f) { + int c, n; + wint_t b, x, y; + if (f->beg < f->end) { + b = f->buf[f->beg++] & 0xff; + } else if ((c = fgetc_unlocked(f)) != -1) { + b = c; + } else { + return -1; + } + if (b < 0300) return b; + n = ThomPikeLen(b); + x = ThomPikeByte(b); + while (--n) { + if ((c = fgetc_unlocked(f)) == -1) return -1; + y = c; + if (ThomPikeCont(y)) { + x = ThomPikeMerge(x, y); + } else { + ungetc_unlocked(y, f); + return b; + } + } + return x; +} diff --git a/libc/stdio/unlocked/fgets_unlocked.S b/libc/stdio/unlocked/fgets_unlocked.S deleted file mode 100644 index 4f2116ec9..000000000 --- a/libc/stdio/unlocked/fgets_unlocked.S +++ /dev/null @@ -1,37 +0,0 @@ -/*-*- 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 │ -│ │ -│ 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" - -// Reads line from stream. -// -// This function is similar to getline() except it'll truncate -// lines exceeding size. The line ending marker is included -// and may be removed using _chomp(). -// -// @param rdi is output buffer -// @param rsi is size of rdi buffer -// @param rdx is file stream object pointer -// @return rax has rdi on success, NULL on error or -// NULL if EOF happens with zero chars read -// @see fgets_unlocked() -// @threadsafe -fgets: mov %rdx,%r11 - ezlea fgets_unlocked,ax - jmp stdio_unlock - .endfn fgets,globl diff --git a/libc/stdio/unlocked/fgetwc_unlocked.S b/libc/stdio/unlocked/fgetwc_unlocked.S deleted file mode 100644 index ec28e1370..000000000 --- a/libc/stdio/unlocked/fgetwc_unlocked.S +++ /dev/null @@ -1,30 +0,0 @@ -/*-*- 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 │ -│ │ -│ 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" - -// Reads UTF-8 wide character from stream. -// -// @param rdi has stream object pointer -// @return wide character or -1 on EOF or error -// @see fgetwc_unlocked() -// @threadsafe -fgetwc: mov %rdi,%r11 - ezlea fgetwc_unlocked,ax - jmp stdio_unlock - .endfn fgetwc,globl diff --git a/libc/stubs/ld.S b/libc/stubs/ld.S index c7e935a5d..f40a2d3b8 100644 --- a/libc/stubs/ld.S +++ b/libc/stubs/ld.S @@ -44,10 +44,12 @@ // Thread local boundaries defined by linker script // @see ape/ape.lds - _tbss_start = 0 - _tbss_end = 0 _tdata_start = 0 _tdata_end = 0 + _tdata_size = 0 + _tbss_start = 0 + _tbss_end = 0 + _tls_size = 0 .globl _base .globl ape_xlm @@ -63,10 +65,12 @@ .globl _end .globl _ereal .globl _etext - .globl _tbss_start - .globl _tbss_end .globl _tdata_start .globl _tdata_end + .globl _tdata_size + .globl _tbss_start + .globl _tbss_end + .globl _tls_size .globl __data_start .globl __data_end .globl __bss_start @@ -86,10 +90,12 @@ .weak _end .weak _ereal .weak _etext - .weak _tbss_start - .weak _tbss_end .weak _tdata_start .weak _tdata_end + .weak _tdata_size + .weak _tbss_start + .weak _tbss_end + .weak _tls_size .weak __data_start .weak __data_end .weak __bss_start diff --git a/libc/sysv/consts.sh b/libc/sysv/consts.sh index d73e7614e..34f2fe680 100755 --- a/libc/sysv/consts.sh +++ b/libc/sysv/consts.sh @@ -1285,6 +1285,14 @@ syscon rusage RUSAGE_THREAD 1 99 1 1 1 1 # faked nt & unavailable syscon rusage RUSAGE_CHILDREN -1 -1 -1 -1 -1 99 # unix consensus & unavailable on nt syscon rusage RUSAGE_BOTH -2 99 99 99 99 99 # woop +# fast userspace mutexes +# +# group name GNU/Systemd XNU's Not UNIX! FreeBSD OpenBSD NetBSD The New Technology Commentary +syscon futex FUTEX_WAIT 0 0 0 1 0 0 +syscon futex FUTEX_WAKE 1 0 0 2 0 0 +syscon futex FUTEX_REQUEUE 3 0 0 3 0 0 +syscon futex FUTEX_PRIVATE_FLAG 128 0 0 128 0 0 + # Teletypewriter Control, e.g. # # TCSETS → About 70,800 results (0.31 seconds) @@ -1817,14 +1825,6 @@ syscon misc DAY_5 0x02000b 11 11 10 10 0 syscon misc DAY_6 0x02000c 12 12 11 11 0 syscon misc DAY_7 0x02000d 13 13 12 12 0 -syscon misc FUTEX_PRIVATE_FLAG 128 0 0 0x80 0x80 0 -syscon misc FUTEX_REQUEUE 3 0 0 3 3 0 -syscon misc FUTEX_REQUEUE_PRIVATE 131 0 0 131 131 0 -syscon misc FUTEX_WAIT 0 0 0 1 1 0 -syscon misc FUTEX_WAIT_PRIVATE 128 0 0 129 129 0 -syscon misc FUTEX_WAKE 1 0 0 2 2 0 -syscon misc FUTEX_WAKE_PRIVATE 129 0 0 130 130 0 - syscon misc HOST_NOT_FOUND 1 1 1 1 1 0x2af9 # unix consensus syscon misc HOST_NAME_MAX 0x40 0 0 255 255 0 @@ -1880,7 +1880,7 @@ syscon misc FALLOC_FL_UNSHARE_RANGE 0x40 -1 -1 -1 -1 -1 # bsd cons # System Call Numbers. # # group name GNU/Systemd XNU's Not UNIX! FreeBSD OpenBSD NetBSD The New Technology -syscon nr __NR_exit 0x003c 0x2000169 0x01af 0x012e 0x136 0xfff # __bsdthread_terminate() on XNU, thr_exit() on FreeBSD, sys___threxit() on OpenBSD, __lwp_exit() on NetBSD +syscon nr __NR_exit 0x003c 0x2000169 0x01af 0x012e 0x136 0xfff # __bsdthread_terminate() on XNU, thr_exit() on FreeBSD, __threxit() on OpenBSD, __lwp_exit() on NetBSD syscon nr __NR_exit_group 0x00e7 0x2000001 0x0001 0x0001 0x001 0xfff syscon nr __NR_read 0x0000 0x2000003 0x0003 0x0003 0x003 0xfff syscon nr __NR_write 0x0001 0x2000004 0x0004 0x0004 0x004 0xfff diff --git a/libc/sysv/consts/FUTEX_PRIVATE_FLAG.S b/libc/sysv/consts/FUTEX_PRIVATE_FLAG.S index 3700a2d98..7bce21bc4 100644 --- a/libc/sysv/consts/FUTEX_PRIVATE_FLAG.S +++ b/libc/sysv/consts/FUTEX_PRIVATE_FLAG.S @@ -1,2 +1,2 @@ #include "libc/sysv/consts/syscon.internal.h" -.syscon misc,FUTEX_PRIVATE_FLAG,128,0,0,0x80,0x80,0 +.syscon futex,FUTEX_PRIVATE_FLAG,128,0,0,128,0,0 diff --git a/libc/sysv/consts/FUTEX_REQUEUE.S b/libc/sysv/consts/FUTEX_REQUEUE.S index f8f1f0b9e..bd5951023 100644 --- a/libc/sysv/consts/FUTEX_REQUEUE.S +++ b/libc/sysv/consts/FUTEX_REQUEUE.S @@ -1,2 +1,2 @@ #include "libc/sysv/consts/syscon.internal.h" -.syscon misc,FUTEX_REQUEUE,3,0,0,3,3,0 +.syscon futex,FUTEX_REQUEUE,3,0,0,3,0,0 diff --git a/libc/sysv/consts/FUTEX_REQUEUE_PRIVATE.S b/libc/sysv/consts/FUTEX_REQUEUE_PRIVATE.S deleted file mode 100644 index 97a3ad3df..000000000 --- a/libc/sysv/consts/FUTEX_REQUEUE_PRIVATE.S +++ /dev/null @@ -1,2 +0,0 @@ -#include "libc/sysv/consts/syscon.internal.h" -.syscon misc,FUTEX_REQUEUE_PRIVATE,131,0,0,131,131,0 diff --git a/libc/sysv/consts/FUTEX_WAIT.S b/libc/sysv/consts/FUTEX_WAIT.S index f17dc576e..8e9527b99 100644 --- a/libc/sysv/consts/FUTEX_WAIT.S +++ b/libc/sysv/consts/FUTEX_WAIT.S @@ -1,2 +1,2 @@ #include "libc/sysv/consts/syscon.internal.h" -.syscon misc,FUTEX_WAIT,0,0,0,1,1,0 +.syscon futex,FUTEX_WAIT,0,0,0,1,0,0 diff --git a/libc/sysv/consts/FUTEX_WAIT_PRIVATE.S b/libc/sysv/consts/FUTEX_WAIT_PRIVATE.S deleted file mode 100644 index 01189de70..000000000 --- a/libc/sysv/consts/FUTEX_WAIT_PRIVATE.S +++ /dev/null @@ -1,2 +0,0 @@ -#include "libc/sysv/consts/syscon.internal.h" -.syscon misc,FUTEX_WAIT_PRIVATE,128,0,0,129,129,0 diff --git a/libc/sysv/consts/FUTEX_WAKE.S b/libc/sysv/consts/FUTEX_WAKE.S index 5342bb7c3..db8ae328c 100644 --- a/libc/sysv/consts/FUTEX_WAKE.S +++ b/libc/sysv/consts/FUTEX_WAKE.S @@ -1,2 +1,2 @@ #include "libc/sysv/consts/syscon.internal.h" -.syscon misc,FUTEX_WAKE,1,0,0,2,2,0 +.syscon futex,FUTEX_WAKE,1,0,0,2,0,0 diff --git a/libc/sysv/consts/FUTEX_WAKE_PRIVATE.S b/libc/sysv/consts/FUTEX_WAKE_PRIVATE.S deleted file mode 100644 index 1411c7592..000000000 --- a/libc/sysv/consts/FUTEX_WAKE_PRIVATE.S +++ /dev/null @@ -1,2 +0,0 @@ -#include "libc/sysv/consts/syscon.internal.h" -.syscon misc,FUTEX_WAKE_PRIVATE,129,0,0,130,130,0 diff --git a/libc/sysv/consts/futex.h b/libc/sysv/consts/futex.h index 6fe97921c..3e13006be 100644 --- a/libc/sysv/consts/futex.h +++ b/libc/sysv/consts/futex.h @@ -2,24 +2,21 @@ #define COSMOPOLITAN_LIBC_SYSV_CONSTS_FUTEX_H_ #include "libc/runtime/symbolic.h" -#define FUTEX_PRIVATE_FLAG SYMBOLIC(FUTEX_PRIVATE_FLAG) -#define FUTEX_REQUEUE SYMBOLIC(FUTEX_REQUEUE) -#define FUTEX_REQUEUE_PRIVATE SYMBOLIC(FUTEX_REQUEUE_PRIVATE) #define FUTEX_WAIT SYMBOLIC(FUTEX_WAIT) -#define FUTEX_WAIT_PRIVATE SYMBOLIC(FUTEX_WAIT_PRIVATE) #define FUTEX_WAKE SYMBOLIC(FUTEX_WAKE) -#define FUTEX_WAKE_PRIVATE SYMBOLIC(FUTEX_WAKE_PRIVATE) +#define FUTEX_REQUEUE SYMBOLIC(FUTEX_REQUEUE) +#define FUTEX_PRIVATE_FLAG SYMBOLIC(FUTEX_PRIVATE_FLAG) +#define FUTEX_WAIT_PRIVATE (FUTEX_WAIT | FUTEX_PRIVATE_FLAG) +#define FUTEX_WAKE_PRIVATE (FUTEX_WAKE | FUTEX_PRIVATE_FLAG) +#define FUTEX_REQUEUE_PRIVATE (FUTEX_REQUEUE | FUTEX_PRIVATE_FLAG) #if !(__ASSEMBLER__ + __LINKER__ + 0) COSMOPOLITAN_C_START_ -extern const long FUTEX_PRIVATE_FLAG; -extern const long FUTEX_REQUEUE; -extern const long FUTEX_REQUEUE_PRIVATE; extern const long FUTEX_WAIT; -extern const long FUTEX_WAIT_PRIVATE; extern const long FUTEX_WAKE; -extern const long FUTEX_WAKE_PRIVATE; +extern const long FUTEX_REQUEUE; +extern const long FUTEX_PRIVATE_FLAG; COSMOPOLITAN_C_END_ #endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */ diff --git a/libc/stdio/unlocked/clearerr_unlocked.S b/libc/sysv/errfun.S similarity index 87% rename from libc/stdio/unlocked/clearerr_unlocked.S rename to libc/sysv/errfun.S index 8f8c7e9f4..7c4c549df 100644 --- a/libc/stdio/unlocked/clearerr_unlocked.S +++ b/libc/sysv/errfun.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 │ @@ -17,14 +17,12 @@ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/macros.internal.h" +.text.unlikely -// Clears error state on stream. -// -// @param rdi has stream pointer -// @see clearerr_unlocked() -// @threadsafe -clearerr: - mov %rdi,%r11 - ezlea clearerr_unlocked,ax - jmp stdio_unlock - .endfn clearerr,globl +__errfun: + .errno + mov %ecx,(%rax) + push $-1 + pop %rax + .leafepilogue + .endfn __errfun,globl,hidden diff --git a/libc/sysv/errfuns/e2big.S b/libc/sysv/errfuns/e2big.S index 3dee651a0..f92f7a0a6 100644 --- a/libc/sysv/errfuns/e2big.S +++ b/libc/sysv/errfuns/e2big.S @@ -1,13 +1,8 @@ #include "libc/macros.internal.h" .text.unlikely -.section .privileged,"ax",@progbits - e2big: .leafprologue + .profilable mov E2BIG(%rip),%ecx - .errno - mov %ecx,(%rax) - push $-1 - pop %rax - .leafepilogue + jmp __errfun .endfn e2big,globl,hidden diff --git a/libc/sysv/errfuns/eacces.S b/libc/sysv/errfuns/eacces.S index f0c068a4a..4732082c4 100644 --- a/libc/sysv/errfuns/eacces.S +++ b/libc/sysv/errfuns/eacces.S @@ -1,13 +1,8 @@ #include "libc/macros.internal.h" .text.unlikely -.section .privileged,"ax",@progbits - eacces: .leafprologue + .profilable mov EACCES(%rip),%ecx - .errno - mov %ecx,(%rax) - push $-1 - pop %rax - .leafepilogue + jmp __errfun .endfn eacces,globl,hidden diff --git a/libc/sysv/errfuns/eaddrinuse.S b/libc/sysv/errfuns/eaddrinuse.S index 88ed82ddf..ac5259926 100644 --- a/libc/sysv/errfuns/eaddrinuse.S +++ b/libc/sysv/errfuns/eaddrinuse.S @@ -1,14 +1,9 @@ #include "libc/macros.internal.h" .text.unlikely -.section .privileged,"ax",@progbits - eaddrinuse: .leafprologue + .profilable mov EADDRINUSE(%rip),%ecx - .errno - mov %ecx,(%rax) - push $-1 - pop %rax - .leafepilogue + jmp __errfun .endfn eaddrinuse,globl,hidden diff --git a/libc/sysv/errfuns/eaddrnotavail.S b/libc/sysv/errfuns/eaddrnotavail.S index e5d7cd459..a9c0cb91c 100644 --- a/libc/sysv/errfuns/eaddrnotavail.S +++ b/libc/sysv/errfuns/eaddrnotavail.S @@ -1,14 +1,9 @@ #include "libc/macros.internal.h" .text.unlikely -.section .privileged,"ax",@progbits - eaddrnotavail: .leafprologue + .profilable mov EADDRNOTAVAIL(%rip),%ecx - .errno - mov %ecx,(%rax) - push $-1 - pop %rax - .leafepilogue + jmp __errfun .endfn eaddrnotavail,globl,hidden diff --git a/libc/sysv/errfuns/eadv.S b/libc/sysv/errfuns/eadv.S index 2ec5fad55..8f30b8ab7 100644 --- a/libc/sysv/errfuns/eadv.S +++ b/libc/sysv/errfuns/eadv.S @@ -1,13 +1,8 @@ #include "libc/macros.internal.h" .text.unlikely -.section .privileged,"ax",@progbits - eadv: .leafprologue + .profilable mov EADV(%rip),%ecx - .errno - mov %ecx,(%rax) - push $-1 - pop %rax - .leafepilogue + jmp __errfun .endfn eadv,globl,hidden diff --git a/libc/sysv/errfuns/eafnosupport.S b/libc/sysv/errfuns/eafnosupport.S index bb61fdf6e..6f017d832 100644 --- a/libc/sysv/errfuns/eafnosupport.S +++ b/libc/sysv/errfuns/eafnosupport.S @@ -1,14 +1,9 @@ #include "libc/macros.internal.h" .text.unlikely -.section .privileged,"ax",@progbits - eafnosupport: .leafprologue + .profilable mov EAFNOSUPPORT(%rip),%ecx - .errno - mov %ecx,(%rax) - push $-1 - pop %rax - .leafepilogue + jmp __errfun .endfn eafnosupport,globl,hidden diff --git a/libc/sysv/errfuns/eagain.S b/libc/sysv/errfuns/eagain.S index 83ae5326a..0dcd6bbf8 100644 --- a/libc/sysv/errfuns/eagain.S +++ b/libc/sysv/errfuns/eagain.S @@ -1,13 +1,8 @@ #include "libc/macros.internal.h" .text.unlikely -.section .privileged,"ax",@progbits - eagain: .leafprologue + .profilable mov EAGAIN(%rip),%ecx - .errno - mov %ecx,(%rax) - push $-1 - pop %rax - .leafepilogue + jmp __errfun .endfn eagain,globl,hidden diff --git a/libc/sysv/errfuns/ealready.S b/libc/sysv/errfuns/ealready.S index 901053e4c..ab74e72f0 100644 --- a/libc/sysv/errfuns/ealready.S +++ b/libc/sysv/errfuns/ealready.S @@ -1,14 +1,9 @@ #include "libc/macros.internal.h" .text.unlikely -.section .privileged,"ax",@progbits - ealready: .leafprologue + .profilable mov EALREADY(%rip),%ecx - .errno - mov %ecx,(%rax) - push $-1 - pop %rax - .leafepilogue + jmp __errfun .endfn ealready,globl,hidden diff --git a/libc/sysv/errfuns/ebade.S b/libc/sysv/errfuns/ebade.S index bba37cbff..140e3a29f 100644 --- a/libc/sysv/errfuns/ebade.S +++ b/libc/sysv/errfuns/ebade.S @@ -1,13 +1,8 @@ #include "libc/macros.internal.h" .text.unlikely -.section .privileged,"ax",@progbits - ebade: .leafprologue + .profilable mov EBADE(%rip),%ecx - .errno - mov %ecx,(%rax) - push $-1 - pop %rax - .leafepilogue + jmp __errfun .endfn ebade,globl,hidden diff --git a/libc/sysv/errfuns/ebadf.S b/libc/sysv/errfuns/ebadf.S index faf167f73..70db3a2b4 100644 --- a/libc/sysv/errfuns/ebadf.S +++ b/libc/sysv/errfuns/ebadf.S @@ -1,13 +1,8 @@ #include "libc/macros.internal.h" .text.unlikely -.section .privileged,"ax",@progbits - ebadf: .leafprologue + .profilable mov EBADF(%rip),%ecx - .errno - mov %ecx,(%rax) - push $-1 - pop %rax - .leafepilogue + jmp __errfun .endfn ebadf,globl,hidden diff --git a/libc/sysv/errfuns/ebadfd.S b/libc/sysv/errfuns/ebadfd.S index 8b05e7210..b034d6530 100644 --- a/libc/sysv/errfuns/ebadfd.S +++ b/libc/sysv/errfuns/ebadfd.S @@ -1,13 +1,8 @@ #include "libc/macros.internal.h" .text.unlikely -.section .privileged,"ax",@progbits - ebadfd: .leafprologue + .profilable mov EBADFD(%rip),%ecx - .errno - mov %ecx,(%rax) - push $-1 - pop %rax - .leafepilogue + jmp __errfun .endfn ebadfd,globl,hidden diff --git a/libc/sysv/errfuns/ebadmsg.S b/libc/sysv/errfuns/ebadmsg.S index 5a4560b5e..7a0f4a89a 100644 --- a/libc/sysv/errfuns/ebadmsg.S +++ b/libc/sysv/errfuns/ebadmsg.S @@ -1,14 +1,9 @@ #include "libc/macros.internal.h" .text.unlikely -.section .privileged,"ax",@progbits - ebadmsg: .leafprologue + .profilable mov EBADMSG(%rip),%ecx - .errno - mov %ecx,(%rax) - push $-1 - pop %rax - .leafepilogue + jmp __errfun .endfn ebadmsg,globl,hidden diff --git a/libc/sysv/errfuns/ebadr.S b/libc/sysv/errfuns/ebadr.S index 7822e2997..353be7769 100644 --- a/libc/sysv/errfuns/ebadr.S +++ b/libc/sysv/errfuns/ebadr.S @@ -1,13 +1,8 @@ #include "libc/macros.internal.h" .text.unlikely -.section .privileged,"ax",@progbits - ebadr: .leafprologue + .profilable mov EBADR(%rip),%ecx - .errno - mov %ecx,(%rax) - push $-1 - pop %rax - .leafepilogue + jmp __errfun .endfn ebadr,globl,hidden diff --git a/libc/sysv/errfuns/ebadrqc.S b/libc/sysv/errfuns/ebadrqc.S index 4ebe49fc0..2be7a42ec 100644 --- a/libc/sysv/errfuns/ebadrqc.S +++ b/libc/sysv/errfuns/ebadrqc.S @@ -1,14 +1,9 @@ #include "libc/macros.internal.h" .text.unlikely -.section .privileged,"ax",@progbits - ebadrqc: .leafprologue + .profilable mov EBADRQC(%rip),%ecx - .errno - mov %ecx,(%rax) - push $-1 - pop %rax - .leafepilogue + jmp __errfun .endfn ebadrqc,globl,hidden diff --git a/libc/sysv/errfuns/ebadslt.S b/libc/sysv/errfuns/ebadslt.S index 389f326b3..e9eb61ce9 100644 --- a/libc/sysv/errfuns/ebadslt.S +++ b/libc/sysv/errfuns/ebadslt.S @@ -1,14 +1,9 @@ #include "libc/macros.internal.h" .text.unlikely -.section .privileged,"ax",@progbits - ebadslt: .leafprologue + .profilable mov EBADSLT(%rip),%ecx - .errno - mov %ecx,(%rax) - push $-1 - pop %rax - .leafepilogue + jmp __errfun .endfn ebadslt,globl,hidden diff --git a/libc/sysv/errfuns/ebusy.S b/libc/sysv/errfuns/ebusy.S index 0d10fbe26..5d7fd977f 100644 --- a/libc/sysv/errfuns/ebusy.S +++ b/libc/sysv/errfuns/ebusy.S @@ -1,13 +1,8 @@ #include "libc/macros.internal.h" .text.unlikely -.section .privileged,"ax",@progbits - ebusy: .leafprologue + .profilable mov EBUSY(%rip),%ecx - .errno - mov %ecx,(%rax) - push $-1 - pop %rax - .leafepilogue + jmp __errfun .endfn ebusy,globl,hidden diff --git a/libc/sysv/errfuns/ecanceled.S b/libc/sysv/errfuns/ecanceled.S index c1182c9c2..eb0dce20a 100644 --- a/libc/sysv/errfuns/ecanceled.S +++ b/libc/sysv/errfuns/ecanceled.S @@ -1,14 +1,9 @@ #include "libc/macros.internal.h" .text.unlikely -.section .privileged,"ax",@progbits - ecanceled: .leafprologue + .profilable mov ECANCELED(%rip),%ecx - .errno - mov %ecx,(%rax) - push $-1 - pop %rax - .leafepilogue + jmp __errfun .endfn ecanceled,globl,hidden diff --git a/libc/sysv/errfuns/echild.S b/libc/sysv/errfuns/echild.S index fb8905559..0a2709c20 100644 --- a/libc/sysv/errfuns/echild.S +++ b/libc/sysv/errfuns/echild.S @@ -1,13 +1,8 @@ #include "libc/macros.internal.h" .text.unlikely -.section .privileged,"ax",@progbits - echild: .leafprologue + .profilable mov ECHILD(%rip),%ecx - .errno - mov %ecx,(%rax) - push $-1 - pop %rax - .leafepilogue + jmp __errfun .endfn echild,globl,hidden diff --git a/libc/sysv/errfuns/echrng.S b/libc/sysv/errfuns/echrng.S index 272ca1fc5..a2a207bbb 100644 --- a/libc/sysv/errfuns/echrng.S +++ b/libc/sysv/errfuns/echrng.S @@ -1,13 +1,8 @@ #include "libc/macros.internal.h" .text.unlikely -.section .privileged,"ax",@progbits - echrng: .leafprologue + .profilable mov ECHRNG(%rip),%ecx - .errno - mov %ecx,(%rax) - push $-1 - pop %rax - .leafepilogue + jmp __errfun .endfn echrng,globl,hidden diff --git a/libc/sysv/errfuns/ecomm.S b/libc/sysv/errfuns/ecomm.S index 159a3057b..4bd2f236b 100644 --- a/libc/sysv/errfuns/ecomm.S +++ b/libc/sysv/errfuns/ecomm.S @@ -1,13 +1,8 @@ #include "libc/macros.internal.h" .text.unlikely -.section .privileged,"ax",@progbits - ecomm: .leafprologue + .profilable mov ECOMM(%rip),%ecx - .errno - mov %ecx,(%rax) - push $-1 - pop %rax - .leafepilogue + jmp __errfun .endfn ecomm,globl,hidden diff --git a/libc/sysv/errfuns/econnaborted.S b/libc/sysv/errfuns/econnaborted.S index a3af8c15d..aa28861e4 100644 --- a/libc/sysv/errfuns/econnaborted.S +++ b/libc/sysv/errfuns/econnaborted.S @@ -1,14 +1,9 @@ #include "libc/macros.internal.h" .text.unlikely -.section .privileged,"ax",@progbits - econnaborted: .leafprologue + .profilable mov ECONNABORTED(%rip),%ecx - .errno - mov %ecx,(%rax) - push $-1 - pop %rax - .leafepilogue + jmp __errfun .endfn econnaborted,globl,hidden diff --git a/libc/sysv/errfuns/econnrefused.S b/libc/sysv/errfuns/econnrefused.S index 293e09244..3db4eef6e 100644 --- a/libc/sysv/errfuns/econnrefused.S +++ b/libc/sysv/errfuns/econnrefused.S @@ -1,14 +1,9 @@ #include "libc/macros.internal.h" .text.unlikely -.section .privileged,"ax",@progbits - econnrefused: .leafprologue + .profilable mov ECONNREFUSED(%rip),%ecx - .errno - mov %ecx,(%rax) - push $-1 - pop %rax - .leafepilogue + jmp __errfun .endfn econnrefused,globl,hidden diff --git a/libc/sysv/errfuns/econnreset.S b/libc/sysv/errfuns/econnreset.S index da02e7656..3effb8195 100644 --- a/libc/sysv/errfuns/econnreset.S +++ b/libc/sysv/errfuns/econnreset.S @@ -1,14 +1,9 @@ #include "libc/macros.internal.h" .text.unlikely -.section .privileged,"ax",@progbits - econnreset: .leafprologue + .profilable mov ECONNRESET(%rip),%ecx - .errno - mov %ecx,(%rax) - push $-1 - pop %rax - .leafepilogue + jmp __errfun .endfn econnreset,globl,hidden diff --git a/libc/sysv/errfuns/edeadlk.S b/libc/sysv/errfuns/edeadlk.S index e38afcad5..d49691d32 100644 --- a/libc/sysv/errfuns/edeadlk.S +++ b/libc/sysv/errfuns/edeadlk.S @@ -1,14 +1,9 @@ #include "libc/macros.internal.h" .text.unlikely -.section .privileged,"ax",@progbits - edeadlk: .leafprologue + .profilable mov EDEADLK(%rip),%ecx - .errno - mov %ecx,(%rax) - push $-1 - pop %rax - .leafepilogue + jmp __errfun .endfn edeadlk,globl,hidden diff --git a/libc/sysv/errfuns/edestaddrreq.S b/libc/sysv/errfuns/edestaddrreq.S index 01db20eca..2fe69ada3 100644 --- a/libc/sysv/errfuns/edestaddrreq.S +++ b/libc/sysv/errfuns/edestaddrreq.S @@ -1,14 +1,9 @@ #include "libc/macros.internal.h" .text.unlikely -.section .privileged,"ax",@progbits - edestaddrreq: .leafprologue + .profilable mov EDESTADDRREQ(%rip),%ecx - .errno - mov %ecx,(%rax) - push $-1 - pop %rax - .leafepilogue + jmp __errfun .endfn edestaddrreq,globl,hidden diff --git a/libc/sysv/errfuns/edom.S b/libc/sysv/errfuns/edom.S index 97fdd0351..79860d335 100644 --- a/libc/sysv/errfuns/edom.S +++ b/libc/sysv/errfuns/edom.S @@ -1,13 +1,8 @@ #include "libc/macros.internal.h" .text.unlikely -.section .privileged,"ax",@progbits - edom: .leafprologue + .profilable mov EDOM(%rip),%ecx - .errno - mov %ecx,(%rax) - push $-1 - pop %rax - .leafepilogue + jmp __errfun .endfn edom,globl,hidden diff --git a/libc/sysv/errfuns/edotdot.S b/libc/sysv/errfuns/edotdot.S index cf9188238..2d24bc9d9 100644 --- a/libc/sysv/errfuns/edotdot.S +++ b/libc/sysv/errfuns/edotdot.S @@ -1,14 +1,9 @@ #include "libc/macros.internal.h" .text.unlikely -.section .privileged,"ax",@progbits - edotdot: .leafprologue + .profilable mov EDOTDOT(%rip),%ecx - .errno - mov %ecx,(%rax) - push $-1 - pop %rax - .leafepilogue + jmp __errfun .endfn edotdot,globl,hidden diff --git a/libc/sysv/errfuns/edquot.S b/libc/sysv/errfuns/edquot.S index f41ed9d9a..6d7263a8e 100644 --- a/libc/sysv/errfuns/edquot.S +++ b/libc/sysv/errfuns/edquot.S @@ -1,13 +1,8 @@ #include "libc/macros.internal.h" .text.unlikely -.section .privileged,"ax",@progbits - edquot: .leafprologue + .profilable mov EDQUOT(%rip),%ecx - .errno - mov %ecx,(%rax) - push $-1 - pop %rax - .leafepilogue + jmp __errfun .endfn edquot,globl,hidden diff --git a/libc/sysv/errfuns/eexist.S b/libc/sysv/errfuns/eexist.S index eb33d9a4a..b5dbf0db5 100644 --- a/libc/sysv/errfuns/eexist.S +++ b/libc/sysv/errfuns/eexist.S @@ -1,13 +1,8 @@ #include "libc/macros.internal.h" .text.unlikely -.section .privileged,"ax",@progbits - eexist: .leafprologue + .profilable mov EEXIST(%rip),%ecx - .errno - mov %ecx,(%rax) - push $-1 - pop %rax - .leafepilogue + jmp __errfun .endfn eexist,globl,hidden diff --git a/libc/sysv/errfuns/efault.S b/libc/sysv/errfuns/efault.S index 6f21320b0..c67571a62 100644 --- a/libc/sysv/errfuns/efault.S +++ b/libc/sysv/errfuns/efault.S @@ -1,13 +1,8 @@ #include "libc/macros.internal.h" .text.unlikely -.section .privileged,"ax",@progbits - efault: .leafprologue + .profilable mov EFAULT(%rip),%ecx - .errno - mov %ecx,(%rax) - push $-1 - pop %rax - .leafepilogue + jmp __errfun .endfn efault,globl,hidden diff --git a/libc/sysv/errfuns/efbig.S b/libc/sysv/errfuns/efbig.S index 1c445d2e0..607373c2b 100644 --- a/libc/sysv/errfuns/efbig.S +++ b/libc/sysv/errfuns/efbig.S @@ -1,13 +1,8 @@ #include "libc/macros.internal.h" .text.unlikely -.section .privileged,"ax",@progbits - efbig: .leafprologue + .profilable mov EFBIG(%rip),%ecx - .errno - mov %ecx,(%rax) - push $-1 - pop %rax - .leafepilogue + jmp __errfun .endfn efbig,globl,hidden diff --git a/libc/sysv/errfuns/ehostdown.S b/libc/sysv/errfuns/ehostdown.S index a33bf3d23..2999ef8c2 100644 --- a/libc/sysv/errfuns/ehostdown.S +++ b/libc/sysv/errfuns/ehostdown.S @@ -1,14 +1,9 @@ #include "libc/macros.internal.h" .text.unlikely -.section .privileged,"ax",@progbits - ehostdown: .leafprologue + .profilable mov EHOSTDOWN(%rip),%ecx - .errno - mov %ecx,(%rax) - push $-1 - pop %rax - .leafepilogue + jmp __errfun .endfn ehostdown,globl,hidden diff --git a/libc/sysv/errfuns/ehostunreach.S b/libc/sysv/errfuns/ehostunreach.S index 9de92d917..48b693cc6 100644 --- a/libc/sysv/errfuns/ehostunreach.S +++ b/libc/sysv/errfuns/ehostunreach.S @@ -1,14 +1,9 @@ #include "libc/macros.internal.h" .text.unlikely -.section .privileged,"ax",@progbits - ehostunreach: .leafprologue + .profilable mov EHOSTUNREACH(%rip),%ecx - .errno - mov %ecx,(%rax) - push $-1 - pop %rax - .leafepilogue + jmp __errfun .endfn ehostunreach,globl,hidden diff --git a/libc/sysv/errfuns/ehwpoison.S b/libc/sysv/errfuns/ehwpoison.S index 24103a255..54ffe73d0 100644 --- a/libc/sysv/errfuns/ehwpoison.S +++ b/libc/sysv/errfuns/ehwpoison.S @@ -1,14 +1,9 @@ #include "libc/macros.internal.h" .text.unlikely -.section .privileged,"ax",@progbits - ehwpoison: .leafprologue + .profilable mov EHWPOISON(%rip),%ecx - .errno - mov %ecx,(%rax) - push $-1 - pop %rax - .leafepilogue + jmp __errfun .endfn ehwpoison,globl,hidden diff --git a/libc/sysv/errfuns/eidrm.S b/libc/sysv/errfuns/eidrm.S index 8b90827df..8d37404c8 100644 --- a/libc/sysv/errfuns/eidrm.S +++ b/libc/sysv/errfuns/eidrm.S @@ -1,13 +1,8 @@ #include "libc/macros.internal.h" .text.unlikely -.section .privileged,"ax",@progbits - eidrm: .leafprologue + .profilable mov EIDRM(%rip),%ecx - .errno - mov %ecx,(%rax) - push $-1 - pop %rax - .leafepilogue + jmp __errfun .endfn eidrm,globl,hidden diff --git a/libc/sysv/errfuns/eilseq.S b/libc/sysv/errfuns/eilseq.S index 689becc06..e1e7eb969 100644 --- a/libc/sysv/errfuns/eilseq.S +++ b/libc/sysv/errfuns/eilseq.S @@ -1,13 +1,8 @@ #include "libc/macros.internal.h" .text.unlikely -.section .privileged,"ax",@progbits - eilseq: .leafprologue + .profilable mov EILSEQ(%rip),%ecx - .errno - mov %ecx,(%rax) - push $-1 - pop %rax - .leafepilogue + jmp __errfun .endfn eilseq,globl,hidden diff --git a/libc/sysv/errfuns/einprogress.S b/libc/sysv/errfuns/einprogress.S index b0d7549c6..50995f90b 100644 --- a/libc/sysv/errfuns/einprogress.S +++ b/libc/sysv/errfuns/einprogress.S @@ -1,14 +1,9 @@ #include "libc/macros.internal.h" .text.unlikely -.section .privileged,"ax",@progbits - einprogress: .leafprologue + .profilable mov EINPROGRESS(%rip),%ecx - .errno - mov %ecx,(%rax) - push $-1 - pop %rax - .leafepilogue + jmp __errfun .endfn einprogress,globl,hidden diff --git a/libc/sysv/errfuns/eintr.S b/libc/sysv/errfuns/eintr.S index 9836589f8..31b06dbb7 100644 --- a/libc/sysv/errfuns/eintr.S +++ b/libc/sysv/errfuns/eintr.S @@ -1,13 +1,8 @@ #include "libc/macros.internal.h" .text.unlikely -.section .privileged,"ax",@progbits - eintr: .leafprologue + .profilable mov EINTR(%rip),%ecx - .errno - mov %ecx,(%rax) - push $-1 - pop %rax - .leafepilogue + jmp __errfun .endfn eintr,globl,hidden diff --git a/libc/sysv/errfuns/einval.S b/libc/sysv/errfuns/einval.S index 83eb007d3..181a69722 100644 --- a/libc/sysv/errfuns/einval.S +++ b/libc/sysv/errfuns/einval.S @@ -1,13 +1,8 @@ #include "libc/macros.internal.h" .text.unlikely -.section .privileged,"ax",@progbits - einval: .leafprologue + .profilable mov EINVAL(%rip),%ecx - .errno - mov %ecx,(%rax) - push $-1 - pop %rax - .leafepilogue + jmp __errfun .endfn einval,globl,hidden diff --git a/libc/sysv/errfuns/eio.S b/libc/sysv/errfuns/eio.S index fcedc61d1..2b9536835 100644 --- a/libc/sysv/errfuns/eio.S +++ b/libc/sysv/errfuns/eio.S @@ -1,13 +1,8 @@ #include "libc/macros.internal.h" .text.unlikely -.section .privileged,"ax",@progbits - eio: .leafprologue + .profilable mov EIO(%rip),%ecx - .errno - mov %ecx,(%rax) - push $-1 - pop %rax - .leafepilogue + jmp __errfun .endfn eio,globl,hidden diff --git a/libc/sysv/errfuns/eisconn.S b/libc/sysv/errfuns/eisconn.S index 65ba958cf..79af6bd51 100644 --- a/libc/sysv/errfuns/eisconn.S +++ b/libc/sysv/errfuns/eisconn.S @@ -1,14 +1,9 @@ #include "libc/macros.internal.h" .text.unlikely -.section .privileged,"ax",@progbits - eisconn: .leafprologue + .profilable mov EISCONN(%rip),%ecx - .errno - mov %ecx,(%rax) - push $-1 - pop %rax - .leafepilogue + jmp __errfun .endfn eisconn,globl,hidden diff --git a/libc/sysv/errfuns/eisdir.S b/libc/sysv/errfuns/eisdir.S index 514e60049..7ca7895d0 100644 --- a/libc/sysv/errfuns/eisdir.S +++ b/libc/sysv/errfuns/eisdir.S @@ -1,13 +1,8 @@ #include "libc/macros.internal.h" .text.unlikely -.section .privileged,"ax",@progbits - eisdir: .leafprologue + .profilable mov EISDIR(%rip),%ecx - .errno - mov %ecx,(%rax) - push $-1 - pop %rax - .leafepilogue + jmp __errfun .endfn eisdir,globl,hidden diff --git a/libc/sysv/errfuns/eisnam.S b/libc/sysv/errfuns/eisnam.S index b4d5af446..20259a92d 100644 --- a/libc/sysv/errfuns/eisnam.S +++ b/libc/sysv/errfuns/eisnam.S @@ -1,13 +1,8 @@ #include "libc/macros.internal.h" .text.unlikely -.section .privileged,"ax",@progbits - eisnam: .leafprologue + .profilable mov EISNAM(%rip),%ecx - .errno - mov %ecx,(%rax) - push $-1 - pop %rax - .leafepilogue + jmp __errfun .endfn eisnam,globl,hidden diff --git a/libc/sysv/errfuns/ekeyexpired.S b/libc/sysv/errfuns/ekeyexpired.S index 4aa6dae18..5a4dd091a 100644 --- a/libc/sysv/errfuns/ekeyexpired.S +++ b/libc/sysv/errfuns/ekeyexpired.S @@ -1,14 +1,9 @@ #include "libc/macros.internal.h" .text.unlikely -.section .privileged,"ax",@progbits - ekeyexpired: .leafprologue + .profilable mov EKEYEXPIRED(%rip),%ecx - .errno - mov %ecx,(%rax) - push $-1 - pop %rax - .leafepilogue + jmp __errfun .endfn ekeyexpired,globl,hidden diff --git a/libc/sysv/errfuns/ekeyrejected.S b/libc/sysv/errfuns/ekeyrejected.S index 92f289082..b0a60a165 100644 --- a/libc/sysv/errfuns/ekeyrejected.S +++ b/libc/sysv/errfuns/ekeyrejected.S @@ -1,14 +1,9 @@ #include "libc/macros.internal.h" .text.unlikely -.section .privileged,"ax",@progbits - ekeyrejected: .leafprologue + .profilable mov EKEYREJECTED(%rip),%ecx - .errno - mov %ecx,(%rax) - push $-1 - pop %rax - .leafepilogue + jmp __errfun .endfn ekeyrejected,globl,hidden diff --git a/libc/sysv/errfuns/ekeyrevoked.S b/libc/sysv/errfuns/ekeyrevoked.S index 4d2afd375..2cc80110a 100644 --- a/libc/sysv/errfuns/ekeyrevoked.S +++ b/libc/sysv/errfuns/ekeyrevoked.S @@ -1,14 +1,9 @@ #include "libc/macros.internal.h" .text.unlikely -.section .privileged,"ax",@progbits - ekeyrevoked: .leafprologue + .profilable mov EKEYREVOKED(%rip),%ecx - .errno - mov %ecx,(%rax) - push $-1 - pop %rax - .leafepilogue + jmp __errfun .endfn ekeyrevoked,globl,hidden diff --git a/libc/sysv/errfuns/el2hlt.S b/libc/sysv/errfuns/el2hlt.S index e804afa80..8b7258771 100644 --- a/libc/sysv/errfuns/el2hlt.S +++ b/libc/sysv/errfuns/el2hlt.S @@ -1,13 +1,8 @@ #include "libc/macros.internal.h" .text.unlikely -.section .privileged,"ax",@progbits - el2hlt: .leafprologue + .profilable mov EL2HLT(%rip),%ecx - .errno - mov %ecx,(%rax) - push $-1 - pop %rax - .leafepilogue + jmp __errfun .endfn el2hlt,globl,hidden diff --git a/libc/sysv/errfuns/el2nsync.S b/libc/sysv/errfuns/el2nsync.S index a48b7b518..dfdb408bb 100644 --- a/libc/sysv/errfuns/el2nsync.S +++ b/libc/sysv/errfuns/el2nsync.S @@ -1,14 +1,9 @@ #include "libc/macros.internal.h" .text.unlikely -.section .privileged,"ax",@progbits - el2nsync: .leafprologue + .profilable mov EL2NSYNC(%rip),%ecx - .errno - mov %ecx,(%rax) - push $-1 - pop %rax - .leafepilogue + jmp __errfun .endfn el2nsync,globl,hidden diff --git a/libc/sysv/errfuns/el3hlt.S b/libc/sysv/errfuns/el3hlt.S index 0650f2e7d..9a3adba9c 100644 --- a/libc/sysv/errfuns/el3hlt.S +++ b/libc/sysv/errfuns/el3hlt.S @@ -1,13 +1,8 @@ #include "libc/macros.internal.h" .text.unlikely -.section .privileged,"ax",@progbits - el3hlt: .leafprologue + .profilable mov EL3HLT(%rip),%ecx - .errno - mov %ecx,(%rax) - push $-1 - pop %rax - .leafepilogue + jmp __errfun .endfn el3hlt,globl,hidden diff --git a/libc/sysv/errfuns/el3rst.S b/libc/sysv/errfuns/el3rst.S index a0e55575a..341309fad 100644 --- a/libc/sysv/errfuns/el3rst.S +++ b/libc/sysv/errfuns/el3rst.S @@ -1,13 +1,8 @@ #include "libc/macros.internal.h" .text.unlikely -.section .privileged,"ax",@progbits - el3rst: .leafprologue + .profilable mov EL3RST(%rip),%ecx - .errno - mov %ecx,(%rax) - push $-1 - pop %rax - .leafepilogue + jmp __errfun .endfn el3rst,globl,hidden diff --git a/libc/sysv/errfuns/elibacc.S b/libc/sysv/errfuns/elibacc.S index efbd75f3c..c3a4bf9c1 100644 --- a/libc/sysv/errfuns/elibacc.S +++ b/libc/sysv/errfuns/elibacc.S @@ -1,14 +1,9 @@ #include "libc/macros.internal.h" .text.unlikely -.section .privileged,"ax",@progbits - elibacc: .leafprologue + .profilable mov ELIBACC(%rip),%ecx - .errno - mov %ecx,(%rax) - push $-1 - pop %rax - .leafepilogue + jmp __errfun .endfn elibacc,globl,hidden diff --git a/libc/sysv/errfuns/elibbad.S b/libc/sysv/errfuns/elibbad.S index 19a7b596c..5a0a91901 100644 --- a/libc/sysv/errfuns/elibbad.S +++ b/libc/sysv/errfuns/elibbad.S @@ -1,14 +1,9 @@ #include "libc/macros.internal.h" .text.unlikely -.section .privileged,"ax",@progbits - elibbad: .leafprologue + .profilable mov ELIBBAD(%rip),%ecx - .errno - mov %ecx,(%rax) - push $-1 - pop %rax - .leafepilogue + jmp __errfun .endfn elibbad,globl,hidden diff --git a/libc/sysv/errfuns/elibexec.S b/libc/sysv/errfuns/elibexec.S index 4e28fa32b..b90ca70ea 100644 --- a/libc/sysv/errfuns/elibexec.S +++ b/libc/sysv/errfuns/elibexec.S @@ -1,14 +1,9 @@ #include "libc/macros.internal.h" .text.unlikely -.section .privileged,"ax",@progbits - elibexec: .leafprologue + .profilable mov ELIBEXEC(%rip),%ecx - .errno - mov %ecx,(%rax) - push $-1 - pop %rax - .leafepilogue + jmp __errfun .endfn elibexec,globl,hidden diff --git a/libc/sysv/errfuns/elibmax.S b/libc/sysv/errfuns/elibmax.S index b14515535..6886b311a 100644 --- a/libc/sysv/errfuns/elibmax.S +++ b/libc/sysv/errfuns/elibmax.S @@ -1,14 +1,9 @@ #include "libc/macros.internal.h" .text.unlikely -.section .privileged,"ax",@progbits - elibmax: .leafprologue + .profilable mov ELIBMAX(%rip),%ecx - .errno - mov %ecx,(%rax) - push $-1 - pop %rax - .leafepilogue + jmp __errfun .endfn elibmax,globl,hidden diff --git a/libc/sysv/errfuns/elibscn.S b/libc/sysv/errfuns/elibscn.S index 4781f239d..5607cb1be 100644 --- a/libc/sysv/errfuns/elibscn.S +++ b/libc/sysv/errfuns/elibscn.S @@ -1,14 +1,9 @@ #include "libc/macros.internal.h" .text.unlikely -.section .privileged,"ax",@progbits - elibscn: .leafprologue + .profilable mov ELIBSCN(%rip),%ecx - .errno - mov %ecx,(%rax) - push $-1 - pop %rax - .leafepilogue + jmp __errfun .endfn elibscn,globl,hidden diff --git a/libc/sysv/errfuns/elnrng.S b/libc/sysv/errfuns/elnrng.S index 25cc0ef0d..0a96e722a 100644 --- a/libc/sysv/errfuns/elnrng.S +++ b/libc/sysv/errfuns/elnrng.S @@ -1,13 +1,8 @@ #include "libc/macros.internal.h" .text.unlikely -.section .privileged,"ax",@progbits - elnrng: .leafprologue + .profilable mov ELNRNG(%rip),%ecx - .errno - mov %ecx,(%rax) - push $-1 - pop %rax - .leafepilogue + jmp __errfun .endfn elnrng,globl,hidden diff --git a/libc/sysv/errfuns/eloop.S b/libc/sysv/errfuns/eloop.S index 3de12f39f..6c77a4f0e 100644 --- a/libc/sysv/errfuns/eloop.S +++ b/libc/sysv/errfuns/eloop.S @@ -1,13 +1,8 @@ #include "libc/macros.internal.h" .text.unlikely -.section .privileged,"ax",@progbits - eloop: .leafprologue + .profilable mov ELOOP(%rip),%ecx - .errno - mov %ecx,(%rax) - push $-1 - pop %rax - .leafepilogue + jmp __errfun .endfn eloop,globl,hidden diff --git a/libc/sysv/errfuns/emediumtype.S b/libc/sysv/errfuns/emediumtype.S index a3d7048ce..4c1ae3177 100644 --- a/libc/sysv/errfuns/emediumtype.S +++ b/libc/sysv/errfuns/emediumtype.S @@ -1,14 +1,9 @@ #include "libc/macros.internal.h" .text.unlikely -.section .privileged,"ax",@progbits - emediumtype: .leafprologue + .profilable mov EMEDIUMTYPE(%rip),%ecx - .errno - mov %ecx,(%rax) - push $-1 - pop %rax - .leafepilogue + jmp __errfun .endfn emediumtype,globl,hidden diff --git a/libc/sysv/errfuns/emfile.S b/libc/sysv/errfuns/emfile.S index f89eb0153..32d5979ec 100644 --- a/libc/sysv/errfuns/emfile.S +++ b/libc/sysv/errfuns/emfile.S @@ -1,13 +1,8 @@ #include "libc/macros.internal.h" .text.unlikely -.section .privileged,"ax",@progbits - emfile: .leafprologue + .profilable mov EMFILE(%rip),%ecx - .errno - mov %ecx,(%rax) - push $-1 - pop %rax - .leafepilogue + jmp __errfun .endfn emfile,globl,hidden diff --git a/libc/sysv/errfuns/emlink.S b/libc/sysv/errfuns/emlink.S index 2921a6f31..e40959fc7 100644 --- a/libc/sysv/errfuns/emlink.S +++ b/libc/sysv/errfuns/emlink.S @@ -1,13 +1,8 @@ #include "libc/macros.internal.h" .text.unlikely -.section .privileged,"ax",@progbits - emlink: .leafprologue + .profilable mov EMLINK(%rip),%ecx - .errno - mov %ecx,(%rax) - push $-1 - pop %rax - .leafepilogue + jmp __errfun .endfn emlink,globl,hidden diff --git a/libc/sysv/errfuns/emsgsize.S b/libc/sysv/errfuns/emsgsize.S index 4553b3c89..cfc4e0cb3 100644 --- a/libc/sysv/errfuns/emsgsize.S +++ b/libc/sysv/errfuns/emsgsize.S @@ -1,14 +1,9 @@ #include "libc/macros.internal.h" .text.unlikely -.section .privileged,"ax",@progbits - emsgsize: .leafprologue + .profilable mov EMSGSIZE(%rip),%ecx - .errno - mov %ecx,(%rax) - push $-1 - pop %rax - .leafepilogue + jmp __errfun .endfn emsgsize,globl,hidden diff --git a/libc/sysv/errfuns/emultihop.S b/libc/sysv/errfuns/emultihop.S index 4b28d701b..627d723c7 100644 --- a/libc/sysv/errfuns/emultihop.S +++ b/libc/sysv/errfuns/emultihop.S @@ -1,14 +1,9 @@ #include "libc/macros.internal.h" .text.unlikely -.section .privileged,"ax",@progbits - emultihop: .leafprologue + .profilable mov EMULTIHOP(%rip),%ecx - .errno - mov %ecx,(%rax) - push $-1 - pop %rax - .leafepilogue + jmp __errfun .endfn emultihop,globl,hidden diff --git a/libc/sysv/errfuns/enametoolong.S b/libc/sysv/errfuns/enametoolong.S index 2fc0821bb..a8fac2275 100644 --- a/libc/sysv/errfuns/enametoolong.S +++ b/libc/sysv/errfuns/enametoolong.S @@ -1,14 +1,9 @@ #include "libc/macros.internal.h" .text.unlikely -.section .privileged,"ax",@progbits - enametoolong: .leafprologue + .profilable mov ENAMETOOLONG(%rip),%ecx - .errno - mov %ecx,(%rax) - push $-1 - pop %rax - .leafepilogue + jmp __errfun .endfn enametoolong,globl,hidden diff --git a/libc/sysv/errfuns/enavail.S b/libc/sysv/errfuns/enavail.S index 130177053..3a4257435 100644 --- a/libc/sysv/errfuns/enavail.S +++ b/libc/sysv/errfuns/enavail.S @@ -1,14 +1,9 @@ #include "libc/macros.internal.h" .text.unlikely -.section .privileged,"ax",@progbits - enavail: .leafprologue + .profilable mov ENAVAIL(%rip),%ecx - .errno - mov %ecx,(%rax) - push $-1 - pop %rax - .leafepilogue + jmp __errfun .endfn enavail,globl,hidden diff --git a/libc/sysv/errfuns/enetdown.S b/libc/sysv/errfuns/enetdown.S index 4876ef920..4a7024d3f 100644 --- a/libc/sysv/errfuns/enetdown.S +++ b/libc/sysv/errfuns/enetdown.S @@ -1,14 +1,9 @@ #include "libc/macros.internal.h" .text.unlikely -.section .privileged,"ax",@progbits - enetdown: .leafprologue + .profilable mov ENETDOWN(%rip),%ecx - .errno - mov %ecx,(%rax) - push $-1 - pop %rax - .leafepilogue + jmp __errfun .endfn enetdown,globl,hidden diff --git a/libc/sysv/errfuns/enetreset.S b/libc/sysv/errfuns/enetreset.S index 33044fed7..dde0626b2 100644 --- a/libc/sysv/errfuns/enetreset.S +++ b/libc/sysv/errfuns/enetreset.S @@ -1,14 +1,9 @@ #include "libc/macros.internal.h" .text.unlikely -.section .privileged,"ax",@progbits - enetreset: .leafprologue + .profilable mov ENETRESET(%rip),%ecx - .errno - mov %ecx,(%rax) - push $-1 - pop %rax - .leafepilogue + jmp __errfun .endfn enetreset,globl,hidden diff --git a/libc/sysv/errfuns/enetunreach.S b/libc/sysv/errfuns/enetunreach.S index ea2037da1..de9a3ebfd 100644 --- a/libc/sysv/errfuns/enetunreach.S +++ b/libc/sysv/errfuns/enetunreach.S @@ -1,14 +1,9 @@ #include "libc/macros.internal.h" .text.unlikely -.section .privileged,"ax",@progbits - enetunreach: .leafprologue + .profilable mov ENETUNREACH(%rip),%ecx - .errno - mov %ecx,(%rax) - push $-1 - pop %rax - .leafepilogue + jmp __errfun .endfn enetunreach,globl,hidden diff --git a/libc/sysv/errfuns/enfile.S b/libc/sysv/errfuns/enfile.S index df349914e..57b750c86 100644 --- a/libc/sysv/errfuns/enfile.S +++ b/libc/sysv/errfuns/enfile.S @@ -1,13 +1,8 @@ #include "libc/macros.internal.h" .text.unlikely -.section .privileged,"ax",@progbits - enfile: .leafprologue + .profilable mov ENFILE(%rip),%ecx - .errno - mov %ecx,(%rax) - push $-1 - pop %rax - .leafepilogue + jmp __errfun .endfn enfile,globl,hidden diff --git a/libc/sysv/errfuns/enoano.S b/libc/sysv/errfuns/enoano.S index ec86713b3..8156727fc 100644 --- a/libc/sysv/errfuns/enoano.S +++ b/libc/sysv/errfuns/enoano.S @@ -1,13 +1,8 @@ #include "libc/macros.internal.h" .text.unlikely -.section .privileged,"ax",@progbits - enoano: .leafprologue + .profilable mov ENOANO(%rip),%ecx - .errno - mov %ecx,(%rax) - push $-1 - pop %rax - .leafepilogue + jmp __errfun .endfn enoano,globl,hidden diff --git a/libc/sysv/errfuns/enobufs.S b/libc/sysv/errfuns/enobufs.S index fba6728f3..7fcf5c965 100644 --- a/libc/sysv/errfuns/enobufs.S +++ b/libc/sysv/errfuns/enobufs.S @@ -1,14 +1,9 @@ #include "libc/macros.internal.h" .text.unlikely -.section .privileged,"ax",@progbits - enobufs: .leafprologue + .profilable mov ENOBUFS(%rip),%ecx - .errno - mov %ecx,(%rax) - push $-1 - pop %rax - .leafepilogue + jmp __errfun .endfn enobufs,globl,hidden diff --git a/libc/sysv/errfuns/enocsi.S b/libc/sysv/errfuns/enocsi.S index fdbd6614f..2eaf13fed 100644 --- a/libc/sysv/errfuns/enocsi.S +++ b/libc/sysv/errfuns/enocsi.S @@ -1,13 +1,8 @@ #include "libc/macros.internal.h" .text.unlikely -.section .privileged,"ax",@progbits - enocsi: .leafprologue + .profilable mov ENOCSI(%rip),%ecx - .errno - mov %ecx,(%rax) - push $-1 - pop %rax - .leafepilogue + jmp __errfun .endfn enocsi,globl,hidden diff --git a/libc/sysv/errfuns/enodata.S b/libc/sysv/errfuns/enodata.S index d41c30fad..896a364e2 100644 --- a/libc/sysv/errfuns/enodata.S +++ b/libc/sysv/errfuns/enodata.S @@ -1,14 +1,9 @@ #include "libc/macros.internal.h" .text.unlikely -.section .privileged,"ax",@progbits - enodata: .leafprologue + .profilable mov ENODATA(%rip),%ecx - .errno - mov %ecx,(%rax) - push $-1 - pop %rax - .leafepilogue + jmp __errfun .endfn enodata,globl,hidden diff --git a/libc/sysv/errfuns/enodev.S b/libc/sysv/errfuns/enodev.S index d2495a202..83734be1b 100644 --- a/libc/sysv/errfuns/enodev.S +++ b/libc/sysv/errfuns/enodev.S @@ -1,13 +1,8 @@ #include "libc/macros.internal.h" .text.unlikely -.section .privileged,"ax",@progbits - enodev: .leafprologue + .profilable mov ENODEV(%rip),%ecx - .errno - mov %ecx,(%rax) - push $-1 - pop %rax - .leafepilogue + jmp __errfun .endfn enodev,globl,hidden diff --git a/libc/sysv/errfuns/enoent.S b/libc/sysv/errfuns/enoent.S index 5ffe65072..c2dbf5309 100644 --- a/libc/sysv/errfuns/enoent.S +++ b/libc/sysv/errfuns/enoent.S @@ -1,13 +1,8 @@ #include "libc/macros.internal.h" .text.unlikely -.section .privileged,"ax",@progbits - enoent: .leafprologue + .profilable mov ENOENT(%rip),%ecx - .errno - mov %ecx,(%rax) - push $-1 - pop %rax - .leafepilogue + jmp __errfun .endfn enoent,globl,hidden diff --git a/libc/sysv/errfuns/enoexec.S b/libc/sysv/errfuns/enoexec.S index 582dc1061..18803b17d 100644 --- a/libc/sysv/errfuns/enoexec.S +++ b/libc/sysv/errfuns/enoexec.S @@ -1,14 +1,9 @@ #include "libc/macros.internal.h" .text.unlikely -.section .privileged,"ax",@progbits - enoexec: .leafprologue + .profilable mov ENOEXEC(%rip),%ecx - .errno - mov %ecx,(%rax) - push $-1 - pop %rax - .leafepilogue + jmp __errfun .endfn enoexec,globl,hidden diff --git a/libc/sysv/errfuns/enokey.S b/libc/sysv/errfuns/enokey.S index 69d99ddaa..5bb89f7df 100644 --- a/libc/sysv/errfuns/enokey.S +++ b/libc/sysv/errfuns/enokey.S @@ -1,13 +1,8 @@ #include "libc/macros.internal.h" .text.unlikely -.section .privileged,"ax",@progbits - enokey: .leafprologue + .profilable mov ENOKEY(%rip),%ecx - .errno - mov %ecx,(%rax) - push $-1 - pop %rax - .leafepilogue + jmp __errfun .endfn enokey,globl,hidden diff --git a/libc/sysv/errfuns/enolck.S b/libc/sysv/errfuns/enolck.S index f4596bde2..170e98bcf 100644 --- a/libc/sysv/errfuns/enolck.S +++ b/libc/sysv/errfuns/enolck.S @@ -1,13 +1,8 @@ #include "libc/macros.internal.h" .text.unlikely -.section .privileged,"ax",@progbits - enolck: .leafprologue + .profilable mov ENOLCK(%rip),%ecx - .errno - mov %ecx,(%rax) - push $-1 - pop %rax - .leafepilogue + jmp __errfun .endfn enolck,globl,hidden diff --git a/libc/sysv/errfuns/enolink.S b/libc/sysv/errfuns/enolink.S index 4d42660e7..2528a2d81 100644 --- a/libc/sysv/errfuns/enolink.S +++ b/libc/sysv/errfuns/enolink.S @@ -1,14 +1,9 @@ #include "libc/macros.internal.h" .text.unlikely -.section .privileged,"ax",@progbits - enolink: .leafprologue + .profilable mov ENOLINK(%rip),%ecx - .errno - mov %ecx,(%rax) - push $-1 - pop %rax - .leafepilogue + jmp __errfun .endfn enolink,globl,hidden diff --git a/libc/sysv/errfuns/enomedium.S b/libc/sysv/errfuns/enomedium.S index f83d3df1b..25b41757a 100644 --- a/libc/sysv/errfuns/enomedium.S +++ b/libc/sysv/errfuns/enomedium.S @@ -1,14 +1,9 @@ #include "libc/macros.internal.h" .text.unlikely -.section .privileged,"ax",@progbits - enomedium: .leafprologue + .profilable mov ENOMEDIUM(%rip),%ecx - .errno - mov %ecx,(%rax) - push $-1 - pop %rax - .leafepilogue + jmp __errfun .endfn enomedium,globl,hidden diff --git a/libc/sysv/errfuns/enomem.S b/libc/sysv/errfuns/enomem.S index cacd2fa07..99fe06ba1 100644 --- a/libc/sysv/errfuns/enomem.S +++ b/libc/sysv/errfuns/enomem.S @@ -1,13 +1,8 @@ #include "libc/macros.internal.h" .text.unlikely -.section .privileged,"ax",@progbits - enomem: .leafprologue + .profilable mov ENOMEM(%rip),%ecx - .errno - mov %ecx,(%rax) - push $-1 - pop %rax - .leafepilogue + jmp __errfun .endfn enomem,globl,hidden diff --git a/libc/sysv/errfuns/enomsg.S b/libc/sysv/errfuns/enomsg.S index a0efe0cea..5c69b73cf 100644 --- a/libc/sysv/errfuns/enomsg.S +++ b/libc/sysv/errfuns/enomsg.S @@ -1,13 +1,8 @@ #include "libc/macros.internal.h" .text.unlikely -.section .privileged,"ax",@progbits - enomsg: .leafprologue + .profilable mov ENOMSG(%rip),%ecx - .errno - mov %ecx,(%rax) - push $-1 - pop %rax - .leafepilogue + jmp __errfun .endfn enomsg,globl,hidden diff --git a/libc/sysv/errfuns/enonet.S b/libc/sysv/errfuns/enonet.S index 1a476bfb9..74702f0fc 100644 --- a/libc/sysv/errfuns/enonet.S +++ b/libc/sysv/errfuns/enonet.S @@ -1,13 +1,8 @@ #include "libc/macros.internal.h" .text.unlikely -.section .privileged,"ax",@progbits - enonet: .leafprologue + .profilable mov ENONET(%rip),%ecx - .errno - mov %ecx,(%rax) - push $-1 - pop %rax - .leafepilogue + jmp __errfun .endfn enonet,globl,hidden diff --git a/libc/sysv/errfuns/enopkg.S b/libc/sysv/errfuns/enopkg.S index f7eac5594..c3eb5056c 100644 --- a/libc/sysv/errfuns/enopkg.S +++ b/libc/sysv/errfuns/enopkg.S @@ -1,13 +1,8 @@ #include "libc/macros.internal.h" .text.unlikely -.section .privileged,"ax",@progbits - enopkg: .leafprologue + .profilable mov ENOPKG(%rip),%ecx - .errno - mov %ecx,(%rax) - push $-1 - pop %rax - .leafepilogue + jmp __errfun .endfn enopkg,globl,hidden diff --git a/libc/sysv/errfuns/enoprotoopt.S b/libc/sysv/errfuns/enoprotoopt.S index 4767e2858..f1ecd43f7 100644 --- a/libc/sysv/errfuns/enoprotoopt.S +++ b/libc/sysv/errfuns/enoprotoopt.S @@ -1,14 +1,9 @@ #include "libc/macros.internal.h" .text.unlikely -.section .privileged,"ax",@progbits - enoprotoopt: .leafprologue + .profilable mov ENOPROTOOPT(%rip),%ecx - .errno - mov %ecx,(%rax) - push $-1 - pop %rax - .leafepilogue + jmp __errfun .endfn enoprotoopt,globl,hidden diff --git a/libc/sysv/errfuns/enospc.S b/libc/sysv/errfuns/enospc.S index fdfd7b9bd..7e1074775 100644 --- a/libc/sysv/errfuns/enospc.S +++ b/libc/sysv/errfuns/enospc.S @@ -1,13 +1,8 @@ #include "libc/macros.internal.h" .text.unlikely -.section .privileged,"ax",@progbits - enospc: .leafprologue + .profilable mov ENOSPC(%rip),%ecx - .errno - mov %ecx,(%rax) - push $-1 - pop %rax - .leafepilogue + jmp __errfun .endfn enospc,globl,hidden diff --git a/libc/sysv/errfuns/enosr.S b/libc/sysv/errfuns/enosr.S index a7c919c96..be466fd09 100644 --- a/libc/sysv/errfuns/enosr.S +++ b/libc/sysv/errfuns/enosr.S @@ -1,13 +1,8 @@ #include "libc/macros.internal.h" .text.unlikely -.section .privileged,"ax",@progbits - enosr: .leafprologue + .profilable mov ENOSR(%rip),%ecx - .errno - mov %ecx,(%rax) - push $-1 - pop %rax - .leafepilogue + jmp __errfun .endfn enosr,globl,hidden diff --git a/libc/sysv/errfuns/enostr.S b/libc/sysv/errfuns/enostr.S index 3a8814f4c..76b02fc99 100644 --- a/libc/sysv/errfuns/enostr.S +++ b/libc/sysv/errfuns/enostr.S @@ -1,13 +1,8 @@ #include "libc/macros.internal.h" .text.unlikely -.section .privileged,"ax",@progbits - enostr: .leafprologue + .profilable mov ENOSTR(%rip),%ecx - .errno - mov %ecx,(%rax) - push $-1 - pop %rax - .leafepilogue + jmp __errfun .endfn enostr,globl,hidden diff --git a/libc/sysv/errfuns/enosys.S b/libc/sysv/errfuns/enosys.S index 09a1d2743..0c5b34638 100644 --- a/libc/sysv/errfuns/enosys.S +++ b/libc/sysv/errfuns/enosys.S @@ -1,13 +1,8 @@ #include "libc/macros.internal.h" .text.unlikely -.section .privileged,"ax",@progbits - enosys: .leafprologue + .profilable mov ENOSYS(%rip),%ecx - .errno - mov %ecx,(%rax) - push $-1 - pop %rax - .leafepilogue + jmp __errfun .endfn enosys,globl,hidden diff --git a/libc/sysv/errfuns/enotblk.S b/libc/sysv/errfuns/enotblk.S index 54eef8c9e..83bb06349 100644 --- a/libc/sysv/errfuns/enotblk.S +++ b/libc/sysv/errfuns/enotblk.S @@ -1,14 +1,9 @@ #include "libc/macros.internal.h" .text.unlikely -.section .privileged,"ax",@progbits - enotblk: .leafprologue + .profilable mov ENOTBLK(%rip),%ecx - .errno - mov %ecx,(%rax) - push $-1 - pop %rax - .leafepilogue + jmp __errfun .endfn enotblk,globl,hidden diff --git a/libc/sysv/errfuns/enotconn.S b/libc/sysv/errfuns/enotconn.S index 7c7762630..b94a5f779 100644 --- a/libc/sysv/errfuns/enotconn.S +++ b/libc/sysv/errfuns/enotconn.S @@ -1,14 +1,9 @@ #include "libc/macros.internal.h" .text.unlikely -.section .privileged,"ax",@progbits - enotconn: .leafprologue + .profilable mov ENOTCONN(%rip),%ecx - .errno - mov %ecx,(%rax) - push $-1 - pop %rax - .leafepilogue + jmp __errfun .endfn enotconn,globl,hidden diff --git a/libc/sysv/errfuns/enotdir.S b/libc/sysv/errfuns/enotdir.S index 9dd8d0e6f..d614544ae 100644 --- a/libc/sysv/errfuns/enotdir.S +++ b/libc/sysv/errfuns/enotdir.S @@ -1,14 +1,9 @@ #include "libc/macros.internal.h" .text.unlikely -.section .privileged,"ax",@progbits - enotdir: .leafprologue + .profilable mov ENOTDIR(%rip),%ecx - .errno - mov %ecx,(%rax) - push $-1 - pop %rax - .leafepilogue + jmp __errfun .endfn enotdir,globl,hidden diff --git a/libc/sysv/errfuns/enotempty.S b/libc/sysv/errfuns/enotempty.S index a686905b0..524ee50ca 100644 --- a/libc/sysv/errfuns/enotempty.S +++ b/libc/sysv/errfuns/enotempty.S @@ -1,14 +1,9 @@ #include "libc/macros.internal.h" .text.unlikely -.section .privileged,"ax",@progbits - enotempty: .leafprologue + .profilable mov ENOTEMPTY(%rip),%ecx - .errno - mov %ecx,(%rax) - push $-1 - pop %rax - .leafepilogue + jmp __errfun .endfn enotempty,globl,hidden diff --git a/libc/sysv/errfuns/enotnam.S b/libc/sysv/errfuns/enotnam.S index d96bb3c8e..6b5d500f9 100644 --- a/libc/sysv/errfuns/enotnam.S +++ b/libc/sysv/errfuns/enotnam.S @@ -1,14 +1,9 @@ #include "libc/macros.internal.h" .text.unlikely -.section .privileged,"ax",@progbits - enotnam: .leafprologue + .profilable mov ENOTNAM(%rip),%ecx - .errno - mov %ecx,(%rax) - push $-1 - pop %rax - .leafepilogue + jmp __errfun .endfn enotnam,globl,hidden diff --git a/libc/sysv/errfuns/enotrecoverable.S b/libc/sysv/errfuns/enotrecoverable.S index e94e3571d..78281dd27 100644 --- a/libc/sysv/errfuns/enotrecoverable.S +++ b/libc/sysv/errfuns/enotrecoverable.S @@ -1,14 +1,9 @@ #include "libc/macros.internal.h" .text.unlikely -.section .privileged,"ax",@progbits - enotrecoverable: .leafprologue + .profilable mov ENOTRECOVERABLE(%rip),%ecx - .errno - mov %ecx,(%rax) - push $-1 - pop %rax - .leafepilogue + jmp __errfun .endfn enotrecoverable,globl,hidden diff --git a/libc/sysv/errfuns/enotsock.S b/libc/sysv/errfuns/enotsock.S index 622795711..128837a63 100644 --- a/libc/sysv/errfuns/enotsock.S +++ b/libc/sysv/errfuns/enotsock.S @@ -1,14 +1,9 @@ #include "libc/macros.internal.h" .text.unlikely -.section .privileged,"ax",@progbits - enotsock: .leafprologue + .profilable mov ENOTSOCK(%rip),%ecx - .errno - mov %ecx,(%rax) - push $-1 - pop %rax - .leafepilogue + jmp __errfun .endfn enotsock,globl,hidden diff --git a/libc/sysv/errfuns/enotsup.S b/libc/sysv/errfuns/enotsup.S index 2018c9d13..006ba3f13 100644 --- a/libc/sysv/errfuns/enotsup.S +++ b/libc/sysv/errfuns/enotsup.S @@ -1,14 +1,9 @@ #include "libc/macros.internal.h" .text.unlikely -.section .privileged,"ax",@progbits - enotsup: .leafprologue + .profilable mov ENOTSUP(%rip),%ecx - .errno - mov %ecx,(%rax) - push $-1 - pop %rax - .leafepilogue + jmp __errfun .endfn enotsup,globl,hidden diff --git a/libc/sysv/errfuns/enotty.S b/libc/sysv/errfuns/enotty.S index 47bef3c9f..e4804e227 100644 --- a/libc/sysv/errfuns/enotty.S +++ b/libc/sysv/errfuns/enotty.S @@ -1,13 +1,8 @@ #include "libc/macros.internal.h" .text.unlikely -.section .privileged,"ax",@progbits - enotty: .leafprologue + .profilable mov ENOTTY(%rip),%ecx - .errno - mov %ecx,(%rax) - push $-1 - pop %rax - .leafepilogue + jmp __errfun .endfn enotty,globl,hidden diff --git a/libc/sysv/errfuns/enotuniq.S b/libc/sysv/errfuns/enotuniq.S index bf5d54242..6d5349b4b 100644 --- a/libc/sysv/errfuns/enotuniq.S +++ b/libc/sysv/errfuns/enotuniq.S @@ -1,14 +1,9 @@ #include "libc/macros.internal.h" .text.unlikely -.section .privileged,"ax",@progbits - enotuniq: .leafprologue + .profilable mov ENOTUNIQ(%rip),%ecx - .errno - mov %ecx,(%rax) - push $-1 - pop %rax - .leafepilogue + jmp __errfun .endfn enotuniq,globl,hidden diff --git a/libc/sysv/errfuns/enxio.S b/libc/sysv/errfuns/enxio.S index 03cb4d809..1cf27b514 100644 --- a/libc/sysv/errfuns/enxio.S +++ b/libc/sysv/errfuns/enxio.S @@ -1,13 +1,8 @@ #include "libc/macros.internal.h" .text.unlikely -.section .privileged,"ax",@progbits - enxio: .leafprologue + .profilable mov ENXIO(%rip),%ecx - .errno - mov %ecx,(%rax) - push $-1 - pop %rax - .leafepilogue + jmp __errfun .endfn enxio,globl,hidden diff --git a/libc/sysv/errfuns/eopnotsupp.S b/libc/sysv/errfuns/eopnotsupp.S index 07cf5dbd2..fffe53502 100644 --- a/libc/sysv/errfuns/eopnotsupp.S +++ b/libc/sysv/errfuns/eopnotsupp.S @@ -1,14 +1,9 @@ #include "libc/macros.internal.h" .text.unlikely -.section .privileged,"ax",@progbits - eopnotsupp: .leafprologue + .profilable mov EOPNOTSUPP(%rip),%ecx - .errno - mov %ecx,(%rax) - push $-1 - pop %rax - .leafepilogue + jmp __errfun .endfn eopnotsupp,globl,hidden diff --git a/libc/sysv/errfuns/eoverflow.S b/libc/sysv/errfuns/eoverflow.S index 6408fe872..2fc7b9998 100644 --- a/libc/sysv/errfuns/eoverflow.S +++ b/libc/sysv/errfuns/eoverflow.S @@ -1,14 +1,9 @@ #include "libc/macros.internal.h" .text.unlikely -.section .privileged,"ax",@progbits - eoverflow: .leafprologue + .profilable mov EOVERFLOW(%rip),%ecx - .errno - mov %ecx,(%rax) - push $-1 - pop %rax - .leafepilogue + jmp __errfun .endfn eoverflow,globl,hidden diff --git a/libc/sysv/errfuns/eownerdead.S b/libc/sysv/errfuns/eownerdead.S index cf7a3c63e..6a66e7146 100644 --- a/libc/sysv/errfuns/eownerdead.S +++ b/libc/sysv/errfuns/eownerdead.S @@ -1,14 +1,9 @@ #include "libc/macros.internal.h" .text.unlikely -.section .privileged,"ax",@progbits - eownerdead: .leafprologue + .profilable mov EOWNERDEAD(%rip),%ecx - .errno - mov %ecx,(%rax) - push $-1 - pop %rax - .leafepilogue + jmp __errfun .endfn eownerdead,globl,hidden diff --git a/libc/sysv/errfuns/eperm.S b/libc/sysv/errfuns/eperm.S index aded81083..e1bdafd89 100644 --- a/libc/sysv/errfuns/eperm.S +++ b/libc/sysv/errfuns/eperm.S @@ -1,13 +1,8 @@ #include "libc/macros.internal.h" .text.unlikely -.section .privileged,"ax",@progbits - eperm: .leafprologue + .profilable mov EPERM(%rip),%ecx - .errno - mov %ecx,(%rax) - push $-1 - pop %rax - .leafepilogue + jmp __errfun .endfn eperm,globl,hidden diff --git a/libc/sysv/errfuns/epfnosupport.S b/libc/sysv/errfuns/epfnosupport.S index 105fbee68..2e1006f39 100644 --- a/libc/sysv/errfuns/epfnosupport.S +++ b/libc/sysv/errfuns/epfnosupport.S @@ -1,14 +1,9 @@ #include "libc/macros.internal.h" .text.unlikely -.section .privileged,"ax",@progbits - epfnosupport: .leafprologue + .profilable mov EPFNOSUPPORT(%rip),%ecx - .errno - mov %ecx,(%rax) - push $-1 - pop %rax - .leafepilogue + jmp __errfun .endfn epfnosupport,globl,hidden diff --git a/libc/sysv/errfuns/epipe.S b/libc/sysv/errfuns/epipe.S index 1fff95c8d..eb9c532f1 100644 --- a/libc/sysv/errfuns/epipe.S +++ b/libc/sysv/errfuns/epipe.S @@ -1,13 +1,8 @@ #include "libc/macros.internal.h" .text.unlikely -.section .privileged,"ax",@progbits - epipe: .leafprologue + .profilable mov EPIPE(%rip),%ecx - .errno - mov %ecx,(%rax) - push $-1 - pop %rax - .leafepilogue + jmp __errfun .endfn epipe,globl,hidden diff --git a/libc/sysv/errfuns/eproto.S b/libc/sysv/errfuns/eproto.S index 4965378ae..dfb855a4b 100644 --- a/libc/sysv/errfuns/eproto.S +++ b/libc/sysv/errfuns/eproto.S @@ -1,13 +1,8 @@ #include "libc/macros.internal.h" .text.unlikely -.section .privileged,"ax",@progbits - eproto: .leafprologue + .profilable mov EPROTO(%rip),%ecx - .errno - mov %ecx,(%rax) - push $-1 - pop %rax - .leafepilogue + jmp __errfun .endfn eproto,globl,hidden diff --git a/libc/sysv/errfuns/eprotonosupport.S b/libc/sysv/errfuns/eprotonosupport.S index 3b3fc92ec..2c3a9a502 100644 --- a/libc/sysv/errfuns/eprotonosupport.S +++ b/libc/sysv/errfuns/eprotonosupport.S @@ -1,14 +1,9 @@ #include "libc/macros.internal.h" .text.unlikely -.section .privileged,"ax",@progbits - eprotonosupport: .leafprologue + .profilable mov EPROTONOSUPPORT(%rip),%ecx - .errno - mov %ecx,(%rax) - push $-1 - pop %rax - .leafepilogue + jmp __errfun .endfn eprotonosupport,globl,hidden diff --git a/libc/sysv/errfuns/eprototype.S b/libc/sysv/errfuns/eprototype.S index ad1471e01..aa45aa8ba 100644 --- a/libc/sysv/errfuns/eprototype.S +++ b/libc/sysv/errfuns/eprototype.S @@ -1,14 +1,9 @@ #include "libc/macros.internal.h" .text.unlikely -.section .privileged,"ax",@progbits - eprototype: .leafprologue + .profilable mov EPROTOTYPE(%rip),%ecx - .errno - mov %ecx,(%rax) - push $-1 - pop %rax - .leafepilogue + jmp __errfun .endfn eprototype,globl,hidden diff --git a/libc/sysv/errfuns/erange.S b/libc/sysv/errfuns/erange.S index d541322c9..898a21b99 100644 --- a/libc/sysv/errfuns/erange.S +++ b/libc/sysv/errfuns/erange.S @@ -1,13 +1,8 @@ #include "libc/macros.internal.h" .text.unlikely -.section .privileged,"ax",@progbits - erange: .leafprologue + .profilable mov ERANGE(%rip),%ecx - .errno - mov %ecx,(%rax) - push $-1 - pop %rax - .leafepilogue + jmp __errfun .endfn erange,globl,hidden diff --git a/libc/sysv/errfuns/eremchg.S b/libc/sysv/errfuns/eremchg.S index 4366c696a..05caafb60 100644 --- a/libc/sysv/errfuns/eremchg.S +++ b/libc/sysv/errfuns/eremchg.S @@ -1,14 +1,9 @@ #include "libc/macros.internal.h" .text.unlikely -.section .privileged,"ax",@progbits - eremchg: .leafprologue + .profilable mov EREMCHG(%rip),%ecx - .errno - mov %ecx,(%rax) - push $-1 - pop %rax - .leafepilogue + jmp __errfun .endfn eremchg,globl,hidden diff --git a/libc/sysv/errfuns/eremote.S b/libc/sysv/errfuns/eremote.S index 40b3595e0..c798603ea 100644 --- a/libc/sysv/errfuns/eremote.S +++ b/libc/sysv/errfuns/eremote.S @@ -1,14 +1,9 @@ #include "libc/macros.internal.h" .text.unlikely -.section .privileged,"ax",@progbits - eremote: .leafprologue + .profilable mov EREMOTE(%rip),%ecx - .errno - mov %ecx,(%rax) - push $-1 - pop %rax - .leafepilogue + jmp __errfun .endfn eremote,globl,hidden diff --git a/libc/sysv/errfuns/eremoteio.S b/libc/sysv/errfuns/eremoteio.S index 5631cfb58..ef8611e73 100644 --- a/libc/sysv/errfuns/eremoteio.S +++ b/libc/sysv/errfuns/eremoteio.S @@ -1,14 +1,9 @@ #include "libc/macros.internal.h" .text.unlikely -.section .privileged,"ax",@progbits - eremoteio: .leafprologue + .profilable mov EREMOTEIO(%rip),%ecx - .errno - mov %ecx,(%rax) - push $-1 - pop %rax - .leafepilogue + jmp __errfun .endfn eremoteio,globl,hidden diff --git a/libc/sysv/errfuns/erestart.S b/libc/sysv/errfuns/erestart.S index 668533c72..fcbf5629d 100644 --- a/libc/sysv/errfuns/erestart.S +++ b/libc/sysv/errfuns/erestart.S @@ -1,14 +1,9 @@ #include "libc/macros.internal.h" .text.unlikely -.section .privileged,"ax",@progbits - erestart: .leafprologue + .profilable mov ERESTART(%rip),%ecx - .errno - mov %ecx,(%rax) - push $-1 - pop %rax - .leafepilogue + jmp __errfun .endfn erestart,globl,hidden diff --git a/libc/sysv/errfuns/erfkill.S b/libc/sysv/errfuns/erfkill.S index 4f509f686..9ef8b1de8 100644 --- a/libc/sysv/errfuns/erfkill.S +++ b/libc/sysv/errfuns/erfkill.S @@ -1,14 +1,9 @@ #include "libc/macros.internal.h" .text.unlikely -.section .privileged,"ax",@progbits - erfkill: .leafprologue + .profilable mov ERFKILL(%rip),%ecx - .errno - mov %ecx,(%rax) - push $-1 - pop %rax - .leafepilogue + jmp __errfun .endfn erfkill,globl,hidden diff --git a/libc/sysv/errfuns/erofs.S b/libc/sysv/errfuns/erofs.S index 0468b5c38..140b9da90 100644 --- a/libc/sysv/errfuns/erofs.S +++ b/libc/sysv/errfuns/erofs.S @@ -1,13 +1,8 @@ #include "libc/macros.internal.h" .text.unlikely -.section .privileged,"ax",@progbits - erofs: .leafprologue + .profilable mov EROFS(%rip),%ecx - .errno - mov %ecx,(%rax) - push $-1 - pop %rax - .leafepilogue + jmp __errfun .endfn erofs,globl,hidden diff --git a/libc/sysv/errfuns/eshutdown.S b/libc/sysv/errfuns/eshutdown.S index 833f3f2c6..d3bf8cfa9 100644 --- a/libc/sysv/errfuns/eshutdown.S +++ b/libc/sysv/errfuns/eshutdown.S @@ -1,14 +1,9 @@ #include "libc/macros.internal.h" .text.unlikely -.section .privileged,"ax",@progbits - eshutdown: .leafprologue + .profilable mov ESHUTDOWN(%rip),%ecx - .errno - mov %ecx,(%rax) - push $-1 - pop %rax - .leafepilogue + jmp __errfun .endfn eshutdown,globl,hidden diff --git a/libc/sysv/errfuns/esocktnosupport.S b/libc/sysv/errfuns/esocktnosupport.S index d6d78a6c4..c6e4169eb 100644 --- a/libc/sysv/errfuns/esocktnosupport.S +++ b/libc/sysv/errfuns/esocktnosupport.S @@ -1,14 +1,9 @@ #include "libc/macros.internal.h" .text.unlikely -.section .privileged,"ax",@progbits - esocktnosupport: .leafprologue + .profilable mov ESOCKTNOSUPPORT(%rip),%ecx - .errno - mov %ecx,(%rax) - push $-1 - pop %rax - .leafepilogue + jmp __errfun .endfn esocktnosupport,globl,hidden diff --git a/libc/sysv/errfuns/espipe.S b/libc/sysv/errfuns/espipe.S index e23d80fca..292111032 100644 --- a/libc/sysv/errfuns/espipe.S +++ b/libc/sysv/errfuns/espipe.S @@ -1,13 +1,8 @@ #include "libc/macros.internal.h" .text.unlikely -.section .privileged,"ax",@progbits - espipe: .leafprologue + .profilable mov ESPIPE(%rip),%ecx - .errno - mov %ecx,(%rax) - push $-1 - pop %rax - .leafepilogue + jmp __errfun .endfn espipe,globl,hidden diff --git a/libc/sysv/errfuns/esrch.S b/libc/sysv/errfuns/esrch.S index a49b81a8a..7373d08d0 100644 --- a/libc/sysv/errfuns/esrch.S +++ b/libc/sysv/errfuns/esrch.S @@ -1,13 +1,8 @@ #include "libc/macros.internal.h" .text.unlikely -.section .privileged,"ax",@progbits - esrch: .leafprologue + .profilable mov ESRCH(%rip),%ecx - .errno - mov %ecx,(%rax) - push $-1 - pop %rax - .leafepilogue + jmp __errfun .endfn esrch,globl,hidden diff --git a/libc/sysv/errfuns/esrmnt.S b/libc/sysv/errfuns/esrmnt.S index fb19cda90..e737d47b6 100644 --- a/libc/sysv/errfuns/esrmnt.S +++ b/libc/sysv/errfuns/esrmnt.S @@ -1,13 +1,8 @@ #include "libc/macros.internal.h" .text.unlikely -.section .privileged,"ax",@progbits - esrmnt: .leafprologue + .profilable mov ESRMNT(%rip),%ecx - .errno - mov %ecx,(%rax) - push $-1 - pop %rax - .leafepilogue + jmp __errfun .endfn esrmnt,globl,hidden diff --git a/libc/sysv/errfuns/estale.S b/libc/sysv/errfuns/estale.S index 40e0e847a..0d891f2a0 100644 --- a/libc/sysv/errfuns/estale.S +++ b/libc/sysv/errfuns/estale.S @@ -1,13 +1,8 @@ #include "libc/macros.internal.h" .text.unlikely -.section .privileged,"ax",@progbits - estale: .leafprologue + .profilable mov ESTALE(%rip),%ecx - .errno - mov %ecx,(%rax) - push $-1 - pop %rax - .leafepilogue + jmp __errfun .endfn estale,globl,hidden diff --git a/libc/sysv/errfuns/estrpipe.S b/libc/sysv/errfuns/estrpipe.S index 8051599dc..e9bfece9e 100644 --- a/libc/sysv/errfuns/estrpipe.S +++ b/libc/sysv/errfuns/estrpipe.S @@ -1,14 +1,9 @@ #include "libc/macros.internal.h" .text.unlikely -.section .privileged,"ax",@progbits - estrpipe: .leafprologue + .profilable mov ESTRPIPE(%rip),%ecx - .errno - mov %ecx,(%rax) - push $-1 - pop %rax - .leafepilogue + jmp __errfun .endfn estrpipe,globl,hidden diff --git a/libc/sysv/errfuns/etime.S b/libc/sysv/errfuns/etime.S index 551d86c09..f835ca0fe 100644 --- a/libc/sysv/errfuns/etime.S +++ b/libc/sysv/errfuns/etime.S @@ -1,13 +1,8 @@ #include "libc/macros.internal.h" .text.unlikely -.section .privileged,"ax",@progbits - etime: .leafprologue + .profilable mov ETIME(%rip),%ecx - .errno - mov %ecx,(%rax) - push $-1 - pop %rax - .leafepilogue + jmp __errfun .endfn etime,globl,hidden diff --git a/libc/sysv/errfuns/etimedout.S b/libc/sysv/errfuns/etimedout.S index eff3c3292..20fd6b1f3 100644 --- a/libc/sysv/errfuns/etimedout.S +++ b/libc/sysv/errfuns/etimedout.S @@ -1,14 +1,9 @@ #include "libc/macros.internal.h" .text.unlikely -.section .privileged,"ax",@progbits - etimedout: .leafprologue + .profilable mov ETIMEDOUT(%rip),%ecx - .errno - mov %ecx,(%rax) - push $-1 - pop %rax - .leafepilogue + jmp __errfun .endfn etimedout,globl,hidden diff --git a/libc/sysv/errfuns/etoomanyrefs.S b/libc/sysv/errfuns/etoomanyrefs.S index 2fa0752a3..fe7d76a17 100644 --- a/libc/sysv/errfuns/etoomanyrefs.S +++ b/libc/sysv/errfuns/etoomanyrefs.S @@ -1,14 +1,9 @@ #include "libc/macros.internal.h" .text.unlikely -.section .privileged,"ax",@progbits - etoomanyrefs: .leafprologue + .profilable mov ETOOMANYREFS(%rip),%ecx - .errno - mov %ecx,(%rax) - push $-1 - pop %rax - .leafepilogue + jmp __errfun .endfn etoomanyrefs,globl,hidden diff --git a/libc/sysv/errfuns/etxtbsy.S b/libc/sysv/errfuns/etxtbsy.S index d3e390030..0d270027e 100644 --- a/libc/sysv/errfuns/etxtbsy.S +++ b/libc/sysv/errfuns/etxtbsy.S @@ -1,14 +1,9 @@ #include "libc/macros.internal.h" .text.unlikely -.section .privileged,"ax",@progbits - etxtbsy: .leafprologue + .profilable mov ETXTBSY(%rip),%ecx - .errno - mov %ecx,(%rax) - push $-1 - pop %rax - .leafepilogue + jmp __errfun .endfn etxtbsy,globl,hidden diff --git a/libc/sysv/errfuns/euclean.S b/libc/sysv/errfuns/euclean.S index af9217e97..8111a0cc3 100644 --- a/libc/sysv/errfuns/euclean.S +++ b/libc/sysv/errfuns/euclean.S @@ -1,14 +1,9 @@ #include "libc/macros.internal.h" .text.unlikely -.section .privileged,"ax",@progbits - euclean: .leafprologue + .profilable mov EUCLEAN(%rip),%ecx - .errno - mov %ecx,(%rax) - push $-1 - pop %rax - .leafepilogue + jmp __errfun .endfn euclean,globl,hidden diff --git a/libc/sysv/errfuns/eunatch.S b/libc/sysv/errfuns/eunatch.S index 97b639674..e155b5c03 100644 --- a/libc/sysv/errfuns/eunatch.S +++ b/libc/sysv/errfuns/eunatch.S @@ -1,14 +1,9 @@ #include "libc/macros.internal.h" .text.unlikely -.section .privileged,"ax",@progbits - eunatch: .leafprologue + .profilable mov EUNATCH(%rip),%ecx - .errno - mov %ecx,(%rax) - push $-1 - pop %rax - .leafepilogue + jmp __errfun .endfn eunatch,globl,hidden diff --git a/libc/sysv/errfuns/eusers.S b/libc/sysv/errfuns/eusers.S index 41a1e5a7d..4a3e504db 100644 --- a/libc/sysv/errfuns/eusers.S +++ b/libc/sysv/errfuns/eusers.S @@ -1,13 +1,8 @@ #include "libc/macros.internal.h" .text.unlikely -.section .privileged,"ax",@progbits - eusers: .leafprologue + .profilable mov EUSERS(%rip),%ecx - .errno - mov %ecx,(%rax) - push $-1 - pop %rax - .leafepilogue + jmp __errfun .endfn eusers,globl,hidden diff --git a/libc/sysv/errfuns/exdev.S b/libc/sysv/errfuns/exdev.S index 2f6b33ba5..4d9cc330f 100644 --- a/libc/sysv/errfuns/exdev.S +++ b/libc/sysv/errfuns/exdev.S @@ -1,13 +1,8 @@ #include "libc/macros.internal.h" .text.unlikely -.section .privileged,"ax",@progbits - exdev: .leafprologue + .profilable mov EXDEV(%rip),%ecx - .errno - mov %ecx,(%rax) - push $-1 - pop %rax - .leafepilogue + jmp __errfun .endfn exdev,globl,hidden diff --git a/libc/sysv/errfuns/exfull.S b/libc/sysv/errfuns/exfull.S index 22d7f6a93..c96809374 100644 --- a/libc/sysv/errfuns/exfull.S +++ b/libc/sysv/errfuns/exfull.S @@ -1,13 +1,8 @@ #include "libc/macros.internal.h" .text.unlikely -.section .privileged,"ax",@progbits - exfull: .leafprologue + .profilable mov EXFULL(%rip),%ecx - .errno - mov %ecx,(%rax) - push $-1 - pop %rax - .leafepilogue + jmp __errfun .endfn exfull,globl,hidden diff --git a/libc/sysv/gen.sh b/libc/sysv/gen.sh index b70ffdfd9..66013f198 100644 --- a/libc/sysv/gen.sh +++ b/libc/sysv/gen.sh @@ -47,18 +47,14 @@ errfun() { ERRNO="$2" { printf '#include "libc/macros.internal.h"\n.text.unlikely\n\n' - printf '.section .privileged,"ax",@progbits\n\n' printf '%s:' "$NAME" if [ "${#NAME}" -gt 6 ]; then printf '\n' fi printf ' .leafprologue + .profilable mov %s(%%rip),%%ecx - .errno - mov %%ecx,(%%rax) - push $-1 - pop %%rax - .leafepilogue + jmp __errfun .endfn %s,globl,hidden ' "$ERRNO" "$NAME" } >"$dir/${1/$/-}.S" diff --git a/libc/sysv/sysv.mk b/libc/sysv/sysv.mk index 9bade5fc2..2bd68845d 100644 --- a/libc/sysv/sysv.mk +++ b/libc/sysv/sysv.mk @@ -39,6 +39,7 @@ LIBC_SYSV_A_FILES := \ libc/sysv/systemfive.S \ libc/sysv/errno_location.greg.c \ libc/sysv/errno.c \ + libc/sysv/errfun.S \ libc/sysv/strace.greg.c \ libc/sysv/describeos.greg.c \ $(wildcard libc/sysv/consts/*) \ diff --git a/libc/testlib/quota.c b/libc/testlib/quota.c index a9e452a66..d454d141c 100644 --- a/libc/testlib/quota.c +++ b/libc/testlib/quota.c @@ -25,6 +25,7 @@ #include "libc/log/internal.h" #include "libc/log/libfatal.internal.h" #include "libc/log/log.h" +#include "libc/runtime/internal.h" #include "libc/runtime/memtrack.internal.h" #include "libc/runtime/runtime.h" #include "libc/stdio/stdio.h" @@ -49,7 +50,8 @@ static relegated void DieBecauseOfQuota(int rc, const char *message) { gethostname(hostname, sizeof(hostname)); kprintf("%s on %s pid %d\n", message, hostname, (long)getpid()); PrintBacktraceUsingSymbols(2, 0, GetSymbolTable()); - exit(rc); + __restorewintty(); + _Exit(rc); } static relegated void OnXcpu(int sig) { @@ -81,7 +83,8 @@ relegated void __oom_hook(size_t request) { kprintf("\nTHE STRAW THAT BROKE THE CAMEL'S BACK\n"); PrintBacktraceUsingSymbols(2, 0, GetSymbolTable()); PrintSystemMappings(2); - exit(42); + __restorewintty(); + _Exit(42); } static textstartup void InstallQuotaHandlers(void) { diff --git a/libc/testlib/showerror.c b/libc/testlib/showerror.c index d244e0ee4..680ee7ef6 100644 --- a/libc/testlib/showerror.c +++ b/libc/testlib/showerror.c @@ -20,6 +20,7 @@ #include "libc/calls/calls.h" #include "libc/fmt/fmt.h" #include "libc/intrin/kprintf.h" +#include "libc/intrin/spinlock.h" #include "libc/log/color.internal.h" #include "libc/log/internal.h" #include "libc/log/libfatal.internal.h" @@ -31,27 +32,30 @@ const char *testlib_showerror_func; const char *testlib_showerror_isfatal; const char *testlib_showerror_macro; const char *testlib_showerror_symbol; +_Alignas(64) static int testlib_showerror_lock; testonly void testlib_showerror(const char *file, int line, const char *func, const char *method, const char *symbol, const char *code, char *v1, char *v2) { char *p; char hostname[128]; + _spinlock(&testlib_showerror_lock); if (!IsWindows()) __getpid(); /* make strace easier to read */ if (!IsWindows()) __getpid(); __stpcpy(hostname, "unknown"); gethostname(hostname, sizeof(hostname)); - kprintf("%serror%s%s:%s:%d%s: %s() in %s(%s) on %s\n" + kprintf("%serror%s%s:%s:%d%s: %s() in %s(%s) on %s pid %d tid %d\n" "\t%s\n" "\t\tneed %s %s\n" "\t\t got %s\n" "\t%s%s\n" "\t%s%s\n", RED2, UNBOLD, BLUE1, file, (long)line, RESET, method, func, - g_fixturename, hostname, code, v1, symbol, v2, SUBTLE, - strerror(errno), GetProgramExecutableName(), RESET); + g_fixturename, hostname, getpid(), gettid(), code, v1, symbol, v2, + SUBTLE, strerror(errno), GetProgramExecutableName(), RESET); free_s(&v1); free_s(&v2); + _spunlock(&testlib_showerror_lock); } /* TODO(jart): Pay off tech debt re duplication */ @@ -61,16 +65,17 @@ testonly void testlib_showerror_(int line, const char *wantcode, int e; va_list va; char hostname[128]; + _spinlock(&testlib_showerror_lock); e = errno; if (!IsWindows()) __getpid(); if (!IsWindows()) __getpid(); if (gethostname(hostname, sizeof(hostname))) { __stpcpy(hostname, "unknown"); } - kprintf("%serror%s:%s%s:%d%s: %s(%s) on %s\n" + kprintf("%serror%s:%s%s:%d%s: %s(%s) on %s pid %d tid %d\n" "\t%s(%s, %s)\n", RED2, UNBOLD, BLUE1, testlib_showerror_file, line, RESET, - testlib_showerror_func, g_fixturename, hostname, + testlib_showerror_func, g_fixturename, hostname, getpid(), gettid(), testlib_showerror_macro, wantcode, gotcode); if (wantcode) { kprintf("\t\tneed %s %s\n" @@ -94,4 +99,5 @@ testonly void testlib_showerror_(int line, const char *wantcode, free_s(&FREED_got); ++g_testlib_failed; if (testlib_showerror_isfatal) testlib_abort(); + _spunlock(&testlib_showerror_lock); } diff --git a/libc/testlib/testrunner.c b/libc/testlib/testrunner.c index 090f7e656..526ec817d 100644 --- a/libc/testlib/testrunner.c +++ b/libc/testlib/testrunner.c @@ -33,6 +33,7 @@ #include "libc/log/internal.h" #include "libc/macros.internal.h" #include "libc/nt/process.h" +#include "libc/runtime/internal.h" #include "libc/runtime/runtime.h" #include "libc/runtime/symbols.internal.h" #include "libc/sock/sock.h" @@ -59,7 +60,8 @@ void testlib_finish(void) { wontreturn void testlib_abort(void) { testlib_finish(); - exit(MIN(255, g_testlib_failed)); + __restorewintty(); + _Exit(MIN(255, g_testlib_failed)); unreachable; } diff --git a/libc/thread/attr.c b/libc/thread/attr.c index cc139fb30..841446ce0 100644 --- a/libc/thread/attr.c +++ b/libc/thread/attr.c @@ -17,15 +17,16 @@ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/errno.h" +#include "libc/runtime/stack.h" #include "libc/thread/attr.h" -#define MIN_STACKSIZE (8 * PAGESIZE) +#define MIN_STACKSIZE (8 * PAGESIZE) // includes guard, rounds up to FRAMESIZE #define MIN_GUARDSIZE PAGESIZE // CTOR/DTOR int cthread_attr_init(cthread_attr_t* attr) { - attr->stacksize = 1024 * PAGESIZE; // 4 MiB - attr->guardsize = 16 * PAGESIZE; // 64 KiB + attr->stacksize = GetStackSize(); + attr->guardsize = PAGESIZE; attr->mode = CTHREAD_CREATE_JOINABLE; return 0; } diff --git a/libc/thread/create.c b/libc/thread/create.c index eeb1df7e6..bae59c26b 100644 --- a/libc/thread/create.c +++ b/libc/thread/create.c @@ -16,108 +16,117 @@ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ +#include "libc/bits/atomic.h" +#include "libc/calls/calls.h" +#include "libc/calls/strace.internal.h" #include "libc/errno.h" -#include "libc/linux/clone.h" +#include "libc/intrin/setjmp.internal.h" +#include "libc/macros.internal.h" +#include "libc/runtime/internal.h" #include "libc/runtime/runtime.h" #include "libc/str/str.h" #include "libc/sysv/consts/clone.h" #include "libc/sysv/consts/map.h" -#include "libc/sysv/consts/nr.h" #include "libc/sysv/consts/prot.h" +#include "libc/thread/attr.h" #include "libc/thread/create.h" +#include "libc/thread/descriptor.h" +#include "libc/thread/zombie.h" STATIC_YOINK("_main_thread_ctor"); -// TLS boundaries -extern char _tbss_start, _tbss_end, _tdata_start, _tdata_end; - -static cthread_t _thread_allocate(const cthread_attr_t* attr) { - size_t stacksize = attr->stacksize; - size_t guardsize = attr->guardsize; - size_t tbsssize = &_tbss_end - &_tbss_start; - size_t tdatasize = &_tdata_end - &_tdata_start; - size_t tlssize = tbsssize + tdatasize; - - size_t totalsize = - 3 * guardsize + stacksize + tlssize + sizeof(struct cthread_descriptor_t); - totalsize = (totalsize + PAGESIZE - 1) & -PAGESIZE; - - uintptr_t mem = (uintptr_t)mmap(NULL, totalsize, PROT_NONE, - MAP_ANONYMOUS | MAP_PRIVATE, -1, 0); - if (mem == -1) return NULL; - - void* alloc_bottom = (void*)mem; - void* stack_bottom = (void*)(mem + guardsize); - void* stack_top = (void*)(mem + guardsize + stacksize); - void* tls_bottom = (void*)(mem + guardsize + stacksize + guardsize); - void* tls_top = (void*)(mem + totalsize - guardsize); - void* alloc_top = (void*)(mem + totalsize); - - if (mprotect(stack_bottom, (uintptr_t)stack_top - (uintptr_t)stack_bottom, - PROT_READ | PROT_WRITE) != 0 || - mprotect(tls_bottom, (uintptr_t)tls_top - (uintptr_t)tls_bottom, - PROT_READ | PROT_WRITE) != 0) { - munmap(alloc_bottom, totalsize); - return NULL; +static cthread_t cthread_allocate(const cthread_attr_t *attr) { + char *mem; + size_t size; + cthread_t td; + size = ROUNDUP( + attr->stacksize + + ROUNDUP((uintptr_t)_tls_size + sizeof(struct cthread_descriptor_t), + PAGESIZE), + FRAMESIZE); + mem = mmap(0, size, PROT_READ | PROT_WRITE, MAP_STACK | MAP_ANONYMOUS, -1, 0); + if (mem == MAP_FAILED) return 0; + if (attr->guardsize > PAGESIZE) { + mprotect(mem, attr->guardsize, PROT_NONE); } - - cthread_t td = (cthread_t)tls_top - 1; + td = (cthread_t)(mem + size - sizeof(struct cthread_descriptor_t)); td->self = td; - td->stack.top = stack_top; - td->stack.bottom = stack_bottom; - td->tls.top = tls_top; - td->tls.bottom = tls_bottom; - td->alloc.top = alloc_top; - td->alloc.bottom = alloc_bottom; - td->state = (attr->mode & CTHREAD_CREATE_DETACHED) ? cthread_detached - : cthread_started; + td->self2 = td; + td->err = errno; + td->tid = -1; + td->stack.bottom = mem; + td->stack.top = mem + attr->stacksize; + td->alloc.bottom = mem; + td->alloc.top = mem + size; + if (attr->mode & CTHREAD_CREATE_DETACHED) { + td->state = cthread_detached; + } else { + td->state = cthread_started; + } // Initialize TLS with content of .tdata section - memmove((void*)((uintptr_t)td - tlssize), &_tdata_start, tdatasize); - + memmove((void *)((intptr_t)td - (intptr_t)_tls_size), _tdata_start, + (intptr_t)_tdata_size); return td; } -int cthread_create(cthread_t* restrict p, const cthread_attr_t* restrict attr, - int (*func)(void*), void* restrict arg) { - extern wontreturn void _thread_run(int (*func)(void*), void* arg); - - cthread_attr_t default_attr; - cthread_attr_init(&default_attr); - cthread_t td = _thread_allocate(attr ? attr : &default_attr); - cthread_attr_destroy(&default_attr); - if (!td) return errno; - - *p = td; - - register cthread_t td_ asm("r8") = td; - register int* ptid_ asm("rdx") = &td->tid; - register int* ctid_ asm("r10") = &td->tid; - register int (*func_)(void*) asm("r12") = func; - register void* arg_ asm("r13") = arg; - - long flags = CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_SIGHAND | - CLONE_PARENT | CLONE_THREAD | /*CLONE_IO |*/ CLONE_SETTLS | - CLONE_PARENT_SETTID | CLONE_CHILD_CLEARTID; - int rc; - // asm ensures the (empty) stack of the child thread is not used - asm volatile("syscall\n\t" // clone - "test\t%0, %0\n\t" // if not child - "jne\t.L.cthread_create.%=\n\t" // jump to `parent` label - "xor\t%%rbp, %%rbp\n\t" // reset stack frame pointer - "mov\t%2, %%rdi\n\t" - "call\t*%1\n\t" // call `func(arg)` - "mov\t%%rax, %%rdi\n\t" - "jmp\tcthread_exit\n" // exit thread - ".L.cthread_create.%=:" - : "=a"(rc) - : "r"(func_), "r"(arg_), "0"(__NR_clone), "D"(flags), - "S"(td->stack.top), "r"(ptid_), "r"(ctid_), "r"(td_) - : "rcx", "r11", "cc", "memory"); - if (__builtin_expect(rc < 0, 0)) { - // `clone` has failed. The thread must be deallocated. - size_t size = (intptr_t)(td->alloc.top) - (intptr_t)(td->alloc.bottom); - munmap(td->alloc.bottom, size); - return -rc; +static int cthread_start(void *arg) { + axdx_t rc; + void *exitcode; + cthread_t td = arg; + if (!(rc = setlongerjmp(td->exiter)).ax) { + exitcode = td->func(td->arg); + } else { + exitcode = (void *)rc.dx; } + td->exitcode = exitcode; + if (atomic_load(&td->state) & cthread_detached) { + // we're still using the stack + // thus we can't munmap it yet + // kick the can down the road! + cthread_zombies_add(td); + } + atomic_fetch_add(&td->state, cthread_finished); return 0; } + +/** + * Creates thread. + * + * @param ptd will receive pointer to new thread descriptor + * @param attr contains special configuration if non-null + * @param func is thread callback function + * @param arg is argument supplied to `func` + * @return 0 on success, or error number on failure + * @threadsafe + */ +int cthread_create(cthread_t *restrict ptd, const cthread_attr_t *restrict attr, + void *(*func)(void *), void *restrict arg) { + int rc, tid; + cthread_t td; + cthread_attr_t default_attr; + cthread_zombies_reap(); + cthread_attr_init(&default_attr); + if ((td = cthread_allocate(attr ? attr : &default_attr))) { + td->func = func; + td->arg = arg; + cthread_attr_destroy(&default_attr); + tid = + clone(cthread_start, td->stack.bottom, td->stack.top - td->stack.bottom, + CLONE_THREAD | CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_SIGHAND | + CLONE_SETTLS | CLONE_CHILD_SETTID | CLONE_CHILD_CLEARTID, + td, 0, td, sizeof(struct cthread_descriptor_t), &td->tid); + if (tid != -1) { + *ptd = td; + rc = 0; + } else { + rc = errno; + munmap(td->alloc.bottom, td->alloc.top - td->alloc.bottom); + } + } else { + rc = errno; + tid = -1; + } + STRACE("cthread_create([%d], %p, %p, %p) → %s", tid, attr, func, arg, + !rc ? "0" : strerrno(rc)); + return rc; +} diff --git a/libc/thread/create.h b/libc/thread/create.h index b13fd614c..452d0ff63 100644 --- a/libc/thread/create.h +++ b/libc/thread/create.h @@ -9,8 +9,8 @@ COSMOPOLITAN_C_START_ * @fileoverview Create a cosmopolitan thread */ -int cthread_create(cthread_t* restrict, const cthread_attr_t* restrict, - int (*)(void*), void* restrict); +int cthread_create(cthread_t *restrict, const cthread_attr_t *restrict, + void *(*)(void *), void *restrict); COSMOPOLITAN_C_END_ #endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */ diff --git a/libc/thread/descriptor.h b/libc/thread/descriptor.h index 29e815563..2b31dee3f 100644 --- a/libc/thread/descriptor.h +++ b/libc/thread/descriptor.h @@ -2,6 +2,7 @@ #define COSMOPOLITAN_LIBC_THREAD_DESCRIPTOR_H_ #if !(__ASSEMBLER__ + __LINKER__ + 0) COSMOPOLITAN_C_START_ +#include "libc/runtime/runtime.h" /** * @fileoverview thread types @@ -16,17 +17,24 @@ enum cthread_state { }; struct cthread_descriptor_t { - struct cthread_descriptor_t* self; /* mandatory for TLS */ + struct cthread_descriptor_t *self; /* 0x00 */ + void *(*func)(void *); /* 0x08 */ + int32_t __pad0; /* 0x10 */ + int32_t state; /* 0x14 */ + void *arg; /* 0x18 */ + void *pthread_ret_ptr; /* 0x20 */ + int64_t __pad1; /* 0x28 */ + struct cthread_descriptor_t *self2; /* 0x30 */ + int32_t tid; /* 0x38 */ + int32_t err; /* 0x3c */ + void *exitcode; struct { - void *top, *bottom; - } stack, tls, alloc; - int state; - int tid; - int rc; - void* pthread_ret_ptr; + char *top, *bottom; + } stack, alloc; + jmp_buf exiter; }; -typedef struct cthread_descriptor_t* cthread_t; +typedef struct cthread_descriptor_t *cthread_t; COSMOPOLITAN_C_END_ #endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */ diff --git a/libc/thread/detach.c b/libc/thread/detach.c index e6e0398f2..70cba3e69 100644 --- a/libc/thread/detach.c +++ b/libc/thread/detach.c @@ -16,19 +16,44 @@ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ -#include "libc/runtime/runtime.h" +#include "libc/bits/atomic.h" +#include "libc/calls/calls.h" +#include "libc/calls/strace.internal.h" +#include "libc/errno.h" +#include "libc/intrin/asan.internal.h" +#include "libc/str/str.h" #include "libc/thread/descriptor.h" #include "libc/thread/detach.h" +/** + * Detaches thread. + * + * Calling this function will cause the thread to free its own memory + * once it exits. Using this function is mutually exclusive from the + * chtread_join() API. + * + * @return 0 on success or errno number on failure + * @raises EINVAL if thread isn't joinable + * @raises ESRCH if no such thread exists + * @threadsafe + */ int cthread_detach(cthread_t td) { - int state; - asm volatile("lock xadd\t%1, %0" - : "+m"(td->state), "=r"(state) - : "1"(cthread_detached) - : "cc"); - if ((state & cthread_finished)) { - size_t size = (intptr_t)(td->alloc.top) - (intptr_t)(td->alloc.bottom); - munmap(td->alloc.bottom, size); + int rc, tid; + if (!td || (IsAsan() && !__asan_is_valid(td, sizeof(*td)))) { + rc = ESRCH; + tid = -1; + } else if ((tid = td->tid) == gettid()) { + rc = EDEADLK; + } else if (atomic_load(&td->state) & (cthread_detached | cthread_joining)) { + rc = EINVAL; + } else if (!atomic_fetch_add(&td->state, cthread_detached) & + cthread_finished) { + rc = 0; + } else if (!munmap(td->alloc.bottom, td->alloc.top - td->alloc.bottom)) { + rc = 0; + } else { + rc = errno; } - return 0; + STRACE("cthread_detached(%d) → %s", tid, !rc ? "0" : strerrno(rc)); + return rc; } diff --git a/libc/thread/exit.c b/libc/thread/exit.c index 459b0f713..968caa73f 100644 --- a/libc/thread/exit.c +++ b/libc/thread/exit.c @@ -17,30 +17,18 @@ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/calls/strace.internal.h" -#include "libc/calls/syscall-sysv.internal.h" -#include "libc/intrin/lockxadd.h" #include "libc/runtime/runtime.h" -#include "libc/thread/descriptor.h" #include "libc/thread/exit.h" #include "libc/thread/self.h" /** * Exits cosmopolitan thread. * - * @param rc is exit code - * @see _Exit1() for the raw system call + * @param exitcode is passed along to cthread_join() * @threadsafe * @noreturn */ -wontreturn void cthread_exit(int rc) { - cthread_t td; - STRACE("cthread_exit(%d)", rc); - td = cthread_self(); - td->rc = rc; - _lockxadd(&td->state, cthread_finished); - if (~td->state & cthread_detached) { - sys_munmap(td->alloc.bottom, - (intptr_t)td->alloc.top - (intptr_t)td->alloc.bottom); - } - _Exit1(rc); +wontreturn void cthread_exit(void *exitcode) { + STRACE("cthread_exit(%p)", exitcode); + longerjmp(cthread_self()->exiter, (intptr_t)exitcode); } diff --git a/libc/thread/exit.h b/libc/thread/exit.h index 679b472c2..764c23ffd 100644 --- a/libc/thread/exit.h +++ b/libc/thread/exit.h @@ -3,11 +3,7 @@ #if !(__ASSEMBLER__ + __LINKER__ + 0) COSMOPOLITAN_C_START_ -/** - * @fileoverview exit the current thread - */ - -wontreturn void cthread_exit(int); +wontreturn void cthread_exit(void *); COSMOPOLITAN_C_END_ #endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */ diff --git a/libc/thread/init.c b/libc/thread/init.c index b4048d6c5..e3ce2c668 100644 --- a/libc/thread/init.c +++ b/libc/thread/init.c @@ -16,59 +16,59 @@ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ +#include "libc/assert.h" #include "libc/calls/calls.h" -#include "libc/dce.h" +#include "libc/errno.h" +#include "libc/macros.internal.h" +#include "libc/nexgen32e/threaded.h" +#include "libc/runtime/internal.h" #include "libc/runtime/runtime.h" +#include "libc/runtime/stack.h" #include "libc/str/str.h" #include "libc/sysv/consts/map.h" -#include "libc/sysv/consts/nr.h" #include "libc/sysv/consts/prot.h" #include "libc/thread/descriptor.h" - -// TLS boundaries -extern char _tbss_start, _tbss_end, _tdata_start, _tdata_end; +#include "libc/thread/self.h" static textstartup void _main_thread_init(void) { - if (!IsLinux()) return; /* TODO */ - size_t tbsssize = &_tbss_end - &_tbss_start; - size_t tdatasize = &_tdata_end - &_tdata_start; - size_t tlssize = tbsssize + tdatasize; - size_t totalsize = tlssize + sizeof(struct cthread_descriptor_t); - totalsize = (totalsize + PAGESIZE - 1) & -PAGESIZE; + _Static_assert(offsetof(struct cthread_descriptor_t, self) == 0x00, ""); + _Static_assert(offsetof(struct cthread_descriptor_t, self2) == 0x30, ""); + _Static_assert(offsetof(struct cthread_descriptor_t, tid) == 0x38, ""); + _Static_assert(offsetof(struct cthread_descriptor_t, err) == 0x3c, ""); + cthread_t td; + size_t totalsize; + char *mem, *bottom, *top; - uintptr_t mem = (uintptr_t)mmap(NULL, totalsize, PROT_READ | PROT_WRITE, - MAP_ANONYMOUS | MAP_PRIVATE, -1, 0); - if (mem == -1) { - abort(); - } + totalsize = ROUNDUP( + (uintptr_t)_tls_size + sizeof(struct cthread_descriptor_t), FRAMESIZE); - void* bottom = (void*)mem; - void* top = (void*)(mem + totalsize); + mem = mmap(0, totalsize, PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE, + -1, 0); + assert(mem != MAP_FAILED); - cthread_t td = (cthread_t)top - 1; + bottom = mem; + top = mem + totalsize; + + td = (cthread_t)(top - sizeof(struct cthread_descriptor_t)); td->self = td; - td->stack.top = NULL; - td->stack.bottom = NULL; - td->tls.top = top; - td->tls.bottom = bottom; - td->alloc.top = top; + td->self2 = td; + td->err = errno; + td->tid = gettid(); td->alloc.bottom = bottom; + td->alloc.top = top; + td->stack.bottom = GetStackAddr(0); + td->stack.top = td->stack.bottom + GetStackSize(); td->state = cthread_main; // Initialize TLS with content of .tdata section - memmove((void*)((uintptr_t)td - tlssize), &_tdata_start, tdatasize); - - // Get TID of main thread - int gettid = __NR_gettid; - if (gettid == 0xfff) gettid = __NR_getpid; - td->tid = syscall(gettid); + memmove((void *)((uintptr_t)td - (uintptr_t)_tls_size), _tdata_start, + (uintptr_t)_tdata_size); // Set FS - if (arch_prctl(ARCH_SET_FS, td) != 0) { - abort(); - } + __install_tls((char *)td); + assert(cthread_self()->tid == gettid()); } -const void* const _main_thread_ctor[] initarray = { +const void *const _main_thread_ctor[] initarray = { _main_thread_init, }; diff --git a/libc/thread/join.c b/libc/thread/join.c index 9dfaa0ed7..b545334c4 100644 --- a/libc/thread/join.c +++ b/libc/thread/join.c @@ -16,38 +16,61 @@ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ +#include "libc/bits/atomic.h" +#include "libc/calls/calls.h" +#include "libc/calls/strace.internal.h" +#include "libc/dce.h" +#include "libc/errno.h" +#include "libc/intrin/asan.internal.h" +#include "libc/intrin/spinlock.h" #include "libc/runtime/runtime.h" +#include "libc/str/str.h" #include "libc/sysv/consts/futex.h" #include "libc/sysv/consts/nr.h" #include "libc/thread/descriptor.h" #include "libc/thread/join.h" -int cthread_join(cthread_t td, int* rc) { - int tid = td->tid; // tid must be loaded before lock xadd - // otherwise, tid could be set to 0 even though `state` is not finished - - // mark thread as joining - int state; - asm volatile("lock xadd\t%1, %0" - : "+m"(td->state), "=r"(state) - : "1"(cthread_joining) - : "cc"); - - if (!(state & cthread_finished)) { - int ax; - int flags = FUTEX_WAIT; // PRIVATE makes it hang - struct timespec* timeout = NULL; - asm volatile("mov\t%5,%%r10\n\t" // timeout - "syscall" - : "=a"(ax) - : "0"(__NR_futex), "D"(&td->tid), "S"(flags), "d"(tid), - "g"(timeout) - : "rcx", "r10", "r11", "cc", "memory"); +/** + * Waits for thread to terminate and frees its memory. + * + * @param td is thread descriptor memory + * @param exitcode optionally receives value returned by thread + * @return 0 on success, or error number on failure + * @raises EDEADLK when trying to join this thread + * @raises EINVAL if another thread is joining + * @raises ESRCH if no such thread exists + * @raises EINVAL if not joinable + * @threadsafe + */ +int cthread_join(cthread_t td, void **exitcode) { + int rc, tid; + // otherwise, tid could be set to 0 even though `state` is not + // finished mark thread as joining + if (!td || (IsAsan() && !__asan_is_valid(td, sizeof(*td)))) { + rc = ESRCH; + tid = -1; + } else if ((tid = td->tid) == gettid()) { // tid must load before lock xadd + rc = EDEADLK; + } else if (atomic_load(&td->state) & (cthread_detached | cthread_joining)) { + rc = EINVAL; + } else { + if (~atomic_fetch_add(&td->state, cthread_joining) & cthread_finished) { + if (IsLinux() || IsOpenbsd()) { + // FUTEX_WAIT_PRIVATE makes it hang + futex((uint32_t *)&td->tid, FUTEX_WAIT, tid, 0, 0); + } + _spinlock(&td->tid); + } + if (exitcode) { + *exitcode = td->exitcode; + } + if (!munmap(td->alloc.bottom, td->alloc.top - td->alloc.bottom)) { + rc = 0; + } else { + rc = errno; + } } - - *rc = td->rc; - - size_t size = (intptr_t)(td->alloc.top) - (intptr_t)(td->alloc.bottom); - munmap(td->alloc.bottom, size); - return 0; + STRACE("cthread_join(%d, [%p]) → %s", tid, !rc && exitcode ? *exitcode : 0, + !rc ? "0" : strerrno(rc)); + return rc; } diff --git a/libc/thread/join.h b/libc/thread/join.h index 986bf67d2..dd29cbf3a 100644 --- a/libc/thread/join.h +++ b/libc/thread/join.h @@ -4,11 +4,7 @@ #if !(__ASSEMBLER__ + __LINKER__ + 0) COSMOPOLITAN_C_START_ -/** - * @fileoverview join a thread - */ - -int cthread_join(cthread_t, int*); +int cthread_join(cthread_t, void **); COSMOPOLITAN_C_END_ #endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */ diff --git a/libc/thread/self.c b/libc/thread/self.c index d3b3098d7..8e6c3c02c 100644 --- a/libc/thread/self.c +++ b/libc/thread/self.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=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 │ @@ -18,4 +18,11 @@ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/thread/self.h" -extern inline cthread_t cthread_self(void); +STATIC_YOINK("_main_thread_ctor"); + +/** + * Returns thread descriptor of the current thread. + */ +cthread_t(cthread_self)(void) { + return cthread_self(); +} diff --git a/libc/thread/self.h b/libc/thread/self.h index 2885eba89..790a890b1 100644 --- a/libc/thread/self.h +++ b/libc/thread/self.h @@ -1,19 +1,18 @@ #ifndef COSMOPOLITAN_LIBC_THREAD_SELF_H_ #define COSMOPOLITAN_LIBC_THREAD_SELF_H_ +#include "libc/nexgen32e/threaded.h" #include "libc/thread/descriptor.h" #if !(__ASSEMBLER__ + __LINKER__ + 0) COSMOPOLITAN_C_START_ -/** - * @fileoverview get the thread descriptor of the current thread - */ +extern const void *const _main_thread_ctor[]; #if defined(__GNUC__) && !defined(__STRICT_ANSI__) -inline cthread_t cthread_self(void) { - cthread_t self; - asm("mov\t%%fs:0,%0" : "=r"(self)); - return self; -} +#define cthread_self() \ + ({ \ + YOINK(_main_thread_ctor); \ + ((cthread_t)__get_tls()); \ + }) #else cthread_t cthread_self(void); #endif diff --git a/libc/thread/sem.c b/libc/thread/sem.c index 2355b8be4..75f602413 100644 --- a/libc/thread/sem.c +++ b/libc/thread/sem.c @@ -21,6 +21,8 @@ #include "libc/thread/wait.h" #include "libc/thread/yield.h" +STATIC_YOINK("_main_thread_ctor"); + #define CTHREAD_THREAD_VAL_BITS 32 static void pause(int attempt) { @@ -33,40 +35,45 @@ static void pause(int attempt) { } } +/** + * Initializes semaphore. + */ int cthread_sem_init(cthread_sem_t* sem, int count) { sem->linux.count = count; return 0; } +/** + * Destroys semaphore. + */ int cthread_sem_destroy(cthread_sem_t* sem) { (void)sem; return 0; } +/** + * Notifies a thread waiting on semaphore. + */ int cthread_sem_signal(cthread_sem_t* sem) { uint64_t count; - asm volatile("lock xadd\t%1,%0" - : "+m"(sem->linux.count), "=r"(count) - : "1"(1) - : "cc"); - + count = atomic_fetch_add(&sem->linux.count, 1); if ((count >> CTHREAD_THREAD_VAL_BITS)) { // WARNING: an offset of 4 bytes would be required on little-endian archs void* wait_address = &sem->linux.count; cthread_memory_wake32(wait_address, 1); } - return 0; } +/** + * Waits on semaphore with kernel assistance. + */ int cthread_sem_wait_futex(cthread_sem_t* sem, const struct timespec* timeout) { uint64_t count; // record current thread as waiter - asm volatile("lock xadd\t%1,%0" - : "+m"(sem->linux.count), "=r"(count) - : "1"((uint64_t)1 << CTHREAD_THREAD_VAL_BITS) - : "cc"); + count = atomic_fetch_add(&sem->linux.count, + (uint64_t)1 << CTHREAD_THREAD_VAL_BITS); for (;;) { // try to acquire the semaphore, as well as remove itself from waiters @@ -88,6 +95,9 @@ int cthread_sem_wait_futex(cthread_sem_t* sem, const struct timespec* timeout) { return 0; } +/** + * Waits on semaphore without kernel assistance. + */ int cthread_sem_wait_spin(cthread_sem_t* sem, uint64_t count, int spin, const struct timespec* timeout) { // spin on pause @@ -106,6 +116,9 @@ int cthread_sem_wait_spin(cthread_sem_t* sem, uint64_t count, int spin, return cthread_sem_wait_futex(sem, timeout); } +/** + * Waits on semaphore. + */ int cthread_sem_wait(cthread_sem_t* sem, int spin, const struct timespec* timeout) { uint64_t count = atomic_load(&sem->linux.count); diff --git a/libc/thread/sem.h b/libc/thread/sem.h index 1e4183f34..d0dc91f69 100644 --- a/libc/thread/sem.h +++ b/libc/thread/sem.h @@ -1,5 +1,6 @@ #ifndef COSMOPOLITAN_LIBC_THREAD_NATIVESEM_H_ #define COSMOPOLITAN_LIBC_THREAD_NATIVESEM_H_ +#include "libc/calls/struct/timespec.h" #if !(__ASSEMBLER__ + __LINKER__ + 0) COSMOPOLITAN_C_START_ @@ -13,16 +14,11 @@ typedef union cthread_sem_t { } linux; } cthread_sem_t; -struct timespec; - -int cthread_sem_init(cthread_sem_t*, int); -int cthread_sem_destroy(cthread_sem_t*); - -int cthread_sem_wait(cthread_sem_t*, int, const struct timespec*); -int cthread_sem_signal(cthread_sem_t*); - +int cthread_sem_init(cthread_sem_t *, int); +int cthread_sem_destroy(cthread_sem_t *); +int cthread_sem_wait(cthread_sem_t *, int, const struct timespec *); +int cthread_sem_signal(cthread_sem_t *); COSMOPOLITAN_C_END_ #endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */ -#endif /* COSMOPOLITAN_LIBC_THREAD_SELF_H_ */ - +#endif /* COSMOPOLITAN_LIBC_THREAD_SELF_H_ */ diff --git a/libc/thread/thread.mk b/libc/thread/thread.mk index 1f99033d5..cf30a8a2a 100644 --- a/libc/thread/thread.mk +++ b/libc/thread/thread.mk @@ -11,43 +11,43 @@ LIBC_THREAD_A_HDRS = $(filter %.h,$(LIBC_THREAD_A_FILES)) LIBC_THREAD_A_SRCS_S = $(filter %.S,$(LIBC_THREAD_A_FILES)) LIBC_THREAD_A_SRCS_C = $(filter %.c,$(LIBC_THREAD_A_FILES)) -LIBC_THREAD_A_SRCS = \ - $(LIBC_THREAD_A_SRCS_S) \ +LIBC_THREAD_A_SRCS = \ + $(LIBC_THREAD_A_SRCS_S) \ $(LIBC_THREAD_A_SRCS_C) -LIBC_THREAD_A_OBJS = \ +LIBC_THREAD_A_OBJS = \ $(LIBC_THREAD_A_SRCS_S:%.S=o/$(MODE)/%.o) \ $(LIBC_THREAD_A_SRCS_C:%.c=o/$(MODE)/%.o) -LIBC_THREAD_A_CHECKS = \ - $(LIBC_THREAD_A).pkg \ +LIBC_THREAD_A_CHECKS = \ + $(LIBC_THREAD_A).pkg \ $(LIBC_THREAD_A_HDRS:%=o/$(MODE)/%.ok) -LIBC_THREAD_A_DIRECTDEPS = \ - LIBC_STUBS \ - LIBC_CALLS \ - LIBC_INTRIN \ - LIBC_BITS \ - LIBC_MEM \ - LIBC_RUNTIME \ - LIBC_SYSV \ - LIBC_SYSV_CALLS \ +LIBC_THREAD_A_DIRECTDEPS = \ + LIBC_STUBS \ + LIBC_CALLS \ + LIBC_INTRIN \ + LIBC_BITS \ + LIBC_MEM \ + LIBC_RUNTIME \ + LIBC_SYSV \ + LIBC_SYSV_CALLS \ LIBC_NEXGEN32E -LIBC_THREAD_A_DEPS := \ +LIBC_THREAD_A_DEPS := \ $(call uniq,$(foreach x,$(LIBC_THREAD_A_DIRECTDEPS),$($(x)))) -$(LIBC_THREAD_A): \ - libc/thread/ \ - $(LIBC_THREAD_A).pkg \ +$(LIBC_THREAD_A): \ + libc/thread/ \ + $(LIBC_THREAD_A).pkg \ $(LIBC_THREAD_A_OBJS) -$(LIBC_THREAD_A).pkg: \ - $(LIBC_THREAD_A_OBJS) \ +$(LIBC_THREAD_A).pkg: \ + $(LIBC_THREAD_A_OBJS) \ $(foreach x,$(LIBC_THREAD_A_DIRECTDEPS),$($(x)_A).pkg) -o/tinylinux/libc/thread/clone.o: \ - OVERRIDE_CFLAGS += \ +o/tinylinux/libc/thread/clone.o: \ + OVERRIDE_CFLAGS += \ -ffunction-sections LIBC_THREAD_LIBS = $(foreach x,$(LIBC_THREAD_ARTIFACTS),$($(x))) diff --git a/libc/thread/wait.c b/libc/thread/wait.c index 1d6565e14..d72081511 100644 --- a/libc/thread/wait.c +++ b/libc/thread/wait.c @@ -16,35 +16,31 @@ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ +#include "libc/bits/atomic.h" +#include "libc/calls/calls.h" +#include "libc/dce.h" #include "libc/sysv/consts/futex.h" -#include "libc/sysv/consts/nr.h" -#include "libc/thread/wait.h" int cthread_memory_wait32(uint32_t* addr, uint32_t val, const struct timespec* timeout) { - if (__NR_futex != 0xfff) { - int flags = FUTEX_WAIT; - int rc; - asm volatile("mov\t%5,%%r10\n\t" // timeout - "syscall" - : "=a"(rc) - : "0"(__NR_futex), "D"(addr), "S"(flags), "d"(val), - "g"(timeout) - : "rcx", "r10", "r11", "cc", "memory"); - return rc; + if (IsLinux() || IsOpenbsd()) { + return futex(addr, FUTEX_WAIT, val, timeout, 0); + } else { + unsigned tries; + for (tries = 1; atomic_load(addr) == val; ++tries) { + if (tries & 7) { + __builtin_ia32_pause(); + } else { + sched_yield(); + } + } + return 0; } - return -1; } int cthread_memory_wake32(uint32_t* addr, int n) { - if (__NR_futex != 0xfff) { - int flags = FUTEX_WAKE; - int rc; - asm volatile("syscall" - : "=a"(rc) - : "0"(__NR_futex), "D"(addr), "S"(flags), "d"(n) - : "rcx", "r11", "cc", "memory"); - return rc; + if (IsLinux() || IsOpenbsd()) { + return futex(addr, FUTEX_WAKE, n, 0, 0); } return -1; } diff --git a/libc/thread/yield.c b/libc/thread/yield.c index 710045b28..22e7fad26 100644 --- a/libc/thread/yield.c +++ b/libc/thread/yield.c @@ -19,6 +19,9 @@ #include "libc/calls/calls.h" #include "libc/thread/yield.h" +/** + * Asks operating system to handoff remaining time slice. + */ int cthread_yield(void) { return sched_yield(); } diff --git a/libc/thread/zombie.c b/libc/thread/zombie.c new file mode 100644 index 000000000..34d2ae52b --- /dev/null +++ b/libc/thread/zombie.c @@ -0,0 +1,50 @@ +/*-*- 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/bits/atomic.h" +#include "libc/mem/mem.h" +#include "libc/runtime/runtime.h" +#include "libc/thread/zombie.h" + +static struct Zombie { + struct Zombie *next; + cthread_t td; +} * cthread_zombies; + +void cthread_zombies_add(cthread_t td) { + struct Zombie *z; + if ((z = malloc(sizeof(struct Zombie)))) { + z->td = td; + z->next = atomic_load(&cthread_zombies); + for (;;) { + if (atomic_compare_exchange_weak(&cthread_zombies, &z->next, z)) { + break; + } + } + } +} + +void cthread_zombies_reap(void) { + struct Zombie *z; + while ((z = atomic_load(&cthread_zombies)) && !atomic_load(&z->td->tid)) { + if (atomic_compare_exchange_weak(&cthread_zombies, &z, z->next)) { + munmap(z->td->alloc.bottom, z->td->alloc.top - z->td->alloc.bottom); + free(z); + } + } +} diff --git a/libc/thread/zombie.h b/libc/thread/zombie.h new file mode 100644 index 000000000..42ab76ee7 --- /dev/null +++ b/libc/thread/zombie.h @@ -0,0 +1,12 @@ +#ifndef COSMOPOLITAN_LIBC_THREAD_ZOMBIE_H_ +#define COSMOPOLITAN_LIBC_THREAD_ZOMBIE_H_ +#include "libc/thread/descriptor.h" +#if !(__ASSEMBLER__ + __LINKER__ + 0) +COSMOPOLITAN_C_START_ + +void cthread_zombies_add(cthread_t); +void cthread_zombies_reap(void); + +COSMOPOLITAN_C_END_ +#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */ +#endif /* COSMOPOLITAN_LIBC_THREAD_ZOMBIE_H_ */ diff --git a/test/libc/calls/dup_test.c b/test/libc/calls/dup_test.c index 5c8734786..3eda2c135 100644 --- a/test/libc/calls/dup_test.c +++ b/test/libc/calls/dup_test.c @@ -19,6 +19,7 @@ #include "libc/calls/calls.h" #include "libc/calls/internal.h" #include "libc/calls/struct/stat.h" +#include "libc/errno.h" #include "libc/log/check.h" #include "libc/runtime/runtime.h" #include "libc/stdio/stdio.h" @@ -44,6 +45,28 @@ static textstartup void TestInit(int argc, char **argv) { const void *const TestCtor[] initarray = {TestInit}; +TEST(dup, ebadf) { + ASSERT_SYS(EBADF, -1, dup(-1)); + ASSERT_SYS(EBADF, -1, dup2(-1, 0)); + ASSERT_SYS(EBADF, -1, dup2(0, -1)); + ASSERT_SYS(EBADF, -1, dup3(0, -1, 0)); + ASSERT_SYS(EBADF, -1, dup3(10, 0, 0)); +} + +TEST(dup, sameNumber) { + ASSERT_SYS(0, 0, dup2(0, 0)); + ASSERT_SYS(EINVAL, -1, dup3(0, 0, 0)); + EXPECT_SYS(EBADF, -1, dup2(-1, -1)); + EXPECT_SYS(EINVAL, -1, dup3(-1, -1, 0)); + ASSERT_SYS(EBADF, -1, dup2(3, 3)); + ASSERT_SYS(EBADF, -1, dup2(0, -1)); +} + +TEST(dup, bigNumber) { + ASSERT_SYS(0, 100, dup2(0, 100)); + ASSERT_SYS(0, 0, close(100)); +} + TEST(dup, clearsCloexecFlag) { int ws; ASSERT_SYS(0, 0, close(creat("file", 0644))); diff --git a/test/libc/calls/stat_test.c b/test/libc/calls/stat_test.c index 61526d11f..5b51ccee0 100644 --- a/test/libc/calls/stat_test.c +++ b/test/libc/calls/stat_test.c @@ -36,6 +36,7 @@ STATIC_YOINK("zip_uri_support"); char testlib_enable_tmp_setup_teardown; +#if 0 TEST(stat_010, testEmptyFile_sizeIsZero) { struct stat st; memset(&st, -1, sizeof(st)); @@ -53,6 +54,7 @@ TEST(stat, enotdir) { ASSERT_SYS(0, 0, close(creat("yo", 0644))); ASSERT_SYS(ENOTDIR, -1, stat("yo/there", 0)); } +#endif TEST(stat, zipos) { struct stat st; @@ -62,6 +64,7 @@ TEST(stat, zipos) { &st)); } +#if 0 static long Stat(const char *path, struct stat *st) { long ax, di, si, dx; asm volatile("syscall" @@ -109,3 +112,4 @@ BENCH(stat, bench) { "tokenize_tests-latin1-coding-cookie-and-utf8-bom-sig.txt", &st)); } +#endif diff --git a/test/libc/runtime/clone_test.c b/test/libc/runtime/clone_test.c index 8c92f9ec6..7cbc631bd 100644 --- a/test/libc/runtime/clone_test.c +++ b/test/libc/runtime/clone_test.c @@ -25,10 +25,12 @@ #include "libc/mem/mem.h" #include "libc/nexgen32e/nexgen32e.h" #include "libc/nexgen32e/threaded.h" +#include "libc/runtime/runtime.h" #include "libc/runtime/stack.h" #include "libc/runtime/symbols.internal.h" #include "libc/sysv/consts/clone.h" #include "libc/sysv/consts/map.h" +#include "libc/sysv/consts/o.h" #include "libc/sysv/consts/prot.h" #include "libc/sysv/consts/sig.h" #include "libc/testlib/ezbench.h" @@ -55,10 +57,8 @@ void TearDown(void) { free(tls); } -int DoNothing(void *arg) { - CheckStackIsAligned(); - return 0; -} +//////////////////////////////////////////////////////////////////////////////// +// TEST THREADS WORK int CloneTest1(void *arg) { intptr_t rsp, top, bot; @@ -105,32 +105,90 @@ TEST(clone, test1) { errno = 0; } +//////////////////////////////////////////////////////////////////////////////// +// TEST THREADS CAN ISSUE SYSTEM CALLS WITH INDEPENDENT ERRNOS + +_Atomic(int) sysbarrier; + int CloneTestSys(void *arg) { + int i, id = (intptr_t)arg; CheckStackIsAligned(); - thechilde = gettid(); - ASSERT_EQ(31337, errno); - open(0, 0); - ASSERT_EQ(EFAULT, errno); + while (!sysbarrier) asm("pause"); + for (i = 0; i < 20; ++i) { + switch (id % 3) { + case 0: + errno = 123; + open(0, 0); + asm("pause"); + ASSERT_EQ(EFAULT, errno); + break; + case 1: + errno = 123; + dup(-1); + asm("pause"); + ASSERT_EQ(EBADF, errno); + break; + case 2: + errno = 123; + dup3(0, 0, 0); + asm("pause"); + ASSERT_EQ(EINVAL, errno); + break; + default: + unreachable; + } + } return 0; } TEST(clone, tlsSystemCallsErrno_wontClobberMainThreadBecauseTls) { + int i; + char *tls[8], *stack[8]; ASSERT_EQ(0, errno); - ASSERT_EQ(31337, *(int *)(tls + 0x3c)); - _seizelock(childetid); - ASSERT_NE(-1, (tid = clone(CloneTestSys, stack, GetStackSize(), - CLONE_THREAD | CLONE_VM | CLONE_FS | CLONE_FILES | - CLONE_SIGHAND | CLONE_CHILD_SETTID | - CLONE_CHILD_CLEARTID | CLONE_SETTLS, - (void *)23, 0, tls, 64, childetid))); - _spinlock(childetid); // CLONE_CHILD_CLEARTID + for (i = 0; i < 8; ++i) { + tls[i] = __initialize_tls(malloc(64)); + stack[i] = mmap(0, GetStackSize(), PROT_READ | PROT_WRITE, + MAP_STACK | MAP_ANONYMOUS, -1, 0); + ASSERT_NE( + -1, + (tid = clone( + CloneTestSys, stack[i], GetStackSize(), + CLONE_THREAD | CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_SIGHAND | + CLONE_CHILD_SETTID | CLONE_CHILD_CLEARTID | CLONE_SETTLS, + (void *)(intptr_t)i, 0, tls[i], 64, (int *)(tls[i] + 0x38)))); + } + sysbarrier = 1; + for (i = 0; i < 8; ++i) { + _spinlock((int *)(tls[i] + 0x38)); + free(tls[i]); + munmap(stack[i], GetStackSize()); + } ASSERT_EQ(0, errno); - ASSERT_EQ(EFAULT, *(int *)(tls + 0x3c)); +} + +//////////////////////////////////////////////////////////////////////////////// +// BENCHMARK + +int DoNothing(void *arg) { + return 0; +} + +void LaunchThread(void) { + char *tls, *stack; + tls = __initialize_tls(malloc(64)); + __cxa_atexit(free, tls, 0); + stack = mmap(0, GetStackSize(), PROT_READ | PROT_WRITE, + MAP_STACK | MAP_ANONYMOUS, -1, 0); + clone(DoNothing, stack, GetStackSize(), + CLONE_THREAD | CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_SIGHAND | + CLONE_CHILD_SETTID | CLONE_CHILD_CLEARTID | CLONE_SETTLS, + 0, 0, tls, 64, (int *)(tls + 0x38)); } BENCH(clone, bench) { - errno_t *volatile ep; char *volatile tp; + errno_t *volatile ep; EZBENCH2("__errno_location", donothing, (ep = __errno_location())); EZBENCH2("__get_tls", donothing, (tp = __get_tls())); + EZBENCH2("clone()", donothing, LaunchThread()); } diff --git a/test/libc/runtime/mmap_test.c b/test/libc/runtime/mmap_test.c index e6e810bee..2d21c0777 100644 --- a/test/libc/runtime/mmap_test.c +++ b/test/libc/runtime/mmap_test.c @@ -196,12 +196,6 @@ TEST(mmap, twoPowerSize_automapsAddressWithThatAlignment) { // verify it's aligned ASSERT_EQ(0, (intptr_t)p & 0x0007ffff); EXPECT_SYS(0, 0, munmap(p, 0x00080000)); - // now try again with a big size that isn't a two power - ASSERT_NE(MAP_FAILED, (p = mmap(NULL, 0x00070000, PROT_READ | PROT_WRITE, - MAP_SHARED | MAP_ANONYMOUS, -1, 0))); - // automap doesn't bother aligning it - ASSERT_NE(0, (intptr_t)p & 0x0007ffff); - EXPECT_SYS(0, 0, munmap(q, 0x00010000)); } TEST(isheap, nullPtr) { diff --git a/test/net/https/argon2_test.c b/test/net/https/argon2_test.c index 86b6632f4..5fabdcc91 100644 --- a/test/net/https/argon2_test.c +++ b/test/net/https/argon2_test.c @@ -16,12 +16,39 @@ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ +#include "libc/dce.h" #include "libc/testlib/ezbench.h" #include "libc/testlib/testlib.h" #include "net/https/https.h" #include "third_party/argon2/argon2.h" -TEST(argon2, test) { +TEST(argon2, testArgon2ReadmeExample) { + uint8_t hash[24]; + uint8_t salt[8] = {'s', 'o', 'm', 'e', 's', 'a', 'l', 't'}; + uint8_t pass[8] = {'p', 'a', 's', 's', 'w', 'o', 'r', 'd'}; + uint32_t parallelism = 4; + uint32_t memorycost = 1 << 16; + uint32_t iterations = 2; + argon2i_hash_raw(iterations, memorycost, parallelism, pass, sizeof(pass), + salt, sizeof(salt), hash, sizeof(hash)); + ASSERT_BINEQ("45d7ac72e76f242b20b77b9bf9bf9d5915894e669a24e6c6", hash); +} + +TEST(argon2, testArgon2ReadmeExampleEncoded) { + char hash[128]; + uint8_t salt[8] = {'s', 'o', 'm', 'e', 's', 'a', 'l', 't'}; + uint8_t pass[8] = {'p', 'a', 's', 's', 'w', 'o', 'r', 'd'}; + uint32_t parallelism = 4; + uint32_t memorycost = 1 << 16; + uint32_t iterations = 2; + argon2i_hash_encoded(iterations, memorycost, parallelism, pass, sizeof(pass), + salt, sizeof(salt), 24, hash, sizeof(hash)); + ASSERT_STREQ("$argon2i$v=19$m=65536,t=2,p=4$c29tZXNhbHQ$RdescudvJCsgt3ub+b+" + "dWRWJTmaaJObG", + hash); +} + +TEST(argon2i, testOnlineGeneratorExample) { /* consistent with https://argon2.online/ */ uint8_t hash[32]; uint8_t salt[8] = {'s', 'a', 'l', 't', 's', 'a', 'l', 't'}; @@ -35,17 +62,31 @@ TEST(argon2, test) { "b5d0818d1c0c05684e68aef02de8b4ed14bfe6c60800e0aa36a5c18f846a297b", hash); } -void specimen(void) { +TEST(argon2id, testOnlineGeneratorExample) { + /* consistent with https://argon2.online/ */ uint8_t hash[32]; uint8_t salt[8] = {'s', 'a', 'l', 't', 's', 'a', 'l', 't'}; uint8_t pass[8] = {'p', 'a', 's', 's', 'w', 'o', 'r', 'd'}; uint32_t parallelism = 1; - uint32_t memorycost = 65536 / 4; + uint32_t memorycost = 65536; + uint32_t iterations = 2; + argon2id_hash_raw(iterations, memorycost, parallelism, pass, sizeof(pass), + salt, sizeof(salt), hash, sizeof(hash)); + ASSERT_BINEQ( + "360da2d90fd9d6f52923f293d142131a13909b780698daf09e6756422ebd1045", hash); +} + +void BenchmarkArgon2(void) { + uint8_t hash[24]; + uint8_t salt[8] = {'s', 'o', 'm', 'e', 's', 'a', 'l', 't'}; + uint8_t pass[8] = {'p', 'a', 's', 's', 'w', 'o', 'r', 'd'}; + uint32_t parallelism = 4; + uint32_t memorycost = (1 << 16) / 8; uint32_t iterations = 2; argon2i_hash_raw(iterations, memorycost, parallelism, pass, sizeof(pass), salt, sizeof(salt), hash, sizeof(hash)); } BENCH(argon2, bench) { - EZBENCH2("argon2", donothing, specimen()); + EZBENCH2("argon2", donothing, BenchmarkArgon2()); } diff --git a/third_party/argon2/argon2.mk b/third_party/argon2/argon2.mk index 9599effd0..88e9eb1ea 100644 --- a/third_party/argon2/argon2.mk +++ b/third_party/argon2/argon2.mk @@ -42,10 +42,13 @@ $(THIRD_PARTY_ARGON2_A).pkg: \ $(THIRD_PARTY_ARGON2_A_OBJS) \ $(foreach x,$(THIRD_PARTY_ARGON2_A_DIRECTDEPS),$($(x)_A).pkg) +# we can't use ubsan because: +# it's just too slow to be practical (like 6s vs. 13s) $(THIRD_PARTY_ARGON2_A_OBJS): \ OVERRIDE_CFLAGS += \ -ffunction-sections \ - -fdata-sections + -fdata-sections \ + -fno-sanitize=undefined THIRD_PARTY_ARGON2_LIBS = $(foreach x,$(THIRD_PARTY_ARGON2_ARTIFACTS),$($(x))) THIRD_PARTY_ARGON2_SRCS = $(foreach x,$(THIRD_PARTY_ARGON2_ARTIFACTS),$($(x)_SRCS)) diff --git a/third_party/lua/lrepl.c b/third_party/lua/lrepl.c index c579add12..b8c01462a 100644 --- a/third_party/lua/lrepl.c +++ b/third_party/lua/lrepl.c @@ -317,9 +317,8 @@ static int multiline (lua_State *L) { ssize_t rc; const char *line = lua_tolstring(L, 1, &len); /* get what it has */ int status = luaL_loadbuffer(L, line, len, "=stdin"); /* try it */ - if (!incomplete(L, status) || pushline(L, 0) != 1) { + if (!incomplete(L, status) || pushline(L, 0) != 1) return status; /* cannot or should not try to add continuation line */ - } lua_pushliteral(L, "\n"); /* add newline... */ lua_insert(L, -2); /* ...between the two lines */ lua_concat(L, 3); /* join them */ @@ -379,7 +378,7 @@ int lua_loadline (lua_State *L) { LUA_REPL_UNLOCK; return rc - 1; /* eof or error */ } - if ((status = addreturn(L)) != LUA_OK) /* 'return ...' did not work? */ + if ((status = addreturn(L)) != LUA_OK) /* 'return ...' did not work? */ status = multiline(L); /* try as command, maybe with continuation lines */ lua_remove(L, 1); /* remove line from the stack */ lua_assert(lua_gettop(L) == 1); diff --git a/third_party/lua/lua.main.c b/third_party/lua/lua.main.c index 9a0ed28fc..214e9f51f 100644 --- a/third_party/lua/lua.main.c +++ b/third_party/lua/lua.main.c @@ -397,7 +397,6 @@ int main (int argc, char **argv) { if (IsModeDbg()) { ShowCrashReports(); } - /* if (IsModeDbg()) ShowCrashReports(); */ L = luaL_newstate(); /* create state */ if (L == NULL) { lua_l_message(argv[0], "cannot create state: not enough memory"); diff --git a/third_party/make/dup2.c b/third_party/make/dup2.c deleted file mode 100644 index c734e82fd..000000000 --- a/third_party/make/dup2.c +++ /dev/null @@ -1,216 +0,0 @@ -/* Duplicate an open file descriptor to a specified file descriptor. - - Copyright (C) 1999, 2004-2007, 2009-2020 Free Software Foundation, Inc. - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . */ - -/* written by Paul Eggert */ - -#include "libc/calls/calls.h" -#include "libc/errno.h" -#include "third_party/make/config.h" -/* clang-format off */ - -#if HAVE_DUP2 - -# undef dup2 - -# if defined _WIN32 && ! defined __CYGWIN__ - -# if HAVE_MSVC_INVALID_PARAMETER_HANDLER -static int -dup2_nothrow (int fd, int desired_fd) -{ - int result; - - TRY_MSVC_INVAL - { - result = dup2 (fd, desired_fd); - } - CATCH_MSVC_INVAL - { - errno = EBADF; - result = -1; - } - DONE_MSVC_INVAL; - - return result; -} -# else -# define dup2_nothrow dup2 -# endif - -static int -ms_windows_dup2 (int fd, int desired_fd) -{ - int result; - - /* If fd is closed, mingw hangs on dup2 (fd, fd). If fd is open, - dup2 (fd, fd) returns 0, but all further attempts to use fd in - future dup2 calls will hang. */ - if (fd == desired_fd) - { - if ((HANDLE) _get_osfhandle (fd) == INVALID_HANDLE_VALUE) - { - errno = EBADF; - return -1; - } - return fd; - } - - /* Wine 1.0.1 return 0 when desired_fd is negative but not -1: - https://bugs.winehq.org/show_bug.cgi?id=21289 */ - if (desired_fd < 0) - { - errno = EBADF; - return -1; - } - - result = dup2_nothrow (fd, desired_fd); - - if (result == 0) - result = desired_fd; - - return result; -} - -# define dup2 ms_windows_dup2 - -# elif defined __KLIBC__ - - -static int -klibc_dup2dirfd (int fd, int desired_fd) -{ - int tempfd; - int dupfd; - - tempfd = open ("NUL", O_RDONLY); - if (tempfd == -1) - return -1; - - if (tempfd == desired_fd) - { - close (tempfd); - - char path[_MAX_PATH]; - if (__libc_Back_ioFHToPath (fd, path, sizeof (path))) - return -1; - - return open(path, O_RDONLY); - } - - dupfd = klibc_dup2dirfd (fd, desired_fd); - - close (tempfd); - - return dupfd; -} - -static int -klibc_dup2 (int fd, int desired_fd) -{ - int dupfd; - struct stat sbuf; - - dupfd = dup2 (fd, desired_fd); - if (dupfd == -1 && errno == ENOTSUP \ - && !fstat (fd, &sbuf) && S_ISDIR (sbuf.st_mode)) - { - close (desired_fd); - - return klibc_dup2dirfd (fd, desired_fd); - } - - return dupfd; -} - -# define dup2 klibc_dup2 -# endif - -int -rpl_dup2 (int fd, int desired_fd) -{ - int result; - -# ifdef F_GETFL - /* On Linux kernels 2.6.26-2.6.29, dup2 (fd, fd) returns -EBADF. - On Cygwin 1.5.x, dup2 (1, 1) returns 0. - On Cygwin 1.7.17, dup2 (1, -1) dumps core. - On Cygwin 1.7.25, dup2 (1, 256) can dump core. - On Haiku, dup2 (fd, fd) mistakenly clears FD_CLOEXEC. */ -# if HAVE_SETDTABLESIZE - setdtablesize (desired_fd + 1); -# endif - if (desired_fd < 0) - fd = desired_fd; - if (fd == desired_fd) - return fcntl (fd, F_GETFL) == -1 ? -1 : fd; -# endif - - result = dup2 (fd, desired_fd); - - /* Correct an errno value on FreeBSD 6.1 and Cygwin 1.5.x. */ - if (result == -1 && errno == EMFILE) - errno = EBADF; -# if REPLACE_FCHDIR - if (fd != desired_fd && result != -1) - result = _gl_register_dup (fd, result); -# endif - return result; -} - -#else /* !HAVE_DUP2 */ - -/* On older platforms, dup2 did not exist. */ - -# ifndef F_DUPFD -static int -dupfd (int fd, int desired_fd) -{ - int duplicated_fd = dup (fd); - if (duplicated_fd < 0 || duplicated_fd == desired_fd) - return duplicated_fd; - else - { - int r = dupfd (fd, desired_fd); - int e = errno; - close (duplicated_fd); - errno = e; - return r; - } -} -# endif - -int -dup2 (int fd, int desired_fd) -{ - int result = fcntl (fd, F_GETFL) < 0 ? -1 : fd; - if (result == -1 || fd == desired_fd) - return result; - close (desired_fd); -# ifdef F_DUPFD - result = fcntl (fd, F_DUPFD, desired_fd); -# if REPLACE_FCHDIR - if (0 <= result) - result = _gl_register_dup (fd, result); -# endif -# else - result = dupfd (fd, desired_fd); -# endif - if (result == -1 && (errno == EMFILE || errno == EINVAL)) - errno = EBADF; - return result; -} -#endif /* !HAVE_DUP2 */ diff --git a/third_party/make/make.mk b/third_party/make/make.mk index 8b703b661..77d8049e1 100644 --- a/third_party/make/make.mk +++ b/third_party/make/make.mk @@ -24,7 +24,6 @@ THIRD_PARTY_MAKE_SRCS_LIB = \ third_party/make/basename-lgpl.c \ third_party/make/concat-filename.c \ third_party/make/dirname-lgpl.c \ - third_party/make/dup2.c \ third_party/make/error.c \ third_party/make/exitfail.c \ third_party/make/fcntl.c \ diff --git a/tool/build/wastecpu.c b/tool/build/wastecpu.c new file mode 100644 index 000000000..bce1ea198 --- /dev/null +++ b/tool/build/wastecpu.c @@ -0,0 +1,77 @@ +/*-*- 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/struct/sigaction.h" +#include "libc/intrin/spinlock.h" +#include "libc/log/log.h" +#include "libc/mem/mem.h" +#include "libc/nexgen32e/threaded.h" +#include "libc/runtime/gc.internal.h" +#include "libc/runtime/runtime.h" +#include "libc/runtime/stack.h" +#include "libc/runtime/sysconf.h" +#include "libc/sysv/consts/clone.h" +#include "libc/sysv/consts/map.h" +#include "libc/sysv/consts/prot.h" +#include "libc/sysv/consts/sig.h" +#include "libc/time/time.h" + +volatile bool gotctrlc; + +void GotCtrlC(int sig) { + gotctrlc = true; +} + +int Worker(void *arg) { + uint8_t *p; + unsigned x = 0; + struct sigaction sa = {.sa_handler = GotCtrlC}; + sigaction(SIGINT, &sa, 0); + for (;;) { + for (p = _base; p < _end; ++p) { + x += *p; + if (gotctrlc) { + return x | x >> 8 | x >> 16 | x >> 24; + } + } + } +} + +int main(int argc, char *argv[]) { + char **tls; + int i, n, prot, flags; + ShowCrashReports(); + n = GetCpuCount(); + tls = gc(malloc(n * sizeof(*tls))); + for (i = 0; i < n; ++i) { + prot = PROT_READ | PROT_WRITE; + flags = MAP_STACK | MAP_ANONYMOUS; + tls[i] = __initialize_tls(malloc(64)); + clone(Worker, mmap(0, GetStackSize(), prot, flags, -1, 0), GetStackSize(), + CLONE_THREAD | CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_SIGHAND | + CLONE_CHILD_SETTID | CLONE_CHILD_CLEARTID | CLONE_SETTLS, + 0, 0, tls[i], 64, (int *)(tls[i] + 0x38)); + } + while (!gotctrlc) { + usleep(1000); + } + for (i = 0; i < n; ++i) { + _spinlock((int *)(tls[i] + 0x38)); + free(tls[i]); + } +} diff --git a/tool/emacs/ld-script.el b/tool/emacs/ld-script.el index 822a42cbf..bc33c3b53 100644 --- a/tool/emacs/ld-script.el +++ b/tool/emacs/ld-script.el @@ -122,8 +122,8 @@ "MEMORY" ;; 3.8 PHDRS Command "PHDRS" "FILEHDR" "FLAGS" - "PT_NULL" "PT_LOAD" "PT_DYNAMIC" "PT_INTERP" "PT_NOTE" "PT_SHLIB" "PT_PHDR" - "PT_GNU_STACK" + "PT_NULL" "PT_LOAD" "PT_DYNAMIC" "PT_INTERP" "PT_NOTE" + "PT_SHLIB" "PT_PHDR" "PT_GNU_STACK" "PT_TLS" ;; 3.9 VERSION Command "VERSION") "Keywords used of GNU ld script.") diff --git a/tool/net/help.txt b/tool/net/help.txt index 254e2b4b3..308d9af0f 100644 --- a/tool/net/help.txt +++ b/tool/net/help.txt @@ -1563,6 +1563,73 @@ MAXMIND MODULE For further details, please see maxmind.lua in redbean-demo.com. +──────────────────────────────────────────────────────────────────────────────── + +ARGON2 MODULE + + This module implemeents a password hashing algorithm based on blake2b + that won the Password Hashing Competition. + + It can be used to securely store user passwords in your SQLite + database, in a way that destroys the password, but can be verified by + regenerating the hash again the next time the user logs in. Destroying + the password is important, since if your database is compromised, the + bad guys won't be able to use rainbow tables to recover the plain text + of the passwords. + + Argon2 achieves this security by being expensive to compute. Care + should be taken in choosing parameters, since an HTTP endpoint that + uses Argon2 can just as easily become a denial of service vector. For + example, you may want to consider throttling your login endpoint. + + argon2.hash_encoded(pass:str, salt:int[, config:table]) + ├─→ ascii:str + └─→ nil, error:str + + Hashes password. + + This is consistent with the README of the reference implementation: + + >: assert(argon2.hash_encoded("password", "somesalt", { + variant = argon2.variants.argon2_i, + m_cost = 65536, + hash_len = 24, + parallelism = 4, + t_cost = 2, + })) + "$argon2i$v=19$m=65536,t=2,p=4$c29tZXNhbHQ$RdescudvJCsgt3ub+b+dWRWJTmaaJObG" + + `pass` is the secret value to be encoded. + + `salt` is a nonce value used to hash the string. + + `config.m_cost` is the memory hardness in kibibytes, which defaults + to 4096 (4 mibibytes). It's recommended that this be tuned upwards. + + `config.t_cost` is the number of iterations, which defaults to 3. + + `config.parallelism` is the parallelism factor, which defaults to 1. + + `config.hash_len` is the number of desired bytes in hash output, + which defaults to 32. + + `config.variant` may be: + + - `argon2.variants.argon2_id` blend of other two methods [default] + - `argon2.variants.argon2_i` maximize resistance to side-channel attacks + - `argon2.variants.argon2_d` maximize resistance to gpu cracking attacks + + argon2.verify(encoded:str, pass:str) + ├─→ ok:bool + └─→ nil, error:str + + Verifies password, e.g. + + >: argon2.verify( + "$argon2i$v=19$m=65536,t=2," .. + "p=4$c29tZXNhbHQ$RdescudvJCsgt3ub+b+dWRWJTmaaJObG", + "password") + true ──────────────────────────────────────────────────────────────────────────────── diff --git a/tool/net/largon2.c b/tool/net/largon2.c index cb0f4e208..1ee8b9c51 100644 --- a/tool/net/largon2.c +++ b/tool/net/largon2.c @@ -60,14 +60,6 @@ original implementaiton. @release 3.0.1 */ -#ifndef LUA_51 -#if !defined(LUA_VERSION_NUM) || LUA_VERSION_NUM < 502 -#define LUA_51 1 -#else -#define LUA_51 0 -#endif -#endif - /*** Argon2 hashing variants. Those fields are `userdatums`, read-only values that @@ -350,12 +342,7 @@ largon2_hash_encoded(lua_State *L) encoded_len = argon2_encodedlen(t_cost, m_cost, parallelism, saltlen, hash_len, variant); -#if LUA_51 - luaL_buffinit(L, &buf); - encoded = luaL_prepbuffer(&buf); -#else encoded = luaL_buffinitsize(L, &buf, encoded_len); -#endif if (variant == Argon2_d) { ret_code = @@ -373,12 +360,7 @@ largon2_hash_encoded(lua_State *L) salt, saltlen, hash_len, encoded, encoded_len); } -#if LUA_51 - luaL_addsize(&buf, encoded_len); - luaL_pushresult(&buf); -#else - luaL_pushresultsize(&buf, encoded_len); -#endif + luaL_pushresultsize(&buf, encoded_len - 1); if (ret_code != ARGON2_OK) { err_msg = (char *) argon2_error_message(ret_code); @@ -484,30 +466,6 @@ largon2_push_argon2_variants_table(lua_State *L) } -#if LUA_51 -/* Compatibility for Lua 5.1. - * - * luaL_setfuncs() is used to create a module table where the functions have - * largon2_config_t as their first upvalue. Code borrowed from Lua 5.2 source. */ -static void -compat_luaL_setfuncs(lua_State *l, const luaL_Reg *reg, int nup) -{ - int i; - - luaL_checkstack(l, nup, "too many upvalues"); - for (; reg->name != NULL; reg++) { /* fill the table with given functions */ - for (i = 0; i < nup; i++) /* copy upvalues to the top */ - lua_pushvalue(l, -nup); - lua_pushcclosure(l, reg->func, nup); /* closure with those upvalues */ - lua_setfield(l, -(nup + 2), reg->name); - } - lua_pop(l, nup); /* remove upvalues */ -} -#else -#define compat_luaL_setfuncs(L, l, nup) luaL_setfuncs(L, l, nup) -#endif - - static const luaL_Reg largon2[] = { { "verify", largon2_verify }, { "hash_encoded", largon2_hash_encoded }, { "t_cost", largon2_cfg_t_cost }, @@ -524,7 +482,7 @@ luaopen_argon2(lua_State *L) lua_newtable(L); largon2_create_config(L); - compat_luaL_setfuncs(L, largon2, 1); + luaL_setfuncs(L, largon2, 1); /* push argon2.variants table */