1 /* 2 * Copyright (c) 2019 The DragonFly Project. All rights reserved. 3 * 4 * This code is derived from software contributed to The DragonFly Project 5 * by Matthew Dillon <dillon@backplane.com> 6 * 7 * This code uses concepts and configuration based on 'synth', by 8 * John R. Marino <draco@marino.st>, which was written in ada. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 14 * 1. Redistributions of source code must retain the above copyright 15 * notice, this list of conditions and the following disclaimer. 16 * 2. Redistributions in binary form must reproduce the above copyright 17 * notice, this list of conditions and the following disclaimer in 18 * the documentation and/or other materials provided with the 19 * distribution. 20 * 3. Neither the name of The DragonFly Project nor the names of its 21 * contributors may be used to endorse or promote products derived 22 * from this software without specific, prior written permission. 23 * 24 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 25 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 26 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 27 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 28 * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 29 * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING, 30 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 31 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 32 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 33 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 34 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 35 * SUCH DAMAGE. 36 */ 37 #include "dsynth.h" 38 39 worker_t WorkerAry[MAXWORKERS]; 40 int BuildInitialized; 41 int RunningWorkers; 42 int DynamicMaxWorkers; 43 int FailedWorkers; 44 long RunningPkgDepSize; 45 pthread_mutex_t WorkerMutex; 46 pthread_cond_t WorkerCond; 47 48 static int build_find_leaves(pkg_t *parent, pkg_t *pkg, 49 pkg_t ***build_tailp, int *app, int *hasworkp, 50 int depth, int first, int first_one_only); 51 static int buildCalculateDepiDepth(pkg_t *pkg); 52 static void build_clear_trav(pkg_t *pkg); 53 static void startbuild(pkg_t **build_listp, pkg_t ***build_tailp); 54 static int qsort_depi(const void *pkg1, const void *pkg2); 55 static int qsort_idep(const void *pkg1, const void *pkg2); 56 static void startworker(pkg_t *pkg, worker_t *work); 57 static void cleanworker(worker_t *work); 58 static void waitbuild(int whilematch, int dynamicmax); 59 static void workercomplete(worker_t *work); 60 static void *childBuilderThread(void *arg); 61 static int childInstallPkgDeps(worker_t *work); 62 static size_t childInstallPkgDeps_recurse(FILE *fp, pkglink_t *list, 63 int undoit, int depth, int first_one_only); 64 static void dophase(worker_t *work, wmsg_t *wmsg, 65 int wdog, int phaseid, const char *phase); 66 static void phaseReapAll(void); 67 static void phaseTerminateSignal(int sig); 68 static char *buildskipreason(pkglink_t *parent, pkg_t *pkg); 69 static int buildskipcount_dueto(pkg_t *pkg, int mode); 70 static int mptylogpoll(int ptyfd, int fdlog, wmsg_t *wmsg, 71 time_t *wdog_timep); 72 static void doHook(pkg_t *pkg, const char *id, const char *path, int waitfor); 73 static void childHookRun(bulk_t *bulk); 74 static void adjloadavg(double *dload); 75 76 static worker_t *SigWork; 77 static int MasterPtyFd = -1; 78 static int CopyFileFd = -1; 79 static pid_t SigPid; 80 static const char *WorkerFlavorPrt = ""; /* "" or "@flavor" */ 81 82 #define MPTY_FAILED -2 83 #define MPTY_AGAIN -1 84 #define MPTY_EOF 0 85 #define MPTY_DATA 1 86 87 int BuildTotal; 88 int BuildCount; 89 int BuildSkipCount; 90 int BuildIgnoreCount; 91 int BuildFailCount; 92 int BuildSuccessCount; 93 94 /* 95 * Initialize the WorkerAry[] 96 */ 97 void 98 DoInitBuild(int slot_override) 99 { 100 worker_t *work; 101 struct stat st; 102 int i; 103 104 ddassert(slot_override < 0 || MaxWorkers == 1); 105 106 bzero(WorkerAry, MaxWorkers * sizeof(worker_t)); 107 pthread_mutex_init(&WorkerMutex, NULL); 108 109 for (i = 0; i < MaxWorkers; ++i) { 110 work = &WorkerAry[i]; 111 work->index = (slot_override >= 0) ? slot_override : i; 112 work->state = WORKER_NONE; 113 asprintf(&work->basedir, "%s/SL%02d", BuildBase, work->index); 114 pthread_cond_init(&work->cond, NULL); 115 } 116 BuildCount = 0; 117 118 /* 119 * Create required sub-directories. The base directories must already 120 * exist as a dsynth configuration safety. 121 */ 122 if (stat(RepositoryPath, &st) < 0) { 123 if (mkdir(RepositoryPath, 0755) < 0) 124 dfatal("Cannot mkdir %s\n", RepositoryPath); 125 } 126 127 BuildInitialized = 1; 128 129 /* 130 * slow-start (increases at a rate of 1 per 5 seconds) 131 */ 132 if (SlowStartOpt > MaxWorkers) 133 DynamicMaxWorkers = MaxWorkers; 134 else if (SlowStartOpt > 0) 135 DynamicMaxWorkers = SlowStartOpt; 136 else 137 DynamicMaxWorkers = MaxWorkers; 138 } 139 140 /* 141 * Called by the frontend to clean-up any hanging mounts. 142 */ 143 void 144 DoCleanBuild(int resetlogs) 145 { 146 int i; 147 148 ddassert(BuildInitialized); 149 150 if (resetlogs) 151 dlogreset(); 152 for (i = 0; i < MaxWorkers; ++i) { 153 DoWorkerUnmounts(&WorkerAry[i]); 154 } 155 } 156 157 void 158 DoBuild(pkg_t *pkgs) 159 { 160 pkg_t *build_list = NULL; 161 pkg_t **build_tail = &build_list; 162 pkg_t *scan; 163 bulk_t *bulk; 164 int haswork = 1; 165 int first = 1; 166 int newtemplate; 167 time_t startTime; 168 time_t t; 169 int h, m, s; 170 171 /* 172 * We use our bulk system to run hooks. This will be for 173 * Skipped and Ignored. Success and Failure are handled by 174 * WorkerProcess() which is a separately-exec'd dsynth. 175 */ 176 if (UsingHooks) 177 initbulk(childHookRun, MaxBulk); 178 179 /* 180 * Count up the packages, not counting dummies 181 */ 182 for (scan = pkgs; scan; scan = scan->bnext) { 183 if ((scan->flags & PKGF_DUMMY) == 0) 184 ++BuildTotal; 185 } 186 187 doHook(NULL, "hook_run_start", HookRunStart, 1); 188 189 /* 190 * The pkg and pkg-static binaries are needed. If already present 191 * then assume that the template is also valid, otherwise build 192 * both. 193 */ 194 scan = GetPkgPkg(pkgs); 195 196 /* 197 * Create our template. The template will be missing pkg 198 * and pkg-static. 199 */ 200 if ((scan->flags & (PKGF_SUCCESS | PKGF_PACKAGED)) == 0) { 201 /* force a fresh template */ 202 newtemplate = DoCreateTemplate(1); 203 } else { 204 newtemplate = DoCreateTemplate(0); 205 } 206 207 /* 208 * This will clear the screen and set-up our gui, so sleep 209 * a little first in case the user wants to see what was 210 * printed before. 211 */ 212 sleep(2); 213 pthread_mutex_lock(&WorkerMutex); 214 startTime = time(NULL); 215 RunStatsInit(); 216 RunStatsReset(); 217 218 /* 219 * Build pkg/pkg-static. 220 */ 221 if ((scan->flags & (PKGF_SUCCESS | PKGF_PACKAGED)) == 0) { 222 build_list = scan; 223 build_tail = &scan->build_next; 224 startbuild(&build_list, &build_tail); 225 while (RunningWorkers == 1) 226 waitbuild(1, 0); 227 228 if (scan->flags & PKGF_NOBUILD) 229 dfatal("Unable to build 'pkg'"); 230 if (scan->flags & PKGF_ERROR) 231 dfatal("Error building 'pkg'"); 232 if ((scan->flags & PKGF_SUCCESS) == 0) 233 dfatal("Error building 'pkg'"); 234 newtemplate = 1; 235 } 236 237 /* 238 * Install pkg/pkg-static into the template 239 */ 240 if (newtemplate) { 241 char *buf; 242 int rc; 243 244 asprintf(&buf, 245 "cd %s/Template; " 246 "tar --exclude '+*' --exclude '*/man/*' " 247 "-xvzpf %s/%s > /dev/null 2>&1", 248 BuildBase, 249 RepositoryPath, 250 scan->pkgfile); 251 rc = system(buf); 252 if (rc) 253 dfatal("Command failed: %s\n", buf); 254 freestrp(&buf); 255 } 256 257 /* 258 * Calculate depi_depth, the longest chain of dependencies 259 * for who depends on me, weighted by powers of two. 260 */ 261 for (scan = pkgs; scan; scan = scan->bnext) { 262 buildCalculateDepiDepth(scan); 263 } 264 265 /* 266 * Nominal bulk build sequence 267 */ 268 while (haswork) { 269 haswork = 0; 270 fflush(stdout); 271 for (scan = pkgs; scan; scan = scan->bnext) { 272 ddprintf(0, "SCANLEAVES %08x %s\n", 273 scan->flags, scan->portdir); 274 scan->flags |= PKGF_BUILDLOOP; 275 /* 276 * NOTE: We must still find dependencies if PACKAGED 277 * to fill in the gaps, as some of them may 278 * need to be rebuilt. 279 */ 280 if (scan->flags & (PKGF_SUCCESS | PKGF_FAILURE | 281 PKGF_ERROR)) { 282 #if 0 283 ddprintf(0, "%s: already built\n", 284 scan->portdir); 285 #endif 286 } else { 287 int ap = 0; 288 build_find_leaves(NULL, scan, &build_tail, 289 &ap, &haswork, 0, first, 0); 290 ddprintf(0, "TOPLEVEL %s %08x\n", 291 scan->portdir, ap); 292 } 293 scan->flags &= ~PKGF_BUILDLOOP; 294 build_clear_trav(scan); 295 } 296 first = 0; 297 fflush(stdout); 298 startbuild(&build_list, &build_tail); 299 300 if (haswork == 0 && RunningWorkers) { 301 waitbuild(RunningWorkers, 1); 302 haswork = 1; 303 } 304 } 305 pthread_mutex_unlock(&WorkerMutex); 306 307 RunStatsUpdateTop(0); 308 RunStatsUpdateLogs(); 309 RunStatsSync(); 310 RunStatsDone(); 311 312 doHook(NULL, "hook_run_end", HookRunEnd, 1); 313 if (UsingHooks) { 314 while ((bulk = getbulk()) != NULL) 315 freebulk(bulk); 316 donebulk(); 317 } 318 319 t = time(NULL) - startTime; 320 h = t / 3600; 321 m = t / 60 % 60; 322 s = t % 60; 323 324 dlog(DLOG_ALL|DLOG_STDOUT, 325 "\n" 326 "Initial queue size: %d\n" 327 " packages built: %d\n" 328 " ignored: %d\n" 329 " skipped: %d\n" 330 " failed: %d\n" 331 "\n" 332 "Duration: %02d:%02d:%02d\n" 333 "\n", 334 BuildTotal, 335 BuildSuccessCount, 336 BuildIgnoreCount, 337 BuildSkipCount, 338 BuildFailCount, 339 h, m, s); 340 } 341 342 /* 343 * Traverse the packages (pkg) depends on recursively until we find 344 * a leaf to build or report as unbuildable. Calculates and assigns a 345 * dependency count. Returns all parallel-buildable packages. 346 * 347 * (pkg) itself is only added to the list if it is immediately buildable. 348 */ 349 static 350 int 351 build_find_leaves(pkg_t *parent, pkg_t *pkg, pkg_t ***build_tailp, 352 int *app, int *hasworkp, int depth, int first, 353 int first_one_only) 354 { 355 pkglink_t *link; 356 pkg_t *scan; 357 int idep_count = 0; 358 int apsub; 359 int dfirst_one_only; 360 int ndepth; 361 char *buf; 362 363 ndepth = depth + 1; 364 365 /* 366 * Already on build list, possibly in-progress, tell caller that 367 * it is not ready. 368 */ 369 ddprintf(ndepth, "sbuild_find_leaves %d %s %08x {\n", 370 depth, pkg->portdir, pkg->flags); 371 if (pkg->flags & PKGF_BUILDLIST) { 372 ddprintf(ndepth, "} (already on build list)\n"); 373 *app |= PKGF_NOTREADY; 374 return (pkg->idep_count); 375 } 376 377 /* 378 * Check dependencies 379 */ 380 PKGLIST_FOREACH(link, &pkg->idepon_list) { 381 scan = link->pkg; 382 383 if (scan == NULL) { 384 if (first_one_only) 385 break; 386 continue; 387 } 388 ddprintf(ndepth, "check %s %08x\t", scan->portdir, scan->flags); 389 390 /* 391 * If this dependency is to a DUMMY node it is a dependency 392 * only on the default flavor which is only the first node 393 * under this one, not all of them. 394 * 395 * DUMMY nodes can be marked SUCCESS so the build skips past 396 * them, but this doesn't mean that their sub-nodes succeeded. 397 * We have to check, so recurse even if it is marked 398 * successful. 399 * 400 * NOTE: The depth is not being for complex dependency type 401 * tests like it is in childInstallPkgDeps_recurse(), 402 * so we don't have to hicup it like we do in that 403 * procedure. 404 */ 405 dfirst_one_only = (scan->flags & PKGF_DUMMY) ? 1 : 0; 406 if (dfirst_one_only) 407 goto skip_to_flavor; 408 409 /* 410 * When accounting for a successful build, just bump 411 * idep_count by one. scan->idep_count will heavily 412 * overlap packages that we count down multiple branches. 413 * 414 * We must still recurse through PACKAGED packages as 415 * some of their dependencies might be missing. 416 */ 417 if (scan->flags & PKGF_SUCCESS) { 418 ddprintf(0, "SUCCESS - OK\n"); 419 ++idep_count; 420 if (first_one_only) 421 break; 422 continue; 423 } 424 425 /* 426 * ERROR includes FAILURE, which is set in numerous situations 427 * including when NOBUILD state is processed. So check for 428 * NOBUILD state first. 429 * 430 * An ERROR in a sub-package causes a NOBUILD in packages 431 * that depend on it. 432 */ 433 if (scan->flags & PKGF_NOBUILD) { 434 ddprintf(0, "NOBUILD - OK " 435 "(propagate failure upward)\n"); 436 *app |= PKGF_NOBUILD_S; 437 if (first_one_only) 438 break; 439 continue; 440 } 441 if (scan->flags & PKGF_ERROR) { 442 ddprintf(0, "ERROR - OK (propagate failure upward)\n"); 443 *app |= PKGF_NOBUILD_S; 444 if (first_one_only) 445 break; 446 continue; 447 } 448 449 /* 450 * If already on build-list this dependency is not ready. 451 */ 452 if (scan->flags & PKGF_BUILDLIST) { 453 ddprintf(0, " [BUILDLIST]"); 454 *app |= PKGF_NOTREADY; 455 } 456 457 /* 458 * If not packaged this dependency is not ready for 459 * the caller. 460 */ 461 if ((scan->flags & PKGF_PACKAGED) == 0) { 462 ddprintf(0, " [NOT_PACKAGED]"); 463 *app |= PKGF_NOTREADY; 464 } 465 466 /* 467 * Reduce search complexity, if we have already processed 468 * scan in the traversal it will either already be on the 469 * build list or it will not be buildable. Either way 470 * the parent is not buildable. 471 */ 472 if (scan->flags & PKGF_BUILDTRAV) { 473 ddprintf(0, " [BUILDTRAV]\n"); 474 *app |= PKGF_NOTREADY; 475 if (first_one_only) 476 break; 477 continue; 478 } 479 skip_to_flavor: 480 481 /* 482 * Assert on dependency loop 483 */ 484 ++idep_count; 485 if (scan->flags & PKGF_BUILDLOOP) { 486 dfatal("pkg dependency loop %s -> %s", 487 parent->portdir, scan->portdir); 488 } 489 490 /* 491 * NOTE: For debug tabbing purposes we use (ndepth + 1) 492 * here (i.e. depth + 2) in our iteration. 493 */ 494 scan->flags |= PKGF_BUILDLOOP; 495 apsub = 0; 496 ddprintf(0, " SUBRECURSION {\n"); 497 idep_count += build_find_leaves(pkg, scan, build_tailp, 498 &apsub, hasworkp, 499 ndepth + 1, first, 500 dfirst_one_only); 501 scan->flags &= ~PKGF_BUILDLOOP; 502 *app |= apsub; 503 if (apsub & PKGF_NOBUILD) { 504 ddprintf(ndepth, "} (sub-nobuild)\n"); 505 } else if (apsub & PKGF_ERROR) { 506 ddprintf(ndepth, "} (sub-error)\n"); 507 } else if (apsub & PKGF_NOTREADY) { 508 ddprintf(ndepth, "} (sub-notready)\n"); 509 } else { 510 ddprintf(ndepth, "} (sub-ok)\n"); 511 } 512 if (first_one_only) 513 break; 514 } 515 pkg->idep_count = idep_count; 516 pkg->flags |= PKGF_BUILDTRAV; 517 518 /* 519 * Incorporate scan results into pkg state. 520 */ 521 if ((pkg->flags & PKGF_NOBUILD) == 0 && (*app & PKGF_NOBUILD)) { 522 *hasworkp = 1; 523 } else if ((pkg->flags & PKGF_ERROR) == 0 && (*app & PKGF_ERROR)) { 524 *hasworkp = 1; 525 } 526 pkg->flags |= *app & ~PKGF_NOTREADY; 527 528 /* 529 * Clear PACKAGED bit if sub-dependencies aren't clean 530 */ 531 if ((pkg->flags & PKGF_PACKAGED) && 532 (pkg->flags & (PKGF_NOTREADY|PKGF_ERROR|PKGF_NOBUILD))) { 533 pkg->flags &= ~PKGF_PACKAGED; 534 ddassert(pkg->pkgfile); 535 asprintf(&buf, "%s/%s", RepositoryPath, pkg->pkgfile); 536 if (remove(buf) < 0) { 537 dlog(DLOG_ALL, 538 "[XXX] %s DELETE-PACKAGE %s (failed)\n", 539 pkg->portdir, buf); 540 } else { 541 dlog(DLOG_ALL, 542 "[XXX] %s DELETE-PACKAGE %s " 543 "(due to dependencies)\n", 544 pkg->portdir, buf); 545 } 546 freestrp(&buf); 547 *hasworkp = 1; 548 } 549 550 /* 551 * Set PKGF_NOBUILD_I if there is IGNORE data 552 */ 553 if (pkg->ignore) 554 pkg->flags |= PKGF_NOBUILD_I; 555 556 /* 557 * Handle propagated flags 558 */ 559 if (pkg->flags & PKGF_ERROR) { 560 /* 561 * This can only happen if the ERROR has already been 562 * processed and accounted for. 563 */ 564 ddprintf(depth, "} (ERROR - %s)\n", pkg->portdir); 565 } else if (*app & PKGF_NOTREADY) { 566 /* 567 * We don't set PKGF_NOTREADY in the pkg, it is strictly 568 * a transient flag propagated via build_find_leaves(). 569 * 570 * Just don't add the package to the list. 571 * 572 * NOTE: Even if NOBUILD is set (meaning we could list it 573 * and let startbuild() finish it up as a skip, we 574 * don't process it to the list because we want to 575 * process all the dependencies, so someone doing a 576 * manual build can get more complete information and 577 * does not have to iterate each failed dependency one 578 * at a time. 579 */ 580 ; 581 } else if (pkg->flags & PKGF_SUCCESS) { 582 ddprintf(depth, "} (SUCCESS - %s)\n", pkg->portdir); 583 } else if (pkg->flags & PKGF_DUMMY) { 584 /* 585 * Just mark dummy packages as successful when all of their 586 * sub-depends (flavors) complete successfully. Note that 587 * dummy packages are not counted in the total, so do not 588 * decrement BuildTotal. 589 * 590 * Do not propagate *app up for the dummy node. If there 591 * is a generic dependency (i.e. no flavor specified), the 592 * upper recursion detects PKGF_DUMMY and traverses through 593 * to the default flavor without checking error/nobuild 594 * flags. 595 */ 596 if (pkg->flags & PKGF_NOBUILD) { 597 ddprintf(depth, "} (DUMMY/META - IGNORED)\n"); 598 } else { 599 ddprintf(depth, "} (DUMMY/META - SUCCESS)\n"); 600 pkg->flags |= PKGF_SUCCESS; 601 *hasworkp = 1; 602 if (first) { 603 dlog(DLOG_ALL | DLOG_FILTER, 604 "[XXX] %s META-ALREADY-BUILT\n", 605 pkg->portdir); 606 } else { 607 dlog(DLOG_SUCC, "[XXX] %s meta-node complete\n", 608 pkg->portdir); 609 RunStatsUpdateCompletion(NULL, DLOG_SUCC, pkg, ""); 610 } 611 } 612 } else if (pkg->flags & PKGF_PACKAGED) { 613 /* 614 * We can just mark the pkg successful. If this is 615 * the first pass, we count this as an initial pruning 616 * pass and reduce BuildTotal. 617 */ 618 ddprintf(depth, "} (PACKAGED - SUCCESS)\n"); 619 pkg->flags |= PKGF_SUCCESS; 620 *hasworkp = 1; 621 if (first) { 622 dlog(DLOG_ALL | DLOG_FILTER, 623 "[XXX] %s ALREADY-BUILT\n", 624 pkg->portdir); 625 --BuildTotal; 626 } 627 } else { 628 /* 629 * All dependencies are successful, queue new work 630 * and indicate not-ready to the parent (since our 631 * package has to be built). 632 * 633 * NOTE: The NOBUILD case propagates to here as well 634 * and is ultimately handled by startbuild(). 635 */ 636 *hasworkp = 1; 637 if (pkg->flags & PKGF_NOBUILD_I) 638 ddprintf(depth, "} (ADDLIST(IGNORE/BROKEN) - %s)\n", 639 pkg->portdir); 640 else if (pkg->flags & PKGF_NOBUILD) 641 ddprintf(depth, "} (ADDLIST(NOBUILD) - %s)\n", 642 pkg->portdir); 643 else 644 ddprintf(depth, "} (ADDLIST - %s)\n", pkg->portdir); 645 pkg->flags |= PKGF_BUILDLIST; 646 **build_tailp = pkg; 647 *build_tailp = &pkg->build_next; 648 *app |= PKGF_NOTREADY; 649 } 650 651 return idep_count; 652 } 653 654 static 655 void 656 build_clear_trav(pkg_t *pkg) 657 { 658 pkglink_t *link; 659 pkg_t *scan; 660 661 pkg->flags &= ~PKGF_BUILDTRAV; 662 PKGLIST_FOREACH(link, &pkg->idepon_list) { 663 scan = link->pkg; 664 if (scan && (scan->flags & PKGF_BUILDTRAV)) 665 build_clear_trav(scan); 666 } 667 } 668 669 /* 670 * Calculate the longest chain of packages that depend on me. The 671 * long the chain, the more important my package is to build earlier 672 * rather than later. 673 */ 674 static int 675 buildCalculateDepiDepth(pkg_t *pkg) 676 { 677 pkglink_t *link; 678 pkg_t *scan; 679 int best_depth = 0; 680 int res; 681 682 if (pkg->depi_depth) 683 return(pkg->depi_depth + 1); 684 pkg->flags |= PKGF_BUILDLOOP; 685 PKGLIST_FOREACH(link, &pkg->deponi_list) { 686 scan = link->pkg; 687 if (scan && (scan->flags & PKGF_BUILDLOOP) == 0) { 688 res = buildCalculateDepiDepth(scan); 689 if (best_depth < res) 690 best_depth = res; 691 } 692 } 693 pkg->flags &= ~PKGF_BUILDLOOP; 694 pkg->depi_depth = best_depth; 695 696 return (best_depth + 1); 697 } 698 699 /* 700 * Take a list of pkg ready to go, sort it, and assign it to worker 701 * slots. This routine blocks in waitbuild() until it can dispose of 702 * the entire list. 703 * 704 * WorkerMutex is held by the caller. 705 */ 706 static 707 void 708 startbuild(pkg_t **build_listp, pkg_t ***build_tailp) 709 { 710 pkg_t *pkg; 711 pkg_t **idep_ary; 712 pkg_t **depi_ary; 713 int count; 714 int idep_index; 715 int depi_index; 716 int i; 717 int n; 718 worker_t *work; 719 static int IterateWorker; 720 721 /* 722 * Nothing to do 723 */ 724 if (*build_listp == NULL) 725 return; 726 727 /* 728 * Sort 729 */ 730 count = 0; 731 for (pkg = *build_listp; pkg; pkg = pkg->build_next) 732 ++count; 733 idep_ary = calloc(count, sizeof(pkg_t *)); 734 depi_ary = calloc(count, sizeof(pkg_t *)); 735 736 count = 0; 737 for (pkg = *build_listp; pkg; pkg = pkg->build_next) { 738 idep_ary[count] = pkg; 739 depi_ary[count] = pkg; 740 ++count; 741 } 742 743 /* 744 * idep_ary - sorted by #of dependencies this pkg has. 745 * depi_ary - sorted by #of other packages that depend on this pkg. 746 */ 747 qsort(idep_ary, count, sizeof(pkg_t *), qsort_idep); 748 qsort(depi_ary, count, sizeof(pkg_t *), qsort_depi); 749 750 idep_index = 0; 751 depi_index = 0; 752 753 /* 754 * Half the workers build based on the highest depi count, 755 * the other half build based on the highest idep count. 756 * 757 * This is an attempt to get projects which many other projects 758 * depend on built first, but to also try to build large projects 759 * (which tend to have a lot of dependencies) earlier rather than 760 * later so the end of the bulk run doesn't inefficiently build 761 * the last few huge projects. 762 * 763 * Loop until we manage to assign slots to everyone. We do not 764 * wait for build completion. 765 * 766 * This is the point where we handle DUMMY packages (these are 767 * dummy unflavored packages which 'cover' all the flavors for 768 * a package). These are not real packages are marked SUCCESS 769 * at this time because their dependencies (the flavors) have all 770 * been built. 771 */ 772 while (idep_index != count || depi_index != count) { 773 pkg_t *pkgi; 774 pkg_t *ipkg; 775 776 /* 777 * Find candidate to start sorted by depi or idep. 778 */ 779 ipkg = NULL; 780 while (idep_index < count) { 781 ipkg = idep_ary[idep_index]; 782 if ((ipkg->flags & 783 (PKGF_SUCCESS | PKGF_FAILURE | 784 PKGF_ERROR | PKGF_RUNNING)) == 0) { 785 break; 786 } 787 ipkg = NULL; 788 ++idep_index; 789 } 790 791 pkgi = NULL; 792 while (depi_index < count) { 793 pkgi = depi_ary[depi_index]; 794 if ((pkgi->flags & 795 (PKGF_SUCCESS | PKGF_FAILURE | 796 PKGF_ERROR | PKGF_RUNNING)) == 0) { 797 break; 798 } 799 pkgi = NULL; 800 ++depi_index; 801 } 802 803 /* 804 * ipkg and pkgi must either both be NULL, or both 805 * be non-NULL. 806 */ 807 if (ipkg == NULL && pkgi == NULL) 808 break; 809 ddassert(ipkg && pkgi); 810 811 /* 812 * Handle the NOBUILD case right here, there's no point 813 * queueing it anywhere. 814 */ 815 if (ipkg->flags & PKGF_NOBUILD) { 816 char *reason; 817 818 ipkg->flags |= PKGF_FAILURE; 819 ipkg->flags &= ~PKGF_BUILDLIST; 820 821 reason = buildskipreason(NULL, ipkg); 822 if (ipkg->flags & PKGF_NOBUILD_I) { 823 ++BuildIgnoreCount; 824 dlog(DLOG_IGN, "[XXX] %s ignored due to %s\n", 825 ipkg->portdir, reason); 826 RunStatsUpdateCompletion(NULL, DLOG_IGN, 827 ipkg, reason); 828 doHook(ipkg, "hook_pkg_ignored", 829 HookPkgIgnored, 0); 830 } else { 831 ++BuildSkipCount; 832 dlog(DLOG_SKIP, "[XXX] %s skipped due to %s\n", 833 ipkg->portdir, reason); 834 RunStatsUpdateCompletion(NULL, DLOG_SKIP, 835 ipkg, reason); 836 doHook(ipkg, "hook_pkg_skipped", 837 HookPkgSkipped, 0); 838 } 839 free(reason); 840 ++BuildCount; 841 continue; 842 } 843 if (pkgi->flags & PKGF_NOBUILD) { 844 char *reason; 845 846 pkgi->flags |= PKGF_FAILURE; 847 pkgi->flags &= ~PKGF_BUILDLIST; 848 849 reason = buildskipreason(NULL, pkgi); 850 if (pkgi->flags & PKGF_NOBUILD_I) { 851 ++BuildIgnoreCount; 852 dlog(DLOG_IGN, "[XXX] %s ignored due to %s\n", 853 pkgi->portdir, reason); 854 RunStatsUpdateCompletion(NULL, DLOG_IGN, 855 pkgi, reason); 856 doHook(pkgi, "hook_pkg_ignored", 857 HookPkgIgnored, 0); 858 } else { 859 ++BuildSkipCount; 860 dlog(DLOG_SKIP, "[XXX] %s skipped due to %s\n", 861 pkgi->portdir, reason); 862 RunStatsUpdateCompletion(NULL, DLOG_SKIP, 863 pkgi, reason); 864 doHook(pkgi, "hook_pkg_skipped", 865 HookPkgSkipped, 0); 866 } 867 free(reason); 868 ++BuildCount; 869 continue; 870 } 871 872 /* 873 * Block while no slots are available. waitbuild() 874 * will clean out any DONE states. 875 */ 876 while (RunningWorkers >= DynamicMaxWorkers || 877 RunningWorkers >= MaxWorkers - FailedWorkers) { 878 waitbuild(RunningWorkers, 1); 879 } 880 881 /* 882 * Find an available worker slot, there should be at 883 * least one. 884 */ 885 for (i = 0; i < MaxWorkers; ++i) { 886 n = IterateWorker % MaxWorkers; 887 work = &WorkerAry[n]; 888 889 if (work->state == WORKER_DONE || 890 work->state == WORKER_FAILED) { 891 workercomplete(work); 892 } 893 if (work->state == WORKER_NONE || 894 work->state == WORKER_IDLE) { 895 if (n <= MaxWorkers / 2) { 896 startworker(pkgi, work); 897 } else { 898 startworker(ipkg, work); 899 } 900 /*RunStatsUpdate(work);*/ 901 break; 902 } 903 ++IterateWorker; 904 } 905 ddassert(i != MaxWorkers); 906 } 907 RunStatsSync(); 908 909 /* 910 * We disposed of the whole list 911 */ 912 free(idep_ary); 913 free(depi_ary); 914 *build_listp = NULL; 915 *build_tailp = build_listp; 916 } 917 918 typedef const pkg_t *pkg_tt; 919 920 static int 921 qsort_idep(const void *pkg1_arg, const void *pkg2_arg) 922 { 923 const pkg_t *pkg1 = *(const pkg_tt *)pkg1_arg; 924 const pkg_t *pkg2 = *(const pkg_tt *)pkg2_arg; 925 926 return (pkg2->idep_count - pkg1->idep_count); 927 } 928 929 static int 930 qsort_depi(const void *pkg1_arg, const void *pkg2_arg) 931 { 932 const pkg_t *pkg1 = *(const pkg_tt *)pkg1_arg; 933 const pkg_t *pkg2 = *(const pkg_tt *)pkg2_arg; 934 935 return ((pkg2->depi_count * pkg2->depi_depth) - 936 (pkg1->depi_count * pkg1->depi_depth)); 937 } 938 939 /* 940 * Frontend starts a pkg up on a worker 941 * 942 * WorkerMutex must be held. 943 */ 944 static void 945 startworker(pkg_t *pkg, worker_t *work) 946 { 947 switch(work->state) { 948 case WORKER_NONE: 949 pthread_create(&work->td, NULL, childBuilderThread, work); 950 work->state = WORKER_IDLE; 951 /* fall through */ 952 case WORKER_IDLE: 953 work->pkg_dep_size = 954 childInstallPkgDeps_recurse(NULL, &pkg->idepon_list, 0, 1, 0); 955 childInstallPkgDeps_recurse(NULL, &pkg->idepon_list, 1, 1, 0); 956 RunningPkgDepSize += work->pkg_dep_size; 957 958 dlog(DLOG_ALL, "[%03d] START %s " 959 "##idep=%02d depi=%02d/%02d dep=%-4.2fG\n", 960 work->index, pkg->portdir, 961 pkg->idep_count, pkg->depi_count, pkg->depi_depth, 962 (double)work->pkg_dep_size / (double)ONEGB); 963 964 cleanworker(work); 965 pkg->flags |= PKGF_RUNNING; 966 work->pkg = pkg; 967 pthread_cond_signal(&work->cond); 968 ++RunningWorkers; 969 /*RunStatsUpdate(work);*/ 970 break; 971 case WORKER_PENDING: 972 case WORKER_RUNNING: 973 case WORKER_DONE: 974 case WORKER_FAILED: 975 case WORKER_FROZEN: 976 case WORKER_EXITING: 977 default: 978 dfatal("startworker: [%03d] Unexpected state %d for worker %d", 979 work->index, work->state, work->index); 980 break; 981 } 982 } 983 984 static void 985 cleanworker(worker_t *work) 986 { 987 work->state = WORKER_PENDING; 988 work->flags = 0; 989 work->accum_error = 0; 990 work->start_time = time(NULL); 991 } 992 993 /* 994 * Frontend finishes up a completed pkg on a worker. 995 * 996 * If the worker is in a FAILED state we clean the pkg out but (for now) 997 * leave it in its failed state so we can debug. At this point 998 * workercomplete() will be called every once in a while on the state 999 * and we have to deal with the NULL pkg. 1000 * 1001 * WorkerMutex must be held. 1002 */ 1003 static void 1004 workercomplete(worker_t *work) 1005 { 1006 pkg_t *pkg; 1007 time_t t; 1008 int h; 1009 int m; 1010 int s; 1011 1012 /* 1013 * Steady state FAILED case. 1014 */ 1015 if (work->state == WORKER_FAILED) { 1016 if (work->pkg == NULL) 1017 return; 1018 } 1019 1020 t = time(NULL) - work->start_time; 1021 h = t / 3600; 1022 m = t / 60 % 60; 1023 s = t % 60; 1024 1025 /* 1026 * Reduce total dep size 1027 */ 1028 RunningPkgDepSize -= work->pkg_dep_size; 1029 RunningPkgDepSize -= work->memuse; 1030 work->pkg_dep_size = 0; 1031 work->memuse = 0; 1032 1033 /* 1034 * Process pkg out of the worker 1035 */ 1036 pkg = work->pkg; 1037 if (pkg->flags & (PKGF_ERROR|PKGF_NOBUILD)) { 1038 pkg->flags |= PKGF_FAILURE; 1039 1040 /* 1041 * This NOBUILD condition XXX can occur if the package is 1042 * not allowed to be built. 1043 */ 1044 if (pkg->flags & PKGF_NOBUILD) { 1045 char *reason; 1046 1047 reason = buildskipreason(NULL, pkg); 1048 if (pkg->flags & PKGF_NOBUILD_I) { 1049 ++BuildIgnoreCount; 1050 dlog(DLOG_SKIP, "[%03d] IGNORD %s - %s\n", 1051 work->index, pkg->portdir, reason); 1052 RunStatsUpdateCompletion(work, DLOG_SKIP, 1053 pkg, reason); 1054 doHook(pkg, "hook_pkg_ignored", 1055 HookPkgIgnored, 0); 1056 } else { 1057 ++BuildSkipCount; 1058 dlog(DLOG_SKIP, "[%03d] SKIPPD %s - %s\n", 1059 work->index, pkg->portdir, reason); 1060 RunStatsUpdateCompletion(work, DLOG_SKIP, 1061 pkg, reason); 1062 doHook(pkg, "hook_pkg_skipped", 1063 HookPkgSkipped, 0); 1064 } 1065 free(reason); 1066 } else { 1067 char skipbuf[16]; 1068 int scount; 1069 1070 scount = buildskipcount_dueto(pkg, 1); 1071 buildskipcount_dueto(pkg, 0); 1072 if (scount) 1073 snprintf(skipbuf, sizeof(skipbuf), " (%d)", scount); 1074 else 1075 skipbuf[0] = 0; 1076 1077 ++BuildFailCount; 1078 dlog(DLOG_FAIL | DLOG_RED, 1079 "[%03d] FAILURE %s%s ##%16.16s %02d:%02d:%02d\n", 1080 work->index, pkg->portdir, skipbuf, 1081 getphasestr(work->phase), 1082 h, m, s); 1083 RunStatsUpdateCompletion(work, DLOG_FAIL, pkg, skipbuf); 1084 doHook(pkg, "hook_pkg_failure", HookPkgFailure, 0); 1085 } 1086 } else { 1087 pkg->flags |= PKGF_SUCCESS; 1088 ++BuildSuccessCount; 1089 dlog(DLOG_SUCC | DLOG_GRN, 1090 "[%03d] SUCCESS %s ##%02d:%02d:%02d\n", 1091 work->index, pkg->portdir, h, m, s); 1092 RunStatsUpdateCompletion(work, DLOG_SUCC, pkg, ""); 1093 doHook(pkg, "hook_pkg_success", HookPkgSuccess, 0); 1094 } 1095 ++BuildCount; 1096 pkg->flags &= ~PKGF_BUILDLIST; 1097 pkg->flags &= ~PKGF_RUNNING; 1098 work->pkg = NULL; 1099 --RunningWorkers; 1100 1101 if (work->state == WORKER_FAILED) { 1102 dlog(DLOG_ALL, "[%03d] XXX/XXX WORKER IS IN A FAILED STATE\n", 1103 work->index); 1104 ++FailedWorkers; 1105 } else if (work->flags & WORKERF_FREEZE) { 1106 dlog(DLOG_ALL, "[%03d] FROZEN(DEBUG) %s\n", 1107 work->index, pkg->portdir); 1108 work->state = WORKER_FROZEN; 1109 } else { 1110 work->state = WORKER_IDLE; 1111 } 1112 } 1113 1114 /* 1115 * Wait for one or more workers to complete. 1116 * 1117 * WorkerMutex must be held. 1118 */ 1119 static void 1120 waitbuild(int whilematch, int dynamicmax) 1121 { 1122 static time_t wblast_time; 1123 static time_t dmlast_time; 1124 struct timespec ts; 1125 worker_t *work; 1126 time_t t; 1127 int i; 1128 1129 if (whilematch == 0) 1130 whilematch = 1; 1131 1132 while (RunningWorkers == whilematch) { 1133 for (i = 0; i < MaxWorkers; ++i) { 1134 work = &WorkerAry[i]; 1135 if (work->state == WORKER_DONE || 1136 work->state == WORKER_FAILED) { 1137 workercomplete(work); 1138 } else { 1139 pthread_cond_signal(&work->cond); 1140 } 1141 RunStatsUpdate(work, NULL); 1142 } 1143 RunStatsUpdateTop(1); 1144 RunStatsUpdateLogs(); 1145 RunStatsSync(); 1146 if (RunningWorkers == whilematch) { 1147 clock_gettime(CLOCK_REALTIME, &ts); 1148 ts.tv_sec += 1; 1149 ts.tv_nsec = 0; 1150 pthread_cond_timedwait(&WorkerCond, &WorkerMutex, &ts); 1151 } 1152 1153 /* 1154 * Dynamically reduce MaxWorkers based on the load. When 1155 * the load exceeds 2 x ncpus we reduce the number of workers 1156 * up to 75% of MaxWorkers @ (5 x ncpus) load. 1157 * 1158 * Dynamically reduce MaxWorkers based on swap use, starting 1159 * at 10% swap and up to 75% of MaxWorkers at 40% swap. 1160 * 1161 * NOTE! Generally speaking this allows more workers to be 1162 * configured which helps in two ways. First it allows 1163 * a higher build rate for smaller packages. Second 1164 * it allows dsynth to ratchet-down the number of slots 1165 * when large packages are forcing the load up. 1166 * 1167 * A high load doesn't hurt efficiency, but swap usage 1168 * due to loading the tmpfs in lots of worker slots up 1169 * with tons of pkg install's (pre-reqs for a build) 1170 * does. Reducing the number of worker slots has a 1171 * huge beneficial effect on reducing swap use / paging. 1172 */ 1173 t = time(NULL); 1174 if (dynamicmax && (wblast_time == 0 || 1175 (unsigned)(t - wblast_time) >= 5)) { 1176 double min_load = 1.5 * NumCores; 1177 double max_load = 5.0 * NumCores; 1178 double min_swap = 0.10; 1179 double max_swap = 0.40; 1180 double dload[3]; 1181 double dswap; 1182 int max1; 1183 int max2; 1184 int max3; 1185 int max_sel; 1186 int noswap; 1187 1188 wblast_time = t; 1189 1190 /* 1191 * Cap based on load. This is back-loaded. 1192 */ 1193 getloadavg(dload, 3); 1194 adjloadavg(dload); 1195 if (dload[0] < min_load) { 1196 max1 = MaxWorkers; 1197 } else if (dload[0] <= max_load) { 1198 max1 = MaxWorkers - 1199 MaxWorkers * 0.75 * 1200 (dload[0] - min_load) / 1201 (max_load - min_load); 1202 } else { 1203 max1 = MaxWorkers * 25 / 100; 1204 } 1205 1206 /* 1207 * Cap based on swap use. This is back-loaded. 1208 */ 1209 dswap = getswappct(&noswap); 1210 if (dswap < min_swap) { 1211 max2 = MaxWorkers; 1212 } else if (dswap <= max_swap) { 1213 max2 = MaxWorkers - 1214 MaxWorkers * 0.75 * 1215 (dswap - min_swap) / 1216 (max_swap - min_swap); 1217 } else { 1218 max2 = MaxWorkers * 25 / 100; 1219 } 1220 1221 /* 1222 * Cap based on aggregate pkg-dependency memory 1223 * use installed in worker slots. This is 1224 * front-loaded. 1225 * 1226 * Since it can take a while for workers to retire 1227 * (to reduce RunningPkgDepSize), just set our 1228 * target 1 below the current run count to allow 1229 * jobs to retire without being replaced with new 1230 * jobs. 1231 * 1232 * In addition, in order to avoid a paging 'shock', 1233 * We enforce a 30 second-per-increment slow-start 1234 * once RunningPkgDepSize exceeds 1/2 the target. 1235 */ 1236 if (RunningPkgDepSize > PkgDepMemoryTarget) { 1237 max3 = RunningWorkers - 1; 1238 } else if (RunningPkgDepSize > PkgDepMemoryTarget / 2) { 1239 if (dmlast_time == 0 || 1240 (unsigned)(t - dmlast_time) >= 30) { 1241 dmlast_time = t; 1242 max3 = RunningWorkers + 1; 1243 } else { 1244 max3 = RunningWorkers; 1245 } 1246 } else { 1247 max3 = MaxWorkers; 1248 } 1249 1250 /* 1251 * Priority reduction, convert to DynamicMaxWorkers 1252 */ 1253 max_sel = max1; 1254 if (max_sel > max2) 1255 max_sel = max2; 1256 if (max_sel > max3) 1257 max_sel = max3; 1258 1259 /* 1260 * Restrict to allowed range, and also handle 1261 * slow-start. 1262 */ 1263 if (max_sel < 1) 1264 max_sel = 1; 1265 if (max_sel > DynamicMaxWorkers + 1) 1266 max_sel = DynamicMaxWorkers + 1; 1267 if (max_sel > MaxWorkers) 1268 max_sel = MaxWorkers; 1269 1270 /* 1271 * Stop waiting if DynamicMaxWorkers is going to 1272 * increase. 1273 */ 1274 if (DynamicMaxWorkers < max1) 1275 whilematch = -1; 1276 1277 /* 1278 * And adjust 1279 */ 1280 if (DynamicMaxWorkers != max1) { 1281 dlog(DLOG_ALL | DLOG_FILTER, 1282 "[XXX] Load=%-6.2f(%2d) " 1283 "Swap=%-3.2f%%(%2d) " 1284 "Mem=%3.2fG(%2d) " 1285 "Adjust Workers %d->%d\n", 1286 dload[0], max1, 1287 dswap * 100.0, max2, 1288 RunningPkgDepSize / (double)ONEGB, max3, 1289 DynamicMaxWorkers, max_sel); 1290 DynamicMaxWorkers = max_sel; 1291 } 1292 } 1293 } 1294 } 1295 1296 1297 /* 1298 * Worker pthread (WorkerAry) 1299 * 1300 * This thread belongs to the dsynth master process and handled a worker slot. 1301 * (this_thread) -> WORKER fork/exec (WorkerPocess) -> (pty) -> sub-processes. 1302 */ 1303 static void * 1304 childBuilderThread(void *arg) 1305 { 1306 char *envary[1] = { NULL }; 1307 worker_t *work = arg; 1308 wmsg_t wmsg; 1309 pkg_t *pkg; 1310 pid_t pid; 1311 int status; 1312 int flags; 1313 volatile int dowait; 1314 char slotbuf[8]; 1315 char fdbuf[8]; 1316 char flagsbuf[16]; 1317 1318 pthread_mutex_lock(&WorkerMutex); 1319 while (work->terminate == 0) { 1320 dowait = 1; 1321 1322 switch(work->state) { 1323 case WORKER_IDLE: 1324 break; 1325 case WORKER_PENDING: 1326 /* 1327 * Fork the management process for the pkg operation 1328 * on this worker slot. 1329 * 1330 * This process will set up the environment, do the 1331 * mounts, will become the reaper, and will process 1332 * pipe commands and handle chroot operations. 1333 * 1334 * NOTE: If SOCK_CLOEXEC is not supported WorkerMutex 1335 * is sufficient to interlock F_SETFD FD_CLOEXEC 1336 * operations. 1337 */ 1338 ddassert(work->pkg); 1339 if (socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 1340 PF_UNSPEC, work->fds)) { 1341 dfatal_errno("socketpair() during worker fork"); 1342 } 1343 snprintf(slotbuf, sizeof(slotbuf), "%d", work->index); 1344 snprintf(fdbuf, sizeof(fdbuf), "3"); 1345 1346 /* 1347 * Pass global flags and add-in the DEBUGSTOP if 1348 * the package is flagged for debugging. 1349 */ 1350 flags = WorkerProcFlags; 1351 if (work->pkg->flags & PKGF_DEBUGSTOP) { 1352 flags |= WORKER_PROC_DEBUGSTOP; 1353 } else { 1354 flags &= ~WORKER_PROC_DEBUGSTOP; 1355 } 1356 snprintf(flagsbuf, sizeof(flagsbuf), "%d", flags); 1357 1358 /* 1359 * fds[0] - master 1360 * fds[1] - slave 1361 * 1362 * We pass the salve descriptor in fd 3 and close all 1363 * other descriptors for security. 1364 */ 1365 pthread_mutex_unlock(&WorkerMutex); 1366 pid = vfork(); 1367 if (pid == 0) { 1368 close(work->fds[0]); 1369 dup2(work->fds[1], 3); 1370 closefrom(4); 1371 fcntl(3, F_SETFD, 0); 1372 execle(DSynthExecPath, DSynthExecPath, 1373 "-p", Profile, 1374 "WORKER", slotbuf, fdbuf, 1375 work->pkg->portdir, work->pkg->pkgfile, 1376 flagsbuf, 1377 NULL, envary); 1378 write(2, "EXECLE FAILURE\n", 15); 1379 _exit(1); 1380 } 1381 pthread_mutex_lock(&WorkerMutex); 1382 close(work->fds[1]); 1383 work->phase = PHASE_PENDING; 1384 work->lines = 0; 1385 work->memuse = 0; 1386 work->pid = pid; 1387 work->state = WORKER_RUNNING; 1388 /* fall through */ 1389 case WORKER_RUNNING: 1390 /* 1391 * Poll for status updates, if NULL is returned 1392 * and status is non-zero, the communications link 1393 * failed unexpectedly. 1394 */ 1395 pkg = work->pkg; 1396 pthread_mutex_unlock(&WorkerMutex); 1397 status = ipcreadmsg(work->fds[0], &wmsg); 1398 pthread_mutex_lock(&WorkerMutex); 1399 1400 if (status == 0) { 1401 /* 1402 * Normal message, can include normal 1403 * termination which changes us over 1404 * to another state. 1405 */ 1406 dowait = 0; 1407 switch(wmsg.cmd) { 1408 case WMSG_CMD_INSTALL_PKGS: 1409 wmsg.cmd = WMSG_RES_INSTALL_PKGS; 1410 wmsg.status = childInstallPkgDeps(work); 1411 pthread_mutex_unlock(&WorkerMutex); 1412 ipcwritemsg(work->fds[0], &wmsg); 1413 pthread_mutex_lock(&WorkerMutex); 1414 break; 1415 case WMSG_CMD_STATUS_UPDATE: 1416 work->phase = wmsg.phase; 1417 work->lines = wmsg.lines; 1418 if (work->memuse != wmsg.memuse) { 1419 RunningPkgDepSize += 1420 wmsg.memuse - work->memuse; 1421 work->memuse = wmsg.memuse; 1422 } 1423 break; 1424 case WMSG_CMD_SUCCESS: 1425 work->flags |= WORKERF_SUCCESS; 1426 break; 1427 case WMSG_CMD_FAILURE: 1428 work->flags |= WORKERF_FAILURE; 1429 break; 1430 case WMSG_CMD_FREEZEWORKER: 1431 work->flags |= WORKERF_FREEZE; 1432 break; 1433 default: 1434 break; 1435 } 1436 RunStatsUpdate(work, NULL); 1437 RunStatsSync(); 1438 } else { 1439 close(work->fds[0]); 1440 pthread_mutex_unlock(&WorkerMutex); 1441 while (waitpid(work->pid, &status, 0) < 0 && 1442 errno == EINTR) { 1443 ; 1444 } 1445 pthread_mutex_lock(&WorkerMutex); 1446 1447 if (work->flags & WORKERF_SUCCESS) { 1448 pkg->flags |= PKGF_SUCCESS; 1449 work->state = WORKER_DONE; 1450 } else if (work->flags & WORKERF_FAILURE) { 1451 pkg->flags |= PKGF_FAILURE; 1452 work->state = WORKER_DONE; 1453 } else { 1454 pkg->flags |= PKGF_FAILURE; 1455 work->state = WORKER_FAILED; 1456 } 1457 work->flags |= WORKERF_STATUS_UPDATE; 1458 pthread_cond_signal(&WorkerCond); 1459 } 1460 break; 1461 case WORKER_DONE: 1462 /* 1463 * pkg remains attached until frontend processes the 1464 * completion. The frontend will then set the state 1465 * back to idle. 1466 */ 1467 break; 1468 case WORKER_FAILED: 1469 /* 1470 * A worker failure means that the worker did not 1471 * send us a WMSG_CMD_SUCCESS or WMSG_CMD_FAILURE 1472 * ipc before terminating. 1473 * 1474 * We just sit in this state until the front-end 1475 * does something about it. 1476 */ 1477 break; 1478 case WORKER_FROZEN: 1479 /* 1480 * A worker getting frozen is debug-related. We 1481 * just sit in this state (likely forever). 1482 */ 1483 break; 1484 default: 1485 dfatal("worker: [%03d] Unexpected state %d " 1486 "for worker %d", 1487 work->index, work->state, work->index); 1488 /* NOT REACHED */ 1489 break; 1490 } 1491 1492 /* 1493 * The dsynth frontend will poll us approximately once 1494 * a second (its variable). 1495 */ 1496 if (dowait) 1497 pthread_cond_wait(&work->cond, &WorkerMutex); 1498 } 1499 1500 /* 1501 * Scrap the comm socket if running, this should cause the worker 1502 * process to kill its sub-programs and cleanup. 1503 */ 1504 if (work->state == WORKER_RUNNING) { 1505 pthread_mutex_unlock(&WorkerMutex); 1506 close(work->fds[0]); 1507 while (waitpid(work->pid, &status, 0) < 0 && 1508 errno == EINTR); 1509 pthread_mutex_lock(&WorkerMutex); 1510 } 1511 1512 /* 1513 * Final handshake 1514 */ 1515 work->state = WORKER_EXITING; 1516 pthread_cond_signal(&WorkerCond); 1517 pthread_mutex_unlock(&WorkerMutex); 1518 1519 return NULL; 1520 } 1521 1522 /* 1523 * Install all the binary packages (we have already built them) that 1524 * the current work package depends on, without duplicates, in a script 1525 * which will be run from within the specified work jail. 1526 * 1527 * Locked by WorkerMutex (global) 1528 */ 1529 static int 1530 childInstallPkgDeps(worker_t *work) 1531 { 1532 char *buf; 1533 FILE *fp; 1534 1535 if (PKGLIST_EMPTY(&work->pkg->idepon_list)) 1536 return 0; 1537 1538 asprintf(&buf, "%s/tmp/dsynth_install_pkgs", work->basedir); 1539 fp = fopen(buf, "w"); 1540 ddassert(fp != NULL); 1541 fprintf(fp, "#!/bin/sh\n"); 1542 fprintf(fp, "#\n"); 1543 fchmod(fileno(fp), 0755); 1544 1545 childInstallPkgDeps_recurse(fp, &work->pkg->idepon_list, 0, 1, 0); 1546 childInstallPkgDeps_recurse(fp, &work->pkg->idepon_list, 1, 1, 0); 1547 fprintf(fp, "\nexit 0\n"); 1548 fclose(fp); 1549 freestrp(&buf); 1550 1551 return 1; 1552 } 1553 1554 /* 1555 * Recursive child install dependencies. 1556 * 1557 * first_one_only is only specified if the pkg the list comes from 1558 * is a generic unflavored package that has flavors, telling us to 1559 * dive the first flavor only. 1560 * 1561 * However, in nearly all cases this flag will now be zero because 1562 * this code now dives the first flavor when encountering a dummy node 1563 * and clears nfirst on success. Hence if you are asking why 'nfirst' 1564 * is set to 1, and then zero, instead of just being removed entirely, 1565 * it is because there might still be an edge case here. 1566 */ 1567 static size_t 1568 childInstallPkgDeps_recurse(FILE *fp, pkglink_t *list, int undoit, 1569 int depth, int first_one_only) 1570 { 1571 pkglink_t *link; 1572 pkg_t *pkg; 1573 size_t tot = 0; 1574 int ndepth; 1575 int nfirst; 1576 1577 PKGLIST_FOREACH(link, list) { 1578 pkg = link->pkg; 1579 1580 /* 1581 * We don't want to mess up our depth test just below if 1582 * a DUMMY node had to be inserted. The nodes under the 1583 * dummy node. 1584 * 1585 * The elements under a dummy node represent all the flabor, 1586 * a dependency that directly references a dummy node only 1587 * uses the first flavor (first_one_only / nfirst). 1588 */ 1589 ndepth = (pkg->flags & PKGF_DUMMY) ? depth : depth + 1; 1590 nfirst = (pkg->flags & PKGF_DUMMY) ? 1 : 0; 1591 1592 /* 1593 * We only need all packages for the top-level dependencies. 1594 * The deeper ones only need DEP_TYPE_LIB and DEP_TYPE_RUN 1595 * (types greater than DEP_TYPE_BUILD) since they are already 1596 * built. 1597 */ 1598 if (depth > 1 && link->dep_type <= DEP_TYPE_BUILD) { 1599 if (first_one_only) 1600 break; 1601 continue; 1602 } 1603 1604 /* 1605 * If this is a dummy node with no package, the originator 1606 * is requesting a flavored package. We select the default 1607 * flavor which we presume is the first one. 1608 */ 1609 if (pkg->pkgfile == NULL && (pkg->flags & PKGF_DUMMY)) { 1610 pkg_t *spkg = pkg->idepon_list.next->pkg; 1611 1612 if (spkg) { 1613 if (fp) { 1614 fprintf(fp, 1615 "echo 'UNFLAVORED %s -> use " 1616 "%s'\n", 1617 pkg->portdir, 1618 spkg->portdir); 1619 } 1620 pkg = spkg; 1621 nfirst = 0; 1622 } else { 1623 if (fp) { 1624 fprintf(fp, 1625 "echo 'CANNOT FIND DEFAULT " 1626 "FLAVOR FOR %s'\n", 1627 pkg->portdir); 1628 } 1629 } 1630 } 1631 1632 if (undoit) { 1633 if (pkg->dsynth_install_flg == 1) { 1634 pkg->dsynth_install_flg = 0; 1635 tot += childInstallPkgDeps_recurse(fp, 1636 &pkg->idepon_list, 1637 undoit, 1638 ndepth, nfirst); 1639 } 1640 if (first_one_only) 1641 break; 1642 continue; 1643 } 1644 1645 if (pkg->dsynth_install_flg) { 1646 if (DebugOpt >= 2 && pkg->pkgfile && fp) { 1647 fprintf(fp, "echo 'AlreadyHave %s'\n", 1648 pkg->pkgfile); 1649 } 1650 if (first_one_only) 1651 break; 1652 continue; 1653 } 1654 1655 tot += childInstallPkgDeps_recurse(fp, &pkg->idepon_list, 1656 undoit, ndepth, nfirst); 1657 if (pkg->dsynth_install_flg) { 1658 if (first_one_only) 1659 break; 1660 continue; 1661 } 1662 pkg->dsynth_install_flg = 1; 1663 1664 /* 1665 * Generate package installation command 1666 */ 1667 if (fp && pkg->pkgfile) { 1668 fprintf(fp, "echo 'Installing /packages/All/%s'\n", 1669 pkg->pkgfile); 1670 fprintf(fp, "pkg install -q -U -y /packages/All/%s " 1671 "|| exit 1\n", 1672 pkg->pkgfile); 1673 } else if (fp) { 1674 fprintf(fp, "echo 'CANNOT FIND PKG FOR %s'\n", 1675 pkg->portdir); 1676 } 1677 1678 if (pkg->pkgfile) { 1679 struct stat st; 1680 char *path; 1681 char *ptr; 1682 1683 asprintf(&path, "%s/%s", RepositoryPath, pkg->pkgfile); 1684 ptr = strrchr(pkg->pkgfile, '.'); 1685 if (stat(path, &st) == 0) { 1686 if (strcmp(ptr, ".tar") == 0) 1687 tot += st.st_size; 1688 else if (strcmp(ptr, ".tgz") == 0) 1689 tot += st.st_size * 3; 1690 else if (strcmp(ptr, ".txz") == 0) 1691 tot += st.st_size * 5; 1692 else if (strcmp(ptr, ".tbz") == 0) 1693 tot += st.st_size * 3; 1694 else 1695 tot += st.st_size * 2; 1696 } 1697 free(path); 1698 } 1699 if (first_one_only) 1700 break; 1701 } 1702 return tot; 1703 } 1704 1705 /* 1706 * Worker process interactions. 1707 * 1708 * The worker process is responsible for managing the build of a single 1709 * package. It is exec'd by the master dsynth and only loads the 1710 * configuration. 1711 * 1712 * This process does not run in the chroot. It will become the reaper for 1713 * all sub-processes and it will enter the chroot to execute various phases. 1714 * It catches SIGINTR, SIGHUP, and SIGPIPE and will iterate, terminate, and 1715 * reap all sub-process upon kill or exit. 1716 * 1717 * The command line forwarded to this function is: 1718 * 1719 * WORKER slot# socketfd portdir/subdir 1720 * 1721 * TERM=dumb 1722 * USER=root 1723 * HOME=/root 1724 * LANG=C 1725 * SSL_NO_VERIFY_PEER=1 1726 * USE_PACKAGE_DEPENDS_ONLY=1 1727 * PORTSDIR=/xports 1728 * PORT_DBDIR=/options For ports options 1729 * PACKAGE_BUILDING=yes Don't build packages that aren't legally 1730 * buildable for a binary repo. 1731 * PKG_DBDIR=/var/db/pkg 1732 * PKG_CACHEDIR=/var/cache/pkg 1733 * PKG_CREATE_VERBOSE=yes Ensure periodic output during packaging 1734 * (custom environment) 1735 * PATH=/sbin:/bin:/usr/sbin:/usr/bin:/usr/local/sbin:/usr/local/bin 1736 * UNAME_s=DragonFly (example) 1737 * UNAME_v=DragonFly 5.7-SYNTH (example) 1738 * UNAME_p=x86_64 (example) 1739 * UNAME_m=x86_64 (example) 1740 * UNAME_r=5.7-SYNTH (example) 1741 * NO_DEPENDS=yes (conditional based on phase) 1742 * DISTDIR=/distfiles 1743 * WRKDIRPREFIX=/construction 1744 * BATCH=yes 1745 * MAKE_JOBS_NUMBER=n 1746 * 1747 * SETUP: 1748 * ldconfig -R 1749 * /usr/local/sbin/pkg-static install /packages/All/<the pkg pkg> 1750 * /usr/local/sbin/pkg-static install /packages/All/<pkg> 1751 * (for all dependencies) 1752 * 1753 * PHASES: make -C path FLAVOR=flavor <phase> 1754 * check-sanity 1755 * pkg-depends 1756 * fetch-depends 1757 * fetch 1758 * checksum 1759 * extract-depends 1760 * extract 1761 * patch-depends 1762 * patch 1763 * build-depends 1764 * lib-depends 1765 * configure 1766 * build 1767 * run-depends 1768 * stage 1769 * test (skipped) 1770 * check-plist ('dsynth test blahblah' or 'dsynth -D everything' only) 1771 * package e.g. /construction/lang/perl5.28/pkg/perl5-5.28.2.txz 1772 * install-mtree (skipped) 1773 * install (skipped) 1774 * deinstall (skipped) 1775 */ 1776 void 1777 WorkerProcess(int ac, char **av) 1778 { 1779 wmsg_t wmsg; 1780 int fd; 1781 int slot; 1782 int tmpfd; 1783 int pkgpkg = 0; 1784 int status; 1785 int len; 1786 int do_install_phase; 1787 char *portdir; 1788 char *pkgfile; 1789 char *flavor; 1790 char *buf; 1791 worker_t *work; 1792 bulk_t *bulk; 1793 pkg_t pkg; 1794 buildenv_t *benv; 1795 FILE *fp; 1796 1797 /* 1798 * Parse arguments 1799 */ 1800 if (ac != 6) { 1801 dlog(DLOG_ALL, "WORKER PROCESS %d- bad arguments\n", getpid()); 1802 exit(1); 1803 } 1804 slot = strtol(av[1], NULL, 0); 1805 fd = strtol(av[2], NULL, 0); /* master<->slave messaging */ 1806 portdir = av[3]; 1807 pkgfile = av[4]; 1808 flavor = strchr(portdir, '@'); 1809 if (flavor) { 1810 *flavor++ = 0; 1811 asprintf(&buf, "@%s", flavor); 1812 WorkerFlavorPrt = buf; 1813 buf = NULL; /* safety */ 1814 } 1815 WorkerProcFlags = strtol(av[5], NULL, 0); 1816 1817 bzero(&wmsg, sizeof(wmsg)); 1818 1819 setproctitle("[%02d] WORKER STARTUP %s%s", 1820 slot, portdir, WorkerFlavorPrt); 1821 1822 if (strcmp(portdir, "ports-mgmt/pkg") == 0) 1823 pkgpkg = 1; 1824 1825 signal(SIGTERM, phaseTerminateSignal); 1826 signal(SIGINT, phaseTerminateSignal); 1827 signal(SIGHUP, phaseTerminateSignal); 1828 1829 /* 1830 * Set up the environment 1831 */ 1832 setenv("TERM", "dumb", 1); 1833 setenv("USER", "root", 1); 1834 setenv("HOME", "/root", 1); 1835 setenv("LANG", "C", 1); 1836 setenv("SSL_NO_VERIFY_PEER", "1", 1); 1837 1838 addbuildenv("USE_PACKAGE_DEPENDS_ONLY", "yes", BENV_MAKECONF); 1839 addbuildenv("PORTSDIR", "/xports", BENV_MAKECONF); 1840 addbuildenv("PORT_DBDIR", "/options", BENV_MAKECONF); 1841 addbuildenv("PKG_DBDIR", "/var/db/pkg", BENV_MAKECONF); 1842 addbuildenv("PKG_CACHEDIR", "/var/cache/pkg", BENV_MAKECONF); 1843 addbuildenv("PKG_SUFX", UsePkgSufx, BENV_MAKECONF); 1844 if (WorkerProcFlags & WORKER_PROC_DEVELOPER) 1845 addbuildenv("DEVELOPER", "1", BENV_MAKECONF); 1846 1847 /* 1848 * CCache is a horrible unreliable hack but... leave the 1849 * mechanism in-place in case someone has a death wish. 1850 */ 1851 if (UseCCache) { 1852 addbuildenv("WITH_CCACHE_BUILD", "yes", BENV_MAKECONF); 1853 addbuildenv("CCACHE_DIR", "/ccache", BENV_MAKECONF); 1854 } 1855 1856 addbuildenv("UID", "0", BENV_MAKECONF); 1857 addbuildenv("ARCH", ArchitectureName, BENV_MAKECONF); 1858 1859 #ifdef __DragonFly__ 1860 addbuildenv("OPSYS", "DragonFly", BENV_MAKECONF); 1861 addbuildenv("DFLYVERSION", VersionFromParamHeader, BENV_MAKECONF); 1862 addbuildenv("OSVERSION", "9999999", BENV_MAKECONF); 1863 #else 1864 #error "Need OS-specific data to generate make.conf" 1865 #endif 1866 1867 addbuildenv("OSREL", ReleaseName, BENV_MAKECONF); 1868 addbuildenv("_OSRELEASE", VersionOnlyName, BENV_MAKECONF); 1869 1870 setenv("PATH", 1871 "/sbin:/bin:/usr/sbin:/usr/bin:/usr/local/sbin:/usr/local/bin", 1872 1); 1873 1874 setenv("UNAME_s", OperatingSystemName, 1); 1875 setenv("UNAME_v", VersionName, 1); 1876 setenv("UNAME_p", ArchitectureName, 1); 1877 setenv("UNAME_m", MachineName, 1); 1878 setenv("UNAME_r", ReleaseName, 1); 1879 1880 addbuildenv("DISTDIR", "/distfiles", BENV_MAKECONF); 1881 addbuildenv("WRKDIRPREFIX", "/construction", BENV_MAKECONF); 1882 addbuildenv("BATCH", "yes", BENV_MAKECONF); 1883 1884 /* 1885 * Special consideration 1886 * 1887 * PACKAGE_BUILDING - Disallow packaging ports which do not allow 1888 * for binary distribution. 1889 * 1890 * PKG_CREATE_VERBOSE - Ensure periodic output during the packaging 1891 * process to avoid a watchdog timeout. 1892 * 1893 */ 1894 addbuildenv("PACKAGE_BUILDING", "yes", BENV_MAKECONF); 1895 addbuildenv("PKG_CREATE_VERBOSE", "yes", BENV_MAKECONF); 1896 asprintf(&buf, "%d", MaxJobs); 1897 addbuildenv("MAKE_JOBS_NUMBER", buf, BENV_MAKECONF); 1898 freestrp(&buf); 1899 1900 if (flavor) 1901 setenv("FLAVOR", flavor, 1); 1902 1903 /* 1904 * Become the reaper 1905 */ 1906 if (procctl(P_PID, getpid(), PROC_REAP_ACQUIRE, NULL) < 0) 1907 dfatal_errno("procctl() - Cannot become reaper"); 1908 1909 /* 1910 * Initialize a worker structure 1911 */ 1912 DoInitBuild(slot); 1913 1914 bzero(&pkg, sizeof(pkg)); 1915 pkg.portdir = portdir; /* sans flavor */ 1916 pkg.pkgfile = pkgfile; 1917 if (strchr(portdir, '/')) 1918 len = strchr(portdir, '/') - portdir; 1919 else 1920 len = 0; 1921 1922 /* 1923 * Setup the logfile 1924 */ 1925 asprintf(&pkg.logfile, 1926 "%s/%*.*s___%s%s%s.log", 1927 LogsPath, len, len, portdir, 1928 ((portdir[len] == '/') ? portdir + len + 1 : portdir + len), 1929 (flavor ? "@" : ""), 1930 (flavor ? flavor : "")); 1931 tmpfd = open(pkg.logfile, O_RDWR|O_CREAT|O_TRUNC, 0666); 1932 if (tmpfd >= 0) { 1933 if (DebugOpt >= 2) { 1934 dlog(DLOG_ALL, "[%03d] %s LOGFILE %s\n", 1935 slot, pkg.portdir, pkg.logfile); 1936 } 1937 close(tmpfd); 1938 } else { 1939 dlog(DLOG_ALL, "[%03d] LOGFILE %s (create failed)\n", 1940 slot, pkg.logfile); 1941 } 1942 1943 /* 1944 * Setup the work structure. Because this is an exec'd sub-process, 1945 * there is only one work structure. 1946 */ 1947 work = &WorkerAry[0]; 1948 work->flavor = flavor; 1949 work->fds[0] = fd; 1950 work->pkg = &pkg; 1951 work->start_time = time(NULL); 1952 1953 /* 1954 * Do mounts 1955 */ 1956 SigWork = work; 1957 setproctitle("[%02d] WORKER MOUNTS %s%s", 1958 slot, portdir, WorkerFlavorPrt); 1959 DoWorkerMounts(work); 1960 1961 /* 1962 * Generate an /etc/make.conf in the build base 1963 */ 1964 asprintf(&buf, "%s/etc/make.conf", work->basedir); 1965 fp = fopen(buf, "w"); 1966 dassert_errno(fp, "Unable to create %s\n", buf); 1967 for (benv = BuildEnv; benv; benv = benv->next) { 1968 if (benv->type & BENV_PKGLIST) 1969 continue; 1970 if ((benv->type & BENV_CMDMASK) == BENV_MAKECONF) { 1971 if (DebugOpt >= 2) { 1972 dlog(DLOG_ALL, "[%03d] ENV %s=%s\n", 1973 slot, benv->label, benv->data); 1974 } 1975 fprintf(fp, "%s=%s\n", benv->label, benv->data); 1976 } 1977 } 1978 fclose(fp); 1979 freestrp(&buf); 1980 1981 /* 1982 * Set up our hooks 1983 */ 1984 if (UsingHooks) 1985 initbulk(childHookRun, MaxBulk); 1986 1987 /* 1988 * Start phases 1989 */ 1990 wmsg.cmd = WMSG_CMD_INSTALL_PKGS; 1991 ipcwritemsg(fd, &wmsg); 1992 status = ipcreadmsg(fd, &wmsg); 1993 if (status < 0 || wmsg.cmd != WMSG_RES_INSTALL_PKGS) 1994 dfatal("pkg installation handshake failed"); 1995 do_install_phase = wmsg.status; 1996 1997 wmsg.cmd = WMSG_CMD_STATUS_UPDATE; 1998 wmsg.phase = PHASE_INSTALL_PKGS; 1999 wmsg.lines = 0; 2000 2001 status = ipcwritemsg(fd, &wmsg); 2002 2003 if (pkgpkg) { 2004 dophase(work, &wmsg, 2005 WDOG5, PHASE_PACKAGE, "package"); 2006 } else { 2007 if (do_install_phase) { 2008 dophase(work, &wmsg, 2009 WDOG4, PHASE_INSTALL_PKGS, "setup"); 2010 } 2011 dophase(work, &wmsg, 2012 WDOG2, PHASE_CHECK_SANITY, "check-sanity"); 2013 dophase(work, &wmsg, 2014 WDOG2, PHASE_PKG_DEPENDS, "pkg-depends"); 2015 dophase(work, &wmsg, 2016 WDOG7, PHASE_FETCH_DEPENDS, "fetch-depends"); 2017 dophase(work, &wmsg, 2018 WDOG7, PHASE_FETCH, "fetch"); 2019 dophase(work, &wmsg, 2020 WDOG2, PHASE_CHECKSUM, "checksum"); 2021 dophase(work, &wmsg, 2022 WDOG3, PHASE_EXTRACT_DEPENDS, "extract-depends"); 2023 dophase(work, &wmsg, 2024 WDOG3, PHASE_EXTRACT, "extract"); 2025 dophase(work, &wmsg, 2026 WDOG2, PHASE_PATCH_DEPENDS, "patch-depends"); 2027 dophase(work, &wmsg, 2028 WDOG2, PHASE_PATCH, "patch"); 2029 dophase(work, &wmsg, 2030 WDOG5, PHASE_BUILD_DEPENDS, "build-depends"); 2031 dophase(work, &wmsg, 2032 WDOG5, PHASE_LIB_DEPENDS, "lib-depends"); 2033 dophase(work, &wmsg, 2034 WDOG3, PHASE_CONFIGURE, "configure"); 2035 dophase(work, &wmsg, 2036 WDOG9, PHASE_BUILD, "build"); 2037 dophase(work, &wmsg, 2038 WDOG5, PHASE_RUN_DEPENDS, "run-depends"); 2039 dophase(work, &wmsg, 2040 WDOG5, PHASE_STAGE, "stage"); 2041 #if 0 2042 dophase(work, &wmsg, 2043 WDOG5, PHASE_TEST, "test"); 2044 #endif 2045 if (WorkerProcFlags & WORKER_PROC_CHECK_PLIST) { 2046 dophase(work, &wmsg, 2047 WDOG1, PHASE_CHECK_PLIST, "check-plist"); 2048 } 2049 dophase(work, &wmsg, 2050 WDOG5, PHASE_PACKAGE, "package"); 2051 #if 0 2052 dophase(work, &wmsg, 2053 WDOG5, PHASE_INSTALL_MTREE, "install-mtree"); 2054 dophase(work, &wmsg, 2055 WDOG5, PHASE_INSTALL, "install"); 2056 dophase(work, &wmsg, 2057 WDOG5, PHASE_DEINSTALL, "deinstall"); 2058 #endif 2059 } 2060 2061 if (MasterPtyFd >= 0) { 2062 close(MasterPtyFd); 2063 MasterPtyFd = -1; 2064 } 2065 2066 setproctitle("[%02d] WORKER CLEANUP %s%s", 2067 slot, portdir, WorkerFlavorPrt); 2068 2069 /* 2070 * Copy the package to the repo. 2071 */ 2072 if (work->accum_error == 0) { 2073 char *b1; 2074 char *b2; 2075 2076 asprintf(&b1, "%s/construction/%s/pkg/%s", 2077 work->basedir, pkg.portdir, pkg.pkgfile); 2078 asprintf(&b2, "%s/%s", RepositoryPath, pkg.pkgfile); 2079 if (copyfile(b1, b2)) { 2080 ++work->accum_error; 2081 dlog(DLOG_ALL, "[%03d] %s Unable to copy %s to %s\n", 2082 work->index, pkg.portdir, b1, b2); 2083 } 2084 free(b1); 2085 free(b2); 2086 } 2087 2088 /* 2089 * Unmount, unless we are in DebugStopMode. 2090 */ 2091 if ((WorkerProcFlags & WORKER_PROC_DEBUGSTOP) == 0) 2092 DoWorkerUnmounts(work); 2093 2094 /* 2095 * Send completion status to master dsynth worker thread. 2096 */ 2097 if (work->accum_error) { 2098 wmsg.cmd = WMSG_CMD_FAILURE; 2099 } else { 2100 wmsg.cmd = WMSG_CMD_SUCCESS; 2101 } 2102 ipcwritemsg(fd, &wmsg); 2103 if (WorkerProcFlags & WORKER_PROC_DEBUGSTOP) { 2104 wmsg.cmd = WMSG_CMD_FREEZEWORKER; 2105 ipcwritemsg(fd, &wmsg); 2106 } 2107 if (UsingHooks) { 2108 while ((bulk = getbulk()) != NULL) 2109 freebulk(bulk); 2110 donebulk(); 2111 } 2112 } 2113 2114 static void 2115 dophase(worker_t *work, wmsg_t *wmsg, int wdog, int phaseid, const char *phase) 2116 { 2117 pkg_t *pkg = work->pkg; 2118 char buf[1024]; 2119 pid_t pid; 2120 int status; 2121 int ms; 2122 pid_t wpid; 2123 int wpid_reaped; 2124 int fdlog; 2125 time_t start_time; 2126 time_t last_time; 2127 time_t next_time; 2128 time_t wdog_time; 2129 FILE *fp; 2130 2131 if (work->accum_error) 2132 return; 2133 setproctitle("[%02d] WORKER %-8.8s %s%s", 2134 work->index, phase, pkg->portdir, WorkerFlavorPrt); 2135 wmsg->phase = phaseid; 2136 if (ipcwritemsg(work->fds[0], wmsg) < 0) { 2137 dlog(DLOG_ALL, "[%03d] %s Lost Communication with dsynth, " 2138 "aborting worker\n", 2139 work->index, pkg->portdir); 2140 ++work->accum_error; 2141 return; 2142 } 2143 2144 /* 2145 * Execute the port make command in chroot on a pty. 2146 */ 2147 fflush(stdout); 2148 fflush(stderr); 2149 if (MasterPtyFd >= 0) { 2150 int slavefd; 2151 2152 /* 2153 * NOTE: We can't open the slave in the child because the 2154 * master may race a disconnection test. If we open 2155 * it in the parent our close() will flush any pending 2156 * output not read by the master (which is the same 2157 * parent process) and deadlock. 2158 * 2159 * Solve this by hand-shaking the slave tty to give 2160 * the master time to close its slavefd (after this 2161 * section). 2162 * 2163 * Leave the tty defaults intact, which also likely 2164 * means it will be in line-buffered mode, so handshake 2165 * with a full line. 2166 * 2167 * TODO: Our handshake probably echos back to the master pty 2168 * due to tty echo, and ends up in the log, so just 2169 * pass through a newline. 2170 */ 2171 slavefd = open(ptsname(MasterPtyFd), O_RDWR); 2172 dassert_errno(slavefd >= 0, "Cannot open slave pty"); 2173 2174 /* 2175 * Now do the fork. 2176 */ 2177 pid = fork(); 2178 if (pid == 0) { 2179 login_tty(slavefd); 2180 /* login_tty() closes slavefd */ 2181 } else { 2182 close(slavefd); 2183 } 2184 } else { 2185 /* 2186 * Initial MasterPtyFd for the slot, just use forkpty(). 2187 */ 2188 pid = forkpty(&MasterPtyFd, NULL, NULL, NULL); 2189 } 2190 2191 /* 2192 * The slave must make sure the master has time to close slavefd 2193 * in the re-use case before going its merry way. The master needs 2194 * to set terminal modes and the window as well. 2195 */ 2196 if (pid == 0) { 2197 /* 2198 * Slave waits for handshake 2199 */ 2200 char ttybuf[2]; 2201 2202 read(0, ttybuf, 1); 2203 } else { 2204 /* 2205 * We are going through a pty, so set the tty modes to 2206 * Set tty modes so we do not get ^M's in the log files. 2207 * 2208 * This isn't fatal if it doesn't work. Remember that 2209 * our output goes through the pty to the management 2210 * process which will log it. 2211 */ 2212 struct termios tio; 2213 struct winsize win; 2214 2215 if (tcgetattr(MasterPtyFd, &tio) == 0) { 2216 tio.c_oflag |= OPOST | ONOCR; 2217 tio.c_oflag &= ~(OCRNL | ONLCR); 2218 tio.c_iflag |= ICRNL; 2219 tio.c_iflag &= ~(INLCR | IGNCR); 2220 if (tcsetattr(MasterPtyFd, TCSANOW, &tio)) { 2221 printf("tcsetattr failed: %s\n", 2222 strerror(errno)); 2223 } 2224 2225 /* 2226 * Give the tty a non-zero columns field. 2227 * This fixes at least one port (textproc/po4a) 2228 */ 2229 if (ioctl(MasterPtyFd, TIOCGWINSZ, &win) == 0) { 2230 win.ws_col = 80; 2231 ioctl(MasterPtyFd, TIOCSWINSZ, &win); 2232 } else { 2233 printf("TIOCGWINSZ failed: %s\n", 2234 strerror(errno)); 2235 } 2236 2237 } else { 2238 printf("tcgetattr failed: %s\n", strerror(errno)); 2239 } 2240 2241 /* 2242 * Master issues handshake 2243 */ 2244 write(MasterPtyFd, "\n", 1); 2245 } 2246 2247 if (pid == 0) { 2248 /* 2249 * Additional phase-specific environment variables 2250 * 2251 * - Do not try to process missing depends outside of the 2252 * depends phases. Also relies on USE_PACKAGE_DEPENDS_ONLY 2253 * in the make.conf. 2254 */ 2255 switch(phaseid) { 2256 case PHASE_CHECK_SANITY: 2257 case PHASE_FETCH: 2258 case PHASE_CHECKSUM: 2259 case PHASE_EXTRACT: 2260 case PHASE_PATCH: 2261 case PHASE_CONFIGURE: 2262 case PHASE_STAGE: 2263 case PHASE_TEST: 2264 case PHASE_CHECK_PLIST: 2265 case PHASE_INSTALL_MTREE: 2266 case PHASE_INSTALL: 2267 case PHASE_DEINSTALL: 2268 break; 2269 case PHASE_PKG_DEPENDS: 2270 case PHASE_FETCH_DEPENDS: 2271 case PHASE_EXTRACT_DEPENDS: 2272 case PHASE_PATCH_DEPENDS: 2273 case PHASE_BUILD_DEPENDS: 2274 case PHASE_LIB_DEPENDS: 2275 case PHASE_RUN_DEPENDS: 2276 break; 2277 default: 2278 setenv("NO_DEPENDS", "1", 1); 2279 break; 2280 } 2281 2282 /* 2283 * Clean-up, chdir, and chroot. 2284 */ 2285 closefrom(3); 2286 if (chdir(work->basedir) < 0) 2287 dfatal_errno("chdir in phase initialization"); 2288 if (chroot(work->basedir) < 0) 2289 dfatal_errno("chroot in phase initialization"); 2290 2291 /* 2292 * We have a choice here on how to handle stdin (fd 0). 2293 * We can leave it connected to the pty in which case 2294 * the build will just block if it tries to ask a 2295 * question (and the watchdog will kill it, eventually), 2296 * or we can try to EOF the pty, or we can attach /dev/null 2297 * to descriptor 0. 2298 */ 2299 if (NullStdinOpt) { 2300 int fd; 2301 2302 fd = open("/dev/null", O_RDWR); 2303 dassert_errno(fd >= 0, "cannot open /dev/null"); 2304 if (fd != 0) { 2305 dup2(fd, 0); 2306 close(fd); 2307 } 2308 } 2309 2310 /* 2311 * Execute the appropriate command. 2312 */ 2313 switch(phaseid) { 2314 case PHASE_INSTALL_PKGS: 2315 snprintf(buf, sizeof(buf), "/tmp/dsynth_install_pkgs"); 2316 execl(buf, buf, NULL); 2317 break; 2318 default: 2319 snprintf(buf, sizeof(buf), "/xports/%s", pkg->portdir); 2320 execl(MAKE_BINARY, MAKE_BINARY, "-C", buf, phase, NULL); 2321 break; 2322 } 2323 _exit(1); 2324 } 2325 fcntl(MasterPtyFd, F_SETFL, O_NONBLOCK); 2326 2327 if (pid < 0) { 2328 dlog(DLOG_ALL, "[%03d] %s Fork Failed: %s\n", 2329 work->index, pkg->logfile, strerror(errno)); 2330 ++work->accum_error; 2331 return; 2332 } 2333 2334 SigPid = pid; 2335 2336 fdlog = open(pkg->logfile, O_RDWR|O_CREAT|O_APPEND, 0644); 2337 if (fdlog < 0) { 2338 dlog(DLOG_ALL, "[%03d] %s Cannot open logfile '%s': %s\n", 2339 work->index, pkg->portdir, 2340 pkg->logfile, strerror(errno)); 2341 } 2342 2343 snprintf(buf, sizeof(buf), 2344 "----------------------------------------" 2345 "---------------------------------------\n" 2346 "-- Phase: %s\n" 2347 "----------------------------------------" 2348 "---------------------------------------\n", 2349 phase); 2350 write(fdlog, buf, strlen(buf)); 2351 2352 start_time = time(NULL); 2353 last_time = start_time; 2354 wdog_time = start_time; 2355 wpid_reaped = 0; 2356 2357 status = 0; 2358 for (;;) { 2359 ms = mptylogpoll(MasterPtyFd, fdlog, wmsg, &wdog_time); 2360 if (ms == MPTY_FAILED) { 2361 dlog(DLOG_ALL, 2362 "[%03d] %s lost pty in phase %s, terminating\n", 2363 work->index, pkg->portdir, phase); 2364 break; 2365 } 2366 if (ms == MPTY_EOF) 2367 break; 2368 2369 /* 2370 * Generally speaking update status once a second. 2371 * This also allows us to detect if the management 2372 * dsynth process has gone away. 2373 */ 2374 next_time = time(NULL); 2375 if (next_time != last_time) { 2376 double dload[3]; 2377 double dv; 2378 int wdog_scaled; 2379 2380 /* 2381 * Send status update to the worker management thread 2382 * in the master dsynth process. Remember, *WE* are 2383 * the worker management process sub-fork. 2384 */ 2385 if (ipcwritemsg(work->fds[0], wmsg) < 0) 2386 break; 2387 last_time = next_time; 2388 2389 /* 2390 * Watchdog scaling 2391 */ 2392 getloadavg(dload, 3); 2393 adjloadavg(dload); 2394 dv = dload[2] / NumCores; 2395 if (dv < (double)NumCores) { 2396 wdog_scaled = wdog; 2397 } else { 2398 if (dv > 4.0 * NumCores) 2399 dv = 4.0 * NumCores; 2400 wdog_scaled = wdog * dv / NumCores; 2401 } 2402 2403 /* 2404 * Watchdog 2405 */ 2406 if (next_time - wdog_time >= wdog_scaled * 60) { 2407 snprintf(buf, sizeof(buf), 2408 "\n--------\n" 2409 "WATCHDOG TIMEOUT FOR %s in %s " 2410 "after %d minutes\n" 2411 "Killing pid %d\n" 2412 "--------\n", 2413 pkg->portdir, phase, wdog_scaled, pid); 2414 if (fdlog >= 0) 2415 write(fdlog, buf, strlen(buf)); 2416 dlog(DLOG_ALL, 2417 "[%03d] %s WATCHDOG TIMEOUT in %s " 2418 "after %d minutes (%d min scaled)\n", 2419 work->index, pkg->portdir, phase, 2420 wdog, wdog_scaled); 2421 kill(pid, SIGKILL); 2422 ++work->accum_error; 2423 break; 2424 } 2425 } 2426 2427 /* 2428 * Check process exit. Normally the pty will EOF 2429 * but if background processes remain we need to 2430 * check here to see if our primary exec is done, 2431 * so we can break out and reap those processes. 2432 * 2433 * Generally reap any other processes we have inherited 2434 * while we are here. 2435 */ 2436 do { 2437 wpid = wait3(&status, WNOHANG, NULL); 2438 } while (wpid > 0 && wpid != pid); 2439 if (wpid == pid && WIFEXITED(status)) { 2440 wpid_reaped = 1; 2441 break; 2442 } 2443 } 2444 2445 next_time = time(NULL); 2446 2447 setproctitle("[%02d] WORKER EXITREAP %s%s", 2448 work->index, pkg->portdir, WorkerFlavorPrt); 2449 2450 /* 2451 * We usually get here due to a mpty EOF, but not always as there 2452 * could be persistent processes still holding the slave. Finish 2453 * up getting the exit status for the main process we are waiting 2454 * on and clean out any data left on the MasterPtyFd (as it could 2455 * be blocking the exit). 2456 */ 2457 while (wpid_reaped == 0) { 2458 (void)mptylogpoll(MasterPtyFd, fdlog, wmsg, &wdog_time); 2459 wpid = waitpid(pid, &status, WNOHANG); 2460 if (wpid == pid && WIFEXITED(status)) { 2461 wpid_reaped = 1; 2462 break; 2463 } 2464 if (wpid < 0 && errno != EINTR) { 2465 break; 2466 } 2467 2468 /* 2469 * Safety. The normal phase waits until the fork/exec'd 2470 * pid finishes, causing a pty EOF on exit (the slave 2471 * descriptor is closed by the kernel on exit so the 2472 * process should already have exited). 2473 * 2474 * However, it is also possible to get here if the pty fails 2475 * for some reason. In this case, make sure that the process 2476 * is killed. 2477 */ 2478 kill(pid, SIGKILL); 2479 } 2480 2481 /* 2482 * Clean out anything left on the pty but don't wait around 2483 * because there could be background processes preventing the 2484 * slave side from closing. 2485 */ 2486 while (mptylogpoll(MasterPtyFd, fdlog, wmsg, &wdog_time) == MPTY_DATA) 2487 ; 2488 2489 /* 2490 * Report on the exit condition. If the pid was somehow lost 2491 * (probably due to someone gdb'ing the process), assume an error. 2492 */ 2493 if (wpid_reaped) { 2494 if (WEXITSTATUS(status)) { 2495 dlog(DLOG_ALL | DLOG_FILTER, 2496 "[%03d] %s Build phase '%s' failed exit %d\n", 2497 work->index, pkg->portdir, phase, 2498 WEXITSTATUS(status)); 2499 ++work->accum_error; 2500 } 2501 } else { 2502 dlog(DLOG_ALL, "[%03d] %s Build phase '%s' failed - lost pid\n", 2503 work->index, pkg->portdir, phase); 2504 ++work->accum_error; 2505 } 2506 2507 /* 2508 * Kill any processes still running (sometimes processes end up in 2509 * the background during a dports build), and clean up any other 2510 * children that we have inherited. 2511 */ 2512 phaseReapAll(); 2513 2514 /* 2515 * After the extraction phase add the space used by /construction 2516 * to the memory use. This helps us reduce the amount of paging 2517 * we do due to extremely large package extractions (languages, 2518 * chromium, etc). 2519 * 2520 * (dsynth already estimated the space used by the package deps 2521 * up front, but this will help us further). 2522 */ 2523 if (work->accum_error == 0 && phaseid == PHASE_EXTRACT) { 2524 struct statfs sfs; 2525 char *b1; 2526 2527 asprintf(&b1, "%s/construction", work->basedir); 2528 if (statfs(b1, &sfs) == 0) { 2529 wmsg->memuse = (sfs.f_blocks - sfs.f_bfree) * 2530 sfs.f_bsize; 2531 ipcwritemsg(work->fds[0], wmsg); 2532 } 2533 } 2534 2535 /* 2536 * Update log 2537 */ 2538 if (fdlog >= 0) { 2539 struct stat st; 2540 int h; 2541 int m; 2542 int s; 2543 2544 last_time = next_time - start_time; 2545 s = last_time % 60; 2546 m = last_time / 60 % 60; 2547 h = last_time / 3600; 2548 2549 fp = fdopen(fdlog, "a"); 2550 if (fp == NULL) { 2551 dlog(DLOG_ALL, "[%03d] %s Cannot fdopen fdlog: %s %d\n", 2552 work->index, pkg->portdir, 2553 strerror(errno), fstat(fdlog, &st)); 2554 close(fdlog); 2555 goto skip; 2556 } 2557 2558 fprintf(fp, "\n"); 2559 if (work->accum_error) { 2560 fprintf(fp, "FAILED %02d:%02d:%02d\n", h, m, s); 2561 } else { 2562 if (phaseid == PHASE_EXTRACT && wmsg->memuse) { 2563 fprintf(fp, "Extracted Memory Use: %6.2fM\n", 2564 wmsg->memuse / (1024.0 * 1024.0)); 2565 } 2566 fprintf(fp, "SUCCEEDED %02d:%02d:%02d\n", h, m, s); 2567 } 2568 last_time = next_time - work->start_time; 2569 s = last_time % 60; 2570 m = last_time / 60 % 60; 2571 h = last_time / 3600; 2572 if (phaseid == PHASE_PACKAGE) { 2573 fprintf(fp, "TOTAL TIME %02d:%02d:%02d\n", h, m, s); 2574 } 2575 fprintf(fp, "\n"); 2576 fclose(fp); 2577 skip: 2578 ; 2579 } 2580 2581 } 2582 2583 static void 2584 phaseReapAll(void) 2585 { 2586 struct reaper_status rs; 2587 int status; 2588 2589 while (procctl(P_PID, getpid(), PROC_REAP_STATUS, &rs) == 0) { 2590 if ((rs.flags & PROC_REAP_ACQUIRE) == 0) 2591 break; 2592 if (rs.pid_head < 0) 2593 break; 2594 if (kill(rs.pid_head, SIGKILL) == 0) { 2595 while (waitpid(rs.pid_head, &status, 0) < 0) 2596 ; 2597 } 2598 } 2599 while (wait3(&status, 0, NULL) > 0) 2600 ; 2601 } 2602 2603 static void 2604 phaseTerminateSignal(int sig __unused) 2605 { 2606 if (CopyFileFd >= 0) 2607 close(CopyFileFd); 2608 if (MasterPtyFd >= 0) 2609 close(MasterPtyFd); 2610 if (SigPid > 1) 2611 kill(SigPid, SIGKILL); 2612 phaseReapAll(); 2613 if (SigWork) 2614 DoWorkerUnmounts(SigWork); 2615 exit(1); 2616 } 2617 2618 static 2619 char * 2620 buildskipreason(pkglink_t *parent, pkg_t *pkg) 2621 { 2622 pkglink_t *link; 2623 pkg_t *scan; 2624 char *reason = NULL; 2625 char *ptr; 2626 size_t tot; 2627 size_t len; 2628 pkglink_t stack; 2629 2630 if ((pkg->flags & PKGF_NOBUILD_I) && pkg->ignore) 2631 asprintf(&reason, "%s ", pkg->ignore); 2632 2633 tot = 0; 2634 PKGLIST_FOREACH(link, &pkg->idepon_list) { 2635 #if 0 2636 if (link->dep_type > DEP_TYPE_BUILD) 2637 continue; 2638 #endif 2639 scan = link->pkg; 2640 if (scan == NULL) 2641 continue; 2642 if ((scan->flags & (PKGF_ERROR | PKGF_NOBUILD)) == 0) 2643 continue; 2644 if (scan->flags & PKGF_NOBUILD) { 2645 stack.pkg = scan; 2646 stack.next = parent; 2647 ptr = buildskipreason(&stack, scan); 2648 len = strlen(scan->portdir) + strlen(ptr) + 8; 2649 reason = realloc(reason, tot + len); 2650 snprintf(reason + tot, len, "%s->%s", 2651 scan->portdir, ptr); 2652 free(ptr); 2653 } else { 2654 len = strlen(scan->portdir) + 8; 2655 reason = realloc(reason, tot + len); 2656 snprintf(reason + tot, len, "%s", scan->portdir); 2657 } 2658 2659 /* 2660 * Don't try to print the entire graph 2661 */ 2662 if (parent) 2663 break; 2664 tot += strlen(reason + tot); 2665 reason[tot++] = ' '; 2666 reason[tot] = 0; 2667 } 2668 return (reason); 2669 } 2670 2671 /* 2672 * Count number of packages that would be skipped due to the 2673 * specified package having failed. 2674 * 2675 * Call with mode 1 to count, and mode 0 to clear the 2676 * cumulative rscan flag (used to de-duplicate the count). 2677 * 2678 * Must be serialized. 2679 */ 2680 static int 2681 buildskipcount_dueto(pkg_t *pkg, int mode) 2682 { 2683 pkglink_t *link; 2684 pkg_t *scan; 2685 int total; 2686 2687 total = 0; 2688 PKGLIST_FOREACH(link, &pkg->deponi_list) { 2689 scan = link->pkg; 2690 if (scan == NULL || scan->rscan == mode) 2691 continue; 2692 scan->rscan = mode; 2693 ++total; 2694 total += buildskipcount_dueto(scan, mode); 2695 } 2696 return total; 2697 } 2698 2699 /* 2700 * The master ptyfd is in non-blocking mode. Drain up to 1024 bytes 2701 * and update wmsg->lines and *wdog_timep as appropriate. 2702 * 2703 * This function will poll, stalling up to 1 second. 2704 */ 2705 static int 2706 mptylogpoll(int ptyfd, int fdlog, wmsg_t *wmsg, time_t *wdog_timep) 2707 { 2708 struct pollfd pfd; 2709 char buf[1024]; 2710 ssize_t r; 2711 2712 pfd.fd = ptyfd; 2713 pfd.events = POLLIN; 2714 pfd.revents = 0; 2715 2716 poll(&pfd, 1, 1000); 2717 if (pfd.revents) { 2718 r = read(ptyfd, buf, sizeof(buf)); 2719 if (r > 0) { 2720 *wdog_timep = time(NULL); 2721 if (r > 0 && fdlog >= 0) 2722 write(fdlog, buf, r); 2723 while (--r >= 0) { 2724 if (buf[r] == '\n') 2725 ++wmsg->lines; 2726 } 2727 return MPTY_DATA; 2728 } else if (r < 0) { 2729 if (errno != EINTR && errno != EAGAIN) 2730 return MPTY_FAILED; 2731 return MPTY_AGAIN; 2732 } else if (r == 0) { 2733 return MPTY_EOF; 2734 } 2735 } 2736 return MPTY_AGAIN; 2737 } 2738 2739 /* 2740 * Copy a (package) file from (src) to (dst), use an intermediate file and 2741 * rename to ensure that interruption does not leave us with a corrupt 2742 * package file. 2743 * 2744 * This is called by the WORKER process. 2745 * 2746 * (dsynth management thread -> WORKER process -> sub-processes) 2747 */ 2748 #define COPYBLKSIZE 32768 2749 2750 int 2751 copyfile(char *src, char *dst) 2752 { 2753 char *tmp; 2754 char *buf; 2755 int fd1; 2756 int fd2; 2757 int error = 0; 2758 int mask; 2759 ssize_t r; 2760 2761 asprintf(&tmp, "%s.new", dst); 2762 buf = malloc(COPYBLKSIZE); 2763 2764 mask = sigsetmask(sigmask(SIGTERM)|sigmask(SIGINT)|sigmask(SIGHUP)); 2765 fd1 = open(src, O_RDONLY|O_CLOEXEC); 2766 fd2 = open(tmp, O_RDWR|O_CREAT|O_TRUNC|O_CLOEXEC, 0644); 2767 CopyFileFd = fd1; 2768 sigsetmask(mask); 2769 while ((r = read(fd1, buf, COPYBLKSIZE)) > 0) { 2770 if (write(fd2, buf, r) != r) 2771 error = 1; 2772 } 2773 if (r < 0) 2774 error = 1; 2775 mask = sigsetmask(sigmask(SIGTERM)|sigmask(SIGINT)|sigmask(SIGHUP)); 2776 CopyFileFd = -1; 2777 close(fd1); 2778 close(fd2); 2779 sigsetmask(mask); 2780 if (error) { 2781 remove(tmp); 2782 } else { 2783 if (rename(tmp, dst)) { 2784 error = 1; 2785 remove(tmp); 2786 } 2787 } 2788 2789 freestrp(&buf); 2790 freestrp(&tmp); 2791 2792 return error; 2793 } 2794 2795 /* 2796 * doHook() 2797 * 2798 * primary process (threaded) - run_start, run_end, pkg_ignored, pkg_skipped 2799 * worker process (threaded) - pkg_sucess, pkg_failure 2800 * 2801 * If waitfor is non-zero this hook will be serialized. 2802 */ 2803 static void 2804 doHook(pkg_t *pkg, const char *id, const char *path, int waitfor) 2805 { 2806 if (path == NULL) 2807 return; 2808 while (waitfor && getbulk() != NULL) 2809 ; 2810 if (pkg) 2811 queuebulk(pkg->portdir, id, path, pkg->pkgfile); 2812 else 2813 queuebulk(NULL, id, path, NULL); 2814 while (waitfor && getbulk() != NULL) 2815 ; 2816 } 2817 2818 /* 2819 * Execute hook (backend) 2820 * 2821 * s1 - portdir 2822 * s2 - id 2823 * s3 - script path 2824 * s4 - pkgfile (if applicable) 2825 */ 2826 static void 2827 childHookRun(bulk_t *bulk) 2828 { 2829 const char *cav[MAXCAC]; 2830 buildenv_t benv[MAXCAC]; 2831 char buf1[128]; 2832 char buf2[128]; 2833 char buf3[128]; 2834 char buf4[128]; 2835 FILE *fp; 2836 char *ptr; 2837 size_t len; 2838 pid_t pid; 2839 int cac; 2840 int bi; 2841 2842 cac = 0; 2843 bi = 0; 2844 bzero(benv, sizeof(benv)); 2845 2846 cav[cac++] = bulk->s3; 2847 2848 benv[bi].label = "PROFILE"; 2849 benv[bi].data = Profile; 2850 ++bi; 2851 2852 benv[bi].label = "DIR_PACKAGES"; 2853 benv[bi].data = PackagesPath; 2854 ++bi; 2855 2856 benv[bi].label = "DIR_REPOSITORY"; 2857 benv[bi].data = RepositoryPath; 2858 ++bi; 2859 2860 benv[bi].label = "DIR_PORTS"; 2861 benv[bi].data = DPortsPath; 2862 ++bi; 2863 2864 benv[bi].label = "DIR_OPTIONS"; 2865 benv[bi].data = OptionsPath; 2866 ++bi; 2867 2868 benv[bi].label = "DIR_DISTFILES"; 2869 benv[bi].data = DistFilesPath; 2870 ++bi; 2871 2872 benv[bi].label = "DIR_LOGS"; 2873 benv[bi].data = LogsPath; 2874 ++bi; 2875 2876 benv[bi].label = "DIR_BUILDBASE"; 2877 benv[bi].data = BuildBase; 2878 ++bi; 2879 2880 if (strcmp(bulk->s2, "hook_run_start") == 0) { 2881 snprintf(buf1, sizeof(buf1), "%d", BuildTotal); 2882 benv[bi].label = "PORTS_QUEUED"; 2883 benv[bi].data = buf1; 2884 ++bi; 2885 } else if (strcmp(bulk->s2, "hook_run_end") == 0) { 2886 snprintf(buf1, sizeof(buf1), "%d", BuildSuccessCount); 2887 benv[bi].label = "PORTS_BUILT"; 2888 benv[bi].data = buf1; 2889 ++bi; 2890 snprintf(buf2, sizeof(buf2), "%d", BuildFailCount); 2891 benv[bi].label = "PORTS_FAILED"; 2892 benv[bi].data = buf2; 2893 ++bi; 2894 snprintf(buf3, sizeof(buf3), "%d", BuildIgnoreCount); 2895 benv[bi].label = "PORTS_IGNORED"; 2896 benv[bi].data = buf3; 2897 ++bi; 2898 snprintf(buf4, sizeof(buf4), "%d", BuildSkipCount); 2899 benv[bi].label = "PORTS_SKIPPED"; 2900 benv[bi].data = buf4; 2901 ++bi; 2902 } else { 2903 /* 2904 * success, failure, ignored, skipped 2905 */ 2906 benv[bi].label = "RESULT"; 2907 if (strcmp(bulk->s2, "hook_pkg_success") == 0) { 2908 benv[bi].data = "success"; 2909 } else if (strcmp(bulk->s2, "hook_pkg_failure") == 0) { 2910 benv[bi].data = "failure"; 2911 } else if (strcmp(bulk->s2, "hook_pkg_ignored") == 0) { 2912 benv[bi].data = "ignored"; 2913 } else if (strcmp(bulk->s2, "hook_pkg_skipped") == 0) { 2914 benv[bi].data = "skipped"; 2915 } else { 2916 dfatal("Unknown hook id: %s", bulk->s2); 2917 /* NOT REACHED */ 2918 } 2919 ++bi; 2920 2921 /* 2922 * For compatibility with synth: 2923 * 2924 * ORIGIN does not include any @flavor, thus it is suitable 2925 * for finding the actual port directory/subdirectory. 2926 * 2927 * FLAVOR is set to ORIGIN if there is no flavor, otherwise 2928 * it is set to only the flavor sans the '@'. 2929 */ 2930 if ((ptr = strchr(bulk->s1, '@')) != NULL) { 2931 snprintf(buf1, sizeof(buf1), "%*.*s", 2932 (int)(ptr - bulk->s1), 2933 (int)(ptr - bulk->s1), 2934 bulk->s1); 2935 benv[bi].label = "ORIGIN"; 2936 benv[bi].data = buf1; 2937 ++bi; 2938 benv[bi].label = "FLAVOR"; 2939 benv[bi].data = ptr + 1; 2940 ++bi; 2941 } else { 2942 benv[bi].label = "ORIGIN"; 2943 benv[bi].data = bulk->s1; 2944 ++bi; 2945 benv[bi].label = "FLAVOR"; 2946 benv[bi].data = bulk->s1; 2947 ++bi; 2948 } 2949 benv[bi].label = "PKGNAME"; 2950 benv[bi].data = bulk->s4; 2951 ++bi; 2952 } 2953 2954 benv[bi].label = NULL; 2955 benv[bi].data = NULL; 2956 2957 fp = dexec_open(cav, cac, &pid, benv, 0, 0); 2958 while ((ptr = fgetln(fp, &len)) != NULL) 2959 ; 2960 2961 if (dexec_close(fp, pid)) { 2962 dlog(DLOG_ALL, 2963 "[XXX] %s SCRIPT %s (%s)\n", 2964 bulk->s1, bulk->s2, bulk->s3); 2965 } 2966 } 2967 2968 /* 2969 * Adjusts dload[0] by adding in t_pw (processes waiting on page-fault). 2970 * We don't want load reductions due to e.g. thrashing to cause dsynth 2971 * to increase the dynamic limit because it thinks the load is low. 2972 * 2973 * This has a desirable property. If the system pager cannot keep up 2974 * with process demand t_pw will spike while loadavg will only drop 2975 * slowly, resulting in a high adjusted load calculation that causes 2976 * dsynth to quickly clamp-down the limit. If the condition alleviates, 2977 * the limit will then rise slowly again, possibly even before existing 2978 * jobs are retired to meet the clamp-down from the original spike. 2979 */ 2980 static void 2981 adjloadavg(double *dload) 2982 { 2983 #if defined(__DragonFly__) 2984 struct vmtotal total; 2985 size_t size; 2986 2987 size = sizeof(total); 2988 if (sysctlbyname("vm.vmtotal", &total, &size, NULL, 0) == 0) { 2989 dload[0] += (double)total.t_pw; 2990 } 2991 #else 2992 dload[0] += 0.0; /* just avoid compiler 'unused' warnings */ 2993 #endif 2994 } 2995