Home | History | Annotate | Download | only in make

Lines Matching defs:Job

1 /*	$NetBSD: job.c,v 1.519 2025/08/04 15:40:39 sjg Exp $	*/
93 * job table is empty.
119 #include "job.h"
126 /* "@(#)job.c 8.2 (Berkeley) 3/19/94" */
127 MAKE_RCSID("$NetBSD: job.c,v 1.519 2025/08/04 15:40:39 sjg Exp $");
155 JOB_ST_FREE, /* Job is available */
156 JOB_ST_SET_UP, /* Job is allocated but otherwise invalid */
157 JOB_ST_RUNNING, /* Job is running, pid valid */
158 JOB_ST_FINISHED /* Job is done (i.e. after SIGCHLD) */
169 * A Job manages the shell commands that are run to create a single target.
170 * Each job is run in a separate subprocess by a shell. Several jobs can run
177 * When a job is finished, Make_Update updates all parents of the node
181 struct Job {
211 int inPipe; /* Pipe for reading output from job */
216 /* Buffer for storing the output of the job, line by line. */
484 static Job *job_table; /* The structures that describe them */
485 static Job *job_table_end; /* job_table + maxJobs */
495 static Job **jobByFdIndex = NULL;
497 static void watchfd(Job *);
498 static void clearfd(Job *);
500 static char *targPrefix = NULL; /* To identify a job change in the output. */
502 static Job tokenPoolJob; /* token wait pseudo-job */
504 static Job childExitJob; /* child exit pseudo-job */
515 static void CollectOutput(Job *, bool);
544 Job_FlagsToString(const Job *job, char *buf, size_t bufsize)
547 job->ignerr ? 'i' : '-',
548 !job->echo ? 's' : '-',
549 job->special ? 'S' : '-');
554 Job_BuildMon(Job *job)
556 return &job->bm;
561 Job_Node(Job *job)
563 return job->node;
567 Job_Pid(Job *job)
569 return job->pid;
575 const Job *job;
578 debug_printf("%s, job table:\n", where);
579 for (job = job_table; job < job_table_end; job++) {
580 Job_FlagsToString(job, flags, sizeof flags);
581 debug_printf("job %d, status %s, flags %s, pid %d\n",
582 (int)(job - job_table), JobStatus_Name[job->status],
583 flags, job->pid);
589 * unsuccessful job unless inhibited by .PRECIOUS.
644 JobCreatePipe(Job *job, int minfd)
661 job->inPipe = pipe_fds[0];
662 job->outPipe = pipe_fds[1];
664 SetCloseOnExec(job->inPipe);
665 SetCloseOnExec(job->outPipe);
669 * pipe when we're waiting for a job token, but we might lose the
673 SetNonblocking(job->inPipe);
676 /* Pass the signal to each running job. */
680 Job *job;
682 DEBUG1(JOB, "JobCondPassSig: signal %d\n", signo);
684 for (job = job_table; job < job_table_end; job++) {
685 if (job->status != JOB_ST_RUNNING)
687 DEBUG2(JOB, "JobCondPassSig passing signal %d to pid %d\n",
688 signo, job->pid);
689 KILLPG(job->pid, signo);
742 /* Suppress job started/continued messages */
745 /* Pass the signal onto every job */
763 DEBUG1(JOB, "JobPassSig_suspend passing signal %d to self\n", signo);
791 static Job *
794 Job *job;
796 for (job = job_table; job < job_table_end; job++) {
797 if (job->status == status && job->pid == pid)
798 return job;
800 if (DEBUG(JOB) && isJobs)
852 DEBUG1(JOB, fmt, arg);
920 JobWriteSpecialsEchoCtl(Job *job, ShellWriter *wr, CommandFlags *inout_cmdFlags,
923 /* XXX: Why is the whole job modified at this point? */
924 job->ignerr = true;
926 if (job->echo && inout_cmdFlags->echo) {
947 JobWriteSpecials(Job *job, ShellWriter *wr, const char *escCmd, bool run,
953 ShellWriter_ErrOff(wr, job->echo && inout_cmdFlags->echo);
955 JobWriteSpecialsEchoCtl(job, wr, inout_cmdFlags, escCmd,
962 * Write a shell command to the job's commands file, to be run later.
968 * of the predefined shells has that), ignore errors for the rest of the job.
970 * XXX: Why ignore errors for the entire job? This is documented in the
973 * If the command is just "...", attach all further commands of this job to
977 JobWriteCommand(Job *job, ShellWriter *wr, StringListNode *ln, const char *ucmd)
988 run = GNode_ShouldExecute(job->node);
990 xcmd = Var_SubstInTarget(ucmd, job->node);
1004 (void)Compat_RunCommand(ucmd, job->node, ln);
1017 if (job->echo && run && shell->hasEchoCtl)
1024 JobWriteSpecials(job, wr, escCmd, run, &cmdFlags, &cmdTemplate);
1035 if (job->echo && cmdFlags.echo) {
1060 ShellWriter_ErrOn(wr, cmdFlags.echo && job->echo);
1075 JobWriteCommands(Job *job)
1081 wr.f = job->cmdFILE;
1084 for (ln = job->node->commands.first; ln != NULL; ln = ln->next) {
1088 job->node->type |= OP_SAVE_CMDS;
1089 job->tailCmds = ln->next;
1093 JobWriteCommand(job, &wr, ln, ln->datum);
1105 JobSaveCommands(Job *job)
1109 for (ln = job->tailCmds; ln != NULL; ln = ln->next) {
1117 expanded_cmd = Var_SubstInTarget(cmd, job->node);
1125 /* Close both input and output pipes when a job is finished. */
1127 JobClosePipes(Job *job)
1129 clearfd(job);
1130 (void)close(job->outPipe);
1131 job->outPipe = -1;
1133 CollectOutput(job, true);
1134 (void)close(job->inPipe);
1135 job->inPipe = -1;
1139 DebugFailedJob(const Job *job)
1147 debug_printf("*** Failed target: %s\n", job->node->name);
1150 for (ln = job->node->commands.first; ln != NULL; ln = ln->next) {
1155 char *xcmd = Var_Subst(cmd, job->node, VARE_EVAL);
1163 JobFinishDoneExitedError(Job *job, int *inout_status)
1165 SwitchOutputTo(job->node);
1168 meta_job_error(job, job->node,
1169 job->ignerr, WEXITSTATUS(*inout_status));
1172 if (!shouldDieQuietly(job->node, -1)) {
1173 DebugFailedJob(job);
1175 job->node->name, WEXITSTATUS(*inout_status),
1176 job->ignerr ? " (ignored)" : "");
1179 if (job->ignerr)
1183 JobDeleteTarget(job->node);
1184 PrintOnError(job->node, "\n");
1189 JobFinishDoneExited(Job *job, int *inout_status)
1191 DEBUG2(JOB, "Target %s, pid %d exited\n",
1192 job->node->name, job->pid);
1195 JobFinishDoneExitedError(job, inout_status);
1196 else if (DEBUG(JOB)) {
1197 SwitchOutputTo(job->node);
1199 job->node->name, job->pid);
1204 JobFinishDoneSignaled(Job *job, int status)
1206 SwitchOutputTo(job->node);
1207 DebugFailedJob(job);
1208 (void)printf("*** [%s] Signal %d\n", job->node->name, WTERMSIG(status));
1210 JobDeleteTarget(job
1214 JobFinishDone(Job *job, int *inout_status)
1217 JobFinishDoneExited(job, inout_status);
1219 JobFinishDoneSignaled(job, *inout_status);
1225 * Finish the job, add deferred commands to the .END node, mark the job as
1229 JobFinish(Job *job, int status)
1233 DEBUG3(JOB, "JobFinish: target %s, pid %d, status %#x\n",
1234 job->node->name, job->pid, status);
1237 ((WEXITSTATUS(status) != 0 && !job->ignerr))) ||
1241 JobClosePipes(job);
1242 if (job->cmdFILE != NULL && job->cmdFILE != stdout) {
1243 if (fclose(job->cmdFILE) != 0)
1245 job->node->name, strerror(errno));
1246 job->cmdFILE = NULL;
1258 JobClosePipes(job);
1266 JobFinishDone(job, &status);
1270 int meta_status = meta_job_finish(job);
1278 Trace_Log(JOBEND, job);
1279 if (!job->special) {
1287 JobSaveCommands(job);
1288 job->node->made = MADE;
1289 if (!job->special)
1291 Make_Update(job->node);
1292 job->status = JOB_ST_FREE;
1295 job->status = JOB_ST_FREE;
1465 * Execute the shell for the given job.
1470 JobExec(Job *job, char **argv)
1475 if (DEBUG(JOB)) {
1478 debug_printf("Running %s\n", job->node->name);
1492 if (job->echo)
1493 SwitchOutputTo(job->node);
1495 /* No interruptions until this job is in the jobs table. */
1498 /* Pre-emptively mark job running, pid still zero though */
1499 job->status = JOB_ST_RUNNING;
1501 Var_ReexportVars(job->node);
1502 Var_ExportStackTrace(job->node->name, NULL);
1514 meta_job_child(job);
1525 if (dup2(fileno(job->cmdFILE), STDIN_FILENO) == -1)
1526 execDie("dup2", "job->cmdFILE");
1532 if (job->node->type & (OP_MAKE | OP_SUBMAKE)) {
1533 /* Pass job token pipe to submakes. */
1542 if (dup2(job->outPipe, STDOUT_FILENO) == -1)
1543 execDie("dup2", "job->outPipe");
1576 job->pid = cpid;
1578 Trace_Log(JOBSTART, job);
1582 meta_job_parent(job, cpid);
1585 job->outBufLen = 0;
1587 watchfd(job);
1589 if (job->cmdFILE != NULL && job->cmdFILE != stdout) {
1590 if (fclose(job->cmdFILE) != 0)
1592 job->node->name, strerror(errno));
1593 job->cmdFILE = NULL;
1596 if (DEBUG(JOB)) {
1599 job->node->name, job->pid);
1600 JobTable_Dump("job started");
1606 BuildArgv(Job *job, char **argv)
1627 !job->ignerr && shell->errFlag != NULL
1629 job->echo && shell->echoFlag != NULL
1636 if (!job->ignerr && shell->errFlag != NULL) {
1640 if (job->echo && shell->echoFlag != NULL) {
1649 JobWriteShellCommands(Job *job, GNode *gn, bool *out_run)
1656 job->cmdFILE = fdopen(fd, "w+");
1657 if (job->cmdFILE == NULL)
1664 meta_job_start(job, gn);
1666 job->echo = false;
1670 *out_run = JobWriteCommands(job);
1676 Job *job;
1681 for (job = job_table; job < job_table_end; job++) {
1682 if (job->status == JOB_ST_FREE)
1685 if (job >= job_table_end)
1686 Punt("Job_Make no job slots vacant");
1688 memset(job, 0, sizeof *job);
1689 job->node = gn;
1690 job->tailCmds = NULL;
1691 job->status = JOB_ST_SET_UP;
1693 job->special = (gn->type & OP_SPECIAL) != OP_NONE;
1694 job->ignerr = opts.ignoreErrors || gn->type & OP_IGNORE;
1695 job->echo = !(opts.silent || gn->type & OP_SILENT);
1703 job->inPollfd = NULL;
1706 job->cmdFILE = stdout;
1723 JobWriteShellCommands(job, gn, &run);
1726 (void)fflush(job->cmdFILE);
1729 job->cmdFILE = stdout;
1731 JobWriteCommands(job);
1733 (void)fflush(job->cmdFILE);
1735 Job_Touch(gn, job->echo);
1740 if (!job->special)
1743 if (job->cmdFILE != NULL && job->cmdFILE != stdout) {
1744 (void)fclose(job->cmdFILE);
1745 job->cmdFILE = NULL;
1749 JobSaveCommands(job);
1750 job->node->made = MADE;
1751 Make_Update(job->node);
1753 job->status = JOB_ST_FREE;
1757 BuildArgv(job, argv);
1758 JobCreatePipe(job, 3);
1759 JobExec(job, argv);
1771 PrintFilteredOutput(Job *job, size_t len)
1773 const char *p = job->outBuf, *ep, *endp;
1782 SwitchOutputTo(job->node);
1796 * Collect output from the job. Print any complete lines.
1802 * If finish is true, collect all remaining output for the job.
1805 CollectOutput(Job *job, bool finish)
1813 nr = (size_t)read(job->inPipe, job->outBuf + job->outBufLen,
1814 JOB_BUFSIZE - job->outBufLen);
1818 if (DEBUG(JOB))
1826 if (nr == 0 && job->outBufLen > 0) {
1827 job->outBuf[job->outBufLen] = '\n';
1831 max = job->outBufLen + nr;
1832 job->outBuf[max] = '\0';
1834 for (i = job->outBufLen; i < max; i++)
1835 if (job->outBuf[i] == '\0')
1836 job->outBuf[i] = ' ';
1838 for (i = max; i > job->outBufLen; i--)
1839 if (job->outBuf[i - 1] == '\n')
1842 if (i == job->outBufLen) {
1843 job->outBufLen = max;
1849 p = PrintFilteredOutput(job, i);
1852 SwitchOutputTo(job->node);
1855 meta_job_output(job, p, (i < max) ? i : max);
1857 (void)fwrite(p, 1, (size_t)(job->outBuf + i - p), stdout);
1860 memmove(job->outBuf, job->outBuf + i, max - i);
1861 job->outBufLen = max - i;
1892 DEBUG2(JOB,
1906 Job *job;
1911 job = JobFindPid(pid, JOB_ST_RUNNING, isJobs);
1912 if (job
1920 DEBUG2(JOB, "Process for target %s, pid %d stopped\n",
1921 job->node->name, job->pid);
1926 job->node->name);
1930 job->node->name);
1934 job->node->name, WSTOPSIG(status));
1936 job->suspended = true;
1942 job->status = JOB_ST_FINISHED;
1943 job->exit_status = status;
1945 job->node->exit_status = WEXITSTATUS(status);
1947 JobFinish(job, status);
1951 Job_Continue(Job *job)
1953 DEBUG1(JOB, "Continuing pid %d\n", job->pid);
1954 if (job->suspended) {
1955 (void)printf("*** [%s] Continued\n", job->node->name);
1957 job->suspended = false;
1959 if (KILLPG(job->pid, SIGCONT) != 0)
1960 DEBUG1(JOB, "Failed to send SIGCONT to pid %d\n", job->pid);
1966 Job *job;
1968 for (job = job_table; job < job_table_end; job++) {
1969 if (job->status == JOB_ST_RUNNING &&
1970 (make_suspended || job->suspended))
1971 Job_Continue(job);
1972 else if (job->status == JOB_ST_FINISHED)
1973 JobFinish(job, job->exit_status);
1982 Job *job;
1988 /* Maybe skip the job token pipe. */
2014 job = jobByFdIndex[i];
2015 if (job->status == JOB_ST_RUNNING)
2016 CollectOutput(job, false);
2019 * With meta mode, we may have activity on the job's filemon
2021 * than job->inPollfd.
2023 if (useMeta && job->inPollfd != &fds[i]) {
2024 if (meta_job_event(job) <= 0)
2087 else if (!Var_Exists(SCOPE_GLOBAL, ".MAKE.JOB.PREFIX"))
2088 Global_Set(".MAKE.JOB.PREFIX", "---");
2090 targPrefix = Var_Subst("${.MAKE.JOB.PREFIX}",
2161 * These signals need to be passed to the jobs, as each job has its
2397 Job *job;
2404 for (job = job_table; job < job_table_end; job++) {
2405 if (job->status == JOB_ST_RUNNING && job->pid != 0) {
2406 DEBUG2(JOB,
2408 signo, job->pid);
2409 KILLPG(job->pid, signo);
2413 for (job = job_table; job < job_table_end; job++) {
2414 if (job->status == JOB_ST_RUNNING && job->pid != 0) {
2416 (void)waitpid(job->pid, &status, 0);
2417 JobDeleteTarget(job->node);
2434 /* Make the .END target, returning the number of job-related errors. */
2475 Job *job;
2481 for (job = job_table; job < job_table_end; job++) {
2482 if (job->status != JOB_ST_RUNNING)
2484 KILLPG(job->pid, SIGINT);
2485 KILLPG(job->pid, SIGKILL);
2494 watchfd(Job *job)
2496 if (job->inPollfd != NULL)
2497 Punt("Watching watched job");
2499 fds[fdsLen].fd = job->inPipe;
2501 jobByFdIndex[fdsLen] = job;
2502 job->inPollfd = &fds[fdsLen];
2506 fds[fdsLen].fd = meta_job_fd(job);
2508 jobByFdIndex[fdsLen] = job;
2515 clearfd(Job *job)
2518 if (job->inPollfd == NULL)
2519 Punt("Unwatching unwatched job");
2520 i = (size_t)(job->inPollfd - fds);
2530 /* Move last job in table into hole made by dead job. */
2542 job->inPollfd = NULL;
2569 * Put a token (back) into the job token pool.
2570 * This allows a make process to start a build job.
2581 DEBUG3(JOB, "TokenPool_Add: pid %d, aborting %s, token %c\n",
2595 /* Prepare the job token pipe in the root make process. */
2611 * Preload the job pipe with one token per job, save the one
2612 * "extra" token for the primary job.
2655 DEBUG3(JOB, "TokenPool_Take: pid %d, aborting %s, running %d\n",
2663 Fatal("eof on job pipe");
2666 Fatal("job pipe read: %s", strerror(errno));
2667 DEBUG1(JOB, "TokenPool_Take: pid %d blocked for token\n",
2674 /* make being aborted - remove any other job tokens */
2675 DEBUG2(JOB, "TokenPool_Take: pid %d aborted by token %c\n",
2694 DEBUG1(JOB, "TokenPool_Take: pid %d took a token\n", getpid());