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