Kernel/LibC: Allocate thread stacks in userspace

This adds support for pthread function for stack manipulation.

Also keep track of main threads stack in the uthread
This commit is contained in:
2026-07-02 19:43:55 +03:00
parent 7bdd9d19d0
commit 0dc74beb0f
5 changed files with 51 additions and 25 deletions

View File

@@ -209,7 +209,7 @@ namespace Kernel
BAN::ErrorOr<long> sys_set_gsbase(void*); BAN::ErrorOr<long> sys_set_gsbase(void*);
BAN::ErrorOr<long> sys_get_gsbase(); BAN::ErrorOr<long> sys_get_gsbase();
BAN::ErrorOr<long> sys_thread_create(void (*entry)(void*), void* arg); BAN::ErrorOr<long> sys_thread_create(void (*entry)(void*), void* arg, void* stack_base, size_t stack_size);
BAN::ErrorOr<long> sys_thread_exit(void* value); BAN::ErrorOr<long> sys_thread_exit(void* value);
BAN::ErrorOr<long> sys_thread_join(pid_t tid, void** value); BAN::ErrorOr<long> sys_thread_join(pid_t tid, void** value);
BAN::ErrorOr<long> sys_thread_getid(); BAN::ErrorOr<long> sys_thread_getid();

View File

@@ -3549,20 +3549,14 @@ namespace Kernel
return Thread::current().get_gsbase(); return Thread::current().get_gsbase();
} }
BAN::ErrorOr<long> Process::sys_thread_create(void (*entry)(void*), void* arg) BAN::ErrorOr<long> Process::sys_thread_create(void (*entry)(void*), void* arg, void* stack_base, size_t stack_size)
{ {
auto userspace_stack = TRY(MemoryBackedRegion::create( const vaddr_t stack_vaddr = reinterpret_cast<vaddr_t>(stack_base);
page_table(), if (stack_vaddr % PAGE_SIZE || stack_size % PAGE_SIZE)
Thread::userspace_stack_size, return BAN::Error::from_errno(EINVAL);
{ Thread::userspace_stack_base, USERSPACE_END },
MemoryRegion::Type::PRIVATE,
PageTable::UserSupervisor | PageTable::ReadWrite | PageTable::Present,
O_RDWR
));
const vaddr_t stack_vaddr = userspace_stack->vaddr(); auto* memory_region = TRY(validate_and_pin_pointer_access(stack_base, stack_size, true));
const size_t stack_size = userspace_stack->size(); BAN::ScopeGuard _0([memory_region] { if (memory_region) memory_region->unpin(); });
TRY(add_mapped_region(BAN::move(userspace_stack)));
const vaddr_t initial_stack_pointer = stack_vaddr + stack_size - sizeof(void*); const vaddr_t initial_stack_pointer = stack_vaddr + stack_size - sizeof(void*);
*reinterpret_cast<void**>(initial_stack_pointer) = arg; *reinterpret_cast<void**>(initial_stack_pointer) = arg;
@@ -3577,7 +3571,7 @@ namespace Kernel
)); ));
thread->m_signal_block_mask = Thread::current().m_signal_block_mask; thread->m_signal_block_mask = Thread::current().m_signal_block_mask;
LockGuard _(m_process_lock); LockGuard _1(m_process_lock);
TRY(m_threads.push_back(thread)); TRY(m_threads.push_back(thread));
if (auto ret = Processor::scheduler().add_thread(thread); ret.is_error()) if (auto ret = Processor::scheduler().add_thread(thread); ret.is_error())

View File

@@ -16,6 +16,7 @@ typedef struct
int schedpolicy; int schedpolicy;
int detachstate; int detachstate;
int scope; int scope;
void* stackaddr;
size_t stacksize; size_t stacksize;
size_t guardsize; size_t guardsize;
} pthread_attr_t; } pthread_attr_t;

View File

@@ -49,6 +49,7 @@ struct uthread
pid_t id; pid_t id;
pthread_attr_t attr; pthread_attr_t attr;
int errno_; int errno_;
int libc_owns_stack;
int cancel_type; int cancel_type;
int cancel_state; int cancel_state;
volatile int canceled; volatile int canceled;

View File

@@ -7,6 +7,7 @@
#include <pthread.h> #include <pthread.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <sys/auxv.h>
#include <sys/futex.h> #include <sys/futex.h>
#include <sys/mman.h> #include <sys/mman.h>
#include <sys/syscall.h> #include <sys/syscall.h>
@@ -36,6 +37,7 @@ static void _init_pthread()
uthread->id = syscall(SYS_THREAD_GETID); uthread->id = syscall(SYS_THREAD_GETID);
uthread->attr = s_default_pthread_attr; uthread->attr = s_default_pthread_attr;
uthread->errno_ = 0; uthread->errno_ = 0;
uthread->libc_owns_stack = false;
uthread->cancel_type = PTHREAD_CANCEL_DEFERRED; uthread->cancel_type = PTHREAD_CANCEL_DEFERRED;
uthread->cancel_state = PTHREAD_CANCEL_ENABLE; uthread->cancel_state = PTHREAD_CANCEL_ENABLE;
uthread->canceled = false; uthread->canceled = false;
@@ -43,6 +45,11 @@ static void _init_pthread()
memset(uthread->specific_keys, 0, sizeof(uthread->specific_keys)); memset(uthread->specific_keys, 0, sizeof(uthread->specific_keys));
memset(uthread->specific_vals, 0, sizeof(uthread->specific_vals)); memset(uthread->specific_vals, 0, sizeof(uthread->specific_vals));
if (auto value = getauxval(AT_STACK_BASE))
uthread->attr.stackaddr = reinterpret_cast<void*>(value);
if (auto value = getauxval(AT_STACK_SIZE))
uthread->attr.stacksize = value;
signal(SIGCANCEL, &_pthread_cancel_handler); signal(SIGCANCEL, &_pthread_cancel_handler);
} }
@@ -120,6 +127,9 @@ static void free_uthread(uthread* uthread)
munmap(reinterpret_cast<void*>(uthread->dtv[i]), size); munmap(reinterpret_cast<void*>(uthread->dtv[i]), size);
} }
if (uthread->libc_owns_stack)
munmap(static_cast<uint8_t*>(uthread->attr.stackaddr) - uthread->attr.guardsize, uthread->attr.guardsize + uthread->attr.stacksize);
uint8_t* tls_addr = reinterpret_cast<uint8_t*>(uthread) - uthread->master_tls_size; uint8_t* tls_addr = reinterpret_cast<uint8_t*>(uthread) - uthread->master_tls_size;
const size_t tls_size = uthread->master_tls_size + sizeof(struct uthread); const size_t tls_size = uthread->master_tls_size + sizeof(struct uthread);
munmap(tls_addr, tls_size); munmap(tls_addr, tls_size);
@@ -288,6 +298,8 @@ int pthread_attr_getguardsize(const pthread_attr_t* __restrict attr, size_t* __r
int pthread_attr_setguardsize(pthread_attr_t* attr, size_t guardsize) int pthread_attr_setguardsize(pthread_attr_t* attr, size_t guardsize)
{ {
if (auto rem = guardsize % getpagesize())
guardsize += getpagesize() - rem;
attr->guardsize = guardsize; attr->guardsize = guardsize;
return 0; return 0;
} }
@@ -364,20 +376,22 @@ int pthread_attr_setscope(pthread_attr_t* attr, int contentionscope)
int pthread_attr_getstack(const pthread_attr_t* __restrict attr, void** __restrict stackaddr, size_t* __restrict stacksize) int pthread_attr_getstack(const pthread_attr_t* __restrict attr, void** __restrict stackaddr, size_t* __restrict stacksize)
{ {
(void)attr; *stackaddr = attr->stackaddr;
(void)stackaddr; *stacksize = attr->stacksize;
(void)stacksize; return 0;
dwarnln("TODO: pthread_attr_getstack");
return ENOTSUP;
} }
int pthread_attr_setstack(pthread_attr_t* attr, void* stackaddr, size_t stacksize) int pthread_attr_setstack(pthread_attr_t* attr, void* stackaddr, size_t stacksize)
{ {
(void)attr; if (stacksize < PTHREAD_STACK_MIN)
(void)stackaddr; return EINVAL;
(void)stacksize; if (reinterpret_cast<uintptr_t>(stackaddr) % getpagesize())
dwarnln("TODO: pthread_attr_setstack"); return EINVAL;
return ENOTSUP; if (stacksize % getpagesize())
return EINVAL;
attr->stackaddr = stackaddr;
attr->stacksize = stacksize;
return 0;
} }
int pthread_attr_getstacksize(const pthread_attr_t* __restrict attr, size_t* __restrict stacksize) int pthread_attr_getstacksize(const pthread_attr_t* __restrict attr, size_t* __restrict stacksize)
@@ -433,6 +447,7 @@ int pthread_create(pthread_t* __restrict thread, const pthread_attr_t* __restric
.id = -1, .id = -1,
.attr = attr ? *attr : s_default_pthread_attr, .attr = attr ? *attr : s_default_pthread_attr,
.errno_ = 0, .errno_ = 0,
.libc_owns_stack = false,
.cancel_type = PTHREAD_CANCEL_DEFERRED, .cancel_type = PTHREAD_CANCEL_DEFERRED,
.cancel_state = PTHREAD_CANCEL_ENABLE, .cancel_state = PTHREAD_CANCEL_ENABLE,
.canceled = 0, .canceled = 0,
@@ -442,6 +457,21 @@ int pthread_create(pthread_t* __restrict thread, const pthread_attr_t* __restric
.dtv = { self->dtv[0] } .dtv = { self->dtv[0] }
}; };
if (uthread->attr.stackaddr == nullptr)
{
ASSERT(uthread->attr.stacksize % getpagesize() == 0);
ASSERT(uthread->attr.guardsize % getpagesize() == 0);
void* stack_addr = mmap(nullptr, uthread->attr.guardsize + uthread->attr.stacksize, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
if (stack_addr == nullptr)
goto pthread_create_error;
uthread->attr.stackaddr = static_cast<uint8_t*>(stack_addr) + uthread->attr.guardsize;
uthread->libc_owns_stack = true;
if (uthread->attr.guardsize != 0 && mprotect(stack_addr, uthread->attr.guardsize, PROT_NONE) == -1)
goto pthread_create_error;
}
const uintptr_t self_addr = reinterpret_cast<uintptr_t>(self); const uintptr_t self_addr = reinterpret_cast<uintptr_t>(self);
const uintptr_t uthread_addr = reinterpret_cast<uintptr_t>(uthread); const uintptr_t uthread_addr = reinterpret_cast<uintptr_t>(uthread);
for (size_t i = 1; i <= self->master_tls_module_count; i++) for (size_t i = 1; i <= self->master_tls_module_count; i++)
@@ -451,7 +481,7 @@ int pthread_create(pthread_t* __restrict thread, const pthread_attr_t* __restric
result = uthread; result = uthread;
} }
if (syscall(SYS_THREAD_CREATE, _pthread_trampoline, info) == -1) if (syscall(SYS_THREAD_CREATE, _pthread_trampoline, info, info->uthread->attr.stackaddr, info->uthread->attr.stacksize) == -1)
goto pthread_create_error; goto pthread_create_error;
if (thread) if (thread)