diff options
author | Marc Espie <espie@cvs.openbsd.org> | 2007-09-17 12:42:10 +0000 |
---|---|---|
committer | Marc Espie <espie@cvs.openbsd.org> | 2007-09-17 12:42:10 +0000 |
commit | 04da241c9a9d1947a02599b69c4d28cad730e2ee (patch) | |
tree | 411a70834205a49e35f9401bcb6a7d91905ebc7a /usr.bin/make/job.c | |
parent | 623d7eb586551d91075741d88eb155937894af6b (diff) |
rewrite of the basic suffix/target parsing: use hash for suffixes.
Store special targets in target hash, and use them for the parsing.
Use OP_DUMMY flag to mark targets that don't really exist yet, such
as interrupt and default nodes.
Also, .PATHxxx is special in suffixes.
Small tweaks to compat.c, so that run_commands does more stuff after
the fork() (and thus no need to free things).
Remove distinction between local and global jobs.
Diffstat (limited to 'usr.bin/make/job.c')
-rw-r--r-- | usr.bin/make/job.c | 310 |
1 files changed, 120 insertions, 190 deletions
diff --git a/usr.bin/make/job.c b/usr.bin/make/job.c index 1105768e8bf..e0e2bf91e75 100644 --- a/usr.bin/make/job.c +++ b/usr.bin/make/job.c @@ -1,5 +1,5 @@ /* $OpenPackages$ */ -/* $OpenBSD: job.c,v 1.77 2007/09/17 12:03:40 espie Exp $ */ +/* $OpenBSD: job.c,v 1.78 2007/09/17 12:42:09 espie Exp $ */ /* $NetBSD: job.c,v 1.16 1996/11/06 17:59:08 christos Exp $ */ /* @@ -48,8 +48,6 @@ * frequently to keep the whole make going at * a decent clip, since job table entries aren't * removed until their process is caught this way. - * Its single argument is true if the function - * should block waiting for a child to terminate. * * Job_CatchOutput Print any output our children have produced. * Should also be called fairly frequently to @@ -132,11 +130,11 @@ * commands. * 4) An FILE* for writing out the commands. This is only * used before the job is actually started. - * 5) Things used for handling the shell's output. + * 5) Things used for handling the shell's output. * the output is being caught via a pipe and * the descriptors of our pipe, an array in which output is line * buffered and the current position in that buffer are all - * maintained for each job. + * maintained for each job. * 6) An identifier provided by and for the exclusive use of the * Rmt module. * 7) A word of flags which determine how the module handles errors, @@ -162,17 +160,17 @@ typedef struct Job_ { short flags; /* Flags to control treatment of job */ #define JOB_IGNERR 0x001 /* Ignore non-zero exits */ #define JOB_SILENT 0x002 /* no output */ -#define JOB_SPECIAL 0x004 /* Target is a special one. i.e. run it locally - * if we can't export it and maxLocal is 0 */ -#define JOB_IGNDOTS 0x008 /* Ignore "..." lines when processing - * commands */ +#define JOB_SPECIAL 0x004 /* Target is a special one. i.e., always run */ + /* it even when the table is full */ +#define JOB_IGNDOTS 0x008 /* Ignore "..." lines when processing */ + /* commands */ #define JOB_FIRST 0x020 /* Job is first job for the node */ #define JOB_RESTART 0x080 /* Job needs to be completely restarted */ -#define JOB_RESUME 0x100 /* Job needs to be resumed b/c it stopped, - * for some reason */ -#define JOB_CONTINUING 0x200 /* We are in the process of resuming this job. - * Used to avoid infinite recursion between - * JobFinish and JobRestart */ +#define JOB_RESUME 0x100 /* Job needs to be resumed b/c it stopped, */ + /* for some reason */ +#define JOB_CONTINUING 0x200 /* We are in the process of resuming this job */ + /* Used to avoid infinite recursion between */ + /* JobFinish and JobRestart */ int inPipe; /* Input side of pipe associated * with job's output channel */ int outPipe; /* Output side of pipe associated with @@ -183,6 +181,7 @@ typedef struct Job_ { int curPos; /* Current position in op_outBuf */ } Job; + /* * error handling variables */ @@ -198,13 +197,6 @@ static int aborting = 0; /* why is the make aborting? */ */ #define FILENO(a) ((unsigned) fileno(a)) -/* - * post-make command processing. The node postCommands is really just the - * .END target but we keep it around to avoid having to search for it - * all the time. - */ -static GNode *postCommands; /* node containing commands to execute when - * everything else is done */ static int numCommands; /* The number of commands actually printed * for a target. Should this number be * 0, no shell will be executed. */ @@ -235,16 +227,11 @@ static char tfile[sizeof(TMPPAT)]; static const char *shellPath = _PATH_BSHELL; static const char *shellName = "sh"; + static int maxJobs; /* The most children we can run at once */ -static int maxLocal; /* The most local ones we can have */ static int nJobs = 0; /* The number of children currently running */ -static int nLocal; /* The number of local children */ static LIST jobs; /* The structures that describe them */ -static bool 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 - * nLocal equals maxLocal */ +static bool jobFull; /* Flag to tell when the job table is full. */ static fd_set *outputsp; /* Set of descriptors of pipes connected to * the output channels of children */ static int outputsn; @@ -539,7 +526,7 @@ DBPRINTF(Job *job, const char *fmt, ...) * If the command is just "..." we take all future commands for this * job to be commands to be executed once the entire graph has been * made and return non-zero to signal that the end of the commands - * was reached. These commands are later attached to the postCommands + * was reached. These commands are later attached to the end_node * node and executed by Job_End when all things are done. * This function is called from JobStart via Lst_Find * @@ -555,20 +542,20 @@ DBPRINTF(Job *job, const char *fmt, ...) *----------------------------------------------------------------------- */ static int -JobPrintCommand(LstNode cmdNode, /* command string to print */ - void *jobp) /* job for which to print it */ +JobPrintCommand(LstNode cmdNode, /* command string to print */ + void *jobp) /* job for which to print it */ { - bool noSpecials; /* true if we shouldn't worry about - * inserting special commands into - * the input stream. */ - bool shutUp = false; /* true if we put a no echo command - * into the command file */ - bool errOff = false; /* true if we turned error checking - * off before printing the command - * and need to turn it back on */ - char *cmdTemplate; /* Template to use when printing the - * command */ - char *cmdStart; /* Start of expanded command */ + bool noSpecials; /* true if we shouldn't worry about + * inserting special commands into + * the input stream. */ + bool shutUp = false; /* true if we put a no echo command + * into the command file */ + bool errOff = false; /* true if we turned error checking + * off before printing the command + * and need to turn it back on */ + char *cmdTemplate; /* Template to use when printing the + * command */ + char *cmdStart; /* Start of expanded command */ char *cmd = (char *)Lst_Datum(cmdNode); Job *job = (Job *)jobp; @@ -583,6 +570,7 @@ JobPrintCommand(LstNode cmdNode, /* command string to print */ return 1; } + numCommands++; /* For debugging, we replace each command with the result of expanding @@ -618,13 +606,12 @@ JobPrintCommand(LstNode cmdNode, /* command string to print */ if (errOff) { if ( !(job->flags & JOB_IGNERR) && !noSpecials) { /* - * we don't want the error-control commands - * showing up either, so we turn off echoing - * while executing them. We could put another - * field in the shell structure to tell - * JobDoOutput to look for this string too, but - * why make it any more complex than it already - * is? + * we don't want the error-control commands showing + * up either, so we turn off echoing while executing + * them. We could put another field in the shell + * structure to tell JobDoOutput to look for this + * string too, but why make it any more complex than + * it already is? */ if (!(job->flags & JOB_SILENT) && !shutUp) { DBPRINTF(job, "%s; %s; %s\n", SHELL_ECHO_OFF, @@ -664,7 +651,7 @@ JobPrintCommand(LstNode cmdNode, /* command string to print */ * Callback function for JobFinish... * * Side Effects: - * The command is tacked onto the end of postCommands's commands list. + * The command is tacked onto the end of end_node's commands list. *----------------------------------------------------------------------- */ static void @@ -674,7 +661,7 @@ JobSaveCommand(void *cmd, void *gn) char *result; result = Var_Subst((char *)cmd, &g->context, false); - Lst_AtEnd(&postCommands->commands, result); + Lst_AtEnd(&end_node->commands, result); } @@ -710,7 +697,7 @@ JobClose(Job *job) * * Side Effects: * Some nodes may be put on the toBeMade queue. - * Final commands for the job are placed on postCommands. + * Final commands for the job are placed on end_node. * * If we got an error and are aborting (aborting == ABORT_ERROR) and * the job list is now empty, we are done for the day. @@ -723,7 +710,7 @@ static void JobFinish(Job *job, /* job to finish */ int *status) /* sub-why job went away */ { - bool done; + bool done; if ((WIFEXITED(*status) && WEXITSTATUS(*status) != 0 && !(job->flags & JOB_IGNERR)) || @@ -773,8 +760,8 @@ JobFinish(Job *job, /* job to finish */ if (WIFEXITED(*status)) { if (DEBUG(JOB)) { - (void)fprintf(stdout, "Process %ld exited.\n", - (long)job->pid); + (void)fprintf(stdout, + "Process %ld exited.\n", (long)job->pid); (void)fflush(stdout); } if (WEXITSTATUS(*status) != 0) { @@ -800,8 +787,8 @@ JobFinish(Job *job, /* job to finish */ } } else if (WIFSTOPPED(*status)) { if (DEBUG(JOB)) { - (void)fprintf(stdout, "Process %ld stopped.\n", - (long)job->pid); + (void)fprintf(stdout, + "Process %ld stopped.\n", (long)job->pid); (void)fflush(stdout); } if (job->node != lastNode) { @@ -831,7 +818,7 @@ JobFinish(Job *job, /* job to finish */ if (!(job->flags & JOB_CONTINUING)) { if (DEBUG(JOB)) { (void)fprintf(stdout, - "Warning: process %ld was not continuing.\n", + "Warning: process %ld was not continuing.\n", (long)job->pid); (void)fflush(stdout); } @@ -855,7 +842,6 @@ JobFinish(Job *job, /* job to finish */ (long)job->pid); (void)fflush(stdout); } - nLocal++; if (nJobs == maxJobs) { jobFull = true; if (DEBUG(JOB)) { @@ -964,7 +950,7 @@ JobExec(Job *job, char **argv) pid_t cpid; /* ID of new child */ if (DEBUG(JOB)) { - int i; + int i; (void)fprintf(stdout, "Running %s\n", job->node->name); (void)fprintf(stdout, "\tCommand: "); @@ -1003,8 +989,8 @@ JobExec(Job *job, char **argv) (void)lseek(0, 0, SEEK_SET); /* - * Set up the child's output to be routed through the - * pipe we've created for it. + * Set up the child's output to be routed through the pipe + * we've created for it. */ if (dup2(job->outPipe, 1) == -1) Punt("Cannot dup2: %s", strerror(errno)); @@ -1069,7 +1055,6 @@ JobExec(Job *job, char **argv) FD_SET(job->inPipe, outputsp); } - nLocal++; /* * XXX: Used to not happen if REMOTE. Why? */ @@ -1111,7 +1096,7 @@ JobMakeArgv(Job *job, char **argv) if (args[1]) { argv[argc] = args; argc++; - } + } argv[argc] = NULL; } @@ -1146,7 +1131,7 @@ JobRestart(Job *job) job->node->name); (void)fflush(stdout); } - if (nLocal >= maxLocal && !(job->flags & JOB_SPECIAL)) { + if (nJobs >= maxJobs && !(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 @@ -1182,13 +1167,10 @@ JobRestart(Job *job) (void)fprintf(stdout, "Resuming %s...", job->node->name); (void)fflush(stdout); } - if ((nLocal < maxLocal || - ((job->flags & JOB_SPECIAL) && - maxLocal == 0) - ) && nJobs != maxJobs) { + if (nJobs != maxJobs || (job->flags & JOB_SPECIAL)) { /* - * If we haven't reached the concurrency limit already - * (or maxLocal is 0), it's ok to resume the job. + * If we haven't reached the concurrency limit already, + * it's ok to resume the job. */ bool error; int status; @@ -1253,17 +1235,17 @@ JobRestart(Job *job) *----------------------------------------------------------------------- */ static int -JobStart(GNode *gn, /* target to create */ - int flags, /* flags for the job to override normal ones. - * e.g. JOB_SPECIAL or JOB_IGNDOTS */ - Job *previous) /* The previous Job structure for this node, - * if any. */ +JobStart(GNode *gn, /* target to create */ + int flags, /* flags for the job to override normal ones. + * e.g. JOB_SPECIAL or JOB_IGNDOTS */ + Job *previous) /* The previous Job structure for this node, + * if any. */ { - Job *job; /* new job descriptor */ - char *argv[4]; /* Argument vector to shell */ - bool cmdsOK; /* true if the nodes commands were all right */ - bool local; /* Set true if the job was run locally */ - bool noExec; /* Set true if we decide not to run the job */ + Job *job; /* new job descriptor */ + char *argv[4]; /* Argument vector to shell */ + bool cmdsOK; /* true if the nodes commands were all right */ + bool local; /* Set true if the job was run locally */ + bool noExec; /* Set true if we decide not to run the job */ if (previous != NULL) { previous->flags &= ~(JOB_FIRST|JOB_IGNERR|JOB_SILENT); @@ -1483,18 +1465,9 @@ JobStart(GNode *gn, /* target to create */ local = true; - if (local && nLocal >= maxLocal && - !(job->flags & JOB_SPECIAL) && - maxLocal != 0 - ) { - /* - * 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) 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. In addition, any target marked - * with .NOEXPORT will be run locally if maxLocal is 0. + if (nJobs >= maxJobs && !(job->flags & JOB_SPECIAL)) { + /* we've hit the limit of concurrency, so put the job on hold + * until some other job finishes. */ jobFull = true; @@ -1504,20 +1477,6 @@ JobStart(GNode *gn, /* target to create */ } job->flags |= JOB_RESTART; Lst_AtEnd(&stoppedJobs, job); - } else { - if (nLocal >= maxLocal && local) { - /* - * 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)) { - (void)fprintf(stdout, - "Local job queue is full.\n"); - (void)fflush(stdout); - } - } - JobExec(job, argv); } return JOB_RUNNING; } @@ -1536,11 +1495,10 @@ JobOutput(Job *job, char *cp, char *endp, int msg) 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. + * 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); @@ -1548,13 +1506,12 @@ JobOutput(Job *job, char *cp, char *endp, int msg) cp = ecp + strlen(SHELL_ECHO_OFF); if (cp != endp) { /* - * Still more to print, look again after - * skipping the whitespace following the - * non-printable command.... + * Still more to print, look again after skipping + * the whitespace following the non-printable + * command.... */ cp++; - while (*cp == ' ' || *cp == '\t' || - *cp == '\n') { + while (*cp == ' ' || *cp == '\t' || *cp == '\n') { cp++; } ecp = strstr(cp, SHELL_ECHO_OFF); @@ -1594,12 +1551,12 @@ JobDoOutput(Job *job, /* the job whose output needs printing */ bool finish) /* true if this is the last time we'll be * called for this job */ { - bool gotNL = false; /* true if got a newline */ + bool gotNL = false; /* true if got a newline */ bool fbuf; /* true if our buffer filled up */ int nr; /* number of bytes read */ int i; /* auxiliary index into outBuf */ - int max; /* limit for i (end of current data) */ - int nRead; /* (Temporary) number of bytes read */ + int max; /* limit for i (end of current data) */ + int nRead; /* (Temporary) number of bytes read */ /* * Read as many bytes as will fit in the buffer. @@ -1620,10 +1577,10 @@ end_loop: } /* - * 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. + * 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. */ if (nr == 0 && job->curPos != 0) { job->outBuf[job->curPos] = '\n'; @@ -1634,9 +1591,9 @@ end_loop: } /* - * Look for the last newline in the bytes we just got. If there - * is one, break out of the loop with 'i' as its index and - * gotNL set true. + * Look for the last newline in the bytes we just got. If there is + * one, break out of the loop with 'i' as its index and gotNL set + * true. */ max = job->curPos + nr; for (i = job->curPos + nr - 1; i >= job->curPos; i--) { @@ -1655,8 +1612,8 @@ end_loop: job->curPos += nr; if (job->curPos == JOB_BUFSIZE) { /* - * If we've run out of buffer space, we have no - * choice but to print the stuff. sigh. + * If we've run out of buffer space, we have no choice + * but to print the stuff. sigh. */ fbuf = true; i = job->curPos; @@ -1664,28 +1621,26 @@ end_loop: } 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 to the shell - * description), we print the line, preceded by a - * target banner if this target isn't the same as the - * one for which we last printed something. The rest - * of the data in the buffer are then shifted down to - * the start of the buffer and curPos is set - * accordingly. + * 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 + * to the shell description), we print the line, preceded + * by a target banner if this target isn't the same as the + * one for which we last printed something. + * The rest of the data in the buffer are then shifted down + * to the start of the buffer and curPos is set accordingly. */ job->outBuf[i] = '\0'; if (i >= job->curPos) { char *cp; - cp = JobOutput(job, job->outBuf, - &job->outBuf[i], false); + cp = JobOutput(job, job->outBuf, &job->outBuf[i], + 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. + * 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') { if (job->node != lastNode) { @@ -1705,21 +1660,20 @@ end_loop: } else { /* - * We have written everything out, so we just - * start over from the start of the buffer. No - * copying. No nothing. + * We have written everything out, so we just start over + * from the start of the buffer. No copying. No nothing. */ job->curPos = 0; } } if (finish) { /* - * 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 explicitly and the child - * has exited). When we do get an EOF, finish will be - * set false and we'll fall through and out. + * 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 explicitly and the child has exited). When + * we do get an EOF, finish will be set false and we'll fall + * through and out. */ goto end_loop; } @@ -1743,15 +1697,15 @@ end_loop: void Job_CatchChildren() { - pid_t pid; /* pid of dead child */ - Job *job; /* job descriptor for dead child */ - LstNode jnode; /* list element for finding job */ - int status; /* Exit/termination status */ + pid_t pid; /* pid of dead child */ + Job *job; /* job descriptor for dead child */ + LstNode jnode; /* list element for finding job */ + int status; /* Exit/termination status */ /* * Don't even bother if we know there's no one around. */ - if (nLocal == 0) { + if (nJobs == 0) { return; } @@ -1790,7 +1744,6 @@ Job_CatchChildren() (void)fflush(stdout); } jobFull = false; - nLocal--; } JobFinish(job, &status); @@ -1820,7 +1773,6 @@ Job_CatchOutput(void) int count = howmany(outputsn+1, NFDBITS) * sizeof(fd_mask); fd_set *readfdsp = malloc(count); - (void)fflush(stdout); if (readfdsp == NULL) return; @@ -1874,12 +1826,8 @@ Job_Make(GNode *gn) *----------------------------------------------------------------------- */ void -Job_Init(int maxproc, /* the greatest number of jobs which may be - * running at one time */ - int maxlocal) /* the greatest number of local jobs which may - * be running at once. */ +Job_Init(int maxproc) { - GNode *begin; /* node for commands to do at the very start */ int tfd; (void)strlcpy(tfile, TMPPAT, sizeof(tfile)); @@ -1891,9 +1839,6 @@ Job_Init(int maxproc, /* the greatest number of jobs which may be Static_Lst_Init(&jobs); Static_Lst_Init(&stoppedJobs); maxJobs = maxproc; - maxLocal = maxlocal; - nJobs = 0; - nLocal = 0; jobFull = false; aborting = 0; @@ -1948,16 +1893,13 @@ Job_Init(int maxproc, /* the greatest number of jobs which may be } #endif - begin = Targ_FindNode(".BEGIN", TARG_NOCREATE); - - if (begin != NULL) { - JobStart(begin, JOB_SPECIAL, (Job *)0); + if ((begin_node->type & OP_DUMMY) == 0) { + JobStart(begin_node, JOB_SPECIAL, (Job *)0); while (nJobs) { Job_CatchOutput(); Job_CatchChildren(); } } - postCommands = Targ_FindNode(".END", TARG_CREATE); } /*- @@ -2026,8 +1968,7 @@ JobInterrupt(int runINTERRUPT, /* Non-zero if commands for the .INTERRUPT int signo) /* signal received */ { LstNode ln; /* element in job table */ - Job *job; /* job descriptor in that element */ - GNode *interrupt; /* the node describing the .INTERRUPT target */ + Job *job; /* job descriptor in that element */ aborting = ABORT_INTERRUPT; @@ -2053,11 +1994,10 @@ JobInterrupt(int runINTERRUPT, /* Non-zero if commands for the .INTERRUPT } if (runINTERRUPT && !touchFlag) { - interrupt = Targ_FindNode(".INTERRUPT", TARG_NOCREATE); - if (interrupt != NULL) { + if ((interrupt_node->type & OP_DUMMY) == 0) { ignoreErrors = false; - JobStart(interrupt, JOB_IGNDOTS, (Job *)0); + JobStart(interrupt_node, JOB_IGNDOTS, (Job *)0); while (nJobs) { Job_CatchOutput(); Job_CatchChildren(); @@ -2085,11 +2025,11 @@ JobInterrupt(int runINTERRUPT, /* Non-zero if commands for the .INTERRUPT int Job_Finish(void) { - if (postCommands != NULL && !Lst_IsEmpty(&postCommands->commands)) { + if (end_node != NULL && !Lst_IsEmpty(&end_node->commands)) { if (errors) { Error("Errors reported so .END ignored"); } else { - JobStart(postCommands, JOB_SPECIAL | JOB_IGNDOTS, NULL); + JobStart(end_node, JOB_SPECIAL | JOB_IGNDOTS, NULL); while (nJobs) { Job_CatchOutput(); @@ -2101,20 +2041,10 @@ Job_Finish(void) return errors; } -/*- - *----------------------------------------------------------------------- - * Job_End -- - * Cleanup any memory used by the jobs module - * - * Side Effects: - * Memory is freed - *----------------------------------------------------------------------- - */ #ifdef CLEANUP void Job_End(void) { - efree(shellArgv); } #endif |