From 09f1e4cf83853e3636a19da17e28e7291aac9bbd Mon Sep 17 00:00:00 2001 From: Paul Smith Date: Sun, 1 Aug 1999 06:05:17 +0000 Subject: * Applied some DOS updates. * Started reworking the jobserver algorithm; not complete yet. --- ChangeLog | 15 ++++++ Makefile.DOS.template | 26 +++++++++-- README.DOS.template | 15 +++--- configh.dos.template | 14 ++++++ function.c | 23 ++++----- job.c | 127 +++++++++++++++++++++++--------------------------- main.c | 65 +++++++++++++++----------- read.c | 14 +++--- remake.c | 4 -- 9 files changed, 171 insertions(+), 132 deletions(-) diff --git a/ChangeLog b/ChangeLog index d4d28bc..59d403d 100644 --- a/ChangeLog +++ b/ChangeLog @@ -12,6 +12,21 @@ * make.texinfo (Quick Reference): Update with the new features. +1999-07-25 Eli Zaretskii + + * remake.c [__MSDOS__]: Don't include variables.h, it's already + included. + + * function.c (msdos_openpipe) [__MSDOS__]: Return FILE ptr. + (func_shell) [__MSDOS__]: Fix the argument list. + + * Makefile.DOS.template: Update from Makefile.in. + + * README.DOS.template: Configure command fixed. + + * configh.dos.template: Update to provide definitions for + uintmax_t, fd_set_size_t, and HAVE_SELECT. + 1999-07-24 Paul D. Smith * Version 3.77.91 released. diff --git a/Makefile.DOS.template b/Makefile.DOS.template index b8d44ee..b90577e 100644 --- a/Makefile.DOS.template +++ b/Makefile.DOS.template @@ -1,7 +1,7 @@ # -*-Makefile-*- template for DJGPP # Makefile.in generated automatically by automake 1.2 from Makefile.am -# Copyright (C) 1994, 1995, 1996, 1997 Free Software Foundation, Inc. +# Copyright (C) 1994, 1995-1998, 1999 Free Software Foundation, Inc. # This Makefile.DOS is free software; the Free Software Foundation # gives unlimited permission to copy, distribute and modify it. @@ -118,7 +118,11 @@ HEADERS = $(wildcard $(srcdir)/*.h) default: all .SUFFIXES: -.SUFFIXES: .c .dvi .info .o .ps .texi .texinfo +.SUFFIXES: .S .c .dvi .info .o .ps .s .texi .texinfo .txi + +mostlyclean-hdr: + +clean-hdr: distclean-hdr: -rm -f config.h @@ -141,11 +145,17 @@ install-binPROGRAMS: $(bin_PROGRAMS) uninstall-binPROGRAMS: $(NORMAL_UNINSTALL) - list='$(bin_PROGRAMS)'; for p in $$list; do rm -f $(bindir)/`echo $$p|sed '$(transform)'`; done + list='$(bin_PROGRAMS)'; for p in $$list; do rm -f $(bindir)/`echo $$p|sed '$(transform)'`.exe; done .c.o: $(COMPILE) -c $< +.s.o: + $(COMPILE) -c $< + +.S.o: + $(COMPILE) -c $< + clean-noinstLIBRARIES: -test -z "$(noinst_LIBRARIES)" || rm -f $(noinst_LIBRARIES) @@ -155,7 +165,7 @@ mostlyclean-compile: clean-compile: distclean-compile: - -rm -f *.tab.c + -rm -f *.tab.c *_tab.c maintainer-clean-compile: @@ -188,6 +198,12 @@ DVIPS = dvips .texinfo.dvi: TEXINPUTS="$(srcdir);$$TEXINPUTS" MAKEINFO='$(MAKEINFO) -I $(srcdir)' $(TEXI2DVI) $< +.txi.info: + $(MAKEINFO) $(srcdir)/$< -o ./$@ + +.txi.dvi: + TEXINPUTS="$(srcdir);$$TEXINPUTS" MAKEINFO='$(MAKEINFO) -I $(srcdir)' $(TEXI2DVI) $< + .dvi.ps: $(DVIPS) $< -o $@ @@ -208,7 +224,7 @@ dist-info: $(INFO_DEPS) for base in $(INFO_DEPS); do d=$(srcdir); for file in `cd $$d && eval echo $$base*`; do test -f $(distdir)/$$file || ln $$d/$$file $(distdir)/$$file 2> /dev/null || cp -p $$d/$$file $(distdir)/$$file; done; done mostlyclean-aminfo: - rm -f make.aux make.cp make.cps make.dvi make.fn make.fns make.ky make.kys make.ps make.log make.pg make.toc make.tp make.tps make.vr make.vrs make.op make.tr make.cv make.cn + cd $(srcdir) && for i in $(INFO_DEPS) make.i; do rm -f `eval echo $$i*`; done clean-aminfo: diff --git a/README.DOS.template b/README.DOS.template index 6372437..1a7cb44 100644 --- a/README.DOS.template +++ b/README.DOS.template @@ -5,7 +5,7 @@ Builds with DJGPP v2 port of GNU C/C++ compiler and utilities. New (since 3.74) DOS-specific features: - 1. Supports long filenames when run from DOS box on Windows 95. + 1. Supports long filenames when run from DOS box on Windows 9x. 2. Supports both stock DOS COMMAND.COM and Unix-style shells (details in ``Notes'' below). @@ -48,9 +48,10 @@ To build: [Enter]. Otherwise, you need to supply the path to the source directory as an argument to the batch file, like this: - configure.bat c:/djgpp/gnu/make-%VERSION% + c:\djgpp\gnu\make-%VERSION%\configure.bat c:/djgpp/gnu/make-%VERSION% - Note the forward slashes: you MUST use them here. + Note the forward slashes in the source path argument: you MUST + use them here. 3. If configure.bat doesn't find a working Make, it will suggest to use the `dosbuild.bat' batch file to build Make. Either do as it @@ -228,9 +229,9 @@ Notes: 4. Letter-case in filenames. - If you run Make on Windows 95, you should be aware of the + If you run Make on Windows 9x, you should be aware of the letter-case issue. Make is internally case-sensitive, but all - file operations are case-insensitive on Windows 95, so + file operations are case-insensitive on Windows 9x, so e.g. files `FAQ', `faq' and `Faq' all refer to the same file, as far as Windows is concerned. The underlying DJGPP C library functions honor the letter-case of the filenames they get from @@ -240,8 +241,8 @@ Notes: converted to lower case are explained in the DJGPP libc docs, under the `_preserve_fncase' and `_lfn_gen_short_fname' functions, but as a thumb rule, any filename that is stored in - upper case in the directory, is a legal DOS 8+3 filename and - doesn't include characters illegal on MSDOS FAT filesystems, + upper case in the directory, is a valid DOS 8+3 filename and + doesn't include characters invalid on MSDOS FAT filesystems, will be automatically down-cased.) User reports that I have indicate that this default behavior is generally what you'd expect; however, your input is most welcome. diff --git a/configh.dos.template b/configh.dos.template index 7eaed6e..3ff5de3 100644 --- a/configh.dos.template +++ b/configh.dos.template @@ -33,3 +33,17 @@ #define HAVE_MEMMOVE 1 #define SCCS_GET "get" + +/* Define to `unsigned long' or `unsigned long long' + if doesn't define. */ +#define uintmax_t unsigned long long + +/* Define the type of the first arg to select(). */ +#define fd_set_size_t int + +/* Define if you have the select function. */ +#define HAVE_SELECT 1 + +/* Define if you have the vprintf library function. */ +#undef HAVE_VPRINTF +#define HAVE_VPRINTF 1 diff --git a/function.c b/function.c index d5ceb78..0771274 100644 --- a/function.c +++ b/function.c @@ -1203,15 +1203,11 @@ windows32_openpipe (int *pipedes, int *pid_p, char **command_argv, char **envp) #ifdef __MSDOS__ -/* - untested -*/ int msdos_openpipe (int* pipedes, int *pidp, char *text) { FILE *fpipe=0; - /* MSDOS can't fork, but it has `popen'. - (Bwt, why isn't `popen' used in all the versions?) */ + /* MSDOS can't fork, but it has `popen'. */ struct variable *sh = lookup_variable ("SHELL", 5); int e; extern int dos_command_running, dos_status; @@ -1235,6 +1231,9 @@ msdos_openpipe (int* pipedes, int *pidp, char *text) errno = 0; dos_command_running = 1; dos_status = 0; + /* If dos_status becomes non-zero, it means the child process + was interrupted by a signal, like SIGINT or SIGQUIT. See + fatal_error_signal in commands.c. */ fpipe = popen (text, "rt"); dos_command_running = 0; if (!fpipe || dos_status) @@ -1250,7 +1249,7 @@ msdos_openpipe (int* pipedes, int *pidp, char *text) else { pipedes[0] = fileno (fpipe); - *pidp = 42; /* uh? The meaning of Life?*/ + *pidp = 42; /* Yes, the Meaning of Life, the Universe, and Everything! */ errno = e; shell_function_completed = 1; } @@ -1308,11 +1307,9 @@ func_shell (o, argv, funcname) /* For error messages. */ if (reading_file != 0) { - error_prefix = (char *) alloca (strlen(reading_file->filenm)+100); - + error_prefix = (char *) alloca (strlen(reading_file->filenm)+100); sprintf (error_prefix, "%s:%lu: ", reading_file->filenm, reading_file->lineno); - } else error_prefix = ""; @@ -1322,11 +1319,11 @@ func_shell (o, argv, funcname) #else /* WINDOWS32 */ # ifdef __MSDOS__ - fpipe = msdos_openpipe (pipedes, argv[0], command_argv, envp); - if (!fpipe || pipedes[0] < 0) + fpipe = msdos_openpipe (pipedes, &pid, argv[0]); + if (pipedes[0] < 0) { - perror_with_name (error_prefix, "pipe"); - return o; + perror_with_name (error_prefix, "pipe"); + return o; } # else if (pipe (pipedes) < 0) diff --git a/job.c b/job.c index 585c35e..17743a2 100644 --- a/job.c +++ b/job.c @@ -299,21 +299,30 @@ vmsWaitForChildren(int *status) #endif -/* 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. */ +/* Handle a dead child. This handler may or may not ever be installed. + + If we're using the jobserver blocking read, we need it. First, installing + it ensures the read will interrupt on SIGCHLD. Second, we close the dup'd + read side of the pipe to ensure we don't enter another blocking read + without reaping all the dead children. In this case we don't need the + dead_children count. + + If we don't have either waitpid or wait3, then make is unreliable, but we + use the dead_children count to reap children as best we can. In this case + job_rfd will never be >= 0. */ static unsigned int dead_children = 0; -/* Notice that a child died. - reap_children should be called when convenient. */ RETSIGTYPE child_handler (sig) int sig; { ++dead_children; + if (job_rfd >= 0) + close (job_rfd); + job_rfd = -1; + if (debug_flag) printf (_("Got a SIGCHLD; %u unreaped children.\n"), dead_children); } @@ -927,12 +936,7 @@ start_job_command (child) /* Set the descriptor to close on exec, so it does not litter any child's descriptor table. When it is dup2'd onto descriptor 0, that descriptor will not close on exec. */ -#ifdef F_SETFD -#ifndef FD_CLOEXEC -#define FD_CLOEXEC 1 -#endif - (void) fcntl (bad_stdin, F_SETFD, FD_CLOEXEC); -#endif + CLOSE_ON_EXEC (bad_stdin); } } @@ -1170,57 +1174,6 @@ start_waiting_job (c) /* If not, start it locally. */ if (!c->remote) { -#ifdef MAKE_JOBSERVER - /* If we are controlling multiple jobs, and we don't yet have one, - * obtain a token before starting the child. */ - if (job_fds[0] >= 0) - { - while (c->job_token == '-') - /* If the reserved token is available, just use that. */ - if (my_job_token != '-') - { - c->job_token = my_job_token; - my_job_token = '-'; - } - /* Read a token. We set the non-blocking bit on this earlier, so - if there's no token to be read we'll return immediately. */ - else if (read (job_fds[0], &c->job_token, 1) < 1) - { - fd_set rfds; - int r; - - FD_ZERO(&rfds); - FD_SET(job_fds[0], &rfds); - - /* The select blocks 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 (SIGCHLD), is reported - (because we installed a handler for it). If the latter, - call reap_children() to try to free up some slots. */ - - 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 != '-'); - if (debug_flag) - printf (_("Obtained token `%c' for child 0x%08lx (%s).\n"), - c->job_token, (unsigned long int) c, c->file->name); - } -#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 ()) @@ -1291,12 +1244,6 @@ 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) - while (job_slots_used == job_slots) - reap_children (1, 0); - /* Expand the command lines and store the results in LINES. */ lines = (char **) xmalloc (cmds->ncommand_lines * sizeof (char *)); for (i = 0; i < cmds->ncommand_lines; ++i) @@ -1413,6 +1360,48 @@ new_job (file) /* Fetch the first command line to be run. */ job_next_command (c); + /* 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 jobserver. */ + if (job_slots != 0) + while (job_slots_used == job_slots) + reap_children (1, 0); +#ifdef MAKE_JOBSERVER + /* If we are controlling multiple jobs, and we don't yet have one, + obtain a token before starting the child. */ + else if (job_fds[0] >= 0) + { + while (c->job_token == '-') + /* If the reserved token is available, just use that. */ + if (my_job_token == '+') + { + c->job_token = my_job_token; + my_job_token = '-'; + } + /* Read a token. As long as there's no token available we'll block. + If we get a SIGCHLD we'll return with EINTR. If one happened + before we got here we'll return with EBADF. */ + else if (read (job_rfd, &c->job_token, 1) < 1) + { + if (errno == EINTR) + ; + + /* If EBADF, we got a SIGCHLD before. Otherwise, who knows? */ + else if (errno != EBADF) + pfatal_with_name (_("read jobs pipe")); + + /* Something's done; reap it. We don't force a block here; if + something strange happened and nothing's ready, just come back + and wait some more. */ + reap_children (0, 0); + } + + assert(c->job_token != '-'); + if (debug_flag) + printf (_("Obtained token `%c' for child 0x%08lx (%s).\n"), + c->job_token, (unsigned long int) c, c->file->name); + } +#endif + /* The job is now primed. Start it running. (This will notice if there are in fact no commands.) */ (void)start_waiting_job (c); diff --git a/main.c b/main.c index 75c86a0..d40ae3f 100644 --- a/main.c +++ b/main.c @@ -205,6 +205,7 @@ static unsigned int inf_jobs = 0; /* File descriptors for the jobs pipe. */ int job_fds[2] = { -1, -1 }; +int job_rfd = -1; /* Maximum load average at which multiple jobs will be run. Negative values mean unlimited, while zero means limit to @@ -251,7 +252,7 @@ static const struct command_switch switches[] = 0, 0, _("Ignored for compatibility") }, { 'C', string, (char *) &directories, 0, 0, 0, 0, 0, - "directory", "DIRECTORY", + "directory", _("DIRECTORY"), _("Change to DIRECTORY before doing anything") }, { 'd', flag, (char *) &debug_flag, 1, 1, 0, 0, 0, "debug", 0, @@ -265,7 +266,7 @@ static const struct command_switch switches[] = "environment-overrides", 0, _("Environment variables override makefiles") }, { 'f', string, (char *) &makefiles, 0, 0, 0, 0, 0, - "file", "FILE", + "file", _("FILE"), _("Read FILE as a makefile") }, { 'h', flag, (char *) &print_usage_flag, 0, 0, 0, 0, 0, "help", 0, @@ -274,7 +275,7 @@ static const struct command_switch switches[] = "ignore-errors", 0, _("Ignore errors from commands") }, { 'I', string, (char *) &include_directories, 1, 1, 0, 0, 0, - "include-dir", "DIRECTORY", + "include-dir", _("DIRECTORY"), _("Search DIRECTORY for included makefiles") }, { 'j', #ifndef MAKE_JOBSERVER @@ -307,7 +308,7 @@ static const struct command_switch switches[] = "just-print", 0, _("Don't actually run any commands; just print them") }, { 'o', string, (char *) &old_files, 0, 0, 0, 0, 0, - "old-file", "FILE", + "old-file", _("FILE"), _("Consider FILE to be very old and don't remake it") }, { 'p', flag, (char *) &print_data_base_flag, 1, 1, 0, 0, 0, "print-data-base", 0, @@ -341,7 +342,7 @@ static const struct command_switch switches[] = "no-print-directory", 0, _("Turn off -w, even if it was turned on implicitly") }, { 'W', string, (char *) &new_files, 0, 0, 0, 0, 0, - "what-if", "FILE", + "what-if", _("FILE"), _("Consider FILE to be infinitely new") }, { 3, flag, (char *) &warn_undefined_variables_flag, 1, 1, 0, 0, 0, "warn-undefined-variables", 0, @@ -1168,31 +1169,36 @@ int main (int argc, char ** argv) } #if defined(MAKE_JOBSERVER) || !defined(HAVE_WAIT_NOHANG) - /* If we don't have a hanging wait we have to fall back to old, broken + /* Set up to handle children dying. This must be done before + reading in the makefiles so that `shell' function calls will work. + + 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. 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. + SIGCHLD is not ignored; we need it to interrupt the read(2) of the + jobserver pipe in job.c if we're waiting for a token. - Use sigaction where possible as it's more reliable. */ + If none of these are true, we don't need a signal handler at all. */ { 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. */ - -#ifndef HAVE_SIGACTION -# define HANDLESIG(s) signal(s, child_handler) -#else -# define HANDLESIG(s) sigaction(s, &sa, NULL) +# if defined HAVE_SIGACTION struct sigaction sa; bzero ((char *)&sa, sizeof (struct sigaction)); sa.sa_handler = child_handler; -#endif +# if defined SA_INTERRUPT + /* This is supposed to be the default, but what the heck... */ + sa.sa_flags = SA_INTERRUPT; +# endif +# define HANDLESIG(s) sigaction(s, &sa, NULL) +# else +# define HANDLESIG(s) signal(s, child_handler) +# endif + /* OK, now actually install the handlers. */ # if defined SIGCHLD (void) HANDLESIG (SIGCHLD); # endif @@ -1287,12 +1293,12 @@ int main (int argc, char ** argv) and write FDs, respectively, for the pipe. Note this last form is undocumented for the user! */ - sscanf(job_slots_str, "%d", &job_slots); + sscanf (job_slots_str, "%d", &job_slots); { - char *cp = index(job_slots_str, ','); + char *cp = index (job_slots_str, ','); /* In case #4, get the FDs. */ - if (cp && sscanf(cp+1, "%d", &job_fds[1]) == 1) + if (cp && sscanf (cp+1, "%d", &job_fds[1]) == 1) { /* Set up the first FD and set job_slots to 0. The combination of a pipe + !job_slots means we're using the jobserver. If !job_slots @@ -1326,10 +1332,6 @@ int main (int argc, char ** argv) 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); - /* Every make assumes that it always has one job it can run. For the 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. */ @@ -1350,6 +1352,16 @@ int main (int argc, char ** argv) sprintf(buf, "%d,%d", job_fds[0], job_fds[1]); job_slots_str = xstrdup(buf); } + + /* If we have a jobserver pipe, dup(2) the read end. We'll use that in + the child handler to note a child has died. See job.c. */ + + if (job_fds[0] >= 0) + { + job_rfds = dup (job_fds[0]); + CLOSE_ON_EXEC (job_rfds); + } + #endif /* Set up MAKEFLAGS and MFLAGS again, so they will be right. */ @@ -1533,7 +1545,8 @@ int main (int argc, char ** argv) if (d->changed & RM_INCLUDED) /* An included makefile. We don't need to die, but we do want to complain. */ - error (NILF, _("Included makefile `%s' was not found."), + error (NILF, + _("Included makefile `%s' was not found."), dep_name (d)); else { @@ -1877,7 +1890,7 @@ print_usage (bad) usageto = bad ? stderr : stdout; - fprintf (usageto, "Usage: %s [options] [target] ...\n", program); + fprintf (usageto, _("Usage: %s [options] [target] ...\n"), program); fputs (_("Options:\n"), usageto); for (cs = switches; cs->c != '\0'; ++cs) diff --git a/read.c b/read.c index c3ce067..400a62c 100644 --- a/read.c +++ b/read.c @@ -658,8 +658,7 @@ read_makefile (filename, flags) if (*p == '\0') { error (&fileinfo, - _("no file name for `%sinclude'"), - noerror ? "-" : ""); + _("no file name for `%sinclude'"), noerror ? "-" : ""); continue; } @@ -692,8 +691,7 @@ read_makefile (filename, flags) if (! read_makefile (name, (RM_INCLUDED | RM_NO_TILDE | (noerror ? RM_DONTCARE : 0))) && ! noerror) - error (&fileinfo, - "%s: %s", name, strerror (errno)); + error (&fileinfo, "%s: %s", name, strerror (errno)); free(name); } @@ -1442,7 +1440,7 @@ record_target_var (filenames, defn, two_colon, origin, flocp) /* Make the new variable context current and define the variable. */ current_variable_set_list = vlist; - v = try_variable_definition(flocp, defn, origin); + v = try_variable_definition (flocp, defn, origin); if (!v) error (flocp, _("Malformed per-target variable definition")); v->per_target = 1; @@ -1455,10 +1453,10 @@ record_target_var (filenames, defn, two_colon, origin, flocp) int len = strlen(v->name); current_variable_set_list = global; - gv = lookup_variable(v->name, len); + gv = lookup_variable (v->name, len); if (gv && (gv->origin == o_env_override || gv->origin == o_command)) - define_variable_in_set(v->name, len, gv->value, gv->origin, - gv->recursive, vlist->set); + define_variable_in_set (v->name, len, gv->value, gv->origin, + gv->recursive, vlist->set); } /* Free name if not needed further. */ diff --git a/remake.c b/remake.c index 45633db..6464f34 100644 --- a/remake.c +++ b/remake.c @@ -32,10 +32,6 @@ Boston, MA 02111-1307, USA. */ #include #endif -#ifdef __MSDOS__ -#include "variable.h" -#endif - #ifdef VMS #include #endif -- cgit v1.2.3