VirtualBox

Changeset 3198 in kBuild for trunk/src/kmk/kmkbuiltin/kSubmit.c


Ignore:
Timestamp:
Mar 28, 2018 4:15:07 PM (7 years ago)
Author:
bird
Message:

kmk/kSubmit,kWorker: Pass the pipe handle via RTL_USER_PROCESS_PARAMETERS::StandardInput instead of command line & inheritance. Replaces _spawnve with CreateProcessW and no automatic handle inherting, using nt_child_inject_standard_handles to do the job. The priority parameter is also obsolete now as kSubmit can set it.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/kmk/kmkbuiltin/kSubmit.c

    r3194 r3198  
    5656#  include "../w32/winchildren.h"
    5757# endif
     58# include "nt/nt_child_inject_standard_handles.h"
    5859#endif
    5960
     
    6970#define KWORKER_PID_HASH(a_pid) ((size_t)(a_pid) % 61)
    7071
     72#define TUPLE(a_sz)     a_sz, sizeof(a_sz) - 1
    7173
    7274/*********************************************************************************************************************************
     
    171173#endif
    172174
     175#ifdef KBUILD_OS_WINDOWS
     176/** Pointer to kernel32!SetThreadGroupAffinity. */
     177static BOOL (WINAPI *g_pfnSetThreadGroupAffinity)(HANDLE, const GROUP_AFFINITY*, GROUP_AFFINITY *);
     178#endif
     179
    173180
    174181
     
    287294    return pWorker;
    288295}
     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 */
     307static 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 */
     355static 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
    289370
    290371
     
    302383static int kSubmitSpawnWorker(PKMKBUILTINCTX pCtx, PWORKERINSTANCE pWorker, int cVerbosity)
    303384{
    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];
    306388#else
    307     static const char s_szWorkerName[] = "kWorker";
    308 #endif
    309     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;
    313389    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;
    315396    struct variable *pVarVolatile = lookup_variable(TUPLE("PATH_OUT"));
    316397    if (pVarVolatile)
    317     { /* likely */ }
     398        pszVarVolatile = "PATH_OUT";
    318399    else
    319400    {
    320401        pVarVolatile = lookup_variable(TUPLE("PATH_OUT_BASE"));
    321         if (!pVarVolatile)
     402        if (pVarVolatile)
     403            pszVarVolatile = "PATH_OUT_BASE";
     404        else
    322405            warn(pCtx, "Neither PATH_OUT_BASE nor PATH_OUT was found.");
    323406    }
     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);
    324411
    325412    /*
    326413     * Construct the executable path.
    327414     */
    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)
    331421    {
    332422#ifdef KBUILD_OS_WINDOWS
    333423        static DWORD        s_fDenyRemoteClients = ~(DWORD)0;
    334         wchar_t             wszPipeName[64];
     424        wchar_t             wszPipeName[128];
    335425        HANDLE              hWorkerPipe;
    336426        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
    361429        /*
    362430         * Create the bi-directional pipe.  Worker end is marked inheritable, our end is not.
     
    364432        if (s_fDenyRemoteClients == ~(DWORD)0)
    365433            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());
    367436        hWorkerPipe = CreateNamedPipeW(wszPipeName,
    368437                                       PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED | FILE_FLAG_FIRST_PIPE_INSTANCE /* win2k sp2+ */,
     
    388457                if (pWorker->OverlappedRead.hEvent != NULL)
    389458                {
    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)
    400476                    {
    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;
    403485                    }
    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)
    405503                    {
    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;
    409509                    }
    410                     apszArgs[cArgs] = NULL;
    411510
    412511                    /*
    413512                     * Create the worker process.
    414513                     */
    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))
    417517                    {
    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);
    423570                    }
    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);
    425574                    CloseHandle(pWorker->OverlappedRead.hEvent);
    426575                    pWorker->OverlappedRead.hEvent = INVALID_HANDLE_VALUE;
    427576                }
    428577                else
    429                     errx(pCtx, 1, "CreateEventW failed: %u", GetLastError());
     578                    rc = errx(pCtx, -1, "CreateEventW failed: %u", GetLastError());
    430579                CloseHandle(pWorker->hPipe);
    431580                pWorker->hPipe = INVALID_HANDLE_VALUE;
    432581            }
    433582            else
    434                 errx(pCtx, 1, "Opening named pipe failed: %u", GetLastError());
     583                rc = errx(pCtx, -1, "Opening named pipe failed: %u", GetLastError());
    435584            CloseHandle(hWorkerPipe);
    436585        }
    437586        else
    438             errx(pCtx, 1, "CreateNamedPipeW failed: %u", GetLastError());
     587            rc = errx(pCtx, -1, "CreateNamedPipeW failed: %u", GetLastError());
    439588
    440589#else
     
    442591         * Create a socket pair.
    443592         */
     593        int aiPair[2] = { -1, -1 };
    444594        if (socketpair(AF_LOCAL, SOCK_STREAM, 0, aiPair) == 0)
     595        {
    445596            pWorker->fdSocket = aiPair[1];
     597
     598            rc = -1;
     599        }
    446600        else
    447             err(pCtx, 1, "socketpair");
     601            rc = err(pCtx, -1, "socketpair");
    448602#endif
    449603    }
    450604    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;
    453607}
    454608
Note: See TracChangeset for help on using the changeset viewer.

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette