diff --git a/jobserver-fifo.patch b/jobserver-fifo.patch new file mode 100644 index 0000000..2cc6640 --- /dev/null +++ b/jobserver-fifo.patch @@ -0,0 +1,1001 @@ +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 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 ++# define FD_OK(_f) (fcntl ((_f), F_GETFD) != -1) + #elif defined(HAVE_SYS_FILE_H) + # include + #endif + ++#if !defined(FD_OK) ++# define FD_OK(_f) 1 ++#endif ++ + #if defined(HAVE_PSELECT) && defined(HAVE_SYS_SELECT_H) + # include + #endif +@@ -34,6 +39,8 @@ this program. If not, see = 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; diff --git a/jobserver-noinherit.patch b/jobserver-noinherit.patch new file mode 100644 index 0000000..66621f1 --- /dev/null +++ b/jobserver-noinherit.patch @@ -0,0 +1,43 @@ +From d79fe162c009788888faaf0317253b6f0cac7092 Mon Sep 17 00:00:00 2001 +From: Kevin Buettner +Date: Thu, 23 Apr 2020 17:05:34 -0400 +Subject: [PATCH] [SV 58232] Disable inheritance of jobserver FDs for recursive + make + +A parent make will invoke a sub-make with close-on-exec disabled for +the jobserver pipe FDs. Force close-on-exec to be to be enabled in +the sub-make so the pipe is not always passed to child jobs. + +I have a test case which, when invoked with a suitable -j switch, +will hang if the recipe inherits the jobserver pipe. This test case +was inspired by a real world case in which testing GDB on Fedora +would hang due to some poorly written test GDB cases having been +passed the jobserver file descriptors. + +* src/posixos.c (jobserver_parse_auth): Call fd_noinherit() for +jobserver pipe descriptors. + +Copyright-paperwork-exempt: yes +--- + src/posixos.c | 5 +++++ + 1 file changed, 5 insertions(+) + +diff --git a/src/posixos.c b/src/posixos.c +index 525f292c..eab175a4 100644 +--- a/src/posixos.c ++++ b/src/posixos.c +@@ -145,6 +145,11 @@ jobserver_parse_auth (const char *auth) + /* When using pselect() we want the read to be non-blocking. */ + set_blocking (job_fds[0], 0); + ++ /* By default we don't send the job pipe FDs to our children. ++ See jobserver_pre_child() and jobserver_post_child(). */ ++ fd_noinherit (job_fds[0]); ++ fd_noinherit (job_fds[1]); ++ + return 1; + } + +-- +2.37.2 + diff --git a/make.changes b/make.changes index 99ac9c0..116b13f 100644 --- a/make.changes +++ b/make.changes @@ -1,3 +1,10 @@ +------------------------------------------------------------------- +Wed Aug 17 15:05:38 UTC 2022 - Andreas Schwab + +- jobserver-noinherit.patch: Disable inheritance of jobserver FDs for + recursive make +- jobserver-fifo.patch: Add support for jobserver using named pipes + ------------------------------------------------------------------- Tue Apr 19 13:30:15 UTC 2022 - Marcus Meissner diff --git a/make.spec b/make.spec index c76887c..4b73ffc 100644 --- a/make.spec +++ b/make.spec @@ -29,13 +29,16 @@ Source1: https://ftp.gnu.org/gnu/make/make-%{version}.tar.gz.sig Source2: %{name}.keyring Patch1: make-testcases_timeout.diff Patch2: fix-57962.patch +Patch3: jobserver-noinherit.patch +Patch4: jobserver-fifo.patch Patch5: test-driver.patch Patch64: make-library-search-path.diff BuildRequires: autoconf BuildRequires: automake +BuildRequires: makeinfo BuildRequires: pkgconfig Requires(post): %{install_info_prereq} -Requires(preun): %{install_info_prereq} +Requires(preun):%{install_info_prereq} Provides: gmake %description @@ -47,6 +50,8 @@ The GNU make command with extensive documentation. %setup -q %patch1 -p1 %patch2 -p1 +%patch3 -p1 +%patch4 -p1 %patch5 -p1 if [ %{_lib} = lib64 ]; then %patch64 -p1