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                         if (send_mtool_msgs) {
1148                                 continue;
1149                         } else {
1150                                 fatal(catgets(catd, 1, 128, "Internal error: returned child pid not in running_list"));
1151                         }
1152                 } else {
1153                         rp->state = (WIFEXITED(status) && WEXITSTATUS(status) == 0) ? build_ok : build_failed;
1154                 }
1155                 nohang = true;
1156                 parallel_process_cnt--;
1157 
1158 #if defined (TEAMWARE_MAKE_CMN) && defined (MAXJOBS_ADJUST_RFE4694000)
1159                 if (job_adjust_mode == ADJUST_M2) {
1160                         if (m2_release_job()) {
1161                                 job_adjust_error();
1162                         }
1163                 }
1164 #endif
1165         }
1166 }
1167 
1168 /*
1169  *      finish_children(docheck)
1170  *
1171  *      Finishes the processing for all targets which were running
1172  *      and have now completed.
1173  *
1174  *      Parameters:
1175  *              docheck         Completely check the finished target
1176  *
1177  *      Static variables used:
1178  *              running_tail    The tail of the running list
1179  *
1180  *      Global variables used:
1181  *              continue_after_error  -k flag
1182  *              fatal_in_progress  True if we are finishing up after fatal err
1183  *              running_list    List of running processes
1184  */
1185 void
1186 finish_children(Boolean docheck)
1187 {
1188         int             cmds_length;
1189         Property        line;
1190         Property        line2;
1191         struct stat     out_buf;
1192         Running         rp;
1193         Running         *rp_prev;
1194         Cmd_line        rule;
1195         Boolean         silent_flag;
1196 
1197         for (rp_prev = &running_list, rp = running_list;
1198              rp != NULL;
1199              rp = rp->next) {
1200 bypass_for_loop_inc_4:
1201                 /*
1202                  * If the state is ok or failed, then this target has
1203                  * finished building.
1204                  * In parallel_mode, output the accumulated stdout/stderr.
1205                  * Read the auto dependency stuff, handle a failed build,
1206                  * update the target, then finish the doname process for
1207                  * that target.
1208                  */
1209                 if (rp->state == build_ok || rp->state == build_failed) {
1210                         *rp_prev = rp->next;
1211                         if (rp->next == NULL) {
1212                                 running_tail = rp_prev;
1213                         }
1214                         if ((line2 = rp->command) == NULL) {
1215                                 line2 = get_prop(rp->target->prop, line_prop);
1216                         }
1217 
1218 
1219                         /*
1220                          * Check if there were any job output
1221                          * from the parallel build.
1222                          */
1223                         if (rp->stdout_file != NULL) {
1224                                 if (stat(rp->stdout_file, &out_buf) < 0) {
1225                                         fatal(catgets(catd, 1, 130, "stat of %s failed: %s"),
1226                                             rp->stdout_file,
1227                                             errmsg(errno));
1228                                 }
1229 
1230                                 if ((line2 != NULL) &&
1231                                     (out_buf.st_size > 0)) {
1232                                         cmds_length = 0;
1233                                         for (rule = line2->body.line.command_used,
1234                                                  silent_flag = silent;
1235                                              rule != NULL;
1236                                              rule = rule->next) {
1237                                                 cmds_length += rule->command_line->hash.length + 1;
1238                                                 silent_flag = BOOLEAN(silent_flag || rule->silent);
1239                                         }
1240                                         if (out_buf.st_size != cmds_length || silent_flag ||
1241                                             output_mode == txt2_mode) {
1242                                                 dump_out_file(rp->stdout_file, false);
1243                                         }
1244                                 }
1245                                 (void) unlink(rp->stdout_file);
1246                                 retmem_mb(rp->stdout_file);
1247                                 rp->stdout_file = NULL;
1248                         }
1249 
1250                         if (!out_err_same && (rp->stderr_file != NULL)) {
1251                                 if (stat(rp->stderr_file, &out_buf) < 0) {
1252                                         fatal(catgets(catd, 1, 130, "stat of %s failed: %s"),
1253                                             rp->stderr_file,
1254                                             errmsg(errno));
1255                                 }
1256                                 if ((line2 != NULL) &&
1257                                     (out_buf.st_size > 0)) {
1258                                         dump_out_file(rp->stderr_file, true);
1259                                 }
1260                                 (void) unlink(rp->stderr_file);
1261                                 retmem_mb(rp->stderr_file);
1262                                 rp->stderr_file = NULL;
1263                         }
1264                         
1265                         check_state(rp->temp_file);
1266                         if (rp->temp_file != NULL) {
1267                                 free_name(rp->temp_file);
1268                         }
1269                         rp->temp_file = NULL;
1270                         if (rp->state == build_failed) {
1271                                 line = get_prop(rp->target->prop, line_prop);
1272                                 if (line != NULL) {
1273                                         line->body.line.command_used = NULL;
1274                                 }
1275                                 if (continue_after_error ||
1276                                     fatal_in_progress ||
1277                                     !docheck) {
1278                                         warning(catgets(catd, 1, 256, "Command failed for target `%s'"),
1279                                                 rp->command ? line2->body.line.target->string_mb : rp->target->string_mb);
1280                                         build_failed_seen = true;
1281                                 } else {
1282                                         /*
1283                                          * XXX??? - DMake needs to exit(),
1284                                          * but shouldn't call fatal().
1285                                          */
1286 #ifdef PRINT_EXIT_STATUS
1287                                         warning(NOCATGETS("I'm in finish_children. rp->state == build_failed."));
1288 #endif
1289 
1290                                         fatal(catgets(catd, 1, 258, "Command failed for target `%s'"),
1291                                                 rp->command ? line2->body.line.target->string_mb : rp->target->string_mb);
1292                                 }
1293                         }
1294                         if (!docheck) {
1295                                 delete_running_struct(rp);
1296                                 rp = *rp_prev;
1297                                 if (rp == NULL) {
1298                                         break;
1299                                 } else {
1300                                         goto bypass_for_loop_inc_4;
1301                                 }
1302                         }
1303                         update_target(get_prop(rp->target->prop, line_prop),
1304                                       rp->state);
1305                         finish_doname(rp);
1306                         delete_running_struct(rp);
1307                         rp = *rp_prev;
1308                         if (rp == NULL) {
1309                                 break;
1310                         } else {
1311                                 goto bypass_for_loop_inc_4;
1312                         }
1313                 } else {
1314                         rp_prev = &rp->next;
1315                 }
1316         }
1317 }
1318 
1319 /*
1320  *      dump_out_file(filename, err)
1321  *
1322  *      Write the contents of the file to stdout, then unlink the file.
1323  *
1324  *      Parameters:
1325  *              filename        Name of temp file containing output
1326  *
1327  *      Global variables used:
1328  */
1329 static void
1330 dump_out_file(char *filename, Boolean err)
1331 {
1332         int             chars_read;
1333         char            copybuf[BUFSIZ];
1334         int             fd;
1335         int             out_fd = (err ? 2 : 1);
1336 
1337         if ((fd = open(filename, O_RDONLY)) < 0) {
1338                 fatal(catgets(catd, 1, 141, "open failed for output file %s: %s"),
1339                       filename,
1340                       errmsg(errno));
1341         }
1342         if (!silent && output_mode != txt2_mode) {
1343                 (void) fprintf(err ? stderr : stdout,
1344                                err ?
1345                                 catgets(catd, 1, 338, "%s --> Job errors\n") :
1346                                 catgets(catd, 1, 259, "%s --> Job output\n"),
1347                                local_host);
1348                 (void) fflush(err ? stderr : stdout);
1349         }
1350         for (chars_read = read(fd, copybuf, BUFSIZ);
1351              chars_read > 0;
1352              chars_read = read(fd, copybuf, BUFSIZ)) {
1353                 /*
1354                  * Read buffers from the source file until end or error.
1355                  */
1356                 if (write(out_fd, copybuf, chars_read) < 0) {
1357                         fatal(catgets(catd, 1, 260, "write failed for output file %s: %s"),
1358                               filename,
1359                               errmsg(errno));
1360                 }
1361         }
1362         (void) close(fd);
1363         (void) unlink(filename);
1364 }
1365 
1366 /*
1367  *      finish_doname(rp)
1368  *
1369  *      Completes the processing for a target which was left running.
1370  *
1371  *      Parameters:
1372  *              rp              Running list entry for target
1373  *
1374  *      Global variables used:
1375  *              debug_level     Debug flag
1376  *              recursion_level Indentation for debug output
1377  */
1378 static void
1379 finish_doname(Running rp)
1380 {
1381         int             auto_count = rp->auto_count;
1382         Name            *automatics = rp->automatics;
1383         Doname          result = rp->state;
1384         Name            target = rp->target;
1385         Name            true_target = rp->true_target;
1386         Property        *conditionals;
1387 
1388         recursion_level = rp->recursion_level;
1389         if (result == build_ok) {
1390                 if (true_target == NULL) {
1391                         (void) printf(NOCATGETS("Target = %s\n"), target->string_mb);
1392                         (void) printf(NOCATGETS(" State = %d\n"), result);
1393                         fatal(NOCATGETS("Internal error: NULL true_target in finish_doname"));
1394                 }
1395                 /* If all went OK, set a nice timestamp */
1396                 if (true_target->stat.time == file_doesnt_exist) {
1397                         true_target->stat.time = file_max_time;
1398                 }
1399         }
1400         target->state = result;
1401         if (target->is_member) {
1402                 Property member;
1403 
1404                 /* Propagate the timestamp from the member file to the member */
1405                 if ((target->stat.time != file_max_time) &&
1406                     ((member = get_prop(target->prop, member_prop)) != NULL) &&
1407                     (exists(member->body.member.member) > file_doesnt_exist)) {
1408                         target->stat.time =
1409 /*
1410                           exists(member->body.member.member);
1411  */
1412                           member->body.member.member->stat.time;
1413                 }
1414         }
1415         /*
1416          * Check if we found any new auto dependencies when we
1417          * built the target.
1418          */
1419         if ((result == build_ok) && check_auto_dependencies(target,
1420                                                             auto_count,
1421                                                             automatics)) {
1422                 if (debug_level > 0) {
1423                         (void) printf(catgets(catd, 1, 261, "%*sTarget `%s' acquired new dependencies from build, checking all dependencies\n"),
1424                                       recursion_level,
1425                                       "",
1426                                       true_target->string_mb);
1427                 }
1428                 target->rechecking_target = true;
1429                 target->state = build_running;
1430 
1431                 /* [tolik, Tue Mar 25 1997]
1432                  * Fix for bug 4038824:
1433                  *       command line options set by conditional macros get dropped
1434                  * rp->conditional_cnt and rp->conditional_targets must be copied
1435                  * to new 'rp' during add_pending(). Set_conditionals() stores
1436                  * rp->conditional_targets to the global variable 'conditional_targets'
1437                  * Add_pending() will use this variable to set up 'rp'.
1438                  */
1439                 conditionals = set_conditionals(rp->conditional_cnt, rp->conditional_targets);
1440                 add_pending(target,
1441                             recursion_level,
1442                             rp->do_get,
1443                             rp->implicit,
1444                             true);
1445                 reset_conditionals(rp->conditional_cnt, rp->conditional_targets, conditionals);
1446         }
1447 }
1448 
1449 /*
1450  *      new_running_struct()
1451  *
1452  *      Constructor for Running struct. Creates a structure and initializes
1453  *      its fields.
1454  *
1455  */
1456 static Running new_running_struct()
1457 {
1458         Running         rp;
1459 
1460         rp = ALLOC(Running);
1461         rp->target = NULL;
1462         rp->true_target = NULL;
1463         rp->command = NULL;
1464         rp->sprodep_value = NULL;
1465         rp->sprodep_env = NULL;
1466         rp->auto_count = 0;
1467         rp->automatics = NULL;
1468         rp->pid = -1;
1469         rp->job_msg_id = -1;
1470         rp->stdout_file = NULL;
1471         rp->stderr_file = NULL;
1472         rp->temp_file = NULL;
1473         rp->next = NULL;
1474         return rp;
1475 }
1476 
1477 /*
1478  *      add_running(target, true_target, command, recursion_level, auto_count,
1479  *                                      automatics, do_get, implicit)
1480  *
1481  *      Adds a record on the running list for this target, which
1482  *      was just spawned and is running.
1483  *
1484  *      Parameters:
1485  *              target          Target being built
1486  *              true_target     True target for target
1487  *              command         Running command.
1488  *              recursion_level Debug indentation level
1489  *              auto_count      Count of automatic dependencies
1490  *              automatics      List of automatic dependencies
1491  *              do_get          Sccs get flag
1492  *              implicit        Implicit flag
1493  *
1494  *      Static variables used:
1495  *              running_tail    Tail of running list
1496  *              process_running PID of process
1497  *
1498  *      Global variables used:
1499  *              current_line    Current line for target
1500  *              current_target  Current target being built
1501  *              stderr_file     Temporary file for stdout
1502  *              stdout_file     Temporary file for stdout
1503  *              temp_file_name  Temporary file for auto dependencies
1504  */
1505 void
1506 add_running(Name target, Name true_target, Property command, int recursion_level, int auto_count, Name *automatics, Boolean do_get, Boolean implicit)
1507 {
1508         Running         rp;
1509         Name            *p;
1510 
1511         rp = new_running_struct();
1512         rp->state = build_running;
1513         rp->target = target;
1514         rp->true_target = true_target;
1515         rp->command = command;
1516         rp->recursion_level = recursion_level;
1517         rp->do_get = do_get;
1518         rp->implicit = implicit;
1519         rp->auto_count = auto_count;
1520         if (auto_count > 0) {
1521                 rp->automatics = (Name *) getmem(auto_count * sizeof (Name));
1522                 for (p = rp->automatics; auto_count > 0; auto_count--) {
1523                         *p++ = *automatics++;
1524                 }
1525         } else {
1526                 rp->automatics = NULL;
1527         }
1528         {
1529                 rp->pid = process_running;
1530                 process_running = -1;
1531                 childPid = -1;
1532         }
1533         rp->job_msg_id = job_msg_id;
1534         rp->stdout_file = stdout_file;
1535         rp->stderr_file = stderr_file;
1536         rp->temp_file = temp_file_name;
1537         rp->redo = false;
1538         rp->next = NULL;
1539         store_conditionals(rp);
1540         stdout_file = NULL;
1541         stderr_file = NULL;
1542         temp_file_name = NULL;
1543         current_target = NULL;
1544         current_line = NULL;
1545         *running_tail = rp;
1546         running_tail = &rp->next;
1547 }
1548 
1549 /*
1550  *      add_pending(target, recursion_level, do_get, implicit, redo)
1551  *
1552  *      Adds a record on the running list for a pending target
1553  *      (waiting for its dependents to finish running).
1554  *
1555  *      Parameters:
1556  *              target          Target being built
1557  *              recursion_level Debug indentation level
1558  *              do_get          Sccs get flag
1559  *              implicit        Implicit flag
1560  *              redo            True if this target is being redone
1561  *
1562  *      Static variables used:
1563  *              running_tail    Tail of running list
1564  */
1565 void
1566 add_pending(Name target, int recursion_level, Boolean do_get, Boolean implicit, Boolean redo)
1567 {
1568         Running         rp;
1569         rp = new_running_struct();
1570         rp->state = build_pending;
1571         rp->target = target;
1572         rp->recursion_level = recursion_level;
1573         rp->do_get = do_get;
1574         rp->implicit = implicit;
1575         rp->redo = redo;
1576         store_conditionals(rp);
1577         *running_tail = rp;
1578         running_tail = &rp->next;
1579 }
1580 
1581 /*
1582  *      add_serial(target, recursion_level, do_get, implicit)
1583  *
1584  *      Adds a record on the running list for a target which must be
1585  *      executed in serial after others have finished.
1586  *
1587  *      Parameters:
1588  *              target          Target being built
1589  *              recursion_level Debug indentation level
1590  *              do_get          Sccs get flag
1591  *              implicit        Implicit flag
1592  *
1593  *      Static variables used:
1594  *              running_tail    Tail of running list
1595  */
1596 void
1597 add_serial(Name target, int recursion_level, Boolean do_get, Boolean implicit)
1598 {
1599         Running         rp;
1600 
1601         rp = new_running_struct();
1602         rp->target = target;
1603         rp->recursion_level = recursion_level;
1604         rp->do_get = do_get;
1605         rp->implicit = implicit;
1606         rp->state = build_serial;
1607         rp->redo = false;
1608         store_conditionals(rp);
1609         *running_tail = rp;
1610         running_tail = &rp->next;
1611 }
1612 
1613 /*
1614  *      add_subtree(target, recursion_level, do_get, implicit)
1615  *
1616  *      Adds a record on the running list for a target which must be
1617  *      executed in isolation after others have finished.
1618  *
1619  *      Parameters:
1620  *              target          Target being built
1621  *              recursion_level Debug indentation level
1622  *              do_get          Sccs get flag
1623  *              implicit        Implicit flag
1624  *
1625  *      Static variables used:
1626  *              running_tail    Tail of running list
1627  */
1628 void
1629 add_subtree(Name target, int recursion_level, Boolean do_get, Boolean implicit)
1630 {
1631         Running         rp;
1632 
1633         rp = new_running_struct();
1634         rp->target = target;
1635         rp->recursion_level = recursion_level;
1636         rp->do_get = do_get;
1637         rp->implicit = implicit;
1638         rp->state = build_subtree;
1639         rp->redo = false;
1640         store_conditionals(rp);
1641         *running_tail = rp;
1642         running_tail = &rp->next;
1643 }
1644 
1645 /*
1646  *      store_conditionals(rp)
1647  *
1648  *      Creates an array of the currently active targets with conditional
1649  *      macros (found in the chain conditional_targets) and puts that
1650  *      array in the Running struct.
1651  *
1652  *      Parameters:
1653  *              rp              Running struct for storing chain
1654  *
1655  *      Global variables used:
1656  *              conditional_targets  Chain of current dynamic conditionals
1657  */
1658 static void
1659 store_conditionals(Running rp)
1660 {
1661         int             cnt;
1662         Chain           cond_name;
1663 
1664         if (conditional_targets == NULL) {
1665                 rp->conditional_cnt = 0;
1666                 rp->conditional_targets = NULL;
1667                 return;
1668         }
1669         cnt = 0;
1670         for (cond_name = conditional_targets;
1671              cond_name != NULL;
1672              cond_name = cond_name->next) {
1673                 cnt++;
1674         }
1675         rp->conditional_cnt = cnt;
1676         rp->conditional_targets = (Name *) getmem(cnt * sizeof(Name));
1677         for (cond_name = conditional_targets;
1678              cond_name != NULL;
1679              cond_name = cond_name->next) {
1680                 rp->conditional_targets[--cnt] = cond_name->name;
1681         }
1682 }
1683 
1684 /*
1685  *      parallel_ok(target, line_prop_must_exists)
1686  *
1687  *      Returns true if the target can be run in parallel
1688  *
1689  *      Return value:
1690  *                              True if can run in parallel
1691  *
1692  *      Parameters:
1693  *              target          Target being tested
1694  *
1695  *      Global variables used:
1696  *              all_parallel    True if all targets default to parallel
1697  *              only_parallel   True if no targets default to parallel
1698  */
1699 Boolean
1700 parallel_ok(Name target, Boolean line_prop_must_exists)
1701 {
1702         Boolean         assign;
1703         Boolean         make_refd;
1704         Property        line;
1705         Cmd_line        rule;
1706 
1707         assign = make_refd = false;
1708         if (((line = get_prop(target->prop, line_prop)) == NULL) &&
1709             line_prop_must_exists) {
1710                 return false;
1711         }
1712         if (line != NULL) {
1713                 for (rule = line->body.line.command_used;
1714                      rule != NULL;
1715                      rule = rule->next) {
1716                         if (rule->assign) {
1717                                 assign = true;
1718                         } else if (rule->make_refd) {
1719                                 make_refd = true;
1720                         }
1721                 }
1722         }
1723         if (assign) {
1724                 return false;
1725         } else if (target->parallel) {
1726                 return true;
1727         } else if (target->no_parallel) {
1728                 return false;
1729         } else if (all_parallel) {
1730                 return true;
1731         } else if (only_parallel) {
1732                 return false;
1733         } else if (make_refd) {
1734                 return false;
1735         } else {
1736                 return true;
1737         }
1738 }
1739 
1740 /*
1741  *      is_running(target)
1742  *
1743  *      Returns true if the target is running.
1744  *
1745  *      Return value:
1746  *                              True if target is running
1747  *
1748  *      Parameters:
1749  *              target          Target to check
1750  *
1751  *      Global variables used:
1752  *              running_list    List of running processes
1753  */
1754 Boolean
1755 is_running(Name target)
1756 {
1757         Running         rp;
1758 
1759         if (target->state != build_running) {
1760                 return false;
1761         }
1762         for (rp = running_list;
1763              rp != NULL && target != rp->target;
1764              rp = rp->next);
1765         if (rp == NULL) {
1766                 return false;
1767         } else {
1768                 return (rp->state == build_running) ? true : false;
1769         }
1770 }
1771 
1772 /*
1773  * This function replaces the makesh binary.
1774  */
1775  
1776 
1777 static pid_t
1778 run_rule_commands(char *host, char **commands)
1779 {
1780         Boolean         always_exec;
1781         Name            command;
1782         Boolean         ignore;
1783         int             length;
1784         Doname          result;
1785         Boolean         silent_flag;
1786         wchar_t         *tmp_wcs_buffer;
1787 
1788         childPid = fork();
1789         switch (childPid) {
1790         case -1:        /* Error */
1791                 fatal(catgets(catd, 1, 337, "Could not fork child process for dmake job: %s"),
1792                       errmsg(errno));
1793                 break;
1794         case 0:         /* Child */
1795                 /* To control the processed targets list is not the child's business */
1796                 running_list = NULL;
1797                 if(out_err_same) {
1798                         redirect_io(stdout_file, (char*)NULL);
1799                 } else {
1800                         redirect_io(stdout_file, stderr_file);
1801                 }
1802                 for (commands = commands;
1803                      (*commands != (char *)NULL);
1804                      commands++) {
1805                         silent_flag = silent;
1806                         ignore = false;
1807                         always_exec = false;
1808                         while ((**commands == (int) at_char) ||
1809                                (**commands == (int) hyphen_char) ||
1810                                (**commands == (int) plus_char)) {
1811                                 if (**commands == (int) at_char) {
1812                                         silent_flag = true;
1813                                 }
1814                                 if (**commands == (int) hyphen_char) {
1815                                         ignore = true;
1816                                 }
1817                                 if (**commands == (int) plus_char) {
1818                                         always_exec = true;
1819                                 }
1820                                 (*commands)++;
1821                         }
1822                         if ((length = strlen(*commands)) >= MAXPATHLEN) {
1823                                 tmp_wcs_buffer = ALLOC_WC(length + 1);
1824                                 (void) mbstowcs(tmp_wcs_buffer, *commands, length + 1);
1825                                 command = GETNAME(tmp_wcs_buffer, FIND_LENGTH);
1826                                 retmem(tmp_wcs_buffer);
1827                         } else {
1828                                 MBSTOWCS(wcs_buffer, *commands);
1829                                 command = GETNAME(wcs_buffer, FIND_LENGTH);
1830                         }
1831                         if ((command->hash.length > 0) &&
1832                             !silent_flag) {
1833                                 (void) printf("%s\n", command->string_mb);
1834                         }
1835                         result = dosys(command,
1836                                        ignore,
1837                                        false,
1838                                        false, /* bugs #4085164 & #4990057 */
1839                                        /* BOOLEAN(silent_flag && ignore), */
1840                                        always_exec, 
1841                                        (Name) NULL,
1842                                        false);
1843                         if (result == build_failed) {
1844                                 if (silent_flag) {
1845                                         (void) printf(catgets(catd, 1, 152, "The following command caused the error:\n%s\n"), command->string_mb);
1846                                 }
1847                                 if (!ignore) {
1848                                         _exit(1);
1849                                 }
1850                         }
1851                 }
1852                 _exit(0);
1853                 break;
1854         default:
1855                 break;
1856         }
1857         return childPid;
1858 }
1859 
1860 static void
1861 maybe_reread_make_state(void)
1862 {
1863         /* Copying dosys()... */
1864         if (report_dependencies_level == 0) {
1865                 make_state->stat.time = file_no_time;
1866                 (void) exists(make_state);
1867                 if (make_state_before == make_state->stat.time) {
1868                         return;
1869                 }
1870                 makefile_type = reading_statefile;
1871                 if (read_trace_level > 1) {
1872                         trace_reader = true;
1873                 }
1874                 temp_file_number++;
1875                 (void) read_simple_file(make_state,
1876                                         false,
1877                                         false,
1878                                         false,
1879                                         false,
1880                                         false,
1881                                         true);
1882                 trace_reader = false;
1883         }
1884 }
1885 
1886 
1887 static void
1888 delete_running_struct(Running rp)
1889 {
1890         if ((rp->conditional_cnt > 0) &&
1891             (rp->conditional_targets != NULL)) {
1892                 retmem_mb((char *) rp->conditional_targets);
1893         }
1894 /**/
1895         if ((rp->auto_count > 0) &&
1896             (rp->automatics != NULL)) {
1897                 retmem_mb((char *) rp->automatics);
1898         }
1899 /**/
1900         if(rp->sprodep_value) {
1901                 free_name(rp->sprodep_value);
1902         }
1903         if(rp->sprodep_env) {
1904                 retmem_mb(rp->sprodep_env);
1905         }
1906         retmem_mb((char *) rp);
1907 
1908 }
1909 
1910