From b8567d7a9da05b713f7e359d962878e433295097 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?kleines=20Filmr=C3=B6llchen?= Date: Sun, 24 Jul 2022 16:00:51 +0200 Subject: [PATCH] Kernel: Make scheduler control syscalls more generic The syscalls are renamed as they no longer reflect the exact POSIX functionality. They can now handle setting/getting scheduler parameters for both threads and processes. --- Kernel/API/Syscall.h | 16 +++- Kernel/Process.h | 6 +- Kernel/Syscalls/sched.cpp | 75 +++++++++++++------ .../DevTools/UserspaceEmulator/Emulator.h | 4 +- .../UserspaceEmulator/Emulator_syscalls.cpp | 20 ++--- Userland/Libraries/LibC/sched.cpp | 16 +++- 6 files changed, 95 insertions(+), 42 deletions(-) diff --git a/Kernel/API/Syscall.h b/Kernel/API/Syscall.h index 365ab9c79bd..3603f5f87e4 100644 --- a/Kernel/API/Syscall.h +++ b/Kernel/API/Syscall.h @@ -8,6 +8,7 @@ #include #include +#include constexpr int syscall_vector = 0x82; @@ -145,8 +146,8 @@ enum class NeedsBigProcessLock { S(recvmsg, NeedsBigProcessLock::Yes) \ S(rename, NeedsBigProcessLock::No) \ S(rmdir, NeedsBigProcessLock::No) \ - S(sched_getparam, NeedsBigProcessLock::No) \ - S(sched_setparam, NeedsBigProcessLock::No) \ + S(scheduler_get_parameters, NeedsBigProcessLock::No) \ + S(scheduler_set_parameters, NeedsBigProcessLock::No) \ S(sendfd, NeedsBigProcessLock::No) \ S(sendmsg, NeedsBigProcessLock::Yes) \ S(set_coredump_metadata, NeedsBigProcessLock::No) \ @@ -480,6 +481,17 @@ struct SC_chmod_params { int follow_symlinks; }; +enum class SchedulerParametersMode : bool { + Process, + Thread, +}; + +struct SC_scheduler_parameters_params { + pid_t pid_or_tid; + SchedulerParametersMode mode; + struct sched_param parameters; +}; + void initialize(); int sync(); diff --git a/Kernel/Process.h b/Kernel/Process.h index b783d8c7a0c..e84a82d890b 100644 --- a/Kernel/Process.h +++ b/Kernel/Process.h @@ -400,8 +400,8 @@ public: ErrorOr sys$getsockname(Userspace); ErrorOr sys$getpeername(Userspace); ErrorOr sys$socketpair(Userspace); - ErrorOr sys$sched_setparam(pid_t pid, Userspace); - ErrorOr sys$sched_getparam(pid_t pid, Userspace); + ErrorOr sys$scheduler_set_parameters(Userspace); + ErrorOr sys$scheduler_get_parameters(Userspace); ErrorOr sys$create_thread(void* (*)(void*), Userspace); [[noreturn]] void sys$exit_thread(Userspace, Userspace, size_t); ErrorOr sys$join_thread(pid_t tid, Userspace exit_value); @@ -840,6 +840,8 @@ private: SpinlockProtected& thread_list() { return m_thread_list; } SpinlockProtected const& thread_list() const { return m_thread_list; } + ErrorOr> get_thread_from_pid_or_tid(pid_t pid_or_tid, Syscall::SchedulerParametersMode mode); + SpinlockProtected m_thread_list { LockRank::None }; MutexProtected m_fds; diff --git a/Kernel/Syscalls/sched.cpp b/Kernel/Syscalls/sched.cpp index d90d9354452..57b38d0ce96 100644 --- a/Kernel/Syscalls/sched.cpp +++ b/Kernel/Syscalls/sched.cpp @@ -1,9 +1,11 @@ /* * Copyright (c) 2018-2020, Andreas Kling + * Copyright (c) 2022, kleines Filmröllchen * * SPDX-License-Identifier: BSD-2-Clause */ +#include #include #include @@ -17,48 +19,75 @@ ErrorOr Process::sys$yield() return 0; } -ErrorOr Process::sys$sched_setparam(int pid, Userspace user_param) +ErrorOr> Process::get_thread_from_pid_or_tid(pid_t pid_or_tid, Syscall::SchedulerParametersMode mode) +{ + VERIFY(g_scheduler_lock.is_locked_by_current_processor()); + Thread* peer; + switch (mode) { + case Syscall::SchedulerParametersMode::Thread: { + peer = Thread::current(); + if (pid_or_tid != 0) + peer = Thread::from_tid(pid_or_tid); + + break; + } + case Syscall::SchedulerParametersMode::Process: { + auto* searched_process = this; + if (pid_or_tid != 0) + searched_process = Process::from_pid(pid_or_tid); + + if (searched_process == nullptr) + return ESRCH; + auto pid = searched_process->pid().value(); + // Main thread has tid == pid + this->thread_list().for_each([&](auto& thread) { + if (thread.tid().value() == pid) + peer = &thread; + }); + break; + } + default: + VERIFY_NOT_REACHED(); + } + if (!peer) + return ESRCH; + return NonnullRefPtr { *peer }; +} + +ErrorOr Process::sys$scheduler_set_parameters(Userspace user_param) { VERIFY_NO_PROCESS_BIG_LOCK(this); TRY(require_promise(Pledge::proc)); - auto param = TRY(copy_typed_from_user(user_param)); + auto parameters = TRY(copy_typed_from_user(user_param)); - if (param.sched_priority < THREAD_PRIORITY_MIN || param.sched_priority > THREAD_PRIORITY_MAX) + if (parameters.parameters.sched_priority < THREAD_PRIORITY_MIN || parameters.parameters.sched_priority > THREAD_PRIORITY_MAX) return EINVAL; - auto* peer = Thread::current(); SpinlockLocker lock(g_scheduler_lock); - if (pid != 0) - peer = Thread::from_tid(pid); - - if (!peer) - return ESRCH; + auto peer = TRY(get_thread_from_pid_or_tid(parameters.pid_or_tid, parameters.mode)); auto credentials = this->credentials(); auto peer_credentials = peer->process().credentials(); if (!credentials->is_superuser() && credentials->euid() != peer_credentials->uid() && credentials->uid() != peer_credentials->uid()) return EPERM; - peer->set_priority((u32)param.sched_priority); + // FIXME: Only sets priority for main thread of process if mode == PROCESS + peer->set_priority((u32)parameters.parameters.sched_priority); return 0; } -ErrorOr Process::sys$sched_getparam(pid_t pid, Userspace user_param) +ErrorOr Process::sys$scheduler_get_parameters(Userspace user_param) { VERIFY_NO_PROCESS_BIG_LOCK(this); TRY(require_promise(Pledge::proc)); + + Syscall::SC_scheduler_parameters_params parameters; + TRY(copy_from_user(¶meters, user_param)); + int priority; { - auto* peer = Thread::current(); SpinlockLocker lock(g_scheduler_lock); - if (pid != 0) { - // FIXME: PID/TID BUG - // The entire process is supposed to be affected. - peer = Thread::from_tid(pid); - } - - if (!peer) - return ESRCH; + auto peer = TRY(get_thread_from_pid_or_tid(parameters.pid_or_tid, parameters.mode)); auto credentials = this->credentials(); auto peer_credentials = peer->process().credentials(); @@ -68,11 +97,9 @@ ErrorOr Process::sys$sched_getparam(pid_t pid, Userspacepriority(); } - struct sched_param param { - priority - }; + parameters.parameters.sched_priority = priority; - TRY(copy_to_user(user_param, ¶m)); + TRY(copy_to_user(user_param, ¶meters)); return 0; } diff --git a/Userland/DevTools/UserspaceEmulator/Emulator.h b/Userland/DevTools/UserspaceEmulator/Emulator.h index 4f53aa50c85..fe7ae3efe2d 100644 --- a/Userland/DevTools/UserspaceEmulator/Emulator.h +++ b/Userland/DevTools/UserspaceEmulator/Emulator.h @@ -222,8 +222,8 @@ private: int virt$recvmsg(int sockfd, FlatPtr msg_addr, int flags); int virt$rename(FlatPtr address); int virt$rmdir(FlatPtr path, size_t path_length); - int virt$sched_getparam(pid_t, FlatPtr); - int virt$sched_setparam(int, FlatPtr); + int virt$scheduler_get_parameters(FlatPtr); + int virt$scheduler_set_parameters(FlatPtr); int virt$sendfd(int, int); int virt$sendmsg(int sockfd, FlatPtr msg_addr, int flags); int virt$set_coredump_metadata(FlatPtr address); diff --git a/Userland/DevTools/UserspaceEmulator/Emulator_syscalls.cpp b/Userland/DevTools/UserspaceEmulator/Emulator_syscalls.cpp index 6e7c741f606..ddd44cccb0f 100644 --- a/Userland/DevTools/UserspaceEmulator/Emulator_syscalls.cpp +++ b/Userland/DevTools/UserspaceEmulator/Emulator_syscalls.cpp @@ -201,10 +201,10 @@ u32 Emulator::virt_syscall(u32 function, u32 arg1, u32 arg2, u32 arg3) return virt$rename(arg1); case SC_rmdir: return virt$rmdir(arg1, arg2); - case SC_sched_getparam: - return virt$sched_getparam(arg1, arg2); - case SC_sched_setparam: - return virt$sched_setparam(arg1, arg2); + case SC_scheduler_get_parameters: + return virt$scheduler_get_parameters(arg1); + case SC_scheduler_set_parameters: + return virt$scheduler_set_parameters(arg1); case SC_sendfd: return virt$sendfd(arg1, arg2); case SC_sendmsg: @@ -1504,20 +1504,20 @@ int Emulator::virt$dup2(int old_fd, int new_fd) return syscall(SC_dup2, old_fd, new_fd); } -int Emulator::virt$sched_getparam(pid_t pid, FlatPtr user_addr) +int Emulator::virt$scheduler_get_parameters(FlatPtr user_addr) { - sched_param user_param; + Syscall::SC_scheduler_parameters_params user_param; mmu().copy_from_vm(&user_param, user_addr, sizeof(user_param)); - auto rc = syscall(SC_sched_getparam, pid, &user_param); + auto rc = syscall(SC_scheduler_get_parameters, &user_param); mmu().copy_to_vm(user_addr, &user_param, sizeof(user_param)); return rc; } -int Emulator::virt$sched_setparam(int pid, FlatPtr user_addr) +int Emulator::virt$scheduler_set_parameters(FlatPtr user_addr) { - sched_param user_param; + Syscall::SC_scheduler_parameters_params user_param; mmu().copy_from_vm(&user_param, user_addr, sizeof(user_param)); - return syscall(SC_sched_setparam, pid, &user_param); + return syscall(SC_scheduler_set_parameters, &user_param); } int Emulator::virt$set_thread_name(pid_t pid, FlatPtr name_addr, size_t name_length) diff --git a/Userland/Libraries/LibC/sched.cpp b/Userland/Libraries/LibC/sched.cpp index 574d85d7eb7..4d1cb46737d 100644 --- a/Userland/Libraries/LibC/sched.cpp +++ b/Userland/Libraries/LibC/sched.cpp @@ -32,14 +32,26 @@ int sched_get_priority_max([[maybe_unused]] int policy) // https://pubs.opengroup.org/onlinepubs/9699919799/functions/sched_setparam.html int sched_setparam(pid_t pid, const struct sched_param* param) { - int rc = syscall(SC_sched_setparam, pid, param); + Syscall::SC_scheduler_parameters_params parameters { + .pid_or_tid = pid, + .mode = Syscall::SchedulerParametersMode::Process, + .parameters = *param, + }; + int rc = syscall(SC_scheduler_set_parameters, ¶meters); __RETURN_WITH_ERRNO(rc, rc, -1); } // https://pubs.opengroup.org/onlinepubs/9699919799/functions/sched_getparam.html int sched_getparam(pid_t pid, struct sched_param* param) { - int rc = syscall(SC_sched_getparam, pid, param); + Syscall::SC_scheduler_parameters_params parameters { + .pid_or_tid = pid, + .mode = Syscall::SchedulerParametersMode::Process, + .parameters = {}, + }; + int rc = syscall(SC_scheduler_get_parameters, ¶meters); + if (rc == 0) + *param = parameters.parameters; __RETURN_WITH_ERRNO(rc, rc, -1); } }