1 /*
   2  * CDDL HEADER START
   3  *
   4  * The contents of this file are subject to the terms of the
   5  * Common Development and Distribution License (the "License").
   6  * You may not use this file except in compliance with the License.
   7  *
   8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
   9  * or http://www.opensolaris.org/os/licensing.
  10  * See the License for the specific language governing permissions
  11  * and limitations under the License.
  12  *
  13  * When distributing Covered Code, include this CDDL HEADER in each
  14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  15  * If applicable, add the following below this CDDL HEADER, with the
  16  * fields enclosed by brackets "[]" replaced with your own identifying
  17  * information: Portions Copyright [yyyy] [name of copyright owner]
  18  *
  19  * CDDL HEADER END
  20  */
  21 /*
  22  * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
  23  * Use is subject to license terms.
  24  */
  25 
  26 #ifdef TEAMWARE_MAKE_CMN
  27 
  28 /*
  29  *      parallel.cc
  30  *
  31  *      Deal with the parallel processing
  32  */
  33 
  34 /*
  35  * Included files
  36  */
  37 #include <errno.h>                /* errno */
  38 #include <fcntl.h>
  39 #include <mk/defs.h>
  40 #include <mksh/dosys.h>           /* redirect_io() */
  41 #include <mksh/macro.h>           /* expand_value() */
  42 #include <mksh/misc.h>            /* getmem() */
  43 #include <sys/signal.h>
  44 #include <sys/stat.h>
  45 #include <sys/types.h>
  46 #include <sys/utsname.h>
  47 #include <sys/wait.h>
  48 #include <unistd.h>
  49 #include <netdb.h>
  50 
  51 
  52 
  53 /*
  54  * Defined macros
  55  */
  56 #define MAXRULES                100
  57 
  58 /*
  59  * This const should be in avo_dms/include/AvoDmakeCommand.h
  60  */
  61 const int local_host_mask = 0x20;
  62 
  63 
  64 /*
  65  * typedefs & structs
  66  */
  67 
  68 
  69 /*
  70  * Static variables
  71  */
  72 #ifdef TEAMWARE_MAKE_CMN
  73 static  Boolean         just_did_subtree = false;
  74 static  char            local_host[MAXNAMELEN] = "";
  75 static  char            user_name[MAXNAMELEN] = "";
  76 #endif
  77 static  int             pmake_max_jobs = 0;
  78 static  pid_t           process_running = -1;
  79 static  Running         *running_tail = &running_list;
  80 static  Name            subtree_conflict;
  81 static  Name            subtree_conflict2;
  82 
  83 
  84 /*
  85  * File table of contents
  86  */
  87 static  void            delete_running_struct(Running rp);
  88 static  Boolean         dependency_conflict(Name target);
  89 static  Doname          distribute_process(char **commands, Property line);
  90 static  void            doname_subtree(Name target, Boolean do_get, Boolean implicit);
  91 static  void            dump_out_file(char *filename, Boolean err);
  92 static  void            finish_doname(Running rp);
  93 static  void            maybe_reread_make_state(void);
  94 static  void            process_next(void);
  95 static  void            reset_conditionals(int cnt, Name *targets, Property *locals);
  96 static  pid_t           run_rule_commands(char *host, char **commands);
  97 static  Property        *set_conditionals(int cnt, Name *targets);
  98 static  void            store_conditionals(Running rp);
  99 
 100 
 101 /*
 102  *      execute_parallel(line, waitflg)
 103  *
 104  *      DMake 2.x:
 105  *      parallel mode: spawns a parallel process to execute the command group.
 106  *      distributed mode: sends the command group down the pipe to rxm.
 107  *
 108  *      Return value:
 109  *                              The result of the execution
 110  *
 111  *      Parameters:
 112  *              line            The command group to execute
 113  */
 114 Doname
 115 execute_parallel(Property line, Boolean waitflg, Boolean local)
 116 {
 117         int                     argcnt;
 118         int                     cmd_options = 0;
 119         char                    *commands[MAXRULES + 5];
 120         char                    *cp;
 121         Name                    dmake_name;
 122         Name                    dmake_value;
 123         int                     ignore;
 124         Name                    make_machines_name;
 125         char                    **p;
 126         Property                prop;
 127         Doname                  result = build_ok;
 128         Cmd_line                rule;
 129         Boolean                 silent_flag;
 130         Name                    target = line->body.line.target;
 131         Boolean                 wrote_state_file = false;
 132 
 133         if ((pmake_max_jobs == 0) &&
 134             (dmake_mode_type == parallel_mode)) {
 135                 if (local_host[0] == '\0') {
 136                         (void) gethostname(local_host, MAXNAMELEN);
 137                 }
 138                 MBSTOWCS(wcs_buffer, NOCATGETS("DMAKE_MAX_JOBS"));
 139                 dmake_name = GETNAME(wcs_buffer, FIND_LENGTH);
 140                 if (((prop = get_prop(dmake_name->prop, macro_prop)) != NULL) &&
 141                     ((dmake_value = prop->body.macro.value) != NULL)) {
 142                         pmake_max_jobs = atoi(dmake_value->string_mb);
 143                         if (pmake_max_jobs <= 0) {
 144                                 warning(catgets(catd, 1, 308, "DMAKE_MAX_JOBS cannot be less than or equal to zero."));
 145                                 warning(catgets(catd, 1, 309, "setting DMAKE_MAX_JOBS to %d."), PMAKE_DEF_MAX_JOBS);
 146                                 pmake_max_jobs = PMAKE_DEF_MAX_JOBS;
 147                         }
 148                 } else {
 149                         /*
 150                          * For backwards compatibility w/ PMake 1.x, when
 151                          * DMake 2.x is being run in parallel mode, DMake
 152                          * should parse the PMake startup file
 153                          * $(HOME)/.make.machines to get the pmake_max_jobs.
 154                          */
 155                         MBSTOWCS(wcs_buffer, NOCATGETS("PMAKE_MACHINESFILE"));
 156                         dmake_name = GETNAME(wcs_buffer, FIND_LENGTH);
 157                         if (((prop = get_prop(dmake_name->prop, macro_prop)) != NULL) &&
 158                             ((dmake_value = prop->body.macro.value) != NULL)) {
 159                                 make_machines_name = dmake_value;
 160                         } else {
 161                                 make_machines_name = NULL;
 162                         }
 163                         if ((pmake_max_jobs = read_make_machines(make_machines_name)) <= 0) {
 164                                 pmake_max_jobs = PMAKE_DEF_MAX_JOBS;
 165                         }
 166                 }
 167         }
 168 
 169         if ((dmake_mode_type == serial_mode) ||
 170             ((dmake_mode_type == parallel_mode) && (waitflg))) {
 171                 return (execute_serial(line));
 172         }
 173 
 174         {
 175                 p = commands;
 176         }
 177 
 178         argcnt = 0;
 179         for (rule = line->body.line.command_used;
 180              rule != NULL;
 181              rule = rule->next) {
 182                 if (posix && (touch || quest) && !rule->always_exec) {
 183                         continue;
 184                 }
 185                 if (vpath_defined) {
 186                         rule->command_line =
 187                           vpath_translation(rule->command_line);
 188                 }
 189                 if (dmake_mode_type == distributed_mode) {
 190                         cmd_options = 0;
 191                         if(local) {
 192                                 cmd_options |= local_host_mask;
 193                         }
 194                 } else {
 195                         silent_flag = false;
 196                         ignore = 0;
 197                 }
 198                 if (rule->command_line->hash.length > 0) {
 199                         if (++argcnt == MAXRULES) {
 200                                 if (dmake_mode_type == distributed_mode) {
 201                                         /* XXX - tell rxm to execute on local host. */
 202                                         /* I WAS HERE!!! */
 203                                 } else {
 204                                         /* Too many rules, run serially instead. */
 205                                         return build_serial;
 206                                 }
 207                         }
 208                         {
 209                                 if (rule->silent && !silent) {
 210                                         silent_flag = true;
 211                                 }
 212                                 if (rule->ignore_error) {
 213                                         ignore++;
 214                                 }
 215                                 /* XXX - need to add support for + prefix */
 216                                 if (silent_flag || ignore) {
 217                                         *p = getmem((silent_flag ? 1 : 0) +
 218                                                     ignore +
 219                                                     (strlen(rule->
 220                                                            command_line->
 221                                                            string_mb)) +
 222                                                     1);
 223                                         cp = *p++;
 224                                         if (silent_flag) {
 225                                                 *cp++ = (int) at_char;
 226                                         }
 227                                         if (ignore) {
 228                                                 *cp++ = (int) hyphen_char;
 229                                         }
 230                                         (void) strcpy(cp, rule->command_line->string_mb);
 231                                 } else {
 232                                         *p++ = rule->command_line->string_mb;
 233                                 }
 234                         }
 235                 }
 236         }
 237         if ((argcnt == 0) ||
 238             (report_dependencies_level > 0)) {
 239                 return build_ok;
 240         }
 241         {
 242                 *p = NULL;
 243 
 244                 Doname res = distribute_process(commands, line);
 245                 if (res == build_running) {
 246                         parallel_process_cnt++;
 247                 }
 248 
 249                 /*
 250                  * Return only those memory that were specially allocated
 251                  * for part of commands.
 252                  */
 253                 for (int i = 0; commands[i] != NULL; i++) {
 254                         if ((commands[i][0] == (int) at_char) ||
 255                             (commands[i][0] == (int) hyphen_char)) {
 256                                 retmem_mb(commands[i]);
 257                         }
 258                 }
 259                 return res;
 260         }
 261 }
 262 
 263 
 264 #ifdef TEAMWARE_MAKE_CMN
 265 #define MAXJOBS_ADJUST_RFE4694000
 266 
 267 #ifdef MAXJOBS_ADJUST_RFE4694000
 268 
 269 #include <unistd.h>       /* sysconf(_SC_NPROCESSORS_ONLN) */
 270 #include <sys/ipc.h>              /* ftok() */
 271 #include <sys/shm.h>              /* shmget(), shmat(), shmdt(), shmctl() */
 272 #include <semaphore.h>            /* sem_init(), sem_trywait(), sem_post(), sem_destroy() */
 273 #include <sys/loadavg.h>  /* getloadavg() */
 274 
 275 /*
 276  *      adjust_pmake_max_jobs (int pmake_max_jobs)
 277  *
 278  *      Parameters:
 279  *              pmake_max_jobs  - max jobs limit set by user
 280  *
 281  *      External functions used:
 282  *              sysconf()
 283  *              getloadavg()
 284  */
 285 static int
 286 adjust_pmake_max_jobs (int pmake_max_jobs)
 287 {
 288         static int      ncpu = 0;
 289         double          loadavg[3];
 290         int             adjustment;
 291         int             adjusted_max_jobs;
 292 
 293         if (ncpu <= 0) {
 294                 if ((ncpu = sysconf(_SC_NPROCESSORS_ONLN)) <= 0) {
 295                         ncpu = 1;
 296                 }
 297         }
 298         if (getloadavg(loadavg, 3) != 3) return(pmake_max_jobs);
 299         adjustment = ((int)loadavg[LOADAVG_1MIN]);
 300         if (adjustment < 2) return(pmake_max_jobs);
 301         if (ncpu > 1) {
 302                 adjustment = adjustment / ncpu;
 303         }
 304         adjusted_max_jobs = pmake_max_jobs - adjustment;
 305         if (adjusted_max_jobs < 1) adjusted_max_jobs = 1;
 306         return(adjusted_max_jobs);
 307 }
 308 
 309 /*
 310  *  M2 adjust mode data and functions
 311  *
 312  *  m2_init()           - initializes M2 shared semaphore
 313  *  m2_acquire_job()    - decrements M2 semaphore counter
 314  *  m2_release_job()    - increments M2 semaphore counter
 315  *  m2_fini()           - destroys M2 semaphore and shared memory*
 316  *
 317  *  Environment variables:
 318  *      __DMAKE_M2_FILE__
 319  *
 320  *  External functions:
 321  *      ftok(), shmget(), shmat(), shmdt(), shmctl()
 322  *      sem_init(), sem_trywait(), sem_post(), sem_destroy()
 323  *      creat(), close(), unlink()
 324  *      getenv(), putenv()
 325  *
 326  *  Static variables:
 327  *      m2_file         - tmp file name to create ipc key for shared memory
 328  *      m2_shm_id       - shared memory id
 329  *      m2_shm_sem      - shared memory semaphore
 330  */
 331 
 332 static char     m2_file[MAXPATHLEN];
 333 static int      m2_shm_id = -1;
 334 static sem_t*   m2_shm_sem = 0;
 335 
 336 static int
 337 m2_init() {
 338         char    *var;
 339         key_t   key;
 340 
 341         if ((var = getenv(NOCATGETS("__DMAKE_M2_FILE__"))) == 0) {
 342                 /* compose tmp file name */
 343                 sprintf(m2_file, NOCATGETS("%s/dmake.m2.%d.XXXXXX"), tmpdir, getpid());
 344 
 345                 /* create tmp file */
 346                 int fd = mkstemp(m2_file);
 347                 if (fd < 0) {
 348                         return -1;
 349                 } else {
 350                         close(fd);
 351                 }
 352         } else {
 353                 /* using existing semaphore */
 354                 strcpy(m2_file, var);
 355         }
 356 
 357         /* combine IPC key */
 358         if ((key = ftok(m2_file, 38)) == (key_t) -1) {
 359                 return -1;
 360         }
 361 
 362         /* create shared memory */
 363         if ((m2_shm_id = shmget(key, sizeof(*m2_shm_sem), 0666 | (var ? 0 : IPC_CREAT|IPC_EXCL))) == -1) {
 364                 return -1;
 365         }
 366 
 367         /* attach shared memory */
 368         if ((m2_shm_sem = (sem_t*) shmat(m2_shm_id, 0, 0666)) == (sem_t*)-1) {
 369                 return -1;
 370         }
 371 
 372         /* root process */
 373         if (var == 0) {
 374                 /* initialize semaphore */
 375                 if (sem_init(m2_shm_sem, 1, pmake_max_jobs)) {
 376                         return -1;
 377                 }
 378 
 379                 /* alloc memory for env variable */
 380                 if ((var = (char*) malloc(MAXPATHLEN)) == 0) {
 381                         return -1;
 382                 }
 383 
 384                 /* put key to env */
 385                 sprintf(var, NOCATGETS("__DMAKE_M2_FILE__=%s"), m2_file);
 386                 if (putenv(var)) {
 387                         return -1;
 388                 }
 389         }
 390         return 0;
 391 }
 392 
 393 static void
 394 m2_fini() {
 395         if (m2_shm_id >= 0) {
 396                 struct shmid_ds stat;
 397 
 398                 /* determine the number of attached processes */
 399                 if (shmctl(m2_shm_id, IPC_STAT, &stat) == 0) {
 400                         if (stat.shm_nattch <= 1) {
 401                                 /* destroy semaphore */
 402                                 if (m2_shm_sem != 0) {
 403                                         (void) sem_destroy(m2_shm_sem);
 404                                 }
 405 
 406                                 /* destroy shared memory */
 407                                 (void) shmctl(m2_shm_id, IPC_RMID, &stat);
 408 
 409                                 /* remove tmp file created for the key */
 410                                 (void) unlink(m2_file);
 411                         } else {
 412                                 /* detach shared memory */
 413                                 if (m2_shm_sem != 0) {
 414                                         (void) shmdt((char*) m2_shm_sem);
 415                                 }
 416                         }
 417                 }
 418 
 419                 m2_shm_id = -1;
 420                 m2_shm_sem = 0;
 421         }
 422 }
 423 
 424 static int
 425 m2_acquire_job() {
 426         if ((m2_shm_id >= 0) && (m2_shm_sem != 0)) {
 427                 if (sem_trywait(m2_shm_sem) == 0) {
 428                         return 1;
 429                 }
 430                 if (errno == EAGAIN) {
 431                         return 0;
 432                 }
 433         }
 434         return -1;
 435 }
 436 
 437 static int
 438 m2_release_job() {
 439         if ((m2_shm_id >= 0) && (m2_shm_sem != 0)) {
 440                 if (sem_post(m2_shm_sem) == 0) {
 441                         return 0;
 442                 }
 443         }
 444         return -1;
 445 }
 446 
 447 /*
 448  *  job adjust mode
 449  *
 450  *  Possible values:
 451  *    ADJUST_M1         - adjustment by system load (default)
 452  *    ADJUST_M2         - fixed limit of jobs for the group of nested dmakes
 453  *    ADJUST_NONE       - no adjustment - fixed limit of jobs for the current dmake
 454  */
 455 static enum {
 456         ADJUST_UNKNOWN,
 457         ADJUST_M1,
 458         ADJUST_M2,
 459         ADJUST_NONE
 460 } job_adjust_mode = ADJUST_UNKNOWN;
 461 
 462 /*
 463  *  void job_adjust_fini()
 464  *
 465  *  Description:
 466  *      Cleans up job adjust data.
 467  *
 468  *  Static variables:
 469  *      job_adjust_mode Current job adjust mode
 470  */
 471 void
 472 job_adjust_fini() {
 473         if (job_adjust_mode == ADJUST_M2) {
 474                 m2_fini();
 475         }
 476 }
 477 
 478 /*
 479  *  void job_adjust_error()
 480  *
 481  *  Description:
 482  *      Prints warning message, cleans up job adjust data, and disables job adjustment
 483  *
 484  *  Environment:
 485  *      DMAKE_ADJUST_MAX_JOBS
 486  *
 487  *  External functions:
 488  *      putenv()
 489  *
 490  *  Static variables:
 491  *      job_adjust_mode Current job adjust mode
 492  */
 493 static void
 494 job_adjust_error() {
 495         if (job_adjust_mode != ADJUST_NONE) {
 496                 /* cleanup internals */
 497                 job_adjust_fini();
 498 
 499                 /* warning message for the user */
 500                 warning(catgets(catd, 1, 339, "Encountered max jobs auto adjustment error - disabling auto adjustment."));
 501 
 502                 /* switch off job adjustment for the children */
 503                 putenv(strdup(NOCATGETS("DMAKE_ADJUST_MAX_JOBS=NO")));
 504 
 505                 /* and for this dmake */
 506                 job_adjust_mode = ADJUST_NONE;
 507         }
 508 }
 509 
 510 /*
 511  *  void job_adjust_init()
 512  *
 513  *  Description:
 514  *      Parses DMAKE_ADJUST_MAX_JOBS env variable
 515  *      and performs appropriate initializations.
 516  *
 517  *  Environment:
 518  *      DMAKE_ADJUST_MAX_JOBS
 519  *        DMAKE_ADJUST_MAX_JOBS == "NO" - no adjustment
 520  *        DMAKE_ADJUST_MAX_JOBS == "M2" - M2 adjust mode
 521  *        other                         - M1 adjust mode
 522  *
 523  *  External functions:
 524  *      getenv()
 525  *
 526  *  Static variables:
 527  *      job_adjust_mode Current job adjust mode
 528  */
 529 static void
 530 job_adjust_init() {
 531         if (job_adjust_mode == ADJUST_UNKNOWN) {
 532                 /* default mode */
 533                 job_adjust_mode = ADJUST_M1;
 534 
 535                 /* determine adjust mode */
 536                 if (char *var = getenv(NOCATGETS("DMAKE_ADJUST_MAX_JOBS"))) {
 537                         if (strcasecmp(var, NOCATGETS("NO")) == 0) {
 538                                 job_adjust_mode = ADJUST_NONE;
 539                         } else if (strcasecmp(var, NOCATGETS("M2")) == 0) {
 540                                 job_adjust_mode = ADJUST_M2;
 541                         }
 542                 }
 543 
 544                 /* M2 specific initialization */
 545                 if (job_adjust_mode == ADJUST_M2) {
 546                         if (m2_init()) {
 547                                 job_adjust_error();
 548                         }
 549                 }
 550         }
 551 }
 552 
 553 #endif /* MAXJOBS_ADJUST_RFE4694000 */
 554 #endif /* TEAMWARE_MAKE_CMN */
 555 
 556 /*
 557  *      distribute_process(char **commands, Property line)
 558  *
 559  *      Parameters:
 560  *              commands        argv vector of commands to execute
 561  *
 562  *      Return value:
 563  *                              The result of the execution
 564  *
 565  *      Static variables used:
 566  *              process_running Set to the pid of the process set running
 567  * #if defined (TEAMWARE_MAKE_CMN) && defined (MAXJOBS_ADJUST_RFE4694000)
 568  *              job_adjust_mode Current job adjust mode
 569  * #endif
 570  */
 571 static Doname
 572 distribute_process(char **commands, Property line)
 573 {
 574         static unsigned file_number = 0;
 575         wchar_t         string[MAXPATHLEN];
 576         char            mbstring[MAXPATHLEN];
 577         int             filed;
 578         int             res;
 579         int             tmp_index;
 580         char            *tmp_index_str_ptr;
 581 
 582 #if !defined (TEAMWARE_MAKE_CMN) || !defined (MAXJOBS_ADJUST_RFE4694000)
 583         while (parallel_process_cnt >= pmake_max_jobs) {
 584                 await_parallel(false);
 585                 finish_children(true);
 586         }
 587 #else /* TEAMWARE_MAKE_CMN && MAXJOBS_ADJUST_RFE4694000 */
 588         /* initialize adjust mode, if not initialized */
 589         if (job_adjust_mode == ADJUST_UNKNOWN) {
 590                 job_adjust_init();
 591         }
 592 
 593         /* actions depend on adjust mode */
 594         switch (job_adjust_mode) {
 595         case ADJUST_M1:
 596                 while (parallel_process_cnt >= adjust_pmake_max_jobs (pmake_max_jobs)) {
 597                         await_parallel(false);
 598                         finish_children(true);
 599                 }
 600                 break;
 601         case ADJUST_M2:
 602                 if ((res = m2_acquire_job()) == 0) {
 603                         if (parallel_process_cnt > 0) {
 604                                 await_parallel(false);
 605                                 finish_children(true);
 606 
 607                                 if ((res = m2_acquire_job()) == 0) {
 608                                         return build_serial;
 609                                 }
 610                         } else {
 611                                 return build_serial;
 612                         }
 613                 }
 614                 if (res < 0) {
 615                         /* job adjustment error */
 616                         job_adjust_error();
 617 
 618                         /* no adjustment */
 619                         while (parallel_process_cnt >= pmake_max_jobs) {
 620                                 await_parallel(false);
 621                                 finish_children(true);
 622                         }
 623                 }
 624                 break;
 625         default:
 626                 while (parallel_process_cnt >= pmake_max_jobs) {
 627                         await_parallel(false);
 628                         finish_children(true);
 629                 }
 630         }
 631 #endif /* TEAMWARE_MAKE_CMN && MAXJOBS_ADJUST_RFE4694000 */
 632         setvar_envvar();
 633         /*
 634          * Tell the user what DMake is doing.
 635          */
 636         if (!silent && output_mode != txt2_mode) {
 637                 /*
 638                  * Print local_host --> x job(s).
 639                  */
 640                 (void) fprintf(stdout,
 641                                catgets(catd, 1, 325, "%s --> %d %s\n"),
 642                                local_host,
 643                                parallel_process_cnt + 1,
 644                                (parallel_process_cnt == 0) ? catgets(catd, 1, 124, "job") : catgets(catd, 1, 125, "jobs"));
 645 
 646                 /* Print command line(s). */
 647                 tmp_index = 0;
 648                 while (commands[tmp_index] != NULL) {
 649                     /* No @ char. */
 650                     /* XXX - need to add [2] when + prefix is added */
 651                     if ((commands[tmp_index][0] != (int) at_char) &&
 652                         (commands[tmp_index][1] != (int) at_char)) {
 653                         tmp_index_str_ptr = commands[tmp_index];
 654                         if (*tmp_index_str_ptr == (int) hyphen_char) {
 655                                 tmp_index_str_ptr++;
 656                         }
 657                         (void) fprintf(stdout, "%s\n", tmp_index_str_ptr);
 658                     }
 659                     tmp_index++;
 660                 }
 661                 (void) fflush(stdout);
 662         }
 663 
 664         (void) sprintf(mbstring,
 665                         NOCATGETS("%s/dmake.stdout.%d.%d.XXXXXX"),
 666                         tmpdir,
 667                         getpid(),
 668                         file_number++);
 669 
 670         mktemp(mbstring);
 671 
 672         stdout_file = strdup(mbstring);
 673         stderr_file = NULL;
 674 #if defined (TEAMWARE_MAKE_CMN)
 675         if (!out_err_same) {
 676                 (void) sprintf(mbstring,
 677                                 NOCATGETS("%s/dmake.stderr.%d.%d.XXXXXX"),
 678                                 tmpdir,
 679                                 getpid(),
 680                                 file_number++);
 681 
 682                 mktemp(mbstring);
 683 
 684                 stderr_file = strdup(mbstring);
 685         }
 686 #endif
 687 
 688         process_running = run_rule_commands(local_host, commands);
 689 
 690         return build_running;
 691 }
 692 
 693 /*
 694  *      doname_parallel(target, do_get, implicit)
 695  *
 696  *      Processes the given target and finishes up any parallel
 697  *      processes left running.
 698  *
 699  *      Return value:
 700  *                              Result of target build
 701  *
 702  *      Parameters:
 703  *              target          Target to build
 704  *              do_get          True if sccs get to be done
 705  *              implicit        True if this is an implicit target
 706  */
 707 Doname
 708 doname_parallel(Name target, Boolean do_get, Boolean implicit)
 709 {
 710         Doname          result;
 711 
 712         result = doname_check(target, do_get, implicit, false);
 713         if (result == build_ok || result == build_failed) {
 714                 return result;
 715         }
 716         finish_running();
 717         return (Doname) target->state;
 718 }
 719 
 720 /*
 721  *      doname_subtree(target, do_get, implicit)
 722  *
 723  *      Completely computes an object and its dependents for a
 724  *      serial subtree build.
 725  *
 726  *      Parameters:
 727  *              target          Target to build
 728  *              do_get          True if sccs get to be done
 729  *              implicit        True if this is an implicit target
 730  *
 731  *      Static variables used:
 732  *              running_tail    Tail of the list of running processes
 733  *
 734  *      Global variables used:
 735  *              running_list    The list of running processes
 736  */
 737 static void
 738 doname_subtree(Name target, Boolean do_get, Boolean implicit)
 739 {
 740         Running         save_running_list;
 741         Running         *save_running_tail;
 742 
 743         save_running_list = running_list;
 744         save_running_tail = running_tail;
 745         running_list = NULL;
 746         running_tail = &running_list;
 747         target->state = build_subtree;
 748         target->checking_subtree = true;
 749         while(doname_check(target, do_get, implicit, false) == build_running) {
 750                 target->checking_subtree = false;
 751                 finish_running();
 752                 target->state = build_subtree;
 753         }
 754         target->checking_subtree = false;
 755         running_list = save_running_list;
 756         running_tail = save_running_tail;
 757 }
 758 
 759 /*
 760  *      finish_running()
 761  *
 762  *      Keeps processing until the running_list is emptied out.
 763  *
 764  *      Parameters:
 765  *
 766  *      Global variables used:
 767  *              running_list    The list of running processes
 768  */
 769 void
 770 finish_running(void)
 771 {
 772         while (running_list != NULL) {
 773                 {
 774                         await_parallel(false);
 775                         finish_children(true);
 776                 }
 777                 if (running_list != NULL) {
 778                         process_next();
 779                 }
 780         }
 781 }
 782 
 783 /*
 784  *      process_next()
 785  *
 786  *      Searches the running list for any targets which can start processing.
 787  *      This can be a pending target, a serial target, or a subtree target.
 788  *
 789  *      Parameters:
 790  *
 791  *      Static variables used:
 792  *              running_tail            The end of the list of running procs
 793  *              subtree_conflict        A target which conflicts with a subtree
 794  *              subtree_conflict2       The other target which conflicts
 795  *
 796  *      Global variables used:
 797  *              commands_done           True if commands executed
 798  *              debug_level             Controls debug output
 799  *              parallel_process_cnt    Number of parallel process running
 800  *              recursion_level         Indentation for debug output
 801  *              running_list            List of running processes
 802  */
 803 static void
 804 process_next(void)
 805 {
 806         Running         rp;
 807         Running         *rp_prev;
 808         Property        line;
 809         Chain           target_group;
 810         Dependency      dep;
 811         Boolean         quiescent = true;
 812         Running         *subtree_target;
 813         Boolean         saved_commands_done;
 814         Property        *conditionals;
 815 
 816         subtree_target = NULL;
 817         subtree_conflict = NULL;
 818         subtree_conflict2 = NULL;
 819         /*
 820          * If nothing currently running, build a serial target, if any.
 821          */
 822 start_loop_1:
 823         for (rp_prev = &running_list, rp = running_list;
 824              rp != NULL && parallel_process_cnt == 0;
 825              rp = rp->next) {
 826                 if (rp->state == build_serial) {
 827                         *rp_prev = rp->next;
 828                         if (rp->next == NULL) {
 829                                 running_tail = rp_prev;
 830                         }
 831                         recursion_level = rp->recursion_level;
 832                         rp->target->state = build_pending;
 833                         (void) doname_check(rp->target,
 834                                             rp->do_get,
 835                                             rp->implicit,
 836                                             false);
 837                         quiescent = false;
 838                         delete_running_struct(rp);
 839                         goto start_loop_1;
 840                 } else {
 841                         rp_prev = &rp->next;
 842                 }
 843         }
 844         /*
 845          * Find a target to build.  The target must be pending, have all
 846          * its dependencies built, and not be in a target group with a target
 847          * currently building.
 848          */
 849 start_loop_2:
 850         for (rp_prev = &running_list, rp = running_list;
 851              rp != NULL;
 852              rp = rp->next) {
 853                 if (!(rp->state == build_pending ||
 854                       rp->state == build_subtree)) {
 855                         quiescent = false;
 856                         rp_prev = &rp->next;
 857                 } else if (rp->state == build_pending) {
 858                         line = get_prop(rp->target->prop, line_prop);
 859                         for (dep = line->body.line.dependencies;
 860                              dep != NULL;
 861                              dep = dep->next) {
 862                                 if (dep->name->state == build_running ||
 863                                     dep->name->state == build_pending ||
 864                                     dep->name->state == build_serial) {
 865                                         break;
 866                                 }
 867                         }
 868                         if (dep == NULL) {
 869                                 for (target_group = line->body.line.target_group;
 870                                      target_group != NULL;
 871                                      target_group = target_group->next) {
 872                                         if (is_running(target_group->name)) {
 873                                                 break;
 874                                         }
 875                                 }
 876                                 if (target_group == NULL) {
 877                                         *rp_prev = rp->next;
 878                                         if (rp->next == NULL) {
 879                                                 running_tail = rp_prev;
 880                                         }
 881                                         recursion_level = rp->recursion_level;
 882                                         rp->target->state = rp->redo ?
 883                                           build_dont_know : build_pending;
 884                                         saved_commands_done = commands_done;
 885                                         conditionals =
 886                                                 set_conditionals
 887                                                     (rp->conditional_cnt,
 888                                                      rp->conditional_targets);
 889                                         rp->target->dont_activate_cond_values = true;
 890                                         if ((doname_check(rp->target,
 891                                                           rp->do_get,
 892                                                           rp->implicit,
 893                                                           rp->target->has_target_prop ? true : false) !=
 894                                              build_running) &&
 895                                             !commands_done) {
 896                                                 commands_done =
 897                                                   saved_commands_done;
 898                                         }
 899                                         rp->target->dont_activate_cond_values = false;
 900                                         reset_conditionals
 901                                                 (rp->conditional_cnt,
 902                                                  rp->conditional_targets,
 903                                                  conditionals);
 904                                         quiescent = false;
 905                                         delete_running_struct(rp);
 906                                         goto start_loop_2;
 907                                 } else {
 908                                         rp_prev = &rp->next;
 909                                 }
 910                         } else {
 911                                 rp_prev = &rp->next;
 912                         }
 913                 } else {
 914                         rp_prev = &rp->next;
 915                 }
 916         }
 917         /*
 918          * If nothing has been found to build and there exists a subtree
 919          * target with no dependency conflicts, build it.
 920          */
 921         if (quiescent) {
 922 start_loop_3:
 923                 for (rp_prev = &running_list, rp = running_list;
 924                      rp != NULL;
 925                      rp = rp->next) {
 926                         if (rp->state == build_subtree) {
 927                                 if (!dependency_conflict(rp->target)) {
 928                                         *rp_prev = rp->next;
 929                                         if (rp->next == NULL) {
 930                                                 running_tail = rp_prev;
 931                                         }
 932                                         recursion_level = rp->recursion_level;
 933                                         doname_subtree(rp->target,
 934                                                        rp->do_get,
 935                                                        rp->implicit);
 936                                         quiescent = false;
 937                                         delete_running_struct(rp);
 938                                         goto start_loop_3;
 939                                 } else {
 940                                         subtree_target = rp_prev;
 941                                         rp_prev = &rp->next;
 942                                 }
 943                         } else {
 944                                 rp_prev = &rp->next;
 945                         }
 946                 }
 947         }
 948         /*
 949          * If still nothing found to build, we either have a deadlock
 950          * or a subtree with a dependency conflict with something waiting
 951          * to build.
 952          */
 953         if (quiescent) {
 954                 if (subtree_target == NULL) {
 955                         fatal(catgets(catd, 1, 126, "Internal error: deadlock detected in process_next"));
 956                 } else {
 957                         rp = *subtree_target;
 958                         if (debug_level > 0) {
 959                                 warning(catgets(catd, 1, 127, "Conditional macro conflict encountered for %s between %s and %s"),
 960                                         subtree_conflict2->string_mb,
 961                                         rp->target->string_mb,
 962                                         subtree_conflict->string_mb);
 963                         }
 964                         *subtree_target = (*subtree_target)->next;
 965                         if (rp->next == NULL) {
 966                                 running_tail = subtree_target;
 967                         }
 968                         recursion_level = rp->recursion_level;
 969                         doname_subtree(rp->target, rp->do_get, rp->implicit);
 970                         delete_running_struct(rp);
 971                 }
 972         }
 973 }
 974 
 975 /*
 976  *      set_conditionals(cnt, targets)
 977  *
 978  *      Sets the conditional macros for the targets given in the array of
 979  *      targets.  The old macro values are returned in an array of
 980  *      Properties for later resetting.
 981  *
 982  *      Return value:
 983  *                                      Array of conditional macro settings
 984  *
 985  *      Parameters:
 986  *              cnt                     Number of targets
 987  *              targets                 Array of targets
 988  */
 989 static Property *
 990 set_conditionals(int cnt, Name *targets)
 991 {
 992         Property        *locals, *lp;
 993         Name            *tp;
 994 
 995         locals = (Property *) getmem(cnt * sizeof(Property));
 996         for (lp = locals, tp = targets;
 997              cnt > 0;
 998              cnt--, lp++, tp++) {
 999                 *lp = (Property) getmem((*tp)->conditional_cnt *
1000                                         sizeof(struct _Property));
1001                 set_locals(*tp, *lp);
1002         }
1003         return locals;
1004 }
1005 
1006 /*
1007  *      reset_conditionals(cnt, targets, locals)
1008  *
1009  *      Resets the conditional macros as saved in the given array of
1010  *      Properties.  The resets are done in reverse order.  Afterwards the
1011  *      data structures are freed.
1012  *
1013  *      Parameters:
1014  *              cnt                     Number of targets
1015  *              targets                 Array of targets
1016  *              locals                  Array of dependency macro settings
1017  */
1018 static void
1019 reset_conditionals(int cnt, Name *targets, Property *locals)
1020 {
1021         Name            *tp;
1022         Property        *lp;
1023 
1024         for (tp = targets + (cnt - 1), lp = locals + (cnt - 1);
1025              cnt > 0;
1026              cnt--, tp--, lp--) {
1027                 reset_locals(*tp,
1028                              *lp,
1029                              get_prop((*tp)->prop, conditional_prop),
1030                              0);
1031                 retmem_mb((caddr_t) *lp);
1032         }
1033         retmem_mb((caddr_t) locals);
1034 }
1035 
1036 /*
1037  *      dependency_conflict(target)
1038  *
1039  *      Returns true if there is an intersection between
1040  *      the subtree of the target and any dependents of the pending targets.
1041  *
1042  *      Return value:
1043  *                                      True if conflict found
1044  *
1045  *      Parameters:
1046  *              target                  Subtree target to check
1047  *
1048  *      Static variables used:
1049  *              subtree_conflict        Target conflict found
1050  *              subtree_conflict2       Second conflict found
1051  *
1052  *      Global variables used:
1053  *              running_list            List of running processes
1054  *              wait_name               .WAIT, not a real dependency
1055  */
1056 static Boolean
1057 dependency_conflict(Name target)
1058 {
1059         Property        line;
1060         Property        pending_line;
1061         Dependency      dp;
1062         Dependency      pending_dp;
1063         Running         rp;
1064 
1065         /* Return if we are already checking this target */
1066         if (target->checking_subtree) {
1067                 return false;
1068         }
1069         target->checking_subtree = true;
1070         line = get_prop(target->prop, line_prop);
1071         if (line == NULL) {
1072                 target->checking_subtree = false;
1073                 return false;
1074         }
1075         /* Check each dependency of the target for conflicts */
1076         for (dp = line->body.line.dependencies; dp != NULL; dp = dp->next) {
1077                 /* Ignore .WAIT dependency */
1078                 if (dp->name == wait_name) {
1079                         continue;
1080                 }
1081                 /*
1082                  * For each pending target, look for a dependency which
1083                  * is the same as a dependency of the subtree target.  Since
1084                  * we can't build the subtree until all pending targets have
1085                  * finished which depend on the same dependency, this is
1086                  * a conflict.
1087                  */
1088                 for (rp = running_list; rp != NULL; rp = rp->next) {
1089                         if (rp->state == build_pending) {
1090                                 pending_line = get_prop(rp->target->prop,
1091                                                         line_prop);
1092                                 if (pending_line == NULL) {
1093                                         continue;
1094                                 }
1095                                 for(pending_dp = pending_line->
1096                                                         body.line.dependencies;
1097                                     pending_dp != NULL;
1098                                     pending_dp = pending_dp->next) {
1099                                         if (dp->name == pending_dp->name) {
1100                                                 target->checking_subtree
1101                                                                 = false;
1102                                                 subtree_conflict = rp->target;
1103                                                 subtree_conflict2 = dp->name;
1104                                                 return true;
1105                                         }
1106                                 }
1107                         }
1108                 }
1109                 if (dependency_conflict(dp->name)) {
1110                         target->checking_subtree = false;
1111                         return true;
1112                 }
1113         }
1114         target->checking_subtree = false;
1115         return false;
1116 }
1117 
1118 /*
1119  *      await_parallel(waitflg)
1120  *
1121  *      Waits for parallel children to exit and finishes their processing.
1122  *      If waitflg is false, the function returns after update_delay.
1123  *
1124  *      Parameters:
1125  *              waitflg         dwight
1126  */
1127 void
1128 await_parallel(Boolean waitflg)
1129 {
1130         Boolean         nohang;
1131         pid_t           pid;
1132         int             status;
1133         Running         rp;
1134         int             waiterr;
1135 
1136         nohang = false;
1137         for ( ; ; ) {
1138                 if (!nohang) {
1139                         (void) alarm((int) update_delay);
1140                 }
1141                 pid = waitpid((pid_t)-1,
1142                               &status,
1143                               nohang ? WNOHANG : 0);
1144                 waiterr = errno;
1145                 if (!nohang) {
1146                         (void) alarm(0);
1147                 }
1148                 if (pid <= 0) {
1149                         if (waiterr == EINTR) {
1150                                 if (waitflg) {
1151                                         continue;
1152                                 } else {
1153                                         return;
1154                                 }
1155                         } else {
1156                                 return;
1157                         }
1158                 }
1159                 for (rp = running_list;
1160                      (rp != NULL) && (rp->pid != pid);
1161                      rp = rp->next) {
1162                         ;
1163                 }
1164                 if (rp == NULL) {
1165                         if (send_mtool_msgs) {
1166                                 continue;
1167                         } else {
1168                                 fatal(catgets(catd, 1, 128, "Internal error: returned child pid not in running_list"));
1169                         }
1170                 } else {
1171                         rp->state = (WIFEXITED(status) && WEXITSTATUS(status) == 0) ? build_ok : build_failed;
1172                 }
1173                 nohang = true;
1174                 parallel_process_cnt--;
1175 
1176 #if defined (TEAMWARE_MAKE_CMN) && defined (MAXJOBS_ADJUST_RFE4694000)
1177                 if (job_adjust_mode == ADJUST_M2) {
1178                         if (m2_release_job()) {
1179                                 job_adjust_error();
1180                         }
1181                 }
1182 #endif
1183         }
1184 }
1185 
1186 /*
1187  *      finish_children(docheck)
1188  *
1189  *      Finishes the processing for all targets which were running
1190  *      and have now completed.
1191  *
1192  *      Parameters:
1193  *              docheck         Completely check the finished target
1194  *
1195  *      Static variables used:
1196  *              running_tail    The tail of the running list
1197  *
1198  *      Global variables used:
1199  *              continue_after_error  -k flag
1200  *              fatal_in_progress  True if we are finishing up after fatal err
1201  *              running_list    List of running processes
1202  */
1203 void
1204 finish_children(Boolean docheck)
1205 {
1206         int             cmds_length;
1207         Property        line;
1208         Property        line2;
1209         struct stat     out_buf;
1210         Running         rp;
1211         Running         *rp_prev;
1212         Cmd_line        rule;
1213         Boolean         silent_flag;
1214 
1215         for (rp_prev = &running_list, rp = running_list;
1216              rp != NULL;
1217              rp = rp->next) {
1218 bypass_for_loop_inc_4:
1219                 /*
1220                  * If the state is ok or failed, then this target has
1221                  * finished building.
1222                  * In parallel_mode, output the accumulated stdout/stderr.
1223                  * Read the auto dependency stuff, handle a failed build,
1224                  * update the target, then finish the doname process for
1225                  * that target.
1226                  */
1227                 if (rp->state == build_ok || rp->state == build_failed) {
1228                         *rp_prev = rp->next;
1229                         if (rp->next == NULL) {
1230                                 running_tail = rp_prev;
1231                         }
1232                         if ((line2 = rp->command) == NULL) {
1233                                 line2 = get_prop(rp->target->prop, line_prop);
1234                         }
1235                         if (dmake_mode_type == distributed_mode) {
1236                                 if (rp->make_refd) {
1237                                         maybe_reread_make_state();
1238                                 }
1239                         } else {
1240                                 /*
1241                                  * Check if there were any job output
1242                                  * from the parallel build.
1243                                  */
1244                                 if (rp->stdout_file != NULL) {
1245                                         if (stat(rp->stdout_file, &out_buf) < 0) {
1246                                                 fatal(catgets(catd, 1, 130, "stat of %s failed: %s"),
1247                                                       rp->stdout_file,
1248                                                       errmsg(errno));
1249                                         }
1250                                         if ((line2 != NULL) &&
1251                                             (out_buf.st_size > 0)) {
1252                                                 cmds_length = 0;
1253                                                 for (rule = line2->body.line.command_used,
1254                                                      silent_flag = silent;
1255                                                      rule != NULL;
1256                                                      rule = rule->next) {
1257                                                         cmds_length += rule->command_line->hash.length + 1;
1258                                                         silent_flag = BOOLEAN(silent_flag || rule->silent);
1259                                                 }
1260                                                 if (out_buf.st_size != cmds_length || silent_flag ||
1261                                                     output_mode == txt2_mode) {
1262                                                         dump_out_file(rp->stdout_file, false);
1263                                                 }
1264                                         }
1265                                         (void) unlink(rp->stdout_file);
1266                                         retmem_mb(rp->stdout_file);
1267                                         rp->stdout_file = NULL;
1268                                 }
1269 
1270                                 if (!out_err_same && (rp->stderr_file != NULL)) {
1271                                         if (stat(rp->stderr_file, &out_buf) < 0) {
1272                                                 fatal(catgets(catd, 1, 130, "stat of %s failed: %s"),
1273                                                       rp->stderr_file,
1274                                                       errmsg(errno));
1275                                         }
1276                                         if ((line2 != NULL) &&
1277                                             (out_buf.st_size > 0)) {
1278                                                 dump_out_file(rp->stderr_file, true);
1279                                         }
1280                                         (void) unlink(rp->stderr_file);
1281                                         retmem_mb(rp->stderr_file);
1282                                         rp->stderr_file = NULL;
1283                                 }
1284                         }
1285                         check_state(rp->temp_file);
1286                         if (rp->temp_file != NULL) {
1287                                 free_name(rp->temp_file);
1288                         }
1289                         rp->temp_file = NULL;
1290                         if (rp->state == build_failed) {
1291                                 line = get_prop(rp->target->prop, line_prop);
1292                                 if (line != NULL) {
1293                                         line->body.line.command_used = NULL;
1294                                 }
1295                                 if (continue_after_error ||
1296                                     fatal_in_progress ||
1297                                     !docheck) {
1298                                         warning(catgets(catd, 1, 256, "Command failed for target `%s'"),
1299                                                 rp->command ? line2->body.line.target->string_mb : rp->target->string_mb);
1300                                         build_failed_seen = true;
1301                                 } else {
1302                                         /*
1303                                          * XXX??? - DMake needs to exit(),
1304                                          * but shouldn't call fatal().
1305                                          */
1306 #ifdef PRINT_EXIT_STATUS
1307                                         warning(NOCATGETS("I'm in finish_children. rp->state == build_failed."));
1308 #endif
1309 
1310                                         fatal(catgets(catd, 1, 258, "Command failed for target `%s'"),
1311                                                 rp->command ? line2->body.line.target->string_mb : rp->target->string_mb);
1312                                 }
1313                         }
1314                         if (!docheck) {
1315                                 delete_running_struct(rp);
1316                                 rp = *rp_prev;
1317                                 if (rp == NULL) {
1318                                         break;
1319                                 } else {
1320                                         goto bypass_for_loop_inc_4;
1321                                 }
1322                         }
1323                         update_target(get_prop(rp->target->prop, line_prop),
1324                                       rp->state);
1325                         finish_doname(rp);
1326                         delete_running_struct(rp);
1327                         rp = *rp_prev;
1328                         if (rp == NULL) {
1329                                 break;
1330                         } else {
1331                                 goto bypass_for_loop_inc_4;
1332                         }
1333                 } else {
1334                         rp_prev = &rp->next;
1335                 }
1336         }
1337 }
1338 
1339 /*
1340  *      dump_out_file(filename, err)
1341  *
1342  *      Write the contents of the file to stdout, then unlink the file.
1343  *
1344  *      Parameters:
1345  *              filename        Name of temp file containing output
1346  *
1347  *      Global variables used:
1348  */
1349 static void
1350 dump_out_file(char *filename, Boolean err)
1351 {
1352         int             chars_read;
1353         char            copybuf[BUFSIZ];
1354         int             fd;
1355         int             out_fd = (err ? 2 : 1);
1356 
1357         if ((fd = open(filename, O_RDONLY)) < 0) {
1358                 fatal(catgets(catd, 1, 141, "open failed for output file %s: %s"),
1359                       filename,
1360                       errmsg(errno));
1361         }
1362         if (!silent && output_mode != txt2_mode) {
1363                 (void) fprintf(err ? stderr : stdout,
1364                                err ?
1365                                 catgets(catd, 1, 338, "%s --> Job errors\n") :
1366                                 catgets(catd, 1, 259, "%s --> Job output\n"),
1367                                local_host);
1368                 (void) fflush(err ? stderr : stdout);
1369         }
1370         for (chars_read = read(fd, copybuf, BUFSIZ);
1371              chars_read > 0;
1372              chars_read = read(fd, copybuf, BUFSIZ)) {
1373                 /*
1374                  * Read buffers from the source file until end or error.
1375                  */
1376                 if (write(out_fd, copybuf, chars_read) < 0) {
1377                         fatal(catgets(catd, 1, 260, "write failed for output file %s: %s"),
1378                               filename,
1379                               errmsg(errno));
1380                 }
1381         }
1382         (void) close(fd);
1383         (void) unlink(filename);
1384 }
1385 
1386 /*
1387  *      finish_doname(rp)
1388  *
1389  *      Completes the processing for a target which was left running.
1390  *
1391  *      Parameters:
1392  *              rp              Running list entry for target
1393  *
1394  *      Global variables used:
1395  *              debug_level     Debug flag
1396  *              recursion_level Indentation for debug output
1397  */
1398 static void
1399 finish_doname(Running rp)
1400 {
1401         int             auto_count = rp->auto_count;
1402         Name            *automatics = rp->automatics;
1403         Doname          result = rp->state;
1404         Name            target = rp->target;
1405         Name            true_target = rp->true_target;
1406         Property        *conditionals;
1407 
1408         recursion_level = rp->recursion_level;
1409         if (result == build_ok) {
1410                 if (true_target == NULL) {
1411                         (void) printf(NOCATGETS("Target = %s\n"), target->string_mb);
1412                         (void) printf(NOCATGETS(" State = %d\n"), result);
1413                         fatal(NOCATGETS("Internal error: NULL true_target in finish_doname"));
1414                 }
1415                 /* If all went OK, set a nice timestamp */
1416                 if (true_target->stat.time == file_doesnt_exist) {
1417                         true_target->stat.time = file_max_time;
1418                 }
1419         }
1420         target->state = result;
1421         if (target->is_member) {
1422                 Property member;
1423 
1424                 /* Propagate the timestamp from the member file to the member */
1425                 if ((target->stat.time != file_max_time) &&
1426                     ((member = get_prop(target->prop, member_prop)) != NULL) &&
1427                     (exists(member->body.member.member) > file_doesnt_exist)) {
1428                         target->stat.time =
1429 /*
1430                           exists(member->body.member.member);
1431  */
1432                           member->body.member.member->stat.time;
1433                 }
1434         }
1435         /*
1436          * Check if we found any new auto dependencies when we
1437          * built the target.
1438          */
1439         if ((result == build_ok) && check_auto_dependencies(target,
1440                                                             auto_count,
1441                                                             automatics)) {
1442                 if (debug_level > 0) {
1443                         (void) printf(catgets(catd, 1, 261, "%*sTarget `%s' acquired new dependencies from build, checking all dependencies\n"),
1444                                       recursion_level,
1445                                       "",
1446                                       true_target->string_mb);
1447                 }
1448                 target->rechecking_target = true;
1449                 target->state = build_running;
1450 
1451                 /* [tolik, Tue Mar 25 1997]
1452                  * Fix for bug 4038824:
1453                  *       command line options set by conditional macros get dropped
1454                  * rp->conditional_cnt and rp->conditional_targets must be copied
1455                  * to new 'rp' during add_pending(). Set_conditionals() stores
1456                  * rp->conditional_targets to the global variable 'conditional_targets'
1457                  * Add_pending() will use this variable to set up 'rp'.
1458                  */
1459                 conditionals = set_conditionals(rp->conditional_cnt, rp->conditional_targets);
1460                 add_pending(target,
1461                             recursion_level,
1462                             rp->do_get,
1463                             rp->implicit,
1464                             true);
1465                 reset_conditionals(rp->conditional_cnt, rp->conditional_targets, conditionals);
1466         }
1467 }
1468 
1469 /*
1470  *      new_running_struct()
1471  *
1472  *      Constructor for Running struct. Creates a structure and initializes
1473  *      its fields.
1474  *
1475  */
1476 static Running new_running_struct()
1477 {
1478         Running         rp;
1479 
1480         rp = ALLOC(Running);
1481         rp->target = NULL;
1482         rp->true_target = NULL;
1483         rp->command = NULL;
1484         rp->sprodep_value = NULL;
1485         rp->sprodep_env = NULL;
1486         rp->auto_count = 0;
1487         rp->automatics = NULL;
1488         rp->pid = -1;
1489         rp->job_msg_id = -1;
1490         rp->stdout_file = NULL;
1491         rp->stderr_file = NULL;
1492         rp->temp_file = NULL;
1493         rp->next = NULL;
1494         return rp;
1495 }
1496 
1497 /*
1498  *      add_running(target, true_target, command, recursion_level, auto_count,
1499  *                                      automatics, do_get, implicit)
1500  *
1501  *      Adds a record on the running list for this target, which
1502  *      was just spawned and is running.
1503  *
1504  *      Parameters:
1505  *              target          Target being built
1506  *              true_target     True target for target
1507  *              command         Running command.
1508  *              recursion_level Debug indentation level
1509  *              auto_count      Count of automatic dependencies
1510  *              automatics      List of automatic dependencies
1511  *              do_get          Sccs get flag
1512  *              implicit        Implicit flag
1513  *
1514  *      Static variables used:
1515  *              running_tail    Tail of running list
1516  *              process_running PID of process
1517  *
1518  *      Global variables used:
1519  *              current_line    Current line for target
1520  *              current_target  Current target being built
1521  *              stderr_file     Temporary file for stdout
1522  *              stdout_file     Temporary file for stdout
1523  *              temp_file_name  Temporary file for auto dependencies
1524  */
1525 void
1526 add_running(Name target, Name true_target, Property command, int recursion_level, int auto_count, Name *automatics, Boolean do_get, Boolean implicit)
1527 {
1528         Running         rp;
1529         Name            *p;
1530 
1531         rp = new_running_struct();
1532         rp->state = build_running;
1533         rp->target = target;
1534         rp->true_target = true_target;
1535         rp->command = command;
1536         rp->recursion_level = recursion_level;
1537         rp->do_get = do_get;
1538         rp->implicit = implicit;
1539         rp->auto_count = auto_count;
1540         if (auto_count > 0) {
1541                 rp->automatics = (Name *) getmem(auto_count * sizeof (Name));
1542                 for (p = rp->automatics; auto_count > 0; auto_count--) {
1543                         *p++ = *automatics++;
1544                 }
1545         } else {
1546                 rp->automatics = NULL;
1547         }
1548         {
1549                 rp->pid = process_running;
1550                 process_running = -1;
1551                 childPid = -1;
1552         }
1553         rp->job_msg_id = job_msg_id;
1554         rp->stdout_file = stdout_file;
1555         rp->stderr_file = stderr_file;
1556         rp->temp_file = temp_file_name;
1557         rp->redo = false;
1558         rp->next = NULL;
1559         store_conditionals(rp);
1560         stdout_file = NULL;
1561         stderr_file = NULL;
1562         temp_file_name = NULL;
1563         current_target = NULL;
1564         current_line = NULL;
1565         *running_tail = rp;
1566         running_tail = &rp->next;
1567 }
1568 
1569 /*
1570  *      add_pending(target, recursion_level, do_get, implicit, redo)
1571  *
1572  *      Adds a record on the running list for a pending target
1573  *      (waiting for its dependents to finish running).
1574  *
1575  *      Parameters:
1576  *              target          Target being built
1577  *              recursion_level Debug indentation level
1578  *              do_get          Sccs get flag
1579  *              implicit        Implicit flag
1580  *              redo            True if this target is being redone
1581  *
1582  *      Static variables used:
1583  *              running_tail    Tail of running list
1584  */
1585 void
1586 add_pending(Name target, int recursion_level, Boolean do_get, Boolean implicit, Boolean redo)
1587 {
1588         Running         rp;
1589         rp = new_running_struct();
1590         rp->state = build_pending;
1591         rp->target = target;
1592         rp->recursion_level = recursion_level;
1593         rp->do_get = do_get;
1594         rp->implicit = implicit;
1595         rp->redo = redo;
1596         store_conditionals(rp);
1597         *running_tail = rp;
1598         running_tail = &rp->next;
1599 }
1600 
1601 /*
1602  *      add_serial(target, recursion_level, do_get, implicit)
1603  *
1604  *      Adds a record on the running list for a target which must be
1605  *      executed in serial after others have finished.
1606  *
1607  *      Parameters:
1608  *              target          Target being built
1609  *              recursion_level Debug indentation level
1610  *              do_get          Sccs get flag
1611  *              implicit        Implicit flag
1612  *
1613  *      Static variables used:
1614  *              running_tail    Tail of running list
1615  */
1616 void
1617 add_serial(Name target, int recursion_level, Boolean do_get, Boolean implicit)
1618 {
1619         Running         rp;
1620 
1621         rp = new_running_struct();
1622         rp->target = target;
1623         rp->recursion_level = recursion_level;
1624         rp->do_get = do_get;
1625         rp->implicit = implicit;
1626         rp->state = build_serial;
1627         rp->redo = false;
1628         store_conditionals(rp);
1629         *running_tail = rp;
1630         running_tail = &rp->next;
1631 }
1632 
1633 /*
1634  *      add_subtree(target, recursion_level, do_get, implicit)
1635  *
1636  *      Adds a record on the running list for a target which must be
1637  *      executed in isolation after others have finished.
1638  *
1639  *      Parameters:
1640  *              target          Target being built
1641  *              recursion_level Debug indentation level
1642  *              do_get          Sccs get flag
1643  *              implicit        Implicit flag
1644  *
1645  *      Static variables used:
1646  *              running_tail    Tail of running list
1647  */
1648 void
1649 add_subtree(Name target, int recursion_level, Boolean do_get, Boolean implicit)
1650 {
1651         Running         rp;
1652 
1653         rp = new_running_struct();
1654         rp->target = target;
1655         rp->recursion_level = recursion_level;
1656         rp->do_get = do_get;
1657         rp->implicit = implicit;
1658         rp->state = build_subtree;
1659         rp->redo = false;
1660         store_conditionals(rp);
1661         *running_tail = rp;
1662         running_tail = &rp->next;
1663 }
1664 
1665 /*
1666  *      store_conditionals(rp)
1667  *
1668  *      Creates an array of the currently active targets with conditional
1669  *      macros (found in the chain conditional_targets) and puts that
1670  *      array in the Running struct.
1671  *
1672  *      Parameters:
1673  *              rp              Running struct for storing chain
1674  *
1675  *      Global variables used:
1676  *              conditional_targets  Chain of current dynamic conditionals
1677  */
1678 static void
1679 store_conditionals(Running rp)
1680 {
1681         int             cnt;
1682         Chain           cond_name;
1683 
1684         if (conditional_targets == NULL) {
1685                 rp->conditional_cnt = 0;
1686                 rp->conditional_targets = NULL;
1687                 return;
1688         }
1689         cnt = 0;
1690         for (cond_name = conditional_targets;
1691              cond_name != NULL;
1692              cond_name = cond_name->next) {
1693                 cnt++;
1694         }
1695         rp->conditional_cnt = cnt;
1696         rp->conditional_targets = (Name *) getmem(cnt * sizeof(Name));
1697         for (cond_name = conditional_targets;
1698              cond_name != NULL;
1699              cond_name = cond_name->next) {
1700                 rp->conditional_targets[--cnt] = cond_name->name;
1701         }
1702 }
1703 
1704 /*
1705  *      parallel_ok(target, line_prop_must_exists)
1706  *
1707  *      Returns true if the target can be run in parallel
1708  *
1709  *      Return value:
1710  *                              True if can run in parallel
1711  *
1712  *      Parameters:
1713  *              target          Target being tested
1714  *
1715  *      Global variables used:
1716  *              all_parallel    True if all targets default to parallel
1717  *              only_parallel   True if no targets default to parallel
1718  */
1719 Boolean
1720 parallel_ok(Name target, Boolean line_prop_must_exists)
1721 {
1722         Boolean         assign;
1723         Boolean         make_refd;
1724         Property        line;
1725         Cmd_line        rule;
1726 
1727         assign = make_refd = false;
1728         if (((line = get_prop(target->prop, line_prop)) == NULL) &&
1729             line_prop_must_exists) {
1730                 return false;
1731         }
1732         if (line != NULL) {
1733                 for (rule = line->body.line.command_used;
1734                      rule != NULL;
1735                      rule = rule->next) {
1736                         if (rule->assign) {
1737                                 assign = true;
1738                         } else if (rule->make_refd) {
1739                                 make_refd = true;
1740                         }
1741                 }
1742         }
1743         if (assign) {
1744                 return false;
1745         } else if (target->parallel) {
1746                 return true;
1747         } else if (target->no_parallel) {
1748                 return false;
1749         } else if (all_parallel) {
1750                 return true;
1751         } else if (only_parallel) {
1752                 return false;
1753         } else if (make_refd) {
1754                 return false;
1755         } else {
1756                 return true;
1757         }
1758 }
1759 
1760 /*
1761  *      is_running(target)
1762  *
1763  *      Returns true if the target is running.
1764  *
1765  *      Return value:
1766  *                              True if target is running
1767  *
1768  *      Parameters:
1769  *              target          Target to check
1770  *
1771  *      Global variables used:
1772  *              running_list    List of running processes
1773  */
1774 Boolean
1775 is_running(Name target)
1776 {
1777         Running         rp;
1778 
1779         if (target->state != build_running) {
1780                 return false;
1781         }
1782         for (rp = running_list;
1783              rp != NULL && target != rp->target;
1784              rp = rp->next);
1785         if (rp == NULL) {
1786                 return false;
1787         } else {
1788                 return (rp->state == build_running) ? true : false;
1789         }
1790 }
1791 
1792 /*
1793  * This function replaces the makesh binary.
1794  */
1795  
1796 
1797 static pid_t
1798 run_rule_commands(char *host, char **commands)
1799 {
1800         Boolean         always_exec;
1801         Name            command;
1802         Boolean         ignore;
1803         int             length;
1804         Doname          result;
1805         Boolean         silent_flag;
1806         wchar_t         *tmp_wcs_buffer;
1807 
1808         childPid = fork();
1809         switch (childPid) {
1810         case -1:        /* Error */
1811                 fatal(catgets(catd, 1, 337, "Could not fork child process for dmake job: %s"),
1812                       errmsg(errno));
1813                 break;
1814         case 0:         /* Child */
1815                 /* To control the processed targets list is not the child's business */
1816                 running_list = NULL;
1817                 if(out_err_same) {
1818                         redirect_io(stdout_file, (char*)NULL);
1819                 } else {
1820                         redirect_io(stdout_file, stderr_file);
1821                 }
1822                 for (commands = commands;
1823                      (*commands != (char *)NULL);
1824                      commands++) {
1825                         silent_flag = silent;
1826                         ignore = false;
1827                         always_exec = false;
1828                         while ((**commands == (int) at_char) ||
1829                                (**commands == (int) hyphen_char) ||
1830                                (**commands == (int) plus_char)) {
1831                                 if (**commands == (int) at_char) {
1832                                         silent_flag = true;
1833                                 }
1834                                 if (**commands == (int) hyphen_char) {
1835                                         ignore = true;
1836                                 }
1837                                 if (**commands == (int) plus_char) {
1838                                         always_exec = true;
1839                                 }
1840                                 (*commands)++;
1841                         }
1842                         if ((length = strlen(*commands)) >= MAXPATHLEN) {
1843                                 tmp_wcs_buffer = ALLOC_WC(length + 1);
1844                                 (void) mbstowcs(tmp_wcs_buffer, *commands, length + 1);
1845                                 command = GETNAME(tmp_wcs_buffer, FIND_LENGTH);
1846                                 retmem(tmp_wcs_buffer);
1847                         } else {
1848                                 MBSTOWCS(wcs_buffer, *commands);
1849                                 command = GETNAME(wcs_buffer, FIND_LENGTH);
1850                         }
1851                         if ((command->hash.length > 0) &&
1852                             !silent_flag) {
1853                                 (void) printf("%s\n", command->string_mb);
1854                         }
1855                         result = dosys(command,
1856                                        ignore,
1857                                        false,
1858                                        false, /* bugs #4085164 & #4990057 */
1859                                        /* BOOLEAN(silent_flag && ignore), */
1860                                        always_exec, 
1861                                        (Name) NULL,
1862                                        false);
1863                         if (result == build_failed) {
1864                                 if (silent_flag) {
1865                                         (void) printf(catgets(catd, 1, 152, "The following command caused the error:\n%s\n"), command->string_mb);
1866                                 }
1867                                 if (!ignore) {
1868                                         _exit(1);
1869                                 }
1870                         }
1871                 }
1872                 _exit(0);
1873                 break;
1874         default:
1875                 break;
1876         }
1877         return childPid;
1878 }
1879 
1880 static void
1881 maybe_reread_make_state(void)
1882 {
1883         /* Copying dosys()... */
1884         if (report_dependencies_level == 0) {
1885                 make_state->stat.time = file_no_time;
1886                 (void) exists(make_state);
1887                 if (make_state_before == make_state->stat.time) {
1888                         return;
1889                 }
1890                 makefile_type = reading_statefile;
1891                 if (read_trace_level > 1) {
1892                         trace_reader = true;
1893                 }
1894                 temp_file_number++;
1895                 (void) read_simple_file(make_state,
1896                                         false,
1897                                         false,
1898                                         false,
1899                                         false,
1900                                         false,
1901                                         true);
1902                 trace_reader = false;
1903         }
1904 }
1905 
1906 
1907 static void
1908 delete_running_struct(Running rp)
1909 {
1910         if ((rp->conditional_cnt > 0) &&
1911             (rp->conditional_targets != NULL)) {
1912                 retmem_mb((char *) rp->conditional_targets);
1913         }
1914 /**/
1915         if ((rp->auto_count > 0) &&
1916             (rp->automatics != NULL)) {
1917                 retmem_mb((char *) rp->automatics);
1918         }
1919 /**/
1920         if(rp->sprodep_value) {
1921                 free_name(rp->sprodep_value);
1922         }
1923         if(rp->sprodep_env) {
1924                 retmem_mb(rp->sprodep_env);
1925         }
1926         retmem_mb((char *) rp);
1927 
1928 }
1929 
1930 #endif
1931