summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Base/etc/SystemServer.ini5
-rw-r--r--Servers/SystemServer/Service.cpp29
-rw-r--r--Servers/SystemServer/Service.h5
-rw-r--r--Servers/SystemServer/main.cpp29
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;