From cf70352caa8e07244a6ed1181f7834ed6d64ef64 Mon Sep 17 00:00:00 2001 From: Max Wash Date: Wed, 18 Mar 2026 21:08:49 +0000 Subject: [PATCH] lib: c: add pthread implementation --- lib/libc/CMakeLists.txt | 2 + lib/libc/pthread/CMakeLists.txt | 42 +++++++++ lib/libc/pthread/include/pthread.h | 25 ++++++ lib/libc/pthread/init.c | 0 lib/libc/pthread/sys/x86_64/pthread_self.S | 13 +++ .../pthread/sys/x86_64/pthread_unmap_exit.S | 35 ++++++++ lib/libc/pthread/thread/pthread.h | 24 +++++ lib/libc/pthread/thread/pthread_attr.h | 0 lib/libc/pthread/thread/pthread_create.c | 89 +++++++++++++++++++ lib/libc/pthread/thread/pthread_detach.c | 17 ++++ lib/libc/pthread/thread/pthread_exit.c | 31 +++++++ lib/libc/pthread/thread/pthread_join.c | 31 +++++++ lib/libc/pthread/thread/pthread_self.c | 0 13 files changed, 309 insertions(+) create mode 100644 lib/libc/pthread/CMakeLists.txt create mode 100644 lib/libc/pthread/include/pthread.h create mode 100644 lib/libc/pthread/init.c create mode 100644 lib/libc/pthread/sys/x86_64/pthread_self.S create mode 100644 lib/libc/pthread/sys/x86_64/pthread_unmap_exit.S create mode 100644 lib/libc/pthread/thread/pthread.h create mode 100644 lib/libc/pthread/thread/pthread_attr.h create mode 100644 lib/libc/pthread/thread/pthread_create.c create mode 100644 lib/libc/pthread/thread/pthread_detach.c create mode 100644 lib/libc/pthread/thread/pthread_exit.c create mode 100644 lib/libc/pthread/thread/pthread_join.c create mode 100644 lib/libc/pthread/thread/pthread_self.c diff --git a/lib/libc/CMakeLists.txt b/lib/libc/CMakeLists.txt index de4a2f3..dcffb55 100644 --- a/lib/libc/CMakeLists.txt +++ b/lib/libc/CMakeLists.txt @@ -28,3 +28,5 @@ bsp_add_library( target_link_libraries(libc libmango libxpc-static interface::fs) target_compile_definitions(libc PRIVATE ENABLE_GLOBAL_HEAP=1) + +add_subdirectory(pthread) diff --git a/lib/libc/pthread/CMakeLists.txt b/lib/libc/pthread/CMakeLists.txt new file mode 100644 index 0000000..7cdda3e --- /dev/null +++ b/lib/libc/pthread/CMakeLists.txt @@ -0,0 +1,42 @@ +set(source_dirs thread) + +foreach (dir ${source_dirs}) + file(GLOB dir_sources ${CMAKE_CURRENT_SOURCE_DIR}/${dir}/*.c) + file(GLOB dir_headers ${CMAKE_CURRENT_SOURCE_DIR}/${dir}/*.h) + + set(sources ${sources} ${dir_sources}) + set(headers ${headers} ${dir_headers}) +endforeach (dir) + +file(GLOB sys_sources + ${CMAKE_CURRENT_SOURCE_DIR}/sys/${CMAKE_SYSTEM_PROCESSOR}/*.c + ${CMAKE_CURRENT_SOURCE_DIR}/sys/${CMAKE_SYSTEM_PROCESSOR}/*.S) +set_property(SOURCE ${sys_sources} PROPERTY LANGUAGE C) + +set(sources ${sources} ${sys_sources}) + +set(headers ${headers} ${CMAKE_CURRENT_SOURCE_DIR}/include/pthread.h) +set(public_include_dir ${CMAKE_CURRENT_SOURCE_DIR}/include) + +rosetta_add_library(STATIC + NAME libc-pthread + PUBLIC_INCLUDE_DIRS ${public_include_dir} + SOURCES ${sources} + HEADERS ${headers}) +rosetta_add_library(SHARED + NAME libpthread + PUBLIC_INCLUDE_DIRS ${public_include_dir} + SOURCES ${sources} + HEADERS ${headers}) + +sysroot_add_library( + NAME libc-pthread + HEADER_DIR /usr/include + LIB_DIR /usr/lib) +sysroot_add_library( + NAME libpthread + HEADER_DIR /usr/include + LIB_DIR /usr/lib) + +target_link_libraries(libc-pthread libc-io libmango) +target_link_libraries(libpthread libmango libc) diff --git a/lib/libc/pthread/include/pthread.h b/lib/libc/pthread/include/pthread.h new file mode 100644 index 0000000..02a9b42 --- /dev/null +++ b/lib/libc/pthread/include/pthread.h @@ -0,0 +1,25 @@ +#ifndef PTHREAD_H_ +#define PTHREAD_H_ + +#define __PTHREAD_ATTR_SIZE__ 32 + +typedef struct __pthread *pthread_t; + +typedef struct __pthread_attr { + long __sig; + char __opaque[__PTHREAD_ATTR_SIZE__]; +} pthread_attr_t; + +extern int __pthread_init(void); + +extern int pthread_create( + pthread_t *thread, + const pthread_attr_t *attr, + void *(*start_func)(void *), + void *arg); +extern pthread_t pthread_self(void); +extern int pthread_join(pthread_t thread, void **retval); +extern int pthread_detach(pthread_t thread); +extern void pthread_exit(void *retval); + +#endif diff --git a/lib/libc/pthread/init.c b/lib/libc/pthread/init.c new file mode 100644 index 0000000..e69de29 diff --git a/lib/libc/pthread/sys/x86_64/pthread_self.S b/lib/libc/pthread/sys/x86_64/pthread_self.S new file mode 100644 index 0000000..cf8a2d8 --- /dev/null +++ b/lib/libc/pthread/sys/x86_64/pthread_self.S @@ -0,0 +1,13 @@ +.code64 + +.global pthread_self +.type pthread_self, @function + +pthread_self: + push %rbp + mov %rsp, %rbp + + mov %gs:0, %rax + + pop %rbp + ret diff --git a/lib/libc/pthread/sys/x86_64/pthread_unmap_exit.S b/lib/libc/pthread/sys/x86_64/pthread_unmap_exit.S new file mode 100644 index 0000000..b9d8232 --- /dev/null +++ b/lib/libc/pthread/sys/x86_64/pthread_unmap_exit.S @@ -0,0 +1,35 @@ +.code64 + +#include "mango/syscall.h" + +.global __pthread_unmap_exit +.type __pthread_unmap_exit, @function + +/* + %rdi = (kern_handle_t)address_space + %rsi = (void *)unmap_base + %rdx = (size_t)unmap_length + */ +__pthread_unmap_exit: + push %rbp + mov %rsp, %rbp + + /* save the address space handle for later */ + mov %rdi, %rbx + + /* first, unmap the specified region */ + mov $SYS_ADDRESS_SPACE_UNMAP, %rax + /* args are already in the correct registers */ + syscall + + /* next, close the handle to the address space */ + mov $SYS_THREAD_EXIT, %rax + mov %rbx, %rdi + syscall + + /* finally, stop the current thread */ + mov $SYS_THREAD_EXIT, %rax + syscall + + /* unreachable */ + ret diff --git a/lib/libc/pthread/thread/pthread.h b/lib/libc/pthread/thread/pthread.h new file mode 100644 index 0000000..cfd2873 --- /dev/null +++ b/lib/libc/pthread/thread/pthread.h @@ -0,0 +1,24 @@ +#ifndef _THREAD_PTHREAD_H_ +#define _THREAD_PTHREAD_H_ + +#include + +enum pthread_flags { + THREAD_DETACHED = 0x01u, +}; + +struct __pthread { + struct __pthread *thr_self; + enum pthread_flags thr_flags; + kern_handle_t thr_handle; + void *thr_map_base; + size_t thr_map_size; + void *thr_result; +}; + +extern void __pthread_unmap_exit( + kern_handle_t address_space, + void *unmap_base, + size_t unmap_length); + +#endif diff --git a/lib/libc/pthread/thread/pthread_attr.h b/lib/libc/pthread/thread/pthread_attr.h new file mode 100644 index 0000000..e69de29 diff --git a/lib/libc/pthread/thread/pthread_create.c b/lib/libc/pthread/thread/pthread_create.c new file mode 100644 index 0000000..fb6c067 --- /dev/null +++ b/lib/libc/pthread/thread/pthread_create.c @@ -0,0 +1,89 @@ +#include "pthread.h" + +#include +#include +#include +#include +#include +#include + +#define DEFAULT_STACK_SIZE 0x40000 + +static void thread_launchpad(uintptr_t thread, uintptr_t func, uintptr_t arg) +{ + struct __pthread *self = (struct __pthread *)thread; + void *(*start_func)(void *) = (void *(*)(void *))func; + + void *result = start_func((void *)arg); + + pthread_exit(result); +} + +int pthread_create( + pthread_t *thread, + const pthread_attr_t *attr, + void *(*start_func)(void *), + void *arg) +{ + kern_status_t status = KERN_OK; + kern_handle_t task; + + status = task_self(&task); + if (status != KERN_OK) { + return __set_errno(EPERM); + } + + size_t stack_size = DEFAULT_STACK_SIZE; + + void *base + = mmap(NULL, + stack_size, + PROT_READ | PROT_WRITE, + MAP_PRIVATE | MAP_ANONYMOUS, + -1, + 0); + + if (!base) { + return __set_errno(ENOMEM); + } + + virt_addr_t sp = (virt_addr_t)base + DEFAULT_STACK_SIZE; + + sp -= sizeof(struct __pthread); + struct __pthread *new = (struct __pthread *)sp; + sp &= ~(virt_addr_t)0x10; + + memset(new, 0x0, sizeof *new); + new->thr_self = new; + new->thr_map_base = base; + new->thr_map_size = stack_size; + + uintptr_t args[] = { + (uintptr_t)new, + (uintptr_t)start_func, + (uintptr_t)arg, + }; + size_t nr_args = sizeof args / sizeof args[0]; + + status = task_create_thread( + task, + (virt_addr_t)thread_launchpad, + sp, + args, + nr_args, + &new->thr_handle); + if (status != KERN_OK) { + munmap(base, stack_size); + return __set_errno(__errno_from_kern_status(status)); + } + + thread_config_set( + new->thr_handle, + THREAD_CFG_GSBASE, + &new, + sizeof(void *)); + thread_start(new->thr_handle); + + *thread = new; + return __set_errno(SUCCESS); +} diff --git a/lib/libc/pthread/thread/pthread_detach.c b/lib/libc/pthread/thread/pthread_detach.c new file mode 100644 index 0000000..887cb72 --- /dev/null +++ b/lib/libc/pthread/thread/pthread_detach.c @@ -0,0 +1,17 @@ +#include "pthread.h" + +#include +#include +#include +#include +#include +#include +#include + +int pthread_detach(struct __pthread *thread) +{ + thread->thr_flags |= THREAD_DETACHED; + kern_handle_close(thread->thr_handle); + + return 0; +} diff --git a/lib/libc/pthread/thread/pthread_exit.c b/lib/libc/pthread/thread/pthread_exit.c new file mode 100644 index 0000000..7d3fb53 --- /dev/null +++ b/lib/libc/pthread/thread/pthread_exit.c @@ -0,0 +1,31 @@ +#include "pthread.h" + +#include +#include +#include +#include + +extern void pthread_exit(void *retval) +{ + struct __pthread *self = pthread_self(); + if (!self) { + /* TODO: abort(); */ + return; + } + + if (self->thr_flags & THREAD_DETACHED) { + kern_handle_t task; + kern_handle_t address_space; + task_self(&task); + task_get_address_space(task, &address_space); + kern_handle_close(task); + + __pthread_unmap_exit( + address_space, + self->thr_map_base, + self->thr_map_size); + } else { + self->thr_result = retval; + thread_exit(); + } +} diff --git a/lib/libc/pthread/thread/pthread_join.c b/lib/libc/pthread/thread/pthread_join.c new file mode 100644 index 0000000..9f0f9ce --- /dev/null +++ b/lib/libc/pthread/thread/pthread_join.c @@ -0,0 +1,31 @@ +#include "pthread.h" + +#include +#include +#include +#include +#include +#include +#include + +int pthread_join(struct __pthread *thread, void **retval) +{ + kern_wait_item_t wait; + wait.w_handle = thread->thr_handle; + wait.w_waitfor = THREAD_SIGNAL_STOPPED; + wait.w_observed = 0; + + kern_status_t status = kern_object_wait(&wait, 1); + if (status != KERN_OK) { + return __set_errno(EINVAL); + } + + if (retval) { + *retval = thread->thr_result; + } + + kern_handle_close(thread->thr_handle); + munmap(thread->thr_map_base, thread->thr_map_size); + + return 0; +} diff --git a/lib/libc/pthread/thread/pthread_self.c b/lib/libc/pthread/thread/pthread_self.c new file mode 100644 index 0000000..e69de29