Prechádzať zdrojové kódy

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.
Sergey Bugaev 5 rokov pred
rodič
commit
52b0bd06a8

+ 3 - 0
Base/etc/SystemServer.ini

@@ -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

+ 28 - 1
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()
 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);

+ 7 - 1
Servers/SystemServer/Service.h

@@ -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();
 };
 };

+ 2 - 2
Servers/SystemServer/main.cpp

@@ -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();