VirtualBox

Changeset 3158 in kBuild


Ignore:
Timestamp:
Mar 18, 2018 9:25:06 PM (7 years ago)
Author:
bird
Message:

kmk/win: Reworking child process handling. Mostly done coding.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/kmk/w32/winchildren.c

    r3156 r3158  
    120120            /** The make shell to use (copy). */
    121121            char           *pszShell;
     122            /** Handle to use for standard out. */
     123            HANDLE          hStdOut;
     124            /** Handle to use for standard out. */
     125            HANDLE          hStdErr;
     126            /** Whether to close hStdOut after creating the process.  */
     127            BOOL            fCloseStdOut;
     128            /** Whether to close hStdErr after creating the process.  */
     129            BOOL            fCloseStdErr;
     130
    122131            /** Child process handle. */
    123132            HANDLE          hProcess;
     
    313322}
    314323
    315 
    316 /**
    317  * Emulate execv() for restarting kmk after one ore more makefiles has been
    318  * made.
    319  *
    320  * Does not return.
    321  *
    322  * @param   papszArgs           The arguments.
    323  * @param   papszEnv            The environment.
    324  */
    325 void MkWinChildReExecMake(char **papszArgs, char **papszEnv)
    326 {
    327     fatal(NILF, 0, __FUNCTION__ "not implemented!\n");
    328 }
    329 
    330324/**
    331325 * Used by mkWinChildcareWorkerThread() and MkWinChildWait() to get the head
     
    10361030    {
    10371031        cwcDst = cbEnvStrings + 32;
    1038         pwszzDst = (WCHAR *)xmalloc(cwcDst);
     1032        pwszzDst = (WCHAR *)xmalloc(cwcDst * sizeof(WCHAR));
    10391033        cwcRc = MultiByteToWideChar(CP_ACP, 0 /*fFlags*/, papszEnv[0], cbEnvStrings, pwszzDst, cwcDst);
    10401034        if (cwcRc != 0)
     
    12171211        StartupInfo.cb = sizeof(StartupInfo);
    12181212        GetStartupInfoW(&StartupInfo);
     1213        if (   pChild->u.Process.hStdErr == INVALID_HANDLE_VALUE
     1214            && pChild->u.Process.hStdOut == INVALID_HANDLE_VALUE)
     1215            StartupInfo.dwFlags &= ~STARTF_USESTDHANDLES;
     1216        else
     1217        {
     1218            StartupInfo.dwFlags |= STARTF_USESTDHANDLES;
     1219            StartupInfo.hStdOutput = pChild->u.Process.hStdOut != INVALID_HANDLE_VALUE
     1220                                   ? pChild->u.Process.hStdOut : GetStdHandle(STD_OUTPUT_HANDLE);
     1221            StartupInfo.hStdError  = pChild->u.Process.hStdErr != INVALID_HANDLE_VALUE
     1222                                   ? pChild->u.Process.hStdErr : GetStdHandle(STD_ERROR_HANDLE);
     1223            StartupInfo.hStdInput  = GetStdHandle(STD_INPUT_HANDLE);
     1224        }
    12191225
    12201226        /*
     
    12411247        fRet = CreateProcessW(pwszImageName, pwszCommandLine, NULL /*pProcSecAttr*/, NULL /*pThreadSecAttr*/,
    12421248                              TRUE /*fInheritHandles*/, fFlags, pwszzEnvironment, NULL /*pwsz*/, &StartupInfo, &ProcInfo);
     1249        rc = GetLastError();
    12431250        if (fRet)
    12441251        {
     
    12711278                (void)fRet;
    12721279            }
     1280
     1281            /*
     1282             * Close unncessary handles.
     1283             */
    12731284            CloseHandle(ProcInfo.hThread);
    12741285            pChild->u.Process.hProcess = ProcInfo.hProcess;
     1286
     1287            if (   pChild->u.Process.fCloseStdOut
     1288                && pChild->u.Process.hStdOut != INVALID_HANDLE_VALUE)
     1289            {
     1290                CloseHandle(pChild->u.Process.hStdOut);
     1291                pChild->u.Process.hStdOut      = INVALID_HANDLE_VALUE;
     1292                pChild->u.Process.fCloseStdOut = FALSE;
     1293            }
     1294            if (   pChild->u.Process.fCloseStdErr
     1295                && pChild->u.Process.hStdErr != INVALID_HANDLE_VALUE)
     1296            {
     1297                CloseHandle(pChild->u.Process.hStdErr);
     1298                pChild->u.Process.hStdErr      = INVALID_HANDLE_VALUE;
     1299                pChild->u.Process.fCloseStdErr = FALSE;
     1300            }
    12751301
    12761302            /*
     
    12791305            mkWinChildcareWorkerWaitForProcess(pWorker, pChild, ProcInfo.hProcess);
    12801306        }
     1307        else
     1308            pChild->iExitCode = rc;
    12811309    }
    12821310    else
     
    15931621                pChild->u.Process.hProcess = NULL;
    15941622            }
     1623            if (   pChild->u.Process.fCloseStdOut
     1624                && pChild->u.Process.hStdOut != INVALID_HANDLE_VALUE)
     1625            {
     1626                CloseHandle(pChild->u.Process.hStdOut);
     1627                pChild->u.Process.hStdOut      = INVALID_HANDLE_VALUE;
     1628                pChild->u.Process.fCloseStdOut = FALSE;
     1629            }
     1630            if (   pChild->u.Process.fCloseStdErr
     1631                && pChild->u.Process.hStdErr != INVALID_HANDLE_VALUE)
     1632            {
     1633                CloseHandle(pChild->u.Process.hStdErr);
     1634                pChild->u.Process.hStdErr      = INVALID_HANDLE_VALUE;
     1635                pChild->u.Process.fCloseStdErr = FALSE;
     1636            }
    15951637            break;
    15961638        }
     
    17581800    if (pszShell)
    17591801        pChild->u.Process.pszShell = xstrdup(pszShell);
     1802    pChild->u.Process.hStdOut = INVALID_HANDLE_VALUE;
     1803    pChild->u.Process.hStdErr = INVALID_HANDLE_VALUE;
    17601804
    17611805    return mkWinChildPushToCareWorker(pChild, pPid);
    17621806}
    17631807
     1808/**
     1809 * Creates a chile process with a pipe hooked up to stdout.
     1810 *
     1811 * @returns 0 on success, non-zero on failure.
     1812 * @param   papszArgs       The argument vector.
     1813 * @param   papszEnv        The environment vector (optional).
     1814 * @param   fdErr           File descriptor to hook up to stderr.
     1815 * @param   pPid            Where to return the pid.
     1816 * @param   pfdReadPipe     Where to return the read end of the pipe.
     1817 */
    17641818int MkWinChildCreateWithStdOutPipe(char **papszArgs, char **papszEnv, int fdErr, pid_t *pPid, int *pfdReadPipe)
    17651819{
    1766     fatal(NILF, 0, __FUNCTION__ "not implemented!\n");
     1820    /*
     1821     * Create the pipe.
     1822     */
     1823    HANDLE hReadPipe;
     1824    HANDLE hWritePipe;
     1825    if (CreatePipe(&hReadPipe, &hWritePipe, NULL, 0 /* default size */))
     1826    {
     1827        if (SetHandleInformation(hWritePipe, HANDLE_FLAG_INHERIT /* clear */ , HANDLE_FLAG_INHERIT /*set*/))
     1828        {
     1829            int fdReadPipe = _open_osfhandle((intptr_t)hReadPipe, O_RDONLY);
     1830            if (fdReadPipe >= 0)
     1831            {
     1832                PWINCHILD pChild;
     1833                int rc;
     1834
     1835                /*
     1836                 * Get a handle for fdErr.  Ignore failure.
     1837                 */
     1838                HANDLE hStdErr = INVALID_HANDLE_VALUE;
     1839                if (fdErr >= 0)
     1840                {
     1841                    HANDLE hNative = (HANDLE)_get_osfhandle(fdErr);
     1842                    if (!DuplicateHandle(GetCurrentProcess(), hNative, GetCurrentProcess(),
     1843                                         &hStdErr, 0 /*DesiredAccess*/, TRUE /*fInherit*/, DUPLICATE_SAME_ACCESS))
     1844                    {
     1845                        ONN(error, NILF, _("DuplicateHandle failed on stderr descriptor (%u): %u\n"), fdErr, GetLastError());
     1846                        hStdErr = INVALID_HANDLE_VALUE;
     1847                    }
     1848                }
     1849
     1850                /*
     1851                 * Push it off to the worker thread.
     1852                 */
     1853                pChild = mkWinChildNew(WINCHILDTYPE_PROCESS);
     1854                pChild->u.Process.papszArgs = mkWinChildCopyStringArray(papszArgs, &pChild->u.Process.cbArgsStrings);
     1855                pChild->u.Process.papszEnv  = mkWinChildCopyStringArray(papszEnv ? papszEnv : environ,
     1856                                                                        &pChild->u.Process.cbEnvStrings);
     1857                //if (pszShell)
     1858                //    pChild->u.Process.pszShell = xstrdup(pszShell);
     1859                pChild->u.Process.hStdOut   = hWritePipe;
     1860                pChild->u.Process.hStdErr   = hStdErr;
     1861                pChild->u.Process.fCloseStdErr = TRUE;
     1862                pChild->u.Process.fCloseStdOut = TRUE;
     1863
     1864                rc = mkWinChildPushToCareWorker(pChild, pPid);
     1865                if (rc == 0)
     1866                    *pfdReadPipe = fdReadPipe;
     1867                else
     1868                {
     1869                    ON(error, NILF, _("mkWinChildPushToCareWorker failed on pipe: %d\n"), rc);
     1870                    close(fdReadPipe);
     1871                    *pfdReadPipe = -1;
     1872                    *pPid = -1;
     1873                }
     1874                return rc;
     1875            }
     1876
     1877            ON(error, NILF, _("_open_osfhandle failed on pipe: %u\n"), errno);
     1878        }
     1879        else
     1880            ON(error, NILF, _("SetHandleInformation failed on pipe: %u\n"), GetLastError());
     1881        if (hReadPipe != INVALID_HANDLE_VALUE)
     1882            CloseHandle(hReadPipe);
     1883        CloseHandle(hWritePipe);
     1884    }
     1885    else
     1886        ON(error, NILF, _("CreatePipe failed: %u\n"), GetLastError());
     1887    *pfdReadPipe = -1;
     1888    *pPid = -1;
    17671889    return -1;
    17681890}
     
    18421964}
    18431965
     1966/**
     1967 * Wait for a child process to complete
     1968 *
     1969 * @returns 0 on success, windows error code on failure.
     1970 * @param   fBlock          Whether to block.
     1971 * @param   pPid            Where to return the pid if a child process
     1972 *                          completed.  This is set to zero if none.
     1973 * @param   piExitCode      Where to return the exit code.
     1974 * @param   piSignal        Where to return the exit signal number.
     1975 * @param   pfCoreDumped    Where to return the core dumped indicator.
     1976 * @param   ppMkChild       Where to return the associated struct child pointer.
     1977 */
    18441978int MkWinChildWait(int fBlock, pid_t *pPid, int *piExitCode, int *piSignal, int *pfCoreDumped, struct child **ppMkChild)
    18451979{
     
    18471981
    18481982    *pPid         = 0;
    1849     *piExitCode   = 0;
     1983    *piExitCode   = -222222;
    18501984    *pfCoreDumped = 0;
    18511985    *ppMkChild    = NULL;
     
    19002034}
    19012035
     2036
     2037/**
     2038 * Emulate execv() for restarting kmk after one ore more makefiles has been
     2039 * made.
     2040 *
     2041 * Does not return.
     2042 *
     2043 * @param   papszArgs           The arguments.
     2044 * @param   papszEnv            The environment.
     2045 */
     2046void MkWinChildReExecMake(char **papszArgs, char **papszEnv)
     2047{
     2048    PROCESS_INFORMATION     ProcInfo;
     2049    STARTUPINFOW            StartupInfo;
     2050    WCHAR                  *pwszCommandLine;
     2051    WCHAR                  *pwszzEnvironment;
     2052    WCHAR                  *pwszPathIgnored;
     2053    int                     rc;
     2054
     2055/** @todo this code needs testing... */
     2056
     2057    /*
     2058     * Get the executable name.
     2059     */
     2060    WCHAR wszImageName[MKWINCHILD_MAX_PATH];
     2061    DWORD cwcImageName = GetModuleFileNameW(GetModuleHandle(NULL), wszImageName, MKWINCHILD_MAX_PATH);
     2062    if (cwcImageName == 0)
     2063        ON(fatal, NILF, _("MkWinChildReExecMake: GetModuleFileName failed: %u\n"), GetLastError());
     2064
     2065    /*
     2066     * Create the command line and environment.
     2067     */
     2068    rc = mkWinChildcareWorkerConvertCommandline(papszArgs, 0 /*fFlags*/, &pwszCommandLine);
     2069    if (rc != 0)
     2070        ON(fatal, NILF, _("MkWinChildReExecMake: mkWinChildcareWorkerConvertCommandline failed: %u\n"), rc);
     2071
     2072    rc = mkWinChildcareWorkerConvertEnvironment(papszEnv ? papszEnv : environ, 0 /*cbEnvStrings*/,
     2073                                                &pwszzEnvironment, &pwszPathIgnored);
     2074    if (rc != 0)
     2075        ON(fatal, NILF, _("MkWinChildReExecMake: mkWinChildcareWorkerConvertEnvironment failed: %u\n"), rc);
     2076
     2077
     2078    /*
     2079     * Fill out the startup info and try create the process.
     2080     */
     2081    memset(&ProcInfo, 0, sizeof(ProcInfo));
     2082    memset(&StartupInfo, 0, sizeof(StartupInfo));
     2083    StartupInfo.cb = sizeof(StartupInfo);
     2084    GetStartupInfoW(&StartupInfo);
     2085    if (!CreateProcessW(wszImageName, pwszCommandLine, NULL /*pProcSecAttr*/, NULL /*pThreadSecAttr*/,
     2086                        TRUE /*fInheritHandles*/, 0 /*fFlags*/, pwszzEnvironment, NULL /*pwsz*/,
     2087                        &StartupInfo, &ProcInfo))
     2088        ON(fatal, NILF, _("MkWinChildReExecMake: CreateProcessW failed: %u\n"), GetLastError());
     2089    CloseHandle(ProcInfo.hThread);
     2090
     2091    /*
     2092     * Wait for it to complete and forward the status code to our parent.
     2093     */
     2094    for (;;)
     2095    {
     2096        DWORD dwExitCode = -2222;
     2097        DWORD dwStatus = WaitForSingleObject(ProcInfo.hProcess, INFINITE);
     2098        if (   dwStatus == WAIT_IO_COMPLETION
     2099            || dwStatus == WAIT_TIMEOUT /* whatever */)
     2100            continue; /* however unlikely, these aren't fatal. */
     2101
     2102        /* Get the status code and terminate. */
     2103        if (dwStatus == WAIT_OBJECT_0)
     2104        {
     2105            if (GetExitCodeProcess(ProcInfo.hProcess, &dwExitCode))
     2106                ON(fatal, NILF, _("MkWinChildReExecMake: GetExitCodeProcess failed: %u\n"), GetLastError());
     2107            else
     2108                dwExitCode = -2222;
     2109        }
     2110        else if (dwStatus)
     2111            dwExitCode = dwStatus;
     2112
     2113        CloseHandle(ProcInfo.hProcess);
     2114        for (;;)
     2115            exit(dwExitCode);
     2116    }
     2117}
     2118
     2119
    19022120int MkWinChildUnrelatedCloseOnExec(int fd)
    19032121{
     
    19142132}
    19152133
     2134
     2135
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