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", 1074 scount); 1075 } else { 1076 skipbuf[0] = 0; 1077 } 1078 1079 ++BuildFailCount; 1080 dlog(DLOG_FAIL | DLOG_RED, 1081 "[%03d] FAILURE %s%s ##%16.16s %02d:%02d:%02d\n", 1082 work->index, pkg->portdir, skipbuf, 1083 getphasestr(work->phase), 1084 h, m, s); 1085 RunStatsUpdateCompletion(work, DLOG_FAIL, pkg, skipbuf); 1086 doHook(pkg, "hook_pkg_failure", HookPkgFailure, 0); 1087 } 1088 } else { 1089 pkg->flags |= PKGF_SUCCESS; 1090 ++BuildSuccessCount; 1091 dlog(DLOG_SUCC | DLOG_GRN, 1092 "[%03d] SUCCESS %s ##%02d:%02d:%02d\n", 1093 work->index, pkg->portdir, h, m, s); 1094 RunStatsUpdateCompletion(work, DLOG_SUCC, pkg, ""); 1095 doHook(pkg, "hook_pkg_success", HookPkgSuccess, 0); 1096 } 1097 ++BuildCount; 1098 pkg->flags &= ~PKGF_BUILDLIST; 1099 pkg->flags &= ~PKGF_RUNNING; 1100 work->pkg = NULL; 1101 --RunningWorkers; 1102 1103 if (work->state == WORKER_FAILED) { 1104 dlog(DLOG_ALL, "[%03d] XXX/XXX WORKER IS IN A FAILED STATE\n", 1105 work->index); 1106 ++FailedWorkers; 1107 } else if (work->flags & WORKERF_FREEZE) { 1108 dlog(DLOG_ALL, "[%03d] FROZEN(DEBUG) %s\n", 1109 work->index, pkg->portdir); 1110 work->state = WORKER_FROZEN; 1111 } else { 1112 work->state = WORKER_IDLE; 1113 } 1114 } 1115 1116 /* 1117 * Wait for one or more workers to complete. 1118 * 1119 * WorkerMutex must be held. 1120 */ 1121 static void 1122 waitbuild(int whilematch, int dynamicmax) 1123 { 1124 static time_t wblast_time; 1125 static time_t dmlast_time; 1126 struct timespec ts; 1127 worker_t *work; 1128 time_t t; 1129 int i; 1130 1131 if (whilematch == 0) 1132 whilematch = 1; 1133 1134 while (RunningWorkers == whilematch) { 1135 for (i = 0; i < MaxWorkers; ++i) { 1136 work = &WorkerAry[i]; 1137 if (work->state == WORKER_DONE || 1138 work->state == WORKER_FAILED) { 1139 workercomplete(work); 1140 } else { 1141 pthread_cond_signal(&work->cond); 1142 } 1143 RunStatsUpdate(work, NULL); 1144 } 1145 RunStatsUpdateTop(1); 1146 RunStatsUpdateLogs(); 1147 RunStatsSync(); 1148 if (RunningWorkers == whilematch) { 1149 clock_gettime(CLOCK_REALTIME, &ts); 1150 ts.tv_sec += 1; 1151 ts.tv_nsec = 0; 1152 pthread_cond_timedwait(&WorkerCond, &WorkerMutex, &ts); 1153 } 1154 1155 /* 1156 * Dynamically reduce MaxWorkers based on the load. When 1157 * the load exceeds 2 x ncpus we reduce the number of workers 1158 * up to 75% of MaxWorkers @ (5 x ncpus) load. 1159 * 1160 * Dynamically reduce MaxWorkers based on swap use, starting 1161 * at 10% swap and up to 75% of MaxWorkers at 40% swap. 1162 * 1163 * NOTE! Generally speaking this allows more workers to be 1164 * configured which helps in two ways. First it allows 1165 * a higher build rate for smaller packages. Second 1166 * it allows dsynth to ratchet-down the number of slots 1167 * when large packages are forcing the load up. 1168 * 1169 * A high load doesn't hurt efficiency, but swap usage 1170 * due to loading the tmpfs in lots of worker slots up 1171 * with tons of pkg install's (pre-reqs for a build) 1172 * does. Reducing the number of worker slots has a 1173 * huge beneficial effect on reducing swap use / paging. 1174 */ 1175 t = time(NULL); 1176 if (dynamicmax && (wblast_time == 0 || 1177 (unsigned)(t - wblast_time) >= 5)) { 1178 double min_load = 1.5 * NumCores; 1179 double max_load = 5.0 * NumCores; 1180 double min_swap = 0.10; 1181 double max_swap = 0.40; 1182 double dload[3]; 1183 double dswap; 1184 int max1; 1185 int max2; 1186 int max3; 1187 int max_sel; 1188 int noswap; 1189 1190 wblast_time = t; 1191 1192 /* 1193 * Cap based on load. This is back-loaded. 1194 */ 1195 getloadavg(dload, 3); 1196 adjloadavg(dload); 1197 if (dload[0] < min_load) { 1198 max1 = MaxWorkers; 1199 } else if (dload[0] <= max_load) { 1200 max1 = MaxWorkers - 1201 MaxWorkers * 0.75 * 1202 (dload[0] - min_load) / 1203 (max_load - min_load); 1204 } else { 1205 max1 = MaxWorkers * 25 / 100; 1206 } 1207 1208 /* 1209 * Cap based on swap use. This is back-loaded. 1210 */ 1211 dswap = getswappct(&noswap); 1212 if (dswap < min_swap) { 1213 max2 = MaxWorkers; 1214 } else if (dswap <= max_swap) { 1215 max2 = MaxWorkers - 1216 MaxWorkers * 0.75 * 1217 (dswap - min_swap) / 1218 (max_swap - min_swap); 1219 } else { 1220 max2 = MaxWorkers * 25 / 100; 1221 } 1222 1223 /* 1224 * Cap based on aggregate pkg-dependency memory 1225 * use installed in worker slots. This is 1226 * front-loaded. 1227 * 1228 * Since it can take a while for workers to retire 1229 * (to reduce RunningPkgDepSize), just set our 1230 * target 1 below the current run count to allow 1231 * jobs to retire without being replaced with new 1232 * jobs. 1233 * 1234 * In addition, in order to avoid a paging 'shock', 1235 * We enforce a 30 second-per-increment slow-start 1236 * once RunningPkgDepSize exceeds 1/2 the target. 1237 */ 1238 if (RunningPkgDepSize > PkgDepMemoryTarget) { 1239 max3 = RunningWorkers - 1; 1240 } else if (RunningPkgDepSize > PkgDepMemoryTarget / 2) { 1241 if (dmlast_time == 0 || 1242 (unsigned)(t - dmlast_time) >= 30) { 1243 dmlast_time = t; 1244 max3 = RunningWorkers + 1; 1245 } else { 1246 max3 = RunningWorkers; 1247 } 1248 } else { 1249 max3 = MaxWorkers; 1250 } 1251 1252 /* 1253 * Priority reduction, convert to DynamicMaxWorkers 1254 */ 1255 max_sel = max1; 1256 if (max_sel > max2) 1257 max_sel = max2; 1258 if (max_sel > max3) 1259 max_sel = max3; 1260 1261 /* 1262 * Restrict to allowed range, and also handle 1263 * slow-start. 1264 */ 1265 if (max_sel < 1) 1266 max_sel = 1; 1267 if (max_sel > DynamicMaxWorkers + 1) 1268 max_sel = DynamicMaxWorkers + 1; 1269 if (max_sel > MaxWorkers) 1270 max_sel = MaxWorkers; 1271 1272 /* 1273 * Stop waiting if DynamicMaxWorkers is going to 1274 * increase. 1275 */ 1276 if (DynamicMaxWorkers < max1) 1277 whilematch = -1; 1278 1279 /* 1280 * And adjust 1281 */ 1282 if (DynamicMaxWorkers != max1) { 1283 dlog(DLOG_ALL | DLOG_FILTER, 1284 "[XXX] Load=%-6.2f(%2d) " 1285 "Swap=%-3.2f%%(%2d) " 1286 "Mem=%3.2fG(%2d) " 1287 "Adjust Workers %d->%d\n", 1288 dload[0], max1, 1289 dswap * 100.0, max2, 1290 RunningPkgDepSize / (double)ONEGB, max3, 1291 DynamicMaxWorkers, max_sel); 1292 DynamicMaxWorkers = max_sel; 1293 } 1294 } 1295 } 1296 } 1297 1298 1299 /* 1300 * Worker pthread (WorkerAry) 1301 * 1302 * This thread belongs to the dsynth master process and handled a worker slot. 1303 * (this_thread) -> WORKER fork/exec (WorkerPocess) -> (pty) -> sub-processes. 1304 */ 1305 static void * 1306 childBuilderThread(void *arg) 1307 { 1308 char *envary[1] = { NULL }; 1309 worker_t *work = arg; 1310 wmsg_t wmsg; 1311 pkg_t *pkg; 1312 pid_t pid; 1313 int status; 1314 int flags; 1315 volatile int dowait; 1316 char slotbuf[8]; 1317 char fdbuf[8]; 1318 char flagsbuf[16]; 1319 1320 pthread_mutex_lock(&WorkerMutex); 1321 while (work->terminate == 0) { 1322 dowait = 1; 1323 1324 switch(work->state) { 1325 case WORKER_IDLE: 1326 break; 1327 case WORKER_PENDING: 1328 /* 1329 * Fork the management process for the pkg operation 1330 * on this worker slot. 1331 * 1332 * This process will set up the environment, do the 1333 * mounts, will become the reaper, and will process 1334 * pipe commands and handle chroot operations. 1335 * 1336 * NOTE: If SOCK_CLOEXEC is not supported WorkerMutex 1337 * is sufficient to interlock F_SETFD FD_CLOEXEC 1338 * operations. 1339 */ 1340 ddassert(work->pkg); 1341 if (socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 1342 PF_UNSPEC, work->fds)) { 1343 dfatal_errno("socketpair() during worker fork"); 1344 } 1345 snprintf(slotbuf, sizeof(slotbuf), "%d", work->index); 1346 snprintf(fdbuf, sizeof(fdbuf), "3"); 1347 1348 /* 1349 * Pass global flags and add-in the DEBUGSTOP if 1350 * the package is flagged for debugging. 1351 */ 1352 flags = WorkerProcFlags; 1353 if (work->pkg->flags & PKGF_DEBUGSTOP) { 1354 flags |= WORKER_PROC_DEBUGSTOP; 1355 } else { 1356 flags &= ~WORKER_PROC_DEBUGSTOP; 1357 } 1358 snprintf(flagsbuf, sizeof(flagsbuf), "%d", flags); 1359 1360 /* 1361 * fds[0] - master 1362 * fds[1] - slave 1363 * 1364 * We pass the salve descriptor in fd 3 and close all 1365 * other descriptors for security. 1366 */ 1367 pthread_mutex_unlock(&WorkerMutex); 1368 pid = vfork(); 1369 if (pid == 0) { 1370 close(work->fds[0]); 1371 dup2(work->fds[1], 3); 1372 closefrom(4); 1373 fcntl(3, F_SETFD, 0); 1374 execle(DSynthExecPath, DSynthExecPath, 1375 "-p", Profile, 1376 "WORKER", slotbuf, fdbuf, 1377 work->pkg->portdir, work->pkg->pkgfile, 1378 flagsbuf, 1379 NULL, envary); 1380 write(2, "EXECLE FAILURE\n", 15); 1381 _exit(1); 1382 } 1383 pthread_mutex_lock(&WorkerMutex); 1384 close(work->fds[1]); 1385 work->phase = PHASE_PENDING; 1386 work->lines = 0; 1387 work->memuse = 0; 1388 work->pid = pid; 1389 work->state = WORKER_RUNNING; 1390 /* fall through */ 1391 case WORKER_RUNNING: 1392 /* 1393 * Poll for status updates, if NULL is returned 1394 * and status is non-zero, the communications link 1395 * failed unexpectedly. 1396 */ 1397 pkg = work->pkg; 1398 pthread_mutex_unlock(&WorkerMutex); 1399 status = ipcreadmsg(work->fds[0], &wmsg); 1400 pthread_mutex_lock(&WorkerMutex); 1401 1402 if (status == 0) { 1403 /* 1404 * Normal message, can include normal 1405 * termination which changes us over 1406 * to another state. 1407 */ 1408 dowait = 0; 1409 switch(wmsg.cmd) { 1410 case WMSG_CMD_INSTALL_PKGS: 1411 wmsg.cmd = WMSG_RES_INSTALL_PKGS; 1412 wmsg.status = childInstallPkgDeps(work); 1413 pthread_mutex_unlock(&WorkerMutex); 1414 ipcwritemsg(work->fds[0], &wmsg); 1415 pthread_mutex_lock(&WorkerMutex); 1416 break; 1417 case WMSG_CMD_STATUS_UPDATE: 1418 work->phase = wmsg.phase; 1419 work->lines = wmsg.lines; 1420 if (work->memuse != wmsg.memuse) { 1421 RunningPkgDepSize += 1422 wmsg.memuse - work->memuse; 1423 work->memuse = wmsg.memuse; 1424 } 1425 break; 1426 case WMSG_CMD_SUCCESS: 1427 work->flags |= WORKERF_SUCCESS; 1428 break; 1429 case WMSG_CMD_FAILURE: 1430 work->flags |= WORKERF_FAILURE; 1431 break; 1432 case WMSG_CMD_FREEZEWORKER: 1433 work->flags |= WORKERF_FREEZE; 1434 break; 1435 default: 1436 break; 1437 } 1438 RunStatsUpdate(work, NULL); 1439 RunStatsSync(); 1440 } else { 1441 close(work->fds[0]); 1442 pthread_mutex_unlock(&WorkerMutex); 1443 while (waitpid(work->pid, &status, 0) < 0 && 1444 errno == EINTR) { 1445 ; 1446 } 1447 pthread_mutex_lock(&WorkerMutex); 1448 1449 if (work->flags & WORKERF_SUCCESS) { 1450 pkg->flags |= PKGF_SUCCESS; 1451 work->state = WORKER_DONE; 1452 } else if (work->flags & WORKERF_FAILURE) { 1453 pkg->flags |= PKGF_FAILURE; 1454 work->state = WORKER_DONE; 1455 } else { 1456 pkg->flags |= PKGF_FAILURE; 1457 work->state = WORKER_FAILED; 1458 } 1459 work->flags |= WORKERF_STATUS_UPDATE; 1460 pthread_cond_signal(&WorkerCond); 1461 } 1462 break; 1463 case WORKER_DONE: 1464 /* 1465 * pkg remains attached until frontend processes the 1466 * completion. The frontend will then set the state 1467 * back to idle. 1468 */ 1469 break; 1470 case WORKER_FAILED: 1471 /* 1472 * A worker failure means that the worker did not 1473 * send us a WMSG_CMD_SUCCESS or WMSG_CMD_FAILURE 1474 * ipc before terminating. 1475 * 1476 * We just sit in this state until the front-end 1477 * does something about it. 1478 */ 1479 break; 1480 case WORKER_FROZEN: 1481 /* 1482 * A worker getting frozen is debug-related. We 1483 * just sit in this state (likely forever). 1484 */ 1485 break; 1486 default: 1487 dfatal("worker: [%03d] Unexpected state %d " 1488 "for worker %d", 1489 work->index, work->state, work->index); 1490 /* NOT REACHED */ 1491 break; 1492 } 1493 1494 /* 1495 * The dsynth frontend will poll us approximately once 1496 * a second (its variable). 1497 */ 1498 if (dowait) 1499 pthread_cond_wait(&work->cond, &WorkerMutex); 1500 } 1501 1502 /* 1503 * Scrap the comm socket if running, this should cause the worker 1504 * process to kill its sub-programs and cleanup. 1505 */ 1506 if (work->state == WORKER_RUNNING) { 1507 pthread_mutex_unlock(&WorkerMutex); 1508 close(work->fds[0]); 1509 while (waitpid(work->pid, &status, 0) < 0 && 1510 errno == EINTR); 1511 pthread_mutex_lock(&WorkerMutex); 1512 } 1513 1514 /* 1515 * Final handshake 1516 */ 1517 work->state = WORKER_EXITING; 1518 pthread_cond_signal(&WorkerCond); 1519 pthread_mutex_unlock(&WorkerMutex); 1520 1521 return NULL; 1522 } 1523 1524 /* 1525 * Install all the binary packages (we have already built them) that 1526 * the current work package depends on, without duplicates, in a script 1527 * which will be run from within the specified work jail. 1528 * 1529 * Locked by WorkerMutex (global) 1530 */ 1531 static int 1532 childInstallPkgDeps(worker_t *work) 1533 { 1534 char *buf; 1535 FILE *fp; 1536 1537 if (PKGLIST_EMPTY(&work->pkg->idepon_list)) 1538 return 0; 1539 1540 asprintf(&buf, "%s/tmp/dsynth_install_pkgs", work->basedir); 1541 fp = fopen(buf, "w"); 1542 ddassert(fp != NULL); 1543 fprintf(fp, "#!/bin/sh\n"); 1544 fprintf(fp, "#\n"); 1545 fchmod(fileno(fp), 0755); 1546 1547 childInstallPkgDeps_recurse(fp, &work->pkg->idepon_list, 0, 1, 0); 1548 childInstallPkgDeps_recurse(fp, &work->pkg->idepon_list, 1, 1, 0); 1549 fprintf(fp, "\nexit 0\n"); 1550 fclose(fp); 1551 freestrp(&buf); 1552 1553 return 1; 1554 } 1555 1556 /* 1557 * Recursive child install dependencies. 1558 * 1559 * first_one_only is only specified if the pkg the list comes from 1560 * is a generic unflavored package that has flavors, telling us to 1561 * dive the first flavor only. 1562 * 1563 * However, in nearly all cases this flag will now be zero because 1564 * this code now dives the first flavor when encountering a dummy node 1565 * and clears nfirst on success. Hence if you are asking why 'nfirst' 1566 * is set to 1, and then zero, instead of just being removed entirely, 1567 * it is because there might still be an edge case here. 1568 */ 1569 static size_t 1570 childInstallPkgDeps_recurse(FILE *fp, pkglink_t *list, int undoit, 1571 int depth, int first_one_only) 1572 { 1573 pkglink_t *link; 1574 pkg_t *pkg; 1575 size_t tot = 0; 1576 int ndepth; 1577 int nfirst; 1578 1579 PKGLIST_FOREACH(link, list) { 1580 pkg = link->pkg; 1581 1582 /* 1583 * We don't want to mess up our depth test just below if 1584 * a DUMMY node had to be inserted. The nodes under the 1585 * dummy node. 1586 * 1587 * The elements under a dummy node represent all the flabor, 1588 * a dependency that directly references a dummy node only 1589 * uses the first flavor (first_one_only / nfirst). 1590 */ 1591 ndepth = (pkg->flags & PKGF_DUMMY) ? depth : depth + 1; 1592 nfirst = (pkg->flags & PKGF_DUMMY) ? 1 : 0; 1593 1594 /* 1595 * We only need all packages for the top-level dependencies. 1596 * The deeper ones only need DEP_TYPE_LIB and DEP_TYPE_RUN 1597 * (types greater than DEP_TYPE_BUILD) since they are already 1598 * built. 1599 */ 1600 if (depth > 1 && link->dep_type <= DEP_TYPE_BUILD) { 1601 if (first_one_only) 1602 break; 1603 continue; 1604 } 1605 1606 /* 1607 * If this is a dummy node with no package, the originator 1608 * is requesting a flavored package. We select the default 1609 * flavor which we presume is the first one. 1610 */ 1611 if (pkg->pkgfile == NULL && (pkg->flags & PKGF_DUMMY)) { 1612 pkg_t *spkg = pkg->idepon_list.next->pkg; 1613 1614 if (spkg) { 1615 if (fp) { 1616 fprintf(fp, 1617 "echo 'UNFLAVORED %s -> use " 1618 "%s'\n", 1619 pkg->portdir, 1620 spkg->portdir); 1621 } 1622 pkg = spkg; 1623 nfirst = 0; 1624 } else { 1625 if (fp) { 1626 fprintf(fp, 1627 "echo 'CANNOT FIND DEFAULT " 1628 "FLAVOR FOR %s'\n", 1629 pkg->portdir); 1630 } 1631 } 1632 } 1633 1634 if (undoit) { 1635 if (pkg->dsynth_install_flg == 1) { 1636 pkg->dsynth_install_flg = 0; 1637 tot += childInstallPkgDeps_recurse(fp, 1638 &pkg->idepon_list, 1639 undoit, 1640 ndepth, nfirst); 1641 } 1642 if (first_one_only) 1643 break; 1644 continue; 1645 } 1646 1647 if (pkg->dsynth_install_flg) { 1648 if (DebugOpt >= 2 && pkg->pkgfile && fp) { 1649 fprintf(fp, "echo 'AlreadyHave %s'\n", 1650 pkg->pkgfile); 1651 } 1652 if (first_one_only) 1653 break; 1654 continue; 1655 } 1656 1657 tot += childInstallPkgDeps_recurse(fp, &pkg->idepon_list, 1658 undoit, ndepth, nfirst); 1659 if (pkg->dsynth_install_flg) { 1660 if (first_one_only) 1661 break; 1662 continue; 1663 } 1664 pkg->dsynth_install_flg = 1; 1665 1666 /* 1667 * Generate package installation command 1668 */ 1669 if (fp && pkg->pkgfile) { 1670 fprintf(fp, "echo 'Installing /packages/All/%s'\n", 1671 pkg->pkgfile); 1672 fprintf(fp, "pkg install -q -U -y /packages/All/%s " 1673 "|| exit 1\n", 1674 pkg->pkgfile); 1675 } else if (fp) { 1676 fprintf(fp, "echo 'CANNOT FIND PKG FOR %s'\n", 1677 pkg->portdir); 1678 } 1679 1680 if (pkg->pkgfile) { 1681 struct stat st; 1682 char *path; 1683 char *ptr; 1684 1685 asprintf(&path, "%s/%s", RepositoryPath, pkg->pkgfile); 1686 ptr = strrchr(pkg->pkgfile, '.'); 1687 if (stat(path, &st) == 0) { 1688 if (strcmp(ptr, ".tar") == 0) 1689 tot += st.st_size; 1690 else if (strcmp(ptr, ".tgz") == 0) 1691 tot += st.st_size * 3; 1692 else if (strcmp(ptr, ".txz") == 0) 1693 tot += st.st_size * 5; 1694 else if (strcmp(ptr, ".tbz") == 0) 1695 tot += st.st_size * 3; 1696 else 1697 tot += st.st_size * 2; 1698 } 1699 free(path); 1700 } 1701 if (first_one_only) 1702 break; 1703 } 1704 return tot; 1705 } 1706 1707 /* 1708 * Worker process interactions. 1709 * 1710 * The worker process is responsible for managing the build of a single 1711 * package. It is exec'd by the master dsynth and only loads the 1712 * configuration. 1713 * 1714 * This process does not run in the chroot. It will become the reaper for 1715 * all sub-processes and it will enter the chroot to execute various phases. 1716 * It catches SIGINTR, SIGHUP, and SIGPIPE and will iterate, terminate, and 1717 * reap all sub-process upon kill or exit. 1718 * 1719 * The command line forwarded to this function is: 1720 * 1721 * WORKER slot# socketfd portdir/subdir 1722 * 1723 * TERM=dumb 1724 * USER=root 1725 * HOME=/root 1726 * LANG=C 1727 * SSL_NO_VERIFY_PEER=1 1728 * USE_PACKAGE_DEPENDS_ONLY=1 1729 * PORTSDIR=/xports 1730 * PORT_DBDIR=/options For ports options 1731 * PACKAGE_BUILDING=yes Don't build packages that aren't legally 1732 * buildable for a binary repo. 1733 * PKG_DBDIR=/var/db/pkg 1734 * PKG_CACHEDIR=/var/cache/pkg 1735 * PKG_CREATE_VERBOSE=yes Ensure periodic output during packaging 1736 * (custom environment) 1737 * PATH=/sbin:/bin:/usr/sbin:/usr/bin:/usr/local/sbin:/usr/local/bin 1738 * UNAME_s=DragonFly (example) 1739 * UNAME_v=DragonFly 5.7-SYNTH (example) 1740 * UNAME_p=x86_64 (example) 1741 * UNAME_m=x86_64 (example) 1742 * UNAME_r=5.7-SYNTH (example) 1743 * NO_DEPENDS=yes (conditional based on phase) 1744 * DISTDIR=/distfiles 1745 * WRKDIRPREFIX=/construction 1746 * BATCH=yes 1747 * MAKE_JOBS_NUMBER=n 1748 * 1749 * SETUP: 1750 * ldconfig -R 1751 * /usr/local/sbin/pkg-static install /packages/All/<the pkg pkg> 1752 * /usr/local/sbin/pkg-static install /packages/All/<pkg> 1753 * (for all dependencies) 1754 * 1755 * PHASES: make -C path FLAVOR=flavor <phase> 1756 * check-sanity 1757 * pkg-depends 1758 * fetch-depends 1759 * fetch 1760 * checksum 1761 * extract-depends 1762 * extract 1763 * patch-depends 1764 * patch 1765 * build-depends 1766 * lib-depends 1767 * configure 1768 * build 1769 * run-depends 1770 * stage 1771 * test (skipped) 1772 * check-plist ('dsynth test blahblah' or 'dsynth -D everything' only) 1773 * package e.g. /construction/lang/perl5.28/pkg/perl5-5.28.2.txz 1774 * install-mtree (skipped) 1775 * install (skipped) 1776 * deinstall (skipped) 1777 */ 1778 void 1779 WorkerProcess(int ac, char **av) 1780 { 1781 wmsg_t wmsg; 1782 int fd; 1783 int slot; 1784 int tmpfd; 1785 int pkgpkg = 0; 1786 int status; 1787 int len; 1788 int do_install_phase; 1789 char *portdir; 1790 char *pkgfile; 1791 char *flavor; 1792 char *buf; 1793 worker_t *work; 1794 bulk_t *bulk; 1795 pkg_t pkg; 1796 buildenv_t *benv; 1797 FILE *fp; 1798 1799 /* 1800 * Parse arguments 1801 */ 1802 if (ac != 6) { 1803 dlog(DLOG_ALL, "WORKER PROCESS %d- bad arguments\n", getpid()); 1804 exit(1); 1805 } 1806 slot = strtol(av[1], NULL, 0); 1807 fd = strtol(av[2], NULL, 0); /* master<->slave messaging */ 1808 portdir = av[3]; 1809 pkgfile = av[4]; 1810 flavor = strchr(portdir, '@'); 1811 if (flavor) { 1812 *flavor++ = 0; 1813 asprintf(&buf, "@%s", flavor); 1814 WorkerFlavorPrt = buf; 1815 buf = NULL; /* safety */ 1816 } 1817 WorkerProcFlags = strtol(av[5], NULL, 0); 1818 1819 bzero(&wmsg, sizeof(wmsg)); 1820 1821 setproctitle("[%02d] WORKER STARTUP %s%s", 1822 slot, portdir, WorkerFlavorPrt); 1823 1824 if (strcmp(portdir, "ports-mgmt/pkg") == 0) 1825 pkgpkg = 1; 1826 1827 signal(SIGTERM, phaseTerminateSignal); 1828 signal(SIGINT, phaseTerminateSignal); 1829 signal(SIGHUP, phaseTerminateSignal); 1830 1831 /* 1832 * Set up the environment 1833 */ 1834 setenv("TERM", "dumb", 1); 1835 setenv("USER", "root", 1); 1836 setenv("HOME", "/root", 1); 1837 setenv("LANG", "C", 1); 1838 setenv("SSL_NO_VERIFY_PEER", "1", 1); 1839 1840 addbuildenv("USE_PACKAGE_DEPENDS_ONLY", "yes", BENV_MAKECONF); 1841 addbuildenv("PORTSDIR", "/xports", BENV_MAKECONF); 1842 addbuildenv("PORT_DBDIR", "/options", BENV_MAKECONF); 1843 addbuildenv("PKG_DBDIR", "/var/db/pkg", BENV_MAKECONF); 1844 addbuildenv("PKG_CACHEDIR", "/var/cache/pkg", BENV_MAKECONF); 1845 addbuildenv("PKG_SUFX", UsePkgSufx, BENV_MAKECONF); 1846 if (WorkerProcFlags & WORKER_PROC_DEVELOPER) 1847 addbuildenv("DEVELOPER", "1", BENV_MAKECONF); 1848 1849 /* 1850 * CCache is a horrible unreliable hack but... leave the 1851 * mechanism in-place in case someone has a death wish. 1852 */ 1853 if (UseCCache) { 1854 addbuildenv("WITH_CCACHE_BUILD", "yes", BENV_MAKECONF); 1855 addbuildenv("CCACHE_DIR", "/ccache", BENV_MAKECONF); 1856 } 1857 1858 addbuildenv("UID", "0", BENV_MAKECONF); 1859 addbuildenv("ARCH", ArchitectureName, BENV_MAKECONF); 1860 1861 #ifdef __DragonFly__ 1862 addbuildenv("OPSYS", "DragonFly", BENV_MAKECONF); 1863 addbuildenv("DFLYVERSION", VersionFromParamHeader, BENV_MAKECONF); 1864 addbuildenv("OSVERSION", "9999999", BENV_MAKECONF); 1865 #else 1866 #error "Need OS-specific data to generate make.conf" 1867 #endif 1868 1869 addbuildenv("OSREL", ReleaseName, BENV_MAKECONF); 1870 addbuildenv("_OSRELEASE", VersionOnlyName, BENV_MAKECONF); 1871 1872 setenv("PATH", 1873 "/sbin:/bin:/usr/sbin:/usr/bin:/usr/local/sbin:/usr/local/bin", 1874 1); 1875 1876 setenv("UNAME_s", OperatingSystemName, 1); 1877 setenv("UNAME_v", VersionName, 1); 1878 setenv("UNAME_p", ArchitectureName, 1); 1879 setenv("UNAME_m", MachineName, 1); 1880 setenv("UNAME_r", ReleaseName, 1); 1881 1882 addbuildenv("DISTDIR", "/distfiles", BENV_MAKECONF); 1883 addbuildenv("WRKDIRPREFIX", "/construction", BENV_MAKECONF); 1884 addbuildenv("BATCH", "yes", BENV_MAKECONF); 1885 1886 /* 1887 * Special consideration 1888 * 1889 * PACKAGE_BUILDING - Disallow packaging ports which do not allow 1890 * for binary distribution. 1891 * 1892 * PKG_CREATE_VERBOSE - Ensure periodic output during the packaging 1893 * process to avoid a watchdog timeout. 1894 * 1895 */ 1896 addbuildenv("PACKAGE_BUILDING", "yes", BENV_MAKECONF); 1897 addbuildenv("PKG_CREATE_VERBOSE", "yes", BENV_MAKECONF); 1898 asprintf(&buf, "%d", MaxJobs); 1899 addbuildenv("MAKE_JOBS_NUMBER", buf, BENV_MAKECONF); 1900 freestrp(&buf); 1901 1902 if (flavor) 1903 setenv("FLAVOR", flavor, 1); 1904 1905 /* 1906 * Become the reaper 1907 */ 1908 if (procctl(P_PID, getpid(), PROC_REAP_ACQUIRE, NULL) < 0) 1909 dfatal_errno("procctl() - Cannot become reaper"); 1910 1911 /* 1912 * Initialize a worker structure 1913 */ 1914 DoInitBuild(slot); 1915 1916 bzero(&pkg, sizeof(pkg)); 1917 pkg.portdir = portdir; /* sans flavor */ 1918 pkg.pkgfile = pkgfile; 1919 if (strchr(portdir, '/')) 1920 len = strchr(portdir, '/') - portdir; 1921 else 1922 len = 0; 1923 1924 /* 1925 * Setup the logfile 1926 */ 1927 asprintf(&pkg.logfile, 1928 "%s/%*.*s___%s%s%s.log", 1929 LogsPath, len, len, portdir, 1930 ((portdir[len] == '/') ? portdir + len + 1 : portdir + len), 1931 (flavor ? "@" : ""), 1932 (flavor ? flavor : "")); 1933 tmpfd = open(pkg.logfile, O_RDWR|O_CREAT|O_TRUNC, 0666); 1934 if (tmpfd >= 0) { 1935 if (DebugOpt >= 2) { 1936 dlog(DLOG_ALL, "[%03d] %s LOGFILE %s\n", 1937 slot, pkg.portdir, pkg.logfile); 1938 } 1939 close(tmpfd); 1940 } else { 1941 dlog(DLOG_ALL, "[%03d] LOGFILE %s (create failed)\n", 1942 slot, pkg.logfile); 1943 } 1944 1945 /* 1946 * Setup the work structure. Because this is an exec'd sub-process, 1947 * there is only one work structure. 1948 */ 1949 work = &WorkerAry[0]; 1950 work->flavor = flavor; 1951 work->fds[0] = fd; 1952 work->pkg = &pkg; 1953 work->start_time = time(NULL); 1954 1955 /* 1956 * Do mounts 1957 */ 1958 SigWork = work; 1959 setproctitle("[%02d] WORKER MOUNTS %s%s", 1960 slot, portdir, WorkerFlavorPrt); 1961 DoWorkerMounts(work); 1962 1963 /* 1964 * Generate an /etc/make.conf in the build base 1965 */ 1966 asprintf(&buf, "%s/etc/make.conf", work->basedir); 1967 fp = fopen(buf, "w"); 1968 dassert_errno(fp, "Unable to create %s\n", buf); 1969 for (benv = BuildEnv; benv; benv = benv->next) { 1970 if (benv->type & BENV_PKGLIST) 1971 continue; 1972 if ((benv->type & BENV_CMDMASK) == BENV_MAKECONF) { 1973 if (DebugOpt >= 2) { 1974 dlog(DLOG_ALL, "[%03d] ENV %s=%s\n", 1975 slot, benv->label, benv->data); 1976 } 1977 fprintf(fp, "%s=%s\n", benv->label, benv->data); 1978 } 1979 } 1980 fclose(fp); 1981 freestrp(&buf); 1982 1983 /* 1984 * Set up our hooks 1985 */ 1986 if (UsingHooks) 1987 initbulk(childHookRun, MaxBulk); 1988 1989 /* 1990 * Start phases 1991 */ 1992 wmsg.cmd = WMSG_CMD_INSTALL_PKGS; 1993 ipcwritemsg(fd, &wmsg); 1994 status = ipcreadmsg(fd, &wmsg); 1995 if (status < 0 || wmsg.cmd != WMSG_RES_INSTALL_PKGS) 1996 dfatal("pkg installation handshake failed"); 1997 do_install_phase = wmsg.status; 1998 1999 wmsg.cmd = WMSG_CMD_STATUS_UPDATE; 2000 wmsg.phase = PHASE_INSTALL_PKGS; 2001 wmsg.lines = 0; 2002 2003 status = ipcwritemsg(fd, &wmsg); 2004 2005 if (pkgpkg) { 2006 dophase(work, &wmsg, 2007 WDOG5, PHASE_PACKAGE, "package"); 2008 } else { 2009 if (do_install_phase) { 2010 dophase(work, &wmsg, 2011 WDOG4, PHASE_INSTALL_PKGS, "setup"); 2012 } 2013 dophase(work, &wmsg, 2014 WDOG2, PHASE_CHECK_SANITY, "check-sanity"); 2015 dophase(work, &wmsg, 2016 WDOG2, PHASE_PKG_DEPENDS, "pkg-depends"); 2017 dophase(work, &wmsg, 2018 WDOG7, PHASE_FETCH_DEPENDS, "fetch-depends"); 2019 dophase(work, &wmsg, 2020 WDOG7, PHASE_FETCH, "fetch"); 2021 dophase(work, &wmsg, 2022 WDOG2, PHASE_CHECKSUM, "checksum"); 2023 dophase(work, &wmsg, 2024 WDOG3, PHASE_EXTRACT_DEPENDS, "extract-depends"); 2025 dophase(work, &wmsg, 2026 WDOG3, PHASE_EXTRACT, "extract"); 2027 dophase(work, &wmsg, 2028 WDOG2, PHASE_PATCH_DEPENDS, "patch-depends"); 2029 dophase(work, &wmsg, 2030 WDOG2, PHASE_PATCH, "patch"); 2031 dophase(work, &wmsg, 2032 WDOG5, PHASE_BUILD_DEPENDS, "build-depends"); 2033 dophase(work, &wmsg, 2034 WDOG5, PHASE_LIB_DEPENDS, "lib-depends"); 2035 dophase(work, &wmsg, 2036 WDOG3, PHASE_CONFIGURE, "configure"); 2037 dophase(work, &wmsg, 2038 WDOG9, PHASE_BUILD, "build"); 2039 dophase(work, &wmsg, 2040 WDOG5, PHASE_RUN_DEPENDS, "run-depends"); 2041 dophase(work, &wmsg, 2042 WDOG5, PHASE_STAGE, "stage"); 2043 #if 0 2044 dophase(work, &wmsg, 2045 WDOG5, PHASE_TEST, "test"); 2046 #endif 2047 if (WorkerProcFlags & WORKER_PROC_CHECK_PLIST) { 2048 dophase(work, &wmsg, 2049 WDOG1, PHASE_CHECK_PLIST, "check-plist"); 2050 } 2051 dophase(work, &wmsg, 2052 WDOG5, PHASE_PACKAGE, "package"); 2053 #if 0 2054 dophase(work, &wmsg, 2055 WDOG5, PHASE_INSTALL_MTREE, "install-mtree"); 2056 dophase(work, &wmsg, 2057 WDOG5, PHASE_INSTALL, "install"); 2058 dophase(work, &wmsg, 2059 WDOG5, PHASE_DEINSTALL, "deinstall"); 2060 #endif 2061 } 2062 2063 if (MasterPtyFd >= 0) { 2064 close(MasterPtyFd); 2065 MasterPtyFd = -1; 2066 } 2067 2068 setproctitle("[%02d] WORKER CLEANUP %s%s", 2069 slot, portdir, WorkerFlavorPrt); 2070 2071 /* 2072 * Copy the package to the repo. 2073 */ 2074 if (work->accum_error == 0) { 2075 char *b1; 2076 char *b2; 2077 2078 asprintf(&b1, "%s/construction/%s/pkg/%s", 2079 work->basedir, pkg.portdir, pkg.pkgfile); 2080 asprintf(&b2, "%s/%s", RepositoryPath, pkg.pkgfile); 2081 if (copyfile(b1, b2)) { 2082 ++work->accum_error; 2083 dlog(DLOG_ALL, "[%03d] %s Unable to copy %s to %s\n", 2084 work->index, pkg.portdir, b1, b2); 2085 } 2086 free(b1); 2087 free(b2); 2088 } 2089 2090 /* 2091 * Unmount, unless we are in DebugStopMode. 2092 */ 2093 if ((WorkerProcFlags & WORKER_PROC_DEBUGSTOP) == 0) 2094 DoWorkerUnmounts(work); 2095 2096 /* 2097 * Send completion status to master dsynth worker thread. 2098 */ 2099 if (work->accum_error) { 2100 wmsg.cmd = WMSG_CMD_FAILURE; 2101 } else { 2102 wmsg.cmd = WMSG_CMD_SUCCESS; 2103 } 2104 ipcwritemsg(fd, &wmsg); 2105 if (WorkerProcFlags & WORKER_PROC_DEBUGSTOP) { 2106 wmsg.cmd = WMSG_CMD_FREEZEWORKER; 2107 ipcwritemsg(fd, &wmsg); 2108 } 2109 if (UsingHooks) { 2110 while ((bulk = getbulk()) != NULL) 2111 freebulk(bulk); 2112 donebulk(); 2113 } 2114 } 2115 2116 static void 2117 dophase(worker_t *work, wmsg_t *wmsg, int wdog, int phaseid, const char *phase) 2118 { 2119 pkg_t *pkg = work->pkg; 2120 char buf[1024]; 2121 pid_t pid; 2122 int status; 2123 int ms; 2124 pid_t wpid; 2125 int wpid_reaped; 2126 int fdlog; 2127 time_t start_time; 2128 time_t last_time; 2129 time_t next_time; 2130 time_t wdog_time; 2131 FILE *fp; 2132 2133 if (work->accum_error) 2134 return; 2135 setproctitle("[%02d] WORKER %-8.8s %s%s", 2136 work->index, phase, pkg->portdir, WorkerFlavorPrt); 2137 wmsg->phase = phaseid; 2138 if (ipcwritemsg(work->fds[0], wmsg) < 0) { 2139 dlog(DLOG_ALL, "[%03d] %s Lost Communication with dsynth, " 2140 "aborting worker\n", 2141 work->index, pkg->portdir); 2142 ++work->accum_error; 2143 return; 2144 } 2145 2146 /* 2147 * Execute the port make command in chroot on a pty. 2148 */ 2149 fflush(stdout); 2150 fflush(stderr); 2151 if (MasterPtyFd >= 0) { 2152 int slavefd; 2153 2154 /* 2155 * NOTE: We can't open the slave in the child because the 2156 * master may race a disconnection test. If we open 2157 * it in the parent our close() will flush any pending 2158 * output not read by the master (which is the same 2159 * parent process) and deadlock. 2160 * 2161 * Solve this by hand-shaking the slave tty to give 2162 * the master time to close its slavefd (after this 2163 * section). 2164 * 2165 * Leave the tty defaults intact, which also likely 2166 * means it will be in line-buffered mode, so handshake 2167 * with a full line. 2168 * 2169 * TODO: Our handshake probably echos back to the master pty 2170 * due to tty echo, and ends up in the log, so just 2171 * pass through a newline. 2172 */ 2173 slavefd = open(ptsname(MasterPtyFd), O_RDWR); 2174 dassert_errno(slavefd >= 0, "Cannot open slave pty"); 2175 2176 /* 2177 * Now do the fork. 2178 */ 2179 pid = fork(); 2180 if (pid == 0) { 2181 login_tty(slavefd); 2182 /* login_tty() closes slavefd */ 2183 } else { 2184 close(slavefd); 2185 } 2186 } else { 2187 /* 2188 * Initial MasterPtyFd for the slot, just use forkpty(). 2189 */ 2190 pid = forkpty(&MasterPtyFd, NULL, NULL, NULL); 2191 } 2192 2193 /* 2194 * The slave must make sure the master has time to close slavefd 2195 * in the re-use case before going its merry way. The master needs 2196 * to set terminal modes and the window as well. 2197 */ 2198 if (pid == 0) { 2199 /* 2200 * Slave waits for handshake 2201 */ 2202 char ttybuf[2]; 2203 2204 read(0, ttybuf, 1); 2205 } else { 2206 /* 2207 * We are going through a pty, so set the tty modes to 2208 * Set tty modes so we do not get ^M's in the log files. 2209 * 2210 * This isn't fatal if it doesn't work. Remember that 2211 * our output goes through the pty to the management 2212 * process which will log it. 2213 */ 2214 struct termios tio; 2215 struct winsize win; 2216 2217 if (tcgetattr(MasterPtyFd, &tio) == 0) { 2218 tio.c_oflag |= OPOST | ONOCR; 2219 tio.c_oflag &= ~(OCRNL | ONLCR); 2220 tio.c_iflag |= ICRNL; 2221 tio.c_iflag &= ~(INLCR | IGNCR); 2222 if (tcsetattr(MasterPtyFd, TCSANOW, &tio)) { 2223 printf("tcsetattr failed: %s\n", 2224 strerror(errno)); 2225 } 2226 2227 /* 2228 * Give the tty a non-zero columns field. 2229 * This fixes at least one port (textproc/po4a) 2230 */ 2231 if (ioctl(MasterPtyFd, TIOCGWINSZ, &win) == 0) { 2232 win.ws_col = 80; 2233 ioctl(MasterPtyFd, TIOCSWINSZ, &win); 2234 } else { 2235 printf("TIOCGWINSZ failed: %s\n", 2236 strerror(errno)); 2237 } 2238 2239 } else { 2240 printf("tcgetattr failed: %s\n", strerror(errno)); 2241 } 2242 2243 /* 2244 * Master issues handshake 2245 */ 2246 write(MasterPtyFd, "\n", 1); 2247 } 2248 2249 if (pid == 0) { 2250 /* 2251 * Additional phase-specific environment variables 2252 * 2253 * - Do not try to process missing depends outside of the 2254 * depends phases. Also relies on USE_PACKAGE_DEPENDS_ONLY 2255 * in the make.conf. 2256 */ 2257 switch(phaseid) { 2258 case PHASE_CHECK_SANITY: 2259 case PHASE_FETCH: 2260 case PHASE_CHECKSUM: 2261 case PHASE_EXTRACT: 2262 case PHASE_PATCH: 2263 case PHASE_CONFIGURE: 2264 case PHASE_STAGE: 2265 case PHASE_TEST: 2266 case PHASE_CHECK_PLIST: 2267 case PHASE_INSTALL_MTREE: 2268 case PHASE_INSTALL: 2269 case PHASE_DEINSTALL: 2270 break; 2271 case PHASE_PKG_DEPENDS: 2272 case PHASE_FETCH_DEPENDS: 2273 case PHASE_EXTRACT_DEPENDS: 2274 case PHASE_PATCH_DEPENDS: 2275 case PHASE_BUILD_DEPENDS: 2276 case PHASE_LIB_DEPENDS: 2277 case PHASE_RUN_DEPENDS: 2278 break; 2279 default: 2280 setenv("NO_DEPENDS", "1", 1); 2281 break; 2282 } 2283 2284 /* 2285 * Clean-up, chdir, and chroot. 2286 */ 2287 closefrom(3); 2288 if (chdir(work->basedir) < 0) 2289 dfatal_errno("chdir in phase initialization"); 2290 if (chroot(work->basedir) < 0) 2291 dfatal_errno("chroot in phase initialization"); 2292 2293 /* 2294 * We have a choice here on how to handle stdin (fd 0). 2295 * We can leave it connected to the pty in which case 2296 * the build will just block if it tries to ask a 2297 * question (and the watchdog will kill it, eventually), 2298 * or we can try to EOF the pty, or we can attach /dev/null 2299 * to descriptor 0. 2300 */ 2301 if (NullStdinOpt) { 2302 int fd; 2303 2304 fd = open("/dev/null", O_RDWR); 2305 dassert_errno(fd >= 0, "cannot open /dev/null"); 2306 if (fd != 0) { 2307 dup2(fd, 0); 2308 close(fd); 2309 } 2310 } 2311 2312 /* 2313 * Execute the appropriate command. 2314 */ 2315 switch(phaseid) { 2316 case PHASE_INSTALL_PKGS: 2317 snprintf(buf, sizeof(buf), "/tmp/dsynth_install_pkgs"); 2318 execl(buf, buf, NULL); 2319 break; 2320 default: 2321 snprintf(buf, sizeof(buf), "/xports/%s", pkg->portdir); 2322 execl(MAKE_BINARY, MAKE_BINARY, "-C", buf, phase, NULL); 2323 break; 2324 } 2325 _exit(1); 2326 } 2327 fcntl(MasterPtyFd, F_SETFL, O_NONBLOCK); 2328 2329 if (pid < 0) { 2330 dlog(DLOG_ALL, "[%03d] %s Fork Failed: %s\n", 2331 work->index, pkg->logfile, strerror(errno)); 2332 ++work->accum_error; 2333 return; 2334 } 2335 2336 SigPid = pid; 2337 2338 fdlog = open(pkg->logfile, O_RDWR|O_CREAT|O_APPEND, 0644); 2339 if (fdlog < 0) { 2340 dlog(DLOG_ALL, "[%03d] %s Cannot open logfile '%s': %s\n", 2341 work->index, pkg->portdir, 2342 pkg->logfile, strerror(errno)); 2343 } 2344 2345 snprintf(buf, sizeof(buf), 2346 "----------------------------------------" 2347 "---------------------------------------\n" 2348 "-- Phase: %s\n" 2349 "----------------------------------------" 2350 "---------------------------------------\n", 2351 phase); 2352 write(fdlog, buf, strlen(buf)); 2353 2354 start_time = time(NULL); 2355 last_time = start_time; 2356 wdog_time = start_time; 2357 wpid_reaped = 0; 2358 2359 status = 0; 2360 for (;;) { 2361 ms = mptylogpoll(MasterPtyFd, fdlog, wmsg, &wdog_time); 2362 if (ms == MPTY_FAILED) { 2363 dlog(DLOG_ALL, 2364 "[%03d] %s lost pty in phase %s, terminating\n", 2365 work->index, pkg->portdir, phase); 2366 break; 2367 } 2368 if (ms == MPTY_EOF) 2369 break; 2370 2371 /* 2372 * Generally speaking update status once a second. 2373 * This also allows us to detect if the management 2374 * dsynth process has gone away. 2375 */ 2376 next_time = time(NULL); 2377 if (next_time != last_time) { 2378 double dload[3]; 2379 double dv; 2380 int wdog_scaled; 2381 2382 /* 2383 * Send status update to the worker management thread 2384 * in the master dsynth process. Remember, *WE* are 2385 * the worker management process sub-fork. 2386 */ 2387 if (ipcwritemsg(work->fds[0], wmsg) < 0) 2388 break; 2389 last_time = next_time; 2390 2391 /* 2392 * Watchdog scaling 2393 */ 2394 getloadavg(dload, 3); 2395 adjloadavg(dload); 2396 dv = dload[2] / NumCores; 2397 if (dv < (double)NumCores) { 2398 wdog_scaled = wdog; 2399 } else { 2400 if (dv > 4.0 * NumCores) 2401 dv = 4.0 * NumCores; 2402 wdog_scaled = wdog * dv / NumCores; 2403 } 2404 2405 /* 2406 * Watchdog 2407 */ 2408 if (next_time - wdog_time >= wdog_scaled * 60) { 2409 snprintf(buf, sizeof(buf), 2410 "\n--------\n" 2411 "WATCHDOG TIMEOUT FOR %s in %s " 2412 "after %d minutes\n" 2413 "Killing pid %d\n" 2414 "--------\n", 2415 pkg->portdir, phase, wdog_scaled, pid); 2416 if (fdlog >= 0) 2417 write(fdlog, buf, strlen(buf)); 2418 dlog(DLOG_ALL, 2419 "[%03d] %s WATCHDOG TIMEOUT in %s " 2420 "after %d minutes (%d min scaled)\n", 2421 work->index, pkg->portdir, phase, 2422 wdog, wdog_scaled); 2423 kill(pid, SIGKILL); 2424 ++work->accum_error; 2425 break; 2426 } 2427 } 2428 2429 /* 2430 * Check process exit. Normally the pty will EOF 2431 * but if background processes remain we need to 2432 * check here to see if our primary exec is done, 2433 * so we can break out and reap those processes. 2434 * 2435 * Generally reap any other processes we have inherited 2436 * while we are here. 2437 */ 2438 do { 2439 wpid = wait3(&status, WNOHANG, NULL); 2440 } while (wpid > 0 && wpid != pid); 2441 if (wpid == pid && WIFEXITED(status)) { 2442 wpid_reaped = 1; 2443 break; 2444 } 2445 } 2446 2447 next_time = time(NULL); 2448 2449 setproctitle("[%02d] WORKER EXITREAP %s%s", 2450 work->index, pkg->portdir, WorkerFlavorPrt); 2451 2452 /* 2453 * We usually get here due to a mpty EOF, but not always as there 2454 * could be persistent processes still holding the slave. Finish 2455 * up getting the exit status for the main process we are waiting 2456 * on and clean out any data left on the MasterPtyFd (as it could 2457 * be blocking the exit). 2458 */ 2459 while (wpid_reaped == 0) { 2460 (void)mptylogpoll(MasterPtyFd, fdlog, wmsg, &wdog_time); 2461 wpid = waitpid(pid, &status, WNOHANG); 2462 if (wpid == pid && WIFEXITED(status)) { 2463 wpid_reaped = 1; 2464 break; 2465 } 2466 if (wpid < 0 && errno != EINTR) { 2467 break; 2468 } 2469 2470 /* 2471 * Safety. The normal phase waits until the fork/exec'd 2472 * pid finishes, causing a pty EOF on exit (the slave 2473 * descriptor is closed by the kernel on exit so the 2474 * process should already have exited). 2475 * 2476 * However, it is also possible to get here if the pty fails 2477 * for some reason. In this case, make sure that the process 2478 * is killed. 2479 */ 2480 kill(pid, SIGKILL); 2481 } 2482 2483 /* 2484 * Clean out anything left on the pty but don't wait around 2485 * because there could be background processes preventing the 2486 * slave side from closing. 2487 */ 2488 while (mptylogpoll(MasterPtyFd, fdlog, wmsg, &wdog_time) == MPTY_DATA) 2489 ; 2490 2491 /* 2492 * Report on the exit condition. If the pid was somehow lost 2493 * (probably due to someone gdb'ing the process), assume an error. 2494 */ 2495 if (wpid_reaped) { 2496 if (WEXITSTATUS(status)) { 2497 dlog(DLOG_ALL | DLOG_FILTER, 2498 "[%03d] %s Build phase '%s' failed exit %d\n", 2499 work->index, pkg->portdir, phase, 2500 WEXITSTATUS(status)); 2501 ++work->accum_error; 2502 } 2503 } else { 2504 dlog(DLOG_ALL, "[%03d] %s Build phase '%s' failed - lost pid\n", 2505 work->index, pkg->portdir, phase); 2506 ++work->accum_error; 2507 } 2508 2509 /* 2510 * Kill any processes still running (sometimes processes end up in 2511 * the background during a dports build), and clean up any other 2512 * children that we have inherited. 2513 */ 2514 phaseReapAll(); 2515 2516 /* 2517 * After the extraction phase add the space used by /construction 2518 * to the memory use. This helps us reduce the amount of paging 2519 * we do due to extremely large package extractions (languages, 2520 * chromium, etc). 2521 * 2522 * (dsynth already estimated the space used by the package deps 2523 * up front, but this will help us further). 2524 */ 2525 if (work->accum_error == 0 && phaseid == PHASE_EXTRACT) { 2526 struct statfs sfs; 2527 char *b1; 2528 2529 asprintf(&b1, "%s/construction", work->basedir); 2530 if (statfs(b1, &sfs) == 0) { 2531 wmsg->memuse = (sfs.f_blocks - sfs.f_bfree) * 2532 sfs.f_bsize; 2533 ipcwritemsg(work->fds[0], wmsg); 2534 } 2535 } 2536 2537 /* 2538 * Update log 2539 */ 2540 if (fdlog >= 0) { 2541 struct stat st; 2542 int h; 2543 int m; 2544 int s; 2545 2546 last_time = next_time - start_time; 2547 s = last_time % 60; 2548 m = last_time / 60 % 60; 2549 h = last_time / 3600; 2550 2551 fp = fdopen(fdlog, "a"); 2552 if (fp == NULL) { 2553 dlog(DLOG_ALL, "[%03d] %s Cannot fdopen fdlog: %s %d\n", 2554 work->index, pkg->portdir, 2555 strerror(errno), fstat(fdlog, &st)); 2556 close(fdlog); 2557 goto skip; 2558 } 2559 2560 fprintf(fp, "\n"); 2561 if (work->accum_error) { 2562 fprintf(fp, "FAILED %02d:%02d:%02d\n", h, m, s); 2563 } else { 2564 if (phaseid == PHASE_EXTRACT && wmsg->memuse) { 2565 fprintf(fp, "Extracted Memory Use: %6.2fM\n", 2566 wmsg->memuse / (1024.0 * 1024.0)); 2567 } 2568 fprintf(fp, "SUCCEEDED %02d:%02d:%02d\n", h, m, s); 2569 } 2570 last_time = next_time - work->start_time; 2571 s = last_time % 60; 2572 m = last_time / 60 % 60; 2573 h = last_time / 3600; 2574 if (phaseid == PHASE_PACKAGE) { 2575 fprintf(fp, "TOTAL TIME %02d:%02d:%02d\n", h, m, s); 2576 } 2577 fprintf(fp, "\n"); 2578 fclose(fp); 2579 skip: 2580 ; 2581 } 2582 2583 } 2584 2585 static void 2586 phaseReapAll(void) 2587 { 2588 struct reaper_status rs; 2589 int status; 2590 2591 while (procctl(P_PID, getpid(), PROC_REAP_STATUS, &rs) == 0) { 2592 if ((rs.flags & PROC_REAP_ACQUIRE) == 0) 2593 break; 2594 if (rs.pid_head < 0) 2595 break; 2596 if (kill(rs.pid_head, SIGKILL) == 0) { 2597 while (waitpid(rs.pid_head, &status, 0) < 0) 2598 ; 2599 } 2600 } 2601 while (wait3(&status, 0, NULL) > 0) 2602 ; 2603 } 2604 2605 static void 2606 phaseTerminateSignal(int sig __unused) 2607 { 2608 if (CopyFileFd >= 0) 2609 close(CopyFileFd); 2610 if (MasterPtyFd >= 0) 2611 close(MasterPtyFd); 2612 if (SigPid > 1) 2613 kill(SigPid, SIGKILL); 2614 phaseReapAll(); 2615 if (SigWork) 2616 DoWorkerUnmounts(SigWork); 2617 exit(1); 2618 } 2619 2620 static 2621 char * 2622 buildskipreason(pkglink_t *parent, pkg_t *pkg) 2623 { 2624 pkglink_t *link; 2625 pkg_t *scan; 2626 char *reason = NULL; 2627 char *ptr; 2628 size_t tot; 2629 size_t len; 2630 pkglink_t stack; 2631 2632 if ((pkg->flags & PKGF_NOBUILD_I) && pkg->ignore) 2633 asprintf(&reason, "%s ", pkg->ignore); 2634 2635 tot = 0; 2636 PKGLIST_FOREACH(link, &pkg->idepon_list) { 2637 #if 0 2638 if (link->dep_type > DEP_TYPE_BUILD) 2639 continue; 2640 #endif 2641 scan = link->pkg; 2642 if (scan == NULL) 2643 continue; 2644 if ((scan->flags & (PKGF_ERROR | PKGF_NOBUILD)) == 0) 2645 continue; 2646 if (scan->flags & PKGF_NOBUILD) { 2647 stack.pkg = scan; 2648 stack.next = parent; 2649 ptr = buildskipreason(&stack, scan); 2650 len = strlen(scan->portdir) + strlen(ptr) + 8; 2651 reason = realloc(reason, tot + len); 2652 snprintf(reason + tot, len, "%s->%s", 2653 scan->portdir, ptr); 2654 free(ptr); 2655 } else { 2656 len = strlen(scan->portdir) + 8; 2657 reason = realloc(reason, tot + len); 2658 snprintf(reason + tot, len, "%s", scan->portdir); 2659 } 2660 2661 /* 2662 * Don't try to print the entire graph 2663 */ 2664 if (parent) 2665 break; 2666 tot += strlen(reason + tot); 2667 reason[tot++] = ' '; 2668 reason[tot] = 0; 2669 } 2670 return (reason); 2671 } 2672 2673 /* 2674 * Count number of packages that would be skipped due to the 2675 * specified package having failed. 2676 * 2677 * Call with mode 1 to count, and mode 0 to clear the 2678 * cumulative rscan flag (used to de-duplicate the count). 2679 * 2680 * Must be serialized. 2681 */ 2682 static int 2683 buildskipcount_dueto(pkg_t *pkg, int mode) 2684 { 2685 pkglink_t *link; 2686 pkg_t *scan; 2687 int total; 2688 2689 total = 0; 2690 PKGLIST_FOREACH(link, &pkg->deponi_list) { 2691 scan = link->pkg; 2692 if (scan == NULL || scan->rscan == mode) 2693 continue; 2694 scan->rscan = mode; 2695 ++total; 2696 total += buildskipcount_dueto(scan, mode); 2697 } 2698 return total; 2699 } 2700 2701 /* 2702 * The master ptyfd is in non-blocking mode. Drain up to 1024 bytes 2703 * and update wmsg->lines and *wdog_timep as appropriate. 2704 * 2705 * This function will poll, stalling up to 1 second. 2706 */ 2707 static int 2708 mptylogpoll(int ptyfd, int fdlog, wmsg_t *wmsg, time_t *wdog_timep) 2709 { 2710 struct pollfd pfd; 2711 char buf[1024]; 2712 ssize_t r; 2713 2714 pfd.fd = ptyfd; 2715 pfd.events = POLLIN; 2716 pfd.revents = 0; 2717 2718 poll(&pfd, 1, 1000); 2719 if (pfd.revents) { 2720 r = read(ptyfd, buf, sizeof(buf)); 2721 if (r > 0) { 2722 *wdog_timep = time(NULL); 2723 if (r > 0 && fdlog >= 0) 2724 write(fdlog, buf, r); 2725 while (--r >= 0) { 2726 if (buf[r] == '\n') 2727 ++wmsg->lines; 2728 } 2729 return MPTY_DATA; 2730 } else if (r < 0) { 2731 if (errno != EINTR && errno != EAGAIN) 2732 return MPTY_FAILED; 2733 return MPTY_AGAIN; 2734 } else if (r == 0) { 2735 return MPTY_EOF; 2736 } 2737 } 2738 return MPTY_AGAIN; 2739 } 2740 2741 /* 2742 * Copy a (package) file from (src) to (dst), use an intermediate file and 2743 * rename to ensure that interruption does not leave us with a corrupt 2744 * package file. 2745 * 2746 * This is called by the WORKER process. 2747 * 2748 * (dsynth management thread -> WORKER process -> sub-processes) 2749 */ 2750 #define COPYBLKSIZE 32768 2751 2752 int 2753 copyfile(char *src, char *dst) 2754 { 2755 char *tmp; 2756 char *buf; 2757 int fd1; 2758 int fd2; 2759 int error = 0; 2760 int mask; 2761 ssize_t r; 2762 2763 asprintf(&tmp, "%s.new", dst); 2764 buf = malloc(COPYBLKSIZE); 2765 2766 mask = sigsetmask(sigmask(SIGTERM)|sigmask(SIGINT)|sigmask(SIGHUP)); 2767 fd1 = open(src, O_RDONLY|O_CLOEXEC); 2768 fd2 = open(tmp, O_RDWR|O_CREAT|O_TRUNC|O_CLOEXEC, 0644); 2769 CopyFileFd = fd1; 2770 sigsetmask(mask); 2771 while ((r = read(fd1, buf, COPYBLKSIZE)) > 0) { 2772 if (write(fd2, buf, r) != r) 2773 error = 1; 2774 } 2775 if (r < 0) 2776 error = 1; 2777 mask = sigsetmask(sigmask(SIGTERM)|sigmask(SIGINT)|sigmask(SIGHUP)); 2778 CopyFileFd = -1; 2779 close(fd1); 2780 close(fd2); 2781 sigsetmask(mask); 2782 if (error) { 2783 remove(tmp); 2784 } else { 2785 if (rename(tmp, dst)) { 2786 error = 1; 2787 remove(tmp); 2788 } 2789 } 2790 2791 freestrp(&buf); 2792 freestrp(&tmp); 2793 2794 return error; 2795 } 2796 2797 /* 2798 * doHook() 2799 * 2800 * primary process (threaded) - run_start, run_end, pkg_ignored, pkg_skipped 2801 * worker process (threaded) - pkg_sucess, pkg_failure 2802 * 2803 * If waitfor is non-zero this hook will be serialized. 2804 */ 2805 static void 2806 doHook(pkg_t *pkg, const char *id, const char *path, int waitfor) 2807 { 2808 if (path == NULL) 2809 return; 2810 while (waitfor && getbulk() != NULL) 2811 ; 2812 if (pkg) 2813 queuebulk(pkg->portdir, id, path, pkg->pkgfile); 2814 else 2815 queuebulk(NULL, id, path, NULL); 2816 while (waitfor && getbulk() != NULL) 2817 ; 2818 } 2819 2820 /* 2821 * Execute hook (backend) 2822 * 2823 * s1 - portdir 2824 * s2 - id 2825 * s3 - script path 2826 * s4 - pkgfile (if applicable) 2827 */ 2828 static void 2829 childHookRun(bulk_t *bulk) 2830 { 2831 const char *cav[MAXCAC]; 2832 buildenv_t benv[MAXCAC]; 2833 char buf1[128]; 2834 char buf2[128]; 2835 char buf3[128]; 2836 char buf4[128]; 2837 FILE *fp; 2838 char *ptr; 2839 size_t len; 2840 pid_t pid; 2841 int cac; 2842 int bi; 2843 2844 cac = 0; 2845 bi = 0; 2846 bzero(benv, sizeof(benv)); 2847 2848 cav[cac++] = bulk->s3; 2849 2850 benv[bi].label = "PROFILE"; 2851 benv[bi].data = Profile; 2852 ++bi; 2853 2854 benv[bi].label = "DIR_PACKAGES"; 2855 benv[bi].data = PackagesPath; 2856 ++bi; 2857 2858 benv[bi].label = "DIR_REPOSITORY"; 2859 benv[bi].data = RepositoryPath; 2860 ++bi; 2861 2862 benv[bi].label = "DIR_PORTS"; 2863 benv[bi].data = DPortsPath; 2864 ++bi; 2865 2866 benv[bi].label = "DIR_OPTIONS"; 2867 benv[bi].data = OptionsPath; 2868 ++bi; 2869 2870 benv[bi].label = "DIR_DISTFILES"; 2871 benv[bi].data = DistFilesPath; 2872 ++bi; 2873 2874 benv[bi].label = "DIR_LOGS"; 2875 benv[bi].data = LogsPath; 2876 ++bi; 2877 2878 benv[bi].label = "DIR_BUILDBASE"; 2879 benv[bi].data = BuildBase; 2880 ++bi; 2881 2882 if (strcmp(bulk->s2, "hook_run_start") == 0) { 2883 snprintf(buf1, sizeof(buf1), "%d", BuildTotal); 2884 benv[bi].label = "PORTS_QUEUED"; 2885 benv[bi].data = buf1; 2886 ++bi; 2887 } else if (strcmp(bulk->s2, "hook_run_end") == 0) { 2888 snprintf(buf1, sizeof(buf1), "%d", BuildSuccessCount); 2889 benv[bi].label = "PORTS_BUILT"; 2890 benv[bi].data = buf1; 2891 ++bi; 2892 snprintf(buf2, sizeof(buf2), "%d", BuildFailCount); 2893 benv[bi].label = "PORTS_FAILED"; 2894 benv[bi].data = buf2; 2895 ++bi; 2896 snprintf(buf3, sizeof(buf3), "%d", BuildIgnoreCount); 2897 benv[bi].label = "PORTS_IGNORED"; 2898 benv[bi].data = buf3; 2899 ++bi; 2900 snprintf(buf4, sizeof(buf4), "%d", BuildSkipCount); 2901 benv[bi].label = "PORTS_SKIPPED"; 2902 benv[bi].data = buf4; 2903 ++bi; 2904 } else { 2905 /* 2906 * success, failure, ignored, skipped 2907 */ 2908 benv[bi].label = "RESULT"; 2909 if (strcmp(bulk->s2, "hook_pkg_success") == 0) { 2910 benv[bi].data = "success"; 2911 } else if (strcmp(bulk->s2, "hook_pkg_failure") == 0) { 2912 benv[bi].data = "failure"; 2913 } else if (strcmp(bulk->s2, "hook_pkg_ignored") == 0) { 2914 benv[bi].data = "ignored"; 2915 } else if (strcmp(bulk->s2, "hook_pkg_skipped") == 0) { 2916 benv[bi].data = "skipped"; 2917 } else { 2918 dfatal("Unknown hook id: %s", bulk->s2); 2919 /* NOT REACHED */ 2920 } 2921 ++bi; 2922 2923 /* 2924 * For compatibility with synth: 2925 * 2926 * ORIGIN does not include any @flavor, thus it is suitable 2927 * for finding the actual port directory/subdirectory. 2928 * 2929 * FLAVOR is set to ORIGIN if there is no flavor, otherwise 2930 * it is set to only the flavor sans the '@'. 2931 */ 2932 if ((ptr = strchr(bulk->s1, '@')) != NULL) { 2933 snprintf(buf1, sizeof(buf1), "%*.*s", 2934 (int)(ptr - bulk->s1), 2935 (int)(ptr - bulk->s1), 2936 bulk->s1); 2937 benv[bi].label = "ORIGIN"; 2938 benv[bi].data = buf1; 2939 ++bi; 2940 benv[bi].label = "FLAVOR"; 2941 benv[bi].data = ptr + 1; 2942 ++bi; 2943 } else { 2944 benv[bi].label = "ORIGIN"; 2945 benv[bi].data = bulk->s1; 2946 ++bi; 2947 benv[bi].label = "FLAVOR"; 2948 benv[bi].data = bulk->s1; 2949 ++bi; 2950 } 2951 benv[bi].label = "PKGNAME"; 2952 benv[bi].data = bulk->s4; 2953 ++bi; 2954 } 2955 2956 benv[bi].label = NULL; 2957 benv[bi].data = NULL; 2958 2959 fp = dexec_open(cav, cac, &pid, benv, 0, 0); 2960 while ((ptr = fgetln(fp, &len)) != NULL) 2961 ; 2962 2963 if (dexec_close(fp, pid)) { 2964 dlog(DLOG_ALL, 2965 "[XXX] %s SCRIPT %s (%s)\n", 2966 bulk->s1, bulk->s2, bulk->s3); 2967 } 2968 } 2969 2970 /* 2971 * Adjusts dload[0] by adding in t_pw (processes waiting on page-fault). 2972 * We don't want load reductions due to e.g. thrashing to cause dsynth 2973 * to increase the dynamic limit because it thinks the load is low. 2974 * 2975 * This has a desirable property. If the system pager cannot keep up 2976 * with process demand t_pw will spike while loadavg will only drop 2977 * slowly, resulting in a high adjusted load calculation that causes 2978 * dsynth to quickly clamp-down the limit. If the condition alleviates, 2979 * the limit will then rise slowly again, possibly even before existing 2980 * jobs are retired to meet the clamp-down from the original spike. 2981 */ 2982 static void 2983 adjloadavg(double *dload) 2984 { 2985 #if defined(__DragonFly__) 2986 struct vmtotal total; 2987 size_t size; 2988 2989 size = sizeof(total); 2990 if (sysctlbyname("vm.vmtotal", &total, &size, NULL, 0) == 0) { 2991 dload[0] += (double)total.t_pw; 2992 } 2993 #else 2994 dload[0] += 0.0; /* just avoid compiler 'unused' warnings */ 2995 #endif 2996 } 2997