Lines Matching refs:job
1 /* $NetBSD: job.c,v 1.519 2025/08/04 15:40:39 sjg Exp $ */
93 * job table is empty.
132 #include "job.h"
139 /* "@(#)job.c 8.2 (Berkeley) 3/19/94" */
140 MAKE_RCSID("$NetBSD: job.c,v 1.519 2025/08/04 15:40:39 sjg Exp $");
183 * Each job is run in a separate subprocess by a shell. Several jobs can run
190 * When a job is finished, Make_Update updates all parents of the node
224 int inPipe; /* Pipe for reading output from job */
229 /* Buffer for storing the output of the job, line by line. */
529 static char *targPrefix = NULL; /* To identify a job change in the output. */
531 static Job tokenPoolJob; /* token wait pseudo-job */
533 static Job childExitJob; /* child exit pseudo-job */
573 Job_FlagsToString(const Job *job, char *buf, size_t bufsize)
576 job->ignerr ? 'i' : '-',
577 !job->echo ? 's' : '-',
578 job->special ? 'S' : '-');
583 Job_BuildMon(Job *job)
585 return &job->bm;
590 Job_Node(Job *job)
592 return job->node;
596 Job_Pid(Job *job)
598 return job->pid;
604 const Job *job;
607 debug_printf("%s, job table:\n", where);
608 for (job = job_table; job < job_table_end; job++) {
609 Job_FlagsToString(job, flags, sizeof flags);
610 debug_printf("job %d, status %s, flags %s, pid %d\n",
611 (int)(job - job_table), JobStatus_Name[job->status],
612 flags, job->pid);
618 * unsuccessful job unless inhibited by .PRECIOUS.
673 JobCreatePipe(Job *job, int minfd)
690 job->inPipe = pipe_fds[0];
691 job->outPipe = pipe_fds[1];
693 SetCloseOnExec(job->inPipe);
694 SetCloseOnExec(job->outPipe);
698 * pipe when we're waiting for a job token, but we might lose the
702 SetNonblocking(job->inPipe);
705 /* Pass the signal to each running job. */
709 Job *job;
713 for (job = job_table; job < job_table_end; job++) {
714 if (job->status != JOB_ST_RUNNING)
717 signo, job->pid);
718 KILLPG(job->pid, signo);
771 /* Suppress job started/continued messages */
774 /* Pass the signal onto every job */
823 Job *job;
825 for (job = job_table; job < job_table_end; job++) {
826 if (job->status == status && job->pid == pid)
827 return job;
949 JobWriteSpecialsEchoCtl(Job *job, ShellWriter *wr, CommandFlags *inout_cmdFlags,
952 /* XXX: Why is the whole job modified at this point? */
953 job->ignerr = true;
955 if (job->echo && inout_cmdFlags->echo) {
976 JobWriteSpecials(Job *job, ShellWriter *wr, const char *escCmd, bool run,
982 ShellWriter_ErrOff(wr, job->echo && inout_cmdFlags->echo);
984 JobWriteSpecialsEchoCtl(job, wr, inout_cmdFlags, escCmd,
991 * Write a shell command to the job's commands file, to be run later.
997 * of the predefined shells has that), ignore errors for the rest of the job.
999 * XXX: Why ignore errors for the entire job? This is documented in the
1002 * If the command is just "...", attach all further commands of this job to
1006 JobWriteCommand(Job *job, ShellWriter *wr, StringListNode *ln, const char *ucmd)
1017 run = GNode_ShouldExecute(job->node);
1019 xcmd = Var_SubstInTarget(ucmd, job->node);
1033 (void)Compat_RunCommand(ucmd, job->node, ln);
1046 if (job->echo && run && shell->hasEchoCtl)
1053 JobWriteSpecials(job, wr, escCmd, run, &cmdFlags, &cmdTemplate);
1064 if (job->echo && cmdFlags.echo) {
1089 ShellWriter_ErrOn(wr, cmdFlags.echo && job->echo);
1104 JobWriteCommands(Job *job)
1110 wr.f = job->cmdFILE;
1113 for (ln = job->node->commands.first; ln != NULL; ln = ln->next) {
1117 job->node->type |= OP_SAVE_CMDS;
1118 job->tailCmds = ln->next;
1122 JobWriteCommand(job, &wr, ln, ln->datum);
1134 JobSaveCommands(Job *job)
1138 for (ln = job->tailCmds; ln != NULL; ln = ln->next) {
1146 expanded_cmd = Var_SubstInTarget(cmd, job->node);
1154 /* Close both input and output pipes when a job is finished. */
1156 JobClosePipes(Job *job)
1158 clearfd(job);
1159 (void)close(job->outPipe);
1160 job->outPipe = -1;
1162 CollectOutput(job, true);
1163 (void)close(job->inPipe);
1164 job->inPipe = -1;
1168 DebugFailedJob(const Job *job)
1176 debug_printf("*** Failed target: %s\n", job->node->name);
1179 for (ln = job->node->commands.first; ln != NULL; ln = ln->next) {
1184 char *xcmd = Var_Subst(cmd, job->node, VARE_EVAL);
1192 JobFinishDoneExitedError(Job *job, WAIT_T *inout_status)
1194 SwitchOutputTo(job->node);
1197 meta_job_error(job, job->node,
1198 job->ignerr, WEXITSTATUS(*inout_status));
1201 if (!shouldDieQuietly(job->node, -1)) {
1202 DebugFailedJob(job);
1204 job->node->name, WEXITSTATUS(*inout_status),
1205 job->ignerr ? " (ignored)" : "");
1208 if (job->ignerr)
1212 JobDeleteTarget(job->node);
1213 PrintOnError(job->node, "\n");
1218 JobFinishDoneExited(Job *job, WAIT_T *inout_status)
1221 job->node->name, job->pid);
1224 JobFinishDoneExitedError(job, inout_status);
1226 SwitchOutputTo(job->node);
1228 job->node->name, job->pid);
1233 JobFinishDoneSignaled(Job *job, WAIT_T status)
1235 SwitchOutputTo(job->node);
1236 DebugFailedJob(job);
1237 (void)printf("*** [%s] Signal %d\n", job->node->name, WTERMSIG(status));
1239 JobDeleteTarget(job->node);
1243 JobFinishDone(Job *job, WAIT_T *inout_status)
1246 JobFinishDoneExited(job, inout_status);
1248 JobFinishDoneSignaled(job, *inout_status);
1254 * Finish the job, add deferred commands to the .END node, mark the job as
1258 JobFinish (Job *job, WAIT_T status)
1263 job->node->name, job->pid, status);
1266 ((WEXITSTATUS(status) != 0 && !job->ignerr))) ||
1270 JobClosePipes(job);
1271 if (job->cmdFILE != NULL && job->cmdFILE != stdout) {
1272 if (fclose(job->cmdFILE) != 0)
1274 job->node->name, strerror(errno));
1275 job->cmdFILE = NULL;
1287 JobClosePipes(job);
1295 JobFinishDone(job, &status);
1299 int meta_status = meta_job_finish(job);
1307 Trace_Log(JOBEND, job);
1308 if (!job->special) {
1316 JobSaveCommands(job);
1317 job->node->made = MADE;
1318 if (!job->special)
1320 Make_Update(job->node);
1321 job->status = JOB_ST_FREE;
1324 job->status = JOB_ST_FREE;
1494 * Execute the shell for the given job.
1499 JobExec(Job *job, char **argv)
1507 debug_printf("Running %s\n", job->node->name);
1521 if (job->echo)
1522 SwitchOutputTo(job->node);
1524 /* No interruptions until this job is in the jobs table. */
1527 /* Pre-emptively mark job running, pid still zero though */
1528 job->status = JOB_ST_RUNNING;
1530 Var_ReexportVars(job->node);
1531 Var_ExportStackTrace(job->node->name, NULL);
1543 meta_job_child(job);
1554 if (dup2(fileno(job->cmdFILE), STDIN_FILENO) == -1)
1555 execDie("dup2", "job->cmdFILE");
1562 (job->node->type & (OP_MAKE | OP_SUBMAKE))) {
1563 /* Pass job token pipe to submakes. */
1572 if (dup2(job->outPipe, STDOUT_FILENO) == -1)
1573 execDie("dup2", "job->outPipe");
1608 job->pid = cpid;
1610 Trace_Log(JOBSTART, job);
1614 meta_job_parent(job, cpid);
1617 job->outBufLen = 0;
1619 watchfd(job);
1621 if (job->cmdFILE != NULL && job->cmdFILE != stdout) {
1622 if (fclose(job->cmdFILE) != 0)
1624 job->node->name, strerror(errno));
1625 job->cmdFILE = NULL;
1631 job->node->name, job->pid);
1632 JobTable_Dump("job started");
1638 BuildArgv(Job *job, char **argv)
1659 !job->ignerr && shell->errFlag != NULL
1661 job->echo && shell->echoFlag != NULL
1668 if (!job->ignerr && shell->errFlag != NULL) {
1672 if (job->echo && shell->echoFlag != NULL) {
1681 JobWriteShellCommands(Job *job, GNode *gn, bool *out_run)
1688 job->cmdFILE = fdopen(fd, "w+");
1689 if (job->cmdFILE == NULL)
1696 meta_job_start(job, gn);
1698 job->echo = false;
1702 *out_run = JobWriteCommands(job);
1708 Job *job;
1713 for (job = job_table; job < job_table_end; job++) {
1714 if (job->status == JOB_ST_FREE)
1717 if (job >= job_table_end)
1718 Punt("Job_Make no job slots vacant");
1720 memset(job, 0, sizeof *job);
1721 job->node = gn;
1722 job->tailCmds = NULL;
1723 job->status = JOB_ST_SET_UP;
1725 job->special = (gn->type & OP_SPECIAL) != OP_NONE;
1726 job->ignerr = opts.ignoreErrors || gn->type & OP_IGNORE;
1727 job->echo = !(opts.silent || gn->type & OP_SILENT);
1735 job->inPollfd = NULL;
1738 job->cmdFILE = stdout;
1755 JobWriteShellCommands(job, gn, &run);
1758 (void)fflush(job->cmdFILE);
1761 job->cmdFILE = stdout;
1763 JobWriteCommands(job);
1765 (void)fflush(job->cmdFILE);
1767 Job_Touch(gn, job->echo);
1772 if (!job->special)
1775 if (job->cmdFILE != NULL && job->cmdFILE != stdout) {
1776 (void)fclose(job->cmdFILE);
1777 job->cmdFILE = NULL;
1781 JobSaveCommands(job);
1782 job->node->made = MADE;
1783 Make_Update(job->node);
1785 job->status = JOB_ST_FREE;
1789 BuildArgv(job, argv);
1790 JobCreatePipe(job, 3);
1791 JobExec(job, argv);
1803 PrintFilteredOutput(Job *job, size_t len)
1805 const char *p = job->outBuf, *ep, *endp;
1814 SwitchOutputTo(job->node);
1828 * Collect output from the job. Print any complete lines.
1834 * If finish is true, collect all remaining output for the job.
1837 CollectOutput(Job *job, bool finish)
1845 nr = (size_t)read(job->inPipe, job->outBuf + job->outBufLen,
1846 JOB_BUFSIZE - job->outBufLen);
1858 if (nr == 0 && job->outBufLen > 0) {
1859 job->outBuf[job->outBufLen] = '\n';
1863 max = job->outBufLen + nr;
1864 job->outBuf[max] = '\0';
1866 for (i = job->outBufLen; i < max; i++)
1867 if (job->outBuf[i] == '\0')
1868 job->outBuf[i] = ' ';
1870 for (i = max; i > job->outBufLen; i--)
1871 if (job->outBuf[i - 1] == '\n')
1874 if (i == job->outBufLen) {
1875 job->outBufLen = max;
1881 p = PrintFilteredOutput(job, i);
1884 SwitchOutputTo(job->node);
1887 meta_job_output(job, p, (i < max) ? i : max);
1889 (void)fwrite(p, 1, (size_t)(job->outBuf + i - p), stdout);
1892 memmove(job->outBuf, job->outBuf + i, max - i);
1893 job->outBufLen = max - i;
1938 Job *job;
1943 job = JobFindPid(pid, JOB_ST_RUNNING, isJobs);
1944 if (job == NULL) {
1953 job->node->name, job->pid);
1958 job->node->name);
1962 job->node->name);
1966 job->node->name, WSTOPSIG(status));
1968 job->suspended = true;
1974 job->status = JOB_ST_FINISHED;
1975 job->exit_status = WAIT_STATUS(status);
1977 job->node->exit_status = WEXITSTATUS(status);
1979 JobFinish(job, status);
1983 Job_Continue(Job *job)
1985 DEBUG1(JOB, "Continuing pid %d\n", job->pid);
1986 if (job->suspended) {
1987 (void)printf("*** [%s] Continued\n", job->node->name);
1989 job->suspended = false;
1991 if (KILLPG(job->pid, SIGCONT) != 0)
1992 DEBUG1(JOB, "Failed to send SIGCONT to pid %d\n", job->pid);
1998 Job *job;
2000 for (job = job_table; job < job_table_end; job++) {
2001 if (job->status == JOB_ST_RUNNING &&
2002 (make_suspended || job->suspended))
2003 Job_Continue(job);
2004 else if (job->status == JOB_ST_FINISHED)
2005 JobFinish(job, job->exit_status);
2014 Job *job;
2020 /* Maybe skip the job token pipe. */
2046 job = jobByFdIndex[i];
2047 if (job->status == JOB_ST_RUNNING)
2048 CollectOutput(job, false);
2051 * With meta mode, we may have activity on the job's filemon
2053 * than job->inPollfd.
2055 if (useMeta && job->inPollfd != &fds[i]) {
2056 if (meta_job_event(job) <= 0)
2204 * These signals need to be passed to the jobs, as each job has its
2440 Job *job;
2447 for (job = job_table; job < job_table_end; job++) {
2448 if (job->status == JOB_ST_RUNNING && job->pid != 0) {
2451 signo, job->pid);
2452 KILLPG(job->pid, signo);
2456 for (job = job_table; job < job_table_end; job++) {
2457 if (job->status == JOB_ST_RUNNING && job->pid != 0) {
2459 (void)waitpid(job->pid, &status, 0);
2460 JobDeleteTarget(job->node);
2477 /* Make the .END target, returning the number of job-related errors. */
2518 Job *job;
2524 for (job = job_table; job < job_table_end; job++) {
2525 if (job->status != JOB_ST_RUNNING)
2527 KILLPG(job->pid, SIGINT);
2528 KILLPG(job->pid, SIGKILL);
2537 watchfd(Job *job)
2539 if (job->inPollfd != NULL)
2540 Punt("Watching watched job");
2542 fds[fdsLen].fd = job->inPipe;
2544 jobByFdIndex[fdsLen] = job;
2545 job->inPollfd = &fds[fdsLen];
2549 fds[fdsLen].fd = meta_job_fd(job);
2551 jobByFdIndex[fdsLen] = job;
2558 clearfd(Job *job)
2561 if (job->inPollfd == NULL)
2562 Punt("Unwatching unwatched job");
2563 i = (size_t)(job->inPollfd - fds);
2573 /* Move last job in table into hole made by dead job. */
2585 job->inPollfd = NULL;
2612 * Put a token (back) into the job token pool.
2613 * This allows a make process to start a build job.
2648 /* Prepare the job token pipe in the root make process. */
2664 * Preload the job pipe with one token per job, save the one
2665 * "extra" token for the primary job.
2716 Fatal("eof on job pipe");
2719 Fatal("job pipe read: %s", strerror(errno));
2727 /* make being aborted - remove any other job tokens */