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.
This commit is contained in:
parent
ab98969403
commit
52b0bd06a8
Notes:
sideshowbarker
2024-07-19 11:03:26 +09:00
Author: https://github.com/bugaevc Commit: https://github.com/SerenityOS/serenity/commit/52b0bd06a86 Pull-request: https://github.com/SerenityOS/serenity/pull/827
4 changed files with 40 additions and 4 deletions
|
@ -6,12 +6,14 @@ Priority=high
|
||||||
|
|
||||||
[ProtocolServer]
|
[ProtocolServer]
|
||||||
Socket=/tmp/portal/protocol
|
Socket=/tmp/portal/protocol
|
||||||
|
Lazy=1
|
||||||
Priority=low
|
Priority=low
|
||||||
KeepAlive=1
|
KeepAlive=1
|
||||||
User=anon
|
User=anon
|
||||||
|
|
||||||
[LookupServer]
|
[LookupServer]
|
||||||
Socket=/tmp/portal/lookup
|
Socket=/tmp/portal/lookup
|
||||||
|
Lazy=1
|
||||||
Priority=low
|
Priority=low
|
||||||
KeepAlive=1
|
KeepAlive=1
|
||||||
User=anon
|
User=anon
|
||||||
|
@ -24,6 +26,7 @@ User=anon
|
||||||
|
|
||||||
[AudioServer]
|
[AudioServer]
|
||||||
Socket=/tmp/portal/audio
|
Socket=/tmp/portal/audio
|
||||||
|
# TODO: we may want to start it lazily, but right now WindowServer connects to it immediately on startup
|
||||||
Priority=high
|
Priority=high
|
||||||
KeepAlive=1
|
KeepAlive=1
|
||||||
User=anon
|
User=anon
|
||||||
|
|
|
@ -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()
|
void Service::spawn()
|
||||||
{
|
{
|
||||||
dbg() << "Spawning " << name();
|
dbg() << "Spawning " << name();
|
||||||
|
@ -172,7 +197,7 @@ void Service::did_exit(int exit_code)
|
||||||
m_pid = -1;
|
m_pid = -1;
|
||||||
|
|
||||||
if (m_keep_alive)
|
if (m_keep_alive)
|
||||||
spawn();
|
activate();
|
||||||
}
|
}
|
||||||
|
|
||||||
Service::Service(const CConfigFile& config, const StringView& name)
|
Service::Service(const CConfigFile& config, const StringView& name)
|
||||||
|
@ -198,6 +223,7 @@ Service::Service(const CConfigFile& config, const StringView& name)
|
||||||
ASSERT_NOT_REACHED();
|
ASSERT_NOT_REACHED();
|
||||||
|
|
||||||
m_keep_alive = config.read_bool_entry(name, "KeepAlive");
|
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");
|
m_socket_path = config.read_entry(name, "Socket");
|
||||||
if (!m_socket_path.is_null()) {
|
if (!m_socket_path.is_null()) {
|
||||||
|
@ -227,6 +253,7 @@ void Service::save_to(JsonObject& json)
|
||||||
json.set("priority", m_priority);
|
json.set("priority", m_priority);
|
||||||
json.set("keep_alive", m_keep_alive);
|
json.set("keep_alive", m_keep_alive);
|
||||||
json.set("socket_path", m_socket_path);
|
json.set("socket_path", m_socket_path);
|
||||||
|
json.set("lazy", m_lazy);
|
||||||
json.set("user", m_user);
|
json.set("user", m_user);
|
||||||
json.set("uid", m_uid);
|
json.set("uid", m_uid);
|
||||||
json.set("gid", m_gid);
|
json.set("gid", m_gid);
|
||||||
|
|
|
@ -15,7 +15,7 @@ class Service final : public CObject {
|
||||||
C_OBJECT(Service)
|
C_OBJECT(Service)
|
||||||
|
|
||||||
public:
|
public:
|
||||||
void spawn();
|
void activate();
|
||||||
void did_exit(int exit_code);
|
void did_exit(int exit_code);
|
||||||
|
|
||||||
static Service* find_by_pid(pid_t);
|
static Service* find_by_pid(pid_t);
|
||||||
|
@ -25,6 +25,8 @@ public:
|
||||||
private:
|
private:
|
||||||
Service(const CConfigFile&, const StringView& name);
|
Service(const CConfigFile&, const StringView& name);
|
||||||
|
|
||||||
|
void spawn();
|
||||||
|
|
||||||
// Path to the executable. By default this is /bin/{m_name}.
|
// Path to the executable. By default this is /bin/{m_name}.
|
||||||
String m_executable_path;
|
String m_executable_path;
|
||||||
// Extra arguments, starting from argv[1], to pass when exec'ing.
|
// Extra arguments, starting from argv[1], to pass when exec'ing.
|
||||||
|
@ -36,6 +38,8 @@ private:
|
||||||
bool m_keep_alive { false };
|
bool m_keep_alive { false };
|
||||||
// Path to the socket to create and listen on on behalf of this service.
|
// Path to the socket to create and listen on on behalf of this service.
|
||||||
String m_socket_path;
|
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.
|
// The name of the user we should run this service as.
|
||||||
String m_user;
|
String m_user;
|
||||||
uid_t m_uid { 0 };
|
uid_t m_uid { 0 };
|
||||||
|
@ -45,7 +49,9 @@ private:
|
||||||
pid_t m_pid { -1 };
|
pid_t m_pid { -1 };
|
||||||
// An open fd to the socket.
|
// An open fd to the socket.
|
||||||
int m_socket_fd { -1 };
|
int m_socket_fd { -1 };
|
||||||
|
RefPtr<CNotifier> m_socket_notifier;
|
||||||
|
|
||||||
void resolve_user();
|
void resolve_user();
|
||||||
void setup_socket();
|
void setup_socket();
|
||||||
|
void setup_notifier();
|
||||||
};
|
};
|
||||||
|
|
|
@ -95,9 +95,9 @@ int main(int, char**)
|
||||||
for (auto name : config->groups())
|
for (auto name : config->groups())
|
||||||
services.append(Service::construct(*config, name));
|
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)
|
for (auto& service : services)
|
||||||
service->spawn();
|
service->activate();
|
||||||
|
|
||||||
// This won't return if we're in test mode.
|
// This won't return if we're in test mode.
|
||||||
check_for_test_mode();
|
check_for_test_mode();
|
||||||
|
|
Loading…
Add table
Reference in a new issue