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.
This commit is contained in:
Andreas Kling 2019-11-17 17:28:17 +01:00
parent 6685be36a0
commit e34ed04d1e
Notes: sideshowbarker 2024-07-19 11:10:50 +09:00
7 changed files with 30 additions and 33 deletions

View file

@ -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();

View file

@ -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);

View file

@ -601,18 +601,6 @@ void Thread::make_userspace_stack_for_main_thread(Vector<String> 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);

View file

@ -325,7 +325,6 @@ public:
void set_default_signal_dispositions();
void push_value_on_stack(u32);
void make_userspace_stack_for_main_thread(Vector<String> arguments, Vector<String> environment);
void make_userspace_stack_for_secondary_thread(void* argument);
void make_thread_specific_region(Badge<Process>);

View file

@ -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);

View file

@ -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);

View file

@ -1,18 +1,36 @@
#include <AK/Assertions.h>
#include <AK/Atomic.h>
#include <AK/StdLibExtras.h>
#include <Kernel/Syscall.h>
#include <pthread.h>
#include <unistd.h>
#include <stdio.h>
#include <sys/mman.h>
#include <unistd.h>
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;
}
}