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