diff options
-rw-r--r-- | Base/etc/SystemServer.ini | 5 | ||||
-rw-r--r-- | Servers/SystemServer/Service.cpp | 29 | ||||
-rw-r--r-- | Servers/SystemServer/Service.h | 5 | ||||
-rw-r--r-- | Servers/SystemServer/main.cpp | 29 |
4 files changed, 64 insertions, 4 deletions
diff --git a/Base/etc/SystemServer.ini b/Base/etc/SystemServer.ini index 22bf7be108..02d93d59d5 100644 --- a/Base/etc/SystemServer.ini +++ b/Base/etc/SystemServer.ini @@ -6,22 +6,27 @@ Priority=high [ProtocolServer] Priority=low +KeepAlive=1 User=anon [LookupServer] Priority=low +KeepAlive=1 User=anon [WindowServer] Priority=high +KeepAlive=1 User=anon [AudioServer] Priority=high +KeepAlive=1 User=anon [Taskbar] Priority=high +KeepAlive=1 User=anon [Terminal] diff --git a/Servers/SystemServer/Service.cpp b/Servers/SystemServer/Service.cpp index c27e8372e7..b955e1efd5 100644 --- a/Servers/SystemServer/Service.cpp +++ b/Servers/SystemServer/Service.cpp @@ -16,6 +16,7 @@ struct UidAndGid { }; static HashMap<String, UidAndGid>* s_user_map; +static HashMap<pid_t, Service*> s_service_map; void Service::resolve_user() { @@ -35,6 +36,14 @@ void Service::resolve_user() m_gid = user.value().gid; } +Service* Service::find_by_pid(pid_t pid) +{ + auto it = s_service_map.find(pid); + if (it == s_service_map.end()) + return nullptr; + return (*it).value; +} + void Service::spawn() { dbg() << "Spawning " << name(); @@ -81,9 +90,26 @@ void Service::spawn() rc = execv(argv[0], argv); perror("exec"); ASSERT_NOT_REACHED(); + } else { + // We are the parent. + s_service_map.set(m_pid, this); } } +void Service::did_exit(int exit_code) +{ + ASSERT(m_pid > 0); + (void)exit_code; + + dbg() << "Service " << name() << " has exited"; + + s_service_map.remove(m_pid); + m_pid = -1; + + if (m_keep_alive) + spawn(); +} + Service::Service(const CConfigFile& config, const StringView& name) : CObject(nullptr) { @@ -106,6 +132,8 @@ Service::Service(const CConfigFile& config, const StringView& name) else ASSERT_NOT_REACHED(); + m_keep_alive = config.read_bool_entry(name, "KeepAlive"); + m_user = config.read_entry(name, "User"); if (!m_user.is_null()) resolve_user(); @@ -127,6 +155,7 @@ void Service::save_to(JsonObject& json) json.set("stdio_file_path", m_stdio_file_path); json.set("priority", m_priority); + json.set("keep_alive", m_keep_alive); json.set("user", m_user); json.set("uid", m_uid); json.set("gid", m_gid); diff --git a/Servers/SystemServer/Service.h b/Servers/SystemServer/Service.h index 06209cbd4d..d685ff4c37 100644 --- a/Servers/SystemServer/Service.h +++ b/Servers/SystemServer/Service.h @@ -15,6 +15,9 @@ class Service final : public CObject { public: void spawn(); + void did_exit(int exit_code); + + static Service* find_by_pid(pid_t); void save_to(AK::JsonObject&) override; @@ -28,6 +31,8 @@ private: // File path to open as stdio fds. String m_stdio_file_path; int m_priority { 1 }; + // Whether we should re-launch it if it exits. + bool m_keep_alive { false }; // The name of the user we should run this service as. String m_user; uid_t m_uid { 0 }; diff --git a/Servers/SystemServer/main.cpp b/Servers/SystemServer/main.cpp index 0030180a43..603fdd4553 100644 --- a/Servers/SystemServer/main.cpp +++ b/Servers/SystemServer/main.cpp @@ -10,12 +10,28 @@ #include <sys/wait.h> #include <unistd.h> -void sigchld_handler(int) +static void sigchld_handler(int) { int status = 0; pid_t pid = waitpid(-1, &status, WNOHANG); - if (pid) - dbg() << "reaped pid " << pid; + if (!pid) + return; + + dbg() << "Reaped child with pid " << pid; + Service* service = Service::find_by_pid(pid); + if (service == nullptr) { + dbg() << "There was no service with this pid, what is going on?"; + return; + } + + // Call service->did_exit(status) some time soon. + // We wouldn't want to run the complex logic, such + // as possibly spawning the service again, from the + // signal handler, so defer it. + CEventLoop::main().post_event(*service, make<CDeferredInvocationEvent>([=](CObject&) { + service->did_exit(status); + })); + CEventLoop::wake(); } static void check_for_test_mode() @@ -63,7 +79,12 @@ int main(int, char**) { mount_all_filesystems(); - signal(SIGCHLD, sigchld_handler); + struct sigaction sa = { + .sa_handler = sigchld_handler, + .sa_mask = 0, + .sa_flags = SA_RESTART + }; + sigaction(SIGCHLD, &sa, nullptr); CEventLoop event_loop; |