summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authorKacper <kacper@mail.openlinux.dev>2025-12-22 23:27:56 +0100
committerKacper <kacper@mail.openlinux.dev>2025-12-22 23:30:32 +0100
commit0f30d227497418c6d3bef7d52244407e30454504 (patch)
tree0e1ac19623d3268380cf74328cdf643648a2f43c /lib
parent90dad97fc07f049383903a166631e2c257f9b8c1 (diff)
Added c11 threads, fixed some locks and add *_unlocked functions
Diffstat (limited to 'lib')
-rw-r--r--lib/libc/Kbuild2
-rw-r--r--lib/libc/errno/errno.c14
-rw-r--r--lib/libc/internal/Kbuild7
-rw-r--r--lib/libc/internal/arch/aarch64/thread_self.c8
-rw-r--r--lib/libc/internal/arch/x86_64/Kbuild2
-rw-r--r--lib/libc/internal/arch/x86_64/_start.c2
-rw-r--r--lib/libc/internal/arch/x86_64/clone.s106
-rw-r--r--lib/libc/internal/arch/x86_64/tcb.c13
-rw-r--r--lib/libc/internal/include/__stdio.h2
-rw-r--r--lib/libc/internal/include/__thread.h44
-rw-r--r--lib/libc/internal/include/atomic.h32
-rw-r--r--lib/libc/internal/include/libc.h18
-rw-r--r--lib/libc/internal/include/libc/fsbase.h7
-rw-r--r--lib/libc/internal/include/libc/futex.h7
-rw-r--r--lib/libc/internal/include/libc/tcb.h9
-rw-r--r--lib/libc/internal/include/libc/thread.h6
-rw-r--r--lib/libc/internal/init/Kbuild1
-rw-r--r--lib/libc/internal/init/init.c35
-rw-r--r--lib/libc/internal/init/io.c42
-rw-r--r--lib/libc/internal/init/tls.c43
-rw-r--r--lib/libc/internal/init/vdso.c13
-rw-r--r--lib/libc/internal/thrd/Kbuild1
-rw-r--r--lib/libc/internal/thrd/self.c6
-rw-r--r--lib/libc/internal/util/Kbuild3
-rw-r--r--lib/libc/internal/util/futex.c13
-rw-r--r--lib/libc/internal/util/panic.c (renamed from lib/libc/internal/panic.c)0
-rw-r--r--lib/libc/internal/util/syscall.c (renamed from lib/libc/internal/syscall.c)0
-rw-r--r--lib/libc/mman/mprotect.c2
-rw-r--r--lib/libc/sched/Kbuild8
-rw-r--r--lib/libc/sched/sched_get_priority_max.c7
-rw-r--r--lib/libc/sched/sched_get_priority_min.c7
-rw-r--r--lib/libc/sched/sched_getparam.c9
-rw-r--r--lib/libc/sched/sched_getscheduler.c7
-rw-r--r--lib/libc/sched/sched_rr_get_interval.c7
-rw-r--r--lib/libc/sched/sched_setparam.c7
-rw-r--r--lib/libc/sched/sched_setscheduler.c7
-rw-r--r--lib/libc/sched/sched_yield.c6
-rw-r--r--lib/libc/stdio/Kbuild20
-rw-r--r--lib/libc/stdio/clearerr.c15
-rw-r--r--lib/libc/stdio/clearerr_unlocked.c8
-rw-r--r--lib/libc/stdio/fclose.c2
-rw-r--r--lib/libc/stdio/fdopen.c25
-rw-r--r--lib/libc/stdio/feof.c15
-rw-r--r--lib/libc/stdio/feof_unlocked.c7
-rw-r--r--lib/libc/stdio/ferror.c14
-rw-r--r--lib/libc/stdio/ferror_unlocked.c7
-rw-r--r--lib/libc/stdio/fflush.c73
-rw-r--r--lib/libc/stdio/fflush_unlocked.c64
-rw-r--r--lib/libc/stdio/fgetc.c11
-rw-r--r--lib/libc/stdio/fgetc_unlocked.c11
-rw-r--r--lib/libc/stdio/fgets.c15
-rw-r--r--lib/libc/stdio/fgets_unlocked.c6
-rw-r--r--lib/libc/stdio/fileno.c20
-rw-r--r--lib/libc/stdio/fileno_unlocked.c13
-rw-r--r--lib/libc/stdio/flockfile.c8
-rw-r--r--lib/libc/stdio/fmemopen.c10
-rw-r--r--lib/libc/stdio/fopen.c18
-rw-r--r--lib/libc/stdio/fputc.c25
-rw-r--r--lib/libc/stdio/fputc_unlocked.c6
-rw-r--r--lib/libc/stdio/fputs.c11
-rw-r--r--lib/libc/stdio/fputs_unlocked.c9
-rw-r--r--lib/libc/stdio/fread.c56
-rw-r--r--lib/libc/stdio/fread_unlocked.c47
-rw-r--r--lib/libc/stdio/fseek.c19
-rw-r--r--lib/libc/stdio/ftrylockfile.c11
-rw-r--r--lib/libc/stdio/funlockfile.c8
-rw-r--r--lib/libc/stdio/fwrite.c136
-rw-r--r--lib/libc/stdio/fwrite_unlocked.c106
-rw-r--r--lib/libc/stdio/getc.c13
-rw-r--r--lib/libc/stdio/getc_unlocked.c6
-rw-r--r--lib/libc/stdio/getchar.c13
-rw-r--r--lib/libc/stdio/getchar_unlocked.c6
-rw-r--r--lib/libc/stdio/pclose.c2
-rw-r--r--lib/libc/stdio/popen.c2
-rw-r--r--lib/libc/stdio/putchar.c13
-rw-r--r--lib/libc/stdio/putchar_unlocked.c6
-rw-r--r--lib/libc/stdio/setvbuf.c10
-rw-r--r--lib/libc/stdio/stderr.c23
-rw-r--r--lib/libc/stdio/stdin.c19
-rw-r--r--lib/libc/stdio/stdout.c37
-rw-r--r--lib/libc/stdio/vfprintf.c245
-rw-r--r--lib/libc/stdlib/exit.c51
-rw-r--r--lib/libc/stdlib/strtox.c12
-rw-r--r--lib/libc/sys/Kbuild1
-rw-r--r--lib/libc/sys/getauxval.c10
-rw-r--r--lib/libc/sys/mqueue/Kbuild (renamed from lib/libc/mqueue/Kbuild)0
-rw-r--r--lib/libc/sys/mqueue/mq_close.c (renamed from lib/libc/mqueue/mq_close.c)0
-rw-r--r--lib/libc/sys/mqueue/mq_getattr.c (renamed from lib/libc/mqueue/mq_getattr.c)0
-rw-r--r--lib/libc/sys/mqueue/mq_notify.c (renamed from lib/libc/mqueue/mq_notify.c)0
-rw-r--r--lib/libc/sys/mqueue/mq_open.c (renamed from lib/libc/mqueue/mq_open.c)0
-rw-r--r--lib/libc/sys/mqueue/mq_receive.c (renamed from lib/libc/mqueue/mq_receive.c)0
-rw-r--r--lib/libc/sys/mqueue/mq_setattr.c (renamed from lib/libc/mqueue/mq_setattr.c)0
-rw-r--r--lib/libc/sys/mqueue/mq_timedreceive.c (renamed from lib/libc/mqueue/mq_timedreceive.c)0
-rw-r--r--lib/libc/sys/mqueue/mq_timedsend.c (renamed from lib/libc/mqueue/mq_timedsend.c)0
-rw-r--r--lib/libc/sys/mqueue/mq_unlink.c (renamed from lib/libc/mqueue/mq_unlink.c)0
-rw-r--r--lib/libc/thread/Kbuild3
-rw-r--r--lib/libc/thread/thrd_create.c113
-rw-r--r--lib/libc/thread/thrd_current.c6
-rw-r--r--lib/libc/thread/thrd_detach.c23
-rw-r--r--lib/libc/thread/thrd_equal.c6
-rw-r--r--lib/libc/thread/thrd_exit.c25
-rw-r--r--lib/libc/thread/thrd_join.c37
-rw-r--r--lib/libc/thread/thrd_sleep.c17
-rw-r--r--lib/libc/thread/thrd_yield.c7
-rw-r--r--lib/libc/thread/tss_create.c0
-rw-r--r--lib/libc/time/clock_gettime.c3
-rw-r--r--lib/libc/time/clock_nanosleep.c3
-rw-r--r--lib/libc/time/time.c3
-rw-r--r--lib/libc/unistd/_exit.c5
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();
}