mirror of
https://github.com/RGBCube/serenity
synced 2025-05-15 12:44:58 +00:00
Kernel: Make sure we free the thread stack on thread exit
This adds two new arguments to the thread_exit system call which let a thread unmap an arbitrary VM range on thread exit. LibPthread uses this functionality to unmap the thread stack. Fixes #7267.
This commit is contained in:
parent
95c2166ca9
commit
42d667645d
4 changed files with 22 additions and 9 deletions
|
@ -379,7 +379,7 @@ public:
|
||||||
KResultOr<int> sys$sched_setparam(pid_t pid, Userspace<const struct sched_param*>);
|
KResultOr<int> sys$sched_setparam(pid_t pid, Userspace<const struct sched_param*>);
|
||||||
KResultOr<int> sys$sched_getparam(pid_t pid, Userspace<struct sched_param*>);
|
KResultOr<int> sys$sched_getparam(pid_t pid, Userspace<struct sched_param*>);
|
||||||
KResultOr<int> sys$create_thread(void* (*)(void*), Userspace<const Syscall::SC_create_thread_params*>);
|
KResultOr<int> sys$create_thread(void* (*)(void*), Userspace<const Syscall::SC_create_thread_params*>);
|
||||||
[[noreturn]] void sys$exit_thread(Userspace<void*>);
|
[[noreturn]] void sys$exit_thread(Userspace<void*>, Userspace<void*>, size_t);
|
||||||
KResultOr<int> sys$join_thread(pid_t tid, Userspace<void**> exit_value);
|
KResultOr<int> sys$join_thread(pid_t tid, Userspace<void**> exit_value);
|
||||||
KResultOr<int> sys$detach_thread(pid_t tid);
|
KResultOr<int> sys$detach_thread(pid_t tid);
|
||||||
KResultOr<int> sys$set_thread_name(pid_t tid, Userspace<const char*> buffer, size_t buffer_size);
|
KResultOr<int> sys$set_thread_name(pid_t tid, Userspace<const char*> buffer, size_t buffer_size);
|
||||||
|
|
|
@ -97,7 +97,7 @@ KResultOr<FlatPtr> handle(RegisterState& regs, FlatPtr function, FlatPtr arg1, F
|
||||||
process.sys$exit(arg1);
|
process.sys$exit(arg1);
|
||||||
break;
|
break;
|
||||||
case SC_exit_thread:
|
case SC_exit_thread:
|
||||||
process.sys$exit_thread(arg1);
|
process.sys$exit_thread(arg1, arg2, arg3);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
VERIFY_NOT_REACHED();
|
VERIFY_NOT_REACHED();
|
||||||
|
|
|
@ -78,7 +78,7 @@ KResultOr<int> Process::sys$create_thread(void* (*entry)(void*), Userspace<const
|
||||||
return thread->tid().value();
|
return thread->tid().value();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Process::sys$exit_thread(Userspace<void*> exit_value)
|
void Process::sys$exit_thread(Userspace<void*> exit_value, Userspace<void*> stack_location, size_t stack_size)
|
||||||
{
|
{
|
||||||
REQUIRE_PROMISE(thread);
|
REQUIRE_PROMISE(thread);
|
||||||
|
|
||||||
|
@ -90,6 +90,12 @@ void Process::sys$exit_thread(Userspace<void*> exit_value)
|
||||||
auto current_thread = Thread::current();
|
auto current_thread = Thread::current();
|
||||||
PerformanceManager::add_thread_exit_event(*current_thread);
|
PerformanceManager::add_thread_exit_event(*current_thread);
|
||||||
|
|
||||||
|
if (stack_location) {
|
||||||
|
auto unmap_result = space().unmap_mmap_range(VirtualAddress { stack_location }, stack_size);
|
||||||
|
if (unmap_result.is_error())
|
||||||
|
dbgln("Failed to unmap thread stack, terminating thread anyway. Error code: {}", unmap_result.error());
|
||||||
|
}
|
||||||
|
|
||||||
current_thread->exit(reinterpret_cast<void*>(exit_value.ptr()));
|
current_thread->exit(reinterpret_cast<void*>(exit_value.ptr()));
|
||||||
VERIFY_NOT_REACHED();
|
VERIFY_NOT_REACHED();
|
||||||
}
|
}
|
||||||
|
|
|
@ -33,13 +33,18 @@ static constexpr size_t required_stack_alignment = 4 * MiB;
|
||||||
static constexpr size_t highest_reasonable_guard_size = 32 * PAGE_SIZE;
|
static constexpr size_t highest_reasonable_guard_size = 32 * PAGE_SIZE;
|
||||||
static constexpr size_t highest_reasonable_stack_size = 8 * MiB; // That's the default in Ubuntu?
|
static constexpr size_t highest_reasonable_stack_size = 8 * MiB; // That's the default in Ubuntu?
|
||||||
|
|
||||||
|
__thread void* s_stack_location;
|
||||||
|
__thread size_t s_stack_size;
|
||||||
|
|
||||||
#define __RETURN_PTHREAD_ERROR(rc) \
|
#define __RETURN_PTHREAD_ERROR(rc) \
|
||||||
return ((rc) < 0 ? -(rc) : 0)
|
return ((rc) < 0 ? -(rc) : 0)
|
||||||
|
|
||||||
extern "C" {
|
extern "C" {
|
||||||
|
|
||||||
static void* pthread_create_helper(void* (*routine)(void*), void* argument)
|
static void* pthread_create_helper(void* (*routine)(void*), void* argument, void* stack_location, size_t stack_size)
|
||||||
{
|
{
|
||||||
|
s_stack_location = stack_location;
|
||||||
|
s_stack_size = stack_size;
|
||||||
void* ret_val = routine(argument);
|
void* ret_val = routine(argument);
|
||||||
pthread_exit(ret_val);
|
pthread_exit(ret_val);
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
@ -57,10 +62,12 @@ static int create_thread(pthread_t* thread, void* (*entry)(void*), void* argumen
|
||||||
|
|
||||||
// We set up the stack for pthread_create_helper.
|
// We set up the stack for pthread_create_helper.
|
||||||
// Note that we need to align the stack to 16B, accounting for
|
// Note that we need to align the stack to 16B, accounting for
|
||||||
// the fact that we also push 8 bytes.
|
// the fact that we also push 16 bytes.
|
||||||
while (((uintptr_t)stack - 8) % 16 != 0)
|
while (((uintptr_t)stack - 16) % 16 != 0)
|
||||||
push_on_stack(nullptr);
|
push_on_stack(nullptr);
|
||||||
|
|
||||||
|
push_on_stack((void*)thread_params->m_stack_size);
|
||||||
|
push_on_stack(thread_params->m_stack_location);
|
||||||
push_on_stack(argument);
|
push_on_stack(argument);
|
||||||
push_on_stack((void*)entry);
|
push_on_stack((void*)entry);
|
||||||
VERIFY((uintptr_t)stack % 16 == 0);
|
VERIFY((uintptr_t)stack % 16 == 0);
|
||||||
|
@ -74,10 +81,10 @@ static int create_thread(pthread_t* thread, void* (*entry)(void*), void* argumen
|
||||||
__RETURN_PTHREAD_ERROR(rc);
|
__RETURN_PTHREAD_ERROR(rc);
|
||||||
}
|
}
|
||||||
|
|
||||||
[[noreturn]] static void exit_thread(void* code)
|
[[noreturn]] static void exit_thread(void* code, void* stack_location, size_t stack_size)
|
||||||
{
|
{
|
||||||
__pthread_key_destroy_for_current_thread();
|
__pthread_key_destroy_for_current_thread();
|
||||||
syscall(SC_exit_thread, code);
|
syscall(SC_exit_thread, code, stack_location, stack_size);
|
||||||
VERIFY_NOT_REACHED();
|
VERIFY_NOT_REACHED();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -119,7 +126,7 @@ int pthread_create(pthread_t* thread, pthread_attr_t* attributes, void* (*start_
|
||||||
|
|
||||||
void pthread_exit(void* value_ptr)
|
void pthread_exit(void* value_ptr)
|
||||||
{
|
{
|
||||||
exit_thread(value_ptr);
|
exit_thread(value_ptr, s_stack_location, s_stack_size);
|
||||||
}
|
}
|
||||||
|
|
||||||
void pthread_cleanup_push([[maybe_unused]] void (*routine)(void*), [[maybe_unused]] void* arg)
|
void pthread_cleanup_push([[maybe_unused]] void (*routine)(void*), [[maybe_unused]] void* arg)
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue