diff options
author | Theo de Raadt <deraadt@cvs.openbsd.org> | 1995-12-14 03:23:42 +0000 |
---|---|---|
committer | Theo de Raadt <deraadt@cvs.openbsd.org> | 1995-12-14 03:23:42 +0000 |
commit | 82bbf197af5c92368dd26a439545e66e1295e4d7 (patch) | |
tree | 94cc412e5255c41ac8a18fb68adcd10f7b92b923 /usr.bin/make/job.c | |
parent | 95f41a9ae474619e43de33821c56a85f414715cf (diff) |
from christos@netbsd:
Minor:
- ${.PREFIX} should never contain a full pathname
- Fixed gcc -Wall warnings
Major:
- compatMake is now FALSE. This means that we are now running in
full pmake mode:
* rules on dependency lines can be executed in parallel and or
out of sequence:
foo: bar baz
can fire the rule for baz before the rule for bar is fired.
To enforce bar to be fired before baz, another rule needs to be
added. [bar: baz]
* adjacent shell commands in a target are now executed by a single
invocation of the shell, not one invocation of the shell per line
(compatMake can be turned off using the -B flag)
- The -j flag now works... I.e. make -j 4 will fork up to four jobs in
parallel when it can. The target name is printed before each burst
of output caused by the target execution as '--- target ---', when j > 1
- I have changed all the Makefiles so that they work with make -j N, and
I have tested the whole netbsd by:
'make -j 4 cleandir; make -j 4 depend; make -j 4; make -j 4 install'
- I have not compiled or tested this version of make with -DREMOTE.
- Turn compat mode on by default. It gets turned off when the -j without
the -B flag is specified. [Thus you can use -j 1 to turn it off].
- Fix malloc -> emalloc as Gordon noted.
Updates for POSIX/SVR4 compiling:
arch.c: Don't require ranlib stuff. Not everybody has it.
dir.c: SunOS-4 != Solaris; change #ifdef sun to #if sun && !__svr4__
job.c, compat.c: Don't use 'union wait', use int and the W*() macros.
main.c: Check for uname() == -1; some unames return > 0...
util.c, job.c: Add signal() with BSD semantics for svr4, don't use bsd
sigmask and friends.
from cgd@netbsd:
pull in make.h. (PAlloc() now uses emalloc(), which is prototyped in
make.h. If the prototype is not in scope on the Alpha, I see lots
of "cast to pointer from integer of different size" warnings.)
Diffstat (limited to 'usr.bin/make/job.c')
-rw-r--r-- | usr.bin/make/job.c | 1542 |
1 files changed, 985 insertions, 557 deletions
diff --git a/usr.bin/make/job.c b/usr.bin/make/job.c index 85fb435b40a..f6b9dda0368 100644 --- a/usr.bin/make/job.c +++ b/usr.bin/make/job.c @@ -1,4 +1,4 @@ -/* $NetBSD: job.c,v 1.11 1995/09/27 18:44:40 jtc Exp $ */ +/* $NetBSD: job.c,v 1.13 1995/11/22 17:40:09 christos Exp $ */ /* * Copyright (c) 1988, 1989, 1990 The Regents of the University of California. @@ -42,7 +42,7 @@ #if 0 static char sccsid[] = "@(#)job.c 5.15 (Berkeley) 3/1/91"; #else -static char rcsid[] = "$NetBSD: job.c,v 1.11 1995/09/27 18:44:40 jtc Exp $"; +static char rcsid[] = "$NetBSD: job.c,v 1.13 1995/11/22 17:40:09 christos Exp $"; #endif #endif /* not lint */ @@ -118,6 +118,12 @@ static char rcsid[] = "$NetBSD: job.c,v 1.11 1995/09/27 18:44:40 jtc Exp $"; #include "dir.h" #include "job.h" #include "pathnames.h" +#ifdef REMOTE +#include "rmt.h" +# define STATIC +#else +# define STATIC static +#endif extern int errno; @@ -130,6 +136,11 @@ static int aborting = 0; /* why is the make aborting? */ #define ABORT_INTERRUPT 2 /* Because it was interrupted */ #define ABORT_WAIT 3 /* Waiting for jobs to finish */ +/* + * XXX: Avoid SunOS bug... FILENO() is fp->_file, and file + * is a char! So when we go above 127 we turn negative! + */ +#define FILENO(a) ((unsigned) fileno(a)) /* * post-make command processing. The node postCommands is really just the @@ -142,7 +153,6 @@ static int numCommands; /* The number of commands actually printed * for a target. Should this number be * 0, no shell will be executed. */ - /* * Return values from JobStart. */ @@ -182,17 +192,20 @@ static Shell shells[] = { { "sh", TRUE, "set -", "set -v", "set -", 5, + TRUE, "set -e", "set +e", +#ifdef OLDBOURNESHELL FALSE, "echo \"%s\"\n", "sh -c '%s || exit 0'\n", +#endif "v", "e", }, /* * UNKNOWN. */ { - (char *)0, - FALSE, (char *)0, (char *)0, (char *)0, 0, - FALSE, (char *)0, (char *)0, - (char *)0, (char *)0, + (char *) 0, + FALSE, (char *) 0, (char *) 0, (char *) 0, 0, + FALSE, (char *) 0, (char *) 0, + (char *) 0, (char *) 0, } }; static Shell *commandShell = &shells[DEFSHELL];/* this is the shell to @@ -200,17 +213,17 @@ static Shell *commandShell = &shells[DEFSHELL];/* this is the shell to * commands in the Makefile. * It is set by the * Job_ParseShell function */ -static char *shellPath = (char *) NULL, /* full pathname of +static char *shellPath = NULL, /* full pathname of * executable image */ *shellName; /* last component of shell */ static int maxJobs; /* The most children we can run at once */ static int maxLocal; /* The most local ones we can have */ -int nJobs; /* The number of children currently running */ -int nLocal; /* The number of local children */ -Lst jobs; /* The structures that describe them */ -Boolean jobFull; /* Flag to tell when the job table is full. It +STATIC int nJobs; /* The number of children currently running */ +STATIC int nLocal; /* The number of local children */ +STATIC Lst jobs; /* The structures that describe them */ +STATIC Boolean jobFull; /* Flag to tell when the job table is full. It * is set TRUE when (1) the total number of * running jobs equals the maximum allowed or * (2) a job can only be run locally, but @@ -220,12 +233,21 @@ static fd_set outputs; /* Set of descriptors of pipes connected to * the output channels of children */ #endif -GNode *lastNode; /* The node for which output was most recently +STATIC GNode *lastNode; /* The node for which output was most recently * produced. */ -char *targFmt; /* Format string to use to head output from a +STATIC char *targFmt; /* Format string to use to head output from a * job when it's not the most-recent job heard * from */ -#define TARG_FMT "--- %s ---\n" /* Default format */ + +#ifdef REMOTE +# define TARG_FMT "--- %s at %s ---\n" /* Default format */ +# define MESSAGE(fp, gn) \ + (void) fprintf(fp, targFmt, gn->name, gn->rem.hname); +#else +# define TARG_FMT "--- %s ---\n" /* Default format */ +# define MESSAGE(fp, gn) \ + (void) fprintf(fp, targFmt, gn->name); +#endif /* * When JobStart attempts to run a job remotely but can't, and isn't allowed @@ -233,34 +255,63 @@ char *targFmt; /* Format string to use to head output from a * been migrated home, the job is placed on the stoppedJobs queue to be run * when the next job finishes. */ -Lst stoppedJobs; /* Lst of Job structures describing +STATIC Lst stoppedJobs; /* Lst of Job structures describing * jobs that were stopped due to concurrency * limits or migration home */ #if defined(USE_PGRP) && defined(SYSV) -#define KILL(pid,sig) killpg (-(pid),(sig)) +# define KILL(pid, sig) killpg(-(pid), (sig)) #else # if defined(USE_PGRP) -#define KILL(pid,sig) killpg ((pid),(sig)) +# define KILL(pid, sig) killpg((pid), (sig)) # else -#define KILL(pid,sig) kill ((pid),(sig)) +# define KILL(pid, sig) kill((pid), (sig)) # endif #endif +/* + * Grmpf... There is no way to set bits of the wait structure + * anymore with the stupid W*() macros. I liked the union wait + * stuff much more. So, we devise our own macros... This is + * really ugly, use dramamine sparingly. You have been warned. + */ +#define W_SETMASKED(st, val, fun) \ + { \ + int sh = (int) ~0; \ + int mask = fun(sh); \ + \ + for (sh = 0; ((mask >> sh) & 1) == 0; sh++) \ + continue; \ + *(st) = (*(st) & ~mask) | ((val) << sh); \ + } + +#define W_SETTERMSIG(st, val) W_SETMASKED(st, val, WTERMSIG) +#define W_SETEXITSTATUS(st, val) W_SETMASKED(st, val, WEXITSTATUS) + + static int JobCondPassSig __P((ClientData, ClientData)); static void JobPassSig __P((int)); static int JobCmpPid __P((ClientData, ClientData)); static int JobPrintCommand __P((ClientData, ClientData)); static int JobSaveCommand __P((ClientData, ClientData)); -static void JobFinish __P((Job *, union wait)); +static void JobClose __P((Job *)); +#ifdef REMOTE +static int JobCmpRmtID __P((Job *, int)); +# ifdef RMT_WILL_WATCH +static void JobLocalInput __P((int, Job *)); +# endif +#else +static void JobFinish __P((Job *, int *)); static void JobExec __P((Job *, char **)); +#endif static void JobMakeArgv __P((Job *, char **)); static void JobRestart __P((Job *)); static int JobStart __P((GNode *, int, Job *)); static void JobDoOutput __P((Job *, Boolean)); static Shell *JobMatchShell __P((char *)); -static void JobInterrupt __P((int)); +static void JobInterrupt __P((int, int)); +static void JobRestartJobs __P((void)); /*- *----------------------------------------------------------------------- @@ -285,7 +336,7 @@ JobCondPassSig(jobp, signop) int signo = *(int *) signop; #ifdef RMT_WANTS_SIGNALS if (job->flags & JOB_REMOTE) { - (void)Rmt_Signal(job, signo); + (void) Rmt_Signal(job, signo); } else { KILL(job->pid, signo); } @@ -294,9 +345,15 @@ JobCondPassSig(jobp, signop) * Assume that sending the signal to job->pid will signal any remote * job as well. */ + if (DEBUG(JOB)) { + (void) fprintf(stdout, + "JobCondPassSig passing signal %d to child %d.\n", + signo, job->pid); + (void) fflush(stdout); + } KILL(job->pid, signo); #endif - return(0); + return 0; } /*- @@ -317,9 +374,13 @@ static void JobPassSig(signo) int signo; /* The signal number we've received */ { - int mask; + sigset_t nmask, omask; - Lst_ForEach(jobs, JobCondPassSig, (ClientData)(long)signo); + if (DEBUG(JOB)) { + (void) fprintf(stdout, "JobPassSig(%d) called.\n", signo); + (void) fflush(stdout); + } + Lst_ForEach(jobs, JobCondPassSig, (ClientData) &signo); /* * Deal with proper cleanup based on the signal received. We only run @@ -327,9 +388,9 @@ JobPassSig(signo) * three termination signals are more of a "get out *now*" command. */ if (signo == SIGINT) { - JobInterrupt(TRUE); + JobInterrupt(TRUE, signo); } else if ((signo == SIGHUP) || (signo == SIGTERM) || (signo == SIGQUIT)) { - JobInterrupt(FALSE); + JobInterrupt(FALSE, signo); } /* @@ -345,17 +406,24 @@ JobPassSig(signo) * This ensures that all our jobs get continued when we wake up before * we take any other signal. */ - mask = sigblock(0); - (void) sigsetmask(~0 & ~(1 << (signo-1))); - signal(signo, SIG_DFL); + sigfillset(&nmask); + (void) sigprocmask(SIG_BLOCK, &nmask, &omask); - kill(getpid(), signo); + if (DEBUG(JOB)) { + (void) fprintf(stdout, + "JobPassSig passing signal to self, mask = %x.\n", + ~0 & ~(1 << (signo-1))); + (void) fflush(stdout); + } + (void) signal(signo, SIG_DFL); + + (void) KILL(getpid(), signo); signo = SIGCONT; Lst_ForEach(jobs, JobCondPassSig, (ClientData) &signo); - sigsetmask(mask); - signal(signo, JobPassSig); + (void) sigprocmask(SIG_SETMASK, &omask, NULL); + (void) signal(signo, JobPassSig); } @@ -374,13 +442,36 @@ JobPassSig(signo) *----------------------------------------------------------------------- */ static int -JobCmpPid (job, pid) +JobCmpPid(job, pid) ClientData job; /* job to examine */ ClientData pid; /* process id desired */ { - return ( *(int *) pid - ((Job *) job)->pid); + return( *(int *) pid - ((Job *) job)->pid); } +#ifdef REMOTE +/*- + *----------------------------------------------------------------------- + * JobCmpRmtID -- + * Compare the rmtID of the job with the given rmtID and return 0 if they + * are equal. + * + * Results: + * 0 if the rmtID's match + * + * Side Effects: + * None. + *----------------------------------------------------------------------- + */ +static int +JobCmpRmtID(job, rmtID) + ClientData job; /* job to examine */ + ClientData rmtID; /* remote id desired */ +{ + return(*(int *) rmtID - *(int *) job->rmtID); +} +#endif + /*- *----------------------------------------------------------------------- * JobPrintCommand -- @@ -409,7 +500,7 @@ JobCmpPid (job, pid) *----------------------------------------------------------------------- */ static int -JobPrintCommand (cmdp, jobp) +JobPrintCommand(cmdp, jobp) ClientData cmdp; /* command string to print */ ClientData jobp; /* job for which to print it */ { @@ -428,19 +519,24 @@ JobPrintCommand (cmdp, jobp) char *cmd = (char *) cmdp; Job *job = (Job *) jobp; - noSpecials = (noExecute && ! (job->node->type & OP_MAKE)); + noSpecials = (noExecute && !(job->node->type & OP_MAKE)); - if (strcmp (cmd, "...") == 0) { + if (strcmp(cmd, "...") == 0) { job->node->type |= OP_SAVE_CMDS; if ((job->flags & JOB_IGNDOTS) == 0) { - job->tailCmds = Lst_Succ (Lst_Member (job->node->commands, - (ClientData)cmd)); - return (1); + job->tailCmds = Lst_Succ(Lst_Member(job->node->commands, + (ClientData)cmd)); + return(1); } - return (0); + return(0); } -#define DBPRINTF(fmt, arg) if (DEBUG(JOB)) printf (fmt, arg); fprintf (job->cmdFILE, fmt, arg) +#define DBPRINTF(fmt, arg) if (DEBUG(JOB)) { \ + (void) fprintf(stdout, fmt, arg); \ + (void) fflush(stdout); \ + } \ + (void) fprintf(job->cmdFILE, fmt, arg); \ + (void) fflush(job->cmdFILE); numCommands += 1; @@ -448,9 +544,9 @@ JobPrintCommand (cmdp, jobp) * For debugging, we replace each command with the result of expanding * the variables in the command. */ - cmdNode = Lst_Member (job->node->commands, (ClientData)cmd); - cmdStart = cmd = Var_Subst (NULL, cmd, job->node, FALSE); - Lst_Replace (cmdNode, (ClientData)cmdStart); + cmdNode = Lst_Member(job->node->commands, (ClientData)cmd); + cmdStart = cmd = Var_Subst(NULL, cmd, job->node, FALSE); + Lst_Replace(cmdNode, (ClientData)cmdStart); cmdTemplate = "%s\n"; @@ -470,16 +566,16 @@ JobPrintCommand (cmdp, jobp) cmd++; if (shutUp) { - if (! (job->flags & JOB_SILENT) && !noSpecials && + if (!(job->flags & JOB_SILENT) && !noSpecials && commandShell->hasEchoCtl) { - DBPRINTF ("%s\n", commandShell->echoOff); + DBPRINTF("%s\n", commandShell->echoOff); } else { shutUp = FALSE; } } if (errOff) { - if ( ! (job->flags & JOB_IGNERR) && !noSpecials) { + if ( !(job->flags & JOB_IGNERR) && !noSpecials) { if (commandShell->hasErrCtl) { /* * we don't want the error-control commands showing @@ -489,16 +585,16 @@ JobPrintCommand (cmdp, jobp) * string too, but why make it any more complex than * it already is? */ - if (! (job->flags & JOB_SILENT) && !shutUp && + if (!(job->flags & JOB_SILENT) && !shutUp && commandShell->hasEchoCtl) { - DBPRINTF ("%s\n", commandShell->echoOff); - DBPRINTF ("%s\n", commandShell->ignErr); - DBPRINTF ("%s\n", commandShell->echoOn); + DBPRINTF("%s\n", commandShell->echoOff); + DBPRINTF("%s\n", commandShell->ignErr); + DBPRINTF("%s\n", commandShell->echoOn); } else { - DBPRINTF ("%s\n", commandShell->ignErr); + DBPRINTF("%s\n", commandShell->ignErr); } } else if (commandShell->ignErr && - (*commandShell->ignErr != '\0')) + (*commandShell->ignErr != '\0')) { /* * The shell has no error control, so we need to be @@ -509,15 +605,15 @@ JobPrintCommand (cmdp, jobp) * to ignore errors. Set cmdTemplate to use the weirdness * instead of the simple "%s\n" template. */ - if (! (job->flags & JOB_SILENT) && !shutUp && + if (!(job->flags & JOB_SILENT) && !shutUp && commandShell->hasEchoCtl) { - DBPRINTF ("%s\n", commandShell->echoOff); - DBPRINTF (commandShell->errCheck, cmd); + DBPRINTF("%s\n", commandShell->echoOff); + DBPRINTF(commandShell->errCheck, cmd); shutUp = TRUE; } cmdTemplate = commandShell->ignErr; /* - * The error ignoration (hee hee) is already taken care + * The error ignoration(hee hee) is already taken care * of by the ignErr template, so pretend error checking * is still on. */ @@ -530,7 +626,7 @@ JobPrintCommand (cmdp, jobp) } } - DBPRINTF (cmdTemplate, cmd); + DBPRINTF(cmdTemplate, cmd); if (errOff) { /* @@ -539,15 +635,15 @@ JobPrintCommand (cmdp, jobp) * for the whole command... */ if (!shutUp && !(job->flags & JOB_SILENT) && commandShell->hasEchoCtl){ - DBPRINTF ("%s\n", commandShell->echoOff); + DBPRINTF("%s\n", commandShell->echoOff); shutUp = TRUE; } - DBPRINTF ("%s\n", commandShell->errCheck); + DBPRINTF("%s\n", commandShell->errCheck); } if (shutUp) { - DBPRINTF ("%s\n", commandShell->echoOn); + DBPRINTF("%s\n", commandShell->echoOn); } - return (0); + return 0; } /*- @@ -565,13 +661,48 @@ JobPrintCommand (cmdp, jobp) *----------------------------------------------------------------------- */ static int -JobSaveCommand (cmd, gn) +JobSaveCommand(cmd, gn) ClientData cmd; ClientData gn; { - cmd = (ClientData) Var_Subst (NULL, (char *) cmd, (GNode *) gn, FALSE); - (void)Lst_AtEnd (postCommands->commands, cmd); - return (0); + cmd = (ClientData) Var_Subst(NULL, (char *) cmd, (GNode *) gn, FALSE); + (void) Lst_AtEnd(postCommands->commands, cmd); + return(0); +} + + +/*- + *----------------------------------------------------------------------- + * JobClose -- + * Called to close both input and output pipes when a job is finished. + * + * Results: + * Nada + * + * Side Effects: + * The file descriptors associated with the job are closed. + * + *----------------------------------------------------------------------- + */ +static void +JobClose(job) + Job *job; +{ + if (usePipes) { +#ifdef RMT_WILL_WATCH + Rmt_Ignore(job->inPipe); +#else + FD_CLR(job->inPipe, &outputs); +#endif + if (job->outPipe != job->inPipe) { + (void) close(job->outPipe); + } + JobDoOutput(job, TRUE); + (void) close(job->inPipe); + } else { + (void) close(job->outFd); + JobDoOutput(job, TRUE); + } } /*- @@ -591,23 +722,23 @@ JobSaveCommand (cmd, gn) * Some nodes may be put on the toBeMade queue. * Final commands for the job are placed on postCommands. * - * If we got an error and are aborting (aborting == ABORT_ERROR) and + * If we got an error and are aborting(aborting == ABORT_ERROR) and * the job list is now empty, we are done for the day. - * If we recognized an error (errors !=0), we set the aborting flag + * If we recognized an error(errors !=0), we set the aborting flag * to ABORT_ERROR so no more jobs will be started. *----------------------------------------------------------------------- */ /*ARGSUSED*/ static void -JobFinish (job, status) - Job *job; /* job to finish */ - union wait status; /* sub-why job went away */ +JobFinish(job, status) + Job *job; /* job to finish */ + int *status; /* sub-why job went away */ { - Boolean done; + Boolean done; - if ((WIFEXITED(status) && - (((status.w_retcode != 0) && !(job->flags & JOB_IGNERR)))) || - (WIFSIGNALED(status) && (status.w_termsig != SIGCONT))) + if ((WIFEXITED(*status) && + (((WEXITSTATUS(*status) != 0) && !(job->flags & JOB_IGNERR)))) || + (WIFSIGNALED(*status) && (WTERMSIG(*status) != SIGCONT))) { /* * If it exited non-zero and either we're doing things our @@ -617,36 +748,38 @@ JobFinish (job, status) * cases, finish out the job's output before printing the exit * status... */ - if (usePipes) { -#ifdef RMT_WILL_WATCH - Rmt_Ignore(job->inPipe); -#else - FD_CLR(job->inPipe, &outputs); -#endif /* RMT_WILL_WATCH */ - if (job->outPipe != job->inPipe) { - (void)close (job->outPipe); - } - JobDoOutput (job, TRUE); - (void)close (job->inPipe); - } else { - (void)close (job->outFd); - JobDoOutput (job, TRUE); - } - +#ifdef REMOTE + KILL(job->pid, SIGCONT); +#endif + JobClose(job); if (job->cmdFILE != NULL && job->cmdFILE != stdout) { - fclose(job->cmdFILE); + (void) fclose(job->cmdFILE); } done = TRUE; - } else if (WIFEXITED(status) && status.w_retcode != 0) { +#ifdef REMOTE + if (job->flags & JOB_REMOTE) + Rmt_Done(job->rmtID, job->node); +#endif + } else if (WIFEXITED(*status)) { /* * Deal with ignored errors in -B mode. We need to print a message * telling of the ignored error as well as setting status.w_status * to 0 so the next command gets run. To do this, we set done to be - * TRUE if in -B mode and the job exited non-zero. Note we don't + * TRUE if in -B mode and the job exited non-zero. + */ + done = WEXITSTATUS(*status) != 0; + /* + * Old comment said: "Note we don't * want to close down any of the streams until we know we're at the - * end. + * end." + * But we do. Otherwise when are we going to print the rest of the + * stuff? */ - done = TRUE; + JobClose(job); +#ifdef REMOTE + if (job->flags & JOB_REMOTE) + Rmt_Done(job->rmtID, job->node); +#endif /* REMOTE */ } else { /* * No need to close things down or anything. @@ -655,93 +788,127 @@ JobFinish (job, status) } if (done || - WIFSTOPPED(status) || - (WIFSIGNALED(status) && (status.w_termsig == SIGCONT)) || + WIFSTOPPED(*status) || + (WIFSIGNALED(*status) && (WTERMSIG(*status) == SIGCONT)) || DEBUG(JOB)) { FILE *out; - if (!usePipes && (job->flags & JOB_IGNERR)) { + if (compatMake && !usePipes && (job->flags & JOB_IGNERR)) { /* * If output is going to a file and this job is ignoring * errors, arrange to have the exit status sent to the * output file as well. */ - out = fdopen (job->outFd, "w"); + out = fdopen(job->outFd, "w"); } else { out = stdout; } - if (WIFEXITED(status)) { - if (status.w_retcode != 0) { + if (WIFEXITED(*status)) { + if (DEBUG(JOB)) { + (void) fprintf(stdout, "Process %d exited.\n", job->pid); + (void) fflush(stdout); + } + if (WEXITSTATUS(*status) != 0) { if (usePipes && job->node != lastNode) { - fprintf (out, targFmt, job->node->name); + MESSAGE(out, job->node); lastNode = job->node; } - fprintf (out, "*** Error code %d%s\n", status.w_retcode, - (job->flags & JOB_IGNERR) ? " (ignored)" : ""); + (void) fprintf(out, "*** Error code %d%s\n", + WEXITSTATUS(*status), + (job->flags & JOB_IGNERR) ? "(ignored)" : ""); if (job->flags & JOB_IGNERR) { - status.w_status = 0; + *status = 0; } } else if (DEBUG(JOB)) { if (usePipes && job->node != lastNode) { - fprintf (out, targFmt, job->node->name); + MESSAGE(out, job->node); lastNode = job->node; } - fprintf (out, "*** Completed successfully\n"); + (void) fprintf(out, "*** Completed successfully\n"); + } + } else if (WIFSTOPPED(*status)) { + if (DEBUG(JOB)) { + (void) fprintf(stdout, "Process %d stopped.\n", job->pid); + (void) fflush(stdout); } - } else if (WIFSTOPPED(status)) { if (usePipes && job->node != lastNode) { - fprintf (out, targFmt, job->node->name); + MESSAGE(out, job->node); lastNode = job->node; } - if (! (job->flags & JOB_REMIGRATE)) { - fprintf (out, "*** Stopped -- signal %d\n", status.w_stopsig); + if (!(job->flags & JOB_REMIGRATE)) { + fprintf(out, "*** Stopped -- signal %d\n", WSTOPSIG(*status)); } job->flags |= JOB_RESUME; (void)Lst_AtEnd(stoppedJobs, (ClientData)job); - fflush(out); +#ifdef REMOTE + if (job->flags & JOB_REMIGRATE) + JobRestart(job); +#endif + (void) fflush(out); return; - } else if (status.w_termsig == SIGCONT) { + } else if (WTERMSIG(*status) == SIGCONT) { /* * If the beastie has continued, shift the Job from the stopped - * list to the running one (or re-stop it if concurrency is + * list to the running one(or re-stop it if concurrency is * exceeded) and go and get another child. */ if (job->flags & (JOB_RESUME|JOB_REMIGRATE|JOB_RESTART)) { if (usePipes && job->node != lastNode) { - fprintf (out, targFmt, job->node->name); + MESSAGE(out, job->node); lastNode = job->node; } - fprintf (out, "*** Continued\n"); + (void) fprintf(out, "*** Continued\n"); } - if (! (job->flags & JOB_CONTINUING)) { - JobRestart(job); - } else { - Lst_AtEnd(jobs, (ClientData)job); - nJobs += 1; - if (! (job->flags & JOB_REMOTE)) { - nLocal += 1; - } - if (nJobs == maxJobs) { - jobFull = TRUE; - if (DEBUG(JOB)) { - printf("Job queue is full.\n"); - } + if (!(job->flags & JOB_CONTINUING)) { + if (DEBUG(JOB)) { + (void) fprintf(stdout, + "Warning: process %d was not continuing.\n", + job->pid); + (void) fflush(stdout); } +#ifdef notdef + /* + * We don't really want to restart a job from scratch just + * because it continued, especially not without killing the + * continuing process! That's why this is ifdef'ed out. + * FD - 9/17/90 + */ + JobRestart(job); +#endif } - fflush(out); - return; + job->flags &= ~JOB_CONTINUING; + Lst_AtEnd(jobs, (ClientData)job); + nJobs += 1; + if (!(job->flags & JOB_REMOTE)) { + if (DEBUG(JOB)) { + (void) fprintf(stdout, + "Process %d is continuing locally.\n", + job->pid); + (void) fflush(stdout); + } + nLocal += 1; + } + if (nJobs == maxJobs) { + jobFull = TRUE; + if (DEBUG(JOB)) { + (void) fprintf(stdout, "Job queue is full.\n"); + (void) fflush(stdout); + } + } + (void) fflush(out); + return; } else { if (usePipes && job->node != lastNode) { - fprintf (out, targFmt, job->node->name); + MESSAGE(out, job->node); lastNode = job->node; } - fprintf (out, "*** Signal %d\n", status.w_termsig); + (void) fprintf(out, "*** Signal %d\n", WTERMSIG(*status)); } - fflush (out); + (void) fflush(out); } /* @@ -749,30 +916,26 @@ JobFinish (job, status) * try and restart the job on the next command. If JobStart says it's * ok, it's ok. If there's an error, this puppy is done. */ - if ((status.w_status == 0) && - !Lst_IsAtEnd (job->node->commands)) - { - switch (JobStart (job->node, - job->flags & JOB_IGNDOTS, - job)) - { - case JOB_RUNNING: - done = FALSE; - break; - case JOB_ERROR: - done = TRUE; - status.w_retcode = 1; - break; - case JOB_FINISHED: - /* - * If we got back a JOB_FINISHED code, JobStart has already - * called Make_Update and freed the job descriptor. We set - * done to false here to avoid fake cycles and double frees. - * JobStart needs to do the update so we can proceed up the - * graph when given the -n flag.. - */ - done = FALSE; - break; + if (compatMake && (WIFEXITED(*status) && + !Lst_IsAtEnd(job->node->commands))) { + switch (JobStart(job->node, job->flags & JOB_IGNDOTS, job)) { + case JOB_RUNNING: + done = FALSE; + break; + case JOB_ERROR: + done = TRUE; + W_SETEXITSTATUS(status, 1); + break; + case JOB_FINISHED: + /* + * If we got back a JOB_FINISHED code, JobStart has already + * called Make_Update and freed the job descriptor. We set + * done to false here to avoid fake cycles and double frees. + * JobStart needs to do the update so we can proceed up the + * graph when given the -n flag.. + */ + done = FALSE; + break; } } else { done = TRUE; @@ -782,7 +945,7 @@ JobFinish (job, status) if (done && (aborting != ABORT_ERROR) && (aborting != ABORT_INTERRUPT) && - (status.w_status == 0)) + (*status == 0)) { /* * As long as we aren't aborting and the job didn't return a non-zero @@ -791,21 +954,19 @@ JobFinish (job, status) * on the .END target. */ if (job->tailCmds != NILLNODE) { - Lst_ForEachFrom (job->node->commands, job->tailCmds, + Lst_ForEachFrom(job->node->commands, job->tailCmds, JobSaveCommand, - (ClientData)job->node); + (ClientData)job->node); } job->node->made = MADE; - Make_Update (job->node); + Make_Update(job->node); free((Address)job); - } else if (status.w_status) { + } else if (*status == 0) { errors += 1; free((Address)job); } - while (!errors && !jobFull && !Lst_IsEmpty(stoppedJobs)) { - JobRestart((Job *)Lst_DeQueue(stoppedJobs)); - } + JobRestartJobs(); /* * Set aborting if any error. @@ -823,8 +984,8 @@ JobFinish (job, status) /* * If we are aborting and the job table is now empty, we finish. */ - (void) unlink (tfile); - Finish (errors); + (void) eunlink(tfile); + Finish(errors); } } @@ -843,7 +1004,7 @@ JobFinish (job, status) *----------------------------------------------------------------------- */ void -Job_Touch (gn, silent) +Job_Touch(gn, silent) GNode *gn; /* the node of the file to touch */ Boolean silent; /* TRUE if should not print messages */ { @@ -859,7 +1020,8 @@ Job_Touch (gn, silent) } if (!silent) { - printf ("touch %s\n", gn->name); + (void) fprintf(stdout, "touch %s\n", gn->name); + (void) fflush(stdout); } if (noExecute) { @@ -867,16 +1029,16 @@ Job_Touch (gn, silent) } if (gn->type & OP_ARCHV) { - Arch_Touch (gn); + Arch_Touch(gn); } else if (gn->type & OP_LIB) { - Arch_TouchLib (gn); + Arch_TouchLib(gn); } else { char *file = gn->path ? gn->path : gn->name; times[0].tv_sec = times[1].tv_sec = now; times[0].tv_usec = times[1].tv_usec = 0; if (utimes(file, times) < 0){ - streamID = open (file, O_RDWR | O_CREAT, 0666); + streamID = open(file, O_RDWR | O_CREAT, 0666); if (streamID >= 0) { char c; @@ -886,13 +1048,16 @@ Job_Touch (gn, silent) * modification time, then close the file. */ if (read(streamID, &c, 1) == 1) { - lseek(streamID, (off_t) 0, SEEK_SET); - write(streamID, &c, 1); + (void) lseek(streamID, 0L, L_SET); + (void) write(streamID, &c, 1); } - (void)close (streamID); - } else - printf("*** couldn't touch %s: %s", file, strerror(errno)); + (void) close(streamID); + } else { + (void) fprintf(stdout, "*** couldn't touch %s: %s", + file, strerror(errno)); + (void) fflush(stdout); + } } } } @@ -911,13 +1076,13 @@ Job_Touch (gn, silent) *----------------------------------------------------------------------- */ Boolean -Job_CheckCommands (gn, abortProc) +Job_CheckCommands(gn, abortProc) GNode *gn; /* The target whose commands need * verifying */ - void (*abortProc) __P((char *, ...)); + void (*abortProc) __P((char *, ...)); /* Function to abort with message */ { - if (OP_NOP(gn->type) && Lst_IsEmpty (gn->commands) && + if (OP_NOP(gn->type) && Lst_IsEmpty(gn->commands) && (gn->type & OP_LIB) == 0) { /* * No commands. Look for .DEFAULT rule from which we might infer @@ -935,10 +1100,10 @@ Job_CheckCommands (gn, abortProc) * .DEFAULT itself. */ Make_HandleUse(DEFAULT, gn); - Var_Set (IMPSRC, Var_Value (TARGET, gn, &p1), gn); + Var_Set(IMPSRC, Var_Value(TARGET, gn, &p1), gn); if (p1) free(p1); - } else if (Dir_MTime (gn) == 0) { + } else if (Dir_MTime(gn) == 0) { /* * The node wasn't the target of an operator we have no .DEFAULT * rule to go on and the target doesn't already exist. There's @@ -946,21 +1111,22 @@ Job_CheckCommands (gn, abortProc) * given, we stop in our tracks, otherwise we just don't update * this node's parents so they never get examined. */ + static const char msg[] = "make: don't know how to make"; + if (gn->type & OP_OPTIONAL) { - printf ("make: don't know how to make %s (ignored)\n", - gn->name); + (void) fprintf(stdout, "%s %s(ignored)\n", msg, gn->name); + (void) fflush(stdout); } else if (keepgoing) { - printf ("make: don't know how to make %s (continuing)\n", - gn->name); - return (FALSE); + (void) fprintf(stdout, "%s %s(continuing)\n", msg, gn->name); + (void) fflush(stdout); + return FALSE; } else { - (*abortProc) ("make: don't know how to make %s. Stop", - gn->name); - return(FALSE); + (*abortProc)("%s %s. Stop", msg, gn->name); + return FALSE; } } } - return (TRUE); + return TRUE; } #ifdef RMT_WILL_WATCH /*- @@ -979,7 +1145,7 @@ Job_CheckCommands (gn, abortProc) /*ARGSUSED*/ static void JobLocalInput(stream, job) - int stream; /* Stream that's ready (ignored) */ + int stream; /* Stream that's ready(ignored) */ Job *job; /* Job to which the stream belongs */ { JobDoOutput(job, FALSE); @@ -1011,25 +1177,25 @@ JobExec(job, argv) if (DEBUG(JOB)) { int i; - printf("Running %s %sly\n", job->node->name, - job->flags&JOB_REMOTE?"remote":"local"); - printf("\tCommand: "); - for (i = 0; argv[i] != (char *)NULL; i++) { - printf("%s ", argv[i]); + (void) fprintf(stdout, "Running %s %sly\n", job->node->name, + job->flags&JOB_REMOTE?"remote":"local"); + (void) fprintf(stdout, "\tCommand: "); + for (i = 0; argv[i] != NULL; i++) { + (void) fprintf(stdout, "%s ", argv[i]); } - printf("\n"); + (void) fprintf(stdout, "\n"); + (void) fflush(stdout); } /* * Some jobs produce no output and it's disconcerting to have - * no feedback of their running (since they produce no output, the + * no feedback of their running(since they produce no output, the * banner with their name in it never appears). This is an attempt to * provide that feedback, even if nothing follows it. */ if ((lastNode != job->node) && (job->flags & JOB_FIRST) && - !(job->flags & JOB_SILENT)) - { - printf(targFmt, job->node->name); + !(job->flags & JOB_SILENT)) { + MESSAGE(stdout, job->node); lastNode = job->node; } @@ -1039,41 +1205,45 @@ JobExec(job, argv) } #endif /* RMT_NO_EXEC */ - if ((cpid = vfork()) == -1) { - Punt ("Cannot fork"); + if ((cpid = vfork()) == -1) { + Punt("Cannot fork"); } else if (cpid == 0) { /* * Must duplicate the input stream down to the child's input and - * reset it to the beginning (again). Since the stream was marked + * reset it to the beginning(again). Since the stream was marked * close-on-exec, we must clear that bit in the new input. */ - (void) dup2(fileno(job->cmdFILE), 0); - fcntl(0, F_SETFD, 0); - lseek(0, (off_t) 0, SEEK_SET); + if (dup2(FILENO(job->cmdFILE), 0) == -1) + Punt("Cannot dup2: %s", strerror(errno)); + (void) fcntl(0, F_SETFD, 0); + (void) lseek(0, 0, L_SET); if (usePipes) { /* * Set up the child's output to be routed through the pipe * we've created for it. */ - (void) dup2 (job->outPipe, 1); + if (dup2(job->outPipe, 1) == -1) + Punt("Cannot dup2: %s", strerror(errno)); } else { /* * We're capturing output in a file, so we duplicate the * descriptor to the temporary file into the standard * output. */ - (void) dup2 (job->outFd, 1); + if (dup2(job->outFd, 1) == -1) + Punt("Cannot dup2: %s", strerror(errno)); } /* * The output channels are marked close on exec. This bit was - * duplicated by the dup2 (on some systems), so we have to clear + * duplicated by the dup2(on some systems), so we have to clear * it before routing the shell's error output to the same place as * its standard output. */ - fcntl(1, F_SETFD, 0); - (void) dup2 (1, 2); + (void) fcntl(1, F_SETFD, 0); + if (dup2(1, 2) == -1) + Punt("Cannot dup2: %s", strerror(errno)); #ifdef USE_PGRP /* @@ -1081,15 +1251,27 @@ JobExec(job, argv) * we can kill it and all its descendants in one fell swoop, * by killing its process family, but not commit suicide. */ - - (void) setpgrp(0, getpid()); -#endif USE_PGRP +# if defined(SYSV) + (void) setsid(); +# else + (void) setpgid(0, getpid()); +# endif +#endif /* USE_PGRP */ - (void) execv (shellPath, argv); - (void) write (2, "Could not execute shell\n", - sizeof ("Could not execute shell")); - _exit (1); +#ifdef REMOTE + if (job->flags & JOB_REMOTE) { + Rmt_Exec(shellPath, argv, FALSE); + } else +#endif /* REMOTE */ + (void) execv(shellPath, argv); + + (void) write(2, "Could not execute shell\n", + sizeof("Could not execute shell")); + _exit(1); } else { +#ifdef REMOTE + long omask = sigblock(sigmask(SIGCHLD)); +#endif job->pid = cpid; if (usePipes && (job->flags & JOB_FIRST) ) { @@ -1108,17 +1290,24 @@ JobExec(job, argv) } if (job->flags & JOB_REMOTE) { +#ifndef REMOTE job->rmtID = 0; +#else + job->rmtID = Rmt_LastID(job->pid); +#endif /* REMOTE */ } else { nLocal += 1; /* - * XXX: Used to not happen if CUSTOMS. Why? + * XXX: Used to not happen if REMOTE. Why? */ - if (job->cmdFILE != stdout) { - fclose(job->cmdFILE); + if (job->cmdFILE != NULL && job->cmdFILE != stdout) { + (void) fclose(job->cmdFILE); job->cmdFILE = NULL; } } +#ifdef REMOTE + (void) sigsetmask(omask); +#endif } #ifdef RMT_NO_EXEC @@ -1128,7 +1317,7 @@ jobExecFinish: * Now the job is actually running, add it to the table. */ nJobs += 1; - (void)Lst_AtEnd (jobs, (ClientData)job); + (void) Lst_AtEnd(jobs, (ClientData)job); if (nJobs == maxJobs) { jobFull = TRUE; } @@ -1186,7 +1375,7 @@ JobMakeArgv(job, argv) argc++; } } - argv[argc] = (char *)NULL; + argv[argc] = NULL; } /*- @@ -1206,44 +1395,91 @@ static void JobRestart(job) Job *job; /* Job to restart */ { +#ifdef REMOTE + int host; +#endif + if (job->flags & JOB_REMIGRATE) { - if (DEBUG(JOB)) { - printf("Remigrating %x\n", job->pid); + if ( +#ifdef REMOTE + verboseRemigrates || +#endif + DEBUG(JOB)) { + (void) fprintf(stdout, "*** remigrating %x(%s)\n", + job->pid, job->node->name); + (void) fflush(stdout); } - if (nLocal != maxLocal) { + +#ifdef REMOTE + if (!Rmt_ReExport(job->pid, job->node, &host)) { + if (verboseRemigrates || DEBUG(JOB)) { + (void) fprintf(stdout, "*** couldn't migrate...\n"); + (void) fflush(stdout); + } +#endif + if (nLocal != maxLocal) { /* * Job cannot be remigrated, but there's room on the local * machine, so resume the job and note that another * local job has started. */ - if (DEBUG(JOB)) { - printf("resuming on local machine\n"); - } + if ( +#ifdef REMOTE + verboseRemigrates || +#endif + DEBUG(JOB)) { + (void) fprintf(stdout, "*** resuming on local machine\n"); + (void) fflush(stdout); + } KILL(job->pid, SIGCONT); nLocal +=1; +#ifdef REMOTE + job->flags &= ~(JOB_REMIGRATE|JOB_RESUME|JOB_REMOTE); + job->flags |= JOB_CONTINUING; +#else job->flags &= ~(JOB_REMIGRATE|JOB_RESUME); +#endif } else { /* * Job cannot be restarted. Mark the table as full and * place the job back on the list of stopped jobs. */ - if (DEBUG(JOB)) { - printf("holding\n"); - } + if ( +#ifdef REMOTE + verboseRemigrates || +#endif + DEBUG(JOB)) { + (void) fprintf(stdout, "*** holding\n"); + (void) fflush(stdout); + } (void)Lst_AtFront(stoppedJobs, (ClientData)job); jobFull = TRUE; if (DEBUG(JOB)) { - printf("Job queue is full.\n"); + (void) fprintf(stdout, "Job queue is full.\n"); + (void) fflush(stdout); } return; + } +#ifdef REMOTE + } else { + /* + * Clear out the remigrate and resume flags. Set the continuing + * flag so we know later on that the process isn't exiting just + * because of a signal. + */ + job->flags &= ~(JOB_REMIGRATE|JOB_RESUME); + job->flags |= JOB_CONTINUING; + job->rmtID = host; } +#endif (void)Lst_AtEnd(jobs, (ClientData)job); nJobs += 1; if (nJobs == maxJobs) { jobFull = TRUE; if (DEBUG(JOB)) { - printf("Job queue is full.\n"); + (void) fprintf(stdout, "Job queue is full.\n"); + (void) fflush(stdout); } } } else if (job->flags & JOB_RESTART) { @@ -1258,33 +1494,60 @@ JobRestart(job) char *argv[4]; JobMakeArgv(job, argv); - + if (DEBUG(JOB)) { - printf("Restarting %s...", job->node->name); + (void) fprintf(stdout, "Restarting %s...", job->node->name); + (void) fflush(stdout); } - if (((nLocal >= maxLocal) && ! (job->flags & JOB_SPECIAL))) { +#ifdef REMOTE + if ((job->node->type&OP_NOEXPORT) || + (nLocal < maxLocal && runLocalFirst) +# ifdef RMT_NO_EXEC + || !Rmt_Export(shellPath, argv, job) +# else + || !Rmt_Begin(shellPath, argv, job->node) +# endif +#endif + { + if (((nLocal >= maxLocal) && !(job->flags & JOB_SPECIAL))) { /* * Can't be exported and not allowed to run locally -- put it * back on the hold queue and mark the table full */ if (DEBUG(JOB)) { - printf("holding\n"); + (void) fprintf(stdout, "holding\n"); + (void) fflush(stdout); } (void)Lst_AtFront(stoppedJobs, (ClientData)job); jobFull = TRUE; if (DEBUG(JOB)) { - printf("Job queue is full.\n"); + (void) fprintf(stdout, "Job queue is full.\n"); + (void) fflush(stdout); } return; - } else { + } else { /* * Job may be run locally. */ if (DEBUG(JOB)) { - printf("running locally\n"); + (void) fprintf(stdout, "running locally\n"); + (void) fflush(stdout); } job->flags &= ~JOB_REMOTE; + } + } +#ifdef REMOTE + else { + /* + * Can be exported. Hooray! + */ + if (DEBUG(JOB)) { + (void) fprintf(stdout, "exporting\n"); + (void) fflush(stdout); + } + job->flags |= JOB_REMOTE; } +#endif JobExec(job, argv); } else { /* @@ -1292,24 +1555,31 @@ JobRestart(job) * we don't know... */ if (DEBUG(JOB)) { - printf("Resuming %s...", job->node->name); + (void) fprintf(stdout, "Resuming %s...", job->node->name); + (void) fflush(stdout); } if (((job->flags & JOB_REMOTE) || - (nLocal < maxLocal) || - (((job->flags & JOB_SPECIAL)) && - (maxLocal == 0))) && - (nJobs != maxJobs)) + (nLocal < maxLocal) || +#ifdef REMOTE + (((job->flags & JOB_SPECIAL) && + (job->node->type & OP_NOEXPORT)) && + (maxLocal == 0))) && +#else + ((job->flags & JOB_SPECIAL) && + (maxLocal == 0))) && +#endif + (nJobs != maxJobs)) { /* * If the job is remote, it's ok to resume it as long as the * maximum concurrency won't be exceeded. If it's local and - * we haven't reached the local concurrency limit already (or the + * we haven't reached the local concurrency limit already(or the * job must be run locally and maxLocal is 0), it's also ok to * resume it. */ Boolean error; extern int errno; - union wait status; + int status; #ifdef RMT_WANTS_SIGNALS if (job->flags & JOB_REMOTE) { @@ -1324,19 +1594,20 @@ JobRestart(job) * actually put the thing in the job table. */ job->flags |= JOB_CONTINUING; - status.w_termsig = SIGCONT; - JobFinish(job, status); + W_SETTERMSIG(&status, SIGCONT); + JobFinish(job, &status); job->flags &= ~(JOB_RESUME|JOB_CONTINUING); if (DEBUG(JOB)) { - printf("done\n"); + (void) fprintf(stdout, "done\n"); + (void) fflush(stdout); } } else { Error("couldn't resume %s: %s", job->node->name, strerror(errno)); - status.w_status = 0; - status.w_retcode = 1; - JobFinish(job, status); + status = 0; + W_SETEXITSTATUS(&status, 1); + JobFinish(job, &status); } } else { /* @@ -1344,12 +1615,14 @@ JobRestart(job) * place the job back on the list of stopped jobs. */ if (DEBUG(JOB)) { - printf("table full\n"); + (void) fprintf(stdout, "table full\n"); + (void) fflush(stdout); } - (void)Lst_AtFront(stoppedJobs, (ClientData)job); + (void) Lst_AtFront(stoppedJobs, (ClientData)job); jobFull = TRUE; if (DEBUG(JOB)) { - printf("Job queue is full.\n"); + (void) fprintf(stdout, "Job queue is full.\n"); + (void) fflush(stdout); } } } @@ -1372,7 +1645,7 @@ JobRestart(job) *----------------------------------------------------------------------- */ static int -JobStart (gn, flags, previous) +JobStart(gn, flags, previous) GNode *gn; /* target to create */ int flags; /* flags for the job to override normal ones. * e.g. JOB_SPECIAL or JOB_IGNDOTS */ @@ -1386,12 +1659,12 @@ JobStart (gn, flags, previous) Boolean local; /* Set true if the job was run locally */ Boolean noExec; /* Set true if we decide not to run the job */ - if (previous != (Job *)NULL) { - previous->flags &= ~ (JOB_FIRST|JOB_IGNERR|JOB_SILENT|JOB_REMOTE); + if (previous != NULL) { + previous->flags &= ~(JOB_FIRST|JOB_IGNERR|JOB_SILENT|JOB_REMOTE); job = previous; } else { - job = (Job *) emalloc (sizeof (Job)); - if (job == (Job *)NULL) { + job = (Job *) emalloc(sizeof(Job)); + if (job == NULL) { Punt("JobStart out of memory"); } flags |= JOB_FIRST; @@ -1406,10 +1679,10 @@ JobStart (gn, flags, previous) * are also added to the field. */ job->flags = 0; - if (Targ_Ignore (gn)) { + if (Targ_Ignore(gn)) { job->flags |= JOB_IGNERR; } - if (Targ_Silent (gn)) { + if (Targ_Silent(gn)) { job->flags |= JOB_SILENT; } job->flags |= flags; @@ -1418,14 +1691,14 @@ JobStart (gn, flags, previous) * Check the commands now so any attributes from .DEFAULT have a chance * to migrate to the node */ - if (job->flags & JOB_FIRST) { + if (!compatMake && job->flags & JOB_FIRST) { cmdsOK = Job_CheckCommands(gn, Error); } else { cmdsOK = TRUE; } /* - * If the -n flag wasn't given, we open up OUR (not the child's) + * If the -n flag wasn't given, we open up OUR(not the child's) * temporary file to stuff commands in it. The thing is rd/wr so we don't * need to reopen it to feed it to the shell. If the -n flag *was* given, * we just set the file to be stdout. Cute, huh? @@ -1439,11 +1712,11 @@ JobStart (gn, flags, previous) DieHorribly(); } - job->cmdFILE = fopen (tfile, "w+"); - if (job->cmdFILE == (FILE *) NULL) { - Punt ("Could not open %s", tfile); + job->cmdFILE = fopen(tfile, "w+"); + if (job->cmdFILE == NULL) { + Punt("Could not open %s", tfile); } - fcntl(fileno(job->cmdFILE), F_SETFD, 1); + (void) fcntl(FILENO(job->cmdFILE), F_SETFD, 1); /* * Send the commands to the command file, flush all its buffers then * rewind and remove the thing. @@ -1466,13 +1739,14 @@ JobStart (gn, flags, previous) if ((job->flags&JOB_FIRST) && (Lst_Open(gn->commands) != SUCCESS)){ cmdsOK = FALSE; } else { - LstNode ln = Lst_Next (gn->commands); + LstNode ln = Lst_Next(gn->commands); if ((ln == NILLNODE) || - JobPrintCommand ((char *)Lst_Datum (ln), job)) + JobPrintCommand((ClientData) Lst_Datum(ln), + (ClientData) job)) { noExec = TRUE; - Lst_Close (gn->commands); + Lst_Close(gn->commands); } if (noExec && !(job->flags & JOB_FIRST)) { /* @@ -1486,21 +1760,7 @@ JobStart (gn, flags, previous) * Job_CatchChildren b/c it wasn't clear if there were * more commands to execute or not... */ - if (usePipes) { -#ifdef RMT_WILL_WATCH - Rmt_Ignore(job->inPipe); -#else - FD_CLR(job->inPipe, &outputs); -#endif - if (job->outPipe != job->inPipe) { - (void)close (job->outPipe); - } - JobDoOutput (job, TRUE); - (void)close (job->inPipe); - } else { - (void)close (job->outFd); - JobDoOutput (job, TRUE); - } + JobClose(job); } } } else { @@ -1508,7 +1768,7 @@ JobStart (gn, flags, previous) * We can do all the commands at once. hooray for sanity */ numCommands = 0; - Lst_ForEach (gn->commands, JobPrintCommand, (ClientData)job); + Lst_ForEach(gn->commands, JobPrintCommand, (ClientData)job); /* * If we didn't print out any commands to the shell script, @@ -1524,7 +1784,7 @@ JobStart (gn, flags, previous) * in one fell swoop. This will still set up job->tailCmds correctly. */ if (lastNode != gn) { - printf (targFmt, gn->name); + MESSAGE(stdout, gn); lastNode = gn; } job->cmdFILE = stdout; @@ -1548,7 +1808,7 @@ JobStart (gn, flags, previous) * up the graph. */ job->cmdFILE = stdout; - Job_Touch (gn, job->flags&JOB_SILENT); + Job_Touch(gn, job->flags&JOB_SILENT); noExec = TRUE; } @@ -1560,10 +1820,11 @@ JobStart (gn, flags, previous) * Unlink and close the command file if we opened one */ if (job->cmdFILE != stdout) { - (void) unlink (tfile); - fclose(job->cmdFILE); + (void) eunlink(tfile); + if (job->cmdFILE != NULL) + (void) fclose(job->cmdFILE); } else { - fflush (stdout); + (void) fflush(stdout); } /* @@ -1575,7 +1836,7 @@ JobStart (gn, flags, previous) if (job->tailCmds != NILLNODE) { Lst_ForEachFrom(job->node->commands, job->tailCmds, JobSaveCommand, - (ClientData)job->node); + (ClientData)job->node); } Make_Update(job->node); } @@ -1586,8 +1847,8 @@ JobStart (gn, flags, previous) return(JOB_ERROR); } } else { - fflush (job->cmdFILE); - (void) unlink (tfile); + (void) fflush(job->cmdFILE); + (void) eunlink(tfile); } /* @@ -1602,54 +1863,75 @@ JobStart (gn, flags, previous) * starting a job and then set up its temporary-file name. This is just * tfile with two extra digits tacked on -- jobno. */ - if (job->flags & JOB_FIRST) { + if (!compatMake || (job->flags & JOB_FIRST)) { if (usePipes) { int fd[2]; - (void) pipe(fd); + if (pipe(fd) == -1) + Punt("Cannot create pipe: %s", strerror(errno)); job->inPipe = fd[0]; job->outPipe = fd[1]; - (void)fcntl (job->inPipe, F_SETFD, 1); - (void)fcntl (job->outPipe, F_SETFD, 1); + (void) fcntl(job->inPipe, F_SETFD, 1); + (void) fcntl(job->outPipe, F_SETFD, 1); } else { - printf ("Remaking `%s'\n", gn->name); - fflush (stdout); - sprintf (job->outFile, "%s%02d", tfile, jobno); + (void) fprintf(stdout, "Remaking `%s'\n", gn->name); + (void) fflush(stdout); + sprintf(job->outFile, "%s%02d", tfile, jobno); jobno = (jobno + 1) % 100; job->outFd = open(job->outFile,O_WRONLY|O_CREAT|O_APPEND,0600); - (void)fcntl (job->outFd, F_SETFD, 1); + (void) fcntl(job->outFd, F_SETFD, 1); } } - local = TRUE; +#ifdef REMOTE + if (!(gn->type & OP_NOEXPORT) && !(runLocalFirst && nLocal < maxLocal)) { +#ifdef RMT_NO_EXEC + local = !Rmt_Export(shellPath, argv, job); +#else + local = !Rmt_Begin(shellPath, argv, job->node); +#endif /* RMT_NO_EXEC */ + if (!local) { + job->flags |= JOB_REMOTE; + } + } else +#endif + local = TRUE; if (local && (((nLocal >= maxLocal) && - !(job->flags & JOB_SPECIAL) && - (maxLocal != 0)))) + !(job->flags & JOB_SPECIAL) && +#ifdef REMOTE + (!(gn->type & OP_NOEXPORT) || (maxLocal != 0)) +#else + (maxLocal != 0) +#endif + ))) { /* * The job can only be run locally, but we've hit the limit of * local concurrency, so put the job on hold until some other job - * finishes. Note that the special jobs (.BEGIN, .INTERRUPT and .END) + * finishes. Note that the special jobs(.BEGIN, .INTERRUPT and .END) * may be run locally even when the local limit has been reached - * (e.g. when maxLocal == 0), though they will be exported if at - * all possible. + *(e.g. when maxLocal == 0), though they will be exported if at + * all possible. In addition, any target marked with .NOEXPORT will + * be run locally if maxLocal is 0. */ jobFull = TRUE; if (DEBUG(JOB)) { - printf("Can only run job locally.\n"); + (void) fprintf(stdout, "Can only run job locally.\n"); + (void) fflush(stdout); } job->flags |= JOB_RESTART; - (void)Lst_AtEnd(stoppedJobs, (ClientData)job); + (void) Lst_AtEnd(stoppedJobs, (ClientData)job); } else { if ((nLocal >= maxLocal) && local) { /* - * If we're running this job locally as a special case (see above), + * If we're running this job locally as a special case(see above), * at least say the table is full. */ jobFull = TRUE; if (DEBUG(JOB)) { - printf("Local job queue is full.\n"); + (void) fprintf(stdout, "Local job queue is full.\n"); + (void) fflush(stdout); } } JobExec(job, argv); @@ -1657,6 +1939,52 @@ JobStart (gn, flags, previous) return(JOB_RUNNING); } +static char * +JobOutput(job, cp, endp, msg) + register Job *job; + register char *cp, *endp; + int msg; +{ + register char *ecp; + + if (commandShell->noPrint) { + ecp = Str_FindSubstring(cp, commandShell->noPrint); + while (ecp != NULL) { + if (cp != ecp) { + *ecp = '\0'; + if (msg && job->node != lastNode) { + MESSAGE(stdout, job->node); + lastNode = job->node; + } + /* + * The only way there wouldn't be a newline after + * this line is if it were the last in the buffer. + * however, since the non-printable comes after it, + * there must be a newline, so we don't print one. + */ + (void) fprintf(stdout, "%s", cp); + (void) fflush(stdout); + } + cp = ecp + commandShell->noPLen; + if (cp != endp) { + /* + * Still more to print, look again after skipping + * the whitespace following the non-printable + * command.... + */ + cp++; + while (*cp == ' ' || *cp == '\t' || *cp == '\n') { + cp++; + } + ecp = Str_FindSubstring(cp, commandShell->noPrint); + } else { + return cp; + } + } + } + return cp; +} + /*- *----------------------------------------------------------------------- * JobDoOutput -- @@ -1674,7 +2002,7 @@ JobStart (gn, flags, previous) * In both cases, however, we keep our figurative eye out for the * 'noPrint' line for the shell from which the output came. If * we recognize a line, we don't print it. If the command is not - * alone on the line (the character after it is not \0 or \n), we + * alone on the line(the character after it is not \0 or \n), we * do print whatever follows it. * * Results: @@ -1684,17 +2012,18 @@ JobStart (gn, flags, previous) * curPos may be shifted as may the contents of outBuf. *----------------------------------------------------------------------- */ -static void -JobDoOutput (job, finish) +STATIC void +JobDoOutput(job, finish) register Job *job; /* the job whose output needs printing */ Boolean finish; /* TRUE if this is the last time we'll be * called for this job */ { Boolean gotNL = FALSE; /* true if got a newline */ + Boolean fbuf; /* true if our buffer filled up */ register int nr; /* number of bytes read */ register int i; /* auxiliary index into outBuf */ - register int max; /* limit for i (end of current data) */ - int nRead; /* (Temporary) number of bytes read */ + register int max; /* limit for i(end of current data) */ + int nRead; /*(Temporary) number of bytes read */ FILE *oFILE; /* Stream pointer to shell's output file */ char inLine[132]; @@ -1705,8 +2034,10 @@ JobDoOutput (job, finish) * Read as many bytes as will fit in the buffer. */ end_loop: + gotNL = FALSE; + fbuf = FALSE; - nRead = read (job->inPipe, &job->outBuf[job->curPos], + nRead = read(job->inPipe, &job->outBuf[job->curPos], JOB_BUFSIZE - job->curPos); if (nRead < 0) { if (DEBUG(JOB)) { @@ -1718,7 +2049,7 @@ end_loop: } /* - * If we hit the end-of-file (the job is dead), we must flush its + * If we hit the end-of-file(the job is dead), we must flush its * remaining output, so pretend we read a newline if there's any * output remaining in the buffer. * Also clear the 'finish' flag so we stop looping. @@ -1756,15 +2087,15 @@ end_loop: * If we've run out of buffer space, we have no choice * but to print the stuff. sigh. */ - gotNL = TRUE; + fbuf = TRUE; i = job->curPos; } } - if (gotNL) { + if (gotNL || fbuf) { /* * Need to send the output to the screen. Null terminate it * first, overwriting the newline character if there was one. - * So long as the line isn't one we should filter (according + * So long as the line isn't one we should filter(according * to the shell description), we print the line, preceeded * by a target banner if this target isn't the same as the * one for which we last printed something. @@ -1773,45 +2104,9 @@ end_loop: */ job->outBuf[i] = '\0'; if (i >= job->curPos) { - register char *cp, *ecp; - - cp = job->outBuf; - if (commandShell->noPrint) { - ecp = Str_FindSubstring(job->outBuf, - commandShell->noPrint); - while (ecp != (char *)NULL) { - if (cp != ecp) { - *ecp = '\0'; - if (job->node != lastNode) { - printf (targFmt, job->node->name); - lastNode = job->node; - } - /* - * The only way there wouldn't be a newline after - * this line is if it were the last in the buffer. - * however, since the non-printable comes after it, - * there must be a newline, so we don't print one. - */ - printf ("%s", cp); - } - cp = ecp + commandShell->noPLen; - if (cp != &job->outBuf[i]) { - /* - * Still more to print, look again after skipping - * the whitespace following the non-printable - * command.... - */ - cp++; - while (*cp == ' ' || *cp == '\t' || *cp == '\n') { - cp++; - } - ecp = Str_FindSubstring (cp, - commandShell->noPrint); - } else { - break; - } - } - } + char *cp; + + cp = JobOutput(job, job->outBuf, &job->outBuf[i]); /* * There's still more in that thar buffer. This time, though, @@ -1820,18 +2115,17 @@ end_loop: */ if (*cp != '\0') { if (job->node != lastNode) { - printf (targFmt, job->node->name); + MESSAGE(stdout, job->node); lastNode = job->node; } - printf ("%s\n", cp); + (void) fprintf(stdout, "%s%s", cp, gotNL ? "\n" : ""); + (void) fflush(stdout); } - - fflush (stdout); } if (i < max - 1) { /* shift the remaining characters down */ - memcpy ( job->outBuf, &job->outBuf[i + 1], max - (i + 1)); - job->curPos = max - (i + 1); + (void) memcpy(job->outBuf, &job->outBuf[i + 1], max -(i + 1)); + job->curPos = max -(i + 1); } else { /* @@ -1845,7 +2139,7 @@ end_loop: /* * If the finish flag is true, we must loop until we hit * end-of-file on the pipe. This is guaranteed to happen eventually - * since the other end of the pipe is now closed (we closed it + * since the other end of the pipe is now closed(we closed it * explicitly and the child has exited). When we do get an EOF, * finish will be set FALSE and we'll fall through and out. */ @@ -1862,62 +2156,36 @@ end_loop: * Change to read in blocks and do FindSubString type things as for * pipes? That would allow for "@echo -n..." */ - oFILE = fopen (job->outFile, "r"); - if (oFILE != (FILE *) NULL) { - printf ("Results of making %s:\n", job->node->name); - while (fgets (inLine, sizeof(inLine), oFILE) != NULL) { - register char *cp, *ecp, *endp; + oFILE = fopen(job->outFile, "r"); + if (oFILE != NULL) { + (void) fprintf(stdout, "Results of making %s:\n", job->node->name); + (void) fflush(stdout); + while (fgets(inLine, sizeof(inLine), oFILE) != NULL) { + register char *cp, *endp, *oendp; cp = inLine; - endp = inLine + strlen(inLine); + oendp = endp = inLine + strlen(inLine); if (endp[-1] == '\n') { *--endp = '\0'; } - if (commandShell->noPrint) { - ecp = Str_FindSubstring(cp, commandShell->noPrint); - while (ecp != (char *)NULL) { - if (cp != ecp) { - *ecp = '\0'; - /* - * The only way there wouldn't be a newline after - * this line is if it were the last in the buffer. - * however, since the non-printable comes after it, - * there must be a newline, so we don't print one. - */ - printf ("%s", cp); - } - cp = ecp + commandShell->noPLen; - if (cp != endp) { - /* - * Still more to print, look again after skipping - * the whitespace following the non-printable - * command.... - */ - cp++; - while (*cp == ' ' || *cp == '\t' || *cp == '\n') { - cp++; - } - ecp = Str_FindSubstring(cp, commandShell->noPrint); - } else { - break; - } - } - } + cp = JobOutput(job, inLine, endp, FALSE); /* * There's still more in that thar buffer. This time, though, * we know there's no newline at the end, so we add one of * our own free will. */ - if (*cp != '\0') { - printf ("%s\n", cp); + (void) fprintf(stdout, "%s", cp); + (void) fflush(stdout); + if (endp != oendp) { + (void) fprintf(stdout, "\n"); + (void) fflush(stdout); } } - fclose (oFILE); - (void) unlink (job->outFile); + (void) fclose(oFILE); + (void) eunlink(job->outFile); } } - fflush(stdout); } /*- @@ -1940,13 +2208,13 @@ end_loop: *----------------------------------------------------------------------- */ void -Job_CatchChildren (block) +Job_CatchChildren(block) Boolean block; /* TRUE if should block on the wait. */ { int pid; /* pid of dead child */ register Job *job; /* job descriptor for dead child */ LstNode jnode; /* list element for finding job */ - union wait status; /* Exit/termination status */ + int status; /* Exit/termination status */ /* * Don't even bother if we know there's no one around. @@ -1955,40 +2223,54 @@ Job_CatchChildren (block) return; } - while ((pid = wait3((int *)&status, (block?0:WNOHANG)|WUNTRACED, - (struct rusage *)0)) > 0) + while ((pid = waitpid((pid_t) -1, &status, + (block?0:WNOHANG)|WUNTRACED)) > 0) { - if (DEBUG(JOB)) - printf("Process %d exited or stopped.\n", pid); + if (DEBUG(JOB)) { + (void) fprintf(stdout, "Process %d exited or stopped.\n", pid); + (void) fflush(stdout); + } - jnode = Lst_Find (jobs, (ClientData)&pid, JobCmpPid); + jnode = Lst_Find(jobs, (ClientData)&pid, JobCmpPid); if (jnode == NILLNODE) { - if (WIFSIGNALED(status) && (status.w_termsig == SIGCONT)) { + if (WIFSIGNALED(status) && (WTERMSIG(status) == SIGCONT)) { jnode = Lst_Find(stoppedJobs, (ClientData) &pid, JobCmpPid); if (jnode == NILLNODE) { - Error("Resumed child (%d) not in table", pid); + Error("Resumed child(%d) not in table", pid); continue; } job = (Job *)Lst_Datum(jnode); - (void)Lst_Remove(stoppedJobs, jnode); + (void) Lst_Remove(stoppedJobs, jnode); } else { - Error ("Child (%d) not in table?", pid); + Error("Child(%d) not in table?", pid); continue; } } else { - job = (Job *) Lst_Datum (jnode); - (void)Lst_Remove (jobs, jnode); + job = (Job *) Lst_Datum(jnode); + (void) Lst_Remove(jobs, jnode); nJobs -= 1; if (jobFull && DEBUG(JOB)) { - printf("Job queue is no longer full.\n"); + (void) fprintf(stdout, "Job queue is no longer full.\n"); + (void) fflush(stdout); } jobFull = FALSE; +#ifdef REMOTE + if (!(job->flags & JOB_REMOTE)) { + if (DEBUG(JOB)) { + (void) fprintf(stdout, + "Job queue has one fewer local process.\n"); + (void) fflush(stdout); + } + nLocal -= 1; + } +#else nLocal -= 1; +#endif } - JobFinish (job, status); + JobFinish(job, &status); } } @@ -1997,7 +2279,7 @@ Job_CatchChildren (block) * Job_CatchOutput -- * Catch the output from our children, if we're using * pipes do so. Otherwise just block time until we get a - * signal (most likely a SIGCHLD) since there's no point in + * signal(most likely a SIGCHLD) since there's no point in * just spinning when there's nothing to do and the reaping * of a child can wait for a while. * @@ -2009,7 +2291,7 @@ Job_CatchChildren (block) * ----------------------------------------------------------------------- */ void -Job_CatchOutput () +Job_CatchOutput() { int nfds; struct timeval timeout; @@ -2020,7 +2302,7 @@ Job_CatchOutput () int pnJobs; /* Previous nJobs */ #endif - fflush(stdout); + (void) fflush(stdout); #ifdef RMT_WILL_WATCH pnJobs = nJobs; @@ -2037,7 +2319,7 @@ Job_CatchOutput () * NOTE: IT IS THE RESPONSIBILITY OF Rmt_Wait TO CALL Job_CatchChildren * IN A TIMELY FASHION TO CATCH ANY LOCALLY RUNNING JOBS THAT EXIT. * It may use the variable nLocal to determine if it needs to call - * Job_CatchChildren (if nLocal is 0, there's nothing for which to + * Job_CatchChildren(if nLocal is 0, there's nothing for which to * wait...) */ while (nJobs != 0 && pnJobs == nJobs) { @@ -2049,21 +2331,21 @@ Job_CatchOutput () timeout.tv_sec = SEL_SEC; timeout.tv_usec = SEL_USEC; - if ((nfds = select (FD_SETSIZE, &readfds, (fd_set *) 0, (fd_set *) 0, &timeout)) < 0) - { + if ((nfds = select(FD_SETSIZE, &readfds, (fd_set *) 0, + (fd_set *) 0, &timeout)) <= 0) return; - } else { - if (Lst_Open (jobs) == FAILURE) { - Punt ("Cannot open job table"); + else { + if (Lst_Open(jobs) == FAILURE) { + Punt("Cannot open job table"); } - while (nfds && (ln = Lst_Next (jobs)) != NILLNODE) { - job = (Job *) Lst_Datum (ln); + while (nfds && (ln = Lst_Next(jobs)) != NILLNODE) { + job = (Job *) Lst_Datum(ln); if (FD_ISSET(job->inPipe, &readfds)) { - JobDoOutput (job, FALSE); + JobDoOutput(job, FALSE); nfds -= 1; } } - Lst_Close (jobs); + Lst_Close(jobs); } } #endif /* RMT_WILL_WATCH */ @@ -2084,10 +2366,10 @@ Job_CatchOutput () *----------------------------------------------------------------------- */ void -Job_Make (gn) +Job_Make(gn) GNode *gn; { - (void)JobStart (gn, 0, (Job *)NULL); + (void) JobStart(gn, 0, NULL); } /*- @@ -2103,7 +2385,7 @@ Job_Make (gn) *----------------------------------------------------------------------- */ void -Job_Init (maxproc, maxlocal) +Job_Init(maxproc, maxlocal) int maxproc; /* the greatest number of jobs which may be * running at one time */ int maxlocal; /* the greatest number of local jobs which may @@ -2111,9 +2393,9 @@ Job_Init (maxproc, maxlocal) { GNode *begin; /* node for commands to do at the very start */ - sprintf (tfile, "/tmp/make%05d", getpid()); + (void) sprintf(tfile, "/tmp/make%05d", getpid()); - jobs = Lst_Init (FALSE); + jobs = Lst_Init(FALSE); stoppedJobs = Lst_Init(FALSE); maxJobs = maxproc; maxLocal = maxlocal; @@ -2126,7 +2408,11 @@ Job_Init (maxproc, maxlocal) lastNode = NILGNODE; - if (maxJobs == 1) { + if (maxJobs == 1 +#ifdef REMOTE + || noMessages +#endif + ) { /* * If only one job can run at a time, there's no need for a banner, * no is there? @@ -2136,7 +2422,7 @@ Job_Init (maxproc, maxlocal) targFmt = TARG_FMT; } - if (shellPath == (char *) NULL) { + if (shellPath == NULL) { /* * The user didn't specify a shell to use, so we are using the * default one... Both the absolute path and the last component @@ -2145,13 +2431,13 @@ Job_Init (maxproc, maxlocal) * All default shells are located in _PATH_DEFSHELLDIR. */ shellName = commandShell->name; - shellPath = str_concat (_PATH_DEFSHELLDIR, shellName, STR_ADDSLASH); + shellPath = str_concat(_PATH_DEFSHELLDIR, shellName, STR_ADDSLASH); } - if (commandShell->exit == (char *)NULL) { + if (commandShell->exit == NULL) { commandShell->exit = ""; } - if (commandShell->echo == (char *)NULL) { + if (commandShell->echo == NULL) { commandShell->echo = ""; } @@ -2159,51 +2445,51 @@ Job_Init (maxproc, maxlocal) * Catch the four signals that POSIX specifies if they aren't ignored. * JobPassSig will take care of calling JobInterrupt if appropriate. */ - if (signal (SIGINT, SIG_IGN) != SIG_IGN) { - signal (SIGINT, JobPassSig); + if (signal(SIGINT, SIG_IGN) != SIG_IGN) { + (void) signal(SIGINT, JobPassSig); } - if (signal (SIGHUP, SIG_IGN) != SIG_IGN) { - signal (SIGHUP, JobPassSig); + if (signal(SIGHUP, SIG_IGN) != SIG_IGN) { + (void) signal(SIGHUP, JobPassSig); } - if (signal (SIGQUIT, SIG_IGN) != SIG_IGN) { - signal (SIGQUIT, JobPassSig); + if (signal(SIGQUIT, SIG_IGN) != SIG_IGN) { + (void) signal(SIGQUIT, JobPassSig); } - if (signal (SIGTERM, SIG_IGN) != SIG_IGN) { - signal (SIGTERM, JobPassSig); + if (signal(SIGTERM, SIG_IGN) != SIG_IGN) { + (void) signal(SIGTERM, JobPassSig); } /* * There are additional signals that need to be caught and passed if * either the export system wants to be told directly of signals or if - * we're giving each job its own process group (since then it won't get + * we're giving each job its own process group(since then it won't get * signals from the terminal driver as we own the terminal) */ #if defined(RMT_WANTS_SIGNALS) || defined(USE_PGRP) - if (signal (SIGTSTP, SIG_IGN) != SIG_IGN) { - signal (SIGTSTP, JobPassSig); + if (signal(SIGTSTP, SIG_IGN) != SIG_IGN) { + (void) signal(SIGTSTP, JobPassSig); } - if (signal (SIGTTOU, SIG_IGN) != SIG_IGN) { - signal (SIGTTOU, JobPassSig); + if (signal(SIGTTOU, SIG_IGN) != SIG_IGN) { + (void) signal(SIGTTOU, JobPassSig); } - if (signal (SIGTTIN, SIG_IGN) != SIG_IGN) { - signal (SIGTTIN, JobPassSig); + if (signal(SIGTTIN, SIG_IGN) != SIG_IGN) { + (void) signal(SIGTTIN, JobPassSig); } - if (signal (SIGWINCH, SIG_IGN) != SIG_IGN) { - signal (SIGWINCH, JobPassSig); + if (signal(SIGWINCH, SIG_IGN) != SIG_IGN) { + (void) signal(SIGWINCH, JobPassSig); } #endif - begin = Targ_FindNode (".BEGIN", TARG_NOCREATE); + begin = Targ_FindNode(".BEGIN", TARG_NOCREATE); if (begin != NILGNODE) { - JobStart (begin, JOB_SPECIAL, (Job *)0); + JobStart(begin, JOB_SPECIAL, (Job *)0); while (nJobs) { Job_CatchOutput(); #ifndef RMT_WILL_WATCH - Job_CatchChildren (!usePipes); + Job_CatchChildren(!usePipes); #endif /* RMT_WILL_WATCH */ } } - postCommands = Targ_FindNode (".END", TARG_CREATE); + postCommands = Targ_FindNode(".END", TARG_CREATE); } /*- @@ -2221,9 +2507,9 @@ Job_Init (maxproc, maxlocal) *----------------------------------------------------------------------- */ Boolean -Job_Full () +Job_Full() { - return (aborting || jobFull); + return(aborting || jobFull); } /*- @@ -2243,7 +2529,7 @@ Job_Full () * ----------------------------------------------------------------------- */ Boolean -Job_Empty () +Job_Empty() { if (nJobs == 0) { if (!Lst_IsEmpty(stoppedJobs) && !aborting) { @@ -2252,9 +2538,7 @@ Job_Empty () * it...Try and restart the stopped jobs. */ jobFull = FALSE; - while (!jobFull && !Lst_IsEmpty(stoppedJobs)) { - JobRestart((Job *)Lst_DeQueue(stoppedJobs)); - } + JobRestartJobs(); return(FALSE); } else { return(TRUE); @@ -2278,7 +2562,7 @@ Job_Empty () *----------------------------------------------------------------------- */ static Shell * -JobMatchShell (name) +JobMatchShell(name) char *name; /* Final component of shell path */ { register Shell *sh; /* Pointer into shells table */ @@ -2287,24 +2571,23 @@ JobMatchShell (name) *cp2; char *eoname; - eoname = name + strlen (name); + eoname = name + strlen(name); - match = (Shell *) NULL; + match = NULL; for (sh = shells; sh->name != NULL; sh++) { - for (cp1 = eoname - strlen (sh->name), cp2 = sh->name; + for (cp1 = eoname - strlen(sh->name), cp2 = sh->name; *cp1 != '\0' && *cp1 == *cp2; cp1++, cp2++) { continue; } if (*cp1 != *cp2) { continue; - } else if (match == (Shell *) NULL || - strlen (match->name) < strlen (sh->name)) { - match = sh; + } else if (match == NULL || strlen(match->name) < strlen(sh->name)) { + match = sh; } } - return (match == (Shell *) NULL ? sh : match); + return(match == NULL ? sh : match); } /*- @@ -2351,7 +2634,7 @@ JobMatchShell (name) *----------------------------------------------------------------------- */ ReturnStatus -Job_ParseShell (line) +Job_ParseShell(line) char *line; /* The shell spec */ { char **words; @@ -2362,88 +2645,88 @@ Job_ParseShell (line) Shell newShell; Boolean fullSpec = FALSE; - while (isspace (*line)) { + while (isspace(*line)) { line++; } - words = brk_string (line, &wordCount, TRUE); + words = brk_string(line, &wordCount, TRUE); - memset ((Address)&newShell, 0, sizeof(newShell)); + memset((Address)&newShell, 0, sizeof(newShell)); /* * Parse the specification by keyword */ - for (path = (char *)NULL, argc = wordCount - 1, argv = words + 1; + for (path = NULL, argc = wordCount - 1, argv = words + 1; argc != 0; argc--, argv++) { - if (strncmp (*argv, "path=", 5) == 0) { + if (strncmp(*argv, "path=", 5) == 0) { path = &argv[0][5]; - } else if (strncmp (*argv, "name=", 5) == 0) { + } else if (strncmp(*argv, "name=", 5) == 0) { newShell.name = &argv[0][5]; } else { - if (strncmp (*argv, "quiet=", 6) == 0) { + if (strncmp(*argv, "quiet=", 6) == 0) { newShell.echoOff = &argv[0][6]; - } else if (strncmp (*argv, "echo=", 5) == 0) { + } else if (strncmp(*argv, "echo=", 5) == 0) { newShell.echoOn = &argv[0][5]; - } else if (strncmp (*argv, "filter=", 7) == 0) { + } else if (strncmp(*argv, "filter=", 7) == 0) { newShell.noPrint = &argv[0][7]; newShell.noPLen = strlen(newShell.noPrint); - } else if (strncmp (*argv, "echoFlag=", 9) == 0) { + } else if (strncmp(*argv, "echoFlag=", 9) == 0) { newShell.echo = &argv[0][9]; - } else if (strncmp (*argv, "errFlag=", 8) == 0) { + } else if (strncmp(*argv, "errFlag=", 8) == 0) { newShell.exit = &argv[0][8]; - } else if (strncmp (*argv, "hasErrCtl=", 10) == 0) { + } else if (strncmp(*argv, "hasErrCtl=", 10) == 0) { char c = argv[0][10]; newShell.hasErrCtl = !((c != 'Y') && (c != 'y') && - (c != 'T') && (c != 't')); - } else if (strncmp (*argv, "check=", 6) == 0) { + (c != 'T') && (c != 't')); + } else if (strncmp(*argv, "check=", 6) == 0) { newShell.errCheck = &argv[0][6]; - } else if (strncmp (*argv, "ignore=", 7) == 0) { + } else if (strncmp(*argv, "ignore=", 7) == 0) { newShell.ignErr = &argv[0][7]; } else { - Parse_Error (PARSE_FATAL, "Unknown keyword \"%s\"", + Parse_Error(PARSE_FATAL, "Unknown keyword \"%s\"", *argv); - return (FAILURE); + return(FAILURE); } fullSpec = TRUE; } } - if (path == (char *)NULL) { + if (path == NULL) { /* * If no path was given, the user wants one of the pre-defined shells, * yes? So we find the one s/he wants with the help of JobMatchShell * and set things up the right way. shellPath will be set up by * Job_Init. */ - if (newShell.name == (char *)NULL) { - Parse_Error (PARSE_FATAL, "Neither path nor name specified"); - return (FAILURE); + if (newShell.name == NULL) { + Parse_Error(PARSE_FATAL, "Neither path nor name specified"); + return(FAILURE); } else { - commandShell = JobMatchShell (newShell.name); + commandShell = JobMatchShell(newShell.name); shellName = newShell.name; } } else { /* - * The user provided a path. If s/he gave nothing else (fullSpec is + * The user provided a path. If s/he gave nothing else(fullSpec is * FALSE), try and find a matching shell in the ones we know of. * Else we just take the specification at its word and copy it * to a new location. In either case, we need to record the * path the user gave for the shell. */ shellPath = path; - path = strrchr (path, '/'); - if (path == (char *)NULL) { + path = strrchr(path, '/'); + if (path == NULL) { path = shellPath; } else { path += 1; } - if (newShell.name != (char *)NULL) { + if (newShell.name != NULL) { shellName = newShell.name; } else { shellName = path; } if (!fullSpec) { - commandShell = JobMatchShell (shellName); + commandShell = JobMatchShell(shellName); } else { commandShell = (Shell *) emalloc(sizeof(Shell)); *commandShell = newShell; @@ -2455,10 +2738,10 @@ Job_ParseShell (line) } if (!commandShell->hasErrCtl) { - if (commandShell->errCheck == (char *)NULL) { + if (commandShell->errCheck == NULL) { commandShell->errCheck = ""; } - if (commandShell->ignErr == (char *)NULL) { + if (commandShell->ignErr == NULL) { commandShell->ignErr = "%s\n"; } } @@ -2467,7 +2750,7 @@ Job_ParseShell (line) * Do not free up the words themselves, since they might be in use by the * shell specification... */ - free (words); + free(words); return SUCCESS; } @@ -2485,9 +2768,10 @@ Job_ParseShell (line) *----------------------------------------------------------------------- */ static void -JobInterrupt (runINTERRUPT) +JobInterrupt(runINTERRUPT, signo) int runINTERRUPT; /* Non-zero if commands for the .INTERRUPT * target should be executed */ + int signo; /* signal received */ { LstNode ln; /* element in job table */ Job *job; /* job descriptor in that element */ @@ -2495,18 +2779,16 @@ JobInterrupt (runINTERRUPT) aborting = ABORT_INTERRUPT; - (void)Lst_Open (jobs); - while ((ln = Lst_Next (jobs)) != NILLNODE) { - job = (Job *) Lst_Datum (ln); + (void) Lst_Open(jobs); + while ((ln = Lst_Next(jobs)) != NILLNODE) { + job = (Job *) Lst_Datum(ln); - if (!Targ_Precious (job->node)) { - char *file = (job->node->path == (char *)NULL ? + if (!Targ_Precious(job->node)) { + char *file = (job->node->path == NULL ? job->node->name : job->node->path); - struct stat st; - if (!noExecute && lstat(file, &st) != -1 && !S_ISDIR(st.st_mode) && - unlink(file) != -1) { - Error ("*** %s removed", file); + if (!noExecute && eunlink(file) != -1) { + Error("*** %s removed", file); } } #ifdef RMT_WANTS_SIGNALS @@ -2514,44 +2796,110 @@ JobInterrupt (runINTERRUPT) /* * If job is remote, let the Rmt module do the killing. */ - if (!Rmt_Signal(job, SIGINT)) { + if (!Rmt_Signal(job, signo)) { /* * If couldn't kill the thing, finish it out now with an * error code, since no exit report will come in likely. */ - union wait status; + int status; status.w_status = 0; status.w_retcode = 1; - JobFinish(job, status); + JobFinish(job, &status); } } else if (job->pid) { - KILL(job->pid, SIGINT); + KILL(job->pid, signo); } #else if (job->pid) { + if (DEBUG(JOB)) { + (void) fprintf(stdout, + "JobInterrupt passing signal to child %d.\n", + job->pid); + (void) fflush(stdout); + } + KILL(job->pid, signo); + } +#endif /* RMT_WANTS_SIGNALS */ + } + +#ifdef REMOTE + (void)Lst_Open(stoppedJobs); + while ((ln = Lst_Next(stoppedJobs)) != NILLNODE) { + job = (Job *) Lst_Datum(ln); + + if (job->flags & JOB_RESTART) { + if (DEBUG(JOB)) { + (void) fprintf(stdout, "%s%s", + "JobInterrupt skipping job on stopped queue", + "-- it was waiting to be restarted.\n"); + (void) fflush(stdout); + } + continue; + } + if (!Targ_Precious(job->node)) { + char *file = (job->node->path == NULL ? + job->node->name : + job->node->path); + if (eunlink(file) == 0) { + Error("*** %s removed", file); + } + } + /* + * Resume the thing so it will take the signal. + */ + if (DEBUG(JOB)) { + (void) fprintf(stdout, + "JobInterrupt passing CONT to stopped child %d.\n", + job->pid); + (void) fflush(stdout); + } + KILL(job->pid, SIGCONT); +#ifdef RMT_WANTS_SIGNALS + if (job->flags & JOB_REMOTE) { + /* + * If job is remote, let the Rmt module do the killing. + */ + if (!Rmt_Signal(job, SIGINT)) { + /* + * If couldn't kill the thing, finish it out now with an + * error code, since no exit report will come in likely. + */ + int status; + status.w_status = 0; + status.w_retcode = 1; + JobFinish(job, &status); + } + } else if (job->pid) { + if (DEBUG(JOB)) { + (void) fprintf(stdout, + "JobInterrupt passing interrupt to stopped child %d.\n", + job->pid); + (void) fflush(stdout); + } KILL(job->pid, SIGINT); } #endif /* RMT_WANTS_SIGNALS */ } - Lst_Close (jobs); +#endif + Lst_Close(stoppedJobs); if (runINTERRUPT && !touchFlag) { - interrupt = Targ_FindNode (".INTERRUPT", TARG_NOCREATE); + interrupt = Targ_FindNode(".INTERRUPT", TARG_NOCREATE); if (interrupt != NILGNODE) { ignoreErrors = FALSE; - JobStart (interrupt, JOB_IGNDOTS, (Job *)0); + JobStart(interrupt, JOB_IGNDOTS, (Job *)0); while (nJobs) { Job_CatchOutput(); #ifndef RMT_WILL_WATCH - Job_CatchChildren (!usePipes); + Job_CatchChildren(!usePipes); #endif /* RMT_WILL_WATCH */ } } } - (void) unlink (tfile); - exit (0); + (void) eunlink(tfile); + exit(signo); } /* @@ -2564,29 +2912,28 @@ JobInterrupt (runINTERRUPT) * Number of errors reported. * * Side Effects: - * The process' temporary file (tfile) is removed if it still + * The process' temporary file(tfile) is removed if it still * existed. *----------------------------------------------------------------------- */ int -Job_End () +Job_End() { - if (postCommands != NILGNODE && !Lst_IsEmpty (postCommands->commands)) { + if (postCommands != NILGNODE && !Lst_IsEmpty(postCommands->commands)) { if (errors) { - Error ("Errors reported so .END ignored"); + Error("Errors reported so .END ignored"); } else { - JobStart (postCommands, JOB_SPECIAL | JOB_IGNDOTS, - (Job *)0); + JobStart(postCommands, JOB_SPECIAL | JOB_IGNDOTS, NULL); while (nJobs) { Job_CatchOutput(); #ifndef RMT_WILL_WATCH - Job_CatchChildren (!usePipes); + Job_CatchChildren(!usePipes); #endif /* RMT_WILL_WATCH */ } } } - (void) unlink (tfile); + (void) eunlink(tfile); return(errors); } @@ -2632,9 +2979,9 @@ Job_Wait() *----------------------------------------------------------------------- */ void -Job_AbortAll () +Job_AbortAll() { - LstNode ln; /* element in job table */ + LstNode ln; /* element in job table */ Job *job; /* the job descriptor in that element */ int foo; @@ -2642,9 +2989,9 @@ Job_AbortAll () if (nJobs) { - (void)Lst_Open (jobs); - while ((ln = Lst_Next (jobs)) != NILLNODE) { - job = (Job *) Lst_Datum (ln); + (void) Lst_Open(jobs); + while ((ln = Lst_Next(jobs)) != NILLNODE) { + job = (Job *) Lst_Datum(ln); /* * kill the child process with increasingly drastic signals to make @@ -2668,7 +3015,88 @@ Job_AbortAll () /* * Catch as many children as want to report in at first, then give up */ - while (wait3(&foo, WNOHANG, (struct rusage *)0) > 0) + while (waitpid((pid_t) -1, &foo, WNOHANG) > 0) continue; - (void) unlink (tfile); + (void) eunlink(tfile); +} + +#ifdef REMOTE +/*- + *----------------------------------------------------------------------- + * JobFlagForMigration -- + * Handle the eviction of a child. Called from RmtStatusChange. + * Flags the child as remigratable and then suspends it. + * + * Results: + * none. + * + * Side Effects: + * The job descriptor is flagged for remigration. + * + *----------------------------------------------------------------------- + */ +void +JobFlagForMigration(hostID) + int hostID; /* ID of host we used, for matching children. */ +{ + register Job *job; /* job descriptor for dead child */ + LstNode jnode; /* list element for finding job */ + + if (DEBUG(JOB)) { + (void) fprintf(stdout, "JobFlagForMigration(%d) called.\n", hostID); + (void) fflush(stdout); + } + jnode = Lst_Find(jobs, (ClientData)hostID, JobCmpRmtID); + + if (jnode == NILLNODE) { + jnode = Lst_Find(stoppedJobs, (ClientData)hostID, JobCmpRmtID); + if (jnode == NILLNODE) { + if (DEBUG(JOB)) { + Error("Evicting host(%d) not in table", hostID); + } + return; + } + } + job = (Job *) Lst_Datum(jnode); + + if (DEBUG(JOB)) { + (void) fprintf(stdout, + "JobFlagForMigration(%d) found job '%s'.\n", hostID, + job->node->name); + (void) fflush(stdout); + } + + KILL(job->pid, SIGSTOP); + + job->flags |= JOB_REMIGRATE; +} + +#endif + +/*- + *----------------------------------------------------------------------- + * JobRestartJobs -- + * Tries to restart stopped jobs if there are slots available. + * Note that this tries to restart them regardless of pending errors. + * It's not good to leave stopped jobs lying around! + * + * Results: + * None. + * + * Side Effects: + * Resumes(and possibly migrates) jobs. + * + *----------------------------------------------------------------------- + */ +static void +JobRestartJobs() +{ + while (!jobFull && !Lst_IsEmpty(stoppedJobs)) { + if (DEBUG(JOB)) { + (void) fprintf(stdout, + "Job queue is not full. Restarting a stopped job.\n"); + (void) fflush(stdout); + } + JobRestart((Job *)Lst_DeQueue(stoppedJobs)); + } } |