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