diff --git a/Base/etc/SystemServer.ini b/Base/etc/SystemServer.ini index 0ead2fb94cf637..3c55918dfac888 100644 --- a/Base/etc/SystemServer.ini +++ b/Base/etc/SystemServer.ini @@ -6,12 +6,14 @@ Priority=high [ProtocolServer] Socket=/tmp/portal/protocol +Lazy=1 Priority=low KeepAlive=1 User=anon [LookupServer] Socket=/tmp/portal/lookup +Lazy=1 Priority=low KeepAlive=1 User=anon @@ -24,6 +26,7 @@ User=anon [AudioServer] Socket=/tmp/portal/audio +# TODO: we may want to start it lazily, but right now WindowServer connects to it immediately on startup Priority=high KeepAlive=1 User=anon diff --git a/Servers/SystemServer/Service.cpp b/Servers/SystemServer/Service.cpp index d1ecbf17c81fea..fcf330415941e7 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 4518d292de9f32..5d3b3522ce45a7 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 @@ class Service final : public CObject { 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 @@ class Service final : public CObject { 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 @@ class Service final : public CObject { pid_t m_pid { -1 }; // An open fd to the socket. int m_socket_fd { -1 }; + RefPtr 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 d8eb333702c926..e69405ce45c09c 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();