📄 job.c
字号:
if (job->node != lastNode) { printf (targFmt, job->node->name); lastNode = job->node; } printf ("%s\n", cp); } 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); } else { /* * 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. */ goto end_loop; } } else { /* * We've been called to retrieve the output of the job from the * temporary file where it's been squirreled away. This consists of * opening the file, reading the output line by line, being sure not * to print the noPrint line for the shell we used, then close and * remove the temporary file. Very simple. * * 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; cp = inLine; 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; } } } /* * 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); } } fclose (oFILE); (void) unlink (job->outFile); } } fflush(stdout);}/*- *----------------------------------------------------------------------- * Job_CatchChildren -- * Handle the exit of a child. Called from Make_Make. * * Results: * none. * * Side Effects: * The job descriptor is removed from the list of children. * * Notes: * We do waits, blocking or not, according to the wisdom of our * caller, until there are no more children to report. For each * job, call JobFinish to finish things off. This will take care of * putting jobs on the stoppedJobs queue. * *----------------------------------------------------------------------- */voidJob_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 */ /* * Don't even bother if we know there's no one around. */ if (nLocal == 0) { return; } while ((pid = wait3((int *)&status, (block?0:WNOHANG)|WUNTRACED, (struct rusage *)0)) > 0) { if (DEBUG(JOB)) printf("Process %d exited or stopped.\n", pid); jnode = Lst_Find (jobs, (ClientData)pid, JobCmpPid); if (jnode == NILLNODE) { if (WIFSIGNALED(status) && (status.w_termsig == SIGCONT)) { jnode = Lst_Find(stoppedJobs, (ClientData)pid, JobCmpPid); if (jnode == NILLNODE) { Error("Resumed child (%d) not in table", pid); continue; } job = (Job *)Lst_Datum(jnode); (void)Lst_Remove(stoppedJobs, jnode); } else { Error ("Child (%d) not in table?", pid); continue; } } else { job = (Job *) Lst_Datum (jnode); (void)Lst_Remove (jobs, jnode); nJobs -= 1; if (jobFull && DEBUG(JOB)) { printf("Job queue is no longer full.\n"); } jobFull = FALSE; nLocal -= 1; } JobFinish (job, status); }}/*- *----------------------------------------------------------------------- * 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 * just spinning when there's nothing to do and the reaping * of a child can wait for a while. * * Results: * None * * Side Effects: * Output is read from pipes if we're piping. * ----------------------------------------------------------------------- */voidJob_CatchOutput (){ int nfds; struct timeval timeout; fd_set readfds; register LstNode ln; register Job *job;#ifdef RMT_WILL_WATCH int pnJobs; /* Previous nJobs */#endif fflush(stdout);#ifdef RMT_WILL_WATCH pnJobs = nJobs; /* * It is possible for us to be called with nJobs equal to 0. This happens * if all the jobs finish and a job that is stopped cannot be run * locally (eg if maxLocal is 0) and cannot be exported. The job will * be placed back on the stoppedJobs queue, Job_Empty() will return false, * Make_Run will call us again when there's nothing for which to wait. * nJobs never changes, so we loop forever. Hence the check. It could * be argued that we should sleep for a bit so as not to swamp the * exportation system with requests. Perhaps we should. * * 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 * wait...) */ while (nJobs != 0 && pnJobs == nJobs) { Rmt_Wait(); }#else if (usePipes) { readfds = outputs; timeout.tv_sec = SEL_SEC; timeout.tv_usec = SEL_USEC; 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"); } while (nfds && (ln = Lst_Next (jobs)) != NILLNODE) { job = (Job *) Lst_Datum (ln); if (FD_ISSET(job->inPipe, &readfds)) { JobDoOutput (job, FALSE); nfds -= 1; } } Lst_Close (jobs); } }#endif /* RMT_WILL_WATCH */}/*- *----------------------------------------------------------------------- * Job_Make -- * Start the creation of a target. Basically a front-end for * JobStart used by the Make module. * * Results: * None. * * Side Effects: * Another job is started. * *----------------------------------------------------------------------- */voidJob_Make (gn) GNode *gn;{ (void)JobStart (gn, 0, (Job *)NULL);}/*- *----------------------------------------------------------------------- * Job_Init -- * Initialize the process module * * Results: * none * * Side Effects: * lists and counters are initialized *----------------------------------------------------------------------- */voidJob_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 * be running at once. */{ GNode *begin; /* node for commands to do at the very start */ sprintf (tfile, "/tmp/make%05d", getpid()); jobs = Lst_Init (FALSE); stoppedJobs = Lst_Init(FALSE); maxJobs = maxproc; maxLocal = maxlocal; nJobs = 0; nLocal = 0; jobFull = FALSE; aborting = 0; errors = 0; lastNode = NILGNODE; if (maxJobs == 1) { /* * If only one job can run at a time, there's no need for a banner, * no is there? */ targFmt = ""; } else { targFmt = TARG_FMT; } if (shellPath == (char *) 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 * must be set. The last component is taken from the 'name' field * of the default shell description pointed-to by commandShell. * All default shells are located in _PATH_DEFSHELLDIR. */ shellName = commandShell->name; shellPath = str_concat (_PATH_DEFSHELLDIR, shellName, STR_ADDSLASH); } if (commandShell->exit == (char *)NULL) { commandShell->exit = ""; } if (commandShell->echo == (char *)NULL) { commandShell->echo = ""; } /* * 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 (SIGHUP, SIG_IGN) != SIG_IGN) { signal (SIGHUP, JobPassSig); } if (signal (SIGQUIT, SIG_IGN) != SIG_IGN) { signal (SIGQUIT, JobPassSig); } if (signal (SIGTERM, SIG_IGN) != SIG_IGN) { 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 * 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 (SIGTTOU, SIG_IGN) != SIG_IGN) { signal (SIGTTOU, JobPassSig); } if (signal (SIGTTIN, SIG_IGN) != SIG_IGN) { signal (SIGTTIN, JobPassSig); } if (signal (SIGWINCH, SIG_IGN) != SIG_IGN) { signal (SIGWINCH, JobPassSig); }#endif begin = Targ_FindNode (".BEGIN", TARG_NOCREATE); if (begin != NILGNODE) { JobStart (begin, JOB_SPECIAL, (Job *)0); while (nJobs) { Job_CatchOutput();#ifndef RMT_WILL_WATCH Job_CatchChildren (!usePipes);#endif /* RMT_WILL_WATCH */ } } postCommands = Targ_FindNode (".END", TARG_CREATE);}/*- *----------------------------------------------------------------------- * Job_Full -- * See if the job table is full. It is considered full if it is OR * if we are in the process of aborting OR if we have * reached/exceeded our local quota. This prevents any more jobs * from starting up. * * Results: * TRUE if the job table is full, FALSE otherwise * Side Effects: * None. *----------------------------------------------------------------------- */BooleanJob_Full (){ return (aborting || jobFull);}/*- *----------------------------------------------------------------------- * Job_Empty -- * See if the job table is empty. Because the local concurrency may * be set to 0, it is possible for the job table to become empty, * while the list of stoppedJobs remains non-empty. In such a case, * we want to restart as many jobs as we can. * * Results: * TRUE if it is. FALSE if it ain't. * * Side Effects: * None. * * ----------------------------------------------------------------------- */BooleanJob_Empty (){ if (nJobs == 0) { if (!Lst_IsEmpty(stoppedJobs) && !aborting) { /* * The job table is obviously not full if it has no jobs in * it...Try and restart the stopped jobs. */ jobFull = FALSE; while (!jobFull && !Lst_IsEmpty(stoppedJobs)) { JobRestart((Job *)Lst_DeQueue(stoppedJobs)); } return(FALSE); } else { return(TRUE); } } else { return(FALSE); }}/*- *----------------------------------------------------------------------- * JobMatch
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -