Serenity Operating System
at master 234 lines 7.0 kB view raw
1/* 2 * Copyright (c) 2018-2021, Andreas Kling <kling@serenityos.org> 3 * 4 * SPDX-License-Identifier: BSD-2-Clause 5 */ 6 7#include <AK/Checked.h> 8#include <Kernel/Memory/MemoryManager.h> 9#include <Kernel/PerformanceManager.h> 10#include <Kernel/Process.h> 11#include <Kernel/Scheduler.h> 12 13namespace Kernel { 14 15ErrorOr<FlatPtr> Process::sys$create_thread(void* (*entry)(void*), Userspace<Syscall::SC_create_thread_params const*> user_params) 16{ 17 VERIFY_PROCESS_BIG_LOCK_ACQUIRED(this); 18 TRY(require_promise(Pledge::thread)); 19 auto params = TRY(copy_typed_from_user(user_params)); 20 21 unsigned detach_state = params.detach_state; 22 int schedule_priority = params.schedule_priority; 23 unsigned stack_size = params.stack_size; 24 25 auto user_sp = Checked<FlatPtr>((FlatPtr)params.stack_location); 26 user_sp += stack_size; 27 if (user_sp.has_overflow()) 28 return EOVERFLOW; 29 30 TRY(address_space().with([&](auto& space) -> ErrorOr<void> { 31 if (!MM.validate_user_stack(*space, VirtualAddress(user_sp.value() - 4))) 32 return EFAULT; 33 return {}; 34 })); 35 36 // FIXME: return EAGAIN if Thread::all_threads().size() is greater than PTHREAD_THREADS_MAX 37 38 int requested_thread_priority = schedule_priority; 39 if (requested_thread_priority < THREAD_PRIORITY_MIN || requested_thread_priority > THREAD_PRIORITY_MAX) 40 return EINVAL; 41 42 bool is_thread_joinable = (0 == detach_state); 43 44 // FIXME: Do something with guard pages? 45 46 auto thread = TRY(Thread::try_create(*this)); 47 48 // We know this thread is not the main_thread, 49 // So give it a unique name until the user calls $set_thread_name on it 50 auto new_thread_name = TRY(name().with([&](auto& process_name) { 51 return KString::formatted("{} [{}]", process_name->view(), thread->tid().value()); 52 })); 53 thread->set_name(move(new_thread_name)); 54 55 if (!is_thread_joinable) 56 thread->detach(); 57 58 auto& regs = thread->regs(); 59 regs.set_ip((FlatPtr)entry); 60 regs.set_sp(user_sp.value()); 61 62#if ARCH(X86_64) 63 regs.set_flags(0x0202); 64 regs.cr3 = address_space().with([](auto& space) { return space->page_directory().cr3(); }); 65 66 regs.rdi = params.rdi; 67 regs.rsi = params.rsi; 68 regs.rdx = params.rdx; 69 regs.rcx = params.rcx; 70#endif 71 72 TRY(thread->make_thread_specific_region({})); 73 74 PerformanceManager::add_thread_created_event(*thread); 75 76 SpinlockLocker lock(g_scheduler_lock); 77 thread->set_priority(requested_thread_priority); 78 thread->set_state(Thread::State::Runnable); 79 return thread->tid().value(); 80} 81 82void Process::sys$exit_thread(Userspace<void*> exit_value, Userspace<void*> stack_location, size_t stack_size) 83{ 84 VERIFY_PROCESS_BIG_LOCK_ACQUIRED(this); 85 86 auto result = require_promise(Pledge::thread); 87 if (result.is_error()) { 88 // Crash now, as we will never reach back to the syscall handler. 89 crash(SIGABRT, {}); 90 } 91 92 if (this->thread_count() == 1) { 93 // If this is the last thread, instead kill the process. 94 this->sys$exit(0); 95 } 96 97 auto* current_thread = Thread::current(); 98 current_thread->set_profiling_suppressed(); 99 PerformanceManager::add_thread_exit_event(*current_thread); 100 101 if (stack_location) { 102 auto unmap_result = address_space().with([&](auto& space) { 103 return space->unmap_mmap_range(stack_location.vaddr(), stack_size); 104 }); 105 if (unmap_result.is_error()) 106 dbgln("Failed to unmap thread stack, terminating thread anyway. Error code: {}", unmap_result.error()); 107 } 108 109 current_thread->exit(reinterpret_cast<void*>(exit_value.ptr())); 110 VERIFY_NOT_REACHED(); 111} 112 113ErrorOr<FlatPtr> Process::sys$detach_thread(pid_t tid) 114{ 115 VERIFY_PROCESS_BIG_LOCK_ACQUIRED(this); 116 TRY(require_promise(Pledge::thread)); 117 auto thread = Thread::from_tid(tid); 118 if (!thread || thread->pid() != pid()) 119 return ESRCH; 120 121 if (!thread->is_joinable()) 122 return EINVAL; 123 124 thread->detach(); 125 return 0; 126} 127 128ErrorOr<FlatPtr> Process::sys$join_thread(pid_t tid, Userspace<void**> exit_value) 129{ 130 VERIFY_PROCESS_BIG_LOCK_ACQUIRED(this); 131 TRY(require_promise(Pledge::thread)); 132 133 auto thread = Thread::from_tid(tid); 134 if (!thread || thread->pid() != pid()) 135 return ESRCH; 136 137 auto* current_thread = Thread::current(); 138 if (thread == current_thread) 139 return EDEADLK; 140 141 void* joinee_exit_value = nullptr; 142 143 // NOTE: pthread_join() cannot be interrupted by signals. Only by death. 144 for (;;) { 145 ErrorOr<void> try_join_result; 146 auto result = current_thread->block<Thread::JoinBlocker>({}, *thread, try_join_result, joinee_exit_value); 147 if (result == Thread::BlockResult::NotBlocked) { 148 if (try_join_result.is_error()) 149 return try_join_result.release_error(); 150 break; 151 } 152 if (result == Thread::BlockResult::InterruptedByDeath) 153 break; 154 dbgln("join_thread: retrying"); 155 } 156 157 if (exit_value) 158 TRY(copy_to_user(exit_value, &joinee_exit_value)); 159 160 return 0; 161} 162 163ErrorOr<FlatPtr> Process::sys$kill_thread(pid_t tid, int signal) 164{ 165 VERIFY_PROCESS_BIG_LOCK_ACQUIRED(this); 166 TRY(require_promise(Pledge::thread)); 167 168 if (signal < 0 || signal >= NSIG) 169 return EINVAL; 170 171 auto thread = Thread::from_tid(tid); 172 if (!thread || thread->pid() != pid()) 173 return ESRCH; 174 175 if (signal != 0) 176 thread->send_signal(signal, &Process::current()); 177 178 return 0; 179} 180 181ErrorOr<FlatPtr> Process::sys$set_thread_name(pid_t tid, Userspace<char const*> user_name, size_t user_name_length) 182{ 183 VERIFY_NO_PROCESS_BIG_LOCK(this); 184 TRY(require_promise(Pledge::stdio)); 185 186 auto name = TRY(try_copy_kstring_from_user(user_name, user_name_length)); 187 188 const size_t max_thread_name_size = 64; 189 if (name->length() > max_thread_name_size) 190 return ENAMETOOLONG; 191 192 auto thread = Thread::from_tid(tid); 193 if (!thread || thread->pid() != pid()) 194 return ESRCH; 195 196 thread->set_name(move(name)); 197 return 0; 198} 199 200ErrorOr<FlatPtr> Process::sys$get_thread_name(pid_t tid, Userspace<char*> buffer, size_t buffer_size) 201{ 202 VERIFY_NO_PROCESS_BIG_LOCK(this); 203 TRY(require_promise(Pledge::thread)); 204 if (buffer_size == 0) 205 return EINVAL; 206 207 auto thread = Thread::from_tid(tid); 208 if (!thread || thread->pid() != pid()) 209 return ESRCH; 210 211 TRY(thread->name().with([&](auto& thread_name) -> ErrorOr<void> { 212 if (thread_name->view().is_null()) { 213 char null_terminator = '\0'; 214 TRY(copy_to_user(buffer, &null_terminator, sizeof(null_terminator))); 215 return {}; 216 } 217 218 if (thread_name->length() + 1 > buffer_size) 219 return ENAMETOOLONG; 220 221 return copy_to_user(buffer, thread_name->characters(), thread_name->length() + 1); 222 })); 223 224 return 0; 225} 226 227ErrorOr<FlatPtr> Process::sys$gettid() 228{ 229 VERIFY_NO_PROCESS_BIG_LOCK(this); 230 TRY(require_promise(Pledge::stdio)); 231 return Thread::current()->tid().value(); 232} 233 234}