chiark / gitweb /
prefork-interp: wip
authorIan Jackson <ijackson@chiark.greenend.org.uk>
Sat, 9 Jul 2022 13:19:52 +0000 (14:19 +0100)
committerIan Jackson <ijackson@chiark.greenend.org.uk>
Sun, 21 Aug 2022 20:21:10 +0000 (21:21 +0100)
Signed-off-by: Ian Jackson <ijackson@chiark.greenend.org.uk>
prefork-interp.c

index 0921835255c9e8a4898e6a5763985a56946bd6d6..3b77f61d9adffba39b1d5720f9161418c5cbceb0 100644 (file)
@@ -6,6 +6,7 @@
 /*
  * Process structure:
  *  client (C wrapper)        connects to server
+ *                              (including reading ack byte)
  *                            if fails or garbage
  *                            === acquire lock ===
  *                               makes new listening socket
@@ -53,6 +54,7 @@
  *
  *          monitor           [fd0: null, fd[12]: syslgo]
  *                            other fds: call(server-end)
+ *                            sends ack byte
  *                            receives args, env, fds
  *                            forks executor
  *
 
 struct sockaddr_un sun;
 
-int main(int argc, const char *const *argv) {
-  script = process_opts(argc, argv);
+#define ACK_BYTE '\n'
+
+// Returns: call(client-end) fd, or -1 to mean "is garbage"
+// find_socket_path must have been called
+static int attempt_connect_existing(void) {
+  int r;
+  int fd = -1;
 
-  find_socket_path();
   FILLZERO(sun);
   sun.sun_family = AF_UNIX;
   assert(strlen(socket_path) <= sizeof(sun.sun_path));
   strncpy(sun.sun_path, socket_path, sizeof(sun.sun_path));
 
   bool isgarbage = check_garbage();
+  if (isgarbage) goto x_garbage;
 
-  int client_fd = socket(AF_UNIX, SOCK_STREAM, 0);
-  if (client_fd==-1) diee("socket() for client");
+  fd = socket(AF_UNIX, SOCK_STREAM, 0);
+  if (fd==-1) diee("socket() for client");
 
   salen_t salen = sizeof(sun);
   r = connect(client, (const struct sockaddr*)sun, salen);
   if (r==-1) {
-    if (errno==ECONNREFUSED || errno==ENOENT) {
-      
+    if (errno==ECONNREFUSED || errno==ENOENT) goto x_garbgae;
+    diee("connect() %s", socket_path);
+  }
+
+  for (;;) {
+    char ack;
+    sr = read(fd, &ack, 1);
+    if (sr == -1) {
+      if (errno==ECONNRESET) goto x_garbage;
+      if (errno==EINTR) continue;
+      diee("read() ack byte");
+    }
+    if (sr == 0) { goto x_garbage; }
+    if (ack != '\n') die("got ack byte 0x%02x, not '\n'", ack);
+    return fd;
+  }
+
+ x_garbage:
+  if (fd >= 0) close(fd);
+  return -1;
+}
+
+static int connect_or_spawn(void) {
+  int fd = connect_existing();
+  if (fd >= 0) return fd;
+
+  let acquire_lock();
+    fd = connect_existing();
+
+int main(int argc, const char *const *argv) {
+  script = process_opts(argc, argv);
+
+  find_socket_path();
+  int fd = connect_or_spawn();
 }