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 36a86a70c6d55db1d6f8b2b2cacebf6a705cb424..c8c54366aa34229bdac189cebf59384a00c26e41 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 2a195a61eb4e4f55711cdea6fe45f06636e229d9..51f86b50e195f71aeecde3ed17a034cf5a2978a2 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 0c2a0bf6093d245bd974a10c4443955eda148680..f270f36df369c8b2e22900e55889e377ec5e233a 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 */