mirror of
https://github.com/mirror/make.git
synced 2025-01-14 06:10:12 +08:00
* Add new jobserver feature.
* Small updates to the manual * E.Zaretskii fix for new DJGPP version.
This commit is contained in:
parent
7f3ffd4019
commit
fc0fe4103a
65
ChangeLog
65
ChangeLog
@ -1,3 +1,68 @@
|
||||
1999-04-25 Paul D. Smith <psmith@gnu.org>
|
||||
|
||||
* make.texinfo: Updates to @dircategory and @direntry suggested by
|
||||
Karl Berry <karl@cs.umb.edu>.
|
||||
|
||||
1999-04-18 Eli Zaretskii <eliz@is.elta.co.il>
|
||||
|
||||
* configh.dos.template: Update to recognize that version 2.02 of
|
||||
DJGPP contains sys_siglist stuff.
|
||||
|
||||
1999-04-14 Paul D. Smith <psmith@gnu.org>
|
||||
|
||||
* make.texinfo (Options/Recursion): Document the job server.
|
||||
(Parallel): Tweaks.
|
||||
|
||||
1999-04-13 Paul D. Smith <psmith@gnu.org>
|
||||
|
||||
Implement a new "job server" feature; the implementation was
|
||||
suggested by Howard Chu <hyc@highlandsun.com>.
|
||||
|
||||
* configure.in (job-server): New disable option for job server
|
||||
support--it's enabled by default.
|
||||
|
||||
* NEWS: Summarize the new feature.
|
||||
|
||||
* acconfig.h: New definition MAKE_JOBSERVER if job server support
|
||||
is enabled.
|
||||
* config.h-vms.template: Undef MAKE_JOBSERVER for this port.
|
||||
* config.h.W32.template: Ditto.
|
||||
* config.ami.template: Ditto.
|
||||
|
||||
* main.c (struct command_switch): Add a new type: int_string.
|
||||
(switches[]) Use int_string for -j if MAKE_JOBSERVER.
|
||||
(init_switches): Initialize the new int_string switch type.
|
||||
(print_usage): New function, extracted from decode_switches().
|
||||
(decode_switches): Call it. Decode the new int_string switch type.
|
||||
(define_makeflags): Add new int_string switch data to MAKEFLAGS.
|
||||
(job_fds[]) Array to contain the pipe file descriptors.
|
||||
(main): Parse the job_slots_str option results. If necessary,
|
||||
create the pipe and seed it with tokens. Set the non-blocking bit
|
||||
for the read fd. Enable the signal handler for SIGCHLD even if we
|
||||
have a non-hanging wait; it's needed to interrupt the select() in
|
||||
job.c:start_waiting_job().
|
||||
|
||||
* make.h: Declare job_fds[].
|
||||
|
||||
* job.h (struct child): Add job_token field to store the token for
|
||||
this job (if any).
|
||||
|
||||
* job.c (reap_children): When a child is fully reaped, release the
|
||||
token back into the pipe.
|
||||
(free_child): If the child to be freed still has a token, put it
|
||||
back.
|
||||
(new_job): Initialize the job_token member.
|
||||
(start_waiting_job): For local jobs, if we're using the pipe, get
|
||||
a token before we check the load, etc. We do this by performing a
|
||||
non-blocking read in a loop. If the read fails, no token is
|
||||
available. Do a select on the fd to wait for a token. We need to
|
||||
re-enable the signal handler for SIGCHLD even if we have a
|
||||
non-hanging waitpid() or wait3(), so that the signal will
|
||||
interrupt the select() and we can wake up to reap children.
|
||||
(child_handler): Re-enable the signal handler. The count is still
|
||||
kept although it's not needed or used unless you don't have
|
||||
waitpid() or wait3().
|
||||
|
||||
1999-04-03 Paul D. Smith <psmith@gnu.org>
|
||||
|
||||
* remake.c (f_mtime): If: a) we found a file and b) we didn't
|
||||
|
11
NEWS
11
NEWS
@ -1,6 +1,6 @@
|
||||
GNU make NEWS -*-indented-text-*-
|
||||
History of user-visible changes.
|
||||
31 Mar 1999
|
||||
13 Apr 1999
|
||||
|
||||
Copyright (C) 1992,93,94,95,96,97,98,1999 Free Software Foundation, Inc.
|
||||
See the end for copying conditions.
|
||||
@ -23,6 +23,15 @@ Version 3.78
|
||||
|
||||
* Make allows CRLF sequences as well as traditional LF, for
|
||||
compatibility with makefiles created on other operating systems.
|
||||
|
||||
* A "job server" feature, proposed by Howard Chu <hyc@highlandsun.com>.
|
||||
|
||||
On systems that support POSIX pipe(2) semantics, GNU make can now pass
|
||||
-jN options to submakes rather than forcing them all to use -j1. The
|
||||
top make and all its sub-make processes use a pipe to communicate with
|
||||
each other to ensure that no more than N jobs are started across all
|
||||
makes. To get the old behavior of -j back, you can configure make
|
||||
with the --disable-job-server option.
|
||||
|
||||
Version 3.77
|
||||
|
||||
|
14
acconfig.h
14
acconfig.h
@ -10,6 +10,9 @@
|
||||
/* Define this if the SCCS `get' command understands the `-G<file>' option. */
|
||||
#undef SCCS_GET_MINUS_G
|
||||
|
||||
/* Define this to enable job server support in GNU make. */
|
||||
#undef MAKE_JOBSERVER
|
||||
|
||||
/* Define to be the nanoseconds member of struct stat's st_mtim,
|
||||
if it exists. */
|
||||
#undef ST_MTIM_NSEC
|
||||
@ -26,3 +29,14 @@
|
||||
/* Define to `unsigned long' or `unsigned long long'
|
||||
if <inttypes.h> doesn't define. */
|
||||
#undef uintmax_t
|
||||
|
||||
/* These are for AC_FUNC_SELECT */
|
||||
|
||||
/* Define if the system doesn't provide fd_set. */
|
||||
#undef fd_set
|
||||
|
||||
/* Define the type of the first arg to select(). */
|
||||
#undef fd_set_size_t
|
||||
|
||||
/* Define this if select() args need to be cast away from fd_set (HP-UX). */
|
||||
#undef SELECT_FD_SET_CAST
|
||||
|
81
acinclude.m4
81
acinclude.m4
@ -208,3 +208,84 @@ AC_DEFUN(jm_AC_TYPE_UINTMAX_T,
|
||||
fi
|
||||
fi
|
||||
])
|
||||
|
||||
|
||||
dnl ---------------------------------------------------------------------------
|
||||
dnl From Steve Robbins <steve@nyongwa.montreal.qc.ca>
|
||||
|
||||
dnl From a proposed change made on the autoconf list on 2 Feb 1999
|
||||
dnl http://sourceware.cygnus.com/ml/autoconf/1999-02/msg00001.html
|
||||
|
||||
AC_DEFUN(AC_FUNC_SELECT,
|
||||
[AC_CHECK_FUNCS(select)
|
||||
if test "$ac_cv_func_select" = yes; then
|
||||
AC_CHECK_HEADERS(unistd.h sys/types.h sys/time.h sys/select.h sys/socket.h)
|
||||
AC_MSG_CHECKING([argument types of select()])
|
||||
AC_CACHE_VAL(ac_cv_type_fd_set_size_t,dnl
|
||||
[AC_CACHE_VAL(ac_cv_type_fd_set,dnl
|
||||
[for ac_cv_type_fd_set in 'fd_set' 'int'; do
|
||||
for ac_cv_type_fd_set_size_t in 'int' 'size_t' 'unsigned long' 'unsigned'; do
|
||||
for ac_type_timeval in 'struct timeval' 'const struct timeval'; do
|
||||
AC_TRY_COMPILE(dnl
|
||||
[#ifdef HAVE_SYS_TIME_H
|
||||
#include <sys/time.h>
|
||||
#endif
|
||||
#ifdef HAVE_SYS_TYPES_H
|
||||
#include <sys/types.h>
|
||||
#endif
|
||||
#ifdef HAVE_UNISTD_H
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
#ifdef HAVE_SYS_SELECT_H
|
||||
#include <sys/select.h>
|
||||
#endif
|
||||
#ifdef HAVE_SYS_SOCKET_H
|
||||
#include <sys/socket.h>
|
||||
#endif],
|
||||
[extern select ($ac_cv_type_fd_set_size_t,
|
||||
$ac_cv_type_fd_set *, $ac_cv_type_fd_set *, $ac_cv_type_fd_set *,
|
||||
$ac_type_timeval *);],
|
||||
[ac_found=yes ; break 3],ac_found=no)
|
||||
done
|
||||
done
|
||||
done
|
||||
])dnl AC_CACHE_VAL
|
||||
])dnl AC_CACHE_VAL
|
||||
if test "$ac_found" = no; then
|
||||
AC_MSG_ERROR([can't determine argument types])
|
||||
fi
|
||||
|
||||
AC_MSG_RESULT([select($ac_cv_type_fd_set_size_t,$ac_cv_type_fd_set *,...)])
|
||||
AC_DEFINE_UNQUOTED(fd_set_size_t, $ac_cv_type_fd_set_size_t)
|
||||
ac_cast=
|
||||
if test "$ac_cv_type_fd_set" != fd_set; then
|
||||
# Arguments 2-4 are not fd_set. Some weirdo systems use fd_set type for
|
||||
# FD_SET macros, but insist that you cast the argument to select. I don't
|
||||
# understand why that might be, but it means we cannot define fd_set.
|
||||
AC_EGREP_CPP(dnl
|
||||
changequote(<<,>>)dnl
|
||||
<<(^|[^a-zA-Z_0-9])fd_set[^a-zA-Z_0-9]>>dnl
|
||||
changequote([,]),dnl
|
||||
[#ifdef HAVE_SYS_TIME_H
|
||||
#include <sys/time.h>
|
||||
#endif
|
||||
#ifdef HAVE_SYS_TYPES_H
|
||||
#include <sys/types.h>
|
||||
#endif
|
||||
#ifdef HAVE_UNISTD_H
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
#ifdef HAVE_SYS_SELECT_H
|
||||
#include <sys/select.h>
|
||||
#endif
|
||||
#ifdef HAVE_SYS_SOCKET_H
|
||||
#include <sys/socket.h>
|
||||
#endif],dnl
|
||||
# We found fd_set type in a header, need special cast
|
||||
ac_cast="($ac_cv_type_fd_set *)",dnl
|
||||
# No fd_set type; it is safe to define it
|
||||
AC_DEFINE_UNQUOTED(fd_set,$ac_cv_type_fd_set))
|
||||
fi
|
||||
AC_DEFINE_UNQUOTED(SELECT_FD_SET_CAST,$ac_cast)
|
||||
fi
|
||||
])
|
||||
|
@ -176,6 +176,13 @@
|
||||
/* Define this if the SCCS `get' command understands the `-G<file>' option. */
|
||||
/* #undef SCCS_GET_MINUS_G */
|
||||
|
||||
/* Define this to enable job server support in GNU make. */
|
||||
/* #undef MAKE_JOBSERVER */
|
||||
|
||||
/* Define to be the nanoseconds member of struct stat's st_mtim,
|
||||
if it exists. */
|
||||
/* #undef ST_MTIM_NSEC */
|
||||
|
||||
/* Define this if the C library defines the variable `sys_siglist'. */
|
||||
/* #undef HAVE_SYS_SIGLIST */
|
||||
|
||||
|
@ -180,6 +180,13 @@
|
||||
/* Define this if the SCCS `get' command understands the `-G<file>' option. */
|
||||
/* #undef SCCS_GET_MINUS_G */
|
||||
|
||||
/* Define this to enable job server support in GNU make. */
|
||||
/* #undef MAKE_JOBSERVER */
|
||||
|
||||
/* Define to be the nanoseconds member of struct stat's st_mtim,
|
||||
if it exists. */
|
||||
/* #undef ST_MTIM_NSEC */
|
||||
|
||||
/* Define this if the C library defines the variable `sys_siglist'. */
|
||||
/* #undefine HAVE_SYS_SIGLIST */
|
||||
|
||||
|
@ -191,6 +191,13 @@
|
||||
/* Define this if the SCCS `get' command understands the `-G<file>' option. */
|
||||
/* #undef SCCS_GET_MINUS_G */
|
||||
|
||||
/* Define this to enable job server support in GNU make. */
|
||||
/* #undef MAKE_JOBSERVER */
|
||||
|
||||
/* Define to be the nanoseconds member of struct stat's st_mtim,
|
||||
if it exists. */
|
||||
/* #undef ST_MTIM_NSEC */
|
||||
|
||||
/* Define this if the C library defines the variable `sys_siglist'. */
|
||||
/* #undef HAVE_SYS_SIGLIST */
|
||||
|
||||
|
@ -1,4 +1,3 @@
|
||||
/* Generated automatically from configure.in by autoheader. DO NOT EDIT! */
|
||||
|
||||
/* Many things are defined already by a system header. */
|
||||
#include <sys/config.h>
|
||||
@ -9,8 +8,20 @@
|
||||
/* Version of this package (needed by automake) */
|
||||
#define VERSION "%VERSION%"
|
||||
|
||||
#if __DJGPP__ > 2 || __DJGPP_MINOR__ > 1
|
||||
|
||||
/* Define if `sys_siglist' is declared by <signal.h>. */
|
||||
# define SYS_SIGLIST_DECLARED 1
|
||||
|
||||
/* Define this if the C library defines the variable `_sys_siglist'. */
|
||||
# define HAVE_SYS_SIGLIST 1
|
||||
|
||||
#else
|
||||
|
||||
/* Define NSIG. */
|
||||
#define NSIG SIGMAX
|
||||
# define NSIG SIGMAX
|
||||
|
||||
#endif
|
||||
|
||||
/* Define if you have sigsetmask. */
|
||||
#define HAVE_SIGSETMASK 1
|
||||
|
17
configure.in
17
configure.in
@ -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.77.90)
|
||||
AM_INIT_AUTOMAKE(make, 3.77.xx)
|
||||
AM_CONFIG_HEADER(config.h)
|
||||
|
||||
dnl Regular configure stuff
|
||||
@ -57,7 +57,7 @@ AC_CHECK_LIB(posix4, clock_gettime)
|
||||
|
||||
AC_CHECK_FUNCS(memmove strdup psignal mktemp pstat_getdynamic \
|
||||
clock_gettime dup2 getcwd sigsetmask getgroups setlinebuf \
|
||||
seteuid setegid setreuid setregid strerror strsignal)
|
||||
seteuid setegid setreuid setregid strerror strsignal pipe)
|
||||
AC_CHECK_SYMBOL(sys_siglist)
|
||||
AC_FUNC_ALLOCA
|
||||
AC_FUNC_VFORK
|
||||
@ -66,6 +66,7 @@ AC_FUNC_STRCOLL
|
||||
AC_FUNC_CLOSEDIR_VOID
|
||||
AC_FUNC_SETVBUF_REVERSED
|
||||
AC_FUNC_GETLOADAVG
|
||||
AC_FUNC_SELECT
|
||||
AC_CHECK_LIB(kstat, kstat_open)
|
||||
|
||||
# Check out the wait reality.
|
||||
@ -124,6 +125,18 @@ AC_ARG_WITH(customs,
|
||||
;;
|
||||
esac])
|
||||
|
||||
dnl See if we can handle the job server feature, and if the user wants it.
|
||||
|
||||
AC_ARG_ENABLE(job-server,
|
||||
[ --disable-job-server Disallow recursive make communication during -jN],
|
||||
[make_cv_job_server="$enableval"],
|
||||
[make_cv_job_server="yes"])
|
||||
|
||||
case "$ac_cv_func_pipe $make_cv_job_server" in
|
||||
"yes yes") AC_DEFINE(MAKE_JOBSERVER) ;;
|
||||
esac
|
||||
|
||||
|
||||
AC_CACHE_CHECK(for location of SCCS get command, make_cv_path_sccs_get, [
|
||||
if test -f /usr/sccs/get; then
|
||||
make_cv_path_sccs_get=/usr/sccs/get
|
||||
|
144
job.c
144
job.c
@ -1,5 +1,5 @@
|
||||
/* Job execution and handling for GNU Make.
|
||||
Copyright (C) 1988,89,90,91,92,93,94,95,96,97 Free Software Foundation, Inc.
|
||||
Copyright (C) 1988,89,90,91,92,93,94,95,96,97,99 Free Software Foundation, Inc.
|
||||
This file is part of GNU Make.
|
||||
|
||||
GNU Make is free software; you can redistribute it and/or modify
|
||||
@ -257,10 +257,10 @@ vmsWaitForChildren(int *status)
|
||||
#endif
|
||||
|
||||
|
||||
/* If we can't use waitpid() or wait3(), then we use a signal handler
|
||||
to track the number of SIGCHLD's we got. This is less robust. */
|
||||
|
||||
#ifndef WAIT_NOHANG
|
||||
/* Count the number of dead children we have. If we can use wait3() or
|
||||
waitpid() then we'll never use this count: it's completely unnecessary.
|
||||
But we need the handler installed to interrupt the select() call for
|
||||
the jobs pipe, so we might as well keep it. */
|
||||
|
||||
static unsigned int dead_children = 0;
|
||||
|
||||
@ -273,10 +273,9 @@ child_handler (sig)
|
||||
++dead_children;
|
||||
|
||||
if (debug_flag)
|
||||
printf ("Got a SIGCHLD; %d unreaped children.\n", dead_children);
|
||||
printf ("Got a SIGCHLD; %u unreaped children.\n", dead_children);
|
||||
}
|
||||
|
||||
#endif /* WAIT_NOHANG */
|
||||
|
||||
extern int shell_function_pid, shell_function_completed;
|
||||
|
||||
@ -292,11 +291,15 @@ reap_children (block, err)
|
||||
{
|
||||
WAIT_T status;
|
||||
#ifdef WAIT_NOHANG
|
||||
int dead_children = 1; /* Initially, assume we have some. */
|
||||
/* Initially, assume we have some. */
|
||||
int reap_more = 1;
|
||||
# define REAP_MORE reap_more
|
||||
#else
|
||||
# define REAP_MORE dead_children
|
||||
#endif
|
||||
|
||||
while ((children != 0 || shell_function_pid != 0) &&
|
||||
(block || dead_children))
|
||||
(block || REAP_MORE))
|
||||
{
|
||||
int remote = 0;
|
||||
register int pid;
|
||||
@ -312,8 +315,12 @@ reap_children (block, err)
|
||||
error (NILF, "*** Waiting for unfinished jobs....");
|
||||
}
|
||||
|
||||
#ifndef WAIT_NOHANG
|
||||
/* We have one less dead child to reap.
|
||||
/* We have one less dead child to reap. As noted in
|
||||
child_handler() above, this count is completely unimportant for
|
||||
all modern, POSIX-y systems that support wait3() or waitpid().
|
||||
The rest of this comment below applies only to early, broken
|
||||
pre-POSIX systems. We keep the count only because... it's there...
|
||||
|
||||
The test and decrement are not atomic; if it is compiled into:
|
||||
register = dead_children - 1;
|
||||
dead_children = register;
|
||||
@ -327,7 +334,6 @@ reap_children (block, err)
|
||||
|
||||
if (dead_children > 0)
|
||||
--dead_children;
|
||||
#endif
|
||||
|
||||
any_remote = 0;
|
||||
any_local = shell_function_pid != 0;
|
||||
@ -405,7 +411,7 @@ reap_children (block, err)
|
||||
{
|
||||
/* No local children are dead. */
|
||||
#ifdef WAIT_NOHANG
|
||||
dead_children = 0;
|
||||
reap_more = 0;
|
||||
#endif
|
||||
if (block && any_remote)
|
||||
{
|
||||
@ -612,6 +618,22 @@ reap_children (block, err)
|
||||
live and call reap_children again. */
|
||||
block_sigs ();
|
||||
|
||||
#ifdef MAKE_JOBSERVER
|
||||
/* If this job has a token out, return it. */
|
||||
if (c->job_token)
|
||||
{
|
||||
assert(job_slots_used > 0);
|
||||
write (job_fds[1], &c->job_token, 1);
|
||||
if (debug_flag)
|
||||
printf ("Released token `%c' for child 0x%08lx.\n",
|
||||
c->job_token, (unsigned long int) c);
|
||||
c->job_token = 0;
|
||||
}
|
||||
#endif
|
||||
/* There is now another slot open. */
|
||||
if (job_slots_used > 0)
|
||||
--job_slots_used;
|
||||
|
||||
/* Remove the child from the chain and free it. */
|
||||
if (lastc == 0)
|
||||
children = c->next;
|
||||
@ -620,10 +642,6 @@ reap_children (block, err)
|
||||
if (! handling_fatal_signal) /* Don't bother if about to die. */
|
||||
free_child (c);
|
||||
|
||||
/* There is now another slot open. */
|
||||
if (job_slots_used > 0)
|
||||
--job_slots_used;
|
||||
|
||||
unblock_sigs ();
|
||||
|
||||
/* If the job failed, and the -k flag was not given, die,
|
||||
@ -662,6 +680,19 @@ free_child (child)
|
||||
free ((char *) child->environment);
|
||||
}
|
||||
|
||||
#ifdef MAKE_JOBSERVER
|
||||
/* If this child has a token it hasn't relinquished, give it up now.
|
||||
This can happen if the job completes immediately, mainly because
|
||||
all the command lines evaluated to empty strings. */
|
||||
if (child->job_token)
|
||||
{
|
||||
write (job_fds[1], &child->job_token, 1);
|
||||
if (debug_flag)
|
||||
printf ("Freed token `%c' for child 0x%08lx.\n",
|
||||
child->job_token, (unsigned long int) child);
|
||||
}
|
||||
#endif
|
||||
|
||||
free ((char *) child);
|
||||
}
|
||||
|
||||
@ -1083,28 +1114,77 @@ static int
|
||||
start_waiting_job (c)
|
||||
struct child *c;
|
||||
{
|
||||
struct file *f = c->file;
|
||||
|
||||
/* If we can start a job remotely, we always want to, and don't care about
|
||||
the local load average. We record that the job should be started
|
||||
remotely in C->remote for start_job_command to test. */
|
||||
|
||||
c->remote = start_remote_job_p (1);
|
||||
|
||||
/* If this job is to be started locally, and we are already running
|
||||
some jobs, make this one wait if the load average is too high. */
|
||||
if (!c->remote && job_slots_used > 0 && load_too_high ())
|
||||
/* If not, start it locally. */
|
||||
if (!c->remote)
|
||||
{
|
||||
/* Put this child on the chain of children waiting
|
||||
for the load average to go down. */
|
||||
set_command_state (c->file, cs_running);
|
||||
c->next = waiting_jobs;
|
||||
waiting_jobs = c;
|
||||
return 0;
|
||||
#ifdef MAKE_JOBSERVER
|
||||
/* If this is not a recurse command and we are controlling
|
||||
multiple jobs, obtain a token before starting child. */
|
||||
if (job_fds[0] >= 0 && !f->cmds->any_recurse)
|
||||
{
|
||||
fd_set rfds;
|
||||
|
||||
FD_ZERO(&rfds);
|
||||
FD_SET(job_fds[0], &rfds);
|
||||
|
||||
/* Read a token. We set the non-blocking bit on this earlier,
|
||||
so if there's no token to be read we'll fall through to the
|
||||
select. The select block until (a) there's data to read,
|
||||
in which case we come back around and try to grab the token
|
||||
before someone else does, or (b) a signal, such as SIGCHLD,
|
||||
is caught (because we installed a handler for it). If the
|
||||
latter, call reap_children() to try to free up some slots. */
|
||||
|
||||
while (read (job_fds[0], &c->job_token, 1) < 1)
|
||||
{
|
||||
int r = select (job_fds[0]+1, SELECT_FD_SET_CAST &rfds,
|
||||
NULL, NULL, NULL);
|
||||
|
||||
if (r < 0)
|
||||
{
|
||||
#ifdef EINTR
|
||||
if (errno != EINTR)
|
||||
/* We should definitely handle this more gracefully!
|
||||
What kinds of things can happen here? ^C closes the
|
||||
pipe? Something else closes it? */
|
||||
pfatal_with_name ("read jobs pipe");
|
||||
#endif
|
||||
/* We were interrupted; handle any dead children. */
|
||||
reap_children (1, 0);
|
||||
}
|
||||
}
|
||||
|
||||
assert(c->job_token != 0);
|
||||
if (debug_flag)
|
||||
printf ("Obtained token `%c' for child 0x%08lx.\n",
|
||||
c->job_token, (unsigned long int) c);
|
||||
}
|
||||
#endif
|
||||
/* If we are running at least one job already and the load average
|
||||
is too high, make this one wait. */
|
||||
if (job_slots_used > 0 && load_too_high ())
|
||||
{
|
||||
/* Put this child on the chain of children waiting
|
||||
for the load average to go down. */
|
||||
set_command_state (f, cs_running);
|
||||
c->next = waiting_jobs;
|
||||
waiting_jobs = c;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* Start the first command; reap_children will run later command lines. */
|
||||
start_job_command (c);
|
||||
|
||||
switch (c->file->command_state)
|
||||
switch (f->command_state)
|
||||
{
|
||||
case cs_running:
|
||||
c->next = children;
|
||||
@ -1120,16 +1200,16 @@ start_waiting_job (c)
|
||||
|
||||
case cs_not_started:
|
||||
/* All the command lines turned out to be empty. */
|
||||
c->file->update_status = 0;
|
||||
f->update_status = 0;
|
||||
/* FALLTHROUGH */
|
||||
|
||||
case cs_finished:
|
||||
notice_finished_file (c->file);
|
||||
notice_finished_file (f);
|
||||
free_child (c);
|
||||
break;
|
||||
|
||||
default:
|
||||
assert (c->file->command_state == cs_finished);
|
||||
assert (f->command_state == cs_finished);
|
||||
break;
|
||||
}
|
||||
|
||||
@ -1157,8 +1237,9 @@ new_job (file)
|
||||
/* Chop the commands up into lines if they aren't already. */
|
||||
chop_commands (cmds);
|
||||
|
||||
/* Wait for a job slot to be freed up. If we allow an infinite number
|
||||
don't bother; also job_slots will == 0 if we're using the job pipe. */
|
||||
if (job_slots != 0)
|
||||
/* Wait for a job slot to be freed up. */
|
||||
while (job_slots_used == job_slots)
|
||||
reap_children (1, 0);
|
||||
|
||||
@ -1273,6 +1354,7 @@ new_job (file)
|
||||
c->command_ptr = 0;
|
||||
c->environment = 0;
|
||||
c->sh_batch_file = NULL;
|
||||
c->job_token = 0;
|
||||
|
||||
/* Fetch the first command line to be run. */
|
||||
if (job_next_command (c))
|
||||
|
5
job.h
5
job.h
@ -1,5 +1,5 @@
|
||||
/* Definitions for managing subprocesses in GNU Make.
|
||||
Copyright (C) 1992, 1993, 1996 Free Software Foundation, Inc.
|
||||
Copyright (C) 1992, 1993, 1996, 1999 Free Software Foundation, Inc.
|
||||
This file is part of GNU Make.
|
||||
|
||||
GNU Make is free software; you can redistribute it and/or modify
|
||||
@ -39,13 +39,14 @@ struct child
|
||||
int efn; /* Completion event flag number */
|
||||
int cstatus; /* Completion status */
|
||||
#endif
|
||||
char *sh_batch_file; /* Script file for shell commands */
|
||||
unsigned int remote:1; /* Nonzero if executing remotely. */
|
||||
|
||||
unsigned int noerror:1; /* Nonzero if commands contained a `-'. */
|
||||
|
||||
unsigned int good_stdin:1; /* Nonzero if this child has a good stdin. */
|
||||
unsigned int deleted:1; /* Nonzero if targets have been deleted. */
|
||||
char *sh_batch_file; /* Script file for shell commands */
|
||||
char job_token; /* The token read from the job pipe. */
|
||||
};
|
||||
|
||||
extern struct child *children;
|
||||
|
306
main.c
306
main.c
@ -1,5 +1,5 @@
|
||||
/* Argument parsing and main program of GNU Make.
|
||||
Copyright (C) 1988,89,90,91,94,95,96,97,98 Free Software Foundation, Inc.
|
||||
Copyright (C) 1988,89,90,91,94,95,96,97,98,99 Free Software Foundation, Inc.
|
||||
This file is part of GNU Make.
|
||||
|
||||
GNU Make is free software; you can redistribute it and/or modify
|
||||
@ -34,6 +34,9 @@ MA 02111-1307, USA. */
|
||||
#include <windows.h>
|
||||
#include "pathstuff.h"
|
||||
#endif
|
||||
#if defined(MAKE_JOBSERVER) && defined(HAVE_FCNTL_H)
|
||||
# include <fcntl.h>
|
||||
#endif
|
||||
|
||||
#ifdef _AMIGA
|
||||
int __stack = 20000; /* Make sure we have 20K of stack space */
|
||||
@ -83,6 +86,7 @@ struct command_switch
|
||||
flag, /* Turn int flag on. */
|
||||
flag_off, /* Turn int flag off. */
|
||||
string, /* One string per switch. */
|
||||
int_string, /* One string. */
|
||||
positive_int, /* A positive integer. */
|
||||
floating, /* A floating-point number (double). */
|
||||
ignore /* Ignored. */
|
||||
@ -190,9 +194,16 @@ static struct stringlist *makefiles = 0;
|
||||
unsigned int job_slots = 1;
|
||||
unsigned int default_job_slots = 1;
|
||||
|
||||
/* Value of job_slots that means no limit. */
|
||||
static char *job_slots_str = "1";
|
||||
|
||||
#ifndef MAKE_JOBSERVER
|
||||
/* Value of job_slots that means no limit. */
|
||||
static unsigned int inf_jobs = 0;
|
||||
#endif
|
||||
|
||||
/* File descriptors for the jobs pipe. */
|
||||
|
||||
int job_fds[2] = { -1, -1 };
|
||||
|
||||
/* Maximum load average at which multiple jobs will be run.
|
||||
Negative values mean unlimited, while zero means limit to
|
||||
@ -264,8 +275,13 @@ static const struct command_switch switches[] =
|
||||
{ 'I', string, (char *) &include_directories, 1, 1, 0, 0, 0,
|
||||
"include-dir", "DIRECTORY",
|
||||
"Search DIRECTORY for included makefiles" },
|
||||
{ 'j', positive_int, (char *) &job_slots, 1, 1, 0,
|
||||
{ 'j',
|
||||
#ifndef MAKE_JOBSERVER
|
||||
positive_int, (char *) &job_slots, 1, 1, 0,
|
||||
(char *) &inf_jobs, (char *) &default_job_slots,
|
||||
#else
|
||||
int_string, (char *)&job_slots_str, 1, 1, 0, "0", "1",
|
||||
#endif
|
||||
"jobs", "N",
|
||||
"Allow N jobs at once; infinite jobs with no arg" },
|
||||
{ 'k', flag, (char *) &keep_going_flag, 1, 1, 0,
|
||||
@ -1144,13 +1160,19 @@ int main (int argc, char ** argv)
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef HAVE_WAIT_NOHANG
|
||||
#if defined(MAKE_JOBSERVER) || !defined(HAVE_WAIT_NOHANG)
|
||||
/* If we don't have a hanging wait we have to fall back to old, broken
|
||||
functionality here and rely on the signal handler and counting
|
||||
children.
|
||||
|
||||
Also, if we're using the jobs pipe we need a signal handler so that
|
||||
SIGCHLD is not ignored; we need it to interrupt select(2) in
|
||||
job.c:start_waiting_job() if we're waiting on the pipe for a token. */
|
||||
{
|
||||
extern RETSIGTYPE child_handler PARAMS ((int sig));
|
||||
|
||||
/* Set up to handle children dying. This must be done before
|
||||
reading in the makefiles so that `shell' function calls will work.
|
||||
Note we only do this if we have to. */
|
||||
reading in the makefiles so that `shell' function calls will work. */
|
||||
# if defined SIGCHLD
|
||||
(void) signal (SIGCHLD, child_handler);
|
||||
# endif
|
||||
@ -1236,6 +1258,59 @@ int main (int argc, char ** argv)
|
||||
decode_env_switches ("MFLAGS", 6);
|
||||
#endif
|
||||
|
||||
#ifdef MAKE_JOBSERVER
|
||||
/* If extended jobs are available then the -j option can have one of 4
|
||||
formats: (1) not specified: default is "1"; (2) specified with no
|
||||
value: default is "0" (infinite); (3) specified with a single
|
||||
value: this means the user wants N job slots; or (4) specified with
|
||||
2 values separated by commas. The latter means we're a submake and
|
||||
the two values are the read and write FDs, respectively, for the
|
||||
pipe. Note this last form is undocumented for the user!
|
||||
*/
|
||||
sscanf(job_slots_str, "%d", &job_slots);
|
||||
{
|
||||
char *cp = index(job_slots_str, ',');
|
||||
|
||||
if (cp && sscanf(cp+1, "%d", &job_fds[1]) == 1)
|
||||
{
|
||||
job_fds[0] = job_slots;
|
||||
job_slots = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* In case #3 above, set up the pipe and set up the submake options
|
||||
properly. */
|
||||
|
||||
if (job_slots > 1)
|
||||
{
|
||||
char buf[(sizeof("1024")*2)+1];
|
||||
char c = '0';
|
||||
|
||||
if (pipe(job_fds) < 0)
|
||||
pfatal_with_name("creating jobs pipe");
|
||||
|
||||
/* Set the read FD to nonblocking; we'll use select() to wait
|
||||
for it in job.c. */
|
||||
fcntl (job_fds[0], F_SETFL, O_NONBLOCK);
|
||||
|
||||
for (; job_slots; --job_slots)
|
||||
{
|
||||
write(job_fds[1], &c, 1);
|
||||
if (c == '9')
|
||||
c = 'a';
|
||||
else if (c == 'z')
|
||||
c = 'A';
|
||||
else if (c == 'Z')
|
||||
c = '0'; /* Start over again!! */
|
||||
else
|
||||
++c;
|
||||
}
|
||||
|
||||
sprintf(buf, "%d,%d", job_fds[0], job_fds[1]);
|
||||
job_slots_str = xstrdup(buf);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Set up MAKEFLAGS and MFLAGS again, so they will be right. */
|
||||
|
||||
define_makeflags (1, 0);
|
||||
@ -1650,6 +1725,7 @@ init_switches ()
|
||||
long_options[i].has_arg = no_argument;
|
||||
break;
|
||||
|
||||
case int_string:
|
||||
case string:
|
||||
case positive_int:
|
||||
case floating:
|
||||
@ -1742,6 +1818,103 @@ handle_non_switch_argument (arg, env)
|
||||
}
|
||||
}
|
||||
|
||||
/* Print a nice usage method. */
|
||||
|
||||
static void
|
||||
print_usage (bad)
|
||||
int bad;
|
||||
{
|
||||
register const struct command_switch *cs;
|
||||
FILE *usageto;
|
||||
|
||||
if (print_version_flag)
|
||||
print_version ();
|
||||
|
||||
usageto = bad ? stderr : stdout;
|
||||
|
||||
fprintf (usageto, "Usage: %s [options] [target] ...\n", program);
|
||||
|
||||
fputs ("Options:\n", usageto);
|
||||
for (cs = switches; cs->c != '\0'; ++cs)
|
||||
{
|
||||
char buf[1024], shortarg[50], longarg[50], *p;
|
||||
|
||||
if (cs->description[0] == '-')
|
||||
continue;
|
||||
|
||||
switch (long_options[cs - switches].has_arg)
|
||||
{
|
||||
case no_argument:
|
||||
shortarg[0] = longarg[0] = '\0';
|
||||
break;
|
||||
case required_argument:
|
||||
sprintf (longarg, "=%s", cs->argdesc);
|
||||
sprintf (shortarg, " %s", cs->argdesc);
|
||||
break;
|
||||
case optional_argument:
|
||||
sprintf (longarg, "[=%s]", cs->argdesc);
|
||||
sprintf (shortarg, " [%s]", cs->argdesc);
|
||||
break;
|
||||
}
|
||||
|
||||
p = buf;
|
||||
|
||||
if (isalnum (cs->c))
|
||||
{
|
||||
sprintf (buf, " -%c%s", cs->c, shortarg);
|
||||
p += strlen (p);
|
||||
}
|
||||
if (cs->long_name != 0)
|
||||
{
|
||||
unsigned int i;
|
||||
sprintf (p, "%s--%s%s",
|
||||
!isalnum (cs->c) ? " " : ", ",
|
||||
cs->long_name, longarg);
|
||||
p += strlen (p);
|
||||
for (i = 0; i < (sizeof (long_option_aliases) /
|
||||
sizeof (long_option_aliases[0]));
|
||||
++i)
|
||||
if (long_option_aliases[i].val == cs->c)
|
||||
{
|
||||
sprintf (p, ", --%s%s",
|
||||
long_option_aliases[i].name, longarg);
|
||||
p += strlen (p);
|
||||
}
|
||||
}
|
||||
{
|
||||
const struct command_switch *ncs = cs;
|
||||
while ((++ncs)->c != '\0')
|
||||
if (ncs->description[0] == '-' &&
|
||||
ncs->description[1] == cs->c)
|
||||
{
|
||||
/* This is another switch that does the same
|
||||
one as the one we are processing. We want
|
||||
to list them all together on one line. */
|
||||
sprintf (p, ", -%c%s", ncs->c, shortarg);
|
||||
p += strlen (p);
|
||||
if (ncs->long_name != 0)
|
||||
{
|
||||
sprintf (p, ", --%s%s", ncs->long_name, longarg);
|
||||
p += strlen (p);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (p - buf > DESCRIPTION_COLUMN - 2)
|
||||
/* The list of option names is too long to fit on the same
|
||||
line with the description, leaving at least two spaces.
|
||||
Print it on its own line instead. */
|
||||
{
|
||||
fprintf (usageto, "%s\n", buf);
|
||||
buf[0] = '\0';
|
||||
}
|
||||
|
||||
fprintf (usageto, "%*s%s.\n",
|
||||
- DESCRIPTION_COLUMN,
|
||||
buf, cs->description);
|
||||
}
|
||||
}
|
||||
|
||||
/* Decode switches from ARGC and ARGV.
|
||||
They came from the environment if ENV is nonzero. */
|
||||
|
||||
@ -1806,6 +1979,20 @@ decode_switches (argc, argv, env)
|
||||
*(int *) cs->value_ptr = cs->type == flag;
|
||||
break;
|
||||
|
||||
case int_string:
|
||||
if (optarg == 0 && argc > optind
|
||||
&& isdigit (argv[optind][0]))
|
||||
optarg = argv[optind++];
|
||||
|
||||
if (!doit)
|
||||
break;
|
||||
|
||||
if (optarg == 0)
|
||||
optarg = cs->noarg_value;
|
||||
|
||||
*(char **)cs->value_ptr = optarg;
|
||||
break;
|
||||
|
||||
case string:
|
||||
if (!doit)
|
||||
break;
|
||||
@ -1891,96 +2078,7 @@ positive integral argument",
|
||||
|
||||
if (!env && (bad || print_usage_flag))
|
||||
{
|
||||
/* Print a nice usage message. */
|
||||
FILE *usageto;
|
||||
|
||||
if (print_version_flag)
|
||||
print_version ();
|
||||
|
||||
usageto = bad ? stderr : stdout;
|
||||
|
||||
fprintf (usageto, "Usage: %s [options] [target] ...\n", program);
|
||||
|
||||
fputs ("Options:\n", usageto);
|
||||
for (cs = switches; cs->c != '\0'; ++cs)
|
||||
{
|
||||
char buf[1024], shortarg[50], longarg[50], *p;
|
||||
|
||||
if (cs->description[0] == '-')
|
||||
continue;
|
||||
|
||||
switch (long_options[cs - switches].has_arg)
|
||||
{
|
||||
case no_argument:
|
||||
shortarg[0] = longarg[0] = '\0';
|
||||
break;
|
||||
case required_argument:
|
||||
sprintf (longarg, "=%s", cs->argdesc);
|
||||
sprintf (shortarg, " %s", cs->argdesc);
|
||||
break;
|
||||
case optional_argument:
|
||||
sprintf (longarg, "[=%s]", cs->argdesc);
|
||||
sprintf (shortarg, " [%s]", cs->argdesc);
|
||||
break;
|
||||
}
|
||||
|
||||
p = buf;
|
||||
|
||||
if (isalnum (cs->c))
|
||||
{
|
||||
sprintf (buf, " -%c%s", cs->c, shortarg);
|
||||
p += strlen (p);
|
||||
}
|
||||
if (cs->long_name != 0)
|
||||
{
|
||||
unsigned int i;
|
||||
sprintf (p, "%s--%s%s",
|
||||
!isalnum (cs->c) ? " " : ", ",
|
||||
cs->long_name, longarg);
|
||||
p += strlen (p);
|
||||
for (i = 0; i < (sizeof (long_option_aliases) /
|
||||
sizeof (long_option_aliases[0]));
|
||||
++i)
|
||||
if (long_option_aliases[i].val == cs->c)
|
||||
{
|
||||
sprintf (p, ", --%s%s",
|
||||
long_option_aliases[i].name, longarg);
|
||||
p += strlen (p);
|
||||
}
|
||||
}
|
||||
{
|
||||
const struct command_switch *ncs = cs;
|
||||
while ((++ncs)->c != '\0')
|
||||
if (ncs->description[0] == '-' &&
|
||||
ncs->description[1] == cs->c)
|
||||
{
|
||||
/* This is another switch that does the same
|
||||
one as the one we are processing. We want
|
||||
to list them all together on one line. */
|
||||
sprintf (p, ", -%c%s", ncs->c, shortarg);
|
||||
p += strlen (p);
|
||||
if (ncs->long_name != 0)
|
||||
{
|
||||
sprintf (p, ", --%s%s", ncs->long_name, longarg);
|
||||
p += strlen (p);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (p - buf > DESCRIPTION_COLUMN - 2)
|
||||
/* The list of option names is too long to fit on the same
|
||||
line with the description, leaving at least two spaces.
|
||||
Print it on its own line instead. */
|
||||
{
|
||||
fprintf (usageto, "%s\n", buf);
|
||||
buf[0] = '\0';
|
||||
}
|
||||
|
||||
fprintf (usageto, "%*s%s.\n",
|
||||
- DESCRIPTION_COLUMN,
|
||||
buf, cs->description);
|
||||
}
|
||||
|
||||
print_usage(bad);
|
||||
die (bad ? 2 : 0);
|
||||
}
|
||||
}
|
||||
@ -2193,6 +2291,22 @@ define_makeflags (all, makefile)
|
||||
break;
|
||||
#endif
|
||||
|
||||
case int_string:
|
||||
if (all)
|
||||
{
|
||||
char *vp = *(char **)cs->value_ptr;
|
||||
|
||||
if (cs->default_value != 0
|
||||
&& streq(vp, cs->default_value))
|
||||
break;
|
||||
if (cs->noarg_value != 0
|
||||
&& streq(vp, cs->noarg_value))
|
||||
ADD_FLAG("", 0); /* Optional value omitted; see below. */
|
||||
else
|
||||
ADD_FLAG(vp, strlen(vp));
|
||||
}
|
||||
break;
|
||||
|
||||
case string:
|
||||
if (all)
|
||||
{
|
||||
|
3
make.h
3
make.h
@ -1,5 +1,5 @@
|
||||
/* Miscellaneous global declarations and portability cruft for GNU Make.
|
||||
Copyright (C) 1988,89,90,91,92,93,94,95,96,97 Free Software Foundation, Inc.
|
||||
Copyright (C) 1988,89,90,91,92,93,94,95,96,97,99 Free Software Foundation, Inc.
|
||||
This file is part of GNU Make.
|
||||
|
||||
GNU Make is free software; you can redistribute it and/or modify
|
||||
@ -458,6 +458,7 @@ extern int clock_skew_detected;
|
||||
extern int batch_mode_shell;
|
||||
|
||||
extern unsigned int job_slots;
|
||||
extern int job_fds[2];
|
||||
#ifndef NO_FLOAT
|
||||
extern double max_load_average;
|
||||
#else
|
||||
|
41
make.texinfo
41
make.texinfo
@ -10,8 +10,8 @@
|
||||
@set RCSID $Id$
|
||||
@set EDITION 0.53
|
||||
@set VERSION 3.78
|
||||
@set UPDATED 22 March 1999
|
||||
@set UPDATE-MONTH March 1999
|
||||
@set UPDATED 14 April 1999
|
||||
@set UPDATE-MONTH April 1999
|
||||
@comment The ISBN number might need to change on next publication.
|
||||
@set ISBN 1-882114-80-9 @c CHANGE THIS BEFORE PRINTING AGAIN! --psmith 16jul98
|
||||
|
||||
@ -24,12 +24,12 @@
|
||||
@c Combine the program and concept indices:
|
||||
@syncodeindex pg cp
|
||||
|
||||
@ifinfo
|
||||
@dircategory The GNU make utility
|
||||
@dircategory GNU Packages
|
||||
@direntry
|
||||
* Make: (make.info). The GNU make utility.
|
||||
* Make: (make). Remake files automatically.
|
||||
@end direntry
|
||||
|
||||
@ifinfo
|
||||
This file documents the GNU Make utility, which determines
|
||||
automatically which pieces of a large program need to be recompiled,
|
||||
and issues the commands to recompile them.
|
||||
@ -3032,8 +3032,8 @@ there is no limit on the number of job slots. The default number of job
|
||||
slots is one, which means serial execution (one thing at a time).
|
||||
|
||||
One unpleasant consequence of running several commands simultaneously is
|
||||
that output from all of the commands comes when the commands send it, so
|
||||
messages from different commands may be interspersed.
|
||||
that output generated by the commands appears whenever each command
|
||||
sends it, so messages from different commands may be interspersed.
|
||||
|
||||
Another problem is that two processes cannot both take input from the
|
||||
same device; so to make sure that only one command tries to take input
|
||||
@ -3057,6 +3057,10 @@ standard input at all if you are using the parallel execution feature; but
|
||||
if you are not using this feature, then standard input works normally in
|
||||
all commands.
|
||||
|
||||
Finally, handling recursive @code{make} invocations raises issues. For
|
||||
more information on this, see
|
||||
@ref{Options/Recursion, ,Communicating Options to a Sub-@code{make}}.
|
||||
|
||||
If a command fails (is killed by a signal or exits with a nonzero
|
||||
status), and errors are not ignored for that command
|
||||
(@pxref{Errors, ,Errors in Commands}),
|
||||
@ -3546,13 +3550,22 @@ into @code{MAKEFLAGS}; these options are not passed down.@refill
|
||||
@cindex recursion, and @code{-j}
|
||||
@cindex job slots, and recursion
|
||||
The @samp{-j} option is a special case (@pxref{Parallel, ,Parallel Execution}).
|
||||
If you set it to some numeric value, @samp{-j 1} is always put into
|
||||
@code{MAKEFLAGS} instead of the value you specified. This is because if
|
||||
the @w{@samp{-j}} option were passed down to sub-@code{make}s, you would
|
||||
get many more jobs running in parallel than you asked for. If you give
|
||||
@samp{-j} with no numeric argument, meaning to run as many jobs as
|
||||
possible in parallel, this is passed down, since multiple infinities are
|
||||
no more than one.@refill
|
||||
If you set it to some numeric value @samp{N} and your operating system
|
||||
supports it (most any UNIX system will; others typically won't), the
|
||||
parent @code{make} and all the sub-@code{make}s will communicate to
|
||||
ensure that there are only @samp{N} jobs running at the same time
|
||||
between them all. Note that any job that is marked recursive
|
||||
(@pxref{Instead of Execution, ,Instead of Executing the Commands})
|
||||
doesn't count against the total jobs (otherwise we could get @samp{N}
|
||||
sub-@code{make}s running and have no slots left over for any real work!)
|
||||
|
||||
If your operating system doesn't support the above communication, then
|
||||
@samp{-j 1} is always put into @code{MAKEFLAGS} instead of the value you
|
||||
specified. This is because if the @w{@samp{-j}} option were passed down
|
||||
to sub-@code{make}s, you would get many more jobs running in parallel
|
||||
than you asked for. If you give @samp{-j} with no numeric argument,
|
||||
meaning to run as many jobs as possible in parallel, this is passed
|
||||
down, since multiple infinities are no more than one.@refill
|
||||
|
||||
If you do not want to pass the other flags down, you must change the
|
||||
value of @code{MAKEFLAGS}, like this:
|
||||
|
Loading…
Reference in New Issue
Block a user