Browse Source

Kernel+LibCore: Make %sid path parsing not take ages

Before this patch, Core::SessionManagement::parse_path_with_sid() would
figure out the root session ID by sifting through /sys/kernel/processes.

That file can take quite a while to generate (sometimes up to 40ms on my
machine, which is a problem on its own!) and with no caching, many of
our programs were effectively doing this multiple times on startup when
unveiling something in /tmp/session/%sid/

While we should find ways to make generating /sys/kernel/processes fast
again, this patch addresses the specific problem by introducing a new
syscall: sys$get_root_session_id(). This extracts the root session ID
by looking directly at the process table and takes <1ms instead of 40ms.

This cuts WebContent process startup time by ~100ms on my machine. :^)
Andreas Kling 2 years ago
parent
commit
5dcc58d54a

+ 1 - 0
Kernel/API/Syscall.h

@@ -81,6 +81,7 @@ enum class NeedsBigProcessLock {
     S(futex, NeedsBigProcessLock::Yes)                      \
     S(futex, NeedsBigProcessLock::Yes)                      \
     S(get_dir_entries, NeedsBigProcessLock::Yes)            \
     S(get_dir_entries, NeedsBigProcessLock::Yes)            \
     S(get_process_name, NeedsBigProcessLock::Yes)           \
     S(get_process_name, NeedsBigProcessLock::Yes)           \
+    S(get_root_session_id, NeedsBigProcessLock::No)         \
     S(get_stack_bounds, NeedsBigProcessLock::No)            \
     S(get_stack_bounds, NeedsBigProcessLock::No)            \
     S(get_thread_name, NeedsBigProcessLock::Yes)            \
     S(get_thread_name, NeedsBigProcessLock::Yes)            \
     S(getcwd, NeedsBigProcessLock::No)                      \
     S(getcwd, NeedsBigProcessLock::No)                      \

+ 1 - 0
Kernel/Process.h

@@ -448,6 +448,7 @@ public:
     ErrorOr<FlatPtr> sys$map_time_page();
     ErrorOr<FlatPtr> sys$map_time_page();
     ErrorOr<FlatPtr> sys$jail_create(Userspace<Syscall::SC_jail_create_params*> user_params);
     ErrorOr<FlatPtr> sys$jail_create(Userspace<Syscall::SC_jail_create_params*> user_params);
     ErrorOr<FlatPtr> sys$jail_attach(Userspace<Syscall::SC_jail_attach_params const*> user_params);
     ErrorOr<FlatPtr> sys$jail_attach(Userspace<Syscall::SC_jail_attach_params const*> user_params);
+    ErrorOr<FlatPtr> sys$get_root_session_id(pid_t force_sid);
 
 
     template<bool sockname, typename Params>
     template<bool sockname, typename Params>
     ErrorOr<void> get_sock_or_peer_name(Params const&);
     ErrorOr<void> get_sock_or_peer_name(Params const&);

+ 21 - 0
Kernel/Syscalls/setpgid.cpp

@@ -139,4 +139,25 @@ ErrorOr<FlatPtr> Process::sys$setpgid(pid_t specified_pid, pid_t specified_pgid)
     });
     });
 }
 }
 
 
+ErrorOr<FlatPtr> Process::sys$get_root_session_id(pid_t force_sid)
+{
+    pid_t sid = (force_sid == -1) ? this->sid().value() : force_sid;
+    if (sid == 0)
+        return 0;
+    while (true) {
+        auto sid_process = Process::from_pid_in_same_jail(sid);
+        if (!sid_process)
+            return ESRCH;
+        auto parent_pid = sid_process->ppid().value();
+        auto parent_process = Process::from_pid_in_same_jail(parent_pid);
+        if (!parent_process)
+            return ESRCH;
+        pid_t parent_sid = parent_process->sid().value();
+        if (parent_sid == 0)
+            break;
+        sid = parent_sid;
+    }
+    return sid;
+}
+
 }
 }

+ 13 - 24
Userland/Libraries/LibCore/SessionManagement.cpp

@@ -5,37 +5,26 @@
  */
  */
 
 
 #include <LibCore/Directory.h>
 #include <LibCore/Directory.h>
-#include <LibCore/ProcessStatisticsReader.h>
 #include <LibCore/SessionManagement.h>
 #include <LibCore/SessionManagement.h>
 #include <LibCore/System.h>
 #include <LibCore/System.h>
 
 
+#ifdef AK_OS_SERENITY
+#    include <LibSystem/syscall.h>
+#endif
+
 namespace Core::SessionManagement {
 namespace Core::SessionManagement {
 
 
-static ErrorOr<Core::ProcessStatistics const*> get_proc(Core::AllProcessesStatistics const& stats, pid_t pid)
+ErrorOr<pid_t> root_session_id([[maybe_unused]] Optional<pid_t> force_sid)
 {
 {
-    for (auto& proc : stats.processes) {
-        if (proc.pid == pid)
-            return &proc;
+#ifdef AK_OS_SERENITY
+    int rc = syscall(SC_get_root_session_id, force_sid.value_or(-1));
+    if (rc < 0) {
+        return Error::from_syscall("get_root_session_id"sv, rc);
     }
     }
-    return Error::from_string_literal("Could not find pid in process statistics.");
-}
-
-ErrorOr<pid_t> root_session_id(Optional<pid_t> force_sid)
-{
-    auto stats = TRY(Core::ProcessStatisticsReader::get_all(false));
-
-    pid_t sid = (force_sid.has_value()) ? force_sid.value() : TRY(System::getsid());
-    while (true) {
-        pid_t parent = TRY(get_proc(stats, sid))->ppid;
-        pid_t parent_sid = TRY(get_proc(stats, parent))->sid;
-
-        if (parent_sid == 0)
-            break;
-
-        sid = parent_sid;
-    }
-
-    return sid;
+    return static_cast<pid_t>(rc);
+#else
+    return 0;
+#endif
 }
 }
 
 
 ErrorOr<void> logout(Optional<pid_t> force_sid)
 ErrorOr<void> logout(Optional<pid_t> force_sid)