chiark / gitweb /
cgi-fcgi-interp: new garbage collection approach, wip implementation
authorIan Jackson <ijackson@chiark.greenend.org.uk>
Thu, 24 Mar 2016 22:03:16 +0000 (22:03 +0000)
committerIan Jackson <ijackson@chiark.greenend.org.uk>
Tue, 29 Mar 2016 18:32:51 +0000 (19:32 +0100)
cprogs/cgi-fcgi-interp.c

index 602ffa6..4ae61d7 100644 (file)
 #include <sys/utsname.h>
 #include <sys/socket.h>
 #include <sys/un.h>
+#include <sys/file.h>
 #include <unistd.h>
+#include <fcntl.h>
 #include <pwd.h>
 #include <err.h>
-
+       
 #include <nettle/sha.h>
 
 #include "myopt.h"
 #define MINHEXHASH 33
 
 static const char *interp, *ident;
-static int numservers, debugmode;
+static int numservers=4, debugmode, stage2;
+static int check_interval=300;
 
 void diee(const char *m) {
   err(127, "error: %s failed", m);
@@ -179,6 +182,8 @@ static const struct cmdinfo cmdinfos[]= {
   { 0, 'g',   1, .sassignto= &ident           },
   { 0, 'M',   1, .call=of_iassign, .iassignto= &numservers      },
   { 0, 'D',   0, .iassignto= &debugmode, .arg= 1 },
+  { 0, 'c',   1, .call=of_iassign, .iassignto= &check_interval  },
+  { "--stage2",0, 0, .iassignto= &stage2, .arg= 1 },
   { 0 }
 };
 
@@ -366,63 +371,32 @@ static bool check_garbage(void) {
   return 0;
 }
 
-static void tidy_1_garbage(const char *leaf) {
+static void tidy_garbage(void) {
+  /* We lock l<ident> and re-check.  The effect of this is that each
+   * stale socket is removed only once.  So unless multiple updates to
+   * the script happen rapidly, we can't be racing with the cgi-fcgi
+   * (which is recreating the socket */
+  int lockfd = -1;
   int r;
-  struct sockaddr_un sun;
-
-  int fd = -1;
 
-  memset(&sun,0,sizeof(sun));
-  sun.sun_family = AF_UNIX;
-  r = snprintf(sun.sun_path, sizeof(sun.sun_path), "%s/%s", run_base, leaf);
-  if (r >= sizeof(sun_path))
-    goto cannot;
+  const char *lock_path = m_asprintf("%s/l%s",run_base,ident);
 
-  fd = socket(AF_UNIX, SOCK_STREAM, 0);
-  if (fd<0) err("create socket for tidying garbage");
+  lockfd = open(lock_path, O_CREAT|O_RDWR, 0600);
+  if (lockfd<0) err(127,"create lock (%s)", lock_path);
 
-  r = fcntl(fd, F_SETFL, O_NONBLOCK);
-  if (r<0) err("set garbage socket nonblocking");
+  r = flock(lockfd, LOCK_EX);
+  if (r) err(127,"lock lock (%s)", lock_path);
 
-  r = connect(fd, &sun, sizeof(sun));
-  if (r) {
-    if (errno == EAGAIN || errno == EWOULDBLOCK || errno == EINTR)
-      goto cannot;
-    if (errno != EINPROGRESS)
-      err("connect to garbage socket (%s)", sun.sun_path);
-    /* well, EINPROGRESS, let's just carry on and hope write works */
-  }
-
-  r = write(
-       
-
-static void tidy_garbage(void) {
-  const char *this_garbage =
-    m_asprintf("%s/g%lu.%lu", run_base,
-              (unsigned long)sock_stab.st_ino,
-              (unsigned long)getpid());
-
-  r = rename(socket_path, this_garbage);
-  if (r) {
-    if (!(errno == ENOENT))
-      err("rename socket from old runner (from %s to %s)",
-         socket_path, this_garbage);
-  }
-
-  DIR *d = opendir(run_base);
-  if (!d) err("open run directory (%d) to clean up garbage", run_base);
-  struct dirent *de;
-  while ((errno = 0, de = readdir(d))) {
-    if (de->d_name[0] != 'g')
-      continue;
-    tidy_1_garbage(de->d_name);
+  if (check_garbage()) {
+    r = unlink(socket_path);
+    if (r) {
+      if (!(errno == ENOENT))
+       err(127,"remove out-of-date socket (%s)", socket_path);
+    }
   }
-  if (errno) err("read run directory (%d) to clean up garbage", run_base);
-  /* 
-  (void)r;
-  if (r) {
 
-  printf("this_garb: %s\n", this_garbage);
+  r = close(lockfd);
+  if (r) errx(127,"close lock (%s)", lock_path);
 }
 
 static void shbang_opts(const char *const **argv_io,
@@ -475,17 +449,17 @@ int main(int argc, const char *const *argv) {
 
   find_socket_path();
 
-  bool havegarbage = check_garbage();
+  bool isgarbage = check_garbage();
 
   if (debugmode) {
     printf("socket: %s\n",socket_path);
     printf("interp: %s\n",interp);
     printf("script: %s\n",script);
-    printf("garbage: %d\n",havegarbage);
+    printf("garbage: %d\n",isgarbage);
     exit(0);
   }
 
-  if (havegarbage)
+  if (isgarbage)
     tidy_garbage();
 
   exit(0);