[gjs] Fix gjs_crash_after_timeout() problems



commit 4175f42adf28325c65a6cb3ab8dea625e14dcdfa
Author: Owen W. Taylor <otaylor fishsoup net>
Date:   Mon Aug 24 21:14:40 2009 -0400

    Fix gjs_crash_after_timeout() problems
    
    Fix two major issues with gjs_crash_after_timeout():
    
     * It didn't notice the parent exiting normally so the forked off
       child would keep running until the timeout. This is fixed by
       using a pipe between the parent and child and watching for the
       pipe to get immediate notification of parent exit.
    
     * The forked off child process would return to the caller of
       gjs_crash_after_timeout() after the timeout completed and it
       killed the parent this would typically fail horribly. Call exit()
       instead.
    
    http://bugzilla.gnome.org/show_bug.cgi?id=592962

 util/crash.c |   62 ++++++++++++++++++++++++++++++++++++++++++++++++++++++---
 1 files changed, 58 insertions(+), 4 deletions(-)
---
diff --git a/util/crash.c b/util/crash.c
index 81328d5..101f094 100644
--- a/util/crash.c
+++ b/util/crash.c
@@ -32,6 +32,8 @@
 #include <stdio.h>
 #include <signal.h>
 #include <stdlib.h>
+#include <sys/select.h>
+#include <sys/time.h>
 #include <unistd.h>
 #include <string.h>
 #include <fcntl.h>
@@ -133,7 +135,31 @@ void
 gjs_crash_after_timeout(int seconds)
 {
     pid_t parent_pid;
-    guint remaining;
+    int pipe_fds[2];
+    fd_set read_fds;
+    struct timeval term_time;
+    struct timeval remaining;
+    struct timeval now;
+    int old_flags;
+
+    /* We use a pipe to know in the child when the parent exited */
+    if (pipe(pipe_fds) != 0) {
+        fprintf(stderr, "Failed to create pipe to crash-in-timeout process: %s\n",
+                strerror(errno));
+        return;
+    }
+
+    /* We want pipe_fds[1] to only be open in the parent process; when it closes
+     * the child will see an EOF. Setting FD_CLOEXEC is protection in case the
+     * parent spawns off some process without properly closing fds.
+     */
+    old_flags = fcntl(pipe_fds[1], F_GETFD);
+    if (old_flags == -1 ||
+        fcntl(pipe_fds[1], F_SETFD, old_flags | FD_CLOEXEC) != 0) {
+        fprintf(stderr, "Couldn't make crash-timeout pipe FD_CLOEXEC: %s\n",
+                strerror(errno));
+        return;
+    }
 
     parent_pid = getpid();
 
@@ -147,12 +173,38 @@ gjs_crash_after_timeout(int seconds)
         break;
     default:
         /* parent */
+        close(pipe_fds[0]);
         return;
     }
 
-    remaining = seconds;
-    while ((remaining = sleep(remaining)) > 0) {
-        /* empty */
+    close (pipe_fds[1]);
+
+    gettimeofday (&now, NULL);
+
+    term_time = now;
+    term_time.tv_sec += seconds;
+
+    FD_ZERO(&read_fds);
+    FD_SET(pipe_fds[0], &read_fds);
+
+    while (TRUE) {
+        remaining.tv_sec = term_time.tv_sec - now.tv_sec;
+        remaining.tv_usec = term_time.tv_usec - now.tv_usec;
+        if (remaining.tv_usec < 0) {
+            remaining.tv_usec += 1000;
+            remaining.tv_sec -= 1;
+        }
+
+        if (remaining.tv_sec < 0) /* expired */
+            break;
+
+        select(pipe_fds[0] + 1, &read_fds, NULL, NULL, &remaining);
+        if (FD_ISSET(pipe_fds[0], &read_fds)) {
+            /* The parent exited */
+            _exit(0);
+        }
+
+        gettimeofday(&now, NULL);
     }
 
     if (kill(parent_pid, 0) == 0) {
@@ -160,5 +212,7 @@ gjs_crash_after_timeout(int seconds)
                 seconds, (int) parent_pid);
         kill(parent_pid, SIGABRT);
     }
+
+    _exit(1);
 }
 



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]