Browse Source

Kernel/LibC: Implement sched_* functionality to set/get process priority

Right now, we allow anything inside a user to raise or lower any other process's
priority. This feels simple enough to me. Linux disallows raising, but
that's annoying in practice.
Robin Burchell 6 years ago
parent
commit
9cd0f6ffac
8 changed files with 103 additions and 1 deletions
  1. 43 0
      Kernel/Process.cpp
  2. 4 0
      Kernel/Process.h
  3. 4 0
      Kernel/Syscall.cpp
  4. 3 1
      Kernel/Syscall.h
  5. 4 0
      Kernel/UnixTypes.h
  6. 24 0
      LibC/sched.cpp
  7. 15 0
      LibC/sched.h
  8. 6 0
      LibC/unistd.h

+ 43 - 0
Kernel/Process.cpp

@@ -2282,6 +2282,49 @@ int Process::sys$getpeername(int sockfd, sockaddr* addr, socklen_t* addrlen)
     return 0;
     return 0;
 }
 }
 
 
+int Process::sys$sched_setparam(pid_t pid, const struct sched_param* param)
+{
+    if (!validate_read_typed(param))
+        return -EFAULT;
+
+    InterruptDisabler disabler;
+    auto* peer = this;
+    if (pid != 0)
+        peer = Process::from_pid(pid);
+
+    if (!peer)
+        return -ESRCH;
+
+    if (!is_superuser() && m_euid != peer->m_uid && m_uid != peer->m_uid)
+        return -EPERM;
+
+    if (param->sched_priority < Process::FirstPriority || param->sched_priority > Process::LastPriority)
+        return -EINVAL;
+
+    peer->set_priority(Priority(param->sched_priority));
+    return 0;
+}
+
+int Process::sys$sched_getparam(pid_t pid, struct sched_param* param)
+{
+    if (!validate_read_typed(param))
+        return -EFAULT;
+
+    InterruptDisabler disabler;
+    auto* peer = this;
+    if (pid != 0)
+        peer = Process::from_pid(pid);
+
+    if (!peer)
+        return -ESRCH;
+
+    if (!is_superuser() && m_euid != peer->m_uid && m_uid != peer->m_uid)
+        return -EPERM;
+
+    param->sched_priority = peer->priority();
+    return 0;
+}
+
 int Process::sys$getsockopt(const Syscall::SC_getsockopt_params* params)
 int Process::sys$getsockopt(const Syscall::SC_getsockopt_params* params)
 {
 {
     if (!validate_read_typed(params))
     if (!validate_read_typed(params))

+ 4 - 0
Kernel/Process.h

@@ -40,9 +40,11 @@ public:
     enum Priority
     enum Priority
     {
     {
         IdlePriority,
         IdlePriority,
+        FirstPriority = IdlePriority,
         LowPriority,
         LowPriority,
         NormalPriority,
         NormalPriority,
         HighPriority,
         HighPriority,
+        LastPriority = HighPriority,
     };
     };
 
 
     enum RingLevel
     enum RingLevel
@@ -186,6 +188,8 @@ public:
     int sys$setsockopt(const Syscall::SC_setsockopt_params*);
     int sys$setsockopt(const Syscall::SC_setsockopt_params*);
     int sys$getsockname(int sockfd, sockaddr* addr, socklen_t* addrlen);
     int sys$getsockname(int sockfd, sockaddr* addr, socklen_t* addrlen);
     int sys$getpeername(int sockfd, sockaddr* addr, socklen_t* addrlen);
     int sys$getpeername(int sockfd, sockaddr* addr, socklen_t* addrlen);
+    int sys$sched_setparam(pid_t pid, const struct sched_param* param);
+    int sys$sched_getparam(pid_t pid, struct sched_param* param);
     int sys$restore_signal_mask(dword mask);
     int sys$restore_signal_mask(dword mask);
     int sys$create_thread(int (*)(void*), void*);
     int sys$create_thread(int (*)(void*), void*);
     void sys$exit_thread(int code);
     void sys$exit_thread(int code);

+ 4 - 0
Kernel/Syscall.cpp

@@ -276,6 +276,10 @@ static dword handle(RegisterDump& regs, dword function, dword arg1, dword arg2,
         return current->process().sys$getsockname((int)arg1, (sockaddr*)arg2, (socklen_t*)arg3);
         return current->process().sys$getsockname((int)arg1, (sockaddr*)arg2, (socklen_t*)arg3);
     case Syscall::SC_getpeername:
     case Syscall::SC_getpeername:
         return current->process().sys$getpeername((int)arg1, (sockaddr*)arg2, (socklen_t*)arg3);
         return current->process().sys$getpeername((int)arg1, (sockaddr*)arg2, (socklen_t*)arg3);
+    case Syscall::SC_sched_setparam:
+        return current->process().sys$sched_setparam((pid_t)arg1, (struct sched_param*)arg2);
+    case Syscall::SC_sched_getparam:
+        return current->process().sys$sched_setparam((pid_t)arg1, (struct sched_param*)arg2);
     default:
     default:
         kprintf("<%u> int0x82: Unknown function %u requested {%x, %x, %x}\n", current->process().pid(), function, arg1, arg2, arg3);
         kprintf("<%u> int0x82: Unknown function %u requested {%x, %x, %x}\n", current->process().pid(), function, arg1, arg2, arg3);
         return -ENOSYS;
         return -ENOSYS;

+ 3 - 1
Kernel/Syscall.h

@@ -105,7 +105,9 @@
     __ENUMERATE_SYSCALL(writev)                 \
     __ENUMERATE_SYSCALL(writev)                 \
     __ENUMERATE_SYSCALL(beep)                   \
     __ENUMERATE_SYSCALL(beep)                   \
     __ENUMERATE_SYSCALL(getsockname)            \
     __ENUMERATE_SYSCALL(getsockname)            \
-    __ENUMERATE_SYSCALL(getpeername)
+    __ENUMERATE_SYSCALL(getpeername)            \
+    __ENUMERATE_SYSCALL(sched_setparam)          \
+    __ENUMERATE_SYSCALL(sched_getparam)
 
 
 namespace Syscall {
 namespace Syscall {
 
 

+ 4 - 0
Kernel/UnixTypes.h

@@ -400,3 +400,7 @@ struct iovec {
     void* iov_base;
     void* iov_base;
     size_t iov_len;
     size_t iov_len;
 };
 };
+
+struct sched_param {
+    int sched_priority;
+};

+ 24 - 0
LibC/sched.cpp

@@ -10,5 +10,29 @@ int sched_yield()
     __RETURN_WITH_ERRNO(rc, rc, -1);
     __RETURN_WITH_ERRNO(rc, rc, -1);
 }
 }
 
 
+int sched_get_priority_min(int policy)
+{
+    (void)policy;
+    return 0; // Idle
+}
+
+int sched_get_priority_max(int policy)
+{
+    (void)policy;
+    return 3; // High
+}
+
+int sched_setparam(pid_t pid, const struct sched_param *param)
+{
+    int rc = syscall(SC_sched_setparam, pid, param);
+    __RETURN_WITH_ERRNO(rc, rc, -1);
+}
+
+int sched_getparam(pid_t pid, struct sched_param *param)
+{
+    int rc = syscall(SC_sched_getparam, pid, param);
+    __RETURN_WITH_ERRNO(rc, rc, -1);
+}
+
 }
 }
 
 

+ 15 - 0
LibC/sched.h

@@ -1,9 +1,24 @@
 #pragma once
 #pragma once
 
 
+#include <sys/types.h>
 #include <sys/cdefs.h>
 #include <sys/cdefs.h>
 
 
 __BEGIN_DECLS
 __BEGIN_DECLS
 
 
 int sched_yield();
 int sched_yield();
 
 
+struct sched_param {
+    int sched_priority;
+};
+
+#define SCHED_FIFO 0
+#define SCHED_RR 1
+#define SCHED_OTHER 2
+#define SCHED_BATCH 3
+
+int sched_get_priority_min(int policy);
+int sched_get_priority_max(int policy);
+int sched_setparam(pid_t pid, const struct sched_param *param);
+int sched_getparam(pid_t pid, struct sched_param *param);
+
 __END_DECLS
 __END_DECLS

+ 6 - 0
LibC/unistd.h

@@ -107,4 +107,10 @@ enum
 #define X_OK 1
 #define X_OK 1
 #define F_OK 0
 #define F_OK 0
 
 
+/*
+ * We aren't fully compliant (don't support policies, and don't have a wide
+ * range of values), but we do have process priorities.
+ */
+#define _POSIX_PRIORITY_SCHEDULING
+
 __END_DECLS
 __END_DECLS