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