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:
@@ -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();
|
||||||
|
|||||||
@@ -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())
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|||||||
Reference in New Issue
Block a user