diff options
author | Sergey Bugaev <bugaevc@gmail.com> | 2019-11-26 19:41:16 +0300 |
---|---|---|
committer | Andreas Kling <awesomekling@gmail.com> | 2019-11-26 19:58:25 +0100 |
commit | 52b0bd06a8627ac75a4b667a5631a1c10456cc82 (patch) | |
tree | b0aaa729afe6e22e52f0546f07725f55e90e1ddf /Servers | |
parent | ab98969403ff69fa9e4001c28ae8ea9115bfd8d4 (diff) | |
download | serenity-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')
-rw-r--r-- | Servers/SystemServer/Service.cpp | 29 | ||||
-rw-r--r-- | Servers/SystemServer/Service.h | 8 | ||||
-rw-r--r-- | Servers/SystemServer/main.cpp | 4 |
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(); |