[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.77 and 1.78

version 1.77, 2007/09/17 12:03:40 version 1.78, 2007/09/17 12:42:09
Line 48 
Line 48 
  *                              frequently to keep the whole make going at   *                              frequently to keep the whole make going at
  *                              a decent clip, since job table entries aren't   *                              a decent clip, since job table entries aren't
  *                              removed until their process is caught this way.   *                              removed until their process is caught this way.
  *                              Its single argument is true if the function  
  *                              should block waiting for a child to terminate.  
  *   *
  *      Job_CatchOutput         Print any output our children have produced.   *      Job_CatchOutput         Print any output our children have produced.
  *                              Should also be called fairly frequently to   *                              Should also be called fairly frequently to
Line 132 
Line 130 
  *         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) Things used for handling the shell's output.   *      5) Things used for handling the shell's output.
  *         the output is being caught via a pipe and   *         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.   *         maintained for each job.
  *      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 162 
Line 160 
     short       flags;      /* Flags to control treatment of job */      short       flags;      /* Flags to control treatment of job */
 #define JOB_IGNERR      0x001   /* Ignore non-zero exits */  #define JOB_IGNERR      0x001   /* Ignore non-zero exits */
 #define JOB_SILENT      0x002   /* no output */  #define JOB_SILENT      0x002   /* no output */
 #define JOB_SPECIAL     0x004   /* Target is a special one. i.e. run it locally  #define JOB_SPECIAL     0x004   /* Target is a special one. i.e., always run */
                                  * if we can't export it and maxLocal is 0 */                                  /* it even when the table is full */
 #define JOB_IGNDOTS     0x008   /* Ignore "..." lines when processing  #define JOB_IGNDOTS     0x008   /* Ignore "..." lines when processing */
                                  * commands */                                  /* commands */
 #define JOB_FIRST       0x020   /* Job is first job for the node */  #define JOB_FIRST       0x020   /* Job is first job for the node */
 #define JOB_RESTART     0x080   /* Job needs to be completely restarted */  #define JOB_RESTART     0x080   /* Job needs to be completely restarted */
 #define JOB_RESUME      0x100   /* Job needs to be resumed b/c it stopped,  #define JOB_RESUME      0x100   /* Job needs to be resumed b/c it stopped, */
                                  * for some reason */                                  /* for some reason */
 #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 */
     int         inPipe;         /* Input side of pipe associated      int         inPipe;         /* Input side of pipe associated
                                  * with job's output channel */                                   * with job's output channel */
     int         outPipe;        /* Output side of pipe associated with      int         outPipe;        /* Output side of pipe associated with
Line 183 
Line 181 
     int         curPos;         /* Current position in op_outBuf */      int         curPos;         /* Current position in op_outBuf */
 } Job;  } Job;
   
   
 /*  /*
  * error handling variables   * error handling variables
  */   */
Line 198 
Line 197 
  */   */
 #define FILENO(a) ((unsigned) fileno(a))  #define FILENO(a) ((unsigned) fileno(a))
   
 /*  
  * post-make command processing. The node postCommands is really just the  
  * .END target but we keep it around to avoid having to search for it  
  * all the time.  
  */  
 static GNode      *postCommands;    /* node containing commands to execute when  
                                      * everything else is done */  
 static int        numCommands;      /* The number of commands actually printed  static int        numCommands;      /* The number of commands actually printed
                                      * for a target. Should this number be                                       * for a target. Should this number be
                                      * 0, no shell will be executed. */                                       * 0, no shell will be executed. */
Line 235 
Line 227 
 static const char *shellPath = _PATH_BSHELL;  static const char *shellPath = _PATH_BSHELL;
 static const char *shellName = "sh";  static const char *shellName = "sh";
   
   
 static int      maxJobs;        /* The most children we can run at once */  static int      maxJobs;        /* The most children we can run at once */
 static int      maxLocal;       /* The most local ones we can have */  
 static int      nJobs = 0;      /* The number of children currently running */  static int      nJobs = 0;      /* The number of children currently running */
 static int      nLocal;         /* The number of local children */  
 static LIST     jobs;           /* The structures that describe them */  static LIST     jobs;           /* The structures that describe them */
 static bool     jobFull;        /* Flag to tell when the job table is full. It  static bool     jobFull;        /* Flag to tell when the job table is full. */
                                  * is set true when (1) the total number of  
                                  * running jobs equals the maximum allowed or  
                                  * (2) a job can only be run locally, but  
                                  * nLocal equals maxLocal */  
 static fd_set   *outputsp;      /* Set of descriptors of pipes connected to  static fd_set   *outputsp;      /* Set of descriptors of pipes connected to
                                  * the output channels of children */                                   * the output channels of children */
 static int      outputsn;  static int      outputsn;
Line 539 
Line 526 
  *      If the command is just "..." we take all future commands for this   *      If the command is just "..." we take all future commands for this
  *      job to be commands to be executed once the entire graph has been   *      job to be commands to be executed once the entire graph has been
  *      made and return non-zero to signal that the end of the commands   *      made and return non-zero to signal that the end of the commands
  *      was reached. These commands are later attached to the postCommands   *      was reached. These commands are later attached to the end_node
  *      node and executed by Job_End when all things are done.   *      node and executed by Job_End when all things are done.
  *      This function is called from JobStart via Lst_Find   *      This function is called from JobStart via Lst_Find
  *   *
Line 555 
Line 542 
  *-----------------------------------------------------------------------   *-----------------------------------------------------------------------
  */   */
 static int  static int
 JobPrintCommand(LstNode cmdNode,    /* command string to print */  JobPrintCommand(LstNode cmdNode,        /* command string to print */
     void *jobp)                     /* job for which to print it */      void *jobp)                         /* job for which to print it */
 {  {
         bool noSpecials;        /* true if we shouldn't worry about          bool noSpecials;                /* true if we shouldn't worry about
                                  * inserting special commands into                                           * inserting special commands into
                                  * the input stream. */                                           * the input stream. */
         bool shutUp = false;    /* true if we put a no echo command          bool shutUp = false;            /* true if we put a no echo command
                                  * into the command file */                                           * into the command file */
         bool errOff = false;    /* true if we turned error checking          bool errOff = false;            /* true if we turned error checking
                                  * off before printing the command                                           * off before printing the command
                                  * and need to turn it back on */                                           * and need to turn it back on */
         char *cmdTemplate;      /* Template to use when printing the          char *cmdTemplate;              /* Template to use when printing the
                                  * command */                                           * command */
         char *cmdStart;         /* Start of expanded command */          char *cmdStart;                 /* Start of expanded command */
         char *cmd = (char *)Lst_Datum(cmdNode);          char *cmd = (char *)Lst_Datum(cmdNode);
         Job *job = (Job *)jobp;          Job *job = (Job *)jobp;
   
Line 583 
Line 570 
                 return 1;                  return 1;
         }          }
   
   
         numCommands++;          numCommands++;
   
         /* For debugging, we replace each command with the result of expanding          /* For debugging, we replace each command with the result of expanding
Line 618 
Line 606 
         if (errOff) {          if (errOff) {
                 if ( !(job->flags & JOB_IGNERR) && !noSpecials) {                  if ( !(job->flags & JOB_IGNERR) && !noSpecials) {
                         /*                          /*
                          * we don't want the error-control commands                           * we don't want the error-control commands showing
                          * showing up either, so we turn off echoing                           * up either, so we turn off echoing while executing
                          * while executing them. We could put another                           * them. We could put another field in the shell
                          * field in the shell structure to tell                           * structure to tell JobDoOutput to look for this
                          * JobDoOutput to look for this string too, but                           * string too, but why make it any more complex than
                          * why make it any more complex than it already                           * it already is?
                          * is?  
                          */                           */
                         if (!(job->flags & JOB_SILENT) && !shutUp) {                          if (!(job->flags & JOB_SILENT) && !shutUp) {
                                 DBPRINTF(job, "%s; %s; %s\n", SHELL_ECHO_OFF,                                  DBPRINTF(job, "%s; %s; %s\n", SHELL_ECHO_OFF,
Line 664 
Line 651 
  *      Callback function for JobFinish...   *      Callback function for JobFinish...
  *   *
  * Side Effects:   * Side Effects:
  *      The command is tacked onto the end of postCommands's commands list.   *      The command is tacked onto the end of end_node's commands list.
  *-----------------------------------------------------------------------   *-----------------------------------------------------------------------
  */   */
 static void  static void
Line 674 
Line 661 
         char *result;          char *result;
   
         result = Var_Subst((char *)cmd, &g->context, false);          result = Var_Subst((char *)cmd, &g->context, false);
         Lst_AtEnd(&postCommands->commands, result);          Lst_AtEnd(&end_node->commands, result);
 }  }
   
   
Line 710 
Line 697 
  *   *
  * Side Effects:   * Side Effects:
  *      Some nodes may be put on the toBeMade queue.   *      Some nodes may be put on the toBeMade queue.
  *      Final commands for the job are placed on postCommands.   *      Final commands for the job are placed on end_node.
  *   *
  *      If we got an error and are aborting (aborting == ABORT_ERROR) and   *      If we got an error and are aborting (aborting == ABORT_ERROR) and
  *      the job list is now empty, we are done for the day.   *      the job list is now empty, we are done for the day.
Line 723 
Line 710 
 JobFinish(Job *job,             /* job to finish */  JobFinish(Job *job,             /* job to finish */
     int *status)                /* sub-why job went away */      int *status)                /* sub-why job went away */
 {  {
         bool done;          bool     done;
   
         if ((WIFEXITED(*status) &&          if ((WIFEXITED(*status) &&
              WEXITSTATUS(*status) != 0 && !(job->flags & JOB_IGNERR)) ||               WEXITSTATUS(*status) != 0 && !(job->flags & JOB_IGNERR)) ||
Line 773 
Line 760 
   
                 if (WIFEXITED(*status)) {                  if (WIFEXITED(*status)) {
                         if (DEBUG(JOB)) {                          if (DEBUG(JOB)) {
                                 (void)fprintf(stdout, "Process %ld exited.\n",                                  (void)fprintf(stdout,
                                     (long)job->pid);                                      "Process %ld exited.\n", (long)job->pid);
                                 (void)fflush(stdout);                                  (void)fflush(stdout);
                         }                          }
                         if (WEXITSTATUS(*status) != 0) {                          if (WEXITSTATUS(*status) != 0) {
Line 800 
Line 787 
                         }                          }
                 } else if (WIFSTOPPED(*status)) {                  } else if (WIFSTOPPED(*status)) {
                         if (DEBUG(JOB)) {                          if (DEBUG(JOB)) {
                                 (void)fprintf(stdout, "Process %ld stopped.\n",                                  (void)fprintf(stdout,
                                     (long)job->pid);                                      "Process %ld stopped.\n", (long)job->pid);
                                 (void)fflush(stdout);                                  (void)fflush(stdout);
                         }                          }
                         if (job->node != lastNode) {                          if (job->node != lastNode) {
Line 831 
Line 818 
                         if (!(job->flags & JOB_CONTINUING)) {                          if (!(job->flags & JOB_CONTINUING)) {
                                 if (DEBUG(JOB)) {                                  if (DEBUG(JOB)) {
                                         (void)fprintf(stdout,                                          (void)fprintf(stdout,
                                 "Warning: process %ld was not continuing.\n",                                              "Warning: process %ld was not continuing.\n",
                                             (long)job->pid);                                              (long)job->pid);
                                         (void)fflush(stdout);                                          (void)fflush(stdout);
                                 }                                  }
Line 855 
Line 842 
                                     (long)job->pid);                                      (long)job->pid);
                                 (void)fflush(stdout);                                  (void)fflush(stdout);
                         }                          }
                         nLocal++;  
                         if (nJobs == maxJobs) {                          if (nJobs == maxJobs) {
                                 jobFull = true;                                  jobFull = true;
                                 if (DEBUG(JOB)) {                                  if (DEBUG(JOB)) {
Line 964 
Line 950 
         pid_t cpid;     /* ID of new child */          pid_t cpid;     /* ID of new child */
   
         if (DEBUG(JOB)) {          if (DEBUG(JOB)) {
                 int       i;                  int i;
   
                 (void)fprintf(stdout, "Running %s\n", job->node->name);                  (void)fprintf(stdout, "Running %s\n", job->node->name);
                 (void)fprintf(stdout, "\tCommand: ");                  (void)fprintf(stdout, "\tCommand: ");
Line 1003 
Line 989 
                 (void)lseek(0, 0, SEEK_SET);                  (void)lseek(0, 0, SEEK_SET);
   
                 /*                  /*
                  * Set up the child's output to be routed through the                   * Set up the child's output to be routed through the pipe
                  * pipe we've created for it.                   * we've created for it.
                  */                   */
                 if (dup2(job->outPipe, 1) == -1)                  if (dup2(job->outPipe, 1) == -1)
                         Punt("Cannot dup2: %s", strerror(errno));                          Punt("Cannot dup2: %s", strerror(errno));
Line 1069 
Line 1055 
                         FD_SET(job->inPipe, outputsp);                          FD_SET(job->inPipe, outputsp);
                 }                  }
   
                 nLocal++;  
                 /*                  /*
                  * XXX: Used to not happen if REMOTE. Why?                   * XXX: Used to not happen if REMOTE. Why?
                  */                   */
Line 1111 
Line 1096 
         if (args[1]) {          if (args[1]) {
                 argv[argc] = args;                  argv[argc] = args;
                 argc++;                  argc++;
         }          }
         argv[argc] = NULL;          argv[argc] = NULL;
 }  }
   
Line 1146 
Line 1131 
                             job->node->name);                              job->node->name);
                         (void)fflush(stdout);                          (void)fflush(stdout);
                 }                  }
                 if (nLocal >= maxLocal && !(job->flags & JOB_SPECIAL)) {                  if (nJobs >= maxJobs && !(job->flags & JOB_SPECIAL)) {
                         /*                          /*
                          * Can't be exported and not allowed to run locally --                           * Can't be exported and not allowed to run locally --
                          * put it back on the hold queue and mark the table                           * put it back on the hold queue and mark the table
Line 1182 
Line 1167 
                        (void)fprintf(stdout, "Resuming %s...", job->node->name);                         (void)fprintf(stdout, "Resuming %s...", job->node->name);
                        (void)fflush(stdout);                         (void)fflush(stdout);
                 }                  }
                 if ((nLocal < maxLocal ||                  if (nJobs != maxJobs || (job->flags & JOB_SPECIAL)) {
                     ((job->flags & JOB_SPECIAL) &&  
                      maxLocal == 0)  
                    ) && nJobs != maxJobs) {  
                         /*                          /*
                          * If we haven't reached the concurrency limit already                           * If we haven't reached the concurrency limit already,
                          * (or maxLocal is 0), it's ok to resume the job.                           * it's ok to resume the job.
                          */                           */
                         bool error;                          bool error;
                         int status;                          int status;
Line 1253 
Line 1235 
  *-----------------------------------------------------------------------   *-----------------------------------------------------------------------
  */   */
 static int  static int
 JobStart(GNode    *gn,        /* target to create */  JobStart(GNode *gn,             /* target to create */
     int            flags,      /* flags for the job to override normal ones.      int flags,                  /* flags for the job to override normal ones.
                                * e.g. JOB_SPECIAL or JOB_IGNDOTS */                                   * e.g. JOB_SPECIAL or JOB_IGNDOTS */
     Job           *previous)  /* The previous Job structure for this node,      Job *previous)              /* The previous Job structure for this node,
                                * if any. */                                   * if any. */
 {  {
         Job *job;       /* new job descriptor */          Job *job;               /* new job descriptor */
         char *argv[4];  /* Argument vector to shell */          char *argv[4];          /* Argument vector to shell */
         bool cmdsOK;    /* true if the nodes commands were all right */          bool cmdsOK;            /* true if the nodes commands were all right */
         bool local;     /* Set true if the job was run locally */          bool local;             /* Set true if the job was run locally */
         bool noExec;    /* Set true if we decide not to run the job */          bool noExec;            /* Set true if we decide not to run the job */
   
         if (previous != NULL) {          if (previous != NULL) {
                 previous->flags &= ~(JOB_FIRST|JOB_IGNERR|JOB_SILENT);                  previous->flags &= ~(JOB_FIRST|JOB_IGNERR|JOB_SILENT);
Line 1483 
Line 1465 
   
         local = true;          local = true;
   
         if (local && nLocal >= maxLocal &&          if (nJobs >= maxJobs && !(job->flags & JOB_SPECIAL)) {
             !(job->flags & JOB_SPECIAL) &&                  /* we've hit the limit of concurrency, so put the job on hold
             maxLocal != 0                   * until some other job finishes.
             ) {  
                 /*  
                  * The job can only be run locally, but we've hit the limit of  
                  * local concurrency, so put the job on hold until some other  
                  * job finishes. Note that the special jobs (.BEGIN, .INTERRUPT  
                  * and .END) may be run locally even when the local limit has  
                  * been reached (e.g. when maxLocal == 0), though they will be  
                  * exported if at all possible. In addition, any target marked  
                  * with .NOEXPORT will be run locally if maxLocal is 0.  
                  */                   */
                 jobFull = true;                  jobFull = true;
   
Line 1504 
Line 1477 
                 }                  }
                 job->flags |= JOB_RESTART;                  job->flags |= JOB_RESTART;
                 Lst_AtEnd(&stoppedJobs, job);                  Lst_AtEnd(&stoppedJobs, job);
         } else {  
                 if (nLocal >= maxLocal && local) {  
                         /*  
                          * If we're running this job locally as a special case  
                          * (see above), at least say the table is full.  
                          */  
                         jobFull = true;  
                         if (DEBUG(JOB)) {  
                                 (void)fprintf(stdout,  
                                     "Local job queue is full.\n");  
                                 (void)fflush(stdout);  
                         }  
                 }  
                 JobExec(job, argv);  
         }          }
         return JOB_RUNNING;          return JOB_RUNNING;
 }  }
Line 1536 
Line 1495 
                                 lastNode = job->node;                                  lastNode = job->node;
                         }                          }
                         /*                          /*
                          * The only way there wouldn't be a newline                           * The only way there wouldn't be a newline after
                          * after this line is if it were the last in                           * this line is if it were the last in the buffer.
                          * the buffer.  however, since the                           * however, since the non-printable comes after it,
                          * non-printable comes after it, there must be                           * there must be a newline, so we don't print one.
                          * a newline, so we don't print one.  
                          */                           */
                         (void)fprintf(stdout, "%s", cp);                          (void)fprintf(stdout, "%s", cp);
                         (void)fflush(stdout);                          (void)fflush(stdout);
Line 1548 
Line 1506 
                 cp = ecp + strlen(SHELL_ECHO_OFF);                  cp = ecp + strlen(SHELL_ECHO_OFF);
                 if (cp != endp) {                  if (cp != endp) {
                         /*                          /*
                          * Still more to print, look again after                           * Still more to print, look again after skipping
                          * skipping the whitespace following the                           * the whitespace following the non-printable
                          * non-printable command....                           * command....
                          */                           */
                         cp++;                          cp++;
                         while (*cp == ' ' || *cp == '\t' ||                          while (*cp == ' ' || *cp == '\t' || *cp == '\n') {
                             *cp == '\n') {  
                                 cp++;                                  cp++;
                         }                          }
                         ecp = strstr(cp, SHELL_ECHO_OFF);                          ecp = strstr(cp, SHELL_ECHO_OFF);
Line 1594 
Line 1551 
     bool finish)                /* true if this is the last time we'll be      bool finish)                /* true if this is the last time we'll be
                                  * called for this job */                                   * called for this job */
 {  {
         bool gotNL = false;     /* true if got a newline */          bool gotNL = false;     /* true if got a newline */
         bool fbuf;              /* true if our buffer filled up */          bool fbuf;              /* true if our buffer filled up */
         int nr;                 /* number of bytes read */          int nr;                 /* number of bytes read */
         int i;                  /* auxiliary index into outBuf */          int i;                  /* auxiliary index into outBuf */
         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 */
   
         /*          /*
          * Read as many bytes as will fit in the buffer.           * Read as many bytes as will fit in the buffer.
Line 1620 
Line 1577 
         }          }
   
         /*          /*
          * 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
          * its remaining output, so pretend we read a newline if           * remaining output, so pretend we read a newline if there's any
          * there's any output remaining in the buffer.  Also clear the           * output remaining in the buffer.
          * 'finish' flag so we stop looping.           * Also clear the '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';
Line 1634 
Line 1591 
         }          }
   
         /*          /*
          * 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
          * is one, break out of the loop with 'i' as its index and           * one, break out of the loop with 'i' as its index and gotNL set
          * gotNL set true.           * 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--) {
Line 1655 
Line 1612 
                 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                           * If we've run out of buffer space, we have no choice
                          * choice but to print the stuff. sigh.                           * but to print the stuff. sigh.
                          */                           */
                         fbuf = true;                          fbuf = true;
                         i = job->curPos;                          i = job->curPos;
Line 1664 
Line 1621 
         }          }
         if (gotNL || fbuf) {          if (gotNL || fbuf) {
                 /*                  /*
                  * Need to send the output to the screen. Null                   * Need to send the output to the screen. Null terminate it
                  * terminate it first, overwriting the newline                   * first, overwriting the newline character if there was one.
                  * character if there was one.  So long as the line                   * So long as the line isn't one we should filter (according
                  * isn't one we should filter (according to the shell                   * to the shell description), we print the line, preceded
                  * description), we print the line, preceded by a                   * by a target banner if this target isn't the same as the
                  * target banner if this target isn't the same as the                   * one for which we last printed something.
                  * one for which we last printed something.  The rest                   * The rest of the data in the buffer are then shifted down
                  * of the data in the buffer are then shifted down to                   * to the start of the buffer and curPos is set accordingly.
                  * the start of the buffer and curPos is set  
                  * accordingly.  
                  */                   */
                 job->outBuf[i] = '\0';                  job->outBuf[i] = '\0';
                 if (i >= job->curPos) {                  if (i >= job->curPos) {
                         char *cp;                          char *cp;
   
                         cp = JobOutput(job, job->outBuf,                          cp = JobOutput(job, job->outBuf, &job->outBuf[i],
                             &job->outBuf[i], false);                              false);
   
                         /*                          /*
                          * There's still more in that thar buffer. This                           * There's still more in that thar buffer. This time,
                          * time, though, we know there's no newline at                           * though, we know there's no newline at the end, so we
                          * the end, so we add one of our own free will.                           * add one of our own free will.
                          */                           */
                         if (*cp != '\0') {                          if (*cp != '\0') {
                                 if (job->node != lastNode) {                                  if (job->node != lastNode) {
Line 1705 
Line 1660 
   
                 } else {                  } else {
                         /*                          /*
                          * We have written everything out, so we just                           * We have written everything out, so we just start over
                          * start over from the start of the buffer. No                           * from the start of the buffer. No copying. No nothing.
                          * copying.  No nothing.  
                          */                           */
                         job->curPos = 0;                          job->curPos = 0;
                 }                  }
         }          }
         if (finish) {          if (finish) {
                 /*                  /*
                  * If the finish flag is true, we must loop until we                   * If the finish flag is true, we must loop until we hit
                  * hit end-of-file on the pipe. This is guaranteed to                   * end-of-file on the pipe. This is guaranteed to happen
                  * happen eventually since the other end of the pipe is                   * eventually since the other end of the pipe is now closed
                  * now closed (we closed it explicitly and the child                   * (we closed it explicitly and the child has exited). When
                  * has exited). When we do get an EOF, finish will be                   * we do get an EOF, finish will be set false and we'll fall
                  * set false and we'll fall through and out.                   * through and out.
                  */                   */
                 goto end_loop;                  goto end_loop;
         }          }
Line 1743 
Line 1697 
 void  void
 Job_CatchChildren()  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 */
         LstNode jnode;          /* list element for finding job */          LstNode jnode;  /* list element for finding job */
         int status;             /* Exit/termination status */          int status;     /* Exit/termination status */
   
         /*          /*
          * Don't even bother if we know there's no one around.           * Don't even bother if we know there's no one around.
          */           */
         if (nLocal == 0) {          if (nJobs == 0) {
                 return;                  return;
         }          }
   
Line 1790 
Line 1744 
                                 (void)fflush(stdout);                                  (void)fflush(stdout);
                         }                          }
                         jobFull = false;                          jobFull = false;
                         nLocal--;  
                 }                  }
   
                 JobFinish(job, &status);                  JobFinish(job, &status);
Line 1820 
Line 1773 
   
         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);
   
         (void)fflush(stdout);          (void)fflush(stdout);
         if (readfdsp == NULL)          if (readfdsp == NULL)
                 return;                  return;
Line 1874 
Line 1826 
  *-----------------------------------------------------------------------   *-----------------------------------------------------------------------
  */   */
 void  void
 Job_Init(int      maxproc,  /* the greatest number of jobs which may be  Job_Init(int maxproc)
                              * 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 */  
         int tfd;          int tfd;
   
         (void)strlcpy(tfile, TMPPAT, sizeof(tfile));          (void)strlcpy(tfile, TMPPAT, sizeof(tfile));
Line 1891 
Line 1839 
         Static_Lst_Init(&jobs);          Static_Lst_Init(&jobs);
         Static_Lst_Init(&stoppedJobs);          Static_Lst_Init(&stoppedJobs);
         maxJobs =         maxproc;          maxJobs =         maxproc;
         maxLocal =        maxlocal;  
         nJobs =   0;  
         nLocal =          0;  
         jobFull =         false;          jobFull =         false;
   
         aborting =        0;          aborting =        0;
Line 1948 
Line 1893 
         }          }
 #endif  #endif
   
         begin = Targ_FindNode(".BEGIN", TARG_NOCREATE);          if ((begin_node->type & OP_DUMMY) == 0) {
                   JobStart(begin_node, JOB_SPECIAL, (Job *)0);
         if (begin != NULL) {  
                 JobStart(begin, JOB_SPECIAL, (Job *)0);  
                 while (nJobs) {                  while (nJobs) {
                         Job_CatchOutput();                          Job_CatchOutput();
                         Job_CatchChildren();                          Job_CatchChildren();
                 }                  }
         }          }
         postCommands = Targ_FindNode(".END", TARG_CREATE);  
 }  }
   
 /*-  /*-
Line 2026 
Line 1968 
     int signo)                  /* signal received */      int signo)                  /* signal received */
 {  {
         LstNode ln;             /* element in job table */          LstNode ln;             /* element in job table */
         Job  *job;              /* job descriptor in that element */          Job *job;               /* job descriptor in that element */
         GNode *interrupt;       /* the node describing the .INTERRUPT target */  
   
         aborting = ABORT_INTERRUPT;          aborting = ABORT_INTERRUPT;
   
Line 2053 
Line 1994 
         }          }
   
         if (runINTERRUPT && !touchFlag) {          if (runINTERRUPT && !touchFlag) {
                 interrupt = Targ_FindNode(".INTERRUPT", TARG_NOCREATE);                  if ((interrupt_node->type & OP_DUMMY) == 0) {
                 if (interrupt != NULL) {  
                         ignoreErrors = false;                          ignoreErrors = false;
   
                         JobStart(interrupt, JOB_IGNDOTS, (Job *)0);                          JobStart(interrupt_node, JOB_IGNDOTS, (Job *)0);
                         while (nJobs) {                          while (nJobs) {
                                 Job_CatchOutput();                                  Job_CatchOutput();
                                 Job_CatchChildren();                                  Job_CatchChildren();
Line 2085 
Line 2025 
 int  int
 Job_Finish(void)  Job_Finish(void)
 {  {
         if (postCommands != NULL && !Lst_IsEmpty(&postCommands->commands)) {          if (end_node != NULL && !Lst_IsEmpty(&end_node->commands)) {
                 if (errors) {                  if (errors) {
                         Error("Errors reported so .END ignored");                          Error("Errors reported so .END ignored");
                 } else {                  } else {
                         JobStart(postCommands, JOB_SPECIAL | JOB_IGNDOTS, NULL);                          JobStart(end_node, JOB_SPECIAL | JOB_IGNDOTS, NULL);
   
                         while (nJobs) {                          while (nJobs) {
                                 Job_CatchOutput();                                  Job_CatchOutput();
Line 2101 
Line 2041 
         return errors;          return errors;
 }  }
   
 /*-  
  *-----------------------------------------------------------------------  
  * Job_End --  
  *      Cleanup any memory used by the jobs module  
  *  
  * Side Effects:  
  *      Memory is freed  
  *-----------------------------------------------------------------------  
  */  
 #ifdef CLEANUP  #ifdef CLEANUP
 void  void
 Job_End(void)  Job_End(void)
 {  {
         efree(shellArgv);  
 }  }
 #endif  #endif
   

Legend:
Removed from v.1.77  
changed lines
  Added in v.1.78