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