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