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