Add a timeout when waiting for child processes to exit before pppd
authorPaul Mackerras <paulus@samba.org>
Thu, 4 Nov 2004 09:46:50 +0000 (09:46 +0000)
committerPaul Mackerras <paulus@samba.org>
Thu, 4 Nov 2004 09:46:50 +0000 (09:46 +0000)
exits.  Send a SIGTERM to the child processes if the timeout expires
or if pppd gets a SIGTERM or SIGINT itself.

pppd/main.c
pppd/options.c
pppd/pppd.h

index 0bb94922e78d545545d134912412acb8ad22c49a..fe2e953eac94202a4ef469e4addfa4bd9ce040e8 100644 (file)
@@ -40,7 +40,7 @@
  * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  */
 
-#define RCSID  "$Id: main.c,v 1.138 2004/10/28 00:32:32 paulus Exp $"
+#define RCSID  "$Id: main.c,v 1.139 2004/11/04 09:46:50 paulus Exp $"
 
 #include <stdio.h>
 #include <ctype.h>
@@ -125,6 +125,8 @@ int do_callback;            /* != 0 if we should do callback next */
 int doing_callback;            /* != 0 if we are doing callback */
 int ppp_session_number;                /* Session number, for channels with such a
                                   concept (eg PPPoE) */
+int childwait_done;            /* have timed out waiting for children */
+
 #ifdef USE_TDB
 TDB_CONTEXT *pppdb;            /* database for storing status etc. */
 #endif
@@ -210,7 +212,8 @@ static void toggle_debug __P((int));
 static void open_ccp __P((int));
 static void bad_signal __P((int));
 static void holdoff_end __P((void *));
-static int reap_kids __P((int waitfor));
+static int reap_kids __P((void));
+static void childwait_end __P((void *));
 
 #ifdef USE_TDB
 static void update_db_entry __P((void));
@@ -627,16 +630,21 @@ main(argc, argv)
     }
 
     /* Wait for scripts to finish */
-    /* XXX should have a timeout here */
-    while (n_children > 0) {
+    reap_kids();
+    if (n_children > 0) {
+       if (child_wait > 0)
+           TIMEOUT(childwait_end, NULL, child_wait);
        if (debug) {
            struct subprocess *chp;
            dbglog("Waiting for %d child processes...", n_children);
            for (chp = children; chp != NULL; chp = chp->next)
                dbglog("  script %s, pid %d", chp->prog, chp->pid);
        }
-       if (reap_kids(1) < 0)
-           break;
+       while (n_children > 0 && !childwait_done) {
+           handle_events();
+           if (kill_link && !childwait_done)
+               childwait_end(NULL);
+       }
     }
 
     die(status);
@@ -677,8 +685,8 @@ handle_events()
        got_sigterm = 0;
     }
     if (got_sigchld) {
-       reap_kids(0);   /* Don't leave dead kids lying around */
        got_sigchld = 0;
+       reap_kids();    /* Don't leave dead kids lying around */
     }
     if (got_sigusr2) {
        open_ccp_flag = 1;
@@ -1735,22 +1743,37 @@ record_child(pid, prog, done, arg)
     }
 }
 
+/*
+ * childwait_end - we got fed up waiting for the child processes to
+ * exit, send them all a SIGTERM.
+ */
+static void
+childwait_end(arg)
+    void *arg;
+{
+    struct subprocess *chp;
+
+    for (chp = children; chp != NULL; chp = chp->next) {
+       if (debug)
+           dbglog("sending SIGTERM to process %d", chp->pid);
+       kill(chp->pid, SIGTERM);
+    }
+    childwait_done = 1;
+}
 
 /*
  * reap_kids - get status from any dead child processes,
  * and log a message for abnormal terminations.
  */
 static int
-reap_kids(waitfor)
-    int waitfor;
+reap_kids()
 {
     int pid, status;
     struct subprocess *chp, **prevp;
 
     if (n_children == 0)
        return 0;
-    while ((pid = waitpid(-1, &status, (waitfor? 0: WNOHANG))) != -1
-          && pid != 0) {
+    while ((pid = waitpid(-1, &status, WNOHANG)) != -1 && pid != 0) {
        for (prevp = &children; (chp = *prevp) != NULL; prevp = &chp->next) {
            if (chp->pid == pid) {
                --n_children;
index f9f10b74ca4859a1d9181f1629ace04d69691eb1..4870128868f63d10ecf1abc5b1562c06ca0f9416 100644 (file)
@@ -40,7 +40,7 @@
  * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  */
 
-#define RCSID  "$Id: options.c,v 1.93 2004/10/28 00:15:08 paulus Exp $"
+#define RCSID  "$Id: options.c,v 1.94 2004/11/04 09:46:50 paulus Exp $"
 
 #include <ctype.h>
 #include <stdio.h>
@@ -113,6 +113,7 @@ char        *bundle_name = NULL;    /* bundle name for multilink */
 bool   dump_options;           /* print out option values */
 bool   dryrun;                 /* print out option values and exit */
 char   *domain;                /* domain name set by domain option */
+int    child_wait = 5;         /* # seconds to wait for children at exit */
 
 #ifdef MAXOCTETS
 unsigned int  maxoctets = 0;    /* default - no limit */
@@ -270,6 +271,9 @@ option_t general_options[] = {
     { "dryrun", o_bool, &dryrun,
       "Stop after parsing, printing, and checking options", 1 },
 
+    { "child-timeout", o_int, &child_wait,
+      "Number of seconds to wait for child processes at exit" },
+
 #ifdef HAVE_MULTILINK
     { "multilink", o_bool, &multilink,
       "Enable multilink operation", OPT_PRIO | 1 },
index 02f983e4bdc9f18eab47437a2bc93eaa327b9a79..232aa32ae4e36130605bbe1854647ec2b0e9b2a0 100644 (file)
@@ -39,7 +39,7 @@
  * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
  * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  *
- * $Id: pppd.h,v 1.84 2004/10/31 22:23:18 paulus Exp $
+ * $Id: pppd.h,v 1.85 2004/11/04 09:46:50 paulus Exp $
  */
 
 /*
@@ -309,6 +309,7 @@ extern bool noendpoint;     /* don't send or accept endpt. discrim. */
 extern char    *bundle_name;   /* bundle name for multilink */
 extern bool    dump_options;   /* print out option values */
 extern bool    dryrun;         /* check everything, print options, exit */
+extern int     child_wait;     /* # seconds to wait for children at end */
 
 #ifdef MAXOCTETS
 extern unsigned int maxoctets;      /* Maximum octetes per session (in bytes) */