فهرست منبع

LibPthread: implicitly call pthread_exit on return from start routine.

Previously, when returning from a pthread's start_routine, we would
segfault. Now we instead implicitly call pthread_exit as specified in
the standard.

pthread_create now creates a thread running the new
pthread_create_helper, which properly manages the calling and exiting
of the start_routine supplied to pthread_create. To accomplish this,
the thread's stack initialization has been moved out of
sys$create_thread and into the userspace function create_thread.
Drew Stratford 5 سال پیش
والد
کامیت
4a37362249
3فایلهای تغییر یافته به همراه32 افزوده شده و 8 حذف شده
  1. 1 5
      Kernel/Process.cpp
  2. 1 1
      Kernel/Process.h
  3. 30 2
      Libraries/LibPthread/pthread.cpp

+ 1 - 5
Kernel/Process.cpp

@@ -3754,7 +3754,7 @@ void Process::send_signal(u8 signal, Process* sender)
     thread->send_signal(signal, sender);
 }
 
-int Process::sys$create_thread(void* (*entry)(void*), void* argument, const Syscall::SC_create_thread_params* user_params)
+int Process::sys$create_thread(void* (*entry)(void*), const Syscall::SC_create_thread_params* user_params)
 {
     REQUIRE_PROMISE(thread);
     if (!validate_read((const void*)entry, sizeof(void*)))
@@ -3806,10 +3806,6 @@ int Process::sys$create_thread(void* (*entry)(void*), void* argument, const Sysc
     tss.cr3 = page_directory().cr3();
     tss.esp = user_stack_address;
 
-    // NOTE: The stack needs to be 16-byte aligned.
-    thread->push_value_on_stack((FlatPtr)argument);
-    thread->push_value_on_stack(0);
-
     thread->make_thread_specific_region({});
     thread->set_state(Thread::State::Runnable);
     return thread->tid();

+ 1 - 1
Kernel/Process.h

@@ -272,7 +272,7 @@ public:
     int sys$getpeername(const Syscall::SC_getpeername_params*);
     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$create_thread(void* (*)(void*), void* argument, const Syscall::SC_create_thread_params*);
+    int sys$create_thread(void* (*)(void*), const Syscall::SC_create_thread_params*);
     void sys$exit_thread(void*);
     int sys$join_thread(int tid, void** exit_value);
     int sys$detach_thread(int tid);

+ 30 - 2
Libraries/LibPthread/pthread.cpp

@@ -50,9 +50,37 @@ constexpr size_t highest_reasonable_stack_size = 8 * MB; // That's the default i
 
 extern "C" {
 
-static int create_thread(void* (*entry)(void*), void* argument, void* thread_params)
+static void* pthread_create_helper(void* (*routine)(void*), void* argument)
 {
-    return syscall(SC_create_thread, entry, argument, thread_params);
+    void* ret_val = routine(argument);
+    pthread_exit(ret_val);
+    return nullptr;
+}
+
+static int create_thread(void* (*entry)(void*), void* argument, PthreadAttrImpl* thread_params)
+{
+    void** stack = (void**)((uintptr_t)thread_params->m_stack_location + thread_params->m_stack_size);
+
+    auto push_on_stack = [&](void* data) {
+        stack--;
+        *stack = data;
+        thread_params->m_stack_size -= sizeof(void*);
+    };
+
+    // 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)
+        push_on_stack(nullptr);
+
+    push_on_stack(argument);
+    push_on_stack((void*)entry);
+    ASSERT((uintptr_t)stack % 16 == 0);
+
+    // Push a fake return address
+    push_on_stack(nullptr);
+
+    return syscall(SC_create_thread, pthread_create_helper, thread_params);
 }
 
 static void exit_thread(void* code)