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