From e34ed04d1ee26e0b4e03d6c6b79b3ff195f9458c Mon Sep 17 00:00:00 2001 From: Andreas Kling Date: Sun, 17 Nov 2019 17:28:17 +0100 Subject: [PATCH] Kernel+LibPthread+LibC: Create secondary thread stacks in userspace Have pthread_create() allocate a stack and passing it to the kernel instead of this work happening in the kernel. The more of this we can do in userspace, the better. This patch also unexposes the raw create_thread() and exit_thread() syscalls since they are now only used by LibPthread anyway. --- Kernel/Process.cpp | 11 +++++++++-- Kernel/Process.h | 2 +- Kernel/Thread.cpp | 12 ------------ Kernel/Thread.h | 1 - Libraries/LibC/unistd.cpp | 12 ------------ Libraries/LibC/unistd.h | 2 -- Libraries/LibPthread/pthread.cpp | 23 ++++++++++++++++++++--- 7 files changed, 30 insertions(+), 33 deletions(-) diff --git a/Kernel/Process.cpp b/Kernel/Process.cpp index 314d2df948c..7b409876f39 100644 --- a/Kernel/Process.cpp +++ b/Kernel/Process.cpp @@ -2861,16 +2861,23 @@ int Process::thread_count() const return count; } -int Process::sys$create_thread(void* (*entry)(void*), void* argument) +int Process::sys$create_thread(void* (*entry)(void*), void* argument, void* stack) { if (!validate_read((const void*)entry, sizeof(void*))) return -EFAULT; + if (!MM.validate_user_stack(*this, VirtualAddress(((u32)stack) - 4))) + return -EFAULT; auto* thread = new Thread(*this); auto& tss = thread->tss(); tss.eip = (u32)entry; tss.eflags = 0x0202; tss.cr3 = page_directory().cr3(); - thread->make_userspace_stack_for_secondary_thread(argument); + tss.esp = (u32)stack; + + // NOTE: The stack needs to be 16-byte aligned. + thread->push_value_on_stack((u32)argument); + thread->push_value_on_stack(0); + thread->make_thread_specific_region({}); thread->set_state(Thread::State::Runnable); return thread->tid(); diff --git a/Kernel/Process.h b/Kernel/Process.h index 1e912aaa61b..58a2d39887b 100644 --- a/Kernel/Process.h +++ b/Kernel/Process.h @@ -204,7 +204,7 @@ public: int sys$sched_setparam(pid_t pid, const struct sched_param* param); int sys$sched_getparam(pid_t pid, struct sched_param* param); int sys$restore_signal_mask(u32 mask); - int sys$create_thread(void* (*)(void*), void*); + int sys$create_thread(void* (*)(void*), void* argument, void* stack); void sys$exit_thread(void*); int sys$join_thread(int tid, void** exit_value); int sys$rename(const char* oldpath, const char* newpath); diff --git a/Kernel/Thread.cpp b/Kernel/Thread.cpp index f1034e61e49..84bf19188a9 100644 --- a/Kernel/Thread.cpp +++ b/Kernel/Thread.cpp @@ -601,18 +601,6 @@ void Thread::make_userspace_stack_for_main_thread(Vector arguments, Vect push_value_on_stack(0); } -void Thread::make_userspace_stack_for_secondary_thread(void* argument) -{ - m_userspace_stack_region = m_process.allocate_region(VirtualAddress(), default_userspace_stack_size, String::format("Stack (Thread %d)", tid()), PROT_READ | PROT_WRITE, false); - ASSERT(m_userspace_stack_region); - m_userspace_stack_region->set_stack(true); - m_tss.esp = m_userspace_stack_region->vaddr().offset(default_userspace_stack_size).get(); - - // NOTE: The stack needs to be 16-byte aligned. - push_value_on_stack((u32)argument); - push_value_on_stack(0); -} - Thread* Thread::clone(Process& process) { auto* clone = new Thread(process); diff --git a/Kernel/Thread.h b/Kernel/Thread.h index 0fd9b9ad37c..7017df3dd95 100644 --- a/Kernel/Thread.h +++ b/Kernel/Thread.h @@ -325,7 +325,6 @@ public: void set_default_signal_dispositions(); void push_value_on_stack(u32); void make_userspace_stack_for_main_thread(Vector arguments, Vector environment); - void make_userspace_stack_for_secondary_thread(void* argument); void make_thread_specific_region(Badge); diff --git a/Libraries/LibC/unistd.cpp b/Libraries/LibC/unistd.cpp index d0f6af955a2..809d7051879 100644 --- a/Libraries/LibC/unistd.cpp +++ b/Libraries/LibC/unistd.cpp @@ -509,18 +509,6 @@ char* getlogin() return nullptr; } -int create_thread(void* (*entry)(void*), void* argument) -{ - int rc = syscall(SC_create_thread, entry, argument); - __RETURN_WITH_ERRNO(rc, rc, -1); -} - -void exit_thread(void* code) -{ - syscall(SC_exit_thread, code); - ASSERT_NOT_REACHED(); -} - int ftruncate(int fd, off_t length) { int rc = syscall(SC_ftruncate, fd, length); diff --git a/Libraries/LibC/unistd.h b/Libraries/LibC/unistd.h index 8f571226935..c7999b335c5 100644 --- a/Libraries/LibC/unistd.h +++ b/Libraries/LibC/unistd.h @@ -35,8 +35,6 @@ void sysbeep(); int systrace(pid_t); int gettid(); int donate(int tid); -int create_thread(void *(*)(void*), void* argument); -void exit_thread(void*); int create_shared_buffer(int, void** buffer); int share_buffer_with(int, pid_t peer_pid); int share_buffer_globally(int); diff --git a/Libraries/LibPthread/pthread.cpp b/Libraries/LibPthread/pthread.cpp index b1e17b1f617..ba844ce4006 100644 --- a/Libraries/LibPthread/pthread.cpp +++ b/Libraries/LibPthread/pthread.cpp @@ -1,18 +1,36 @@ +#include #include #include #include #include -#include #include +#include +#include extern "C" { +static int create_thread(void* (*entry)(void*), void* argument, void* stack) +{ + int rc = syscall(SC_create_thread, entry, argument, stack); + __RETURN_WITH_ERRNO(rc, rc, -1); +} + +static void exit_thread(void* code) +{ + syscall(SC_exit_thread, code); + ASSERT_NOT_REACHED(); +} + int pthread_create(pthread_t* thread, pthread_attr_t* attributes, void* (*start_routine)(void*), void* argument_to_start_routine) { if (!thread) return -EINVAL; UNUSED_PARAM(attributes); - int rc = create_thread(start_routine, argument_to_start_routine); + const size_t stack_size = 4 * MB; + auto* stack = (u8*)mmap_with_name(nullptr, stack_size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS | MAP_STACK, 0, 0, "Thread stack"); + if (!stack) + return -1; + int rc = create_thread(start_routine, argument_to_start_routine, stack + stack_size); if (rc < 0) return rc; *thread = rc; @@ -55,5 +73,4 @@ int pthread_mutex_unlock(pthread_mutex_t* mutex) atomic->store(false, AK::memory_order_release); return 0; } - }