[BACK]Return to job.c CVS log [TXT][DIR] Up to [local] / src / usr.bin / make

Diff for /src/usr.bin/make/job.c between version 1.75 and 1.76

version 1.75, 2007/09/17 11:48:13 version 1.76, 2007/09/17 12:01:16
Line 132 
Line 132 
  *         commands.   *         commands.
  *      4) An FILE* for writing out the commands. This is only   *      4) An FILE* for writing out the commands. This is only
  *         used before the job is actually started.   *         used before the job is actually started.
  *      5) A union of things used for handling the shell's output. Different   *      5) Things used for handling the shell's output.
  *         parts of the union are used based on the value of the usePipes   *         the output is being caught via a pipe and
  *         flag. If it is true, the output is being caught via a pipe and  
  *         the descriptors of our pipe, an array in which output is line   *         the descriptors of our pipe, an array in which output is line
  *         buffered and the current position in that buffer are all   *         buffered and the current position in that buffer are all
  *         maintained for each job. If, on the other hand, usePipes is false,   *         maintained for each job.
  *         the output is routed to a temporary file and all that is kept  
  *         is the name of the file and the descriptor open to the file.  
  *      6) An identifier provided by and for the exclusive use of the   *      6) An identifier provided by and for the exclusive use of the
  *         Rmt module.   *         Rmt module.
  *      7) A word of flags which determine how the module handles errors,   *      7) A word of flags which determine how the module handles errors,
Line 176 
Line 173 
 #define JOB_CONTINUING  0x200   /* We are in the process of resuming this job.  #define JOB_CONTINUING  0x200   /* We are in the process of resuming this job.
                                  * Used to avoid infinite recursion between                                   * Used to avoid infinite recursion between
                                  * JobFinish and JobRestart */                                   * JobFinish and JobRestart */
     union {      int         inPipe;         /* Input side of pipe associated
         struct {                                   * with job's output channel */
             int         op_inPipe;      /* Input side of pipe associated      int         outPipe;        /* Output side of pipe associated with
                                          * with job's output channel */                                   * job's output channel */
             int         op_outPipe;     /* Output side of pipe associated with      char        outBuf[JOB_BUFSIZE + 1];
                                          * job's output channel */                                  /* Buffer for storing the output of the
             char        op_outBuf[JOB_BUFSIZE + 1];                                   * job, line by line */
                                         /* Buffer for storing the output of the      int         curPos;         /* Current position in op_outBuf */
                                          * job, line by line */  
             int         op_curPos;      /* Current position in op_outBuf */  
         }           o_pipe;         /* data used when catching the output via  
                                      * a pipe */  
         struct {  
             char        of_outFile[sizeof(TMPPAT)];  
                                         /* Name of file to which shell output  
                                          * was rerouted */  
             int         of_outFd;       /* Stream open to the output  
                                          * file. Used to funnel all  
                                          * from a single job to one file  
                                          * while still allowing  
                                          * multiple shell invocations */  
         }           o_file;         /* Data used when catching the output in  
                                      * a temporary file */  
     }           output;     /* Data for tracking a shell's output */  
 } Job;  } Job;
   
 #define outPipe         output.o_pipe.op_outPipe  
 #define inPipe          output.o_pipe.op_inPipe  
 #define outBuf          output.o_pipe.op_outBuf  
 #define curPos          output.o_pipe.op_curPos  
 #define outFile         output.o_file.of_outFile  
 #define outFd           output.o_file.of_outFd  
   
 /*  /*
  * error handling variables   * error handling variables
  */   */
Line 716 
Line 690 
 static void  static void
 JobClose(Job *job)  JobClose(Job *job)
 {  {
         if (usePipes) {          FD_CLR(job->inPipe, outputsp);
                 FD_CLR(job->inPipe, outputsp);          if (job->outPipe != job->inPipe) {
                 if (job->outPipe != job->inPipe) {                 (void)close(job->outPipe);
                        (void)close(job->outPipe);  
                 }  
                 JobDoOutput(job, true);  
                 (void)close(job->inPipe);  
         } else {  
                 (void)close(job->outFd);  
                 JobDoOutput(job, true);  
         }          }
           JobDoOutput(job, true);
           (void)close(job->inPipe);
 }  }
   
 /*-  /*-
Line 800 
Line 769 
             DEBUG(JOB)) {              DEBUG(JOB)) {
                 FILE *out;                  FILE *out;
   
                 if (compatMake && !usePipes && (job->flags & JOB_IGNERR)) {                  out = stdout;
                         /*  
                          * If output is going to a file and this job is ignoring  
                          * errors, arrange to have the exit status sent to the  
                          * output file as well.  
                          */  
                         out = fdopen(job->outFd, "w");  
                 } else {  
                         out = stdout;  
                 }  
   
                 if (WIFEXITED(*status)) {                  if (WIFEXITED(*status)) {
                         if (DEBUG(JOB)) {                          if (DEBUG(JOB)) {
Line 818 
Line 778 
                                 (void)fflush(stdout);                                  (void)fflush(stdout);
                         }                          }
                         if (WEXITSTATUS(*status) != 0) {                          if (WEXITSTATUS(*status) != 0) {
                                 if (usePipes && job->node != lastNode) {                                  if (job->node != lastNode) {
                                         MESSAGE(out, job->node);                                          MESSAGE(out, job->node);
                                         lastNode = job->node;                                          lastNode = job->node;
                                 }                                  }
Line 831 
Line 791 
                                         *status = 0;                                          *status = 0;
                                 }                                  }
                         } else if (DEBUG(JOB)) {                          } else if (DEBUG(JOB)) {
                                 if (usePipes && job->node != lastNode) {                                  if (job->node != lastNode) {
                                         MESSAGE(out, job->node);                                          MESSAGE(out, job->node);
                                         lastNode = job->node;                                          lastNode = job->node;
                                 }                                  }
Line 844 
Line 804 
                                     (long)job->pid);                                      (long)job->pid);
                                 (void)fflush(stdout);                                  (void)fflush(stdout);
                         }                          }
                         if (usePipes && job->node != lastNode) {                          if (job->node != lastNode) {
                                 MESSAGE(out, job->node);                                  MESSAGE(out, job->node);
                                 lastNode = job->node;                                  lastNode = job->node;
                         }                          }
Line 862 
Line 822 
                          * child.                           * child.
                          */                           */
                         if (job->flags & (JOB_RESUME|JOB_RESTART)) {                          if (job->flags & (JOB_RESUME|JOB_RESTART)) {
                                 if (usePipes && job->node != lastNode) {                                  if (job->node != lastNode) {
                                         MESSAGE(out, job->node);                                          MESSAGE(out, job->node);
                                         lastNode = job->node;                                          lastNode = job->node;
                                 }                                  }
Line 907 
Line 867 
                         (void)fflush(out);                          (void)fflush(out);
                         return;                          return;
                 } else {                  } else {
                         if (usePipes && job->node != lastNode) {                          if (job->node != lastNode) {
                                 MESSAGE(out, job->node);                                  MESSAGE(out, job->node);
                                 lastNode = job->node;                                  lastNode = job->node;
                         }                          }
Line 1042 
Line 1002 
                 (void)fcntl(0, F_SETFD, 0);                  (void)fcntl(0, F_SETFD, 0);
                 (void)lseek(0, 0, SEEK_SET);                  (void)lseek(0, 0, SEEK_SET);
   
                 if (usePipes) {  
                         /*  
                          * 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));  
                 } else {  
                         /*  
                          * We're capturing output in a file, so we duplicate the  
                          * descriptor to the temporary file into the standard  
                          * output.  
                          */  
                         if (dup2(job->outFd, 1) == -1)  
                                 Punt("Cannot dup2: %s", strerror(errno));  
                 }  
                 /*                  /*
                    * 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));
                   /*
                  * The output channels are marked close on exec. This bit was                   * The output channels are marked close on exec. This bit was
                  * duplicated by the dup2 (on some systems), so we have to                   * duplicated by the dup2 (on some systems), so we have to
                  * clear it before routing the shell's error output to the same                   * clear it before routing the shell's error output to the same
Line 1089 
Line 1039 
         } else {          } else {
                 job->pid = cpid;                  job->pid = cpid;
   
                 if (usePipes && (job->flags & JOB_FIRST) ) {                  if (job->flags & JOB_FIRST) {
                         /*                          /*
                          * The first time a job is run for a node, we set the                           * The first time a job is run for a node, we set the
                          * current position in the buffer to the beginning and                           * current position in the buffer to the beginning and
Line 1522 
Line 1472 
          * starting a job and then set up its temporary-file name.           * starting a job and then set up its temporary-file name.
          */           */
         if (!compatMake || (job->flags & JOB_FIRST)) {          if (!compatMake || (job->flags & JOB_FIRST)) {
                 if (usePipes) {                  int fd[2];
                         int fd[2];                  if (pipe(fd) == -1)
                         if (pipe(fd) == -1)                          Punt("Cannot create pipe: %s", strerror(errno));
                                 Punt("Cannot create pipe: %s", strerror(errno));                  job->inPipe = fd[0];
                         job->inPipe = fd[0];                  job->outPipe = fd[1];
                         job->outPipe = fd[1];                  (void)fcntl(job->inPipe, F_SETFD, 1);
                         (void)fcntl(job->inPipe, F_SETFD, 1);                  (void)fcntl(job->outPipe, F_SETFD, 1);
                         (void)fcntl(job->outPipe, F_SETFD, 1);  
                 } else {  
                         (void)fprintf(stdout, "Remaking `%s'\n", gn->name);  
                         (void)fflush(stdout);  
                         (void)strlcpy(job->outFile, TMPPAT,  
                             sizeof(job->outFile));  
                         if ((job->outFd = mkstemp(job->outFile)) == -1)  
                                 Punt("Cannot create temp file: %s",  
                                     strerror(errno));  
                         (void)fcntl(job->outFd, F_SETFD, 1);  
                 }  
         }          }
   
         local = true;          local = true;
Line 1662 
Line 1601 
         int max;                /* limit for i (end of current data) */          int max;                /* limit for i (end of current data) */
         int nRead;              /* (Temporary) number of bytes read */          int nRead;              /* (Temporary) number of bytes read */
   
         FILE *oFILE;            /* Stream pointer to shell's output file */          /*
         char inLine[132];           * Read as many bytes as will fit in the buffer.
            */
   
         if (usePipes) {  
                 /*  
                  * Read as many bytes as will fit in the buffer.  
                  */  
 end_loop:  end_loop:
                 gotNL = false;          gotNL = false;
                 fbuf = false;          fbuf = false;
   
                 nRead = read(job->inPipe, &job->outBuf[job->curPos],          nRead = read(job->inPipe, &job->outBuf[job->curPos],
                     JOB_BUFSIZE - job->curPos);              JOB_BUFSIZE - job->curPos);
                 if (nRead == -1) {          if (nRead == -1) {
                         if (DEBUG(JOB)) {                  if (DEBUG(JOB)) {
                                 perror("JobDoOutput(piperead)");                          perror("JobDoOutput(piperead)");
                         }  
                         nr = 0;  
                 } else {  
                         nr = nRead;  
                 }                  }
                   nr = 0;
           } else {
                   nr = nRead;
           }
   
                 /*          /*
                  * If we hit the end-of-file (the job is dead), we must flush           * If we hit the end-of-file (the job is dead), we must flush
                  * its remaining output, so pretend we read a newline if           * its remaining output, so pretend we read a newline if
                  * there's any output remaining in the buffer.  Also clear the           * there's any output remaining in the buffer.  Also clear the
                  * 'finish' flag so we stop looping.           * 'finish' flag so we stop looping.
                  */           */
                 if (nr == 0 && job->curPos != 0) {          if (nr == 0 && job->curPos != 0) {
                         job->outBuf[job->curPos] = '\n';                  job->outBuf[job->curPos] = '\n';
                         nr = 1;                  nr = 1;
                         finish = false;                  finish = false;
                 } else if (nr == 0) {          } else if (nr == 0) {
                         finish = false;                  finish = false;
                 }          }
   
                 /*          /*
                  * Look for the last newline in the bytes we just got. If there           * 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           * is one, break out of the loop with 'i' as its index and
                  * gotNL set true.           * gotNL set true.
                  */           */
                 max = job->curPos + nr;          max = job->curPos + nr;
                 for (i = job->curPos + nr - 1; i >= job->curPos; i--) {          for (i = job->curPos + nr - 1; i >= job->curPos; i--) {
                         if (job->outBuf[i] == '\n') {                  if (job->outBuf[i] == '\n') {
                                 gotNL = true;                          gotNL = true;
                                 break;                          break;
                         } else if (job->outBuf[i] == '\0') {                  } else if (job->outBuf[i] == '\0') {
                                 /*                          /*
                                  * Why?                           * Why?
                                  */                           */
                                 job->outBuf[i] = ' ';                          job->outBuf[i] = ' ';
                         }  
                 }                  }
           }
   
                 if (!gotNL) {          if (!gotNL) {
                         job->curPos += nr;                  job->curPos += nr;
                         if (job->curPos == JOB_BUFSIZE) {                  if (job->curPos == JOB_BUFSIZE) {
                                 /*  
                                  * If we've run out of buffer space, we have no  
                                  * choice but to print the stuff. sigh.  
                                  */  
                                 fbuf = true;  
                                 i = job->curPos;  
                         }  
                 }  
                 if (gotNL || fbuf) {  
                         /*                          /*
                          * Need to send the output to the screen. Null                           * If we've run out of buffer space, we have no
                          * terminate it first, overwriting the newline                           * choice but to print the stuff. sigh.
                          * 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';                          fbuf = true;
                         if (i >= job->curPos) {                          i = job->curPos;
                                 char *cp;                  }
           }
           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.
                    */
                   job->outBuf[i] = '\0';
                   if (i >= job->curPos) {
                           char *cp;
   
                                 cp = JobOutput(job, job->outBuf,                          cp = JobOutput(job, job->outBuf,
                                     &job->outBuf[i], false);                              &job->outBuf[i], false);
   
                                 /*                          /*
                                  * There's still more in that thar buffer. This                           * There's still more in that thar buffer. This
                                  * time, though, we know there's no newline at                           * time, though, we know there's no newline at
                                  * the end, so we add one of our own free will.                           * the end, so we add one of our own free will.
                                  */                           */
                                 if (*cp != '\0') {                          if (*cp != '\0') {
                                         if (job->node != lastNode) {                                  if (job->node != lastNode) {
                                                 MESSAGE(stdout, job->node);                                          MESSAGE(stdout, job->node);
                                                 lastNode = job->node;                                          lastNode = job->node;
                                         }  
                                         (void)fprintf(stdout, "%s%s", cp,  
                                             gotNL ? "\n" : "");  
                                         (void)fflush(stdout);  
                                 }                                  }
                                   (void)fprintf(stdout, "%s%s", cp,
                                       gotNL ? "\n" : "");
                                   (void)fflush(stdout);
                         }                          }
                         if (i < max - 1) {  
                                 /* shift the remaining characters down */  
                                 (void)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 (i < max - 1) {
                           /* shift the remaining characters down */
                           (void)memcpy(job->outBuf, &job->outBuf[i + 1],
                               max - (i + 1));
                           job->curPos = max - (i + 1);
   
                   } else {
                         /*                          /*
                          * If the finish flag is true, we must loop until we                           * We have written everything out, so we just
                          * hit end-of-file on the pipe. This is guaranteed to                           * start over from the start of the buffer. No
                          * happen eventually since the other end of the pipe is                           * copying.  No nothing.
                          * 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;                          job->curPos = 0;
                 }                  }
         } else {          }
           if (finish) {
                 /*                  /*
                  * We've been called to retrieve the output of the job from the                   * If the finish flag is true, we must loop until we
                  * temporary file where it's been squirreled away. This                   * hit end-of-file on the pipe. This is guaranteed to
                  * consists of opening the file, reading the output line by                   * happen eventually since the other end of the pipe is
                  * line, being sure not to print the noPrint line for the shell                   * now closed (we closed it explicitly and the child
                  * we used, then close and remove the temporary file. Very                   * has exited). When we do get an EOF, finish will be
                  * simple.                   * set false and we'll fall through and out.
                  *  
                  * Change to read in blocks and do FindSubString type things as  
                  * for pipes? That would allow for "@echo -n..."  
                  */                   */
                 oFILE = fopen(job->outFile, "r");                  goto end_loop;
                 if (oFILE != NULL) {  
                         (void)fprintf(stdout, "Results of making %s:\n",  
                             job->node->name);  
                         (void)fflush(stdout);  
                         while (fgets(inLine, sizeof(inLine), oFILE) != NULL) {  
                                 char *cp, *endp, *oendp;  
   
                                 cp = inLine;  
                                 oendp = endp = inLine + strlen(inLine);  
                                 if (endp != inLine && endp[-1] == '\n') {  
                                         *--endp = '\0';  
                                 }  
                                 cp = JobOutput(job, inLine, endp, 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.  
                                  */  
                                 (void)fprintf(stdout, "%s", cp);  
                                 (void)fflush(stdout);  
                                 if (endp != oendp) {  
                                         (void)fprintf(stdout, "\n");  
                                         (void)fflush(stdout);  
                                 }  
                         }  
                         (void)fclose(oFILE);  
                         (void)eunlink(job->outFile);  
                 }  
         }          }
 }  }
   
Line 1850 
Line 1741 
  *-----------------------------------------------------------------------   *-----------------------------------------------------------------------
  */   */
 void  void
 Job_CatchChildren(bool block)   /* true if should block on the wait. */  Job_CatchChildren()
 {  {
         pid_t pid;              /* pid of dead child */          pid_t pid;              /* pid of dead child */
         Job *job;               /* job descriptor for dead child */          Job *job;               /* job descriptor for dead child */
Line 1864 
Line 1755 
                 return;                  return;
         }          }
   
         while ((pid = waitpid((pid_t) -1, &status,          while ((pid = waitpid((pid_t) -1, &status, WNOHANG|WUNTRACED)) > 0) {
             (block?0:WNOHANG)|WUNTRACED)) > 0) {  
                 HandleSigs();                  HandleSigs();
                 if (DEBUG(JOB)) {                  if (DEBUG(JOB)) {
                         (void)fprintf(stdout,                          (void)fprintf(stdout,
Line 1929 
Line 1819 
         Job *job;          Job *job;
   
         (void)fflush(stdout);          (void)fflush(stdout);
         if (usePipes) {          int count = howmany(outputsn+1, NFDBITS) * sizeof(fd_mask);
                 int count = howmany(outputsn+1, NFDBITS) * sizeof(fd_mask);          fd_set *readfdsp = malloc(count);
                 fd_set *readfdsp = malloc(count);          if (readfdsp == NULL)
                 if (readfdsp == NULL)                  return;
                         return;  
   
                 memcpy(readfdsp, outputsp, count);          memcpy(readfdsp, outputsp, count);
                 timeout.tv_sec = SEL_SEC;          timeout.tv_sec = SEL_SEC;
                 timeout.tv_usec = SEL_USEC;          timeout.tv_usec = SEL_USEC;
   
                 if ((nfds = select(outputsn+1, readfdsp, (fd_set *) 0,          if ((nfds = select(outputsn+1, readfdsp, (fd_set *) 0,
                     (fd_set *) 0, &timeout)) <= 0) {              (fd_set *) 0, &timeout)) <= 0) {
                         HandleSigs();                  HandleSigs();
                         free(readfdsp);                  free(readfdsp);
                         return;                  return;
                 } else {          } else {
                         HandleSigs();                  HandleSigs();
                         for (ln = Lst_First(&jobs); nfds && ln != NULL;                  for (ln = Lst_First(&jobs); nfds && ln != NULL;
                             ln = Lst_Adv(ln)) {                      ln = Lst_Adv(ln)) {
                                 job = (Job *)Lst_Datum(ln);                          job = (Job *)Lst_Datum(ln);
                                 if (FD_ISSET(job->inPipe, readfdsp)) {                          if (FD_ISSET(job->inPipe, readfdsp)) {
                                         JobDoOutput(job, false);                                  JobDoOutput(job, false);
                                         nfds--;                                  nfds--;
                                 }  
                         }                          }
                 }                  }
                 free(readfdsp);  
         }          }
           free(readfdsp);
 }  }
   
 /*-  /*-
Line 2065 
Line 1953 
                 JobStart(begin, JOB_SPECIAL, (Job *)0);                  JobStart(begin, JOB_SPECIAL, (Job *)0);
                 while (nJobs) {                  while (nJobs) {
                         Job_CatchOutput();                          Job_CatchOutput();
                         Job_CatchChildren(!usePipes);                          Job_CatchChildren();
                 }                  }
         }          }
         postCommands = Targ_FindNode(".END", TARG_CREATE);          postCommands = Targ_FindNode(".END", TARG_CREATE);
Line 2171 
Line 2059 
                         JobStart(interrupt, JOB_IGNDOTS, (Job *)0);                          JobStart(interrupt, JOB_IGNDOTS, (Job *)0);
                         while (nJobs) {                          while (nJobs) {
                                 Job_CatchOutput();                                  Job_CatchOutput();
                                 Job_CatchChildren(!usePipes);                                  Job_CatchChildren();
                         }                          }
                 }                  }
         }          }
Line 2204 
Line 2092 
   
                         while (nJobs) {                          while (nJobs) {
                                 Job_CatchOutput();                                  Job_CatchOutput();
                                 Job_CatchChildren(!usePipes);                                  Job_CatchChildren();
                         }                          }
                 }                  }
         }          }
Line 2246 
Line 2134 
         aborting = ABORT_WAIT;          aborting = ABORT_WAIT;
         while (nJobs != 0) {          while (nJobs != 0) {
                 Job_CatchOutput();                  Job_CatchOutput();
                 Job_CatchChildren(!usePipes);                  Job_CatchChildren();
         }          }
         aborting = 0;          aborting = 0;
 }  }

Legend:
Removed from v.1.75  
changed lines
  Added in v.1.76