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