Explorar o código

LibCore+rpcdump: Publish CObject graph to on-demand RPC socket

All programs that have a CEventLoop now allow local socket connections
via /tmp/rpc.PID and will dump a serialized JSON array of all the live
CObjects in the program onto connecting sockets.

Also added a small /bin/rpcdump tool that connects to an RPC socket and
produces a raw dump of the JSON that comes out.
Andreas Kling %!s(int64=6) %!d(string=hai) anos
pai
achega
1febd59f83
Modificáronse 3 ficheiros con 77 adicións e 1 borrados
  1. 31 0
      Libraries/LibCore/CEventLoop.cpp
  2. 4 1
      Libraries/LibCore/CEventLoop.h
  3. 42 0
      Userland/rpcdump.cpp

+ 31 - 0
Libraries/LibCore/CEventLoop.cpp

@@ -1,6 +1,10 @@
+#include <AK/JsonArray.h>
+#include <AK/JsonObject.h>
+#include <AK/JsonValue.h>
 #include <AK/Time.h>
 #include <LibCore/CEvent.h>
 #include <LibCore/CEventLoop.h>
+#include <LibCore/CLocalSocket.h>
 #include <LibCore/CLock.h>
 #include <LibCore/CNotifier.h>
 #include <LibCore/CObject.h>
@@ -25,6 +29,7 @@ HashMap<int, NonnullOwnPtr<CEventLoop::EventLoopTimer>>* CEventLoop::s_timers;
 HashTable<CNotifier*>* CEventLoop::s_notifiers;
 int CEventLoop::s_next_timer_id = 1;
 int CEventLoop::s_wake_pipe_fds[2];
+CLocalServer CEventLoop::s_rpc_server;
 
 CEventLoop::CEventLoop()
 {
@@ -39,6 +44,32 @@ CEventLoop::CEventLoop()
         int rc = pipe2(s_wake_pipe_fds, O_CLOEXEC);
         ASSERT(rc == 0);
         s_event_loop_stack->append(this);
+
+
+        auto rpc_path = String::format("/tmp/rpc.%d", getpid());
+        rc = unlink(rpc_path.characters());
+        if (rc < 0 && errno != ENOENT) {
+            perror("unlink");
+            ASSERT_NOT_REACHED();
+        }
+        bool listening = s_rpc_server.listen(rpc_path);
+        ASSERT(listening);
+
+        s_rpc_server.on_ready_to_accept = [&] {
+            auto* client = s_rpc_server.accept();
+            ASSERT(client);
+            JsonArray objects;
+            for (auto& object : CObject::all_objects()) {
+                JsonObject json_object;
+                json_object.set("class_name", object.class_name());
+                json_object.set("address", String::format("%p", &object));
+                json_object.set("name", object.name());
+                json_object.set("parent", String::format("%p", object.parent()));
+                objects.append(move(json_object));
+            }
+            client->write(objects.to_string());
+            client->delete_later();
+        };
     }
 
 #ifdef CEVENTLOOP_DEBUG

+ 4 - 1
Libraries/LibCore/CEventLoop.h

@@ -5,8 +5,9 @@
 #include <AK/OwnPtr.h>
 #include <AK/Vector.h>
 #include <AK/WeakPtr.h>
-#include <LibCore/CLock.h>
 #include <LibCore/CEvent.h>
+#include <LibCore/CLocalServer.h>
+#include <LibCore/CLock.h>
 #include <sys/select.h>
 #include <sys/time.h>
 #include <time.h>
@@ -85,4 +86,6 @@ private:
     static int s_next_timer_id;
 
     static HashTable<CNotifier*>* s_notifiers;
+
+    static CLocalServer s_rpc_server;
 };

+ 42 - 0
Userland/rpcdump.cpp

@@ -0,0 +1,42 @@
+#include <LibCore/CEventLoop.h>
+#include <LibCore/CLocalSocket.h>
+#include <stdio.h>
+
+int main(int argc, char** argv)
+{
+    if (argc != 2) {
+        printf("usage: %s <pid>\n", argv[0]);
+        return 0;
+    }
+
+    CEventLoop loop;
+
+    int pid = atoi(argv[1]);
+
+    CLocalSocket socket;
+    auto success = socket.connect(CSocketAddress::local(String::format("/tmp/rpc.%d", pid)));
+    if (!success) {
+        fprintf(stderr, "Couldn't connect to PID %d\n", pid);
+        return 1;
+    }
+
+    socket.on_connected = [&] {
+        dbg() << "Connected to PID " << pid;
+    };
+
+    socket.on_ready_to_read = [&] {
+        if (socket.eof()) {
+            dbg() << "Disconnected from PID " << pid;
+            loop.quit(0);
+            return;
+        }
+
+        auto data = socket.read_all();
+
+        for (int i = 0; i < data.size(); ++i)
+            putchar(data[i]);
+        printf("\n");
+    };
+
+    return loop.exec();
+}