properly handle child processes
authorBruce Korb <korbb@gcc.gnu.org>
Mon, 26 Apr 1999 10:38:38 +0000 (10:38 +0000)
committerBruce Korb <korbb@gcc.gnu.org>
Mon, 26 Apr 1999 10:38:38 +0000 (10:38 +0000)
From-SVN: r26644

gcc/fixinc/fixincl.c
gcc/fixinc/server.c
gcc/fixinc/server.h

index 36a86a7..c8c5436 100644 (file)
@@ -147,9 +147,11 @@ pid_t process_chain_head = (pid_t) -1;
 const char incl_quote_pat[] = "^[ \t]*#[ \t]*include[ \t]*\"[^/]";
 regex_t incl_quote_re;
 
-char *load_file (const char *pzFile);
-void process (char *data, const char *file);
-void run_compiles (void);
+char *load_file (const char *);
+void process (char *, const char *);
+void run_compiles ();
+void wait_for_pid( pid_t, int );
+void initialize ();
 
 #include "fixincl.x"
 
@@ -164,8 +166,6 @@ main (argc, argv)
 {
   static const char gnu_lib_mark[] =
     "This file is part of the GNU C Library";
-  static const char var_not_found[] =
-    "fixincl ERROR:  %s environment variable not defined\n";
 
 #ifndef NO_BOGOSITY_LIMITS
 # define BOGUS_LIMIT    MINIMUM_MAXIMUM_LINES
@@ -212,6 +212,113 @@ main (argc, argv)
       exit (EXIT_FAILURE);
     }
 
+  initialize ();
+
+#ifndef NO_BOGOSITY_LIMITS
+  /*  Some systems only allow so many calls to fork(2).
+      This is inadequate for this program.  Consequently,
+      we must let a grandfather process spawn children
+      that then spawn all the processes that do the real work.
+      */
+  for (;;)
+    {
+      file_name_ct = 0;
+
+      {
+        char *pz_buf = file_name_buf;
+
+        /* Only the parent process can read from stdin without confusing
+           the world. (How does the child tell the parent to skip
+           forward?  Pipes and files behave differently.)  */
+
+        while (  (file_name_ct < BOGUS_LIMIT)
+              && (pz_buf < (file_name_buf + NAME_TABLE_SIZE - MAXPATHLEN)))
+          {
+            if (fgets (pz_buf, MAXPATHLEN, stdin) == (char *) NULL)
+              break;
+            while (isspace (*pz_buf))
+              pz_buf++;
+            if ((*pz_buf == '\0') || (*pz_buf == '#'))
+              continue;
+            apz_names[file_name_ct++] = pz_buf;
+            pz_buf += strlen (pz_buf);
+            while (isspace (pz_buf[-1]))
+              pz_buf--;
+            *pz_buf++ = '\0';
+          }
+      }
+
+      /*  IF we did not get any files this time thru
+          THEN we must be done.  */
+      if (file_name_ct == 0)
+        return EXIT_SUCCESS;
+
+      {
+        pid_t child = fork ();
+        if (child == NULLPROCESS)
+          break;
+
+        if (child == NOPROCESS)
+          {
+            fprintf (stderr, "Error %d (%s) forking in main\n",
+                     errno, strerror (errno));
+            exit (EXIT_FAILURE);
+          }
+
+        wait_for_pid( child, file_name_ct );
+      }
+    }
+#else
+#error "NON-BOGUS LIMITS NOT SUPPORTED?!?!"
+#endif
+
+  /*
+     Here we are the child of the grandparent process.  The parent
+     of all the little fixup processes.  We ignore the deaths of
+     our children.  */
+
+  signal (SIGCLD,  SIG_IGN);
+
+#ifdef DEBUG
+  fprintf (stderr, "Child start  --  processing %d files\n",
+           file_name_ct);
+#endif
+
+  /*  For every file specified in stdandard in
+      (except as throttled for bogus reasons)...
+      */
+  for (loop_ct = 0; loop_ct < file_name_ct; loop_ct++)
+    {
+      char *pz_data;
+      char *pz_file_name = apz_names[loop_ct];
+
+      if (access (pz_file_name, R_OK) != 0)
+        {
+          int erno = errno;
+          fprintf (stderr, "Cannot access %s from %s\n\terror %d (%s)\n",
+                   pz_file_name, getcwd ((char *) NULL, MAXPATHLEN),
+                   erno, strerror (erno));
+        }
+      else if (pz_data = load_file (pz_file_name), (pz_data != (char *) NULL))
+        {
+          if (strstr (pz_data, gnu_lib_mark) == (char *) NULL)
+            process (pz_data, pz_file_name);
+          free ((void *) pz_data);
+        }
+    }
+
+  return EXIT_SUCCESS;
+}
+
+
+/* * * * * * * * * * * * */
+
+void
+initialize()
+{
+  static const char var_not_found[] =
+    "fixincl ERROR:  %s environment variable not defined\n";
+
   {
     static const char var[] = "TARGET_MACHINE";
     pz_machine = getenv (var);
@@ -264,110 +371,74 @@ main (argc, argv)
   signal (SIGALRM, SIG_IGN);
   signal (SIGTERM, SIG_IGN);
 
-#ifndef NO_BOGOSITY_LIMITS
-  /*  Some systems only allow so many calls to fork(2).
-      This is inadequate for this program.  Consequently,
-      we must let a grandfather process spawn children
-      that then spawn all the processes that do the real work.
-      */
-  for (;;)
-    {
-      char *pz_buf;
-      pid_t child;
-
-      /* Only the parent process can read from stdin without confusing
-         the world. (How does the child tell the parent to skip
-         forward?  Pipes and files behave differently.)  */
-      file_name_ct = 0;
-      pz_buf = file_name_buf;
-      while (  (file_name_ct < BOGUS_LIMIT)
-            && (pz_buf < (file_name_buf + NAME_TABLE_SIZE - MAXPATHLEN)))
-        {
-          if (fgets (pz_buf, MAXPATHLEN, stdin) == (char *) NULL)
-            break;
-          while (isspace (*pz_buf))
-            pz_buf++;
-          if ((*pz_buf == '\0') || (*pz_buf == '#'))
-            continue;
-          apz_names[file_name_ct++] = pz_buf;
-          pz_buf += strlen (pz_buf);
-          while (isspace (pz_buf[-1]))
-            pz_buf--;
-          *pz_buf++ = '\0';
-        }
-
-      /*  IF we did not get any files this time thru
-          THEN we must be done.  */
-      if (file_name_ct == 0)
-        return EXIT_SUCCESS;
-
-      child = fork ();
-      if (child == NULLPROCESS)
-        break;
+  /*
+     Make sure that if we opened a server process, we close it now.
+     This is the grandparent process.  We don't need the server anymore
+     and our children should make their own.  */
 
-      if (child == NOPROCESS)
-        {
-          fprintf (stderr, "Error %d (%s) forking in main\n",
-                   errno, strerror (errno));
-          exit (EXIT_FAILURE);
-        }
-#ifndef DEBUG
-      {
-        int status;
-        (void)wait (&status);
-      }
-#else
-      fprintf (stderr, "Waiting for %d to complete %d files\n",
-               child, file_name_ct);
+  close_server ();
+  (void)wait ( (int*)NULL );
+}
 
-      {
-        int status;
-        pid_t dead_kid = wait (&status);
+/* * * * * * * * * * * * *
+   wait_for_pid  -  Keep calling `wait(2)' until it returns
+   the process id we are looking for.  Not every system has
+   `waitpid(2)'.  We also ensure that the children exit with success. */
 
-        if (dead_kid != child)
-          fprintf (stderr, "fixincl woke up from a strange child %d (not %d)\n",
-                   dead_kid, child);
-        else
-          fprintf (stderr, "child finished %d files %s\n", file_name_ct,
-                   status ? strerror (status & 0xFF) : "ok");
-      }
-#endif
-    }
-#else
-#error "NON-BOGUS LIMITS NOT SUPPORTED?!?!"
+void
+wait_for_pid( pid_t child, int file_name_ct )
+{
+#ifdef DEBUG
+  fprintf (stderr, "Waiting for %d to complete %d files\n",
+           child, file_name_ct);
 #endif
 
-  signal (SIGCLD,  SIG_IGN);
+  for (;;) {
+    int status;
+    pid_t dead_kid = wait (&status);
 
+    if (dead_kid == child)
+      {
+        if (! WIFEXITED( status ))
+          {
+            fprintf (stderr, "child process %d is hung on signal %d\n",
+                     child, WSTOPSIG( status ));
+            exit (EXIT_FAILURE);
+          }
+        if (WEXITSTATUS( status ) != 0)
+          {
+            fprintf (stderr, "child process %d exited with status %d\n",
+                     child, WEXITSTATUS( status ));
+            exit (EXIT_FAILURE);
+          }
 #ifdef DEBUG
-  fprintf (stderr, "Child start  --  processing %d files\n",
-           file_name_ct);
+        fprintf (stderr, "child finished %d files %s\n", file_name_ct,
+                 status ? strerror (status & 0xFF) : "ok");
 #endif
+        break; /* normal child completion */
+      }
 
-  /*  For every file specified in stdandard in
-      (except as throttled for bogus reasons)...
-      */
-  for (loop_ct = 0; loop_ct < file_name_ct; loop_ct++)
-    {
-      char *pz_data;
-      char *pz_file_name = apz_names[loop_ct];
+    /*
+       IF there is an error, THEN see if it is retryable.
+       If it is not retryable, then break out of this loop.  */
+    if (dead_kid == NOPROCESS)
+      {
+        switch (errno) {
+        case EINTR:
+        case EAGAIN:
+          break;
 
-      if (access (pz_file_name, R_OK) != 0)
-        {
-          int erno = errno;
-          fprintf (stderr, "Cannot access %s from %s\n\terror %d (%s)\n",
-                   pz_file_name, getcwd ((char *) NULL, MAXPATHLEN),
-                   erno, strerror (erno));
-        }
-      else if (pz_data = load_file (pz_file_name), (pz_data != (char *) NULL))
-        {
-          if (strstr (pz_data, gnu_lib_mark) == (char *) NULL)
-            process (pz_data, pz_file_name);
-          free ((void *) pz_data);
-        }
-    }
+        default:
+          fprintf (stderr, "Error %d (%s) waiting for %d to finish\n",
+                   errno, strerror( errno ), child );
+          /* FALLTHROUGH */
 
-  return EXIT_SUCCESS;
+        case ECHILD: /* no children to wait for?? */
+          return;
+        }
+      }
+  } done_waiting:;
 }
 
 
@@ -476,6 +547,12 @@ run_compiles ()
       exit (EXIT_FAILURE);
     }
 
+  /*  Make sure re_compile_pattern does not stumble across invalid
+      data */
+
+  memset ( (void*)p_re, '\0', REGEX_COUNT * sizeof (regex_t) );
+  memset ( (void*)&incl_quote_re, '\0', sizeof (regex_t) );
+
   /*  The patterns we search for are all egrep patterns.
       In the shell version of this program, we invoke egrep
       with the supplied pattern.  Here, we will run
index 2a195a6..51f86b5 100644 (file)
@@ -178,14 +178,17 @@ load_data (fp)
  *  Make certain the server process is dead, close the 
  *  pipes to it and from it, finally NULL out the file pointers
  */
-static void
+void
 close_server ()
 {
-  kill ((pid_t) server_id, SIGKILL);
-  server_id = NULLPROCESS;
-  fclose (server_pair.pf_read);
-  fclose (server_pair.pf_write);
-  server_pair.pf_read = server_pair.pf_write = (FILE *) NULL;
+  if (server_id != NULLPROCESS)
+    {
+      kill ((pid_t) server_id, SIGKILL);
+      server_id = NULLPROCESS;
+      fclose (server_pair.pf_read);
+      fclose (server_pair.pf_write);
+      server_pair.pf_read = server_pair.pf_write = (FILE *) NULL;
+    }
 }
 
 /*
index 0c2a0bf..f270f36 100644 (file)
@@ -90,5 +90,5 @@ pid_t proc2_open  _P_ (( t_fd_pair * p_pair, t_pchar * pp_args));
 int chain_open    _P_ (( int in_fd,
                          t_pchar * pp_args,
                          pid_t * p_child));
-
+void close_server _P_ (( void ));
 #endif /* FIXINC_SERVER_H */