[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: GNU make jobserver redux
From: |
Paul Eggert |
Subject: |
Re: GNU make jobserver redux |
Date: |
Sun, 6 May 2001 23:59:49 -0700 (PDT) |
> Date: Sat, 5 May 2001 15:55:28 -0400
> From: "Paul D. Smith" <address@hidden>
>
> Yes, this is what I was suggesting. That instead of installing the
> SIGCHLD handler at the start of the make process and leaving it there,
> we only install it when we're going to do the read, then after we get
> the token we put back SIG_DFL for SIGCHLD.
Mightn't SIG_DFL cause the read() to misbehave on the Hurd, for
reasons similar to why SA_RESTART misbehaves?
If the current code is working in the field, perhaps it would be
better to disable SA_RESTART instead; that is closer to what is
currently occurring. Here's a proposed patch to implement that idea;
it replaces my earlier patch on this subject. (This patch also uses
bsd_signal in a couple more places than the earlier patch, to simplify
the code.)
2001-05-06 Paul Eggert <address@hidden>
Restart almost all system calls that are interrupted, instead
of worrying about EINTR. The lone exception is the read() for
job tokens.
* configure.in (HAVE_SA_RESTART): New macro.
(MAKE_JOBSERVER): Define to 1 only if HAVE_SA_RESTART.
* main.c (main): Use SA_RESTART instead of the old,
nonstandard SA_INTERRUPT.
* configure.in (AC_CHECK_FUNCS): Add bsd_signal.
* main.c (bsd_signal): New function or macro,
if the implementation doesn't supply it.
(The bsd_signal function will be in POSIX 1003.1-200x.)
(HANDLESIG): Remove.
(main, FATAL_SIG): Use bsd_signal instead of signal or HANDLESIG.
* make.h (EINTR_SET): Remove.
(SA_RESTART): New macro.
* arscan.c (ar_member_touch): Don't worry about EINTR.
* function.c (func_shell): Likewise.
* job.c (reap_children, free_child, new_job): Likewise.
* main.c (main): Likewise.
* remake.c (touch_file, name_mtime): Likewise.
* arscan.c (ar_member_touch): Fix bug uncovered by EINTR removal;
if fstat failed with errno!=EINTR, the error was ignored.
* job.c (set_child_handler_action_flags): New function.
(new_job): Use it to temporarily clear the SIGCHLD action flags
while reading the token.
===================================================================
RCS file: arscan.c,v
retrieving revision 3.79.1.0
retrieving revision 3.79.1.1
diff -pu -r3.79.1.0 -r3.79.1.1
--- arscan.c 2000/04/18 14:40:59 3.79.1.0
+++ arscan.c 2001/05/05 00:08:04 3.79.1.1
@@ -793,8 +793,8 @@ ar_member_touch (arname, memname)
if (AR_HDR_SIZE != write (fd, (char *) &ar_hdr, AR_HDR_SIZE))
goto lose;
/* The file's mtime is the time we we want. */
- while (fstat (fd, &statbuf) < 0 && EINTR_SET)
- ;
+ if (fstat (fd, &statbuf) < 0)
+ goto lose;
#if defined(ARFMAG) || defined(ARFZMAG) || defined(AIAMAG) ||
defined(WINDOWS32)
/* Advance member's time to that time */
for (i = 0; i < sizeof ar_hdr.ar_date; i++)
===================================================================
RCS file: configure.in,v
retrieving revision 3.79.1.3
retrieving revision 3.79.1.4
diff -pu -r3.79.1.3 -r3.79.1.4
--- configure.in 2000/07/24 06:44:47 3.79.1.3
+++ configure.in 2001/05/05 00:08:04 3.79.1.4
@@ -113,6 +113,7 @@ if test $ac_cv_func_gettimeofday = yes;
fi
AC_CHECK_FUNCS( memmove memcpy strchr strdup psignal mkstemp mktemp
fdopen \
+ bsd_signal \
dup2 getcwd sigsetmask sigaction getgroups setlinebuf \
seteuid setegid setreuid setregid pipe strerror strsignal)
@@ -196,9 +197,20 @@ case "$ac_cv_func_waitpid/$ac_cv_func_wa
no/no) has_wait_nohang=no ;;
esac
-case
"$ac_cv_func_pipe/$ac_cv_func_sigaction/$has_wait_nohang/$make_cv_job_server" in
- yes/yes/yes/yes) AC_DEFINE(MAKE_JOBSERVER, 1,
- [Define this to enable job server support in GNU make.]);;
+AC_CACHE_CHECK(for SA_RESTART, make_cv_sa_restart, [
+ AC_TRY_COMPILE([#include <signal.h>],
+ [return SA_RESTART;],
+ make_cv_sa_restart=yes,
+ make_cv_sa_restart=no)])
+if test "$make_cv_sa_restart" != no; then
+ AC_DEFINE(HAVE_SA_RESTART, 1,
+ [Define if <signal.h> defines the SA_RESTART constant.])
+fi
+
+case
"$ac_cv_func_pipe/$ac_cv_func_sigaction/$make_cv_sa_restart/$has_wait_nohang/$make_cv_job_server"
in
+ yes/yes/yes/yes/yes)
+ AC_DEFINE(MAKE_JOBSERVER, 1,
+ [Define this to enable job server support in GNU make.]);;
esac
dnl Allow building with dmalloc
===================================================================
RCS file: function.c,v
retrieving revision 3.79.1.0
retrieving revision 3.79.1.1
diff -pu -r3.79.1.0 -r3.79.1.1
--- function.c 2000/06/20 14:00:16 3.79.1.0
+++ function.c 2001/05/05 00:08:04 3.79.1.1
@@ -1435,8 +1435,7 @@ func_shell (o, argv, funcname)
buffer = (char *) xmalloc (maxlen + 1);
/* Read from the pipe until it gets EOF. */
- i = 0;
- do
+ for (i = 0; ; i += cc)
{
if (i == maxlen)
{
@@ -1444,12 +1443,10 @@ func_shell (o, argv, funcname)
buffer = (char *) xrealloc (buffer, maxlen + 1);
}
- errno = 0;
cc = read (pipedes[0], &buffer[i], maxlen - i);
- if (cc > 0)
- i += cc;
+ if (cc <= 0)
+ break;
}
- while (cc > 0 || EINTR_SET);
/* Close the read side of the pipe. */
#ifdef __MSDOS__
===================================================================
RCS file: job.c,v
retrieving revision 3.79.1.0
retrieving revision 3.79.1.3
diff -pu -r3.79.1.0 -r3.79.1.3
--- job.c 2000/06/23 15:54:56 3.79.1.0
+++ job.c 2001/05/07 06:51:03 3.79.1.3
@@ -195,6 +195,7 @@ extern int remote_status PARAMS ((int *e
RETSIGTYPE child_handler PARAMS ((int));
static void free_child PARAMS ((struct child *));
+static void set_child_handler_action_flags PARAMS ((int));
static void start_job_command PARAMS ((struct child *child));
static int load_too_high PARAMS ((void));
static int job_next_command PARAMS ((struct child *));
@@ -500,9 +501,6 @@ reap_children (block, err)
{
/* A remote status command failed miserably. Punt. */
remote_status_lose:
- if (EINTR_SET)
- continue;
-
pfatal_with_name ("remote_status");
}
else
@@ -529,10 +527,6 @@ reap_children (block, err)
if (pid < 0)
{
- /* EINTR? Try again. */
- if (EINTR_SET)
- goto local_wait;
-
/* The wait*() failed miserably. Punt. */
pfatal_with_name ("wait");
}
@@ -792,9 +786,8 @@ free_child (child)
/* Write a job token back to the pipe. */
- while (write (job_fds[1], &token, 1) != 1)
- if (!EINTR_SET)
- pfatal_with_name (_("write jobserver"));
+ if (write (job_fds[1], &token, 1) != 1)
+ pfatal_with_name (_("write jobserver"));
DB (DB_JOBS, (_("Released token for child 0x%08lx (%s).\n"),
(unsigned long int) child, child->file->name));
@@ -848,6 +841,25 @@ unblock_sigs ()
}
#endif
+/* Set the child handler action flags to FLAGS. */
+static void
+set_child_handler_action_flags (flags)
+ int flags;
+{
+#if defined HAVE_SIGACTION && defined HAVE_SA_RESTART
+ struct sigaction sa;
+ bzero ((char *) &sa, sizeof sa);
+ sa.sa_handler = child_handler;
+ sa.sa_flags = flags;
+# if defined SIGCHLD
+ sigaction (SIGCHLD, &sa, NULL);
+# endif
+# if defined SIGCLD && SIGCLD != SIGCHLD
+ sigaction (SIGCLD, &sa, NULL);
+# endif
+#endif
+}
+
/* Start a job to run the commands specified in CHILD.
CHILD is updated to reflect the commands and ID of the child process.
@@ -1483,6 +1495,8 @@ new_job (file)
while (1)
{
char token;
+ int read_yield;
+ int read_errno;
/* If we don't already have a job started, use our "free" token. */
if (!children)
@@ -1491,15 +1505,32 @@ new_job (file)
/* Read a token. As long as there's no token available we'll block.
If we get a SIGCHLD we'll return with EINTR. If one happened
before we got here we'll return immediately with EBADF because
- the signal handler closes the dup'd file descriptor. */
+ the signal handler closes the dup'd file descriptor.
+
+ Temporarily adjust the SIGCHLD action so that read returns
+ with EINTR if interrupted with SIGCHLD; otherwise, on the
+ Hurd (and perhaps other systems) the read might hang
+ indefinitely, because on these systems SA_RESTART causes
+ interrupted system calls to restart from where they left
+ off, not from the beginning of the call.
+
+ It's a pain to check for EINTR after each system call, so
+ normally SA_RESTART is used; this `read' call is the only
+ exception. */
+
+ set_child_handler_action_flags (0);
+ read_yield = read (job_rfd, &token, 1);
+ read_errno = errno;
+ set_child_handler_action_flags (SA_RESTART);
- if (read (job_rfd, &token, 1) == 1)
+ if (read_yield == 1)
{
DB (DB_JOBS, (_("Obtained token for child 0x%08lx (%s).\n"),
(unsigned long int) c, c->file->name));
break;
}
+ errno = read_errno;
if (errno != EINTR && errno != EBADF)
pfatal_with_name (_("read jobs pipe"));
===================================================================
RCS file: main.c,v
retrieving revision 3.79.1.0
retrieving revision 3.79.1.2
diff -pu -r3.79.1.0 -r3.79.1.2
--- main.c 2000/06/13 14:24:45 3.79.1.0
+++ main.c 2001/05/07 06:37:51 3.79.1.2
@@ -448,6 +448,27 @@ int fatal_signal_mask;
#endif
#endif
+#if !defined HAVE_BSD_SIGNAL && !defined bsd_signal
+# if !defined HAVE_SIGACTION
+# define bsd_signal signal
+# else
+static RETSIGTYPE
+(*bsd_signal) PARAMS ((int)) (sig, func)
+ int sig;
+ RETSIGTYPE (*func) PARAMS ((int));
+{
+ struct sigaction act, oact;
+ act.sa_handler = func;
+ act.sa_flags = SA_RESTART;
+ sigemptyset (&act.sa_mask);
+ sigaddset (&act.sa_mask, sig);
+ if (sigaction (sig, &act, &oact) != 0)
+ return SIG_ERR;
+ return oact.sa_handler;
+}
+# endif
+#endif
+
static struct file *
enter_command_line_file (name)
char *name;
@@ -839,8 +860,8 @@ int main (int argc, char ** argv)
#endif
#define FATAL_SIG(sig)
\
- if (signal ((sig), fatal_error_signal) == SIG_IGN) \
- (void) signal ((sig), SIG_IGN); \
+ if (bsd_signal (sig, fatal_error_signal) == SIG_IGN) \
+ bsd_signal (sig, SIG_IGN); \
else \
ADD_SIG (sig);
@@ -879,10 +900,10 @@ int main (int argc, char ** argv)
#ifdef HAVE_WAIT_NOHANG
# if defined SIGCHLD
- (void) signal (SIGCHLD, SIG_DFL);
+ (void) bsd_signal (SIGCHLD, SIG_DFL);
# endif
# if defined SIGCLD && SIGCLD != SIGCHLD
- (void) signal (SIGCLD, SIG_DFL);
+ (void) bsd_signal (SIGCLD, SIG_DFL);
# endif
#endif
@@ -1345,34 +1366,18 @@ int main (int argc, char ** argv)
If none of these are true, we don't need a signal handler at all. */
{
extern RETSIGTYPE child_handler PARAMS ((int sig));
-
-# if defined HAVE_SIGACTION
- struct sigaction sa;
-
- bzero ((char *)&sa, sizeof (struct sigaction));
- sa.sa_handler = child_handler;
-# if defined SA_INTERRUPT
- /* This is supposed to be the default, but what the heck... */
- sa.sa_flags = SA_INTERRUPT;
-# endif
-# define HANDLESIG(s) sigaction (s, &sa, NULL)
-# else
-# define HANDLESIG(s) signal (s, child_handler)
-# endif
-
- /* OK, now actually install the handlers. */
# if defined SIGCHLD
- (void) HANDLESIG (SIGCHLD);
+ bsd_signal (SIGCHLD, child_handler);
# endif
# if defined SIGCLD && SIGCLD != SIGCHLD
- (void) HANDLESIG (SIGCLD);
+ bsd_signal (SIGCLD, child_handler);
# endif
}
#endif
/* Let the user send us SIGUSR1 to toggle the -d flag during the run. */
#ifdef SIGUSR1
- (void) signal (SIGUSR1, debug_signal_handler);
+ bsd_signal (SIGUSR1, debug_signal_handler);
#endif
/* Define the initial list of suffixes for old-style rules. */
@@ -1527,9 +1532,8 @@ int main (int argc, char ** argv)
want job_slots to be 0 to indicate we're using the jobserver. */
while (--job_slots)
- while (write (job_fds[1], &c, 1) != 1)
- if (!EINTR_SET)
- pfatal_with_name (_("init jobserver pipe"));
+ if (write (job_fds[1], &c, 1) != 1)
+ pfatal_with_name (_("init jobserver pipe"));
/* Fill in the jobserver_fds struct for our children. */
===================================================================
RCS file: make.h,v
retrieving revision 3.79.1.0
retrieving revision 3.79.1.2
diff -pu -r3.79.1.0 -r3.79.1.2
--- make.h 2000/06/15 05:25:37 3.79.1.0
+++ make.h 2001/05/07 06:40:42 3.79.1.2
@@ -111,14 +111,6 @@ Boston, MA 02111-1307, USA. */
extern int errno;
#endif
-/* A shortcut for EINTR checking. Note you should be careful when negating
- this! That might not mean what you want if EINTR is not available. */
-#ifdef EINTR
-# define EINTR_SET (errno == EINTR)
-#else
-# define EINTR_SET (0)
-#endif
-
#ifndef isblank
# define isblank(c) ((c) == ' ' || (c) == '\t')
#endif
@@ -149,6 +141,10 @@ extern int errno;
# define sigmask(sig) (1 << ((sig) - 1))
#endif
+#ifndef HAVE_SA_RESTART
+# define SA_RESTART 0
+#endif
+
#ifdef HAVE_LIMITS_H
# include <limits.h>
#endif
===================================================================
RCS file: remake.c,v
retrieving revision 3.79.1.3
retrieving revision 3.79.1.4
diff -pu -r3.79.1.3 -r3.79.1.4
--- remake.c 2000/07/24 06:44:47 3.79.1.3
+++ remake.c 2001/05/05 00:08:04 3.79.1.4
@@ -933,13 +933,8 @@ touch_file (file)
{
struct stat statbuf;
char buf;
- int status;
- do
- status = fstat (fd, &statbuf);
- while (status < 0 && EINTR_SET);
-
- if (status < 0)
+ if (fstat (fd, &statbuf) < 0)
TOUCH_ERROR ("touch: fstat: ");
/* Rewrite character 0 same as it already is. */
if (read (fd, &buf, 1) < 0)
@@ -1243,13 +1238,12 @@ name_mtime (name)
{
struct stat st;
- while (stat (name, &st) != 0)
- if (errno != EINTR)
- {
- if (errno != ENOENT && errno != ENOTDIR)
- perror_with_name ("stat:", name);
- return NONEXISTENT_MTIME;
- }
+ if (stat (name, &st) != 0)
+ {
+ if (errno != ENOENT && errno != ENOTDIR)
+ perror_with_name ("stat:", name);
+ return NONEXISTENT_MTIME;
+ }
return FILE_TIMESTAMP_STAT_MODTIME (name, st);
}
- GNU make jobserver redux, Paul D. Smith, 2001/05/04
- Re: GNU make jobserver redux, Paul Eggert, 2001/05/04
- Re: GNU make jobserver redux, Paul D. Smith, 2001/05/04
- Re: GNU make jobserver redux, Paul Eggert, 2001/05/05
- Re: GNU make jobserver redux, Paul D. Smith, 2001/05/05
- Re: GNU make jobserver redux,
Paul Eggert <=
- Re: GNU make jobserver redux, Paul D. Smith, 2001/05/07
- Re: GNU make jobserver redux, Paul Eggert, 2001/05/07
- Re: GNU make jobserver redux, Paul D. Smith, 2001/05/07