Changeset 3161 for trunk/src/kmk/w32
- Timestamp:
- Mar 19, 2018, 11:40:35 PM (7 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/kmk/w32/winchildren.c
r3159 r3161 76 76 77 77 #include <Windows.h> 78 #include <Winternl.h> 78 79 #include <assert.h> 79 80 #include <process.h> … … 270 271 /** Kernel32!SetThreadGroupAffinity */ 271 272 static BOOL (WINAPI *g_pfnSetThreadGroupAffinity)(HANDLE, CONST GROUP_AFFINITY *, GROUP_AFFINITY *); 273 /** NTDLL!NtQueryInformationProcess */ 274 static NTSTATUS (NTAPI *g_pfnNtQueryInformationProcess)(HANDLE, PROCESSINFOCLASS, PVOID, ULONG, PULONG); 275 /** Set if the windows host is 64-bit. */ 276 static BOOL g_f64BitHost = (K_ARCH_BITS == 64); 272 277 /** Windows version info. 273 278 * @note Putting this before the volatile stuff, hoping to keep it in a … … 289 294 static unsigned volatile g_idxLastChildcareWorker = 0; 290 295 291 /** TemporaryRW lock for serializing kmkbuiltin_redirect and CreateProcess. */296 /** RW lock for serializing kmkbuiltin_redirect and CreateProcess. */ 292 297 static SRWLOCK g_RWLock; 293 298 … … 301 306 void MkWinChildInit(unsigned int cJobSlots) 302 307 { 308 HMODULE hmod; 309 303 310 /* 304 311 * Figure out how many childcare workers first. … … 322 329 323 330 /* 331 * NTDLL imports that we need. 332 */ 333 hmod = GetModuleHandleA("NTDLL.DLL"); 334 *(FARPROC *)&g_pfnNtQueryInformationProcess = GetProcAddress(hmod, "NtQueryInformationProcess"); 335 if (!g_pfnNtQueryInformationProcess) 336 fatal(NILF, 0, _("MkWinChildInit: NtQueryInformationProcess not found")); 337 338 #if K_ARCH_BITS == 32 339 /* 340 * Initialize g_f64BitHost. 341 */ 342 if (!IsWow64Process(GetCurrentProcess(), &g_f64BitHost)) 343 fatal(NILF, INTSTR_LENGTH, _("MkWinChildInit: IsWow64Process failed: %u"), GetLastError()); 344 #elif K_ARCH_BITS == 64 345 assert(g_f64BitHost); 346 #else 347 # error "K_ARCH_BITS is bad/missing" 348 #endif 349 350 /* 324 351 * Figure out how many processor groups there are. 325 352 * For that we need to first figure the windows version. … … 334 361 if (g_VersionInfo.dwMajorVersion >= 6) 335 362 { 336 HMODULEhmod = GetModuleHandleA("KERNEL32.DLL");363 hmod = GetModuleHandleA("KERNEL32.DLL"); 337 364 *(FARPROC *)&g_pfnGetActiveProcessorGroupCount = GetProcAddress(hmod, "GetActiveProcessorGroupCount"); 338 365 *(FARPROC *)&g_pfnGetActiveProcessorCount = GetProcAddress(hmod, "GetActiveProcessorCount"); … … 365 392 } 366 393 367 /* Temporary: */ 394 /* 395 * For serializing with standard file handle manipulation (kmkbuiltin_redirect). 396 */ 368 397 InitializeSRWLock(&g_RWLock); 369 398 } … … 465 494 } 466 495 } 496 497 498 /** 499 * Does the actual process creation given. 500 * 501 * @returns 0 if there is anything to wait on, otherwise non-zero windows error. 502 * @param pWorker The childcare worker. 503 * @param pChild The child. 504 * @param pwszImageName The image path. 505 * @param pwszCommandLine The command line. 506 * @param pwszzEnvironment The enviornment block. 507 */ 508 static int mkWinChildcareWorkerCreateProcess(PWINCHILDCAREWORKER pWorker, PWINCHILD pChild, WCHAR const *pwszImageName, 509 WCHAR const *pwszCommandLine, WCHAR const *pwszzEnvironment) 510 { 511 PROCESS_INFORMATION ProcInfo; 512 STARTUPINFOW StartupInfo; 513 DWORD fFlags = CREATE_UNICODE_ENVIRONMENT; 514 BOOL const fHaveHandles = pChild->u.Process.hStdErr != INVALID_HANDLE_VALUE 515 || pChild->u.Process.hStdOut != INVALID_HANDLE_VALUE; 516 BOOL fRet; 517 DWORD dwErr; 518 #ifdef KMK 519 extern int process_priority; 520 #endif 521 522 /* 523 * Populate startup info. 524 * 525 * Turns out we can get away without passing TRUE for the inherit handles 526 * parameter to CreateProcess when we're not using STARTF_USESTDHANDLES. 527 * At least on NT, which is all worth caring about at this point + context IMO. 528 * 529 * Not inherting the handles is a good thing because it means we won't 530 * accidentally end up with a pipe handle or such intended for a different 531 * child process, potentially causing the EOF/HUP event to be delayed. 532 * 533 * Since the present handle inhertiance requirements only involves standard 534 * output and error, we'll never set the inherit handles flag and instead 535 * do manual handle duplication and planting. 536 */ 537 memset(&StartupInfo, 0, sizeof(StartupInfo)); 538 StartupInfo.cb = sizeof(StartupInfo); 539 GetStartupInfoW(&StartupInfo); 540 if (!fHaveHandles) 541 StartupInfo.dwFlags &= ~STARTF_USESTDHANDLES; 542 else 543 { 544 fFlags |= CREATE_SUSPENDED; 545 StartupInfo.dwFlags &= ~STARTF_USESTDHANDLES; 546 547 /* Don't pass CRT inheritance info to the child (from our parent actually). */ 548 StartupInfo.cbReserved2 = 0; 549 StartupInfo.lpReserved2 = 0; 550 } 551 552 /* 553 * Flags. 554 */ 555 #ifdef KMK 556 switch (process_priority) 557 { 558 case 1: fFlags |= CREATE_SUSPENDED | IDLE_PRIORITY_CLASS; break; 559 case 2: fFlags |= CREATE_SUSPENDED | BELOW_NORMAL_PRIORITY_CLASS; break; 560 case 3: fFlags |= CREATE_SUSPENDED | NORMAL_PRIORITY_CLASS; break; 561 case 4: fFlags |= CREATE_SUSPENDED | HIGH_PRIORITY_CLASS; break; 562 case 5: fFlags |= CREATE_SUSPENDED | REALTIME_PRIORITY_CLASS; break; 563 } 564 #endif 565 if (g_cProcessorGroups > 1) 566 fFlags |= CREATE_SUSPENDED; 567 568 /* 569 * Try create the process. 570 */ 571 DB(DB_JOBS, ("CreateProcessW(%ls, %ls,,, TRUE, %#x...)\n", pwszImageName, pwszCommandLine, fFlags)); 572 memset(&ProcInfo, 0, sizeof(ProcInfo)); 573 AcquireSRWLockShared(&g_RWLock); 574 575 fRet = CreateProcessW((WCHAR *)pwszImageName, (WCHAR *)pwszCommandLine, NULL /*pProcSecAttr*/, NULL /*pThreadSecAttr*/, 576 FALSE /*fInheritHandles*/, fFlags, (WCHAR *)pwszzEnvironment, NULL /*pwsz*/, &StartupInfo, &ProcInfo); 577 dwErr = GetLastError(); 578 579 ReleaseSRWLockShared(&g_RWLock); 580 if (fRet) 581 pChild->u.Process.hProcess = ProcInfo.hProcess; 582 else 583 { 584 fprintf(stderr, "CreateProcess(%ls) failed: %u\n", pwszImageName, dwErr); 585 return pChild->iExitCode = (int)dwErr; 586 } 587 588 /* 589 * If the child is suspended, we've got some adjustment work to be done. 590 */ 591 dwErr = ERROR_SUCCESS; 592 if (fFlags & CREATE_SUSPENDED) 593 { 594 /* 595 * First do handle inhertiance as that's the most complicated. 596 */ 597 if (fHaveHandles) 598 { 599 /* 600 * Get the PEB address and figure out the child process bit count. 601 */ 602 ULONG cbActual1 = 0; 603 PROCESS_BASIC_INFORMATION BasicInfo = { 0, 0, }; 604 NTSTATUS rcNt = g_pfnNtQueryInformationProcess(ProcInfo.hProcess, ProcessBasicInformation, 605 &BasicInfo, sizeof(BasicInfo), &cbActual1); 606 if (NT_SUCCESS(rcNt)) 607 { 608 /* 609 * Read the user process parameter pointer from the PEB. 610 * 611 * Note! Seems WOW64 processes starts out with a 64-bit PEB and 612 * process parameter block. 613 */ 614 BOOL const f32BitPeb = !g_f64BitHost; 615 ULONG const cbChildPtr = f32BitPeb ? 4 : 8; 616 PVOID pvSrcInPeb = (char *)BasicInfo.PebBaseAddress + (f32BitPeb ? 0x10 : 0x20); 617 char * pbDst = 0; 618 SIZE_T cbActual2 = 0; 619 if (ReadProcessMemory(ProcInfo.hProcess, pvSrcInPeb, &pbDst, cbChildPtr, &cbActual2)) 620 { 621 /* 622 * Duplicate the handles into the child. 623 */ 624 union 625 { 626 ULONGLONG au64Bit[2]; 627 ULONG au32Bit[2]; 628 } WriteBuf; 629 ULONG idx = 0; 630 HANDLE hChildStdOut = INVALID_HANDLE_VALUE; 631 HANDLE hChildStdErr = INVALID_HANDLE_VALUE; 632 633 pbDst += (f32BitPeb ? 0x1c : 0x28); 634 if (pChild->u.Process.hStdOut != INVALID_HANDLE_VALUE) 635 { 636 if (DuplicateHandle(GetCurrentProcess(), pChild->u.Process.hStdOut, ProcInfo.hProcess, 637 &hChildStdOut, 0, TRUE /*fInheritable*/, DUPLICATE_SAME_ACCESS)) 638 { 639 if (f32BitPeb) 640 WriteBuf.au32Bit[idx++] = (DWORD)(uintptr_t)hChildStdOut; 641 else 642 WriteBuf.au64Bit[idx++] = (uintptr_t)hChildStdOut; 643 } 644 else 645 { 646 dwErr = GetLastError(); 647 fprintf(stderr, "Failed to duplicate %p (stdout) into the child: %u\n", 648 pChild->u.Process.hStdOut, dwErr); 649 } 650 } 651 else 652 pbDst += cbChildPtr; 653 654 if (pChild->u.Process.hStdErr != INVALID_HANDLE_VALUE) 655 { 656 if (DuplicateHandle(GetCurrentProcess(), pChild->u.Process.hStdErr, ProcInfo.hProcess, 657 &hChildStdErr, 0, TRUE /*fInheritable*/, DUPLICATE_SAME_ACCESS)) 658 { 659 if (f32BitPeb) 660 WriteBuf.au32Bit[idx++] = (DWORD)(uintptr_t)hChildStdOut; 661 else 662 WriteBuf.au64Bit[idx++] = (uintptr_t)hChildStdOut; 663 } 664 else 665 { 666 dwErr = GetLastError(); 667 fprintf(stderr, "Failed to duplicate %p (stderr) into the child: %u\n", 668 pChild->u.Process.hStdOut, dwErr); 669 } 670 } 671 672 /* 673 * Finally write the handle values into the child. 674 */ 675 if ( idx > 0 676 && !WriteProcessMemory(ProcInfo.hProcess, pbDst, &WriteBuf, idx * cbChildPtr, &cbActual2)) 677 { 678 dwErr = GetLastError(); 679 fprintf(stderr, "Failed to write %p LB %u into child: %u\n", pbDst, idx * cbChildPtr, dwErr); 680 } 681 } 682 else 683 { 684 dwErr = GetLastError(); 685 fprintf(stderr, "Failed to read %p LB %u from the child: %u\n", pvSrcInPeb, cbChildPtr, dwErr); 686 } 687 } 688 else 689 { 690 fprintf(stderr, "NtQueryInformationProcess failed on child: %#x\n", rcNt); 691 dwErr = (DWORD)rcNt; 692 } 693 } 694 695 /* 696 * Assign processor group (ignore failure). 697 */ 698 if (g_cProcessorGroups > 1) 699 { 700 GROUP_AFFINITY Affinity = { ~(ULONG_PTR)0, pWorker->iProcessorGroup, { 0, 0, 0 } }; 701 fRet = g_pfnSetThreadGroupAffinity(ProcInfo.hThread, &Affinity, NULL); 702 assert(fRet); 703 } 704 705 #ifdef KMK 706 /* 707 * Set priority (ignore failure). 708 */ 709 switch (process_priority) 710 { 711 case 1: fRet = SetThreadPriority(ProcInfo.hThread, THREAD_PRIORITY_IDLE); break; 712 case 2: fRet = SetThreadPriority(ProcInfo.hThread, THREAD_PRIORITY_BELOW_NORMAL); break; 713 case 3: fRet = SetThreadPriority(ProcInfo.hThread, THREAD_PRIORITY_NORMAL); break; 714 case 4: fRet = SetThreadPriority(ProcInfo.hThread, THREAD_PRIORITY_HIGHEST); break; 715 case 5: fRet = SetThreadPriority(ProcInfo.hThread, THREAD_PRIORITY_TIME_CRITICAL); break; 716 default: fRet = TRUE; 717 } 718 assert(fRet); 719 #endif 720 721 /* 722 * Resume the thread if the adjustments succeeded, otherwise kill it. 723 */ 724 if (dwErr == ERROR_SUCCESS) 725 { 726 fRet = ResumeThread(ProcInfo.hThread); 727 assert(fRet); 728 if (!fRet) 729 { 730 dwErr = GetLastError(); 731 fprintf(stderr, "ResumeThread failed on child process: %u\n", dwErr); 732 } 733 } 734 if (dwErr != ERROR_SUCCESS) 735 TerminateProcess(ProcInfo.hProcess, dwErr); 736 } 737 738 /* 739 * Close unnecessary handles. 740 */ 741 if ( pChild->u.Process.fCloseStdOut 742 && pChild->u.Process.hStdOut != INVALID_HANDLE_VALUE) 743 { 744 CloseHandle(pChild->u.Process.hStdOut); 745 pChild->u.Process.hStdOut = INVALID_HANDLE_VALUE; 746 pChild->u.Process.fCloseStdOut = FALSE; 747 } 748 if ( pChild->u.Process.fCloseStdErr 749 && pChild->u.Process.hStdErr != INVALID_HANDLE_VALUE) 750 { 751 CloseHandle(pChild->u.Process.hStdErr); 752 pChild->u.Process.hStdErr = INVALID_HANDLE_VALUE; 753 pChild->u.Process.fCloseStdErr = FALSE; 754 } 755 756 CloseHandle(ProcInfo.hThread); 757 return 0; 758 } 759 467 760 468 761 #define MKWCCWCMD_F_CYGWIN_SHELL 1 … … 1215 1508 static void mkWinChildcareWorkerThreadHandleProcess(PWINCHILDCAREWORKER pWorker, PWINCHILD pChild) 1216 1509 { 1217 PROCESS_INFORMATION ProcInfo;1218 STARTUPINFOW StartupInfo;1219 1510 WCHAR const *pwszPath = NULL; 1220 1511 WCHAR *pwszzEnvironment = NULL; … … 1222 1513 WCHAR *pwszImageName = NULL; 1223 1514 BOOL fNeedShell = FALSE; 1224 DWORD fFlags = CREATE_UNICODE_ENVIRONMENT;1225 BOOL fRet;1226 1515 int rc; 1227 #ifdef KMK1228 extern int process_priority;1229 #endif1230 1516 1231 1517 /* … … 1249 1535 else 1250 1536 rc = mkWinChildcareWorkerConvertCommandlineWithShell(pwszImageName, pChild->u.Process.papszArgs, &pwszCommandLine); 1251 }1252 if (rc == 0)1253 {1254 AcquireSRWLockShared(&g_RWLock); /* temporary */1255 1537 1256 1538 /* 1257 * Populate startup info.1539 * Create the child process. 1258 1540 */ 1259 memset(&StartupInfo, 0, sizeof(StartupInfo)); 1260 StartupInfo.cb = sizeof(StartupInfo); 1261 GetStartupInfoW(&StartupInfo); 1262 if ( pChild->u.Process.hStdErr == INVALID_HANDLE_VALUE 1263 && pChild->u.Process.hStdOut == INVALID_HANDLE_VALUE) 1264 StartupInfo.dwFlags &= ~STARTF_USESTDHANDLES; 1265 else 1266 { 1267 StartupInfo.dwFlags |= STARTF_USESTDHANDLES; 1268 StartupInfo.hStdOutput = pChild->u.Process.hStdOut != INVALID_HANDLE_VALUE 1269 ? pChild->u.Process.hStdOut : GetStdHandle(STD_OUTPUT_HANDLE); 1270 StartupInfo.hStdError = pChild->u.Process.hStdErr != INVALID_HANDLE_VALUE 1271 ? pChild->u.Process.hStdErr : GetStdHandle(STD_ERROR_HANDLE); 1272 StartupInfo.hStdInput = GetStdHandle(STD_INPUT_HANDLE); 1273 } 1274 1275 /* 1276 * Flags. 1277 */ 1278 #ifdef KMK 1279 switch (process_priority) 1280 { 1281 case 1: fFlags |= CREATE_SUSPENDED | IDLE_PRIORITY_CLASS; break; 1282 case 2: fFlags |= CREATE_SUSPENDED | BELOW_NORMAL_PRIORITY_CLASS; break; 1283 case 3: fFlags |= CREATE_SUSPENDED | NORMAL_PRIORITY_CLASS; break; 1284 case 4: fFlags |= CREATE_SUSPENDED | HIGH_PRIORITY_CLASS; break; 1285 case 5: fFlags |= CREATE_SUSPENDED | REALTIME_PRIORITY_CLASS; break; 1286 } 1287 #endif 1288 if (g_cProcessorGroups > 1) 1289 fFlags |= CREATE_SUSPENDED; 1290 1291 /* 1292 * Try create the process. 1293 */ 1294 DB(DB_JOBS, ("CreateProcessW(%ls, %ls,,, TRUE, %#x...)\n", pwszImageName, pwszCommandLine, fFlags)); 1295 memset(&ProcInfo, 0, sizeof(ProcInfo)); 1296 fRet = CreateProcessW(pwszImageName, pwszCommandLine, NULL /*pProcSecAttr*/, NULL /*pThreadSecAttr*/, 1297 TRUE /*fInheritHandles*/, fFlags, pwszzEnvironment, NULL /*pwsz*/, &StartupInfo, &ProcInfo); 1298 rc = GetLastError(); 1299 ReleaseSRWLockShared(&g_RWLock); /* temporary */ 1300 if (fRet) 1301 { 1302 /* 1303 * Make thread priority and affinity changes if necessary. 1304 */ 1305 if (fFlags & CREATE_SUSPENDED) 1306 { 1307 BOOL fRet; 1308 if (g_cProcessorGroups > 1) 1309 { 1310 GROUP_AFFINITY Affinity = { ~(ULONG_PTR)0, pWorker->iProcessorGroup, { 0, 0, 0 } }; 1311 fRet = g_pfnSetThreadGroupAffinity(ProcInfo.hThread, &Affinity, NULL); 1312 assert(fRet); 1313 } 1314 #ifdef KMK 1315 switch (process_priority) 1316 { 1317 case 1: fRet = SetThreadPriority(ProcInfo.hThread, THREAD_PRIORITY_IDLE); break; 1318 case 2: fRet = SetThreadPriority(ProcInfo.hThread, THREAD_PRIORITY_BELOW_NORMAL); break; 1319 case 3: fRet = SetThreadPriority(ProcInfo.hThread, THREAD_PRIORITY_NORMAL); break; 1320 case 4: fRet = SetThreadPriority(ProcInfo.hThread, THREAD_PRIORITY_HIGHEST); break; 1321 case 5: fRet = SetThreadPriority(ProcInfo.hThread, THREAD_PRIORITY_TIME_CRITICAL); break; 1322 default: fRet = TRUE; 1323 } 1324 assert(fRet); 1325 #endif 1326 fRet = ResumeThread(ProcInfo.hThread); 1327 assert(fRet); 1328 (void)fRet; 1329 } 1330 1331 /* 1332 * Close unncessary handles. 1333 */ 1334 CloseHandle(ProcInfo.hThread); 1335 pChild->u.Process.hProcess = ProcInfo.hProcess; 1336 1337 if ( pChild->u.Process.fCloseStdOut 1338 && pChild->u.Process.hStdOut != INVALID_HANDLE_VALUE) 1339 { 1340 CloseHandle(pChild->u.Process.hStdOut); 1341 pChild->u.Process.hStdOut = INVALID_HANDLE_VALUE; 1342 pChild->u.Process.fCloseStdOut = FALSE; 1343 } 1344 if ( pChild->u.Process.fCloseStdErr 1345 && pChild->u.Process.hStdErr != INVALID_HANDLE_VALUE) 1346 { 1347 CloseHandle(pChild->u.Process.hStdErr); 1348 pChild->u.Process.hStdErr = INVALID_HANDLE_VALUE; 1349 pChild->u.Process.fCloseStdErr = FALSE; 1350 } 1351 1352 /* 1353 * Wait for the child to complete. 1354 */ 1355 mkWinChildcareWorkerWaitForProcess(pWorker, pChild, ProcInfo.hProcess); 1541 if (rc == 0) 1542 { 1543 rc = mkWinChildcareWorkerCreateProcess(pWorker, pChild, pwszImageName, pwszCommandLine, pwszzEnvironment); 1544 if (rc == 0) 1545 { 1546 /* 1547 * Wait for the child to complete. 1548 */ 1549 mkWinChildcareWorkerWaitForProcess(pWorker, pChild, pChild->u.Process.hProcess); 1550 } 1551 else 1552 pChild->iExitCode = rc; 1356 1553 } 1357 1554 else … … 1513 1710 pChild->pNext = pTailExpect; 1514 1711 pTailActual = _InterlockedCompareExchangePointer(&g_pTailCompletedChildren, pChild, pTailExpect); 1515 if (pTailActual == pTailExpect) 1712 if (pTailActual != pTailExpect) 1713 pTailExpect = pTailActual; 1714 else 1516 1715 { 1517 1716 _InterlockedDecrement(&g_cPendingChildren); … … 2205 2404 } 2206 2405 2207 /** Temporary serialization with kmkbuiltin_redirect. */2406 /** Serialization with kmkbuiltin_redirect. */ 2208 2407 void MkWinChildExclusiveAcquire(void) 2209 2408 { … … 2211 2410 } 2212 2411 2213 /** Temporary serialization with kmkbuiltin_redirect. */2412 /** Serialization with kmkbuiltin_redirect. */ 2214 2413 void MkWinChildExclusiveRelease(void) 2215 2414 {
Note:
See TracChangeset
for help on using the changeset viewer.