📄 job.c
字号:
GNode *gn; /* The target whose commands need * verifying */ void (*abortProc) __P((const char *, ...)); /* Function to abort with message */{ 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 * commands */ if ((DEFAULT != NILGNODE) && !Lst_IsEmpty(DEFAULT->commands)) { /* * Make only looks for a .DEFAULT if the node was never the * target of an operator, so that's what we do too. If * a .DEFAULT was given, we substitute its commands for gn's * commands and set the IMPSRC variable to be the target's name * The DEFAULT node acts like a transformation rule, in that * gn also inherits any attributes or sources attached to * .DEFAULT itself. */ Make_HandleUse(DEFAULT, gn); Var_Set (IMPSRC, Var_Value (TARGET, gn), gn); } 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 * nothing more we can do for this branch. If the -k flag wasn't * given, we stop in our tracks, otherwise we just don't update * this node's parents so they never get examined. */ if (gn->type & OP_OPTIONAL) { printf ("make: don't know how to make %s (ignored)\n", gn->name); } else if (keepgoing) { printf ("make: don't know how to make %s (continuing)\n", gn->name); return (FALSE); } else { (*abortProc) ("make: don't know how to make %s. Stop", gn->name); return(FALSE); } } } return (TRUE);}#ifdef RMT_WILL_WATCH/*- *----------------------------------------------------------------------- * JobLocalInput -- * Handle a pipe becoming readable. Callback function for Rmt_Watch * * Results: * None * * Side Effects: * JobDoOutput is called. * *----------------------------------------------------------------------- *//*ARGSUSED*/static voidJobLocalInput(stream, job) int stream; /* Stream that's ready (ignored) */ Job *job; /* Job to which the stream belongs */{ JobDoOutput(job, FALSE);}#endif /* RMT_WILL_WATCH *//*- *----------------------------------------------------------------------- * JobExec -- * Execute the shell for the given job. Called from JobStart and * JobRestart. * * Results: * None. * * Side Effects: * A shell is executed, outputs is altered and the Job structure added * to the job table. * *----------------------------------------------------------------------- */static voidJobExec(job, argv) Job *job; /* Job to execute */ char **argv;{ int cpid; /* ID of new child */ 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]); } printf("\n"); } /* * Some jobs produce no output and it's disconcerting to have * 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); lastNode = job->node; } #ifdef RMT_NO_EXEC if (job->flags & JOB_REMOTE) { goto jobExecFinish; }#endif /* RMT_NO_EXEC */ 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 * 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, 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); } 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); } /* * The output channels are marked close on exec. This bit was * 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);#ifdef USE_PGRP /* * We want to switch the child into a different process family so * 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 (void) execv (shellPath, argv); (void) write (2, "Could not execute shell\n", sizeof ("Could not execute shell")); _exit (1); } else { job->pid = cpid; if (usePipes && (job->flags & JOB_FIRST) ) { /* * The first time a job is run for a node, we set the current * position in the buffer to the beginning and mark another * stream to watch in the outputs mask */ job->curPos = 0; #ifdef RMT_WILL_WATCH Rmt_Watch(job->inPipe, JobLocalInput, job);#else FD_SET(job->inPipe, &outputs);#endif /* RMT_WILL_WATCH */ } if (job->flags & JOB_REMOTE) { job->rmtID = 0; } else { nLocal += 1; /* * XXX: Used to not happen if CUSTOMS. Why? */ if (job->cmdFILE != stdout) { fclose(job->cmdFILE); job->cmdFILE = NULL; } } }#ifdef RMT_NO_EXECjobExecFinish: #endif /* * Now the job is actually running, add it to the table. */ nJobs += 1; (void)Lst_AtEnd (jobs, (ClientData)job); if (nJobs == maxJobs) { jobFull = TRUE; }}/*- *----------------------------------------------------------------------- * JobMakeArgv -- * Create the argv needed to execute the shell for a given job. * * * Results: * * Side Effects: * *----------------------------------------------------------------------- */static voidJobMakeArgv(job, argv) Job *job; char **argv;{ int argc; static char args[10]; /* For merged arguments */ argv[0] = shellName; argc = 1; if ((commandShell->exit && (*commandShell->exit != '-')) || (commandShell->echo && (*commandShell->echo != '-'))) { /* * At least one of the flags doesn't have a minus before it, so * merge them together. Have to do this because the *(&(@*#*&#$# * Bourne shell thinks its second argument is a file to source. * Grrrr. Note the ten-character limitation on the combined arguments. */ (void)sprintf(args, "-%s%s", ((job->flags & JOB_IGNERR) ? "" : (commandShell->exit ? commandShell->exit : "")), ((job->flags & JOB_SILENT) ? "" : (commandShell->echo ? commandShell->echo : ""))); if (args[1]) { argv[argc] = args; argc++; } } else { if (!(job->flags & JOB_IGNERR) && commandShell->exit) { argv[argc] = commandShell->exit; argc++; } if (!(job->flags & JOB_SILENT) && commandShell->echo) { argv[argc] = commandShell->echo; argc++; } } argv[argc] = (char *)NULL;}/*- *----------------------------------------------------------------------- * JobRestart -- * Restart a job that stopped for some reason. * * Results: * None. * * Side Effects: * jobFull will be set if the job couldn't be run. * *----------------------------------------------------------------------- */static voidJobRestart(job) Job *job; /* Job to restart */{ if (job->flags & JOB_REMIGRATE) { if (DEBUG(JOB)) { printf("Remigrating %x\n", job->pid); } 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"); } KILL(job->pid, SIGCONT); nLocal +=1; job->flags &= ~(JOB_REMIGRATE|JOB_RESUME); } 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"); } (void)Lst_AtFront(stoppedJobs, (ClientData)job); jobFull = TRUE; if (DEBUG(JOB)) { printf("Job queue is full.\n"); } return; } (void)Lst_AtEnd(jobs, (ClientData)job); nJobs += 1; if (nJobs == maxJobs) { jobFull = TRUE; if (DEBUG(JOB)) { printf("Job queue is full.\n"); } } } else if (job->flags & JOB_RESTART) { /* * Set up the control arguments to the shell. This is based on the * flags set earlier for this job. If the JOB_IGNERR flag is clear, * the 'exit' flag of the commandShell is used to cause it to exit * upon receiving an error. If the JOB_SILENT flag is clear, the * 'echo' flag of the commandShell is used to get it to start echoing * as soon as it starts processing commands. */ char *argv[4]; JobMakeArgv(job, argv); if (DEBUG(JOB)) { printf("Restarting %s...", job->node->name); } 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)Lst_AtFront(stoppedJobs, (ClientData)job); jobFull = TRUE; if (DEBUG(JOB)) { printf("Job queue is full.\n"); } return; } else { /* * Job may be run locally. */ if (DEBUG(JOB)) { printf("running locally\n"); } job->flags &= ~JOB_REMOTE; } JobExec(job, argv); } else { /* * The job has stopped and needs to be restarted. Why it stopped, * we don't know... */ if (DEBUG(JOB)) { printf("Resuming %s...", job->node->name); } if (((job->flags & JOB_REMOTE) || (nLocal < maxLocal) || (((job->flags & JOB_SPECIAL)) && (maxLocal == 0))) && (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 * job must be run locally and maxLocal is 0), it's also ok to * resume it. */ Boolean error; extern int errno; union wait status; #ifdef RMT_WANTS_SIGNALS if (job->flags & JOB_REMOTE) { error = !Rmt_Signal(job, SIGCONT); } else#endif /* RMT_WANTS_SIGNALS */ error = (KILL(job->pid, SIGCONT) != 0); if (!error) { /* * Make sure the user knows we've continued the beast and * actually put the thing in the job table. */ job->flags |= JOB_CONTINUING; status.w_termsig = SIGCONT; JobFinish(job, status); job->flags &= ~(JOB_RESUME|JOB_CONTINUING); if (DEBUG(JOB)) { printf("done\n"); } } else { Error("couldn't resume %s: %s", job->node->name, strerror(errno)); status.w_status = 0; status.w_retcode = 1; JobFinish(job, status); } } 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("table full\n"); } (void)Lst_AtFront(stoppedJobs, (ClientData)job); jobFull = TRUE; if (DEBUG(JOB)) { printf("Job queue is full.\n"); } } }}/*- *----------------------------------------------------------------------- * JobStart -- * Start a target-creation process going for the target described * by the graph node gn. * * Results: * JOB_ERROR if there was an error in the commands, JOB_FINISHED * if there isn't actually anything left to do for the job and * JOB_RUNNING if the job has been started. * * Side Effects:
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -