Andreas Schwab
6c29d04f43
- jobserver-noinherit.patch: Disable inheritance of jobserver FDs for recursive make - jobserver-fifo.patch: Add support for jobserver using named pipes OBS-URL: https://build.opensuse.org/request/show/998857 OBS-URL: https://build.opensuse.org/package/show/Base:System/make?expand=0&rev=73
1002 lines
36 KiB
Diff
1002 lines
36 KiB
Diff
Support implementing the jobserver using named pipes
|
|
|
|
Using anonymous pipes for jobserver support has some advantages:
|
|
for example there is nothing on disk that needs to be cleaned up.
|
|
However it has many obscure problems, related to the fact that in
|
|
order for it to work we need to ensure these resources are properly
|
|
passed through to child processes that want to use the jobserver.
|
|
At the same time we don't want to pass the pipe to process which
|
|
DON'T know about the jobserver.
|
|
|
|
Other processes can open file descriptors which we then think are
|
|
our jobserver, but aren't. And, we open the pipe file descriptors
|
|
in blocking mode which doesn't work for all users.
|
|
|
|
See issues such as SV 57178, SV 57242, and SV 62397
|
|
|
|
To avoid these issues, use named pipes (on systems where they are
|
|
available) instead of anonoymous pipes. This simplifies many things:
|
|
we never need to pass open file descriptors to our children; they
|
|
can open the jobserver named pipe. We don't need to worry about
|
|
recursive vs. non-recursive children. Users don't have to "pass
|
|
through" the resources if they are invoking sub-makes. Each child
|
|
can open its own file descriptor and set blocking as needed.
|
|
|
|
The downside is the named pipe exists on disk and so must be cleaned
|
|
up when the "top-level" make instance exits.
|
|
|
|
In order to allow make to continue to be used in build systems where
|
|
older versions of GNU make, or other tools that want to use the
|
|
jobserver, but don't understand named pipes, introduce a new option
|
|
--jobserver-style that allows the user to choose anonymous pipes.
|
|
|
|
* NEWS: Announce the change and the --jobserver-style option.
|
|
* doc/make.1: Add --jobserver-style documentation.
|
|
* doc/make.texi (Special Variables): Add missing items to .FEATURES.
|
|
(Options Summary): Add --jobserver-style.
|
|
(POSIX Jobserver): Named pipes, changes to --jobserver-auth, and the
|
|
--jobserver-style option.
|
|
(Windows Jobserver): Document --jobserver-style for Windows.
|
|
* configure.ac: Check for mkfifo.
|
|
* src/config.h-vms.template: Undefined HAVE_MKFIFO.
|
|
* src/config.h.W32.template: Ditto.
|
|
* src/main.c: Add jobserver-style as a new command line option.
|
|
(main): Add jobserver-fifo to .FEATURES if supported. Pass the style
|
|
option to jobserver_setup().
|
|
* src/os.h (jobserver_setup): Accept a style string option.
|
|
* src/posixos.c (enum js_type): Enumeration of the jobserver style.
|
|
(js_type): Which style we are currently using.
|
|
(fifo_name): The path to the named pipe (if in use).
|
|
(jobserver_setup): If no style is given, or "fifo" is given, set up a
|
|
named pipe: get a temporary file and use mkfifo() on it, then open it
|
|
for reading and writing. If something fails fall back to anonymous
|
|
pipes.
|
|
(jobserver_parse_auth): Parse jobserver-auth to determine the style.
|
|
If we are using a named pipe, open it. If we're using anonymous pipes
|
|
ensure they're valid as before.
|
|
(jobserver_get_invalid_auth): Don't invalidate the jobserver when
|
|
using named pipes.
|
|
(jobserver_clear): Clean up memory used for named pipes.
|
|
(jobserver_acquire_all): Unlink the named pipe when done.
|
|
* src/w32/w32os.c (jobserver_setup): Check the style argument.
|
|
* tests/scripts/features/jobserver: Use --jobserver-style to test
|
|
the anonymous pipe behavior, and also test named pipe/semaphore
|
|
behavior. Check invalid jobserver-style options.
|
|
* tests/scripts/functions/shell: Use --jobserver-style to test the
|
|
anonymous pipe behavior, and also test named pipe/semaphore
|
|
behavior.
|
|
---
|
|
configure.ac | 2 +-
|
|
doc/make.1 | 10 ++
|
|
doc/make.texi | 133 +++++++++++++++---------
|
|
src/config.h-vms.template | 3 +
|
|
src/config.h.W32.template | 3 +
|
|
src/main.c | 49 ++-------
|
|
src/makeint.h | 3 +-
|
|
src/misc.c | 88 +++++++++++++---
|
|
src/os.h | 26 ++---
|
|
src/posixos.c | 172 ++++++++++++++++++++++++++-----
|
|
src/vmsjobs.c | 4 +-
|
|
src/w32/w32os.c | 5 +-
|
|
tests/scripts/features/jobserver | 33 ++++--
|
|
tests/scripts/functions/shell | 16 +++
|
|
14 files changed, 391 insertions(+), 156 deletions(-)
|
|
|
|
Index: make-4.3/configure.ac
|
|
===================================================================
|
|
--- make-4.3.orig/configure.ac
|
|
+++ make-4.3/configure.ac
|
|
@@ -141,7 +141,7 @@ AS_IF([test "$ac_cv_func_gettimeofday" =
|
|
AC_CHECK_FUNCS([strdup strndup memrchr umask mkstemp mktemp fdopen \
|
|
dup dup2 getcwd realpath sigsetmask sigaction \
|
|
getgroups seteuid setegid setlinebuf setreuid setregid \
|
|
- getrlimit setrlimit setvbuf pipe strsignal \
|
|
+ mkfifo getrlimit setrlimit setvbuf pipe strsignal \
|
|
lstat readlink atexit isatty ttyname pselect posix_spawn \
|
|
posix_spawnattr_setsigmask])
|
|
|
|
Index: make-4.3/doc/make.1
|
|
===================================================================
|
|
--- make-4.3.orig/doc/make.1
|
|
+++ make-4.3/doc/make.1
|
|
@@ -198,6 +198,16 @@ option is given without an argument,
|
|
.BR make
|
|
will not limit the number of jobs that can run simultaneously.
|
|
.TP 0.5i
|
|
+\fB\--jobserver-style=\fR\fIstyle\fR
|
|
+The style of jobserver to use. The
|
|
+.I style
|
|
+may be one of
|
|
+.BR fifo ,
|
|
+.BR pipe ,
|
|
+or
|
|
+.B sem
|
|
+(Windows only).
|
|
+.TP 0.5i
|
|
\fB\-k\fR, \fB\-\-keep\-going\fR
|
|
Continue as much as possible after an error.
|
|
While the target that failed, and those that depend on it, cannot
|
|
Index: make-4.3/doc/make.texi
|
|
===================================================================
|
|
--- make-4.3.orig/doc/make.texi
|
|
+++ make-4.3/doc/make.texi
|
|
@@ -6607,6 +6607,10 @@ Syntax, ,Syntax of Conditionals}.
|
|
Supports ``job server'' enhanced parallel builds. @xref{Parallel,
|
|
,Parallel Execution}.
|
|
|
|
+@item jobserver-fifo
|
|
+Supports ``job server'' enhanced parallel builds using named pipes.
|
|
+@xref{Integrating make, ,Integrating GNU @code{make}}.
|
|
+
|
|
@item oneshell
|
|
Supports the @code{.ONESHELL} special target. @xref{One Shell, ,Using
|
|
One Shell}.
|
|
@@ -8955,6 +8959,15 @@ If there is more than one @samp{-j} opti
|
|
@xref{Parallel, ,Parallel Execution}, for more information on how
|
|
recipes are run. Note that this option is ignored on MS-DOS.
|
|
|
|
+@item --jobserver-style=[@var{style}]
|
|
+@cindex @code{--jobserver-style}
|
|
+Chooses the style of jobserver to use. This option only has effect if
|
|
+parallel builds are enabled (@pxref{Parallel, ,Parallel Execution}). On POSIX
|
|
+systems @var{style} can be one of @code{fifo} (the default) or @code{pipe}.
|
|
+On Windows the only acceptable @var{style} is @code{sem} (the default). This
|
|
+option is useful if you need to use an older versions of GNU @code{make}, or a
|
|
+different tool that requires a specific jobserver style.
|
|
+
|
|
@item -k
|
|
@cindex @code{-k}
|
|
@itemx --keep-going
|
|
@@ -11643,20 +11656,20 @@ number of active jobs across recursive i
|
|
implementation of the jobserver varies across different operating
|
|
systems, but some fundamental aspects are always true.
|
|
|
|
-First, only command lines that @code{make} understands to be recursive
|
|
-invocations of @code{make} (@pxref{MAKE Variable, ,How the @code{MAKE}
|
|
-Variable Works}) will have access to the jobserver. When writing
|
|
-makefiles you must be sure to mark the command as recursive (most
|
|
-commonly by prefixing the command line with the @code{+} indicator
|
|
-(@pxref{Recursion, ,Recursive Use of @code{make}}).
|
|
-
|
|
-Second, @code{make} will provide information necessary for accessing
|
|
-the jobserver through the environment to its children, in the
|
|
-@code{MAKEFLAGS} environment variable. Tools which want to
|
|
-participate in the jobserver protocol will need to parse this
|
|
-environment variable, as described in subsequent sections.
|
|
+@cindex @code{--jobserver-auth}
|
|
+First, @code{make} will provide information necessary for accessing the
|
|
+jobserver through the environment to its children, in the @code{MAKEFLAGS}
|
|
+environment variable. Tools which want to participate in the jobserver
|
|
+protocol will need to parse this environment variable and find the word
|
|
+starting with @code{--jobserver-auth=}. The value of this option will
|
|
+describe how to communicate with the jobserver. The interpretation of this
|
|
+value is described in the sections below.
|
|
+
|
|
+Be aware that the @code{MAKEFLAGS} variable may contain multiple instances of
|
|
+the @code{--jobserver-auth=} option. Only the @emph{last} instance is
|
|
+relevant.
|
|
|
|
-Third, every command @code{make} starts has one implicit job slot
|
|
+Second, every command @code{make} starts has one implicit job slot
|
|
reserved for it before it starts. Any tool which wants to participate
|
|
in the jobserver protocol should assume it can always run one job
|
|
without having to contact the jobserver at all.
|
|
@@ -11693,54 +11706,75 @@ the jobserver.
|
|
@subsection POSIX Jobserver Interaction
|
|
@cindex jobserver on POSIX
|
|
|
|
-On POSIX systems the jobserver is implemented as a simple UNIX pipe.
|
|
-The pipe will be pre-loaded with one single-character token for each
|
|
-available job. To obtain an extra slot you must read a single
|
|
-character from the jobserver pipe; to release a slot you must write a
|
|
-single character back into the jobserver pipe. Note that the read
|
|
-side of the jobserver pipe is set to ``blocking'' mode.
|
|
-
|
|
-To access the pipe you must parse the @code{MAKEFLAGS} variable and
|
|
-look for the argument string @code{--jobserver-auth=R,W} where
|
|
-@samp{R} and @samp{W} are non-negative integers representing file
|
|
-descriptors: @samp{R} is the read file descriptor and @samp{W} is the
|
|
-write file descriptor.
|
|
-
|
|
-It's important that when you release the job slot, you write back the
|
|
-same character you read from the pipe for that slot. Don't assume
|
|
-that all tokens are the same character; different characters may have
|
|
-different meanings to GNU @code{make}. The order is not important,
|
|
-since @code{make} has no idea in what order jobs will complete anyway.
|
|
+On POSIX systems the jobserver is implemented in one of two ways: on systems
|
|
+that support it, GNU @code{make} will create a named pipe and use that for the
|
|
+jobserver. In this case the auth option will have the form
|
|
+@code{--jobserver-auth=fifo:PATH} where @samp{PATH} is the pathname of the
|
|
+named pipe. To access the jobserver you should open the named pipe path and
|
|
+read/write to it as described below.
|
|
+
|
|
+@cindex @code{--jobserver-style}
|
|
+If the system doesn't support named pipes, or if the user provided the
|
|
+@code{--jobserver-style} option and specified @samp{pipe}, then the jobserver
|
|
+will be implemented as a simple UNIX pipe. In this case the auth option will
|
|
+have the form @code{--jobserver-auth=R,W} where @samp{R} and @samp{W} are
|
|
+non-negative integers representing file descriptors: @samp{R} is the read file
|
|
+descriptor and @samp{W} is the write file descriptor. If either or both of
|
|
+these file descriptors are negative, it means the jobserver is disabled for
|
|
+this process.
|
|
+
|
|
+When using a simple pipe, only command lines that @code{make} understands to
|
|
+be recursive invocations of @code{make} (@pxref{MAKE Variable, ,How the
|
|
+@code{MAKE} Variable Works}) will have access to the jobserver. When writing
|
|
+makefiles you must be sure to mark the command as recursive (most commonly by
|
|
+prefixing the command line with the @code{+} indicator (@pxref{Recursion,
|
|
+,Recursive Use of @code{make}}). Note that the read side of the jobserver
|
|
+pipe is set to ``blocking'' mode. This should not be changed.
|
|
+
|
|
+In both implementations of the jobserver, the pipe will be pre-loaded with one
|
|
+single-character token for each available job. To obtain an extra slot you
|
|
+must read a single character from the jobserver; to release a slot you must
|
|
+write a single character back into the jobserver.
|
|
+
|
|
+It's important that when you release the job slot, you write back the same
|
|
+character you read. Don't assume that all tokens are the same character;
|
|
+different characters may have different meanings to GNU @code{make}. The
|
|
+order is not important, since @code{make} has no idea in what order jobs will
|
|
+complete anyway.
|
|
|
|
There are various error conditions you must consider to ensure your
|
|
implementation is robust:
|
|
|
|
@itemize @bullet
|
|
@item
|
|
-Usually you will have a command-line argument controlling the parallel
|
|
-operation of your tool. Consider whether your tool should detect
|
|
-situations where both the jobserver and the command-line argument are
|
|
-specified, and how it should react.
|
|
+If you have a command-line argument controlling the parallel operation of your
|
|
+tool, consider whether your tool should detect situations where both the
|
|
+jobserver and the command-line argument are specified, and how it should
|
|
+react.
|
|
|
|
@item
|
|
-If your tool determines that the @code{--jobserver-auth} option is
|
|
-available in @code{MAKEFLAGS} but that the file descriptors specified
|
|
-are closed, this means that the calling @code{make} process did not
|
|
-think that your tool was a recursive @code{make} invocation (e.g., the
|
|
-command line was not prefixed with a @code{+} character). You should
|
|
-notify your users of this situation.
|
|
+If your tool does not recognize the format of the @code{--jobserver-auth}
|
|
+string, it should assume the jobserver is using a different style and it
|
|
+cannot connect.
|
|
|
|
@item
|
|
-Your tool should also examine the first word of the @code{MAKEFLAGS}
|
|
-variable and look for the character @code{n}. If this character is
|
|
-present then @code{make} was invoked with the @samp{-n} option and
|
|
-your tool should stop without performing any operations.
|
|
+If your tool determines that the @code{--jobserver-auth} option references a
|
|
+simple pipe but that the file descriptors specified are closed, this means
|
|
+that the calling @code{make} process did not think that your tool was a
|
|
+recursive @code{make} invocation (e.g., the command line was not prefixed with
|
|
+a @code{+} character). You should notify your users of this situation.
|
|
|
|
@item
|
|
-Your tool should be sure to write back the tokens it read, even under
|
|
-error conditions. This includes not only errors in your tool but also
|
|
-outside influences such as interrupts (@code{SIGINT}), etc. You may
|
|
-want to install signal handlers to manage this write-back.
|
|
+Your tool should be sure to write back the tokens it read, even under error
|
|
+conditions. This includes not only errors in your tool but also outside
|
|
+influences such as interrupts (@code{SIGINT}), etc. You may want to install
|
|
+signal handlers to manage this write-back.
|
|
+
|
|
+@item
|
|
+Your tool may also examine the first word of the @code{MAKEFLAGS} variable and
|
|
+look for the character @code{n}. If this character is present then
|
|
+@code{make} was invoked with the @samp{-n} option and your tool may want to
|
|
+stop without performing any operations.
|
|
@end itemize
|
|
|
|
@node Windows Jobserver, , POSIX Jobserver, Job Slots
|
|
@@ -11757,6 +11791,9 @@ look for the argument string @code{--job
|
|
@samp{NAME} is the name of the named semaphore. Use this name with
|
|
@code{OpenSemaphore} to create a handle to the semaphore.
|
|
|
|
+@cindex @code{--jobserver-style} for Windows
|
|
+The only valid style for @code{--jobserver-style} is @samp{sem}.
|
|
+
|
|
There are various error conditions you must consider to ensure your
|
|
implementation is robust:
|
|
|
|
Index: make-4.3/src/config.h-vms
|
|
===================================================================
|
|
--- make-4.3.orig/src/config.h-vms
|
|
+++ make-4.3/src/config.h-vms
|
|
@@ -259,6 +259,9 @@ this program. If not, see <http://www.g
|
|
/* Define to 1 if you have the memmove function. */
|
|
#define HAVE_MEMMOVE 1
|
|
|
|
+/* Define to 1 if you have the 'mkfifo' function. */
|
|
+/* #undef HAVE_MKFIFO */
|
|
+
|
|
/* Define to 1 if you have the mktemp function. */
|
|
#define HAVE_MKTEMP 1
|
|
|
|
Index: make-4.3/src/config.h.W32
|
|
===================================================================
|
|
--- make-4.3.orig/src/config.h.W32
|
|
+++ make-4.3/src/config.h.W32
|
|
@@ -178,6 +178,9 @@ this program. If not, see <http://www.g
|
|
/* Define to 1 if you have the <memory.h> header file. */
|
|
#define HAVE_MEMORY_H 1
|
|
|
|
+/* Define to 1 if you have the 'mkfifo' function. */
|
|
+/* #undef HAVE_MKFIFO */
|
|
+
|
|
/* Define to 1 if you have the 'mkstemp' function. */
|
|
/* #undef HAVE_MKSTEMP */
|
|
|
|
Index: make-4.3/src/main.c
|
|
===================================================================
|
|
--- make-4.3.orig/src/main.c
|
|
+++ make-4.3/src/main.c
|
|
@@ -267,6 +267,9 @@ static const int inf_jobs = 0;
|
|
|
|
static char *jobserver_auth = NULL;
|
|
|
|
+/* Style for the jobserver. */
|
|
+static char *jobserver_style = NULL;
|
|
+
|
|
/* Handle for the mutex used on Windows to synchronize output of our
|
|
children under -O. */
|
|
|
|
@@ -362,6 +365,8 @@ static const char *const usage[] =
|
|
N_("\
|
|
-j [N], --jobs[=N] Allow N jobs at once; infinite jobs with no arg.\n"),
|
|
N_("\
|
|
+ --jobserver-style=STYLE Select the style of jobserver to use.\n"),
|
|
+ N_("\
|
|
-k, --keep-going Keep going when some targets can't be made.\n"),
|
|
N_("\
|
|
-l [N], --load-average[=N], --max-load[=N]\n\
|
|
@@ -464,6 +469,7 @@ static const struct command_switch switc
|
|
{ CHAR_MAX+7, string, &sync_mutex, 1, 1, 0, 0, 0, "sync-mutex" },
|
|
{ CHAR_MAX+8, flag_off, &silent_flag, 1, 1, 0, 0, &default_silent_flag, "no-silent" },
|
|
{ CHAR_MAX+9, string, &jobserver_auth, 1, 0, 0, 0, 0, "jobserver-fds" },
|
|
+ { CHAR_MAX+12, string, &jobserver_style, 1, 0, 0, 0, 0, "jobserver-style" },
|
|
{ 0, 0, 0, 0, 0, 0, 0, 0, 0 }
|
|
};
|
|
|
|
@@ -1319,6 +1325,9 @@ main (int argc, char **argv, char **envp
|
|
#endif
|
|
#ifdef MAKE_JOBSERVER
|
|
" jobserver"
|
|
+#ifdef HAVE_MKFIFO
|
|
+ " jobserver-fifo"
|
|
+#endif
|
|
#endif
|
|
#ifndef NO_OUTPUT_SYNC
|
|
" output-sync"
|
|
@@ -1773,48 +1782,12 @@ main (int argc, char **argv, char **envp
|
|
and thus re-read the makefiles, we read standard input
|
|
into a temporary file and read from that. */
|
|
FILE *outfile;
|
|
- char *template;
|
|
- const char *tmpdir;
|
|
|
|
if (stdin_nm)
|
|
O (fatal, NILF,
|
|
_("Makefile from standard input specified twice."));
|
|
|
|
-#ifdef VMS
|
|
-# define DEFAULT_TMPDIR "/sys$scratch/"
|
|
-#else
|
|
-# ifdef P_tmpdir
|
|
-# define DEFAULT_TMPDIR P_tmpdir
|
|
-# else
|
|
-# define DEFAULT_TMPDIR "/tmp"
|
|
-# endif
|
|
-#endif
|
|
-#define DEFAULT_TMPFILE "GmXXXXXX"
|
|
-
|
|
- if (((tmpdir = getenv ("TMPDIR")) == NULL || *tmpdir == '\0')
|
|
-#if defined (__MSDOS__) || defined (WINDOWS32) || defined (__EMX__)
|
|
- /* These are also used commonly on these platforms. */
|
|
- && ((tmpdir = getenv ("TEMP")) == NULL || *tmpdir == '\0')
|
|
- && ((tmpdir = getenv ("TMP")) == NULL || *tmpdir == '\0')
|
|
-#endif
|
|
- )
|
|
- tmpdir = DEFAULT_TMPDIR;
|
|
-
|
|
- template = alloca (strlen (tmpdir) + CSTRLEN (DEFAULT_TMPFILE) + 2);
|
|
- strcpy (template, tmpdir);
|
|
-
|
|
-#ifdef HAVE_DOS_PATHS
|
|
- if (strchr ("/\\", template[strlen (template) - 1]) == NULL)
|
|
- strcat (template, "/");
|
|
-#else
|
|
-# ifndef VMS
|
|
- if (template[strlen (template) - 1] != '/')
|
|
- strcat (template, "/");
|
|
-# endif /* !VMS */
|
|
-#endif /* !HAVE_DOS_PATHS */
|
|
-
|
|
- strcat (template, DEFAULT_TMPFILE);
|
|
- outfile = get_tmpfile (&stdin_nm, template);
|
|
+ outfile = get_tmpfile (&stdin_nm);
|
|
if (outfile == 0)
|
|
pfatal_with_name (_("fopen (temporary file)"));
|
|
while (!feof (stdin) && ! ferror (stdin))
|
|
@@ -2079,7 +2052,7 @@ main (int argc, char **argv, char **envp
|
|
submakes it's the token they were given by their parent. For the top
|
|
make, we just subtract one from the number the user wants. */
|
|
|
|
- if (job_slots > 1 && jobserver_setup (job_slots - 1))
|
|
+ if (job_slots > 1 && jobserver_setup (job_slots - 1, jobserver_style))
|
|
{
|
|
/* Fill in the jobserver_auth for our children. */
|
|
jobserver_auth = jobserver_get_auth ();
|
|
Index: make-4.3/src/makeint.h
|
|
===================================================================
|
|
--- make-4.3.orig/src/makeint.h
|
|
+++ make-4.3/src/makeint.h
|
|
@@ -530,7 +530,8 @@ int alpha_compare (const void *, const v
|
|
void print_spaces (unsigned int);
|
|
char *find_percent (char *);
|
|
const char *find_percent_cached (const char **);
|
|
-FILE *get_tmpfile (char **, const char *);
|
|
+char *get_tmppath ();
|
|
+FILE *get_tmpfile (char **);
|
|
ssize_t writebuf (int, const void *, size_t);
|
|
ssize_t readbuf (int, void *, size_t);
|
|
|
|
Index: make-4.3/src/misc.c
|
|
===================================================================
|
|
--- make-4.3.orig/src/misc.c
|
|
+++ make-4.3/src/misc.c
|
|
@@ -475,8 +475,76 @@ umask (mode_t mask)
|
|
}
|
|
#endif
|
|
|
|
+static char *
|
|
+get_tmptemplate ()
|
|
+{
|
|
+ const char *tmpdir;
|
|
+ char *template;
|
|
+ size_t len;
|
|
+
|
|
+#ifdef VMS
|
|
+# define DEFAULT_TMPFILE "sys$scratch:gnv$make_cmdXXXXXX.com"
|
|
+#else
|
|
+# define DEFAULT_TMPFILE "GmXXXXXX"
|
|
+#endif
|
|
+
|
|
+#ifdef VMS
|
|
+# define DEFAULT_TMPDIR "/sys$scratch/"
|
|
+#else
|
|
+# ifdef P_tmpdir
|
|
+# define DEFAULT_TMPDIR P_tmpdir
|
|
+# else
|
|
+# define DEFAULT_TMPDIR "/tmp"
|
|
+# endif
|
|
+#endif
|
|
+
|
|
+ if (
|
|
+#if defined (__MSDOS__) || defined (WINDOWS32) || defined (__EMX__)
|
|
+ ((tmpdir = getenv ("TMP")) == NULL || *tmpdir == '\0') &&
|
|
+ ((tmpdir = getenv ("TEMP")) == NULL || *tmpdir == '\0') &&
|
|
+#endif
|
|
+ ((tmpdir = getenv ("TMPDIR")) == NULL || *tmpdir == '\0'))
|
|
+ tmpdir = DEFAULT_TMPDIR;
|
|
+
|
|
+ len = strlen (tmpdir);
|
|
+ template = xmalloc (len + CSTRLEN (DEFAULT_TMPFILE) + 2);
|
|
+ strcpy (template, tmpdir);
|
|
+
|
|
+#ifdef HAVE_DOS_PATHS
|
|
+ if (template[len - 1] != '/' && template[len - 1] != '\\')
|
|
+ strcat (template, "/");
|
|
+#else
|
|
+# ifndef VMS
|
|
+ if (template[len - 1] != '/')
|
|
+ strcat (template, "/");
|
|
+# endif /* !VMS */
|
|
+#endif /* !HAVE_DOS_PATHS */
|
|
+
|
|
+ strcat (template, DEFAULT_TMPFILE);
|
|
+
|
|
+ return template;
|
|
+}
|
|
+
|
|
+char *
|
|
+get_tmppath ()
|
|
+{
|
|
+ char *path;
|
|
+
|
|
+#ifdef HAVE_MKTEMP
|
|
+ path = get_tmptemplate();
|
|
+ if (*mktemp (path) == '\0')
|
|
+ pfatal_with_name ("mktemp");
|
|
+#else
|
|
+ path = xmalloc (L_tmpnam + 1);
|
|
+ if (tmpnam (path) == NULL)
|
|
+ pfatal_with_name ("tmpnam");
|
|
+#endif
|
|
+
|
|
+ return path;
|
|
+}
|
|
+
|
|
FILE *
|
|
-get_tmpfile (char **name, const char *template)
|
|
+get_tmpfile (char **name)
|
|
{
|
|
FILE *file;
|
|
#ifdef HAVE_FDOPEN
|
|
@@ -486,15 +554,9 @@ get_tmpfile (char **name, const char *te
|
|
/* Preserve the current umask, and set a restrictive one for temp files. */
|
|
mode_t mask = umask (0077);
|
|
|
|
-#if defined(HAVE_MKSTEMP) || defined(HAVE_MKTEMP)
|
|
-# define TEMPLATE_LEN strlen (template)
|
|
-#else
|
|
-# define TEMPLATE_LEN L_tmpnam
|
|
-#endif
|
|
- *name = xmalloc (TEMPLATE_LEN + 1);
|
|
- strcpy (*name, template);
|
|
-
|
|
#if defined(HAVE_MKSTEMP) && defined(HAVE_FDOPEN)
|
|
+ *name = get_tmptemplate ();
|
|
+
|
|
/* It's safest to use mkstemp(), if we can. */
|
|
EINTRLOOP (fd, mkstemp (*name));
|
|
if (fd == -1)
|
|
@@ -502,14 +564,10 @@ get_tmpfile (char **name, const char *te
|
|
else
|
|
file = fdopen (fd, "w");
|
|
#else
|
|
-# ifdef HAVE_MKTEMP
|
|
- (void) mktemp (*name);
|
|
-# else
|
|
- (void) tmpnam (*name);
|
|
-# endif
|
|
+ *name = get_tmppath ();
|
|
|
|
# ifdef HAVE_FDOPEN
|
|
- /* Can't use mkstemp(), but guard against a race condition. */
|
|
+ /* Can't use mkstemp(), but try to guard against a race condition. */
|
|
EINTRLOOP (fd, open (*name, O_CREAT|O_EXCL|O_WRONLY, 0600));
|
|
if (fd == -1)
|
|
return 0;
|
|
Index: make-4.3/src/os.h
|
|
===================================================================
|
|
--- make-4.3.orig/src/os.h
|
|
+++ make-4.3/src/os.h
|
|
@@ -23,7 +23,7 @@ this program. If not, see <http://www.g
|
|
unsigned int jobserver_enabled (void);
|
|
|
|
/* Called in the master instance to set up the jobserver initially. */
|
|
-unsigned int jobserver_setup (int job_slots);
|
|
+unsigned int jobserver_setup (int job_slots, const char *style);
|
|
|
|
/* Called in a child instance to connect to the jobserver. */
|
|
unsigned int jobserver_parse_auth (const char* auth);
|
|
@@ -61,18 +61,18 @@ unsigned int jobserver_acquire (int time
|
|
|
|
#else
|
|
|
|
-#define jobserver_enabled() (0)
|
|
-#define jobserver_setup(_slots) (0)
|
|
-#define jobserver_parse_auth(_auth) (0)
|
|
-#define jobserver_get_auth() (NULL)
|
|
-#define jobserver_clear() (void)(0)
|
|
-#define jobserver_release(_fatal) (void)(0)
|
|
-#define jobserver_acquire_all() (0)
|
|
-#define jobserver_signal() (void)(0)
|
|
-#define jobserver_pre_child(_r) (void)(0)
|
|
-#define jobserver_post_child(_r) (void)(0)
|
|
-#define jobserver_pre_acquire() (void)(0)
|
|
-#define jobserver_acquire(_tmout) (0)
|
|
+#define jobserver_enabled() (0)
|
|
+#define jobserver_setup(_slots, _style) (0)
|
|
+#define jobserver_parse_auth(_auth) (0)
|
|
+#define jobserver_get_auth() (NULL)
|
|
+#define jobserver_clear() (void)(0)
|
|
+#define jobserver_release(_fatal) (void)(0)
|
|
+#define jobserver_acquire_all() (0)
|
|
+#define jobserver_signal() (void)(0)
|
|
+#define jobserver_pre_child(_r) (void)(0)
|
|
+#define jobserver_post_child(_r) (void)(0)
|
|
+#define jobserver_pre_acquire() (void)(0)
|
|
+#define jobserver_acquire(_tmout) (0)
|
|
|
|
#endif
|
|
|
|
Index: make-4.3/src/posixos.c
|
|
===================================================================
|
|
--- make-4.3.orig/src/posixos.c
|
|
+++ make-4.3/src/posixos.c
|
|
@@ -20,10 +20,15 @@ this program. If not, see <http://www.g
|
|
|
|
#ifdef HAVE_FCNTL_H
|
|
# include <fcntl.h>
|
|
+# define FD_OK(_f) (fcntl ((_f), F_GETFD) != -1)
|
|
#elif defined(HAVE_SYS_FILE_H)
|
|
# include <sys/file.h>
|
|
#endif
|
|
|
|
+#if !defined(FD_OK)
|
|
+# define FD_OK(_f) 1
|
|
+#endif
|
|
+
|
|
#if defined(HAVE_PSELECT) && defined(HAVE_SYS_SELECT_H)
|
|
# include <sys/select.h>
|
|
#endif
|
|
@@ -34,6 +39,8 @@ this program. If not, see <http://www.g
|
|
|
|
#ifdef MAKE_JOBSERVER
|
|
|
|
+#define FIFO_PREFIX "fifo:"
|
|
+
|
|
/* This section provides OS-specific functions to support the jobserver. */
|
|
|
|
/* These track the state of the jobserver pipe. Passed to child instances. */
|
|
@@ -47,6 +54,19 @@ static int job_rfd = -1;
|
|
/* Token written to the pipe (could be any character...) */
|
|
static char token = '+';
|
|
|
|
+/* The type of jobserver we're using. */
|
|
+enum js_type
|
|
+ {
|
|
+ js_none = 0, /* No jobserver. */
|
|
+ js_pipe, /* Use a simple pipe as the jobserver. */
|
|
+ js_fifo /* Use a named pipe as the jobserver. */
|
|
+ };
|
|
+
|
|
+static enum js_type js_type = js_none;
|
|
+
|
|
+/* The name of the named pipe (if used). */
|
|
+static char *fifo_name = NULL;
|
|
+
|
|
static int
|
|
make_job_rfd (void)
|
|
{
|
|
@@ -81,13 +101,57 @@ set_blocking (int fd, int blocking)
|
|
}
|
|
|
|
unsigned int
|
|
-jobserver_setup (int slots)
|
|
+jobserver_setup (int slots, const char *style)
|
|
{
|
|
int r;
|
|
|
|
- EINTRLOOP (r, pipe (job_fds));
|
|
- if (r < 0)
|
|
- pfatal_with_name (_("creating jobs pipe"));
|
|
+#if HAVE_MKFIFO
|
|
+ if (style == NULL || strcmp (style, "fifo") == 0)
|
|
+ {
|
|
+ fifo_name = get_tmppath ();
|
|
+
|
|
+ EINTRLOOP (r, mkfifo (fifo_name, 0600));
|
|
+ if (r < 0)
|
|
+ {
|
|
+ perror_with_name("jobserver mkfifo: ", fifo_name);
|
|
+ free (fifo_name);
|
|
+ }
|
|
+ else
|
|
+ {
|
|
+ /* We have to open the read side in non-blocking mode, else it will
|
|
+ hang until the write side is open. */
|
|
+ EINTRLOOP (job_fds[0], open (fifo_name, O_RDONLY|O_NONBLOCK));
|
|
+ if (job_fds[0] < 0)
|
|
+ OSS (fatal, NILF, _("Cannot open jobserver %s: %s"),
|
|
+ fifo_name, strerror (errno));
|
|
+
|
|
+ EINTRLOOP (job_fds[1], open (fifo_name, O_WRONLY));
|
|
+ if (job_fds[0] < 0)
|
|
+ OSS (fatal, NILF, _("Cannot open jobserver %s: %s"),
|
|
+ fifo_name, strerror (errno));
|
|
+
|
|
+ DB (DB_JOBS,
|
|
+ (_("Jobserver setup (fifo %s)\n"), fifo_name));
|
|
+
|
|
+ js_type = js_fifo;
|
|
+ }
|
|
+ }
|
|
+#endif
|
|
+
|
|
+ if (js_type == js_none)
|
|
+ {
|
|
+ if (style && strcmp (style, "pipe") != 0)
|
|
+ OS (fatal, NILF, _("Unknown jobserver auth style '%s'"), style);
|
|
+
|
|
+ EINTRLOOP (r, pipe (job_fds));
|
|
+ if (r < 0)
|
|
+ pfatal_with_name (_("creating jobs pipe"));
|
|
+
|
|
+ DB (DB_JOBS,
|
|
+ (_("Jobserver setup (fds %d,%d)\n"), job_fds[0], job_fds[1]));
|
|
+
|
|
+ js_type = js_pipe;
|
|
+ }
|
|
|
|
/* By default we don't send the job pipe FDs to our children.
|
|
See jobserver_pre_child() and jobserver_post_child(). */
|
|
@@ -113,31 +177,63 @@ jobserver_setup (int slots)
|
|
unsigned int
|
|
jobserver_parse_auth (const char *auth)
|
|
{
|
|
+ int rfd, wfd;
|
|
+
|
|
/* Given the command-line parameter, parse it. */
|
|
- if (sscanf (auth, "%d,%d", &job_fds[0], &job_fds[1]) != 2)
|
|
- OS (fatal, NILF,
|
|
- _("internal error: invalid --jobserver-auth string '%s'"), auth);
|
|
|
|
- DB (DB_JOBS,
|
|
- (_("Jobserver client (fds %d,%d)\n"), job_fds[0], job_fds[1]));
|
|
+ /* First see if we're using a named pipe. */
|
|
+ if (strncmp (auth, FIFO_PREFIX, CSTRLEN (FIFO_PREFIX)) == 0)
|
|
+ {
|
|
+ fifo_name = xstrdup (auth + CSTRLEN (FIFO_PREFIX));
|
|
|
|
-#ifdef HAVE_FCNTL_H
|
|
-# define FD_OK(_f) (fcntl ((_f), F_GETFD) != -1)
|
|
-#else
|
|
-# define FD_OK(_f) 1
|
|
-#endif
|
|
+ EINTRLOOP (job_fds[0], open (fifo_name, O_RDONLY));
|
|
+ if (job_fds[0] < 0)
|
|
+ OSS (fatal, NILF,
|
|
+ _("Cannot open jobserver %s: %s"), fifo_name, strerror (errno));
|
|
+
|
|
+ EINTRLOOP (job_fds[1], open (fifo_name, O_WRONLY));
|
|
+ if (job_fds[0] < 0)
|
|
+ OSS (fatal, NILF,
|
|
+ _("Cannot open jobserver %s: %s"), fifo_name, strerror (errno));
|
|
+
|
|
+ js_type = js_fifo;
|
|
+ }
|
|
+ /* If not, it must be a simple pipe. */
|
|
+ else if (sscanf (auth, "%d,%d", &rfd, &wfd) == 2)
|
|
+ {
|
|
+ DB (DB_JOBS,
|
|
+ (_("Jobserver client (fds %d,%d)\n"), rfd, wfd));
|
|
|
|
- /* Make sure our pipeline is valid, and (possibly) create a duplicate pipe,
|
|
- that will be closed in the SIGCHLD handler. If this fails with EBADF,
|
|
- the parent has closed the pipe on us because it didn't think we were a
|
|
- submake. If so, warn and default to -j1. */
|
|
+ /* The parent overrode our FDs because we aren't a recursive make. */
|
|
+ if (rfd == -2 || wfd == -2)
|
|
+ return 0;
|
|
|
|
- if (!FD_OK (job_fds[0]) || !FD_OK (job_fds[1]) || make_job_rfd () < 0)
|
|
+ /* Make sure our pipeline is valid. */
|
|
+ if (!FD_OK (rfd) || !FD_OK (wfd))
|
|
+ return 0;
|
|
+
|
|
+ job_fds[0] = rfd;
|
|
+ job_fds[1] = wfd;
|
|
+
|
|
+ js_type = js_pipe;
|
|
+ }
|
|
+ /* Who knows what it is? */
|
|
+ else
|
|
+ {
|
|
+ OS (error, NILF, _("invalid --jobserver-auth string '%s'"), auth);
|
|
+ return 0;
|
|
+ }
|
|
+
|
|
+ /* Create a duplicate pipe, if needed, that will be closed in the SIGCHLD
|
|
+ handler. If this fails with EBADF, the parent closed the pipe on us as
|
|
+ it didn't think we were a submake. If so, warn and default to -j1. */
|
|
+
|
|
+ if (make_job_rfd () < 0)
|
|
{
|
|
if (errno != EBADF)
|
|
- pfatal_with_name (_("jobserver pipeline"));
|
|
+ pfatal_with_name ("jobserver readfd");
|
|
|
|
- job_fds[0] = job_fds[1] = -1;
|
|
+ jobserver_clear ();
|
|
|
|
return 0;
|
|
}
|
|
@@ -156,15 +252,23 @@ jobserver_parse_auth (const char *auth)
|
|
char *
|
|
jobserver_get_auth (void)
|
|
{
|
|
- char *auth = xmalloc ((INTSTR_LENGTH * 2) + 2);
|
|
- sprintf (auth, "%d,%d", job_fds[0], job_fds[1]);
|
|
+ char *auth;
|
|
+
|
|
+ if (js_type == js_fifo) {
|
|
+ auth = xmalloc (strlen (fifo_name) + CSTRLEN (FIFO_PREFIX) + 1);
|
|
+ sprintf (auth, FIFO_PREFIX "%s", fifo_name);
|
|
+ } else {
|
|
+ auth = xmalloc ((INTSTR_LENGTH * 2) + 2);
|
|
+ sprintf (auth, "%d,%d", job_fds[0], job_fds[1]);
|
|
+ }
|
|
+
|
|
return auth;
|
|
}
|
|
|
|
unsigned int
|
|
jobserver_enabled (void)
|
|
{
|
|
- return job_fds[0] >= 0;
|
|
+ return js_type != js_none;
|
|
}
|
|
|
|
void
|
|
@@ -178,6 +282,11 @@ jobserver_clear (void)
|
|
close (job_rfd);
|
|
|
|
job_fds[0] = job_fds[1] = job_rfd = -1;
|
|
+
|
|
+ free (fifo_name);
|
|
+ fifo_name = NULL;
|
|
+
|
|
+ js_type = js_none;
|
|
}
|
|
|
|
void
|
|
@@ -196,6 +305,7 @@ jobserver_release (int is_fatal)
|
|
unsigned int
|
|
jobserver_acquire_all (void)
|
|
{
|
|
+ int r;
|
|
unsigned int tokens = 0;
|
|
|
|
/* Use blocking reads to wait for all outstanding jobs. */
|
|
@@ -208,19 +318,25 @@ jobserver_acquire_all (void)
|
|
while (1)
|
|
{
|
|
char intake;
|
|
- int r;
|
|
EINTRLOOP (r, read (job_fds[0], &intake, 1));
|
|
if (r != 1)
|
|
- return tokens;
|
|
+ break;
|
|
++tokens;
|
|
}
|
|
+
|
|
+ if (fifo_name)
|
|
+ EINTRLOOP (r, unlink (fifo_name));
|
|
+
|
|
+ DB (DB_JOBS, ("Acquired all %u jobserver tokens.\n", tokens));
|
|
+
|
|
+ return tokens;
|
|
}
|
|
|
|
/* Prepare the jobserver to start a child process. */
|
|
void
|
|
jobserver_pre_child (int recursive)
|
|
{
|
|
- if (recursive && job_fds[0] >= 0)
|
|
+ if (recursive && js_type == js_pipe)
|
|
{
|
|
fd_inherit (job_fds[0]);
|
|
fd_inherit (job_fds[1]);
|
|
@@ -231,7 +347,7 @@ jobserver_pre_child (int recursive)
|
|
void
|
|
jobserver_post_child (int recursive)
|
|
{
|
|
- if (recursive && job_fds[0] >= 0)
|
|
+ if (recursive && js_type == js_pipe)
|
|
{
|
|
fd_noinherit (job_fds[0]);
|
|
fd_noinherit (job_fds[1]);
|
|
Index: make-4.3/src/vmsjobs.c
|
|
===================================================================
|
|
--- make-4.3.orig/src/vmsjobs.c
|
|
+++ make-4.3/src/vmsjobs.c
|
|
@@ -1241,9 +1241,7 @@ child_execute_job (struct childbase *chi
|
|
FILE *outfile;
|
|
int cmd_len;
|
|
|
|
- outfile = get_tmpfile (&child->comname,
|
|
- "sys$scratch:gnv$make_cmdXXXXXX.com");
|
|
- /* 123456789012345678901234567890 */
|
|
+ outfile = get_tmpfile (&child->comname);
|
|
if (outfile == 0)
|
|
pfatal_with_name (_("fopen (temporary file)"));
|
|
comnamelen = strlen (child->comname);
|
|
Index: make-4.3/src/w32/w32os.c
|
|
===================================================================
|
|
--- make-4.3.orig/src/w32/w32os.c
|
|
+++ make-4.3/src/w32/w32os.c
|
|
@@ -34,10 +34,13 @@ static char jobserver_semaphore_name[MAX
|
|
static HANDLE jobserver_semaphore = NULL;
|
|
|
|
unsigned int
|
|
-jobserver_setup (int slots)
|
|
+jobserver_setup (int slots, const char *style)
|
|
{
|
|
/* sub_proc.c is limited in the number of objects it can wait for. */
|
|
|
|
+ if (style && strcmp (style, "sem") != 0)
|
|
+ OS (fatal, NILF, _("Unknown jobserver auth style '%s'"), style);
|
|
+
|
|
if (slots > process_table_usable_size())
|
|
{
|
|
slots = process_table_usable_size();
|
|
Index: make-4.3/tests/scripts/features/jobserver
|
|
===================================================================
|
|
--- make-4.3.orig/tests/scripts/features/jobserver
|
|
+++ make-4.3/tests/scripts/features/jobserver
|
|
@@ -83,25 +83,42 @@ unlink('inc.mk');
|
|
# Test recursion which is hidden from make.
|
|
# See Savannah bug #39934
|
|
# Or Red Hat bug https://bugzilla.redhat.com/show_bug.cgi?id=885474
|
|
-# Windows doesn't use a pipe, and doesn't close access, so this won't happen.
|
|
+# Environments that don't use a pipe won't close access, so this won't happen.
|
|
if ($port_type ne 'W32') {
|
|
- open(MAKEFILE,"> Makefile2");
|
|
- print MAKEFILE '
|
|
- vpath %.c ../
|
|
- foo:
|
|
- ';
|
|
- close(MAKEFILE);
|
|
+ create_file('Makefile2', "vpath %.c ../\n", "foo:\n");
|
|
|
|
run_make_test(q!
|
|
default: ; @ #MAKEPATH# -f Makefile2
|
|
!,
|
|
- "-j2 $np",
|
|
+ "--jobserver-style=pipe -j2 $np",
|
|
"#MAKE#[1]: warning: jobserver unavailable: using -j1. Add '+' to parent make rule.
|
|
#MAKE#[1]: Nothing to be done for 'foo'.");
|
|
|
|
rmfiles('Makefile2');
|
|
}
|
|
|
|
+# For Windows and named pipes, we don't need to worry about recursion
|
|
+if ($port_type eq 'W32' || exists $FEATURES{'jobserver-fifo'}) {
|
|
+ create_file('Makefile2', "vpath %.c ../\n", "foo:\n");
|
|
+
|
|
+ run_make_test(q!
|
|
+default: ; @ #MAKEPATH# -f Makefile2
|
|
+!,
|
|
+ "-j2 $np",
|
|
+"#MAKE#[1]: Nothing to be done for 'foo'.");
|
|
+
|
|
+ rmfiles('Makefile2');
|
|
+}
|
|
+
|
|
+# Check for invalid jobserver-style options
|
|
+
|
|
+run_make_test(q!
|
|
+all: a
|
|
+all a: ; @echo $@
|
|
+!,
|
|
+ '--jobserver-style=foo -j8',
|
|
+ "#MAKE#: *** Unknown jobserver auth style 'foo'. Stop.", 512);
|
|
+
|
|
1;
|
|
|
|
### Local Variables:
|
|
Index: make-4.3/tests/scripts/functions/shell
|
|
===================================================================
|
|
--- make-4.3.orig/tests/scripts/functions/shell
|
|
+++ make-4.3/tests/scripts/functions/shell
|
|
@@ -81,6 +81,22 @@ $(shell kill -2 $$$$)
|
|
STAT := $(.SHELLSTATUS)
|
|
all: ; @echo STAT=$(STAT)
|
|
','',"STAT=$ret\n");
|
|
+
|
|
+# If we're not using pipes for jobserver, then they are available in sub-makes
|
|
+# invoked by $(shell ...)
|
|
+if ($port_type eq 'W32' || exists $FEATURES{'jobserver-fifo'}) {
|
|
+ run_make_test(q!
|
|
+ifeq ($(ELT),)
|
|
+default:; @$(MAKE) -f #MAKEFILE# ELT=1
|
|
+else ifeq ($(ELT),1)
|
|
+OUTPUT := $(shell $(MAKE) -f #MAKEFILE# ELT=2)
|
|
+$(info $(OUTPUT))
|
|
+default:;: $(ELT)
|
|
+else
|
|
+default:;: $(ELT)
|
|
+endif
|
|
+!,
|
|
+ '--no-print-directory -j2', ": 2\n: 1");
|
|
}
|
|
|
|
1;
|