diff --git a/kernel/kernel/Process.cpp b/kernel/kernel/Process.cpp index 778dcb6f..eb655ec1 100644 --- a/kernel/kernel/Process.cpp +++ b/kernel/kernel/Process.cpp @@ -431,52 +431,41 @@ namespace Kernel O_EXEC | O_RDWR )); - BAN::Vector temp_buffer; - TRY(temp_buffer.resize(BAN::Math::min(master_size, PAGE_SIZE))); - size_t bytes_copied = 0; while (bytes_copied < master_size) { - const size_t to_copy = BAN::Math::min(master_size - bytes_copied, temp_buffer.size()); + uint8_t buffer[PAGE_SIZE]; + const size_t to_copy = BAN::Math::min(master_size - bytes_copied, sizeof(buffer)); const vaddr_t vaddr = master_addr + bytes_copied; const paddr_t paddr = page_table.physical_address_of(vaddr & PAGE_ADDR_MASK); PageTable::with_fast_page(paddr, [&] { - memcpy(temp_buffer.data(), PageTable::fast_page_as_ptr(vaddr % PAGE_SIZE), to_copy); + memcpy(buffer, PageTable::fast_page_as_ptr(vaddr % PAGE_SIZE), to_copy); }); - TRY(region->copy_data_to_region(bytes_copied, temp_buffer.data(), to_copy)); + TRY(region->copy_data_to_region(bytes_copied, buffer, to_copy)); bytes_copied += to_copy; } - auto uthread = TRY(BAN::UniqPtr::create()); - *uthread = { - .self = reinterpret_cast(region->vaddr() + master_size), - .master_tls_addr = reinterpret_cast(master_addr), - .master_tls_size = master_size, - .master_tls_module_count = 1, - .dynamic_tls = nullptr, - .cleanup_stack = nullptr, - .id = 0, - .errno_ = 0, - .cancel_type = 0, - .cancel_state = 0, - .canceled = 0, - .specific_keys = {}, - .specific_values = {}, - .dtv = { 0, region->vaddr() } - }; + uthread uthread {}; + uthread.self = reinterpret_cast(region->vaddr() + master_size); + uthread.master_tls_addr = reinterpret_cast(master_addr), + uthread.master_tls_size = master_size, + uthread.master_tls_module_count = 1; + uthread.dynamic_tls = nullptr; + uthread.dtv[0] = 0; + uthread.dtv[1] = region->vaddr(); TRY(region->copy_data_to_region( master_size, - reinterpret_cast(uthread.ptr()), + reinterpret_cast(&uthread), sizeof(struct uthread) )); - TLSResult result; - result.addr = region->vaddr() + master_size;; - result.region = BAN::move(region); - return result; + return TLSResult { + .region = BAN::move(region), + .addr = region->vaddr() + master_size, + }; } BAN::ErrorOr Process::add_mapped_region(BAN::UniqPtr&& region) diff --git a/userspace/libraries/LibC/include/bits/types/pthread_t.h b/userspace/libraries/LibC/include/bits/types/pthread_t.h index 9ad15105..5e167026 100644 --- a/userspace/libraries/LibC/include/bits/types/pthread_t.h +++ b/userspace/libraries/LibC/include/bits/types/pthread_t.h @@ -7,10 +7,7 @@ __BEGIN_DECLS -#define __need_pid_t -#include - -typedef pid_t pthread_t; +typedef struct uthread* pthread_t; __END_DECLS diff --git a/userspace/libraries/LibC/include/bits/types/uthread.h b/userspace/libraries/LibC/include/bits/types/uthread.h index 187875d8..00e88eec 100644 --- a/userspace/libraries/LibC/include/bits/types/uthread.h +++ b/userspace/libraries/LibC/include/bits/types/uthread.h @@ -5,9 +5,11 @@ __BEGIN_DECLS +#define __need_pid_t #define __need_size_t #include +#include #include #include #include @@ -36,18 +38,24 @@ typedef struct _dynamic_tls_t struct uthread { struct uthread* self; + + // TLS void* master_tls_addr; size_t master_tls_size; size_t master_tls_module_count; _dynamic_tls_t* dynamic_tls; - _pthread_cleanup_t* cleanup_stack; - pthread_t id; + + // LIBC + pid_t id; + pthread_attr_t attr; int errno_; int cancel_type; int cancel_state; volatile int canceled; + _pthread_cleanup_t* cleanup_funcs; pthread_key_t specific_keys[PTHREAD_KEYS_MAX]; - void* specific_values[PTHREAD_KEYS_MAX]; + void* specific_vals[PTHREAD_KEYS_MAX]; + // FIXME: make this dynamic uintptr_t dtv[1 + 256]; }; diff --git a/userspace/libraries/LibC/include/pthread.h b/userspace/libraries/LibC/include/pthread.h index b95033d7..89363a2e 100644 --- a/userspace/libraries/LibC/include/pthread.h +++ b/userspace/libraries/LibC/include/pthread.h @@ -168,7 +168,7 @@ void pthread_cleanup_push(void (*routine)(void*), void* arg); #define _pthread_equal(t1, t2) ((t1) == (t2)) -#define _pthread_self() (_get_uthread()->id) +#define _pthread_self() (_get_uthread()) #define _pthread_testcancel() do { \ struct uthread* uthread = _get_uthread(); \ diff --git a/userspace/libraries/LibC/pthread.cpp b/userspace/libraries/LibC/pthread.cpp index 00e3daa7..c62c5439 100644 --- a/userspace/libraries/LibC/pthread.cpp +++ b/userspace/libraries/LibC/pthread.cpp @@ -18,7 +18,6 @@ struct pthread_trampoline_info_t { struct uthread* uthread; - bool detached; void* (*start_routine)(void*); void* arg; }; @@ -61,8 +60,10 @@ asm( extern "C" void _pthread_trampoline_cpp(void* arg) { - auto info = *reinterpret_cast(arg); + auto info = *static_cast(arg); + info.uthread->id = syscall(SYS_THREAD_GETID); + #if defined(__x86_64__) syscall(SYS_SET_FSBASE, info.uthread); #elif defined(__i686__) @@ -70,10 +71,14 @@ extern "C" void _pthread_trampoline_cpp(void* arg) #else #error #endif + + // NOTE: we have to get id and set TLS to for free to be able to use pthread_self free(arg); + signal(SIGCANCEL, &_pthread_cancel_handler); - if (info.detached) - pthread_detach(info.uthread->id); + if (info.uthread->attr.detachstate == PTHREAD_CREATE_DETACHED) + pthread_detach(info.uthread); + pthread_exit(info.start_routine(info.arg)); ASSERT_NOT_REACHED(); } @@ -115,10 +120,10 @@ static void free_uthread(uthread* uthread) void pthread_cleanup_pop(int execute) { uthread* uthread = _get_uthread(); - ASSERT(uthread->cleanup_stack); + ASSERT(uthread->cleanup_funcs); - auto* cleanup = uthread->cleanup_stack; - uthread->cleanup_stack = cleanup->next; + auto* cleanup = uthread->cleanup_funcs; + uthread->cleanup_funcs = cleanup->next; if (execute) cleanup->routine(cleanup->arg); @@ -135,9 +140,9 @@ void pthread_cleanup_push(void (*routine)(void*), void* arg) cleanup->routine = routine; cleanup->arg = arg; - cleanup->next = uthread->cleanup_stack; + cleanup->next = uthread->cleanup_funcs; - uthread->cleanup_stack = cleanup; + uthread->cleanup_funcs = cleanup; } static pthread_key_t s_pthread_key_current = 1; @@ -197,9 +202,9 @@ void* pthread_getspecific(pthread_key_t key) if (uthread->specific_keys[i] != key) { uthread->specific_keys[i] = key; - uthread->specific_values[i] = nullptr; + uthread->specific_vals[i] = nullptr; } - ret = uthread->specific_values[i]; + ret = uthread->specific_vals[i]; break; } pthread_spin_unlock(&s_pthread_key_lock); @@ -220,7 +225,7 @@ int pthread_setspecific(pthread_key_t key, const void* value) continue; if (uthread->specific_keys[i] != key) uthread->specific_keys[i] = key; - uthread->specific_values[i] = const_cast(value); + uthread->specific_vals[i] = const_cast(value); ret = 0; break; } @@ -375,11 +380,16 @@ int pthread_attr_getstacksize(const pthread_attr_t* __restrict attr, size_t* __r int pthread_attr_setstacksize(pthread_attr_t* attr, size_t stacksize) { + if (stacksize < PTHREAD_STACK_MIN) + return EINVAL; + if (auto rem = stacksize % getpagesize()) + stacksize += getpagesize() - rem; + attr->stackaddr = nullptr; attr->stacksize = stacksize; return 0; } -int pthread_create(pthread_t* __restrict thread_id, const pthread_attr_t* __restrict attr, void* (*start_routine)(void*), void* __restrict arg) +int pthread_create(pthread_t* __restrict thread, const pthread_attr_t* __restrict attr, void* (*start_routine)(void*), void* __restrict arg) { auto* info = static_cast(malloc(sizeof(pthread_trampoline_info_t))); if (info == nullptr) @@ -387,12 +397,11 @@ int pthread_create(pthread_t* __restrict thread_id, const pthread_attr_t* __rest *info = { .uthread = nullptr, - .detached = attr ? (attr->detachstate == PTHREAD_CREATE_DETACHED) : false, .start_routine = start_routine, .arg = arg, }; - long syscall_ret = 0; + uthread* result = nullptr; { uthread* self = _get_uthread(); @@ -413,14 +422,15 @@ int pthread_create(pthread_t* __restrict thread_id, const pthread_attr_t* __rest .master_tls_size = self->master_tls_size, .master_tls_module_count = self->master_tls_module_count, .dynamic_tls = self->dynamic_tls, - .cleanup_stack = nullptr, .id = -1, + .attr = attr ? *attr : s_default_pthread_attr, .errno_ = 0, .cancel_type = PTHREAD_CANCEL_DEFERRED, .cancel_state = PTHREAD_CANCEL_ENABLE, .canceled = 0, + .cleanup_funcs = nullptr, .specific_keys = {}, - .specific_values = {}, + .specific_vals = {}, .dtv = { self->dtv[0] } }; @@ -430,14 +440,14 @@ int pthread_create(pthread_t* __restrict thread_id, const pthread_attr_t* __rest uthread->dtv[i] = self->dtv[i] - self_addr + uthread_addr; info->uthread = uthread; + result = uthread; } - syscall_ret = syscall(SYS_THREAD_CREATE, _pthread_trampoline, info); - if (syscall_ret == -1) + if (syscall(SYS_THREAD_CREATE, _pthread_trampoline, info) == -1) goto pthread_create_error; - if (thread_id) - *thread_id = syscall_ret; + if (thread) + *thread = result; return 0; pthread_create_error: @@ -450,13 +460,17 @@ pthread_create_error: int pthread_detach(pthread_t thread) { - return syscall(SYS_THREAD_DETACH, thread); + // FIXME: race if detached thread exits before assigning detachstate + if (syscall(SYS_THREAD_DETACH, thread->id) == -1) + return errno; + thread->attr.detachstate = PTHREAD_CREATE_DETACHED; + return 0; } void pthread_exit(void* value_ptr) { uthread* uthread = _get_uthread(); - while (uthread->cleanup_stack) + while (uthread->cleanup_funcs) pthread_cleanup_pop(1); for (size_t iteration = 0; iteration < PTHREAD_DESTRUCTOR_ITERATIONS; iteration++) @@ -471,8 +485,8 @@ void pthread_exit(void* value_ptr) if (s_pthread_key_map[i] && uthread->specific_keys[i] == s_pthread_key_map[i]) { destructor = s_pthread_key_destructors[i]; - value = uthread->specific_values[i]; - uthread->specific_values[i] = nullptr; + value = uthread->specific_vals[i]; + uthread->specific_vals[i] = nullptr; } pthread_spin_unlock(&s_pthread_key_lock); @@ -485,18 +499,26 @@ void pthread_exit(void* value_ptr) break; } - free_uthread(uthread); + if (uthread->attr.detachstate == PTHREAD_CREATE_DETACHED) + free_uthread(uthread); syscall(SYS_THREAD_EXIT, value_ptr); ASSERT_NOT_REACHED(); } int pthread_join(pthread_t thread, void** value_ptr) { + if (thread->attr.detachstate != PTHREAD_CREATE_JOINABLE) + return EINVAL; + do { pthread_testcancel(); errno = 0; - } while (syscall(SYS_THREAD_JOIN, thread, value_ptr) == -1 && errno == EINTR); - return errno; + } while (syscall(SYS_THREAD_JOIN, thread->id, value_ptr) == -1 && errno == EINTR); + + const int ret = errno; + if (ret == 0) + free_uthread(thread); + return ret; } int pthread_once(pthread_once_t* once_control, void (*init_routine)(void)) @@ -536,8 +558,8 @@ void _pthread_call_atfork(int state) switch (state) { case _PTHREAD_ATFORK_PREPARE: list = s_atfork_prepare; break; - case _PTHREAD_ATFORK_PARENT: list = s_atfork_parent; break; - case _PTHREAD_ATFORK_CHILD: list = s_atfork_child; break; + case _PTHREAD_ATFORK_PARENT: list = s_atfork_parent; break; + case _PTHREAD_ATFORK_CHILD: list = s_atfork_child; break; default: ASSERT_NOT_REACHED(); } @@ -802,7 +824,7 @@ int pthread_mutex_lock(pthread_mutex_t* mutex) int pthread_mutex_trylock(pthread_mutex_t* mutex) { - const uint32_t tid = pthread_self(); + const uint32_t tid = pthread_self()->id; switch (mutex->attr.type) { @@ -831,7 +853,7 @@ int pthread_mutex_timedlock(pthread_mutex_t* __restrict mutex, const struct time if (const int ret = pthread_mutex_trylock(mutex); ret != EBUSY) return ret; - const uint32_t tid = pthread_self(); + const uint32_t tid = pthread_self()->id; uint32_t expected = 0; while (!BAN::atomic_compare_exchange(mutex->futex, expected, tid, BAN::memory_order_acquire)) @@ -854,7 +876,7 @@ int pthread_mutex_timedlock(pthread_mutex_t* __restrict mutex, const struct time int pthread_mutex_unlock(pthread_mutex_t* mutex) { - ASSERT(mutex->futex == static_cast(pthread_self())); + ASSERT(mutex->futex == static_cast(pthread_self()->id)); mutex->lock_depth--; if (mutex->lock_depth == 0) diff --git a/userspace/libraries/LibC/signal.cpp b/userspace/libraries/LibC/signal.cpp index 5eb05ff4..aaf55edc 100644 --- a/userspace/libraries/LibC/signal.cpp +++ b/userspace/libraries/LibC/signal.cpp @@ -41,7 +41,7 @@ void psignal(int signum, const char* message) int pthread_kill(pthread_t thread, int sig) { - if (syscall(SYS_THREAD_KILL, thread, sig) == -1) + if (syscall(SYS_THREAD_KILL, thread->id, sig) == -1) return errno; return 0; } diff --git a/userspace/libraries/LibC/unistd.cpp b/userspace/libraries/LibC/unistd.cpp index 3aa9ce22..0d6fa71b 100644 --- a/userspace/libraries/LibC/unistd.cpp +++ b/userspace/libraries/LibC/unistd.cpp @@ -65,12 +65,12 @@ extern "C" void _init_libc(char** environ, init_funcs_t init_funcs, init_funcs_t #error #endif { - self->cleanup_stack = nullptr; self->id = syscall(SYS_THREAD_GETID); self->errno_ = 0; self->cancel_type = PTHREAD_CANCEL_DEFERRED; self->cancel_state = PTHREAD_CANCEL_ENABLE; self->canceled = false; + self->cleanup_funs = nullptr; } else { @@ -83,14 +83,14 @@ extern "C" void _init_libc(char** environ, init_funcs_t init_funcs, init_funcs_t .master_tls_size = 0, .master_tls_module_count = 1, .dynamic_tls = nullptr, - .cleanup_stack = nullptr, .id = static_cast(syscall(SYS_THREAD_GETID)), .errno_ = 0, .cancel_type = PTHREAD_CANCEL_DEFERRED, .cancel_state = PTHREAD_CANCEL_ENABLE, .canceled = false, + .cleanup_funs = nullptr, .specific_keys = {}, - .specific_values = {}, + .specific_vals = {}, .dtv = { 0 }, }; diff --git a/userspace/programs/DynamicLoader/main.cpp b/userspace/programs/DynamicLoader/main.cpp index b2d7b915..03b358bc 100644 --- a/userspace/programs/DynamicLoader/main.cpp +++ b/userspace/programs/DynamicLoader/main.cpp @@ -216,16 +216,16 @@ static _dynamic_tls_t* s_dynamic_tls = nullptr; static const char* s_ld_library_path = nullptr; -static BAN::Atomic s_global_locker = 0; +static BAN::Atomic s_global_locker = 0; static uint32_t s_global_lock_depth = 0; constexpr uintptr_t SYM_NOT_FOUND = -1; static void lock_global_lock() { - const pthread_t tid = syscall(SYS_THREAD_GETID); + const pid_t tid = syscall(SYS_THREAD_GETID); - pthread_t expected = 0; + pid_t expected = 0; while (!s_global_locker.compare_exchange(expected, tid)) { if (expected == tid) @@ -1349,25 +1349,21 @@ static void initialize_tls(MasterTLS master_tls) memcpy(tls_addr, master_tls.addr, master_tls.size); uthread& uthread = *reinterpret_cast(tls_addr + master_tls.size); + memset(&uthread, 0, sizeof(uthread)); - // uthread is prepared in libc init, but some other stuff may be calling pthread functions - // for example __cxa_guard_release calls pthread_cond_broadcast - uthread = { - .self = &uthread, - .master_tls_addr = master_tls.addr, - .master_tls_size = master_tls.size, - .master_tls_module_count = master_tls.module_count, - .dynamic_tls = s_dynamic_tls, - .cleanup_stack = nullptr, - .id = static_cast(syscall(SYS_THREAD_GETID)), - .errno_ = 0, - .cancel_type = PTHREAD_CANCEL_DEFERRED, - .cancel_state = PTHREAD_CANCEL_ENABLE, - .canceled = false, - .specific_keys = {}, - .specific_values = {}, - .dtv = {}, - }; + uthread.self = &uthread; + uthread.master_tls_addr = master_tls.addr, + uthread.master_tls_size = master_tls.size, + uthread.master_tls_module_count = master_tls.module_count, + uthread.dynamic_tls = s_dynamic_tls, + + // these are prepared in libc init, but some other stuff may be calling pthread functions + // for example __cxa_guard_release calls pthread_cond_broadcast + uthread.id = syscall(SYS_THREAD_GETID); + uthread.errno_ = 0; + uthread.cancel_type = PTHREAD_CANCEL_DEFERRED; + uthread.cancel_state = PTHREAD_CANCEL_ENABLE; + uthread.canceled = false; uthread.dtv[0] = master_tls.module_count; for (size_t i = 0; i < s_loaded_file_count; i++)