[fixinc/fixincl.c patch] for eliminating strange children
korbb@egcs.cygnus.com
korbb@egcs.cygnus.com
Fri Apr 23 08:59:00 GMT 1999
Reply-To: ddsinc09@ix.netcom.com
The "grandparent" fixincl process needs to terminate its
shell server process before starting its children. This
patch will do that and also be much more rigorous about
waiting for just the right child to signal its exit notification.
I also added code to zero out the allocated regex_t array,
in case this gets linked with a library that needs it
done before calling re_compile_pattern().
Index: fixincl.c
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/fixinc/fixincl.c,v
retrieving revision 1.5
diff -u -r1.5 fixincl.c
--- fixincl.c 1999/03/31 11:51:27 1.5
+++ fixincl.c 1999/04/23 15:46:47
@@ -147,9 +147,11 @@
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 @@
{
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 @@
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);
@@ -258,116 +365,86 @@
*/
run_compiles ();
+ /*
+ 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. */
+
+ close_server ();
+ (void)wait ( (int*)NULL );
+
signal (SIGQUIT, SIG_IGN);
signal (SIGIOT, SIG_IGN);
signal (SIGPIPE, SIG_IGN);
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';
- }
+/* * * * * * * * * * * * *
+
+ 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 we did not get any files this time thru
- THEN we must be done. */
- if (file_name_ct == 0)
- return EXIT_SUCCESS;
+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
- child = fork ();
- if (child == NULLPROCESS)
- break;
+ for (;;) {
+ int status;
+ pid_t dead_kid = wait (&status);
- if (child == NOPROCESS)
- {
- fprintf (stderr, "Error %d (%s) forking in main\n",
- errno, strerror (errno));
- exit (EXIT_FAILURE);
- }
-#ifndef DEBUG
+ if (dead_kid == child)
{
- int status;
- (void)wait (&status);
+ 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 finished %d files %s\n", file_name_ct,
+ status ? strerror (status & 0xFF) : "ok");
+#endif
+ break; /* normal child completion */
}
-#else
- fprintf (stderr, "Waiting for %d to complete %d files\n",
- child, file_name_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)
{
- int status;
- pid_t dead_kid = wait (&status);
+ switch (errno) {
+ case EINTR:
+ case EAGAIN:
+ break;
+
+ default:
+ fprintf (stderr, "Error %d (%s) waiting for %d to finish\n",
+ errno, strerror( errno ), child );
+ /* FALLTHROUGH */
- 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");
+ case ECHILD: /* no children to wait for?? */
+ return;
+ }
}
-#endif
- }
-#else
-#error "NON-BOGUS LIMITS NOT SUPPORTED?!?!"
-#endif
- 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];
+ else
+ fprintf (stderr, "While waiting for pid %d, straggler child %d "
+ "exited with status %d\n", child, dead_kid,
+ WEXITSTATUS( status ));
- 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;
+ } done_waiting:;
}
@@ -475,6 +552,11 @@
REGEX_COUNT * sizeof (regex_t));
exit (EXIT_FAILURE);
}
+
+ /* Make sure re_compile_pattern does not stumble across invalid
+ data */
+
+ memset ( (void*)p_re, '\0', REGEX_COUNT * sizeof (regex_t) );
/* The patterns we search for are all egrep patterns.
In the shell version of this program, we invoke egrep
Index: server.c
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/fixinc/server.c,v
retrieving revision 1.4
diff -u -r1.4 server.c
--- server.c 1999/03/17 22:03:34 1.4
+++ server.c 1999/04/23 15:46:48
@@ -178,14 +178,17 @@
* 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: server.h
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/fixinc/server.h,v
retrieving revision 1.3
diff -u -r1.3 server.h
--- server.h 1999/03/03 07:41:52 1.3
+++ server.h 1999/04/23 15:46:48
@@ -90,5 +90,5 @@
int chain_open _P_ (( int in_fd,
t_pchar * pp_args,
pid_t * p_child));
-
+void close_server _P_ (( void ));
#endif /* FIXINC_SERVER_H */
More information about the Gcc-bugs
mailing list