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