Fix for EINTR problems when using jobserver.

New translation files.
Fix for @+ inside define macros being applied too widely.
Various other bug fixes.
This commit is contained in:
Paul Smith 2001-06-01 03:56:50 +00:00
parent 5d582d4ba0
commit ce2c6eadf1
15 changed files with 1834 additions and 1376 deletions

View File

@ -1,3 +1,45 @@
2001-05-06 Paul D. Smith <psmith@gnu.org>
Modify the EINTR handling.
* job.c (new_job): Reorganize the jobserver algorithm. Reorder
the way in which we manage the file descriptor/signal handler race
trap to be more efficient.
2001-05-06 Paul Eggert <eggert@twinsun.com>
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.
2001-05-02 Paul D. Smith <psmith@gnu.org>
* job.c (start_job_command): Don't add define/endef per-line flags
@ -11,6 +53,19 @@
(VMS_get_member_info): Calculate the timezone differences correctly.
Reported by John Fowler <jfowler@nyx.net>.
2001-03-14 Paul D. Smith <psmith@gnu.org>
* variable.c (lookup_variable) [VMS]: Null-terminate the variable
value before invoking define_variable().
Reported by John Fowler <jfowler@nyx.net>.
2001-02-07 Paul D. Smith <psmith@gnu.org>
* read.c (record_target_var): If we reset the variable due to a
command-line variable setting overriding it, turn off the "append"
flag.
2001-01-17 Paul D. Smith <psmith@gnu.org>
* variable.c (lookup_variable) [VMS]: When getting values from the

9
NEWS
View File

@ -1,8 +1,8 @@
GNU make NEWS -*-indented-text-*-
History of user-visible changes.
23 Jun 2000
30 May 2001
Copyright (C) 1992,93,94,95,96,97,98,99,2000 Free Software Foundation, Inc.
Copyright (C) 1992,93,94,95,96,97,98,99,2000,2001 Free Software Foundation, Inc.
See the end for copying conditions.
All changes mentioned here are more fully described in the GNU make
@ -12,12 +12,17 @@ Please send GNU make bug reports to <bug-make@gnu.org>.
See the README file and the GNU make manual for details on sending bug
reports.
Version 3.79.2
* New pseudo-target .LOW_RESOLUTION_TIME, superseding the configure
option --disable-nsec-timestamps. You might need this if your build
process depends on tools like "cp -p" preserving time stamps, since
"cp -p" (right now) doesn't preserve the subsecond portion of a time
stamp.
* Updated translations for Galician, Japanese, and Russian, and a new
Turkish translation.
Version 3.79.1
* .SECONDARY with no prerequisites now prevents any target from being

View File

@ -797,8 +797,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++)

View File

@ -3,7 +3,7 @@ AC_REVISION([$Id$])
AC_PREREQ(2.13)dnl dnl Minimum Autoconf version required.
AC_INIT(vpath.c)dnl dnl A distinctive file to look for in srcdir.
AM_INIT_AUTOMAKE(make, 3.79.1.0)
AM_INIT_AUTOMAKE(make, 3.79.1.90)
AM_CONFIG_HEADER(config.h)
dnl Regular configure stuff
@ -42,7 +42,7 @@ AC_HEADER_TIME
dnl Handle internationalization
ALL_LINGUAS="de es fr gl ja ko nl pl pt_BR ru"
ALL_LINGUAS="de es fr gl ja ko nl pl pt_BR ru tr"
pds_WITH_GETTEXT
jm_AC_TYPE_UINTMAX_T
@ -113,8 +113,9 @@ if test $ac_cv_func_gettimeofday = yes; then
fi
AC_CHECK_FUNCS( memmove memcpy strchr strdup psignal mkstemp mktemp fdopen \
dup2 getcwd sigsetmask sigaction getgroups setlinebuf \
seteuid setegid setreuid setregid pipe strerror strsignal)
bsd_signal dup2 getcwd sigsetmask sigaction getgroups \
setlinebuf seteuid setegid setreuid setregid pipe \
strerror strsignal)
AC_CHECK_SYMBOL(sys_siglist)
AC_FUNC_ALLOCA
@ -196,9 +197,20 @@ case "$ac_cv_func_waitpid/$ac_cv_func_wait3" in
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

10
dir.c
View File

@ -725,7 +725,7 @@ file_impossible (filename)
dir = find_directory ("[]");
#else
dirend = strrchr (p, '/');
#if defined (WINDOWS32) || defined (__MSDOS__)
# if defined (WINDOWS32) || defined (__MSDOS__)
/* Forward and backslashes might be mixed. We need the rightmost one. */
{
char *bslash = strrchr(p, '\\');
@ -735,13 +735,13 @@ file_impossible (filename)
if (!dirend && p[0] && p[1] == ':')
dirend = p + 1;
}
#endif /* WINDOWS32 or __MSDOS__ */
# endif /* WINDOWS32 or __MSDOS__ */
if (dirend == 0)
#ifdef _AMIGA
# ifdef _AMIGA
dir = find_directory ("");
#else /* !VMS && !AMIGA */
# else /* !VMS && !AMIGA */
dir = find_directory (".");
#endif /* AMIGA */
# endif /* AMIGA */
#endif /* VMS */
else
{

View File

@ -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);
buffer[i] = '\0';
/* Close the read side of the pipe. */

File diff suppressed because it is too large Load Diff

2437
i18n/ru.po

File diff suppressed because it is too large Load Diff

104
job.c
View File

@ -436,8 +436,8 @@ reap_children (block, err)
we'll keep reaping children. */
while ((children != 0 || shell_function_pid != 0) &&
(block || REAP_MORE))
while ((children != 0 || shell_function_pid != 0)
&& (block || REAP_MORE))
{
int remote = 0;
register int pid;
@ -500,9 +500,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
@ -511,7 +508,6 @@ reap_children (block, err)
#if !defined(__MSDOS__) && !defined(_AMIGA) && !defined(WINDOWS32)
if (any_local)
{
local_wait:
#ifdef VMS
vmsWaitForChildren (&status);
pid = c->pid;
@ -529,10 +525,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");
}
@ -737,7 +729,7 @@ reap_children (block, err)
update_status to its also_make files. */
notice_finished_file (c->file);
DB (DB_JOBS, (_("Removing child 0x%08lx PID %ld %s from chain.\n"),
DB (DB_JOBS, (_("Removing child 0x%08lx PID %ld%s from chain.\n"),
(unsigned long int) c, (long) c->pid,
c->remote ? _(" (remote)") : ""));
@ -792,9 +784,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 +839,26 @@ unblock_sigs ()
}
#endif
#ifdef MAKE_JOBSERVER
/* Set the child handler action flags to FLAGS. */
static void
set_child_handler_action_flags (flags)
int flags;
{
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.
@ -1489,34 +1500,73 @@ new_job (file)
while (1)
{
char token;
int got_token;
int saved_errno;
DB (DB_JOBS, ("Need a job token; we %shave children\n",
children ? "" : "don't "));
/* If we don't already have a job started, use our "free" token. */
if (!children)
break;
/* 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. */
We enable interruptible system calls before the read(2) so that if
we get a SIGCHLD while we're waiting, we'll return with EINTR and
we can process the death(s) and return tokens to the free pool.
if (read (job_rfd, &token, 1) == 1)
Once we return from the read, we immediately reinstate restartable
system calls. This allows us to not worry about checking for
EINTR on all the other system calls in the program.
There is one other twist: there is a span between the time
reap_children() does its last check for dead children and the time
the read(2) call is entered, below, where if a child dies we won't
notice. This is extremely serious as it could cause us to
deadlock, given the right set of events.
To avoid this, we do the following: before we reap_children(), we
dup(2) the read FD on the jobserver pipe. The read(2) call below
uses that new FD. In the signal handler, we close that FD. That
way, if a child dies during the section mentioned above, the
read(2) will be invoked with an invalid FD and will return
immediately with EBADF. */
/* Make sure we have a dup'd FD. */
if (job_rfd < 0)
{
DB (DB_JOBS, ("Duplicate the job FD\n"));
job_rfd = dup (job_fds[0]);
}
/* Reap anything that's currently waiting. */
reap_children (0, 0);
/* If our "free" token has become available, use it. */
if (!children)
break;
/* Set interruptible system calls, and read() for a job token. */
set_child_handler_action_flags (0);
got_token = read (job_rfd, &token, 1);
saved_errno = errno;
set_child_handler_action_flags (SA_RESTART);
/* If we got one, we're done here. */
if (got_token == 1)
{
DB (DB_JOBS, (_("Obtained token for child 0x%08lx (%s).\n"),
(unsigned long int) c, c->file->name));
break;
}
/* If the error _wasn't_ expected (EINTR or EBADF), punt. Otherwise,
go back and reap_children(), and try again. */
errno = saved_errno;
if (errno != EINTR && errno != EBADF)
pfatal_with_name (_("read jobs pipe"));
/* Re-dup the read side of the pipe, so the signal handler can
notify us if we miss a child. */
if (job_rfd < 0)
job_rfd = dup (job_fds[0]);
/* Something's done. We don't want to block for a whole child,
just reap whatever's there. */
reap_children (0, 0);
if (errno == EBADF)
DB (DB_JOBS, ("Read returned EBADF.\n"));
}
#endif

56
main.c
View File

@ -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. */

12
make.h
View File

@ -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

View File

@ -2223,7 +2223,7 @@ SUBDIRS = foo bar baz
subdirs: $(SUBDIRS)
$(SUBDIRS):
$(MAKE) -C $@
$(MAKE) -C $@@
foo: baz
@end group

7
read.c
View File

@ -1490,8 +1490,11 @@ record_target_var (filenames, defn, two_colon, origin, flocp)
current_variable_set_list = global;
gv = lookup_variable (v->name, len);
if (gv && (gv->origin == o_env_override || gv->origin == o_command))
define_variable_in_set (v->name, len, gv->value, gv->origin,
gv->recursive, vlist->set, flocp);
{
v = define_variable_in_set (v->name, len, gv->value, gv->origin,
gv->recursive, vlist->set, flocp);
v->append = 0;
}
}
/* Free name if not needed further. */

View File

@ -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)
@ -1239,13 +1234,12 @@ name_mtime (name)
{
struct stat st;
while (stat (name, &st) != 0)
if (!EINTR_SET)
{
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);
}

View File

@ -207,6 +207,7 @@ lookup_variable (name, length)
sptr++;
}
*nptr = '\0';
return define_variable (vname, length, nvalue, o_env, 1);
}