diff --git a/Kernel/Process.h b/Kernel/Process.h index caa1de3ccb..acd1b14756 100644 --- a/Kernel/Process.h +++ b/Kernel/Process.h @@ -379,7 +379,7 @@ public: KResultOr sys$sched_setparam(pid_t pid, Userspace); KResultOr sys$sched_getparam(pid_t pid, Userspace); KResultOr sys$create_thread(void* (*)(void*), Userspace); - [[noreturn]] void sys$exit_thread(Userspace); + [[noreturn]] void sys$exit_thread(Userspace, Userspace, size_t); KResultOr sys$join_thread(pid_t tid, Userspace exit_value); KResultOr sys$detach_thread(pid_t tid); KResultOr sys$set_thread_name(pid_t tid, Userspace buffer, size_t buffer_size); diff --git a/Kernel/Syscall.cpp b/Kernel/Syscall.cpp index 49da400045..754f18a40e 100644 --- a/Kernel/Syscall.cpp +++ b/Kernel/Syscall.cpp @@ -97,7 +97,7 @@ KResultOr handle(RegisterState& regs, FlatPtr function, FlatPtr arg1, F process.sys$exit(arg1); break; case SC_exit_thread: - process.sys$exit_thread(arg1); + process.sys$exit_thread(arg1, arg2, arg3); break; default: VERIFY_NOT_REACHED(); diff --git a/Kernel/Syscalls/thread.cpp b/Kernel/Syscalls/thread.cpp index 42acab2690..3dc4852ac4 100644 --- a/Kernel/Syscalls/thread.cpp +++ b/Kernel/Syscalls/thread.cpp @@ -78,7 +78,7 @@ KResultOr Process::sys$create_thread(void* (*entry)(void*), Userspacetid().value(); } -void Process::sys$exit_thread(Userspace exit_value) +void Process::sys$exit_thread(Userspace exit_value, Userspace stack_location, size_t stack_size) { REQUIRE_PROMISE(thread); @@ -90,6 +90,12 @@ void Process::sys$exit_thread(Userspace exit_value) auto current_thread = Thread::current(); PerformanceManager::add_thread_exit_event(*current_thread); + if (stack_location) { + auto unmap_result = space().unmap_mmap_range(VirtualAddress { stack_location }, stack_size); + if (unmap_result.is_error()) + dbgln("Failed to unmap thread stack, terminating thread anyway. Error code: {}", unmap_result.error()); + } + current_thread->exit(reinterpret_cast(exit_value.ptr())); VERIFY_NOT_REACHED(); } diff --git a/Userland/Libraries/LibPthread/pthread.cpp b/Userland/Libraries/LibPthread/pthread.cpp index d265d93046..9f82ec3e58 100644 --- a/Userland/Libraries/LibPthread/pthread.cpp +++ b/Userland/Libraries/LibPthread/pthread.cpp @@ -33,13 +33,18 @@ static constexpr size_t required_stack_alignment = 4 * MiB; static constexpr size_t highest_reasonable_guard_size = 32 * PAGE_SIZE; static constexpr size_t highest_reasonable_stack_size = 8 * MiB; // That's the default in Ubuntu? +__thread void* s_stack_location; +__thread size_t s_stack_size; + #define __RETURN_PTHREAD_ERROR(rc) \ return ((rc) < 0 ? -(rc) : 0) extern "C" { -static void* pthread_create_helper(void* (*routine)(void*), void* argument) +static void* pthread_create_helper(void* (*routine)(void*), void* argument, void* stack_location, size_t stack_size) { + s_stack_location = stack_location; + s_stack_size = stack_size; void* ret_val = routine(argument); pthread_exit(ret_val); return nullptr; @@ -57,10 +62,12 @@ static int create_thread(pthread_t* thread, void* (*entry)(void*), void* argumen // We set up the stack for pthread_create_helper. // Note that we need to align the stack to 16B, accounting for - // the fact that we also push 8 bytes. - while (((uintptr_t)stack - 8) % 16 != 0) + // the fact that we also push 16 bytes. + while (((uintptr_t)stack - 16) % 16 != 0) push_on_stack(nullptr); + push_on_stack((void*)thread_params->m_stack_size); + push_on_stack(thread_params->m_stack_location); push_on_stack(argument); push_on_stack((void*)entry); VERIFY((uintptr_t)stack % 16 == 0); @@ -74,10 +81,10 @@ static int create_thread(pthread_t* thread, void* (*entry)(void*), void* argumen __RETURN_PTHREAD_ERROR(rc); } -[[noreturn]] static void exit_thread(void* code) +[[noreturn]] static void exit_thread(void* code, void* stack_location, size_t stack_size) { __pthread_key_destroy_for_current_thread(); - syscall(SC_exit_thread, code); + syscall(SC_exit_thread, code, stack_location, stack_size); VERIFY_NOT_REACHED(); } @@ -119,7 +126,7 @@ int pthread_create(pthread_t* thread, pthread_attr_t* attributes, void* (*start_ void pthread_exit(void* value_ptr) { - exit_thread(value_ptr); + exit_thread(value_ptr, s_stack_location, s_stack_size); } void pthread_cleanup_push([[maybe_unused]] void (*routine)(void*), [[maybe_unused]] void* arg)