diff options
| author | Kacper <kacper@mail.openlinux.dev> | 2025-12-22 23:27:56 +0100 |
|---|---|---|
| committer | Kacper <kacper@mail.openlinux.dev> | 2025-12-22 23:30:32 +0100 |
| commit | 0f30d227497418c6d3bef7d52244407e30454504 (patch) | |
| tree | 0e1ac19623d3268380cf74328cdf643648a2f43c /lib/libc | |
| parent | 90dad97fc07f049383903a166631e2c257f9b8c1 (diff) | |
Added c11 threads, fixed some locks and add *_unlocked functions
Diffstat (limited to 'lib/libc')
109 files changed, 1268 insertions, 751 deletions
diff --git a/lib/libc/Kbuild b/lib/libc/Kbuild index 8a52fdb3..60ab4f8e 100644 --- a/lib/libc/Kbuild +++ b/lib/libc/Kbuild @@ -20,10 +20,10 @@ obj-y += inttypes/ obj-y += libgen/ obj-y += mman/ obj-y += monetary/ -obj-y += mqueue/ obj-y += msg/ obj-y += poll/ obj-y += pwd/ +obj-y += sched/ obj-y += select/ obj-y += sem/ obj-y += setjmp/ diff --git a/lib/libc/errno/errno.c b/lib/libc/errno/errno.c index fc7c99bb..56925b9f 100644 --- a/lib/libc/errno/errno.c +++ b/lib/libc/errno/errno.c @@ -1 +1,13 @@ -_Thread_local int errno; +#include <__thread.h> +#include <libc.h> + +#include <threads.h> + +/* Ensure TLS is initialized if errno is used */ +extern void __init_tls(void); +void *__force_tls_init = (void *) __init_tls; + +int *__errno(void) +{ + return &thrd_current()->errno_v; +} diff --git a/lib/libc/internal/Kbuild b/lib/libc/internal/Kbuild index d391eaa8..1bb5eaed 100644 --- a/lib/libc/internal/Kbuild +++ b/lib/libc/internal/Kbuild @@ -1,5 +1,4 @@ -obj-y += init/ obj-y += arch/ - -obj-y += panic.o -obj-y += syscall.o +obj-y += init/ +obj-y += thrd/ +obj-y += util/ diff --git a/lib/libc/internal/arch/aarch64/thread_self.c b/lib/libc/internal/arch/aarch64/thread_self.c new file mode 100644 index 00000000..543b07ab --- /dev/null +++ b/lib/libc/internal/arch/aarch64/thread_self.c @@ -0,0 +1,8 @@ +#include <__thread.h> + +inline struct __thread_self *__thread_self(void) +{ + struct __thread_self *self; + __asm__("mrs %0, tpidr_el0" : "=r"(self)); + return self; +} diff --git a/lib/libc/internal/arch/x86_64/Kbuild b/lib/libc/internal/arch/x86_64/Kbuild index 830a1c5b..49e4284f 100644 --- a/lib/libc/internal/arch/x86_64/Kbuild +++ b/lib/libc/internal/arch/x86_64/Kbuild @@ -1,5 +1,7 @@ obj-y += _start.o +obj-y += clone.o obj-y += fenv.o obj-y += longjmp.o obj-y += setjmp.o obj-y += sigsetjmp.o +obj-y += tcb.o diff --git a/lib/libc/internal/arch/x86_64/_start.c b/lib/libc/internal/arch/x86_64/_start.c index f3f4fef2..e8846bfa 100644 --- a/lib/libc/internal/arch/x86_64/_start.c +++ b/lib/libc/internal/arch/x86_64/_start.c @@ -4,5 +4,5 @@ __dead __naked void _start(void) { __asm__ __volatile__("mov %rsp, %rdi\n" - "call __init\n"); + "call __libc_init\n"); } diff --git a/lib/libc/internal/arch/x86_64/clone.s b/lib/libc/internal/arch/x86_64/clone.s new file mode 100644 index 00000000..80f512b1 --- /dev/null +++ b/lib/libc/internal/arch/x86_64/clone.s @@ -0,0 +1,106 @@ +/* + * x86_64 clone syscall trampoline + * + * Goal: provide a reliable way to run a C function in the child after the + * clone(2) syscall, without depending on the parent's stack frame (which is + * invalid in the child because the child starts with a new stack pointer). + * + * API (internal): + * + * long __clone(long (*fn)(void *), void *arg, + * unsigned long flags, void *child_stack, + * int *ptid, void *newtls, int *ctid); + * + * This uses the raw Linux x86_64 clone syscall: + * long clone(unsigned long flags, void *child_stack, + * int *ptid, int *ctid, unsigned long newtls); + * + * Behavior: + * - In the parent, returns child TID (> 0) or -errno (< 0). + * - In the child, calls fn(arg) and then exits the thread/process via + * SYS_exit (does not return). + * + * Notes: + * - We explicitly place (fn,arg) onto the child's new stack before issuing + * the syscall. On success in the child, we recover them from %rsp and call. + * - This avoids relying on any locals from the parent frame. + * - The stack is aligned to 16 bytes before the call into C. + */ + + .text + .globl __clone + .type __clone, @function + +__clone: + /* + * SysV AMD64 calling convention: + * fn in %rdi + * arg in %rsi + * flags in %rdx + * child_stack in %rcx + * ptid in %r8 + * newtls in %r9 + * ctid at 8(%rsp) + */ + movq 8(%rsp), %r10 /* r10 = ctid (7th arg from caller stack) */ + + /* r11 = child_stack (we'll use it as our working "new sp") */ + movq %rcx, %r11 + + /* + * Ensure 16-byte alignment for the eventual C call: + * We'll build the child's stack as: + * [low] fn (8) + * arg (8) + * [high] <-- %rsp in child before call site + * + * We align first, then reserve 16 bytes. + */ + andq $-16, %r11 + subq $16, %r11 + + /* Store fn and arg onto the child's stack */ + movq %rdi, 0(%r11) /* fn */ + movq %rsi, 8(%r11) /* arg */ + + /* + * Prepare registers for Linux x86_64 clone syscall: + * rax = SYS_clone + * rdi = flags + * rsi = child_stack + * rdx = ptid + * r10 = ctid + * r8 = newtls + */ + movq %rdx, %rdi /* flags */ + movq %r11, %rsi /* child_stack (new sp) */ + movq %r8, %rdx /* ptid */ + movq %r9, %r8 /* newtls */ + /* r10 already holds ctid */ + + movq $56, %rax /* SYS_clone on x86_64 */ + syscall + + /* Parent: rax = child tid (>0) or -errno (<0) */ + testq %rax, %rax + jnz 1f + + /* Child: rax == 0 */ + + /* %rsp is already the child_stack we provided. Recover fn/arg from it. */ + movq 8(%rsp), %rdi /* first arg to fn = arg */ + call *0(%rsp) /* call fn(arg) */ + + /* + * If fn returns, exit the thread/process. + * Use SYS_exit (60). Return value of fn is in %rax; pass as status in %rdi. + */ + movq %rax, %rdi + movq $60, %rax /* SYS_exit */ + syscall + hlt /* should not reach */ + +1: + ret + + .size __clone, .-__clone diff --git a/lib/libc/internal/arch/x86_64/tcb.c b/lib/libc/internal/arch/x86_64/tcb.c new file mode 100644 index 00000000..6e1f0c15 --- /dev/null +++ b/lib/libc/internal/arch/x86_64/tcb.c @@ -0,0 +1,13 @@ +#include <libc/tcb.h> + +__attribute__((__always_inline__)) void __libc_tcb_set(uint64_t tcb) +{ + __asm__ volatile("wrfsbase %0" ::"r"(tcb)); +} + +__attribute__((__always_inline__)) void *__libc_tcb_get(void) +{ + void *tcb; + __asm__ volatile("rdfsbase %0" : "=r"(tcb)); + return tcb; +} diff --git a/lib/libc/internal/include/__stdio.h b/lib/libc/internal/include/__stdio.h index 487a0382..7846b139 100644 --- a/lib/libc/internal/include/__stdio.h +++ b/lib/libc/internal/include/__stdio.h @@ -31,8 +31,6 @@ struct __FILE { struct __FILE *next; }; -#define __FILE(__stream) ((struct __FILE *)(__stream)) - void __libc_fadd(struct __FILE *f); #endif diff --git a/lib/libc/internal/include/__thread.h b/lib/libc/internal/include/__thread.h index 7639707a..3c68f8dd 100644 --- a/lib/libc/internal/include/__thread.h +++ b/lib/libc/internal/include/__thread.h @@ -1,8 +1,50 @@ #ifndef __LIBC_THREAD_H #define __LIBC_THREAD_H +#include <stdatomic.h> +#include <stddef.h> +#include <stdint.h> + +#define THREAD_STACK_SIZE (1024 * 1024) +#define THREAD_GUARD_SIZE 8192 + +enum __thread_state { THREAD_STATE_EXITED, THREAD_STATE_JOINABLE, THREAD_STATE_DETACHED }; + +struct tls { + void *data; + size_t length; + size_t size; + size_t align; +}; + struct __thread_self { - int tid; + struct __thread_self *self; + + /* Backing mapping for this thread (used by thrd_join/thrd_detach to munmap safely) */ + void *map_base; + size_t map_size; + +#ifdef __aarch64__ + uintptr_t *dtv; + uintptr_t canary; +#endif + + long tid; + int res; + int errno_v; + volatile int state; + +#ifdef __x86_64__ + uintptr_t canary; + uintptr_t *dtv; +#endif }; +void __libc_tls_copy(void *); + +#if defined(__x86_64__) +long __clone(long (*fn)(void *), void *arg, unsigned long flags, void *child_stack, long *ptid, void *newtls, + long *ctid); +#endif + #endif diff --git a/lib/libc/internal/include/atomic.h b/lib/libc/internal/include/atomic.h index e0593021..d40c1eae 100644 --- a/lib/libc/internal/include/atomic.h +++ b/lib/libc/internal/include/atomic.h @@ -1,22 +1,32 @@ #ifndef __LIBC_ATOMIC_H #define __LIBC_ATOMIC_H +#include <libc/futex.h> +#include <sched.h> #include <stdatomic.h> +#include <unistd.h> #define LIBC_LOCK(__lock) __libc_lock(&((__lock))) -#define LIBC_UNLOCK(__lock) atomic_flag_clear(&((__lock))) +#define LIBC_UNLOCK(__lock) __libc_unlock(&((__lock))) -static __inline void __libc_lock(volatile atomic_flag *lock) +__attribute__((__always_inline__)) __inline void __libc_unlock(volatile atomic_flag *lock) { - while (atomic_flag_test_and_set_explicit(lock, memory_order_acquire)) { - unsigned int spins = 1; - do { - for (unsigned int i = 0; i < spins; i++) - __asm__ volatile("pause"); - if (spins < 64) - spins *= 2; - } while (atomic_flag_test_and_set_explicit( - lock, memory_order_relaxed)); + atomic_flag_clear_explicit(lock, memory_order_release); + __futex_wake((volatile int *)lock, 1); +} + +__attribute__((__always_inline__)) __inline void __libc_lock(volatile atomic_flag *lock) +{ + if (atomic_flag_test_and_set_explicit(lock, memory_order_acquire) == 0) + return; + + while (1) { + __futex_wait((volatile int *)lock, 1); + + if (atomic_flag_test_and_set_explicit(lock, memory_order_acquire) == 0) + return; + + sched_yield(); } } diff --git a/lib/libc/internal/include/libc.h b/lib/libc/internal/include/libc.h index f06fa6d8..75a06dd2 100644 --- a/lib/libc/internal/include/libc.h +++ b/lib/libc/internal/include/libc.h @@ -1,26 +1,20 @@ #ifndef __LIBC_LIBC_H #define __LIBC_LIBC_H +#include <__stdio.h> #include <stdatomic.h> #include <stddef.h> #include <sys/cdefs.h> #define weak_reference(old, new) extern __typeof(old)((new)) __attribute__((__weak__, __alias__(#old))) -struct tls { - struct tls *next; - void *data; - size_t size; - size_t align; - size_t length; - size_t offset; -}; - struct libc { - size_t auxv[32]; + size_t *auxv; + struct { void *base; size_t size; + size_t align; } tls; enum { @@ -32,6 +26,10 @@ struct libc { volatile atomic_flag malloc; volatile atomic_flag environ; } lock; + + struct __FILE stdin; + struct __FILE stdout; + struct __FILE stderr; }; extern struct libc __libc; diff --git a/lib/libc/internal/include/libc/fsbase.h b/lib/libc/internal/include/libc/fsbase.h new file mode 100644 index 00000000..61f4abce --- /dev/null +++ b/lib/libc/internal/include/libc/fsbase.h @@ -0,0 +1,7 @@ +#ifndef __LIBC_FSBASE_H +#define __LIBC_FSBASE_H + +void *rdfsbase(void); +void wrfsbase(unsigned long); + +#endif diff --git a/lib/libc/internal/include/libc/futex.h b/lib/libc/internal/include/libc/futex.h new file mode 100644 index 00000000..a00cf0e7 --- /dev/null +++ b/lib/libc/internal/include/libc/futex.h @@ -0,0 +1,7 @@ +#ifndef __LIBC_FUTEX_H +#define __LIBC_FUTEX_H + +int __futex_wait(volatile int *, int); +int __futex_wake(volatile int *, int); + +#endif diff --git a/lib/libc/internal/include/libc/tcb.h b/lib/libc/internal/include/libc/tcb.h new file mode 100644 index 00000000..1defd41c --- /dev/null +++ b/lib/libc/internal/include/libc/tcb.h @@ -0,0 +1,9 @@ +#ifndef __LIBC_TCB_H +#define __LIBC_TCB_H + +#include <stdint.h> + +void *__libc_tcb_get(void); +void __libc_tcb_set(uint64_t); + +#endif diff --git a/lib/libc/internal/include/libc/thread.h b/lib/libc/internal/include/libc/thread.h new file mode 100644 index 00000000..6422a0e2 --- /dev/null +++ b/lib/libc/internal/include/libc/thread.h @@ -0,0 +1,6 @@ +#ifndef __LIBC_THREAD_H +#define __LIBC_THREAD_H + +void *__libc_thread_self(void); + +#endif diff --git a/lib/libc/internal/init/Kbuild b/lib/libc/internal/init/Kbuild index 361f220a..3c1bab0b 100644 --- a/lib/libc/internal/init/Kbuild +++ b/lib/libc/internal/init/Kbuild @@ -1,3 +1,4 @@ obj-y += init.o +obj-y += io.o obj-y += tls.o obj-y += vdso.o diff --git a/lib/libc/internal/init/init.c b/lib/libc/internal/init/init.c index b2dd8487..62678dce 100644 --- a/lib/libc/internal/init/init.c +++ b/lib/libc/internal/init/init.c @@ -1,11 +1,15 @@ +#include <alloca.h> #include <libc.h> #include <stddef.h> #include <stdint.h> #include <stdlib.h> #include <sys/cdefs.h> -extern void __init_vdso(void); -extern void __init_tls(void); +#define BUFSIZ 4096 + +extern void __libc_init_vdso(void) __attribute__((weak)); +extern void __libc_init_tls(void) __attribute__((weak)); +extern void __libc_init_io(void) __attribute__((weak)); extern int main(int, char **, char **); @@ -13,10 +17,9 @@ struct libc __libc = { 0 }; char **environ; char *__progname; -__used void __init(uintptr_t *rsp) +__used void __libc_init(uintptr_t *rsp) { char **argv; - size_t *auxv; int argc; argc = (int)(*rsp); @@ -30,13 +33,27 @@ __used void __init(uintptr_t *rsp) while (*rsp) rsp++; - auxv = (size_t *)++rsp; + __libc.auxv = (size_t *)++rsp; + + if (__libc_init_io) { + __libc_init_io(); + + __libc.stdout.buf = alloca(BUFSIZ); + __libc.stdout.buf_size = BUFSIZ; + __libc.stdout.buf_len = 0; + __libc.stdout.buf_pos = 0; + + __libc.stdin.buf = alloca(BUFSIZ); + __libc.stdin.buf_size = BUFSIZ; + __libc.stdin.buf_len = 0; + __libc.stdin.buf_pos = 0; + } - for (size_t i = 0; auxv[i]; i += 2) - __libc.auxv[auxv[i]] = auxv[i + 1]; + if (__libc_init_tls) + __libc_init_tls(); - __init_tls(); - __init_vdso(); + if (__libc_init_vdso) + __libc_init_vdso(); exit(main(argc, argv, environ)); } diff --git a/lib/libc/internal/init/io.c b/lib/libc/internal/init/io.c new file mode 100644 index 00000000..4790af89 --- /dev/null +++ b/lib/libc/internal/init/io.c @@ -0,0 +1,42 @@ +#include <atomic.h> +#include <fcntl.h> +#include <libc.h> +#include <stdio.h> +#include <unistd.h> + +struct __FILE *const stdout = (struct __FILE *)&__libc.stdout; +struct __FILE *const stdin = (struct __FILE *)&__libc.stdin; +struct __FILE *const stderr = (struct __FILE *)&__libc.stderr; + +void __libc_init_io(void) +{ + /* stdout */ + memset(&__libc.stdout, 0, sizeof(struct __FILE)); + __libc.stdout.fd = STDOUT_FILENO; + __libc.stdout.flags = O_WRONLY; + __libc.stdout.type = _IOLBF; + __libc.stdout.buf = NULL; + __libc.stdout.buf_size = 0; + __libc.stdout.buf_len = 0; + __libc.stdout.buf_pos = 0; + + /* stdin */ + memset(&__libc.stdin, 0, sizeof(struct __FILE)); + __libc.stdin.fd = STDIN_FILENO; + __libc.stdin.flags = O_RDONLY; + __libc.stdin.type = _IONBF; + __libc.stdin.buf = NULL; + __libc.stdin.buf_size = 0; + __libc.stdin.buf_len = 0; + __libc.stdin.buf_pos = 0; + + /* stderr */ + memset(&__libc.stderr, 0, sizeof(struct __FILE)); + __libc.stderr.fd = STDERR_FILENO; + __libc.stderr.flags = O_WRONLY; + __libc.stderr.type = _IONBF; + __libc.stderr.buf = NULL; + __libc.stderr.buf_size = 0; + __libc.stderr.buf_len = 0; + __libc.stderr.buf_pos = 0; +} diff --git a/lib/libc/internal/init/tls.c b/lib/libc/internal/init/tls.c index f6ccde35..302edd9d 100644 --- a/lib/libc/internal/init/tls.c +++ b/lib/libc/internal/init/tls.c @@ -6,14 +6,31 @@ #include <sys/mman.h> #include <syscall.h> -#define ALIGN_DOWN(x, a) ((x) & ~((a) - 1)) -#define ALIGN_UP(x, a) (((x) + (a) - 1) & ~((a) - 1)) +#include <libc/tcb.h> +#include <stdio.h> + +// TODO: remove this thing static struct tls __libc_tls = { 0 }; + static struct __thread_self __libc_thread; volatile int __libc_tid; -void __init_tls(void) +void __libc_tls_copy(void *dest) +{ + if (__libc_tls.size == 0) + return; + + if (__libc_tls.length > 0) { + memcpy(dest, __libc_tls.data, __libc_tls.length); + + memset((unsigned char *)dest + __libc_tls.length, 0, __libc_tls.size - __libc_tls.length); + } else { + memset(dest, 0, __libc_tls.size); + } +} + +void __libc_init_tls(void) { int r; void *mem; @@ -40,6 +57,7 @@ void __init_tls(void) __libc_tls.length = tls_phdr->p_filesz; __libc_tls.size = tls_phdr->p_memsz; __libc_tls.align = tls_phdr->p_align; + __libc.tls.align = __libc_tls.align; } if (__libc_tls.size != 0) { @@ -56,21 +74,22 @@ void __init_tls(void) thrd = (struct __thread_self *)mem; tls_mem = (unsigned char *)mem + sizeof(struct __thread_self); - if (tls_phdr->p_filesz > 0) { - memcpy(tls_mem, (void *)tls_phdr->p_vaddr, tls_phdr->p_filesz); - memset(tls_mem + tls_phdr->p_filesz, 0, tls_phdr->p_memsz - tls_phdr->p_filesz); - } else { - memset(tls_mem, 0, tls_phdr->p_memsz); - } + __libc_tls_copy(tls_mem); - r = syscall(arch_prctl, ARCH_SET_FS, mem + sizeof(struct __thread_self)); - panic_if(r < 0, "arch_prctl(SET_FS) failed"); + __libc.tls.base = tls_mem; + __libc.tls.size = __libc_tls.size; } else { - __libc.tls.base = NULL; thrd = &__libc_thread; + __libc.tls.base = &__libc_thread; + __libc.tls.size = 0; } r = syscall(set_tid_address, &__libc_tid); panic_if(r < 0, "set_tid_address failed"); + + thrd->self = thrd; thrd->tid = r; + thrd->dtv = NULL; + + __libc_tcb_set((uint64_t)thrd); } diff --git a/lib/libc/internal/init/vdso.c b/lib/libc/internal/init/vdso.c index de8d0e2f..73bfb46b 100644 --- a/lib/libc/internal/init/vdso.c +++ b/lib/libc/internal/init/vdso.c @@ -3,7 +3,18 @@ #include <string.h> #include <sys/auxv.h> -void __init_vdso(void) +int (*__vdso_clock_gettime)(int, struct timespec *) = 0; +int (*__vdso_getcpu)(unsigned *, unsigned *, void *) = 0; +int (*__vdso_time)(long *) = 0; + +struct __vdso_sym __vdso_symtab[] = { + { "__vdso_clock_gettime", (void *)&__vdso_clock_gettime }, + { "__vdso_getcpu", (void *)&__vdso_getcpu }, + { "__vdso_time", (void *)&__vdso_time }, + { 0, 0 }, +}; + +void __libc_init_vdso(void) { Elf64_Ehdr *ehdr = (Elf64_Ehdr *)getauxval(AT_SYSINFO_EHDR); diff --git a/lib/libc/internal/thrd/Kbuild b/lib/libc/internal/thrd/Kbuild new file mode 100644 index 00000000..c3817f75 --- /dev/null +++ b/lib/libc/internal/thrd/Kbuild @@ -0,0 +1 @@ +obj-y += self.o diff --git a/lib/libc/internal/thrd/self.c b/lib/libc/internal/thrd/self.c new file mode 100644 index 00000000..b083223f --- /dev/null +++ b/lib/libc/internal/thrd/self.c @@ -0,0 +1,6 @@ +#include <libc/tcb.h> + +__attribute__((__always_inline__)) void *__libc_thread_self(void) +{ + return __libc_tcb_get(); +} diff --git a/lib/libc/internal/util/Kbuild b/lib/libc/internal/util/Kbuild new file mode 100644 index 00000000..9c8d0fc7 --- /dev/null +++ b/lib/libc/internal/util/Kbuild @@ -0,0 +1,3 @@ +obj-y += futex.o +obj-y += panic.o +obj-y += syscall.o diff --git a/lib/libc/internal/util/futex.c b/lib/libc/internal/util/futex.c new file mode 100644 index 00000000..2f9872a0 --- /dev/null +++ b/lib/libc/internal/util/futex.c @@ -0,0 +1,13 @@ +#include <linux/futex.h> +#include <syscall.h> + +int __futex_wait(volatile int *uaddr, int val) +{ + return syscall(futex, uaddr, FUTEX_WAIT | FUTEX_PRIVATE_FLAG, val, 0, 0, 0); +} + +int __futex_wake(volatile int *uaddr, int n) +{ + /* futex(uaddr, FUTEX_WAKE, val=n, ...) */ + return syscall(futex, uaddr, FUTEX_WAKE | FUTEX_PRIVATE_FLAG, n, 0, 0, 0); +} diff --git a/lib/libc/internal/panic.c b/lib/libc/internal/util/panic.c index 1af6d6cf..1af6d6cf 100644 --- a/lib/libc/internal/panic.c +++ b/lib/libc/internal/util/panic.c diff --git a/lib/libc/internal/syscall.c b/lib/libc/internal/util/syscall.c index f7fd3c4b..f7fd3c4b 100644 --- a/lib/libc/internal/syscall.c +++ b/lib/libc/internal/util/syscall.c diff --git a/lib/libc/mman/mprotect.c b/lib/libc/mman/mprotect.c index bc97ae4a..51c11b15 100644 --- a/lib/libc/mman/mprotect.c +++ b/lib/libc/mman/mprotect.c @@ -1,5 +1,3 @@ - - #include <stddef.h> // for size_t #include <syscall.h> // for __syscall_3, syscall diff --git a/lib/libc/sched/Kbuild b/lib/libc/sched/Kbuild new file mode 100644 index 00000000..9e6415ba --- /dev/null +++ b/lib/libc/sched/Kbuild @@ -0,0 +1,8 @@ +obj-y += sched_get_priority_max.o +obj-y += sched_get_priority_min.o +obj-y += sched_getparam.o +obj-y += sched_getscheduler.o +obj-y += sched_rr_get_interval.o +obj-y += sched_setparam.o +obj-y += sched_setscheduler.o +obj-y += sched_yield.o diff --git a/lib/libc/sched/sched_get_priority_max.c b/lib/libc/sched/sched_get_priority_max.c new file mode 100644 index 00000000..a6a859db --- /dev/null +++ b/lib/libc/sched/sched_get_priority_max.c @@ -0,0 +1,7 @@ +#include <sched.h> +#include <syscall.h> + +int sched_get_priority_max(int policy) +{ + return syscall(sched_get_priority_max, policy); +} diff --git a/lib/libc/sched/sched_get_priority_min.c b/lib/libc/sched/sched_get_priority_min.c new file mode 100644 index 00000000..869afd9c --- /dev/null +++ b/lib/libc/sched/sched_get_priority_min.c @@ -0,0 +1,7 @@ +#include <sched.h> +#include <syscall.h> + +int sched_get_priority_min(int policy) +{ + return syscall(sched_get_priority_min, policy); +} diff --git a/lib/libc/sched/sched_getparam.c b/lib/libc/sched/sched_getparam.c new file mode 100644 index 00000000..0c9ae00e --- /dev/null +++ b/lib/libc/sched/sched_getparam.c @@ -0,0 +1,9 @@ +#include <errno.h> +#include <sched.h> +#include <sys/cdefs.h> + +int sched_getparam(pid_t __unused pid, struct sched_param *__unused param) +{ + errno = ENOSYS; + return -1; +} diff --git a/lib/libc/sched/sched_getscheduler.c b/lib/libc/sched/sched_getscheduler.c new file mode 100644 index 00000000..9dc6da82 --- /dev/null +++ b/lib/libc/sched/sched_getscheduler.c @@ -0,0 +1,7 @@ +#include <sched.h> +#include <syscall.h> + +int sched_getscheduler(pid_t pid) +{ + return syscall(sched_getscheduler, pid); +} diff --git a/lib/libc/sched/sched_rr_get_interval.c b/lib/libc/sched/sched_rr_get_interval.c new file mode 100644 index 00000000..a99f2a3d --- /dev/null +++ b/lib/libc/sched/sched_rr_get_interval.c @@ -0,0 +1,7 @@ +#include <sched.h> +#include <syscall.h> + +int sched_rr_get_interval(pid_t pid, struct timespec *tp) +{ + return syscall(sched_rr_get_interval, pid, tp); +} diff --git a/lib/libc/sched/sched_setparam.c b/lib/libc/sched/sched_setparam.c new file mode 100644 index 00000000..2eae75dd --- /dev/null +++ b/lib/libc/sched/sched_setparam.c @@ -0,0 +1,7 @@ +#include <sched.h> +#include <syscall.h> + +int sched_setparam(pid_t pid, const struct sched_param *param) +{ + return syscall(sched_setparam, pid, param); +} diff --git a/lib/libc/sched/sched_setscheduler.c b/lib/libc/sched/sched_setscheduler.c new file mode 100644 index 00000000..39dd0336 --- /dev/null +++ b/lib/libc/sched/sched_setscheduler.c @@ -0,0 +1,7 @@ +#include <sched.h> +#include <syscall.h> + +int sched_setscheduler(pid_t pid, int policy, const struct sched_param *param) +{ + return syscall(sched_setscheduler, pid, policy, param); +} diff --git a/lib/libc/sched/sched_yield.c b/lib/libc/sched/sched_yield.c new file mode 100644 index 00000000..e74abec8 --- /dev/null +++ b/lib/libc/sched/sched_yield.c @@ -0,0 +1,6 @@ +#include <syscall.h> + +int sched_yield(void) +{ + return syscall(sched_yield); +} diff --git a/lib/libc/stdio/Kbuild b/lib/libc/stdio/Kbuild index 36339313..0d1df566 100644 --- a/lib/libc/stdio/Kbuild +++ b/lib/libc/stdio/Kbuild @@ -1,33 +1,50 @@ obj-y += asprintf.o obj-y += clearerr.o +obj-y += clearerr_unlocked.o obj-y += dprintf.o obj-y += dtoa.o obj-y += fclose.o obj-y += fdopen.o obj-y += feof.o +obj-y += feof_unlocked.o obj-y += ferror.o +obj-y += ferror_unlocked.o obj-y += fflush.o +obj-y += fflush_unlocked.o obj-y += fgetc.o +obj-y += fgetc_unlocked.o obj-y += fgets.o +obj-y += fgets_unlocked.o obj-y += fileno.o +obj-y += fileno_unlocked.o +obj-y += flockfile.o obj-y += fmemopen.o obj-y += fopen.o obj-y += fprintf.o obj-y += fputc.o +obj-y += fputc_unlocked.o obj-y += fputs.o +obj-y += fputs_unlocked.o obj-y += fread.o +obj-y += fread_unlocked.o obj-y += fseek.o obj-y += ftell.o obj-y += ftello.o +obj-y += ftrylockfile.o +obj-y += funlockfile.o obj-y += fwrite.o +obj-y += fwrite_unlocked.o obj-y += getc.o +obj-y += getc_unlocked.o obj-y += getchar.o +obj-y += getchar_unlocked.o obj-y += pclose.o obj-y += perror.o obj-y += popen.o obj-y += printf.o obj-y += putc.o obj-y += putchar.o +obj-y += putchar_unlocked.o obj-y += puts.o obj-y += remove.o obj-y += rename.o @@ -37,9 +54,6 @@ obj-y += setbuf.o obj-y += setvbuf.o obj-y += snprintf.o obj-y += sprintf.o -obj-y += stderr.o -obj-y += stdin.o -obj-y += stdout.o obj-y += vasprintf.o obj-y += vdprintf.o obj-y += vfprintf.o diff --git a/lib/libc/stdio/clearerr.c b/lib/libc/stdio/clearerr.c index 02244466..8389a085 100644 --- a/lib/libc/stdio/clearerr.c +++ b/lib/libc/stdio/clearerr.c @@ -1,14 +1,9 @@ -#include "__stdio.h" // for __FILE, _IO_EOF, _IO_ERR -#include "stddef.h" // for NULL - -#include <stdio.h> // for FILE, clearerr +#include <__stdio.h> +#include <stdio.h> void clearerr(FILE *stream) { - struct __FILE *stream_impl = __FILE(stream); - - if (stream == NULL) - return; - - stream_impl->flags &= ~(_IO_ERR | _IO_EOF); + flockfile(stream); + clearerr_unlocked(stream); + funlockfile(stream); } diff --git a/lib/libc/stdio/clearerr_unlocked.c b/lib/libc/stdio/clearerr_unlocked.c new file mode 100644 index 00000000..da4ea106 --- /dev/null +++ b/lib/libc/stdio/clearerr_unlocked.c @@ -0,0 +1,8 @@ +#include <__stdio.h> +#include <stdio.h> + +void clearerr_unlocked(FILE *stream) +{ + if (stream != NULL) + stream->flags &= ~(_IO_ERR | _IO_EOF); +} diff --git a/lib/libc/stdio/fclose.c b/lib/libc/stdio/fclose.c index 4534715b..4fdf6495 100644 --- a/lib/libc/stdio/fclose.c +++ b/lib/libc/stdio/fclose.c @@ -8,7 +8,7 @@ int fclose(FILE *stream) return -1; if (stream != stdin && stream != stdout && stream != stderr) { - if (close((__FILE(stream))->fd) == -1) + if (close(fileno(stream)) == -1) return -1; } diff --git a/lib/libc/stdio/fdopen.c b/lib/libc/stdio/fdopen.c index bded5f27..dc9da567 100644 --- a/lib/libc/stdio/fdopen.c +++ b/lib/libc/stdio/fdopen.c @@ -4,33 +4,30 @@ #include <sys/cdefs.h> #include <unistd.h> // for lseek, off_t -__weak void __stdio_cleanup(void) -{ -} - FILE *fdopen(int fildes, const char *mode) { - FILE *stream; + struct __FILE *stream; if (mode == NULL || (mode[0] != 'r' && mode[0] != 'w' && mode[0] != 'a')) { return NULL; } - stream = calloc(1, sizeof(FILE)); + stream = calloc(1, sizeof(struct __FILE)); if (stream == NULL) return NULL; - __FILE(stream)->fd = fildes; - atomic_flag_clear(&__FILE(stream)->lock); + stream->fd = fildes; + atomic_flag_clear(&stream->lock); + if (mode[0] == 'r') { - __FILE(stream)->type = _IONBF; + stream->type = _IONBF; } else if (mode[0] == 'w') { - __FILE(stream)->type = _IOLBF; + stream->type = _IOLBF; } else if (mode[0] == 'a') { - __FILE(stream)->type = _IONBF; - - off_t offset = lseek(fildes, 0, SEEK_END); - if (offset == (off_t)-1) { + off_t off; + stream->type = _IONBF; + off = lseek(fildes, 0, SEEK_END); + if (off == (off_t)-1) { free(stream); return NULL; } diff --git a/lib/libc/stdio/feof.c b/lib/libc/stdio/feof.c index f9245d06..6a36172b 100644 --- a/lib/libc/stdio/feof.c +++ b/lib/libc/stdio/feof.c @@ -1,12 +1,13 @@ -#include "stddef.h" // for NULL - -#include <__stdio.h> // for __FILE -#include <stdio.h> // for FILE, feof +#include <__stdio.h> +#include <stdio.h> int feof(FILE *stream) { - if (stream == NULL) - return 0; + int r; + + flockfile(stream); + r = feof_unlocked(stream); + funlockfile(stream); - return (__FILE(stream))->eof; + return r; } diff --git a/lib/libc/stdio/feof_unlocked.c b/lib/libc/stdio/feof_unlocked.c new file mode 100644 index 00000000..4d7d9d53 --- /dev/null +++ b/lib/libc/stdio/feof_unlocked.c @@ -0,0 +1,7 @@ +#include <__stdio.h> +#include <stdio.h> + +int feof_unlocked(FILE *stream) +{ + return (stream) ? stream->eof : 0; +} diff --git a/lib/libc/stdio/ferror.c b/lib/libc/stdio/ferror.c index 5e4b8dc4..9391a44a 100644 --- a/lib/libc/stdio/ferror.c +++ b/lib/libc/stdio/ferror.c @@ -1,12 +1,12 @@ -#include "__stdio.h" // for __FILE, _IO_ERR -#include "stddef.h" // for NULL - -#include <stdio.h> // for FILE, ferror +#include <stdio.h> int ferror(FILE *stream) { - if (stream == NULL) - return 0; + int r; + + flockfile(stream); + r = ferror_unlocked(stream); + funlockfile(stream); - return (__FILE(stream)->flags & _IO_ERR) != 0; + return r; } diff --git a/lib/libc/stdio/ferror_unlocked.c b/lib/libc/stdio/ferror_unlocked.c new file mode 100644 index 00000000..3c622dd9 --- /dev/null +++ b/lib/libc/stdio/ferror_unlocked.c @@ -0,0 +1,7 @@ +#include <__stdio.h> +#include <stdio.h> + +int ferror_unlocked(FILE *stream) +{ + return (stream) ? (stream->flags & _IO_ERR) != 0 : 0; +} diff --git a/lib/libc/stdio/fflush.c b/lib/libc/stdio/fflush.c index 1cf4b7bd..b3fca8bd 100644 --- a/lib/libc/stdio/fflush.c +++ b/lib/libc/stdio/fflush.c @@ -3,74 +3,15 @@ #include <atomic.h> // for LIBC_UNLOCK, LIBC_LOCK #include <errno.h> // for errno, EBADF, EIO -#include <fcntl.h> // for O_ACCMODE, O_RDONLY -#include <stdio.h> // for EOF, FILE, fflush -#include <string.h> // for memmove -#include <unistd.h> // for size_t, write, ssize_t +#include <stdio.h> -int fflush(FILE *stream) +int fflush(struct __FILE *stream) { - if (stream == NULL) { - // TODO: Implement flushing all open streams - // For now, just return success - return 0; - } + int r; - if (__FILE(stream)->buf_len == 0) { - return 0; - } + flockfile(stream); + r = fflush_unlocked(stream); + funlockfile(stream); - if (__FILE(stream)->fd == -1) { - __FILE(stream)->buf_len = 0; - return 0; - } - - if (__FILE(stream)->flags & _IO_ERR) { - errno = EIO; - return EOF; - } - - if ((__FILE(stream)->flags & O_ACCMODE) == O_RDONLY) { - errno = EBADF; - return EOF; - } - - LIBC_LOCK(__FILE(stream)->lock); - - size_t bytes_to_write = __FILE(stream)->buf_len; - size_t total_written = 0; - char *buf_ptr = __FILE(stream)->buf; - - while (total_written < bytes_to_write) { - ssize_t result = write(__FILE(stream)->fd, - buf_ptr + total_written, - bytes_to_write - total_written); - - if (result < 0) { - __FILE(stream)->flags |= _IO_ERR; - LIBC_UNLOCK(__FILE(stream)->lock); - return EOF; - } - - if (result == 0) { - break; - } - - total_written += result; - } - - if (total_written == bytes_to_write) { - __FILE(stream)->buf_len = 0; - __FILE(stream)->buf_pos = 0; - } else { - size_t remaining = bytes_to_write - total_written; - memmove(__FILE(stream)->buf, - __FILE(stream)->buf + total_written, remaining); - __FILE(stream)->buf_len = remaining; - __FILE(stream)->buf_pos = 0; - } - - LIBC_UNLOCK(__FILE(stream)->lock); - - return (total_written == bytes_to_write) ? 0 : EOF; + return r; } diff --git a/lib/libc/stdio/fflush_unlocked.c b/lib/libc/stdio/fflush_unlocked.c new file mode 100644 index 00000000..b4ee3e43 --- /dev/null +++ b/lib/libc/stdio/fflush_unlocked.c @@ -0,0 +1,64 @@ +#include <__stdio.h> +#include <errno.h> +#include <fcntl.h> +#include <stdio.h> +#include <sys/cdefs.h> +#include <unistd.h> + +int fflush_unlocked(struct __FILE *stream) +{ + if (stream == NULL) { + // TODO: flush all streams + return 0; + } + + if (__predict_false(stream->fd) == -1) { + stream->buf_len = 0; + return 0; + } + + if (__predict_false(stream->buf == 0)) { + return 0; + } + + if (stream->flags & _IO_ERR) { + errno = EIO; + return EOF; + } + + if ((stream->flags & O_ACCMODE) == O_RDONLY) { + errno = EBADF; + return EOF; + } + + size_t bytes_to_write = stream->buf_len; + size_t total_written = 0; + char *buf_ptr = stream->buf; + + while (total_written < bytes_to_write) { + ssize_t result = write(stream->fd, buf_ptr + total_written, bytes_to_write - total_written); + + if (result < 0) { + stream->flags |= _IO_ERR; + return EOF; + } + + if (result == 0) { + break; + } + + total_written += result; + } + + if (total_written == bytes_to_write) { + stream->buf_len = 0; + stream->buf_pos = 0; + } else { + size_t remaining = bytes_to_write - total_written; + memmove(stream->buf, stream->buf + total_written, remaining); + stream->buf_len = remaining; + stream->buf_pos = 0; + } + + return (total_written == bytes_to_write) ? 0 : EOF; +} diff --git a/lib/libc/stdio/fgetc.c b/lib/libc/stdio/fgetc.c index a7612f42..f0642c30 100644 --- a/lib/libc/stdio/fgetc.c +++ b/lib/libc/stdio/fgetc.c @@ -1,11 +1,12 @@ -#include <stdio.h> // for fread, FILE, fgetc +#include <stdio.h> int fgetc(FILE *stream) { - int c; + int r; - if (fread(&c, 1, 1, stream) < 0) - return -1; + flockfile(stream); + r = fgetc_unlocked(stream); + funlockfile(stream); - return c; + return r; } diff --git a/lib/libc/stdio/fgetc_unlocked.c b/lib/libc/stdio/fgetc_unlocked.c new file mode 100644 index 00000000..5cccfd87 --- /dev/null +++ b/lib/libc/stdio/fgetc_unlocked.c @@ -0,0 +1,11 @@ +#include <stdio.h> + +int fgetc_unlocked(FILE *stream) +{ + int c; + + if (fread_unlocked(&c, 1, 1, stream) < 0) + return -1; + + return c; +} diff --git a/lib/libc/stdio/fgets.c b/lib/libc/stdio/fgets.c index adeae1b4..d0f7d2d9 100644 --- a/lib/libc/stdio/fgets.c +++ b/lib/libc/stdio/fgets.c @@ -1,11 +1,12 @@ -#include "stddef.h" // for NULL - -#include <libc.h> // for weak_reference -#include <stdio.h> // for fread, FILE, fgets +#include <stdio.h> char *fgets(char *restrict s, int n, FILE *restrict stream) { - return fread(s, 1, n, stream) ? s : NULL; -} + char *r; -weak_reference(fgets, fgets_unlocked); + flockfile(stream); + r = fgets_unlocked(s, n, stream); + funlockfile(stream); + + return r; +} diff --git a/lib/libc/stdio/fgets_unlocked.c b/lib/libc/stdio/fgets_unlocked.c new file mode 100644 index 00000000..9e2dca60 --- /dev/null +++ b/lib/libc/stdio/fgets_unlocked.c @@ -0,0 +1,6 @@ +#include <stdio.h> + +char *fgets_unlocked(char *s, int n, FILE *stream) +{ + return fread_unlocked(s, 1, n, stream) ? s : NULL; +} diff --git a/lib/libc/stdio/fileno.c b/lib/libc/stdio/fileno.c index e27b56de..4fa47eb4 100644 --- a/lib/libc/stdio/fileno.c +++ b/lib/libc/stdio/fileno.c @@ -1,20 +1,12 @@ -#include <__stdio.h> // for __FILE -#include <atomic.h> // for LIBC_LOCK, LIBC_UNLOCK -#include <errno.h> // for EBADF, errno -#include <stdio.h> // for FILE, fileno +#include <stdio.h> int fileno(FILE *stream) { - int fd; + int r; - LIBC_LOCK(__FILE(stream)->lock); - fd = __FILE(stream)->fd; - LIBC_UNLOCK(__FILE(stream)->lock); + flockfile(stream); + r = fileno_unlocked(stream); + funlockfile(stream); - if (fd < 0) { - errno = EBADF; - return -1; - } - - return fd; + return r; } diff --git a/lib/libc/stdio/fileno_unlocked.c b/lib/libc/stdio/fileno_unlocked.c new file mode 100644 index 00000000..a3490686 --- /dev/null +++ b/lib/libc/stdio/fileno_unlocked.c @@ -0,0 +1,13 @@ +#include <__stdio.h> +#include <errno.h> +#include <stdio.h> + +int fileno_unlocked(FILE *stream) +{ + if (stream->fd < 0) { + errno = EBADF; + return -1; + } + + return stream->fd; +} diff --git a/lib/libc/stdio/flockfile.c b/lib/libc/stdio/flockfile.c new file mode 100644 index 00000000..788750b0 --- /dev/null +++ b/lib/libc/stdio/flockfile.c @@ -0,0 +1,8 @@ +#include <__stdio.h> +#include <atomic.h> +#include <stdio.h> + +void flockfile(FILE *file) +{ + LIBC_LOCK(file->lock); +} diff --git a/lib/libc/stdio/fmemopen.c b/lib/libc/stdio/fmemopen.c index e1b2ccff..1e90b5ea 100644 --- a/lib/libc/stdio/fmemopen.c +++ b/lib/libc/stdio/fmemopen.c @@ -21,10 +21,10 @@ FILE *fmemopen(void *restrict buf, size_t max_size, const char *restrict mode) if (stream == NULL) return stream; - __FILE(stream)->fd = -1; - __FILE(stream)->buf = buf; - __FILE(stream)->buf_size = max_size; - __FILE(stream)->type = _IOFBF; + stream->fd = -1; + stream->buf = buf; + stream->buf_size = max_size; + stream->type = _IOFBF; if (mode[0] == 'r') { flags = O_RDONLY; @@ -42,7 +42,7 @@ FILE *fmemopen(void *restrict buf, size_t max_size, const char *restrict mode) flags = (flags & ~(O_RDONLY | O_WRONLY)) | O_RDWR; } - __FILE(stream)->flags = flags; + stream->flags = flags; __libc_fadd(stream); diff --git a/lib/libc/stdio/fopen.c b/lib/libc/stdio/fopen.c index 5415e711..0265694a 100644 --- a/lib/libc/stdio/fopen.c +++ b/lib/libc/stdio/fopen.c @@ -8,10 +8,6 @@ #include <sys/cdefs.h> #include <unistd.h> // for close -__weak void __stdio_cleanup(void) -{ -} - FILE *fopen(const char *restrict pathname, const char *restrict mode) { int fd, flags, _mode; @@ -42,15 +38,15 @@ FILE *fopen(const char *restrict pathname, const char *restrict mode) if (stream == NULL) return NULL; - __FILE(stream)->fd = fd; - __FILE(stream)->buf_size = BUFSIZ; - __FILE(stream)->flags = flags; - __FILE(stream)->type = _IOLBF; - atomic_flag_clear(&__FILE(stream)->lock); + stream->fd = fd; + stream->buf_size = BUFSIZ; + stream->flags = flags; + stream->type = _IOLBF; + atomic_flag_clear(&stream->lock); - __FILE(stream)->buf = malloc(BUFSIZ); + stream->buf = malloc(BUFSIZ); - if (__FILE(stream)->buf == NULL) { + if (stream->buf == NULL) { close(fd); free(stream); return NULL; diff --git a/lib/libc/stdio/fputc.c b/lib/libc/stdio/fputc.c index 922011f2..365fbb96 100644 --- a/lib/libc/stdio/fputc.c +++ b/lib/libc/stdio/fputc.c @@ -1,25 +1,12 @@ -#include "stddef.h" // for NULL - -#include <__stdio.h> // for __FILE -#include <errno.h> // for EINVAL, errno -#include <stdio.h> // for EOF, fwrite, FILE, fputc +#include <stdio.h> int fputc(int c, FILE *stream) { - if (stream == NULL) { - errno = EINVAL; - return EOF; - } - - if ((__FILE(stream))->fd == -1 && (__FILE(stream))->buf != NULL) { - if ((__FILE(stream))->buf_len >= - (__FILE(stream))->buf_size - 1) { - return EOF; - } + int r; - (__FILE(stream))->buf[(__FILE(stream))->buf_len++] = (char)c; - return (unsigned char)c; - } + flockfile(stream); + r = fputc_unlocked(c, stream); + funlockfile(stream); - return fwrite(&c, 1, 1, stream) ? c : EOF; + return r; } diff --git a/lib/libc/stdio/fputc_unlocked.c b/lib/libc/stdio/fputc_unlocked.c new file mode 100644 index 00000000..966721e7 --- /dev/null +++ b/lib/libc/stdio/fputc_unlocked.c @@ -0,0 +1,6 @@ +#include <stdio.h> + +int fputc_unlocked(int c, FILE *stream) +{ + return fwrite_unlocked(&c, 1, 1, stream) ? c : EOF; +} diff --git a/lib/libc/stdio/fputs.c b/lib/libc/stdio/fputs.c index 2ba0d4d1..ac5261e7 100644 --- a/lib/libc/stdio/fputs.c +++ b/lib/libc/stdio/fputs.c @@ -1,7 +1,12 @@ -#include <stdio.h> // for fwrite, EOF, FILE, fputs -#include <string.h> // for strlen +#include <stdio.h> int fputs(const char *restrict s, FILE *restrict stream) { - return fwrite(s, 1, strlen(s), stream) == strlen(s) ? 0 : EOF; + int r; + + flockfile(stream); + r = fputs_unlocked(s, stream); + funlockfile(stream); + + return r; } diff --git a/lib/libc/stdio/fputs_unlocked.c b/lib/libc/stdio/fputs_unlocked.c new file mode 100644 index 00000000..aeab8d32 --- /dev/null +++ b/lib/libc/stdio/fputs_unlocked.c @@ -0,0 +1,9 @@ +#include <stdio.h> +#include <string.h> + +int fputs_unlocked(const char *s, FILE *stream) +{ + size_t len = strlen(s); + + return fwrite_unlocked(s, 1, len, stream) == len ? 0 : EOF; +} diff --git a/lib/libc/stdio/fread.c b/lib/libc/stdio/fread.c index 443b4874..bcadbbdc 100644 --- a/lib/libc/stdio/fread.c +++ b/lib/libc/stdio/fread.c @@ -1,54 +1,12 @@ -#include "__stdio.h" // for __FILE, _IO_EOF, _IO_ERR +#include <stdio.h> -#include <atomic.h> // for LIBC_LOCK, LIBC_UNLOCK -#include <stdio.h> // for fread, BUFSIZ, FILE -#include <string.h> // for memcpy -#include <unistd.h> // for size_t, read, ssize_t - -char __stdin_buffer[BUFSIZ]; - -size_t fread(void *restrict ptr, size_t size, size_t nitems, - FILE *restrict stream) +size_t fread(void *restrict ptr, size_t size, size_t nitems, FILE *restrict stream) { - if (size == 0 || nitems == 0) - return 0; - - size_t total = size * nitems; - size_t bytes_read = 0; - char *p = ptr; - - LIBC_LOCK(__FILE(stream)->lock); - - while (total > 0) { - if (__FILE(stream)->buf_pos < __FILE(stream)->buf_len) { - size_t available = __FILE(stream)->buf_len - - __FILE(stream)->buf_pos; - size_t to_copy = total < available ? total : available; - - memcpy(p, __FILE(stream)->buf + __FILE(stream)->buf_pos, - to_copy); - __FILE(stream)->buf_pos += to_copy; - p += to_copy; - bytes_read += to_copy; - total -= to_copy; - continue; - } - - ssize_t ret = read(__FILE(stream)->fd, __FILE(stream)->buf, - __FILE(stream)->buf_size); - if (ret <= 0) { - if (ret < 0) - __FILE(stream)->flags |= _IO_ERR; - else - __FILE(stream)->flags |= _IO_EOF; - break; - } - - __FILE(stream)->buf_len = ret; - __FILE(stream)->buf_pos = 0; - } + size_t r; - LIBC_UNLOCK(__FILE(stream)->lock); + flockfile(stream); + r = fread_unlocked(ptr, size, nitems, stream); + funlockfile(stream); - return bytes_read / size; + return r; } diff --git a/lib/libc/stdio/fread_unlocked.c b/lib/libc/stdio/fread_unlocked.c new file mode 100644 index 00000000..4251a7ed --- /dev/null +++ b/lib/libc/stdio/fread_unlocked.c @@ -0,0 +1,47 @@ +#include "__stdio.h" // for __FILE, _IO_EOF, _IO_ERR + +#include <atomic.h> +#include <stdio.h> +#include <string.h> +#include <unistd.h> + +extern void __libc_init_io(void); +void *__libc_force_io_init = (void *)__libc_init_io; + +size_t fread_unlocked(void *restrict ptr, size_t size, size_t nitems, FILE *restrict stream) +{ + if (size == 0 || nitems == 0) + return 0; + + size_t total = size * nitems; + size_t bytes_read = 0; + char *p = ptr; + + while (total > 0) { + if (stream->buf_pos < stream->buf_len) { + size_t available = stream->buf_len - stream->buf_pos; + size_t to_copy = total < available ? total : available; + + memcpy(p, stream->buf + stream->buf_pos, to_copy); + stream->buf_pos += to_copy; + p += to_copy; + bytes_read += to_copy; + total -= to_copy; + continue; + } + + ssize_t ret = read(stream->fd, stream->buf, stream->buf_size); + if (ret <= 0) { + if (ret < 0) + stream->flags |= _IO_ERR; + else + stream->flags |= _IO_EOF; + break; + } + + stream->buf_len = ret; + stream->buf_pos = 0; + } + + return bytes_read / size; +} diff --git a/lib/libc/stdio/fseek.c b/lib/libc/stdio/fseek.c index 7a6754f7..19459e7f 100644 --- a/lib/libc/stdio/fseek.c +++ b/lib/libc/stdio/fseek.c @@ -7,24 +7,21 @@ int fseek(FILE *stream, long offset, int whence) { - if (stream == NULL || __FILE(stream)->fd < 0) + if (stream == NULL || stream->fd < 0) return -1; - LIBC_LOCK(__FILE(stream)->lock); + stream->buf_pos = 0; + stream->buf_len = 0; + stream->flags &= ~_IO_EOF; - __FILE(stream)->buf_pos = 0; - __FILE(stream)->buf_len = 0; - __FILE(stream)->flags &= ~_IO_EOF; - - off_t result = lseek(__FILE(stream)->fd, offset, whence); - - LIBC_UNLOCK(__FILE(stream)->lock); + off_t result = lseek(stream->fd, offset, whence); if (result == (off_t)-1) { - __FILE(stream)->flags |= _IO_ERR; + stream->flags |= _IO_ERR; return -1; } - __FILE(stream)->offset = result; + stream->offset = result; + return 0; } diff --git a/lib/libc/stdio/ftrylockfile.c b/lib/libc/stdio/ftrylockfile.c new file mode 100644 index 00000000..b8f89e4b --- /dev/null +++ b/lib/libc/stdio/ftrylockfile.c @@ -0,0 +1,11 @@ +#include <__stdio.h> +#include <atomic.h> +#include <stdio.h> + +int ftrylockfile(FILE *file) +{ + if (file == NULL) + return -1; + + return atomic_flag_test_and_set_explicit(&file->lock, memory_order_acquire) ? 1 : 0; +} diff --git a/lib/libc/stdio/funlockfile.c b/lib/libc/stdio/funlockfile.c new file mode 100644 index 00000000..9d4154c7 --- /dev/null +++ b/lib/libc/stdio/funlockfile.c @@ -0,0 +1,8 @@ +#include <__stdio.h> +#include <atomic.h> +#include <stdio.h> + +void funlockfile(FILE *file) +{ + LIBC_UNLOCK(file->lock); +} diff --git a/lib/libc/stdio/fwrite.c b/lib/libc/stdio/fwrite.c index c21054da..8d81c7ac 100644 --- a/lib/libc/stdio/fwrite.c +++ b/lib/libc/stdio/fwrite.c @@ -1,134 +1,12 @@ -#include "__stdio.h" // for __FILE, _IO_ERR -#include "stddef.h" // for NULL +#include <stdio.h> -#include <atomic.h> // for LIBC_UNLOCK, LIBC_LOCK -#include <errno.h> // for errno, EOVERFLOW, EBADF, EINVAL, EIO -#include <fcntl.h> // for O_ACCMODE, O_RDONLY -#include <stdio.h> // for fflush, fwrite, BUFSIZ, FILE, _IOFBF, _IOLBF -#include <string.h> // for memcpy, memchr -#include <unistd.h> // for size_t, ssize_t, write - -char __stdout_buffer[BUFSIZ]; -void (*__stdio_cleanup)(void); - -size_t fwrite(const void *restrict ptr, size_t size, size_t nitems, - FILE *restrict stream) +size_t fwrite(const void *restrict ptr, size_t size, size_t nitems, FILE *restrict stream) { - size_t total_bytes; - size_t written = 0; - const char *data = (const char *)ptr; - - if (ptr == NULL || stream == NULL || size == 0) { - if (size == 0) { - return nitems; - } - errno = EINVAL; - return 0; - } - - if (__FILE(stream)->fd == -1 && __FILE(stream)->buf != NULL) { - if (__builtin_mul_overflow(size, nitems, &total_bytes)) { - errno = EOVERFLOW; - return 0; - } - - size_t space_left = - __FILE(stream)->buf_size > __FILE(stream)->buf_len ? - __FILE(stream)->buf_size - - __FILE(stream)->buf_len - 1 : - 0; - - if (space_left == 0) { - return 0; - } - - size_t to_copy = total_bytes < space_left ? total_bytes : - space_left; - - if (to_copy > 0) { - memcpy(__FILE(stream)->buf + __FILE(stream)->buf_len, - data, to_copy); - __FILE(stream)->buf_len += to_copy; - } - - return to_copy == total_bytes ? nitems : to_copy / size; - } - - if (__builtin_mul_overflow(size, nitems, &total_bytes)) { - errno = EOVERFLOW; - return 0; - } - - if ((__FILE(stream)->flags & O_ACCMODE) == O_RDONLY) { - errno = EBADF; - return 0; - } - - if (__FILE(stream)->flags & _IO_ERR) { - errno = EIO; - return 0; - } - - LIBC_LOCK(__FILE(stream)->lock); - - if (__FILE(stream)->type == _IONBF) { - ssize_t result = write(__FILE(stream)->fd, data, total_bytes); - LIBC_UNLOCK(__FILE(stream)->lock); - - if (result < 0) { - __FILE(stream)->flags |= _IO_ERR; - return 0; - } - - return result == (ssize_t)total_bytes ? nitems : result / size; - } - - size_t remaining = total_bytes; - - while (remaining > 0) { - size_t space_available = - __FILE(stream)->buf_size - __FILE(stream)->buf_len; - - if (space_available == 0) { - LIBC_UNLOCK(__FILE(stream)->lock); - if (fflush(stream) != 0) { - return written / size; - } - space_available = __FILE(stream)->buf_size; - } - - size_t to_copy = remaining < space_available ? remaining : - space_available; - - memcpy(__FILE(stream)->buf + __FILE(stream)->buf_len, - data + written, to_copy); - __FILE(stream)->buf_len += to_copy; - written += to_copy; - remaining -= to_copy; - - if (__FILE(stream)->type == _IOLBF) { - char *newline_pos = memchr( - __FILE(stream)->buf + __FILE(stream)->buf_len - - to_copy, - '\n', to_copy); - if (newline_pos != NULL) { - LIBC_UNLOCK(__FILE(stream)->lock); - if (fflush(stream) != 0) { - return written / size; - } - } - } - - else if (__FILE(stream)->type == _IOFBF && - __FILE(stream)->buf_len == __FILE(stream)->buf_size) { - LIBC_UNLOCK(__FILE(stream)->lock); - if (fflush(stream) != 0) { - return written / size; - } - } - } + size_t r; - LIBC_UNLOCK(__FILE(stream)->lock); + flockfile(stream); + r = fwrite_unlocked(ptr, size, nitems, stream); + funlockfile(stream); - return written == total_bytes ? nitems : written / size; + return r; } diff --git a/lib/libc/stdio/fwrite_unlocked.c b/lib/libc/stdio/fwrite_unlocked.c new file mode 100644 index 00000000..dd5f4c0b --- /dev/null +++ b/lib/libc/stdio/fwrite_unlocked.c @@ -0,0 +1,106 @@ +#include "__stdio.h" +#include <atomic.h> +#include <errno.h> +#include <fcntl.h> +#include <stddef.h> +#include <stdio.h> +#include <string.h> +#include <unistd.h> + +extern void __libc_init_io(void); +void *__libc_force_io_init = (void *)__libc_init_io; + +size_t fwrite_unlocked(const void *restrict ptr, size_t size, size_t nitems, FILE *restrict stream) +{ + size_t total_bytes; + size_t written = 0; + const char *data = (const char *)ptr; + + if (ptr == NULL || stream == NULL || size == 0) { + if (size == 0) { + return nitems; + } + errno = EINVAL; + return 0; + } + + if (__builtin_mul_overflow(size, nitems, &total_bytes)) { + errno = EOVERFLOW; + return 0; + } + + if ((stream->flags & O_ACCMODE) == O_RDONLY) { + errno = EBADF; + return 0; + } + + if (stream->flags & _IO_ERR) { + errno = EIO; + return 0; + } + + /* Handle in-memory buffer case (e.g., string streams) */ + if (stream->fd == -1 && stream->buf != NULL) { + size_t space_left = (stream->buf_size > stream->buf_len) ? + stream->buf_size - stream->buf_len - 1 /* Reserve for '\0' */ + : + 0; + if (space_left == 0) { + return 0; + } + size_t to_copy = (total_bytes < space_left) ? total_bytes : space_left; + if (to_copy > 0) { + memcpy(stream->buf + stream->buf_len, data, to_copy); + stream->buf_len += to_copy; + } + return (to_copy == total_bytes) ? nitems : to_copy / size; + } + + if (stream->type != _IONBF && stream->buf == NULL) { + errno = EIO; + return 0; + } + + /* Unbuffered mode: direct write */ + if (stream->type == _IONBF) { + ssize_t result = write(stream->fd, data, total_bytes); + if (result < 0) { + stream->flags |= _IO_ERR; + return 0; + } + return (result == (ssize_t)total_bytes) ? nitems : result / size; + } + + size_t remaining = total_bytes; + while (remaining > 0) { + size_t space_available = stream->buf_size - stream->buf_len; + if (space_available == 0) { + if (fflush_unlocked(stream) != 0) { + return written / size; + } + space_available = stream->buf_size; + } + size_t to_copy = (remaining < space_available) ? remaining : space_available; + memcpy(stream->buf + stream->buf_len, data + written, to_copy); + stream->buf_len += to_copy; + written += to_copy; + remaining -= to_copy; + + /* Line-buffered: flush on newline in the copied chunk */ + if (stream->type == _IOLBF) { + char *newline_pos = memchr(stream->buf + stream->buf_len - to_copy, '\n', to_copy); + if (newline_pos != NULL) { + if (fflush_unlocked(stream) != 0) { + return written / size; + } + } + } else if (stream->type == _IOFBF && stream->buf_len == stream->buf_size) { + /* Full-buffered: flush when buffer is full */ + if (fflush_unlocked(stream) != 0) { + return written / size; + } + } + } + + return (written == total_bytes) ? nitems : written / size; +} diff --git a/lib/libc/stdio/getc.c b/lib/libc/stdio/getc.c index 242c8396..2f59ba5c 100644 --- a/lib/libc/stdio/getc.c +++ b/lib/libc/stdio/getc.c @@ -1,9 +1,12 @@ -#include <libc.h> // for weak_reference -#include <stdio.h> // for fgetc, FILE, getc, getc_unlocked +#include <stdio.h> int getc(FILE *stream) { - return fgetc(stream); -} + int r; + + flockfile(stream); + r = getc_unlocked(stream); + funlockfile(stream); -weak_reference(getc, getc_unlocked); + return r; +} diff --git a/lib/libc/stdio/getc_unlocked.c b/lib/libc/stdio/getc_unlocked.c new file mode 100644 index 00000000..1fc46d0a --- /dev/null +++ b/lib/libc/stdio/getc_unlocked.c @@ -0,0 +1,6 @@ +#include <stdio.h> + +int getc_unlocked(FILE *stream) +{ + return fgetc_unlocked(stream); +} diff --git a/lib/libc/stdio/getchar.c b/lib/libc/stdio/getchar.c index d26c3c6b..d5e08cd1 100644 --- a/lib/libc/stdio/getchar.c +++ b/lib/libc/stdio/getchar.c @@ -1,9 +1,12 @@ -#include <libc.h> // for weak_reference -#include <stdio.h> // for fgetc, getchar, getchar_unlocked, stdin +#include <stdio.h> int getchar(void) { - return fgetc(stdin); -} + int r; + + flockfile(stdin); + r = getchar_unlocked(); + funlockfile(stdin); -weak_reference(getchar, getchar_unlocked); + return r; +} diff --git a/lib/libc/stdio/getchar_unlocked.c b/lib/libc/stdio/getchar_unlocked.c new file mode 100644 index 00000000..e7b2fed2 --- /dev/null +++ b/lib/libc/stdio/getchar_unlocked.c @@ -0,0 +1,6 @@ +#include <stdio.h> + +int getchar_unlocked(void) +{ + return fgetc_unlocked(stdin); +} diff --git a/lib/libc/stdio/pclose.c b/lib/libc/stdio/pclose.c index a515981c..1967b2c8 100644 --- a/lib/libc/stdio/pclose.c +++ b/lib/libc/stdio/pclose.c @@ -6,5 +6,5 @@ int pclose(FILE *stream) { int stat; fclose(stream); - return (waitpid(__FILE(stream)->pid, &stat, 0) < 0) ? -1 : stat; + return (waitpid(stream->pid, &stat, 0) < 0) ? -1 : stat; } diff --git a/lib/libc/stdio/popen.c b/lib/libc/stdio/popen.c index 1fd5f991..5720fba3 100644 --- a/lib/libc/stdio/popen.c +++ b/lib/libc/stdio/popen.c @@ -62,7 +62,7 @@ FILE *popen(const char *command, const char *mode) close(pipefd[0]); } - __FILE(stream)->pid = pid; + stream->pid = pid; return stream; } diff --git a/lib/libc/stdio/putchar.c b/lib/libc/stdio/putchar.c index c9e3ba08..c0673473 100644 --- a/lib/libc/stdio/putchar.c +++ b/lib/libc/stdio/putchar.c @@ -1,9 +1,12 @@ -#include <libc.h> // for weak_reference -#include <stdio.h> // for putc, putchar, putchar_unlocked, stdout +#include <stdio.h> int putchar(int c) { - return putc(c, stdout); -} + int r; + + flockfile(stdout); + r = putchar_unlocked(c); + funlockfile(stdout); -weak_reference(putchar, putchar_unlocked); + return r; +} diff --git a/lib/libc/stdio/putchar_unlocked.c b/lib/libc/stdio/putchar_unlocked.c new file mode 100644 index 00000000..a8a5fc47 --- /dev/null +++ b/lib/libc/stdio/putchar_unlocked.c @@ -0,0 +1,6 @@ +#include <stdio.h> + +int putchar_unlocked(int c) +{ + return fputc_unlocked(c, stdout); +} diff --git a/lib/libc/stdio/setvbuf.c b/lib/libc/stdio/setvbuf.c index 686640f4..d6b41d31 100644 --- a/lib/libc/stdio/setvbuf.c +++ b/lib/libc/stdio/setvbuf.c @@ -10,13 +10,13 @@ int setvbuf(FILE *restrict stream, char *restrict buf, int type, size_t size) if (type != _IONBF && (buf == NULL || size == 0)) return -1; - if (__FILE(stream)->fd < 0) + if (stream->fd < 0) return -1; - __FILE(stream)->buf = buf; - __FILE(stream)->buf_size = size; - __FILE(stream)->buf_pos = 0; - __FILE(stream)->type = type; + stream->buf = buf; + stream->buf_size = size; + stream->buf_pos = 0; + stream->type = type; return 0; } diff --git a/lib/libc/stdio/stderr.c b/lib/libc/stdio/stderr.c deleted file mode 100644 index ec115fd0..00000000 --- a/lib/libc/stdio/stderr.c +++ /dev/null @@ -1,23 +0,0 @@ -#include "__stdio.h" // for __FILE -#include "stdatomic.h" // for ATOMIC_FLAG_INIT - -#include <fcntl.h> // for O_WRONLY -#include <stdio.h> // for FILE, stderr -#include <unistd.h> // for STDERR_FILENO - -#define BUFSIZ 4096 - -struct __FILE __stderr = { .fd = STDERR_FILENO, - .flags = O_WRONLY, - .type = 0, - .buf = 0, - .buf_len = 0, - .buf_size = 0, - .buf_pos = 0, - .eof = 0, - .unget_cnt = 0, - .next = 0, - .offset = 0, - .lock = ATOMIC_FLAG_INIT }; - -FILE *const stderr = (FILE *)&__stderr; diff --git a/lib/libc/stdio/stdin.c b/lib/libc/stdio/stdin.c deleted file mode 100644 index 0d127efa..00000000 --- a/lib/libc/stdio/stdin.c +++ /dev/null @@ -1,19 +0,0 @@ -#include "__stdio.h" // for __FILE - -#include <fcntl.h> // for O_RDONLY -#include <stdio.h> // for FILE, stdin -#include <sys/cdefs.h> -#include <unistd.h> // for STDOUT_FILENO - -#define BUFSIZ 4096 - -__weak char __stdin_buffer[0]; -struct __FILE __stdin = { .fd = STDOUT_FILENO, - .flags = O_RDONLY, - .buf = __stdin_buffer, - .type = 0x0, - .buf_size = BUFSIZ, - .buf_pos = 0, - .offset = 0 }; - -FILE *const stdin = (FILE *)&__stdin; diff --git a/lib/libc/stdio/stdout.c b/lib/libc/stdio/stdout.c deleted file mode 100644 index 471a54b9..00000000 --- a/lib/libc/stdio/stdout.c +++ /dev/null @@ -1,37 +0,0 @@ -#include "__stdio.h" // for __FILE, __libc_fadd - -#include <atomic.h> // for LIBC_LOCK, LIBC_UNLOCK -#include <fcntl.h> // for O_WRONLY -#include <stddef.h> // for NULL -#include <stdio.h> // for stdout -#include <sys/cdefs.h> -#include <unistd.h> // for STDOUT_FILENO - -#define BUFSIZ 4096 - -__weak char __stdout_buffer[0]; -static atomic_flag __stdio_lock = ATOMIC_FLAG_INIT; -struct __FILE __stdout = { .fd = STDOUT_FILENO, - .flags = O_WRONLY, - .type = 1, - .buf = __stdout_buffer, - .buf_len = 0, - .buf_size = BUFSIZ, - .buf_pos = 0, - .eof = 0, - .unget_cnt = 0, - .offset = 0, - .next = NULL, - .lock = ATOMIC_FLAG_INIT }; - -struct __FILE *const stdout = (struct __FILE *)&__stdout; - -void __libc_fadd(struct __FILE *f) -{ - LIBC_LOCK(__stdio_lock); - struct __FILE *cur = &__stdout; - while (cur->next) - cur = cur->next; - cur->next = f; - LIBC_UNLOCK(__stdio_lock); -} diff --git a/lib/libc/stdio/vfprintf.c b/lib/libc/stdio/vfprintf.c index 06609046..4dc1a4d2 100644 --- a/lib/libc/stdio/vfprintf.c +++ b/lib/libc/stdio/vfprintf.c @@ -1,13 +1,13 @@ -#include <ctype.h> // for isdigit -#include <errno.h> // for EINVAL, errno -#include <math.h> // for isinf, isnan -#include <stdarg.h> // for va_arg -#include <stddef.h> // for NULL, ptrdiff_t +#include <ctype.h> +#include <errno.h> +#include <math.h> +#include <stdarg.h> +#include <stddef.h> #include <stdint.h> -#include <stdint.h> // for uintptr_t, intmax_t, uintmax_t -#include <stdio.h> // for fwrite, fputc, vfprintf, FILE, va_list -#include <string.h> // for memmove, strlcpy, strlen -#include <sys/types.h> // for size_t, ssize_t +#include <stdint.h> +#include <stdio.h> +#include <string.h> +#include <sys/types.h> static double __frexp(double x, int *e) { @@ -35,8 +35,7 @@ static double __frexp(double x, int *e) return y.d; } -extern char *dtoa(double, int mode, int ndigits, int *decpt, int *sign, - char **rve); +extern char *dtoa(double, int mode, int ndigits, int *decpt, int *sign, char **rve); extern void freedtoa(char *s); static int utoa_base(unsigned long long v, char *s, int b, int p, int u) @@ -65,12 +64,14 @@ int vfprintf(FILE *restrict stream, const char *restrict format, va_list ap) const char *ptr; int total_printed; + flockfile(stream); + ptr = format; total_printed = 0; while (*ptr != '\0') { if (*ptr != '%') { - fputc(*ptr, stream); + fputc_unlocked(*ptr, stream); total_printed++; ptr++; } else { @@ -104,8 +105,7 @@ int vfprintf(FILE *restrict stream, const char *restrict format, va_list ap) LENGTH_CAPL } length = LENGTH_NONE; - while (*ptr == '-' || *ptr == '+' || *ptr == ' ' || - *ptr == '0' || *ptr == '#') { + while (*ptr == '-' || *ptr == '+' || *ptr == ' ' || *ptr == '0' || *ptr == '#') { if (*ptr == '-') flags |= FLAG_MINUS; else if (*ptr == '+') @@ -143,8 +143,7 @@ int vfprintf(FILE *restrict stream, const char *restrict format, va_list ap) } else { precision = 0; while (isdigit(*ptr)) { - precision = precision * 10 + - (*ptr - '0'); + precision = precision * 10 + (*ptr - '0'); ptr++; } } @@ -196,7 +195,7 @@ int vfprintf(FILE *restrict stream, const char *restrict format, va_list ap) val = va_arg(ap, int); break; case LENGTH_HH: - val = (signed char)va_arg(ap, int); + val = (unsigned char)va_arg(ap, int); break; case LENGTH_H: val = (short)va_arg(ap, int); @@ -218,6 +217,7 @@ int vfprintf(FILE *restrict stream, const char *restrict format, va_list ap) break; case LENGTH_CAPL: errno = EINVAL; + funlockfile(stream); return -1; } @@ -261,12 +261,10 @@ int vfprintf(FILE *restrict stream, const char *restrict format, va_list ap) val = va_arg(ap, unsigned int); break; case LENGTH_HH: - val = (unsigned char)va_arg( - ap, unsigned int); + val = (unsigned char)va_arg(ap, unsigned int); break; case LENGTH_H: - val = (unsigned short)va_arg( - ap, unsigned int); + val = (unsigned short)va_arg(ap, unsigned int); break; case LENGTH_L: val = va_arg(ap, unsigned long); @@ -285,24 +283,20 @@ int vfprintf(FILE *restrict stream, const char *restrict format, va_list ap) break; case LENGTH_CAPL: errno = EINVAL; + funlockfile(stream); return -1; } if (fmt_char == 'o') { - l = utoa_base(val, buf, 8, precision, - 0); + l = utoa_base(val, buf, 8, precision, 0); } else if (fmt_char == 'u') { - l = utoa_base(val, buf, 10, precision, - 0); + l = utoa_base(val, buf, 10, precision, 0); } else if (fmt_char == 'x') { - l = utoa_base(val, buf, 16, precision, - 0); + l = utoa_base(val, buf, 16, precision, 0); } else if (fmt_char == 'X') { - l = utoa_base(val, buf, 16, precision, - 1); + l = utoa_base(val, buf, 16, precision, 1); } else { - l = utoa_base(val, buf, 10, precision, - 0); + l = utoa_base(val, buf, 10, precision, 0); } s = buf; @@ -350,11 +344,7 @@ int vfprintf(FILE *restrict stream, const char *restrict format, va_list ap) int pos = 0; if (isnan(val)) { - strlcpy(buf, - (*ptr == 'F' || *ptr == 'E' || - *ptr == 'G') ? - "NAN" : - "nan", + strlcpy(buf, (*ptr == 'F' || *ptr == 'E' || *ptr == 'G') ? "NAN" : "nan", sizeof(buf)); l = 3; break; @@ -367,11 +357,7 @@ int vfprintf(FILE *restrict stream, const char *restrict format, va_list ap) } else if (flags & FLAG_SPACE) { buf[pos++] = ' '; } - strlcpy(buf + pos, - (*ptr == 'F' || *ptr == 'E' || - *ptr == 'G') ? - "INF" : - "inf", + strlcpy(buf + pos, (*ptr == 'F' || *ptr == 'E' || *ptr == 'G') ? "INF" : "inf", sizeof(buf) - pos); l = pos + 3; break; @@ -391,58 +377,40 @@ int vfprintf(FILE *restrict stream, const char *restrict format, va_list ap) case 'F': { int decpt, sign; char *rve; - char *digits = dtoa(val, 3, precision, - &decpt, &sign, - &rve); + char *digits = dtoa(val, 3, precision, &decpt, &sign, &rve); if (sign && val != 0.0) { buf[pos++] = '-'; } - if (decpt <= 1 && digits[0] == '0' && - digits[1] == '\0') { + if (decpt <= 1 && digits[0] == '0' && digits[1] == '\0') { buf[pos++] = '0'; if (precision > 0) { buf[pos++] = '.'; - for (int i = 0; - i < precision; - i++) { - buf[pos++] = - '0'; + for (int i = 0; i < precision; i++) { + buf[pos++] = '0'; } } } else if (decpt <= 0) { buf[pos++] = '0'; if (precision > 0) { buf[pos++] = '.'; - for (int i = 0; - i < -decpt && - i < precision; - i++) { - buf[pos++] = - '0'; + for (int i = 0; i < -decpt && i < precision; i++) { + buf[pos++] = '0'; } - int remaining = - precision + - decpt; + int remaining = precision + decpt; char *d = digits; - while (*d && - remaining-- > - 0) { - buf[pos++] = - *d++; + while (*d && remaining-- > 0) { + buf[pos++] = *d++; } - while (remaining-- > - 0) { - buf[pos++] = - '0'; + while (remaining-- > 0) { + buf[pos++] = '0'; } } } else { char *d = digits; int digits_used = 0; - for (int i = 0; i < decpt && *d; - i++) { + for (int i = 0; i < decpt && *d; i++) { buf[pos++] = *d++; digits_used++; } @@ -452,15 +420,11 @@ int vfprintf(FILE *restrict stream, const char *restrict format, va_list ap) } if (precision > 0) { buf[pos++] = '.'; - for (int i = 0; - i < precision; - i++) { + for (int i = 0; i < precision; i++) { if (*d) { - buf[pos++] = - *d++; + buf[pos++] = *d++; } else { - buf[pos++] = - '0'; + buf[pos++] = '0'; } } } @@ -475,9 +439,7 @@ int vfprintf(FILE *restrict stream, const char *restrict format, va_list ap) case 'E': { int decpt, sign; char *rve; - char *digits = - dtoa(val, 2, precision + 1, - &decpt, &sign, &rve); + char *digits = dtoa(val, 2, precision + 1, &decpt, &sign, &rve); if (sign && val != 0.0) { buf[pos++] = '-'; @@ -491,14 +453,11 @@ int vfprintf(FILE *restrict stream, const char *restrict format, va_list ap) if (precision > 0) { buf[pos++] = '.'; - for (int i = 0; i < precision; - i++) { + for (int i = 0; i < precision; i++) { if (*digits) { - buf[pos++] = - *digits++; + buf[pos++] = *digits++; } else { - buf[pos++] = - '0'; + buf[pos++] = '0'; } } } @@ -510,8 +469,7 @@ int vfprintf(FILE *restrict stream, const char *restrict format, va_list ap) exp = -exp; if (exp < 10) buf[pos++] = '0'; - pos += utoa_base(exp, buf + pos, 10, 0, - 0); + pos += utoa_base(exp, buf + pos, 10, 0, 0); buf[pos] = '\0'; l = pos; @@ -522,9 +480,7 @@ int vfprintf(FILE *restrict stream, const char *restrict format, va_list ap) case 'G': { int decpt, sign; char *rve; - char *digits = dtoa(val, 2, precision, - &decpt, &sign, - &rve); + char *digits = dtoa(val, 2, precision, &decpt, &sign, &rve); if (sign && val != 0.0) { buf[pos++] = '-'; @@ -538,63 +494,44 @@ int vfprintf(FILE *restrict stream, const char *restrict format, va_list ap) if (*digits) { buf[pos++] = '.'; while (*digits) { - buf[pos++] = - *digits++; + buf[pos++] = *digits++; } } - buf[pos++] = (*ptr == 'G') ? - 'E' : - 'e'; - buf[pos++] = (exp >= 0) ? '+' : - '-'; + buf[pos++] = (*ptr == 'G') ? 'E' : 'e'; + buf[pos++] = (exp >= 0) ? '+' : '-'; if (exp < 0) exp = -exp; if (exp < 10) buf[pos++] = '0'; - pos += utoa_base(exp, buf + pos, - 10, 0, 0); + pos += utoa_base(exp, buf + pos, 10, 0, 0); } else { if (decpt <= 0) { buf[pos++] = '0'; - if (*digits && - *digits != '0') { - buf[pos++] = - '.'; - for (int i = 0; - i < -decpt; - i++) { - buf[pos++] = - '0'; + if (*digits && *digits != '0') { + buf[pos++] = '.'; + for (int i = 0; i < -decpt; i++) { + buf[pos++] = '0'; } - char *d = - digits; - while (*d && - *d != '0') { - buf[pos++] = - *d++; + char *d = digits; + while (*d && *d != '0') { + buf[pos++] = *d++; } } } else { char *d = digits; - for (int i = 0; - i < decpt && *d; - i++) { - buf[pos++] = - *d++; + for (int i = 0; i < decpt && *d; i++) { + buf[pos++] = *d++; } if (*d) { - buf[pos++] = - '.'; + buf[pos++] = '.'; while (*d) { - buf[pos++] = - *d++; + buf[pos++] = *d++; } } } } - while (pos > 1 && buf[pos - 1] == '0' && - pos > 2 && buf[pos - 2] != 'e' && + while (pos > 1 && buf[pos - 1] == '0' && pos > 2 && buf[pos - 2] != 'e' && buf[pos - 2] != 'E') { pos--; } @@ -634,9 +571,7 @@ int vfprintf(FILE *restrict stream, const char *restrict format, va_list ap) } if (val == 0.0) { - strlcpy(buf + pos, - upper ? "0X0P+0" : "0x0p+0", - sizeof(buf) - pos); + strlcpy(buf + pos, upper ? "0X0P+0" : "0x0p+0", sizeof(buf) - pos); l = pos + 6; break; } @@ -662,15 +597,9 @@ int vfprintf(FILE *restrict stream, const char *restrict format, va_list ap) int digit = (int)mant; if (digit > 15) digit = 15; - buf[pos++] = - (digit < 10) ? - ('0' + digit) : - (upper ? ('A' + - digit - - 10) : - ('a' + - digit - - 10)); + buf[pos++] = (digit < 10) ? + ('0' + digit) : + (upper ? ('A' + digit - 10) : ('a' + digit - 10)); mant -= digit; } @@ -728,9 +657,7 @@ int vfprintf(FILE *restrict stream, const char *restrict format, va_list ap) case 'p': { void *ptr_val = va_arg(ap, void *); uintptr_t uptr = (uintptr_t)ptr_val; - int len = utoa_base((unsigned long long)uptr, - buf + 2, 16, - sizeof(void *) * 2, 0); + int len = utoa_base((unsigned long long)uptr, buf + 2, 16, sizeof(void *) * 2, 0); buf[0] = '0'; buf[1] = 'x'; buf[len + 2] = '\0'; @@ -755,6 +682,7 @@ int vfprintf(FILE *restrict stream, const char *restrict format, va_list ap) } default: errno = EINVAL; + funlockfile(stream); return -1; } @@ -767,46 +695,39 @@ int vfprintf(FILE *restrict stream, const char *restrict format, va_list ap) char format_char = *(ptr - 1); char pad_char = ' '; if ((flags & FLAG_ZERO) && !(flags & FLAG_MINUS) && - (format_char == 'd' || format_char == 'i' || - format_char == 'u' || format_char == 'o' || - format_char == 'x' || format_char == 'X' || - format_char == 'f' || format_char == 'F' || - format_char == 'e' || format_char == 'E' || - format_char == 'g' || format_char == 'G') && + (format_char == 'd' || format_char == 'i' || format_char == 'u' || format_char == 'o' || + format_char == 'x' || format_char == 'X' || format_char == 'f' || format_char == 'F' || + format_char == 'e' || format_char == 'E' || format_char == 'g' || format_char == 'G') && precision < 0) { pad_char = '0'; } if ((flags & FLAG_MINUS) == 0) { if (pad_char == '0' && s != NULL) { - if (s[0] == '-' || s[0] == '+' || - s[0] == ' ') { - fwrite(s, 1, 1, stream); + if (s[0] == '-' || s[0] == '+' || s[0] == ' ') { + fwrite_unlocked(s, 1, 1, stream); total_printed++; s++; l--; } - if (l >= 2 && s[0] == '0' && - (s[1] == 'x' || s[1] == 'X')) { - fwrite(s, 1, 2, stream); + if (l >= 2 && s[0] == '0' && (s[1] == 'x' || s[1] == 'X')) { + fwrite_unlocked(s, 1, 2, stream); total_printed += 2; s += 2; l -= 2; } for (int i = 0; i < padding; i++) { - fwrite("0", 1, 1, stream); + fwrite_unlocked("0", 1, 1, stream); total_printed++; } } else { for (int i = 0; i < padding; i++) { if (pad_char == '0') { - fwrite("0", 1, 1, - stream); + fwrite_unlocked("0", 1, 1, stream); } else { - fwrite(" ", 1, 1, - stream); + fwrite_unlocked(" ", 1, 1, stream); } total_printed++; } @@ -815,18 +736,20 @@ int vfprintf(FILE *restrict stream, const char *restrict format, va_list ap) if (l > 0) { if (s != NULL) - fwrite(s, 1, l, stream); + fwrite_unlocked(s, 1, l, stream); total_printed += l; } if (flags & FLAG_MINUS) { for (int i = 0; i < padding; i++) { - fwrite(" ", 1, 1, stream); + fwrite_unlocked(" ", 1, 1, stream); total_printed++; } } } } + funlockfile(stream); + return total_printed; } diff --git a/lib/libc/stdlib/exit.c b/lib/libc/stdlib/exit.c index 7fc96f28..80054637 100644 --- a/lib/libc/stdlib/exit.c +++ b/lib/libc/stdlib/exit.c @@ -1,65 +1,14 @@ -#include "__stdio.h" // for __FILE -#include "stddef.h" // for NULL - #include <libc.h> // for weak_reference -#include <stdio.h> // for fflush, stdout, FILE, stderr, stdin #include <stdlib.h> // for free, exit #include <unistd.h> // for _exit, close, write, STDERR_FILENO void (*__dummy_atexit_fvec)(void); weak_reference(__dummy_atexit_fvec, __atexit_fvec); -void (*__dummy_stdio_cleanup)(void); -weak_reference(__dummy_stdio_cleanup, __stdio_cleanup); - -static void __fclose(FILE *stream) -{ - if (stream == NULL) { - return; - } - - if (__FILE(stream)->buf_len > 0) { - fflush(stream); - } - - if (__FILE(stream)->fd > STDERR_FILENO) { - close(__FILE(stream)->fd); - } - - if (__FILE(stream)->buf) { - free(__FILE(stream)->buf); - } - - if (stream != stdout && stream != stderr && stream != stdin) { - free(stream); - } -} - -static void __stdio_cleanup_impl(void) -{ - write(1, "HELLO\n", 6); - fflush(stdout); - - if (stdout->next != NULL) { - FILE *cur = stdout->next; - while (cur) { - struct __FILE *next = cur->next; - __fclose(cur); - cur = next; - } - } -} - void exit(int status) { void (*fptr)(void); - /* Only do stdio cleanup if it was referenced (meaning stdio was used) - */ - if (__stdio_cleanup) { - __stdio_cleanup_impl(); - } - if (__atexit_fvec) { fptr = __atexit_fvec; while (fptr) { diff --git a/lib/libc/stdlib/strtox.c b/lib/libc/stdlib/strtox.c index b50a77a1..276b8c2e 100644 --- a/lib/libc/stdlib/strtox.c +++ b/lib/libc/stdlib/strtox.c @@ -6,8 +6,7 @@ #include <stdlib.h> // for strtof, strtol, strtold, strtoll, strtoul, strt... #include <strings.h> // for strncasecmp -static unsigned long long -__scanint(const char *s, int base, unsigned long long lim, int *neg, char **end) +static unsigned long long __scanint(const char *s, int base, unsigned long long lim, int *neg, char **end) { unsigned long long res = 0; int digit, any = 0; @@ -21,8 +20,7 @@ __scanint(const char *s, int base, unsigned long long lim, int *neg, char **end) s++; } - if ((base == 0 || base == 16) && s[0] == '0' && - (s[1] == 'x' || s[1] == 'X')) { + if ((base == 0 || base == 16) && s[0] == '0' && (s[1] == 'x' || s[1] == 'X')) { base = 16; s += 2; } else if (base == 0 && *s == '0') { @@ -193,8 +191,7 @@ long long strtoll(const char *restrict nptr, char **restrict endptr, int base) return (long long)v; } -unsigned long strtoul(const char *restrict nptr, char **restrict endptr, - int base) +unsigned long strtoul(const char *restrict nptr, char **restrict endptr, int base) { int neg; unsigned long long v; @@ -214,8 +211,7 @@ unsigned long strtoul(const char *restrict nptr, char **restrict endptr, return (unsigned long)v; } -unsigned long long strtoull(const char *restrict nptr, char **restrict endptr, - int base) +unsigned long long strtoull(const char *restrict nptr, char **restrict endptr, int base) { int neg; unsigned long long v; diff --git a/lib/libc/sys/Kbuild b/lib/libc/sys/Kbuild index a2928e14..78ac7eaa 100644 --- a/lib/libc/sys/Kbuild +++ b/lib/libc/sys/Kbuild @@ -1,6 +1,7 @@ obj-y += eventfd/ obj-y += inotify/ obj-y += io_uring/ +obj-y += mqueue/ obj-y += flock.o obj-y += getauxval.o diff --git a/lib/libc/sys/getauxval.c b/lib/libc/sys/getauxval.c index c9a2bf66..f58aae33 100644 --- a/lib/libc/sys/getauxval.c +++ b/lib/libc/sys/getauxval.c @@ -5,12 +5,12 @@ unsigned long getauxval(unsigned long type) { - size_t *auxv = __libc.auxv; + size_t *p = __libc.auxv; - while (*auxv) { - if (*auxv == type) - return auxv[1]; - auxv += 2; + while (*p != 0) { + if (*p == type) + return p[1]; + p += 2; } errno = ENOENT; diff --git a/lib/libc/mqueue/Kbuild b/lib/libc/sys/mqueue/Kbuild index 52c3dbbc..52c3dbbc 100644 --- a/lib/libc/mqueue/Kbuild +++ b/lib/libc/sys/mqueue/Kbuild diff --git a/lib/libc/mqueue/mq_close.c b/lib/libc/sys/mqueue/mq_close.c index 50877fb1..50877fb1 100644 --- a/lib/libc/mqueue/mq_close.c +++ b/lib/libc/sys/mqueue/mq_close.c diff --git a/lib/libc/mqueue/mq_getattr.c b/lib/libc/sys/mqueue/mq_getattr.c index f5ca62de..f5ca62de 100644 --- a/lib/libc/mqueue/mq_getattr.c +++ b/lib/libc/sys/mqueue/mq_getattr.c diff --git a/lib/libc/mqueue/mq_notify.c b/lib/libc/sys/mqueue/mq_notify.c index 6011f567..6011f567 100644 --- a/lib/libc/mqueue/mq_notify.c +++ b/lib/libc/sys/mqueue/mq_notify.c diff --git a/lib/libc/mqueue/mq_open.c b/lib/libc/sys/mqueue/mq_open.c index 15ae9e18..15ae9e18 100644 --- a/lib/libc/mqueue/mq_open.c +++ b/lib/libc/sys/mqueue/mq_open.c diff --git a/lib/libc/mqueue/mq_receive.c b/lib/libc/sys/mqueue/mq_receive.c index 98d3cd9e..98d3cd9e 100644 --- a/lib/libc/mqueue/mq_receive.c +++ b/lib/libc/sys/mqueue/mq_receive.c diff --git a/lib/libc/mqueue/mq_setattr.c b/lib/libc/sys/mqueue/mq_setattr.c index be2a3b3d..be2a3b3d 100644 --- a/lib/libc/mqueue/mq_setattr.c +++ b/lib/libc/sys/mqueue/mq_setattr.c diff --git a/lib/libc/mqueue/mq_timedreceive.c b/lib/libc/sys/mqueue/mq_timedreceive.c index bf877fa5..bf877fa5 100644 --- a/lib/libc/mqueue/mq_timedreceive.c +++ b/lib/libc/sys/mqueue/mq_timedreceive.c diff --git a/lib/libc/mqueue/mq_timedsend.c b/lib/libc/sys/mqueue/mq_timedsend.c index 228a5d06..228a5d06 100644 --- a/lib/libc/mqueue/mq_timedsend.c +++ b/lib/libc/sys/mqueue/mq_timedsend.c diff --git a/lib/libc/mqueue/mq_unlink.c b/lib/libc/sys/mqueue/mq_unlink.c index da16f030..da16f030 100644 --- a/lib/libc/mqueue/mq_unlink.c +++ b/lib/libc/sys/mqueue/mq_unlink.c diff --git a/lib/libc/thread/Kbuild b/lib/libc/thread/Kbuild index 3e28ece3..b419b566 100644 --- a/lib/libc/thread/Kbuild +++ b/lib/libc/thread/Kbuild @@ -1 +1,4 @@ +obj-y += thrd_create.o obj-y += thrd_current.o +obj-y += thrd_exit.o +obj-y += thrd_join.o diff --git a/lib/libc/thread/thrd_create.c b/lib/libc/thread/thrd_create.c new file mode 100644 index 00000000..e5b7405c --- /dev/null +++ b/lib/libc/thread/thrd_create.c @@ -0,0 +1,113 @@ +#include <__thread.h> +#include <asm/prctl.h> +#include <errno.h> +#include <libc.h> +#include <linux/sched.h> +#include <sched.h> +#include <signal.h> +#include <stdio.h> +#include <sys/mman.h> +#include <syscall.h> +#include <threads.h> +#include <unistd.h> + +struct thread_start { + struct __thread_self *self; + thrd_start_t func; + void *arg; +}; + +static long __thread_start(void *arg) +{ + struct thread_start *ts = (struct thread_start *)arg; + syscall(set_tid_address, &ts->self->tid); + int r = ts->func(ts->arg); + thrd_exit(r); + __builtin_unreachable(); +} + +int thrd_create(thrd_t *thr, thrd_start_t func, void *arg) +{ + struct thread_start *ts; + + if ((void *)thr == NULL || func == NULL) + return thrd_error; + + /* Ensure callers never observe an uninitialized thread handle on failure. */ + *thr = NULL; + + void *map; + size_t size = THREAD_GUARD_SIZE + THREAD_STACK_SIZE + __libc.tls.size + sizeof(struct __thread_self); + map = mmap(NULL, size, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); + + if (__predict_false(map == MAP_FAILED)) + return thrd_nomem; + + if (__predict_false(mprotect((unsigned char *)map + THREAD_GUARD_SIZE, size - THREAD_GUARD_SIZE, + PROT_READ | PROT_WRITE) < 0)) { + munmap(map, size); + return thrd_error; + } + + unsigned char *base = (unsigned char *)map; + + /* Place TCB at the very end of the mapping. */ + struct __thread_self *tcb = (struct __thread_self *)(base + size - sizeof(struct __thread_self)); + + /* Place TLS immediately below the TCB, aligned down. */ + unsigned char *tls_end = (unsigned char *)tcb; + + size_t tls_align = __libc.tls.align; + if (tls_align == 0 || (tls_align & (tls_align - 1)) != 0) + tls_align = sizeof(void *); + if (tls_align < sizeof(void *)) + tls_align = sizeof(void *); + + unsigned char *tls_start = + (unsigned char *)(((uintptr_t)(tls_end - __libc.tls.size)) & ~((uintptr_t)tls_align - 1)); + + __libc_tls_copy(tls_start); + + /* Build initial stack just below TLS. */ + unsigned char *stack_top = tls_start; + ts = (struct thread_start *)(stack_top - sizeof(struct thread_start)); + stack_top -= sizeof(struct thread_start); + + ts->self = tcb; + ts->func = func; + ts->arg = arg; + + stack_top = (unsigned char *)((uintptr_t)stack_top & ~15UL); + + tcb->self = tcb; + tcb->map_base = map; + tcb->map_size = size; + tcb->errno_v = 0; + tcb->dtv = 0; + tcb->state = THREAD_STATE_JOINABLE; + + unsigned long flags = CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_SIGHAND | CLONE_THREAD | CLONE_SYSVSEM | + CLONE_SETTLS | CLONE_PARENT_SETTID | CLONE_CHILD_SETTID | CLONE_CHILD_CLEARTID; + +#if defined(__x86_64__) + long tid = __clone(__thread_start, ts, flags, stack_top, &tcb->tid, tcb, &tcb->tid); +#endif + + if (__predict_false(tid < 0)) { + munmap(map, size); + return thrd_error; + } + +#if !defined(__x86_64__) + if (tid == 0) { + __thread_start(ts); + __builtin_unreachable(); + } +#endif + + tcb->tid = tid; + + *thr = tcb; + + return thrd_success; +} diff --git a/lib/libc/thread/thrd_current.c b/lib/libc/thread/thrd_current.c index b588cc27..fd563bb6 100644 --- a/lib/libc/thread/thrd_current.c +++ b/lib/libc/thread/thrd_current.c @@ -1,9 +1,7 @@ -#include <__thread.h> +#include <libc/thread.h> #include <threads.h> -thread_local struct __thread_self __thread_self; - thrd_t thrd_current(void) { - return &__thread_self; + return __libc_thread_self(); } diff --git a/lib/libc/thread/thrd_detach.c b/lib/libc/thread/thrd_detach.c new file mode 100644 index 00000000..b315a20a --- /dev/null +++ b/lib/libc/thread/thrd_detach.c @@ -0,0 +1,23 @@ +#include <__thread.h> +#include <libc/futex.h> +#include <stdatomic.h> +#include <sys/mman.h> +#include <threads.h> +#include <unistd.h> + +int thrd_detach(thrd_t thr) +{ + struct __thread_self *tcb = (struct __thread_self *)thr; + + if (tcb == NULL) + return thrd_error; + + int state = atomic_exchange_explicit(&tcb->state, THREAD_STATE_DETACHED, memory_order_seq_cst); + + if (state == THREAD_STATE_EXITED) { + if (tcb->map_base && tcb->map_size) + munmap(tcb->map_base, tcb->map_size); + } + + return thrd_success; +} diff --git a/lib/libc/thread/thrd_equal.c b/lib/libc/thread/thrd_equal.c new file mode 100644 index 00000000..25cfd963 --- /dev/null +++ b/lib/libc/thread/thrd_equal.c @@ -0,0 +1,6 @@ +#include <threads.h> + +int thrd_equal(thrd_t thr0, thrd_t thr1) +{ + return thr0 == thr1; +} diff --git a/lib/libc/thread/thrd_exit.c b/lib/libc/thread/thrd_exit.c new file mode 100644 index 00000000..9ba1f54a --- /dev/null +++ b/lib/libc/thread/thrd_exit.c @@ -0,0 +1,25 @@ +#include <__thread.h> +#include <libc/futex.h> +#include <stdatomic.h> +#include <sys/mman.h> +#include <threads.h> +#include <unistd.h> + +_Noreturn void thrd_exit(int res) +{ + struct __thread_self *self = thrd_current(); + + self->res = res; + + int state = atomic_load_explicit((int *)&self->state, memory_order_seq_cst); + if (state == THREAD_STATE_DETACHED) { + if (self->map_base && self->map_size) + munmap(self->map_base, self->map_size); + _exit(0); + } + + atomic_store_explicit(&self->state, THREAD_STATE_EXITED, memory_order_seq_cst); + __futex_wake(&self->state, 1); + + _exit(0); +} diff --git a/lib/libc/thread/thrd_join.c b/lib/libc/thread/thrd_join.c new file mode 100644 index 00000000..7ec38c4a --- /dev/null +++ b/lib/libc/thread/thrd_join.c @@ -0,0 +1,37 @@ +#include <__thread.h> +#include <libc/futex.h> +#include <stdatomic.h> +#include <sys/mman.h> +#include <threads.h> + +int thrd_join(thrd_t thr, int *res) +{ + struct __thread_self *tcb = (struct __thread_self *)thr; + if (tcb == NULL) + return thrd_error; + + int state = atomic_load_explicit(&tcb->state, memory_order_seq_cst); + if (state == THREAD_STATE_DETACHED) + return thrd_error; // Cannot join a detached thread + + while (atomic_load_explicit(&tcb->state, memory_order_seq_cst) != THREAD_STATE_EXITED) { + int cur = atomic_load_explicit(&tcb->state, memory_order_seq_cst); + int r = __futex_wait((volatile int *)&tcb->state, cur); + if (r < 0) + return thrd_error; + } + + if (res) { + *res = tcb->res; + } + + atomic_store_explicit(&tcb->state, THREAD_STATE_JOINABLE, memory_order_seq_cst); + __futex_wake((volatile int *)&tcb->state, 1); + + if (tcb->map_base == NULL || tcb->map_size == 0) + return thrd_error; + + munmap(tcb->map_base, tcb->map_size); + + return thrd_success; +} diff --git a/lib/libc/thread/thrd_sleep.c b/lib/libc/thread/thrd_sleep.c new file mode 100644 index 00000000..075431e3 --- /dev/null +++ b/lib/libc/thread/thrd_sleep.c @@ -0,0 +1,17 @@ +#include <errno.h> +#include <syscall.h> +#include <threads.h> +#include <time.h> + +int thrd_sleep(const struct timespec *duration, struct timespec *remaining) +{ + int r = __syscall(nanosleep, CLOCK_REALTIME, 0, duration, remaining); + + if (r == 0) + return 0; + + if (r == EINTR) + return -1; + + return -2; +} diff --git a/lib/libc/thread/thrd_yield.c b/lib/libc/thread/thrd_yield.c new file mode 100644 index 00000000..38cff265 --- /dev/null +++ b/lib/libc/thread/thrd_yield.c @@ -0,0 +1,7 @@ +#include <sched.h> +#include <threads.h> + +void thrd_yield(void) +{ + sched_yield(); +} diff --git a/lib/libc/thread/tss_create.c b/lib/libc/thread/tss_create.c new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/lib/libc/thread/tss_create.c diff --git a/lib/libc/time/clock_gettime.c b/lib/libc/time/clock_gettime.c index 31e91d01..1cf1cdaa 100644 --- a/lib/libc/time/clock_gettime.c +++ b/lib/libc/time/clock_gettime.c @@ -2,6 +2,9 @@ #include <syscall.h> #include <time.h> +extern void __libc_init_vdso(void); +void *__libc_force_vdso_init = (void *) __libc_init_vdso; + int clock_gettime(clockid_t clock_id, struct timespec *tp) { #if defined(__VDSO_CLOCK_GETTIME) diff --git a/lib/libc/time/clock_nanosleep.c b/lib/libc/time/clock_nanosleep.c index 0722963f..a3d65edd 100644 --- a/lib/libc/time/clock_nanosleep.c +++ b/lib/libc/time/clock_nanosleep.c @@ -3,8 +3,7 @@ #include <syscall.h> // for __syscall, __syscall_4 #include <time.h> // for clock_nanosleep, clockid_t -int clock_nanosleep(clockid_t clock_id, int flags, const struct timespec *rqtp, - struct timespec *rmtp) +int clock_nanosleep(clockid_t clock_id, int flags, const struct timespec *rqtp, struct timespec *rmtp) { return __syscall(nanosleep, clock_id, flags, rqtp, rmtp) * -1; } diff --git a/lib/libc/time/time.c b/lib/libc/time/time.c index b5f0e449..27e5a06f 100644 --- a/lib/libc/time/time.c +++ b/lib/libc/time/time.c @@ -1,6 +1,9 @@ #include <asm/vdso.h> #include <time.h> +extern void __libc_init_vdso(void); +void *__libc_force_vdso_init = (void *) __libc_init_vdso; + time_t time(time_t *tloc) { struct timespec ts; diff --git a/lib/libc/unistd/_exit.c b/lib/libc/unistd/_exit.c index 9ca98613..60ab93b0 100644 --- a/lib/libc/unistd/_exit.c +++ b/lib/libc/unistd/_exit.c @@ -1,9 +1,8 @@ - - #include <syscall.h> // for __syscall, __syscall_1 -void _exit(int status) +_Noreturn void _exit(int status) { __syscall(exit, status); + __builtin_unreachable(); } |
