Changeset 3161 for trunk/src/kmk


Ignore:
Timestamp:
Mar 19, 2018, 11:40:35 PM (7 years ago)
Author:
bird
Message:

kmk/win: More child process work, focusing on making kmk_builtin_redirect not requiring the shared lock.

Location:
trunk/src/kmk
Files:
3 edited

Legend:

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

    r3159 r3161  
    3939#if defined(KBUILD_OS_WINDOWS) || defined(KBUILD_OS_OS2)
    4040# include <process.h>
     41#endif
     42#if defined(KBUILD_OS_WINDOWS) || defined(KBUILD_OS_OS2)
     43# include <Windows.h>
     44# include <Winternl.h>
    4145#endif
    4246#if defined(_MSC_VER)
     
    9195
    9296
     97/*********************************************************************************************************************************
     98*   Defined Constants And Macros                                                                                                 *
     99*********************************************************************************************************************************/
    93100/* String + strlen tuple. */
    94101#define TUPLE(a_sz)     a_sz, sizeof(a_sz) - 1
     102
     103/** Only standard handles on windows. */
     104#ifdef KBUILD_OS_WINDOWS
     105# define ONLY_TARGET_STANDARD_HANDLES
     106#endif
     107
    95108
    96109
     
    156169            "\n"
    157170            "The -d switch duplicate the right hand file descriptor (src-fd) to the left\n"
    158             "hand side one (fd).\n"
     171            "hand side one (fd). The latter is limited to standard handles on windows.\n"
    159172            "\n"
    160             "The -c switch will close the specified file descriptor.\n"
     173            "The -c switch will close the specified file descriptor. Limited to standard\n"
     174            "handles on windows.\n"
    161175            "\n"
    162176            "The -Z switch zaps the environment.\n"
     
    165179            "fashion.\n"
    166180            "\n"
    167             "The -C switch is for changing the current directory. This takes immediate\n"
    168             "effect, so be careful where you put it.\n"
     181            "The -C switch is for changing the current directory.  Please specify an\n"
     182            "absolute program path as it's platform dependent whether this takes effect\n"
     183            "before or after the executable is located.\n"
    169184            "\n"
    170185            "The --wcc-brain-damage switch is to work around wcc and wcc386 (Open Watcom)\n"
     
    439454        if (fdOpened >= 0)
    440455        {
     456#ifndef KBUILD_OS_WINDOWS
    441457            if (   !kRedirectHasConflict(fdOpened, cOrders, paOrders)
    442 #ifdef _MSC_VER
     458# ifdef _MSC_VER
    443459                && fdOpened != fdTarget
    444 #endif
     460# endif
    445461                )
     462#endif
    446463            {
    447464#ifndef _MSC_VER
     
    510527
    511528
    512 #ifndef USE_POSIX_SPAWN
     529#if !defined(USE_POSIX_SPAWN) && !defined(KBUILD_OS_WINDOWS)
    513530
    514531/**
     
    778795#endif /* !USE_POSIX_SPAWN */
    779796
     797#ifdef KBUILD_OS_WINDOWS
     798
     799/**
     800 * Tries to locate the executable image.
     801 *
     802 * This isn't quite perfect yet...
     803 *
     804 * @returns pszExecutable or pszBuf with valid string.
     805 * @param   pszExecutable   The specified executable.
     806 * @param   pszBuf          Buffer to return a modified path in.
     807 * @param   cbBuf           Size of return buffer.
     808 * @param   pszPath         The search path.
     809 */
     810static const char *kRedirectCreateProcessWindowsFindImage(const char *pszExecutable, char *pszBuf, size_t cbBuf,
     811                                                          const char *pszPath)
     812{
     813    /*
     814     * Analyze the name.
     815     */
     816    size_t const cchExecutable = strlen(pszExecutable);
     817    BOOL         fHavePath = FALSE;
     818    BOOL         fHaveSuffix = FALSE;
     819    size_t       off = cchExecutable;
     820    while (off > 0)
     821    {
     822        char ch = pszExecutable[--off];
     823        if (ch == '.')
     824        {
     825            fHaveSuffix = TRUE;
     826            break;
     827        }
     828        if (ch == '\\' || ch == '/' || ch == ':')
     829        {
     830            fHavePath = TRUE;
     831            break;
     832        }
     833    }
     834    if (!fHavePath)
     835        while (off > 0)
     836        {
     837            char ch = pszExecutable[--off];
     838            if (ch == '\\' || ch == '/' || ch == ':')
     839            {
     840                fHavePath = TRUE;
     841                break;
     842            }
     843        }
     844   /*
     845    * If no path, search the path value.
     846    */
     847   if (!fHavePath)
     848   {
     849       char *pszFilename;
     850       DWORD cchFound = SearchPathA(pszPath, pszExecutable, fHaveSuffix ? NULL : ".exe", cbBuf, pszBuf, &pszFilename);
     851       if (cchFound)
     852           return pszBuf;
     853   }
     854
     855   /*
     856    * If no suffix, try add .exe.
     857    */
     858   if (   !fHaveSuffix
     859       && GetFileAttributesA(pszExecutable) == INVALID_FILE_ATTRIBUTES
     860       && cchExecutable + 4 < cbBuf)
     861   {
     862       memcpy(pszBuf, pszExecutable, cchExecutable);
     863       memcpy(&pszBuf[cchExecutable], ".exe", 5);
     864       if (GetFileAttributesA(pszBuf) != INVALID_FILE_ATTRIBUTES)
     865           return pszBuf;
     866   }
     867
     868   return pszExecutable;
     869}
     870
     871/**
     872 * Alternative approach on windows that use CreateProcess and doesn't require
     873 * any serialization wrt handles and CWD.
     874 *
     875 * @returns 0 on success, non-zero on failure to create.
     876 * @param   pszExecutable       The child process executable.
     877 * @param   cArgs               Number of arguments.
     878 * @param   papszArgs           The child argument vector.
     879 * @param   papszEnvVars        The child environment vector.
     880 * @param   pszCwd              The current working directory of the child.
     881 * @param   cOrders             Number of file operation orders.
     882 * @param   paOrders            The file operation orders.
     883 * @param   phProcess           Where to return process handle.
     884 */
     885static kRedirectCreateProcessWindows(const char *pszExecutable, int cArgs, char **papszArgs, char **papszEnvVars,
     886                                     const char *pszCwd, unsigned cOrders, REDIRECTORDERS *paOrders, HANDLE *phProcess)
     887{
     888    static NTSTATUS (NTAPI *s_pfnNtQueryInformationProcess)(HANDLE, PROCESSINFOCLASS, PVOID, ULONG, PULONG) = NULL;
     889    size_t cbArgs;
     890    char  *pszCmdLine;
     891    size_t cbEnv;
     892    char  *pszzEnv;
     893    char  *pch;
     894    int    i;
     895    int    rc;
     896
     897    /*
     898     * Determin host bitness and APIs while we can still easily return.
     899     */
     900#if K_ARCH_BITS == 32
     901    BOOL   f64BitHost = TRUE;
     902    if (!IsWow64Process(GetCurrentProcess(), &f64BitHost))
     903        return errx(9, "IsWow64Process failed: %u", GetLastError());
     904#elif K_ARCH_BITS == 64
     905    BOOL const f64BitHost = TRUE;
     906#else
     907# error "K_ARCH_BITS is bad/missing"
     908#endif
     909    if (cOrders > 0 && !s_pfnNtQueryInformationProcess)
     910    {
     911        *(FARPROC *)&s_pfnNtQueryInformationProcess = GetProcAddress(GetModuleHandleA("NTDLL.DLL"), "NtQueryInformationProcess");
     912        if (!s_pfnNtQueryInformationProcess)
     913            return errx(9, "NtQueryInformationProcess not found!");
     914    }
     915
     916    /*
     917     * Start by making the the command line.  We just need to put spaces
     918     * between the arguments since quote_argv don't the quoting already.
     919     */
     920    cbArgs = 0;
     921    for (i = 0; i < cArgs; i++)
     922        cbArgs += strlen(papszArgs[i]) + 1;
     923    pszCmdLine = pch = (char *)malloc(cbArgs);
     924    if (!pszCmdLine)
     925        return errx(9, "out of memory!");
     926    for (i = 0; i < cArgs; i++)
     927    {
     928        size_t cch;
     929        if (i != 0)
     930            *pch++ = ' ';
     931        cch = strlen(papszArgs[i]);
     932        memcpy(pch, papszArgs[i], cch);
     933        pch += cch;
     934    }
     935    *pch++ = '\0';
     936    assert(pch - pszCmdLine == cbArgs);
     937
     938    /*
     939     * The environment vector is also simple.
     940     */
     941    cbEnv = 0;
     942    for (i = 0; papszEnvVars[i]; i++)
     943        cbEnv += strlen(papszEnvVars[i]) + 1;
     944    cbEnv++;
     945    pszzEnv = pch = (char *)malloc(cbEnv);
     946    if (pszzEnv)
     947    {
     948        char                szAbsExe[1024];
     949        const char         *pszPathVal = NULL;
     950        STARTUPINFOA        StartupInfo;
     951        PROCESS_INFORMATION ProcInfo = { NULL, NULL, 0, 0 };
     952
     953        for (i = 0; papszEnvVars[i]; i++)
     954        {
     955            size_t cbSrc = strlen(papszEnvVars[i]) + 1;
     956            memcpy(pch, papszEnvVars[i], cbSrc);
     957            if (   !pszPathVal
     958                && cbSrc >= 5
     959                && pch[4] == '='
     960                && (pch[0] == 'P' || pch[0] == 'p')
     961                && (pch[1] == 'A' || pch[1] == 'a')
     962                && (pch[2] == 'T' || pch[2] == 't')
     963                && (pch[3] == 'H' || pch[3] == 'h'))
     964                pszPathVal = &pch[5];
     965            pch += cbSrc;
     966        }
     967        *pch++ = '\0';
     968        assert(pch - pszzEnv == cbEnv);
     969
     970        /*
     971         * Locate the executable.
     972         */
     973        pszExecutable = kRedirectCreateProcessWindowsFindImage(pszExecutable, szAbsExe, sizeof(szAbsExe), pszPathVal);
     974
     975        /*
     976         * Do basic startup info preparation.
     977         */
     978        memset(&StartupInfo, 0, sizeof(StartupInfo));
     979        StartupInfo.cb = sizeof(StartupInfo);
     980        GetStartupInfoA(&StartupInfo);
     981        StartupInfo.dwFlags &= ~STARTF_USESTDHANDLES;
     982
     983        /*
     984         * If there are no redirection orders, we're good.
     985         */
     986        if (!cOrders)
     987        {
     988            if (CreateProcessA(pszExecutable, pszCmdLine, NULL /*pProcAttrs*/, NULL /*pThreadAttrs*/,
     989                               FALSE /*fInheritHandles*/, 0 /*fFlags*/, pszzEnv, pszCwd, &StartupInfo, &ProcInfo))
     990            {
     991                CloseHandle(ProcInfo.hThread);
     992                *phProcess = ProcInfo.hProcess;
     993                rc = 0;
     994            }
     995            else
     996                rc = errx(10, "CreateProcessA(%s) failed: %u", pszExecutable, GetLastError());
     997        }
     998        else
     999        {
     1000            /*
     1001             * Execute the orders, ending up with three handles we need to
     1002             * implant into the guest process.
     1003             *
     1004             * This isn't 100% perfect wrt O_APPEND, but it'll have to do for now.
     1005             */
     1006            BOOL   afReplace[3] = { FALSE, FALSE, FALSE };
     1007            HANDLE ahChild[3]   = { NULL,  NULL,  NULL  };
     1008            rc = 0;
     1009            for (i = 0; i < (int)cOrders; i++)
     1010            {
     1011                int fdTarget = paOrders[i].fdTarget;
     1012                assert(fdTarget >= 0 && fdTarget < 3);
     1013                switch (paOrders[i].enmOrder)
     1014                {
     1015                    case kRedirectOrder_Open:
     1016                        if (   (paOrders[i].fOpen & O_APPEND)
     1017                            && lseek(paOrders[i].fdSource, 0, SEEK_END) < 0)
     1018                            rc = err(10, "lseek-to-end failed on %d (for %d)", paOrders[i].fdSource, fdTarget);
     1019                    case kRedirectOrder_Dup:
     1020                        ahChild[fdTarget] = (HANDLE)_get_osfhandle(paOrders[i].fdSource);
     1021                        if (ahChild[fdTarget] == NULL || ahChild[fdTarget] == INVALID_HANDLE_VALUE)
     1022                            rc = err(10, "_get_osfhandle failed on %d (for %d)", paOrders[i].fdSource, fdTarget);
     1023                        break;
     1024                    case kRedirectOrder_Close:
     1025                        ahChild[fdTarget] = NULL;
     1026                        break;
     1027                    default:
     1028                        assert(0);
     1029                }
     1030                afReplace[fdTarget] = TRUE;
     1031            }
     1032            if (rc == 0)
     1033            {
     1034                /*
     1035                 * Start the process in suspended animation so we can inject handles.
     1036                 *
     1037                 * We clear the reserved 2 pointer + size to avoid passing the wrong
     1038                 * filehandle info to the child.  We may later want to generate this.
     1039                 */
     1040                StartupInfo.cbReserved2 = 0;
     1041                StartupInfo.lpReserved2 = 0;
     1042
     1043                if (CreateProcessA(pszExecutable, pszCmdLine, NULL /*pProcAttrs*/, NULL /*pThreadAttrs*/,
     1044                                   FALSE /*fInheritHandles*/, CREATE_SUSPENDED, pszzEnv, pszCwd, &StartupInfo, &ProcInfo))
     1045                {
     1046                    /*
     1047                     * Figure out where we need to write the handles.
     1048                     */
     1049                    ULONG                     cbActual1 = 0;
     1050                    PROCESS_BASIC_INFORMATION BasicInfo = { 0, 0, };
     1051                    NTSTATUS rcNt = s_pfnNtQueryInformationProcess(ProcInfo.hProcess, ProcessBasicInformation,
     1052                                                                   &BasicInfo, sizeof(BasicInfo), &cbActual1);
     1053                    if (NT_SUCCESS(rcNt))
     1054                    {
     1055                        BOOL const   f32BitPeb  = !f64BitHost;
     1056                        ULONG  const cbChildPtr = f32BitPeb ? 4 : 8;
     1057                        PVOID        pvSrcInPeb = (char *)BasicInfo.PebBaseAddress + (f32BitPeb ? 0x10 : 0x20);
     1058                        char *       pbDst      = 0;
     1059                        SIZE_T       cbActual2  = 0;
     1060                        if (ReadProcessMemory(ProcInfo.hProcess, pvSrcInPeb, &pbDst, cbChildPtr, &cbActual2))
     1061                        {
     1062                            union
     1063                            {
     1064                                KU32 au32[3];
     1065                                KU64 au64[3];
     1066                            } uBuf;
     1067                            memset(&uBuf, 0, sizeof(uBuf));
     1068                            pbDst += f32BitPeb ? 0x18 : 0x20;
     1069                            if (   (afReplace[0] && afReplace[1] && afReplace[2])
     1070                                || ReadProcessMemory(ProcInfo.hProcess, pbDst, &uBuf, cbChildPtr * 3, &cbActual2))
     1071                            {
     1072                                for (i = 0; i < 3; i++)
     1073                                    if (afReplace[i])
     1074                                    {
     1075                                        HANDLE hInChild = INVALID_HANDLE_VALUE;
     1076                                        if (   ahChild[i] == NULL /* just closed*/
     1077                                            || DuplicateHandle(GetCurrentProcess(), ahChild[i], ProcInfo.hProcess, &hInChild,
     1078                                                               0, TRUE /*fInheriable*/, DUPLICATE_SAME_ACCESS))
     1079                                        {
     1080                                            if (f32BitPeb)
     1081                                                uBuf.au32[i] = (KU32)(uintptr_t)hInChild;
     1082                                            else
     1083                                                uBuf.au64[i] = (uintptr_t)hInChild;
     1084                                        }
     1085                                        else
     1086                                            rc = errx(10, "Error duplicating %p into the child: %u", ahChild[i], GetLastError());
     1087                                    }
     1088                                if (    rc == 0
     1089                                    && !WriteProcessMemory(ProcInfo.hProcess, pbDst, &uBuf, cbChildPtr * 3, &cbActual2))
     1090                                    rc = errx(10, "Error writing standard handles at %p LB %u in the child: %u",
     1091                                              pbDst, cbChildPtr * 3, GetLastError());
     1092                            }
     1093                            else
     1094                                rc = errx(10, "Error reading %p LB %u from the child: %u",
     1095                                          pbDst, cbChildPtr * 3, GetLastError());
     1096                        }
     1097                        else
     1098                            rc = errx(10, "Error reading %p LB %u from the child: %u", pvSrcInPeb, cbChildPtr);
     1099                    }
     1100                    else
     1101                        rc = errx(10, "NtQueryInformationProcess failed: %#x", rcNt);
     1102
     1103                    /* Resume the bugger... */
     1104                    if (   rc == 0
     1105                        && !ResumeThread(ProcInfo.hThread))
     1106                        rc = errx(10, "ResumeThread failed: %u", GetLastError());
     1107
     1108                    /* .. or kill it. */
     1109                    if (rc != 0)
     1110                        TerminateProcess(ProcInfo.hProcess, rc);
     1111
     1112                    CloseHandle(ProcInfo.hThread);
     1113                    *phProcess = ProcInfo.hProcess;
     1114                    rc = 0;
     1115                }
     1116                else
     1117                    rc = errx(10, "CreateProcessA(%s) failed: %u", pszExecutable, GetLastError());
     1118            }
     1119        }
     1120        free(pszzEnv);
     1121    }
     1122    else
     1123        rc = errx(9, "out of memory!");
     1124    free(pszCmdLine);
     1125    return rc;
     1126}
     1127#endif /* KBUILD_OS_WINDOWS */
    7801128
    7811129/**
     
    8021150 *                              is from the child or from our setup efforts.
    8031151 */
    804 static int kRedirectDoSpawn(const char *pszExecutable, int cArgs, char **papszArgs, int fWatcomBrainDamage, char **papszEnvVars,
    805                             const char *pszCwd, const char *pszSavedCwd, unsigned cOrders, REDIRECTORDERS *paOrders,
     1152static int kRedirectDoSpawn(const char *pszExecutable, int cArgs, char **papszArgs, int fWatcomBrainDamage,
     1153                            char **papszEnvVars, const char *pszCwd, const char *pszSavedCwd,
     1154                            unsigned cOrders, REDIRECTORDERS *paOrders,
    8061155#ifdef USE_POSIX_SPAWN
    8071156                            posix_spawn_file_actions_t *pFileActions,
     
    8631212        }
    8641213
     1214#ifndef KBUILD_OS_WINDOWS
    8651215        /*
    8661216         * Change working directory if so requested.
     
    8711221                rcExit = errx(10, "Failed to change directory to '%s'", pszCwd);
    8721222        }
     1223#endif /* KBUILD_OS_WINDOWS */
    8731224        if (rcExit == 0)
    8741225        {
    875 #ifndef USE_POSIX_SPAWN
     1226# if !defined(USE_POSIX_SPAWN) && !defined(KBUILD_OS_WINDOWS)
    8761227            /*
    8771228             * Execute the file orders.
    8781229             */
    8791230            FILE *pWorkingStdErr = NULL;
    880 # if defined(CONFIG_NEW_WIN_CHILDREN) && defined(KMK)
     1231#  if defined(CONFIG_NEW_WIN_CHILDREN) && defined(KMK)
    8811232            if (cOrders > 0)
    8821233                MkWinChildExclusiveAcquire();
    883 # endif
     1234#  endif
    8841235            rcExit = kRedirectExecFdOrders(cOrders, paOrders, &pWorkingStdErr);
    8851236            if (rcExit == 0)
    886 #endif
    887             {
    888 #ifdef KMK
     1237# endif
     1238            {
     1239# ifdef KMK
    8891240                /*
    8901241                 * We're spawning from within kmk.
    8911242                 */
    892 #if defined(KBUILD_OS_WINDOWS)
    893                 /* Windows is slightly complicated due to handles and sub_proc.c. */
     1243# if defined(KBUILD_OS_WINDOWS)
     1244                /* Windows is slightly complicated due to handles and winchildren.c. */
     1245#  if 1
     1246                HANDLE hProcess = INVALID_HANDLE_VALUE;
     1247                rcExit = kRedirectCreateProcessWindows(pszExecutable, cArgs, papszArgs, papszEnvVars, pszCwd,
     1248                                                       cOrders, paOrders, &hProcess);
     1249                if (rcExit == 0)
     1250#  else
    8941251                HANDLE  hProcess = (HANDLE)_spawnvpe(_P_NOWAIT, pszExecutable, papszArgs, papszEnvVars);
    8951252                kRedirectRestoreFdOrders(cOrders, paOrders, &pWorkingStdErr);
    896 # ifdef CONFIG_NEW_WIN_CHILDREN
     1253#  ifdef CONFIG_NEW_WIN_CHILDREN
    8971254                if (cOrders > 0)
    8981255                    MkWinChildExclusiveRelease();
     1256#  endif
     1257                if ((intptr_t)hProcess != -1)
    8991258# endif
    900                 if ((intptr_t)hProcess != -1)
    901                 {
    902 # ifndef CONFIG_NEW_WIN_CHILDREN
     1259                {
     1260#  ifndef CONFIG_NEW_WIN_CHILDREN
    9031261                    if (process_kmk_register_redirect(hProcess, pPidSpawned) == 0)
    904 # else
     1262#  else
    9051263                    if (MkWinChildCreateRedirect((intptr_t)hProcess, pPidSpawned) == 0)
    906 # endif
     1264#  endif
    9071265                    {
    9081266                        if (cVerbosity > 0)
     
    9121270                    {
    9131271                        DWORD dwTmp;
    914 # ifndef CONFIG_NEW_WIN_CHILDREN
     1272#  ifndef CONFIG_NEW_WIN_CHILDREN
    9151273                        warn("sub_proc is out of slots, waiting for child...");
    916 # else
     1274#  else
    9171275                        warn("MkWinChildCreateRedirect failed...");
    918 # endif
     1276#  endif
    9191277                        dwTmp = WaitForSingleObject(hProcess, INFINITE);
    9201278                        if (dwTmp != WAIT_OBJECT_0)
     
    9351293                    }
    9361294                }
     1295#  if 0
    9371296                else
    9381297                    rcExit = err(10, "_spawnvpe(%s) failed", pszExecutable);
     1298#  endif
    9391299
    9401300# elif defined(KBUILD_OS_OS2)
     
    9511311                    *pPidSpawned = 0;
    9521312                }
    953 #else
     1313# else
    9541314                rcExit = posix_spawnp(pPidSpawned, pszExecutable, pFileActions, NULL /*pAttr*/, papszArgs, papszEnvVars);
    9551315                if (rcExit == 0)
     
    9631323                    *pPidSpawned = 0;
    9641324                }
    965 #endif
     1325# endif
    9661326
    9671327#else  /* !KMK */
     
    9691329                 * Spawning from inside the kmk_redirect executable.
    9701330                 */
    971 # if defined(KBUILD_OS_WINDOWS) || defined(KBUILD_OS_OS2)
     1331# ifdef KBUILD_OS_WINDOWS
     1332                HANDLE hProcess = INVALID_HANDLE_VALUE;
     1333                rcExit = kRedirectCreateProcessWindows(pszExecutable, cArgs, papszArgs, papszEnvVars, pszCwd,
     1334                                                       cOrders, paOrders, &hProcess);
     1335                if (rcExit == 0)
     1336                {
     1337                    DWORD dwWait;
     1338                    do
     1339                        dwWait = WaitForSingleObject(hProcess, INFINITE);
     1340                    while (dwWait == WAIT_IO_COMPLETION || dwWait == WAIT_TIMEOUT);
     1341
     1342                    dwWait = 11;
     1343                    if (GetExitCodeProcess(hProcess, &dwWait))
     1344                        rcExit = dwWait;
     1345                    else
     1346                        rcExit = errx(11, "GetExitCodeProcess(%s) failed: %u", pszExecutable, GetLastError());
     1347                }
     1348
     1349#elif defined(KBUILD_OS_WINDOWS) || defined(KBUILD_OS_OS2)
    9721350                errno  = 0;
    9731351#  if defined(KBUILD_OS_WINDOWS)
     
    10231401#endif /* !KMK */
    10241402            }
    1025 #if defined(CONFIG_NEW_WIN_CHILDREN) && defined(KBUILD_OS_WINDOWS) && defined(KMK)
     1403#if defined(CONFIG_NEW_WIN_CHILDREN) && defined(KBUILD_OS_WINDOWS) && defined(KMK) && 0
    10261404            else if (cOrders > 0)
    10271405                MkWinChildExclusiveRelease();
     
    14411819                else if (fd < 0)
    14421820                    rcExit = errx(2, "error: negative fd %d (%s)", fd, pszValue);
     1821#ifdef ONLY_TARGET_STANDARD_HANDLES
     1822                else if (fd > 2)
     1823                    rcExit = errx(2, "error: %d is not a standard descriptor number", fd);
     1824#endif
    14431825                else
    14441826                {
     
    14641846                else if (fd < 0)
    14651847                    rcExit = errx(2, "error: negative target descriptor %d ('-d %s')", fd, pszValue);
     1848#ifdef ONLY_TARGET_STANDARD_HANDLES
     1849                else if (fd > 2)
     1850                    rcExit = errx(2, "error: target %d is not a standard descriptor number", fd);
     1851#endif
    14661852                else if (*pszEqual != '=')
    14671853                    rcExit = errx(2, "syntax error: expected '=' to follow target descriptor: '-d %s'", pszValue);
     
    16081994                        else if (fd < 0)
    16091995                            rcExit = errx(2, "error: negative fd %d (%s)", fd, argv[iArg]);
     1996#ifdef ONLY_TARGET_STANDARD_HANDLES
     1997                        else if (fd > 2)
     1998                            rcExit = errx(2, "error: %d is not a standard descriptor number", fd);
     1999#endif
    16102000                        else
    16112001                            break;
     
    16882078         * Do the spawning in a separate function (main is far to large as it is by now).
    16892079         */
    1690         rcExit = kRedirectDoSpawn(pszExecutable, argc - iArg, &argv[iArg], fWatcomBrainDamage, papszEnvVars, szCwd, pszSavedCwd,
     2080        rcExit = kRedirectDoSpawn(pszExecutable, argc - iArg, &argv[iArg], fWatcomBrainDamage,
     2081                                  papszEnvVars,
     2082                                  szCwd, pszSavedCwd,
    16912083#ifdef USE_POSIX_SPAWN
    16922084                                  cOrders, aOrders, &FileActions, cVerbosity,
  • trunk/src/kmk/main.c

    r3159 r3161  
    14701470    if (!cpus)
    14711471      cpus = 1;
     1472#  ifdef CONFIG_NEW_WIN_CHILDREN
    14721473    if (cpus > 64)
    14731474      cpus = 64; /* (wait for multiple objects limit) */
     1475#  endif
    14741476    return cpus;
    14751477
     
    31293131            setrlimit (RLIMIT_STACK, &stack_limit);
    31303132#endif
    3131 fprintf(stderr, "respawning 1..\n");
    3132 fprintf(stderr, "respawning 2..\n");
    3133 fprintf(stderr, "respawning 3..!\n");
    31343133# if !defined(WINDOWS32) || !defined(CONFIG_NEW_WIN_CHILDREN)
    31353134          exec_command ((char **)nargv, environ);
  • trunk/src/kmk/w32/winchildren.c

    r3159 r3161  
    7676
    7777#include <Windows.h>
     78#include <Winternl.h>
    7879#include <assert.h>
    7980#include <process.h>
     
    270271/** Kernel32!SetThreadGroupAffinity */
    271272static BOOL (WINAPI        *g_pfnSetThreadGroupAffinity)(HANDLE, CONST GROUP_AFFINITY *, GROUP_AFFINITY *);
     273/** NTDLL!NtQueryInformationProcess */
     274static NTSTATUS (NTAPI     *g_pfnNtQueryInformationProcess)(HANDLE, PROCESSINFOCLASS, PVOID, ULONG, PULONG);
     275/** Set if the windows host is 64-bit. */
     276static BOOL                 g_f64BitHost = (K_ARCH_BITS == 64);
    272277/** Windows version info.
    273278 * @note Putting this before the volatile stuff, hoping to keep it in a
     
    289294static unsigned volatile    g_idxLastChildcareWorker = 0;
    290295
    291 /** Temporary RW lock for serializing kmkbuiltin_redirect and CreateProcess. */
     296/** RW lock for serializing kmkbuiltin_redirect and CreateProcess. */
    292297static SRWLOCK              g_RWLock;
    293298
     
    301306void MkWinChildInit(unsigned int cJobSlots)
    302307{
     308    HMODULE hmod;
     309
    303310    /*
    304311     * Figure out how many childcare workers first.
     
    322329
    323330    /*
     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    /*
    324351     * Figure out how many processor groups there are.
    325352     * For that we need to first figure the windows version.
     
    334361    if (g_VersionInfo.dwMajorVersion >= 6)
    335362    {
    336         HMODULE hmod = GetModuleHandleA("KERNEL32.DLL");
     363        hmod = GetModuleHandleA("KERNEL32.DLL");
    337364        *(FARPROC *)&g_pfnGetActiveProcessorGroupCount = GetProcAddress(hmod, "GetActiveProcessorGroupCount");
    338365        *(FARPROC *)&g_pfnGetActiveProcessorCount      = GetProcAddress(hmod, "GetActiveProcessorCount");
     
    365392    }
    366393
    367     /* Temporary: */
     394    /*
     395     * For serializing with standard file handle manipulation (kmkbuiltin_redirect).
     396     */
    368397    InitializeSRWLock(&g_RWLock);
    369398}
     
    465494    }
    466495}
     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 */
     508static 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
    467760
    468761#define MKWCCWCMD_F_CYGWIN_SHELL    1
     
    12151508static void mkWinChildcareWorkerThreadHandleProcess(PWINCHILDCAREWORKER pWorker, PWINCHILD pChild)
    12161509{
    1217     PROCESS_INFORMATION     ProcInfo;
    1218     STARTUPINFOW            StartupInfo;
    12191510    WCHAR const            *pwszPath         = NULL;
    12201511    WCHAR                  *pwszzEnvironment = NULL;
     
    12221513    WCHAR                  *pwszImageName    = NULL;
    12231514    BOOL                    fNeedShell       = FALSE;
    1224     DWORD                   fFlags = CREATE_UNICODE_ENVIRONMENT;
    1225     BOOL                    fRet;
    12261515    int                     rc;
    1227 #ifdef KMK
    1228     extern int process_priority;
    1229 #endif
    12301516
    12311517    /*
     
    12491535        else
    12501536            rc = mkWinChildcareWorkerConvertCommandlineWithShell(pwszImageName, pChild->u.Process.papszArgs, &pwszCommandLine);
    1251     }
    1252     if (rc == 0)
    1253     {
    1254         AcquireSRWLockShared(&g_RWLock); /* temporary */
    12551537
    12561538        /*
    1257          * Populate startup info.
     1539         * Create the child process.
    12581540         */
    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;
    13561553        }
    13571554        else
     
    15131710                    pChild->pNext = pTailExpect;
    15141711                    pTailActual = _InterlockedCompareExchangePointer(&g_pTailCompletedChildren, pChild, pTailExpect);
    1515                     if (pTailActual == pTailExpect)
     1712                    if (pTailActual != pTailExpect)
     1713                        pTailExpect = pTailActual;
     1714                    else
    15161715                    {
    15171716                        _InterlockedDecrement(&g_cPendingChildren);
     
    22052404}
    22062405
    2207 /** Temporary serialization with kmkbuiltin_redirect. */
     2406/** Serialization with kmkbuiltin_redirect. */
    22082407void MkWinChildExclusiveAcquire(void)
    22092408{
     
    22112410}
    22122411
    2213 /** Temporary serialization with kmkbuiltin_redirect. */
     2412/** Serialization with kmkbuiltin_redirect. */
    22142413void MkWinChildExclusiveRelease(void)
    22152414{
Note: See TracChangeset for help on using the changeset viewer.