summaryrefslogtreecommitdiff
path: root/Servers/SystemServer
diff options
context:
space:
mode:
authorSergey Bugaev <bugaevc@gmail.com>2019-11-26 19:41:16 +0300
committerAndreas Kling <awesomekling@gmail.com>2019-11-26 19:58:25 +0100
commit52b0bd06a8627ac75a4b667a5631a1c10456cc82 (patch)
treeb0aaa729afe6e22e52f0546f07725f55e90e1ddf /Servers/SystemServer
parentab98969403ff69fa9e4001c28ae8ea9115bfd8d4 (diff)
downloadserenity-52b0bd06a8627ac75a4b667a5631a1c10456cc82.zip
SystemServer: Implement lazy spawning
For services explicitly configured as lazy, SystemServer will now listen on the socket and only spawn the service once a client attempts to connect to the socket.
Diffstat (limited to 'Servers/SystemServer')
-rw-r--r--Servers/SystemServer/Service.cpp29
-rw-r--r--Servers/SystemServer/Service.h8
-rw-r--r--Servers/SystemServer/main.cpp4
3 files changed, 37 insertions, 4 deletions
diff --git a/Servers/SystemServer/Service.cpp b/Servers/SystemServer/Service.cpp
index d1ecbf17c8..fcf3304159 100644
--- a/Servers/SystemServer/Service.cpp
+++ b/Servers/SystemServer/Service.cpp
@@ -101,6 +101,31 @@ void Service::setup_socket()
}
}
+void Service::setup_notifier()
+{
+ ASSERT(m_lazy);
+ ASSERT(m_socket_fd >= 0);
+ ASSERT(!m_socket_notifier);
+
+ m_socket_notifier = CNotifier::construct(m_socket_fd, CNotifier::Event::Read, this);
+ m_socket_notifier->on_ready_to_read = [this] {
+ dbg() << "Ready to read on behalf of " << name();
+ remove_child(*m_socket_notifier);
+ m_socket_notifier = nullptr;
+ spawn();
+ };
+}
+
+void Service::activate()
+{
+ ASSERT(m_pid < 0);
+
+ if (m_lazy)
+ setup_notifier();
+ else
+ spawn();
+}
+
void Service::spawn()
{
dbg() << "Spawning " << name();
@@ -172,7 +197,7 @@ void Service::did_exit(int exit_code)
m_pid = -1;
if (m_keep_alive)
- spawn();
+ activate();
}
Service::Service(const CConfigFile& config, const StringView& name)
@@ -198,6 +223,7 @@ Service::Service(const CConfigFile& config, const StringView& name)
ASSERT_NOT_REACHED();
m_keep_alive = config.read_bool_entry(name, "KeepAlive");
+ m_lazy = config.read_bool_entry(name, "Lazy");
m_socket_path = config.read_entry(name, "Socket");
if (!m_socket_path.is_null()) {
@@ -227,6 +253,7 @@ void Service::save_to(JsonObject& json)
json.set("priority", m_priority);
json.set("keep_alive", m_keep_alive);
json.set("socket_path", m_socket_path);
+ json.set("lazy", m_lazy);
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 4518d292de..5d3b3522ce 100644
--- a/Servers/SystemServer/Service.h
+++ b/Servers/SystemServer/Service.h
@@ -15,7 +15,7 @@ class Service final : public CObject {
C_OBJECT(Service)
public:
- void spawn();
+ void activate();
void did_exit(int exit_code);
static Service* find_by_pid(pid_t);
@@ -25,6 +25,8 @@ public:
private:
Service(const CConfigFile&, const StringView& name);
+ void spawn();
+
// Path to the executable. By default this is /bin/{m_name}.
String m_executable_path;
// Extra arguments, starting from argv[1], to pass when exec'ing.
@@ -36,6 +38,8 @@ private:
bool m_keep_alive { false };
// Path to the socket to create and listen on on behalf of this service.
String m_socket_path;
+ // Whether we should only spawn this service once somebody connects to the socket.
+ bool m_lazy;
// The name of the user we should run this service as.
String m_user;
uid_t m_uid { 0 };
@@ -45,7 +49,9 @@ private:
pid_t m_pid { -1 };
// An open fd to the socket.
int m_socket_fd { -1 };
+ RefPtr<CNotifier> m_socket_notifier;
void resolve_user();
void setup_socket();
+ void setup_notifier();
};
diff --git a/Servers/SystemServer/main.cpp b/Servers/SystemServer/main.cpp
index d8eb333702..e69405ce45 100644
--- a/Servers/SystemServer/main.cpp
+++ b/Servers/SystemServer/main.cpp
@@ -95,9 +95,9 @@ int main(int, char**)
for (auto name : config->groups())
services.append(Service::construct(*config, name));
- // After we've set them all up, spawn them!
+ // After we've set them all up, activate them!
for (auto& service : services)
- service->spawn();
+ service->activate();
// This won't return if we're in test mode.
check_for_test_mode();