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