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