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.
This commit is contained in:
Justine Tunney 2022-05-27 13:25:46 -07:00
parent cb67223051
commit de5de19004
234 changed files with 1728 additions and 1993 deletions

View file

@ -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));

View file

@ -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]);
}

View file

@ -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;
}

15
examples/tls.c Normal file
View file

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

View file

@ -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

View file

@ -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();
}
}

View file

@ -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);

View file

@ -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;
}

View file

@ -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);
}

View file

@ -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);
}
}

View file

@ -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);
}

View file

@ -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;

View file

@ -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,
};

View file

@ -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;
}

View file

@ -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)),

View file

@ -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;
}

View file

@ -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,
};

View file

@ -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_ */

View file

@ -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();

View file

@ -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;

View file

@ -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();
}

View file

@ -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),

30
libc/calls/siglock.c Normal file
View file

@ -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);
}

View file

@ -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];

View file

@ -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));

View file

@ -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 {

View file

@ -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"

View file

@ -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)

View file

@ -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

View file

@ -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

View file

@ -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;

View file

@ -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;

View file

@ -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,

View file

@ -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

View file

@ -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

View file

@ -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() &&

View file

@ -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;

View file

@ -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) {

View file

@ -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;

View file

@ -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);
}

View file

@ -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;
}

View file

@ -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;
}

View file

@ -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;
}

View file

@ -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;
}

View file

@ -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;
}

View file

@ -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;
}

View file

@ -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];
}
}

View file

@ -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;
}

View file

@ -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;
}

View file

@ -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;
}

View file

@ -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;
}

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -1,2 +0,0 @@
#include "libc/sysv/consts/syscon.internal.h"
.syscon misc,FUTEX_REQUEUE_PRIVATE,131,0,0,131,131,0

View file

@ -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

View file

@ -1,2 +0,0 @@
#include "libc/sysv/consts/syscon.internal.h"
.syscon misc,FUTEX_WAIT_PRIVATE,128,0,0,129,129,0

View file

@ -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

View file

@ -1,2 +0,0 @@
#include "libc/sysv/consts/syscon.internal.h"
.syscon misc,FUTEX_WAKE_PRIVATE,129,0,0,130,130,0

View file

@ -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) */

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

Some files were not shown because too many files have changed in this diff Show more