Changeset 3198 in kBuild for trunk/src/kmk/kmkbuiltin/kSubmit.c
- Timestamp:
- Mar 28, 2018 4:15:07 PM (7 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/kmk/kmkbuiltin/kSubmit.c
r3194 r3198 56 56 # include "../w32/winchildren.h" 57 57 # endif 58 # include "nt/nt_child_inject_standard_handles.h" 58 59 #endif 59 60 … … 69 70 #define KWORKER_PID_HASH(a_pid) ((size_t)(a_pid) % 61) 70 71 72 #define TUPLE(a_sz) a_sz, sizeof(a_sz) - 1 71 73 72 74 /********************************************************************************************************************************* … … 171 173 #endif 172 174 175 #ifdef KBUILD_OS_WINDOWS 176 /** Pointer to kernel32!SetThreadGroupAffinity. */ 177 static BOOL (WINAPI *g_pfnSetThreadGroupAffinity)(HANDLE, const GROUP_AFFINITY*, GROUP_AFFINITY *); 178 #endif 179 173 180 174 181 … … 287 294 return pWorker; 288 295 } 296 297 298 /** 299 * Calcs the path to the kWorker binary for the worker. 300 * 301 * @returns 302 * @param pCtx The command execution context. 303 * @param pWorker The worker (for its bitcount). 304 * @param pszExecutable The output buffer. 305 * @param cbExecutable The output buffer size. 306 */ 307 static int kSubmitCalcExecutablePath(PKMKBUILTINCTX pCtx, PWORKERINSTANCE pWorker, char *pszExecutable, size_t cbExecutable) 308 { 309 #if defined(KBUILD_OS_WINDOWS) || defined(KBUILD_OS_OS2) 310 static const char s_szWorkerName[] = "kWorker.exe"; 311 #else 312 static const char s_szWorkerName[] = "kWorker"; 313 #endif 314 const char *pszBinPath = get_kbuild_bin_path(); 315 size_t const cchBinPath = strlen(pszBinPath); 316 size_t cchExecutable; 317 if ( pWorker->cBits == g_cArchBits 318 ? cchBinPath + 1 + sizeof(s_szWorkerName) <= cbExecutable 319 : cchBinPath + 1 - sizeof(g_szArch) + sizeof(g_szAltArch) + sizeof(s_szWorkerName) <= cbExecutable ) 320 { 321 memcpy(pszExecutable, pszBinPath, cchBinPath); 322 cchExecutable = cchBinPath; 323 324 /* Replace the arch bin directory extension with the alternative one if requested. */ 325 if (pWorker->cBits != g_cArchBits) 326 { 327 if ( cchBinPath < sizeof(g_szArch) 328 || memcmp(&pszExecutable[cchBinPath - sizeof(g_szArch) + 1], g_szArch, sizeof(g_szArch) - 1) != 0) 329 return errx(pCtx, 1, "KBUILD_BIN_PATH does not end with main architecture (%s) as expected: %s", 330 pszBinPath, g_szArch); 331 cchExecutable -= sizeof(g_szArch) - 1; 332 memcpy(&pszExecutable[cchExecutable], g_szAltArch, sizeof(g_szAltArch) - 1); 333 cchExecutable += sizeof(g_szAltArch) - 1; 334 } 335 336 /* Append a slash and the worker name. */ 337 pszExecutable[cchExecutable++] = '/'; 338 memcpy(&pszExecutable[cchExecutable], s_szWorkerName, sizeof(s_szWorkerName)); 339 return 0; 340 } 341 return errx(pCtx, 1, "KBUILD_BIN_PATH is too long"); 342 } 343 344 345 #ifdef KBUILD_OS_WINDOWS 346 /** 347 * Calcs the UTF-16 path to the kWorker binary for the worker. 348 * 349 * @returns 350 * @param pCtx The command execution context. 351 * @param pWorker The worker (for its bitcount). 352 * @param pwszExecutable The output buffer. 353 * @param cwcExecutable The output buffer size. 354 */ 355 static int kSubmitCalcExecutablePathW(PKMKBUILTINCTX pCtx, PWORKERINSTANCE pWorker, wchar_t *pwszExecutable, size_t cwcExecutable) 356 { 357 char szExecutable[MAX_PATH]; 358 int rc = kSubmitCalcExecutablePath(pCtx, pWorker, szExecutable, sizeof(szExecutable)); 359 if (rc == 0) 360 { 361 int cwc = MultiByteToWideChar(CP_ACP, 0 /*fFlags*/, szExecutable, strlen(szExecutable) + 1, 362 pwszExecutable, cwcExecutable); 363 if (cwc > 0) 364 return 0; 365 return errx(pCtx, 1, "MultiByteToWideChar failed on '%s': %u", szExecutable, GetLastError()); 366 } 367 return rc; 368 } 369 #endif 289 370 290 371 … … 302 383 static int kSubmitSpawnWorker(PKMKBUILTINCTX pCtx, PWORKERINSTANCE pWorker, int cVerbosity) 303 384 { 304 #if defined(KBUILD_OS_WINDOWS) || defined(KBUILD_OS_OS2) 305 static const char s_szWorkerName[] = "kWorker.exe"; 385 int rc; 386 #ifdef KBUILD_OS_WINDOWS 387 wchar_t wszExecutable[MAX_PATH]; 306 388 #else 307 static const char s_szWorkerName[] = "kWorker";308 #endif309 const char *pszBinPath = get_kbuild_bin_path();310 size_t const cchBinPath = strlen(pszBinPath);311 size_t cchExectuable;312 size_t const cbExecutableBuf = GET_PATH_MAX;313 389 PATH_VAR(szExecutable); 314 #define TUPLE(a_sz) a_sz, sizeof(a_sz) - 1 390 #endif 391 392 /* 393 * Get the output path so it can be passed on as a volatile. 394 */ 395 const char *pszVarVolatile; 315 396 struct variable *pVarVolatile = lookup_variable(TUPLE("PATH_OUT")); 316 397 if (pVarVolatile) 317 { /* likely */ }398 pszVarVolatile = "PATH_OUT"; 318 399 else 319 400 { 320 401 pVarVolatile = lookup_variable(TUPLE("PATH_OUT_BASE")); 321 if (!pVarVolatile) 402 if (pVarVolatile) 403 pszVarVolatile = "PATH_OUT_BASE"; 404 else 322 405 warn(pCtx, "Neither PATH_OUT_BASE nor PATH_OUT was found."); 323 406 } 407 if (pVarVolatile && strchr(pVarVolatile->value, '"')) 408 return errx(pCtx, -1, "%s contains double quotes.", pszVarVolatile); 409 if (pVarVolatile && strlen(pVarVolatile->value) >= GET_PATH_MAX) 410 return errx(pCtx, -1, "%s is too long (max %u)", pszVarVolatile, GET_PATH_MAX); 324 411 325 412 /* 326 413 * Construct the executable path. 327 414 */ 328 if ( pWorker->cBits == g_cArchBits 329 ? cchBinPath + 1 + sizeof(s_szWorkerName) <= cbExecutableBuf 330 : cchBinPath + 1 - sizeof(g_szArch) + sizeof(g_szAltArch) + sizeof(s_szWorkerName) <= cbExecutableBuf ) 415 #ifdef KBUILD_OS_WINDOWS 416 rc = kSubmitCalcExecutablePathW(pCtx, pWorker, wszExecutable, K_ELEMENTS(wszExecutable)); 417 #else 418 rc = kSubmitCalcExecutablePath(pCtx, pWorker, szExecutable, GET_PATH_MAX); 419 #endif 420 if (rc == 0) 331 421 { 332 422 #ifdef KBUILD_OS_WINDOWS 333 423 static DWORD s_fDenyRemoteClients = ~(DWORD)0; 334 wchar_t wszPipeName[ 64];424 wchar_t wszPipeName[128]; 335 425 HANDLE hWorkerPipe; 336 426 SECURITY_ATTRIBUTES SecAttrs = { /*nLength:*/ sizeof(SecAttrs), /*pAttrs:*/ NULL, /*bInheritHandle:*/ TRUE }; 337 #else 338 int aiPair[2] = { -1, -1 }; 339 #endif 340 341 memcpy(szExecutable, pszBinPath, cchBinPath); 342 cchExectuable = cchBinPath; 343 344 /* Replace the arch bin directory extension with the alternative one if requested. */ 345 if (pWorker->cBits != g_cArchBits) 346 { 347 if ( cchBinPath < sizeof(g_szArch) 348 || memcmp(&szExecutable[cchBinPath - sizeof(g_szArch) + 1], g_szArch, sizeof(g_szArch) - 1) != 0) 349 return errx(pCtx, 1, "KBUILD_BIN_PATH does not end with main architecture (%s) as expected: %s", 350 pszBinPath, g_szArch); 351 cchExectuable -= sizeof(g_szArch) - 1; 352 memcpy(&szExecutable[cchExectuable], g_szAltArch, sizeof(g_szAltArch) - 1); 353 cchExectuable += sizeof(g_szAltArch) - 1; 354 } 355 356 /* Append a slash and the worker name. */ 357 szExecutable[cchExectuable++] = '/'; 358 memcpy(&szExecutable[cchExectuable], s_szWorkerName, sizeof(s_szWorkerName)); 359 360 #ifdef KBUILD_OS_WINDOWS 427 int iProcessorGroup = -1; /** @todo determine process group. */ 428 361 429 /* 362 430 * Create the bi-directional pipe. Worker end is marked inheritable, our end is not. … … 364 432 if (s_fDenyRemoteClients == ~(DWORD)0) 365 433 s_fDenyRemoteClients = GetVersion() >= 0x60000 ? PIPE_REJECT_REMOTE_CLIENTS : 0; 366 _snwprintf(wszPipeName, sizeof(wszPipeName), L"\\\\.\\pipe\\kmk-%u-kWorker-%u", getpid(), g_uWorkerSeqNo++); 434 _snwprintf(wszPipeName, sizeof(wszPipeName), L"\\\\.\\pipe\\kmk-%u-kWorker-%u-%u", 435 GetCurrentProcessId(), g_uWorkerSeqNo++, GetTickCount()); 367 436 hWorkerPipe = CreateNamedPipeW(wszPipeName, 368 437 PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED | FILE_FLAG_FIRST_PIPE_INSTANCE /* win2k sp2+ */, … … 388 457 if (pWorker->OverlappedRead.hEvent != NULL) 389 458 { 390 char szHandleArg[32]; 391 extern int process_priority; /* main.c */ 392 char szPriorityArg[32]; 393 const char *apszArgs[10]; 394 int cArgs = 0; 395 apszArgs[cArgs++] = szExecutable; 396 apszArgs[cArgs++] = "--pipe"; 397 _snprintf(szHandleArg, sizeof(szHandleArg), "%p", hWorkerPipe); 398 apszArgs[cArgs++] = szHandleArg; 399 if (pVarVolatile) 459 extern int process_priority; /* main.c */ 460 wchar_t wszCommandLine[MAX_PATH * 3]; 461 wchar_t *pwszDst = wszCommandLine; 462 size_t cwcDst = K_ELEMENTS(wszCommandLine); 463 int cwc; 464 DWORD fFlags; 465 STARTUPINFOW StartupInfo; 466 PROCESS_INFORMATION ProcInfo = { NULL, NULL, 0, 0 }; 467 468 /* 469 * Compose the command line. 470 */ 471 cwc = _snwprintf(pwszDst, cwcDst, L"\"%s\" ", wszExecutable); 472 assert(cwc > 0 && cwc < cwcDst); 473 pwszDst += cwc; 474 cwcDst -= cwc; 475 if (pVarVolatile && *pVarVolatile->value) 400 476 { 401 apszArgs[cArgs++] = "--volatile"; 402 apszArgs[cArgs++] = pVarVolatile->value; 477 char chEnd = strchr(pVarVolatile->value, '\0')[-1]; 478 if (chEnd == '\\') 479 cwc = _snwprintf(pwszDst, cwcDst, L" --volatile \"%S.\"", pVarVolatile->value); 480 else 481 cwc = _snwprintf(pwszDst, cwcDst, L" --volatile \"%S\"", pVarVolatile->value); 482 assert(cwc > 0 && cwc < cwcDst); 483 pwszDst += cwc; 484 cwcDst -= cwc; 403 485 } 404 if (process_priority != 0) 486 *pwszDst = '\0'; 487 488 /* 489 * Fill in the startup information. 490 */ 491 memset(&StartupInfo, 0, sizeof(StartupInfo)); 492 StartupInfo.cb = sizeof(StartupInfo); 493 GetStartupInfoW(&StartupInfo); 494 StartupInfo.dwFlags &= ~STARTF_USESTDHANDLES; 495 StartupInfo.lpReserved2 = NULL; 496 StartupInfo.cbReserved2 = 0; 497 498 /* 499 * Flags and such. 500 */ 501 fFlags = CREATE_SUSPENDED; 502 switch (process_priority) 405 503 { 406 apszArgs[cArgs++] = "--priority"; 407 _snprintf(szPriorityArg, sizeof(szPriorityArg), "%u", process_priority); 408 apszArgs[cArgs++] = szPriorityArg; 504 case 1: fFlags |= CREATE_SUSPENDED | IDLE_PRIORITY_CLASS; break; 505 case 2: fFlags |= CREATE_SUSPENDED | BELOW_NORMAL_PRIORITY_CLASS; break; 506 case 3: fFlags |= CREATE_SUSPENDED | NORMAL_PRIORITY_CLASS; break; 507 case 4: fFlags |= CREATE_SUSPENDED | HIGH_PRIORITY_CLASS; break; 508 case 5: fFlags |= CREATE_SUSPENDED | REALTIME_PRIORITY_CLASS; break; 409 509 } 410 apszArgs[cArgs] = NULL;411 510 412 511 /* 413 512 * Create the worker process. 414 513 */ 415 pWorker->hProcess = (HANDLE) _spawnve(_P_NOWAIT, szExecutable, apszArgs, environ); 416 if ((intptr_t)pWorker->hProcess != -1) 514 if (CreateProcessW(wszExecutable, wszCommandLine, NULL /*pProcSecAttr*/, NULL /*pThreadSecAttr*/, 515 FALSE /*fInheritHandles*/, fFlags, NULL /*pwszzEnvironment*/, 516 NULL /*pwszCwd*/, &StartupInfo, &ProcInfo)) 417 517 { 418 CloseHandle(hWorkerPipe); 419 pWorker->pid = GetProcessId(pWorker->hProcess); 420 if (cVerbosity > 0) 421 warnx(pCtx, "created %d bit worker %d\n", pWorker->cBits, pWorker->pid); 422 return 0; 518 char szErrMsg[256]; 519 BOOL afReplace[3] = { TRUE, FALSE, FALSE }; 520 HANDLE ahReplace[3] = { hWorkerPipe, INVALID_HANDLE_VALUE, INVALID_HANDLE_VALUE }; 521 rc = nt_child_inject_standard_handles(ProcInfo.hProcess, afReplace, ahReplace, szErrMsg, sizeof(szErrMsg)); 522 if (rc == 0) 523 { 524 BOOL fRet; 525 switch (process_priority) 526 { 527 case 1: fRet = SetThreadPriority(ProcInfo.hThread, THREAD_PRIORITY_IDLE); break; 528 case 2: fRet = SetThreadPriority(ProcInfo.hThread, THREAD_PRIORITY_BELOW_NORMAL); break; 529 case 3: fRet = SetThreadPriority(ProcInfo.hThread, THREAD_PRIORITY_NORMAL); break; 530 case 4: fRet = SetThreadPriority(ProcInfo.hThread, THREAD_PRIORITY_HIGHEST); break; 531 case 5: fRet = SetThreadPriority(ProcInfo.hThread, THREAD_PRIORITY_TIME_CRITICAL); break; 532 default: fRet = TRUE; 533 } 534 if (!fRet) 535 warnx(pCtx, "warning: failed to set kWorker thread priority: %u\n", GetLastError()); 536 537 if (iProcessorGroup >= 0) 538 { 539 GROUP_AFFINITY NewAff = { ~(uintptr_t)0, (WORD)iProcessorGroup, 0, 0, 0 }; 540 GROUP_AFFINITY OldAff = { 0, 0, 0, 0, 0 }; 541 if (!g_pfnSetThreadGroupAffinity(ProcInfo.hThread, &NewAff, &OldAff)) 542 warnx(pCtx, "warning: Failed to set processor group to %d: %u\n", 543 iProcessorGroup, GetLastError()); 544 } 545 546 /* 547 * Now, we just need to resume the thread. 548 */ 549 if (ResumeThread(ProcInfo.hThread)) 550 { 551 CloseHandle(hWorkerPipe); 552 CloseHandle(ProcInfo.hThread); 553 pWorker->pid = ProcInfo.dwProcessId; 554 pWorker->hProcess = ProcInfo.hProcess; 555 if (cVerbosity > 0) 556 warnx(pCtx, "created %d bit worker %d\n", pWorker->cBits, pWorker->pid); 557 return 0; 558 } 559 560 /* 561 * Failed, bail out. 562 */ 563 rc = errx(pCtx, -3, "ResumeThread failed: %u", GetLastError()); 564 } 565 else 566 rc = errx(pCtx, -3, "%s", szErrMsg); 567 TerminateProcess(ProcInfo.hProcess, 1234); 568 CloseHandle(ProcInfo.hThread); 569 CloseHandle(ProcInfo.hProcess); 423 570 } 424 err(pCtx, 1, "_spawnve(,%s,,)", szExecutable); 571 else 572 rc = errx(pCtx, -2, "CreateProcessW failed: %u (exe=%s cmdline=%s)", 573 GetLastError(), wszExecutable, wszCommandLine); 425 574 CloseHandle(pWorker->OverlappedRead.hEvent); 426 575 pWorker->OverlappedRead.hEvent = INVALID_HANDLE_VALUE; 427 576 } 428 577 else 429 errx(pCtx,1, "CreateEventW failed: %u", GetLastError());578 rc = errx(pCtx, -1, "CreateEventW failed: %u", GetLastError()); 430 579 CloseHandle(pWorker->hPipe); 431 580 pWorker->hPipe = INVALID_HANDLE_VALUE; 432 581 } 433 582 else 434 errx(pCtx,1, "Opening named pipe failed: %u", GetLastError());583 rc = errx(pCtx, -1, "Opening named pipe failed: %u", GetLastError()); 435 584 CloseHandle(hWorkerPipe); 436 585 } 437 586 else 438 errx(pCtx,1, "CreateNamedPipeW failed: %u", GetLastError());587 rc = errx(pCtx, -1, "CreateNamedPipeW failed: %u", GetLastError()); 439 588 440 589 #else … … 442 591 * Create a socket pair. 443 592 */ 593 int aiPair[2] = { -1, -1 }; 444 594 if (socketpair(AF_LOCAL, SOCK_STREAM, 0, aiPair) == 0) 595 { 445 596 pWorker->fdSocket = aiPair[1]; 597 598 rc = -1; 599 } 446 600 else 447 err(pCtx,1, "socketpair");601 rc = err(pCtx, -1, "socketpair"); 448 602 #endif 449 603 } 450 604 else 451 errx(pCtx,1, "KBUILD_BIN_PATH is too long");452 return -1;605 rc = errx(pCtx, -1, "KBUILD_BIN_PATH is too long"); 606 return rc; 453 607 } 454 608
Note:
See TracChangeset
for help on using the changeset viewer.