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