Changeset 3357
- Timestamp:
- Jun 5, 2020, 4:49:14 PM (5 years ago)
- Location:
- trunk/src/kmk
- Files:
-
- 2 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/kmk/main.c
r3353 r3357 424 424 /* --job-object-name=name */ 425 425 char *win_job_object_name = NULL; 426 427 /** --job-object-no-kill. */ 428 int win_job_object_no_kill = 0; 426 429 #endif 427 430 … … 563 566 N_("\ 564 567 --job-object=mode Windows job object mode:\n\ 565 root-kill = Root make instance only, kill all\n\ 566 process when root exits. (def)\n\ 567 root-nokill = Root make instance only.\n\ 568 No killing.\n\ 569 each-kill = Each make instances, kill all\n\ 570 children when an instance exits.\n\ 571 each-nokill = Each make instances, no killing.\n\ 572 none = No job objects.\n"), 568 login = Per login session (default).\n\ 569 root = Root make instance only.\n\ 570 each = Each make instances.\n\ 571 none = No job objects.\n"), 573 572 N_("\ 574 573 --job-object-name=name Name of windows job object to open or create.\n\ 575 The default name is 'kmk-job-obj-<date>Z<pid>'.\n"), 574 The default name depends on the level.\n"), 575 N_("\ 576 --job-object-no-kill Do not kill orphaned child processes when done.\n"), 576 577 #endif 577 578 NULL … … 664 665 #if defined (WINDOWS32) && defined (CONFIG_NEW_WIN_CHILDREN) 665 666 { CHAR_MAX+58, string, &win_job_object_mode, 1, 1, 1, 0, 0, "job-object" }, 666 { CHAR_MAX+59, string, &win_job_object_name, 667 { CHAR_MAX+59, string, &win_job_object_name, 1, 1, 1, 0, 0, 667 668 "job-object-name" }, 669 { CHAR_MAX+60, flag, &win_job_object_no_kill, 1, 1, 1, 0, 0, 670 "job-object-no-kill" }, 668 671 #endif 669 672 { 0, 0, 0, 0, 0, 0, 0, 0, 0 } … … 3760 3763 /* validate the job object mode value . */ 3761 3764 if (win_job_object_mode == NULL) 3762 win_job_object_mode = xstrdup ("root-kill");3765 win_job_object_mode = xstrdup ("login"); 3763 3766 else if ( strcmp (win_job_object_mode, "none") != 0 3764 && strcmp (win_job_object_mode, "root-kill") != 0 3765 && strcmp (win_job_object_mode, "root-nokill") != 0 3766 && strcmp (win_job_object_mode, "each-kill") != 0 3767 && strcmp (win_job_object_mode, "each-nokill") != 0) 3767 && strcmp (win_job_object_mode, "login") != 0 3768 && strcmp (win_job_object_mode, "root") != 0 3769 && strcmp (win_job_object_mode, "each") != 0) 3768 3770 OS (fatal, NILF, _("unknown job object mode '%s'"), win_job_object_mode); 3769 3771 #endif -
trunk/src/kmk/w32/winchildren.c
r3355 r3357 111 111 extern const char *win_job_object_mode; 112 112 extern const char *win_job_object_name; 113 extern int win_job_object_no_kill; 113 114 114 115 … … 378 379 #endif 379 380 381 /** The job object for this make instance, if we created/opened one. */ 382 static HANDLE g_hJob = NULL; 383 384 385 /********************************************************************************************************************************* 386 * Internal Functions * 387 *********************************************************************************************************************************/ 388 static void mkWinChildInitJobObjectAssociation(void); 380 389 381 390 #if K_ARCH_BITS == 32 && !defined(_InterlockedCompareExchangePointer) … … 487 496 488 497 /* 489 * Depending on the --job-object=mode value, we typically create a job 490 * object here if we're the root make instance. The job object is then 491 * typically configured to kill all remaining processes when the root make 492 * terminates, so that there aren't any stuck processes around messing up 493 * subsequent builds. This is very handy on build servers, provided of 494 * course that, there aren't parallel kmk instance that wants to share 495 * mspdbsrv.exe or something like that. 496 * 497 * If we're not in a -kill mode, the job object is pretty pointless for 498 * manual cleanup as the job object becomes invisible (or something) when 499 * the last handle to it closes, i.e. hJob below. On windows 8 and later 500 * it looks like any orphaned children are immediately assigned to the 501 * parent job object. Too bad for kmk_kill and such. 502 * 503 * win_job_object_mode values: none, root-kill, root-nokill, all-kill, all-nokill 504 */ 505 if ( strcmp(win_job_object_mode, "none") != 0 506 && ( makelevel == 0 507 || strstr(win_job_object_mode, "root") == NULL)) 508 { 509 HANDLE hJob = NULL; 510 BOOL fCreate = TRUE; 511 const char *pszJobName = win_job_object_name; 512 if (pszJobName) 513 { 514 /* Try open it first, in case it already exists. If it doesn't we'll try create it. */ 515 fCreate = FALSE; 516 hJob = OpenJobObjectA(JOB_OBJECT_ASSIGN_PROCESS, FALSE /*bInheritHandle*/, pszJobName); 517 if (hJob) 518 { 519 DWORD dwErr = GetLastError(); 520 if (dwErr == ERROR_PATH_NOT_FOUND || dwErr == ERROR_FILE_NOT_FOUND) 521 fCreate = TRUE; 522 else 523 OSN(message, 0, _("OpenJobObjectA(,,%s) failed: %u"), pszJobName, GetLastError()); 524 } 525 } 526 527 if (fCreate) 528 { 529 char szJobName[128]; 530 SYSTEMTIME Now = {0}; 531 GetSystemTime(&Now); 532 snprintf(szJobName, sizeof(szJobName) / 2, "kmk-job-obj-%04u-%02u-%02uT%02u-%02u-%02uZ%u", 533 Now.wYear, Now.wMonth, Now.wDay, Now.wHour, Now.wMinute, Now.wSecond, getpid()); 534 if (!pszJobName) 535 pszJobName = szJobName; 536 537 hJob = CreateJobObjectA(NULL, pszJobName); 538 if (hJob) 539 { 540 /* We need to set the BREAKAWAY_OK flag, as we don't want make CreateProcess fail if 541 someone tries to break way. Also set KILL_ON_JOB_CLOSE unless 'nokill' is given. */ 542 JOBOBJECT_EXTENDED_LIMIT_INFORMATION Info; 543 DWORD cbActual = 0; 544 memset(&Info, 0, sizeof(Info)); 545 if (QueryInformationJobObject(hJob, JobObjectExtendedLimitInformation, &Info, sizeof(Info), &cbActual)) 546 { 547 Info.BasicLimitInformation.LimitFlags |= JOB_OBJECT_LIMIT_BREAKAWAY_OK; 548 if (strstr(win_job_object_mode, "nokill") == NULL) 549 Info.BasicLimitInformation.LimitFlags |= JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE; 550 else 551 Info.BasicLimitInformation.LimitFlags &= ~JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE; 552 if (!SetInformationJobObject(hJob, JobObjectExtendedLimitInformation, &Info, sizeof(Info))) 553 OSSN(message, 0, _("SetInformationJobObject(%s,JobObjectExtendedLimitInformation,{%s},) failed: %u"), 554 pszJobName, win_job_object_mode, GetLastError()); 555 } 556 else 557 OSN(message, 0, _("QueryInformationJobObject(%s,JobObjectExtendedLimitInformation,,,) failed: %u"), 558 pszJobName, GetLastError()); 559 } 560 else 561 OSN(message, 0, _("CreateJobObjectA(NULL,%s) failed: %u"), pszJobName, GetLastError()); 562 } 563 564 if (hJob) 565 { 566 if (!(AssignProcessToJobObject(hJob, GetCurrentProcess()))) 567 OSN(message, 0, _("AssignProcessToJobObject(%s, me) failed: %u"), pszJobName, GetLastError()); 568 } 569 } 498 * Associate with a job object. 499 */ 500 mkWinChildInitJobObjectAssociation(); 570 501 571 502 /* … … 638 569 639 570 /** 571 * Create or open a job object for this make instance and its children. 572 * 573 * Depending on the --job-object=mode value, we typically create/open a job 574 * object here if we're the root make instance. The job object is then 575 * typically configured to kill all remaining processes when the root make 576 * terminates, so that there aren't any stuck processes around messing up 577 * subsequent builds. This is very handy on build servers. 578 * 579 * If we're it no-kill mode, the job object is pretty pointless for manual 580 * cleanup as the job object becomes invisible (or something) when the last 581 * handle to it closes, i.e. g_hJob. On windows 8 and later it looks 582 * like any orphaned children are immediately assigned to the parent job 583 * object. Too bad for kmk_kill and such. 584 * 585 * win_job_object_mode values: login, root, each, none 586 */ 587 static void mkWinChildInitJobObjectAssociation(void) 588 { 589 BOOL fCreate = TRUE; 590 char szJobName[128]; 591 const char *pszJobName = win_job_object_name; 592 593 /* Skip if disabled. */ 594 if (strcmp(win_job_object_mode, "none") == 0) 595 return; 596 597 /* Skip if not root make instance, unless we're having one job object 598 per make instance. */ 599 if ( makelevel != 0 600 && strcmp(win_job_object_mode, "each") != 0) 601 return; 602 603 /* Format the the default job object name if --job-object-name 604 wasn't given. */ 605 if (!pszJobName || *pszJobName == '\0') 606 { 607 pszJobName = szJobName; 608 if (strcmp(win_job_object_mode, "login") == 0) 609 { 610 /* Use the AuthenticationId like mspdbsrv.exe does. */ 611 HANDLE hToken; 612 if (OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &hToken)) 613 { 614 TOKEN_STATISTICS TokenStats; 615 DWORD cbRet = 0; 616 memset(&TokenStats, 0, sizeof(TokenStats)); 617 if (GetTokenInformation(hToken, TokenStatistics, &TokenStats, sizeof(TokenStats), &cbRet)) 618 snprintf(szJobName, sizeof(szJobName), "kmk-job-obj-login-%08x.%08x", 619 (unsigned)TokenStats.AuthenticationId.HighPart, (unsigned)TokenStats.AuthenticationId.LowPart); 620 else 621 { 622 ONN(message, 0, _("GetTokenInformation failed: %u (cbRet=%u)"), GetLastError(), cbRet); 623 return; 624 } 625 CloseHandle(hToken); 626 } 627 else 628 { 629 ON(message, 0, _("OpenProcessToken failed: %u"), GetLastError()); 630 return; 631 } 632 } 633 else 634 { 635 SYSTEMTIME Now = {0}; 636 GetSystemTime(&Now); 637 snprintf(szJobName, sizeof(szJobName), "kmk-job-obj-%04u-%02u-%02uT%02u-%02u-%02uZ%u", 638 Now.wYear, Now.wMonth, Now.wDay, Now.wHour, Now.wMinute, Now.wSecond, getpid()); 639 } 640 } 641 642 /* In login mode and when given a job object name, we try open it first. */ 643 if ( win_job_object_name 644 || strcmp(win_job_object_mode, "login") == 0) 645 { 646 g_hJob = OpenJobObjectA(JOB_OBJECT_ASSIGN_PROCESS, win_job_object_no_kill /*bInheritHandle*/, pszJobName); 647 if (g_hJob) 648 fCreate = FALSE; 649 else 650 { 651 DWORD dwErr = GetLastError(); 652 if (dwErr != ERROR_PATH_NOT_FOUND && dwErr != ERROR_FILE_NOT_FOUND) 653 { 654 OSN(message, 0, _("OpenJobObjectA(,,%s) failed: %u"), pszJobName, GetLastError()); 655 return; 656 } 657 } 658 } 659 660 if (fCreate) 661 { 662 SECURITY_ATTRIBUTES SecAttr = { sizeof(SecAttr), NULL, TRUE /*bInheritHandle*/ }; 663 g_hJob = CreateJobObjectA(win_job_object_no_kill ? &SecAttr : NULL, pszJobName); 664 if (g_hJob) 665 { 666 /* We need to set the BREAKAWAY_OK flag, as we don't want make CreateProcess 667 fail if someone tries to break way. Also set KILL_ON_JOB_CLOSE unless 668 --job-object-no-kill is given. */ 669 JOBOBJECT_EXTENDED_LIMIT_INFORMATION Info; 670 DWORD cbActual = 0; 671 memset(&Info, 0, sizeof(Info)); 672 if (QueryInformationJobObject(g_hJob, JobObjectExtendedLimitInformation, &Info, sizeof(Info), &cbActual)) 673 { 674 Info.BasicLimitInformation.LimitFlags |= JOB_OBJECT_LIMIT_BREAKAWAY_OK; 675 if (!win_job_object_no_kill) 676 Info.BasicLimitInformation.LimitFlags |= JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE; 677 else 678 Info.BasicLimitInformation.LimitFlags &= ~JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE; 679 if (!SetInformationJobObject(g_hJob, JobObjectExtendedLimitInformation, &Info, sizeof(Info))) 680 OSSN(message, 0, _("SetInformationJobObject(%s,JobObjectExtendedLimitInformation,{%s},) failed: %u"), 681 pszJobName, win_job_object_mode, GetLastError()); 682 } 683 else 684 OSN(message, 0, _("QueryInformationJobObject(%s,JobObjectExtendedLimitInformation,,,) failed: %u"), 685 pszJobName, GetLastError()); 686 } 687 else 688 { 689 OSN(message, 0, _("CreateJobObjectA(NULL,%s) failed: %u"), pszJobName, GetLastError()); 690 return; 691 } 692 } 693 694 /* Make it our job object. */ 695 if (!(AssignProcessToJobObject(g_hJob, GetCurrentProcess()))) 696 OSN(message, 0, _("AssignProcessToJobObject(%s, me) failed: %u"), pszJobName, GetLastError()); 697 } 698 699 /** 640 700 * Used by mkWinChildcareWorkerThread() and MkWinChildWait() to get the head 641 701 * child from a lifo (g_pTailCompletedChildren, pTailTodoChildren). … … 1155 1215 1156 1216 /** 1157 * Does the actual process creation given.1217 * Does the actual process creation. 1158 1218 * 1159 1219 * @returns 0 if there is anything to wait on, otherwise non-zero windows error. … … 1304 1364 assert(fRet); 1305 1365 #endif 1366 1367 /* 1368 * Inject the job object if we're in a non-killing mode, to postpone 1369 * the closing of the job object and maybe make it more useful. 1370 */ 1371 if (win_job_object_no_kill && g_hJob) 1372 { 1373 HANDLE hWhatever = INVALID_HANDLE_VALUE; 1374 DuplicateHandle(GetCurrentProcess(), g_hJob, ProcInfo.hProcess, &hWhatever, GENERIC_ALL, 1375 TRUE /*bInheritHandle*/, DUPLICATE_SAME_ACCESS); 1376 } 1306 1377 1307 1378 /* … … 3536 3607 3537 3608 /** 3538 * Emulate execv() for restarting kmk after one ore more makefiles has been 3539 * made. 3609 * Emulate execv() for restarting kmk after one or more makefiles has been made. 3540 3610 * 3541 3611 * Does not return.
Note:
See TracChangeset
for help on using the changeset viewer.