Changeset 3185 for trunk/src/kmk


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

winchildren: Display messages every 15 or 30 secons when processes keep on running. Strighten out the PATH searching. Use the directory cache when resolving the executable image, now that kFsCache have basic locking in place. Be more careful in mkWinChildCopyStringArray to make sure the strings are always zero terminated, even if the input is volatile/corrupted for some reason (parnaoia).

File:
1 edited

Legend:

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

    r3182 r3185  
    6363 * processor groups, using a very simple algorithm (see details in code).
    6464 *
     65 *
     66 * @todo Output buffering using pipes, finally making 'link' output readable.
     67 *
     68 *
     69 * @section sec_win_children_av     Remarks on Microsoft Defender and other AV
     70 *
     71 * Part of the motivation for writing this code was horrible CPU utilization on
     72 * a brand new AMD Threadripper 1950X system with lots of memory and SSDs,
     73 * running 64-bit Windows 10 build 16299.
     74 *
     75 * Turns out Microsoft defender adds some overhead to CreateProcess
     76 * and other stuff:
     77 *     - Old make with CreateProcess on main thread:
     78 *          - With runtime defender enabled: 14 min  6 seconds
     79 *          - With runtime defender disabled: 4 min 49 seconds
     80 *     - New make with CreateProcess on worker thread (this code):
     81 *          - With runtime defender enabled:  6 min 29 seconds
     82 *          - With runtime defender disabled: 4 min 36 seconds
     83 *          - With runtime defender disabled out dir only: 5 min 59 seconds
     84 *
     85 * See also kWorker / kSubmit for more bickering about AV & disk encryption.
    6586 */
    6687
     
    7192#include "../makeint.h"
    7293#include "../job.h"
     94#include "../filedef.h"
    7395#include "../debug.h"
    7496#include "../kmkbuiltin.h"
     
    576598 * @param   pChild              The child.
    577599 * @param   hProcess            The process handle.
    578  */
    579 static void mkWinChildcareWorkerWaitForProcess(PWINCHILDCAREWORKER pWorker, PWINCHILD pChild, HANDLE hProcess)
    580 {
     600 * @param   pwszJob             The job name.
     601 */
     602static void mkWinChildcareWorkerWaitForProcess(PWINCHILDCAREWORKER pWorker, PWINCHILD pChild, HANDLE hProcess,
     603                                               WCHAR const *pwszJob)
     604{
     605    DWORD const msStart = GetTickCount();
     606    DWORD       msNextMsg = msStart + 15000;
    581607    for (;;)
    582608    {
    583609        DWORD dwExitCode = -42;
    584         DWORD dwStatus = WaitForSingleObject(hProcess, INFINITE);
     610        DWORD dwStatus = WaitForSingleObject(hProcess, 15001 /*ms*/);
    585611        assert(dwStatus != WAIT_FAILED);
    586612        if (dwStatus == WAIT_OBJECT_0)
     
    593619            }
    594620        }
    595         else if (   dwStatus == WAIT_IO_COMPLETION
    596                  || dwStatus == WAIT_TIMEOUT /* whatever */)
    597             continue; /* however unlikely, these aren't fatal. */
     621        else if (   dwStatus == WAIT_TIMEOUT /* whatever */
     622                 || dwStatus == WAIT_IO_COMPLETION)
     623        {
     624            DWORD msNow = GetTickCount();
     625            if (msNow >= msNextMsg)
     626            {
     627                if (   !pChild->pMkChild
     628                    || !pChild->pMkChild->recursive) /* ignore make recursions */
     629                {
     630                    if (   !pChild->pMkChild
     631                        || !pChild->pMkChild->file
     632                        || !pChild->pMkChild->file->name)
     633                        printf("Pid %u ('%s') still running after %u seconds\n",
     634                               GetProcessId(hProcess), pwszJob, (msNow - msStart) / 1000);
     635                    else
     636                        printf("Target '%s' (pid %u) still running after %u seconds\n",
     637                               pChild->pMkChild->file->name, GetProcessId(hProcess), (msNow - msStart) / 1000);
     638                }
     639
     640                /* After 15s, 30s, 60s, 120s, 180s, ... */
     641                if (msNextMsg == msStart + 15000)
     642                    msNextMsg += 15000;
     643                else
     644                    msNextMsg += 30000;
     645            }
     646            continue;
     647        }
    598648
    599649        /* Something failed. */
     
    10301080{
    10311081    fprintf(stderr, "%s: not found!\n", papszArgs[0]);
     1082//__debugbreak();
    10321083    return ERROR_FILE_NOT_FOUND;
    10331084}
     
    11751226                if (cwcAbsPath > 0)
    11761227                {
    1177                     cwcAbsPath = cwcPath + 1; /* include terminator, like MultiByteToWideChar does. */
     1228                    cwcPath  = cwcAbsPath + 1; /* include terminator, like MultiByteToWideChar does. */
    11781229                    pwszPath = wszPathBuf;
    11791230                }
     
    11811232
    11821233            /*
    1183              * If there is an exectuable path, we only need to check that it exists.
     1234             * Check with .exe suffix first.
     1235             * We don't open .exe files and look for hash bang stuff, we just
     1236             * assume they are executable images that CreateProcess can deal with.
    11841237             */
    1185             if (fHasExeSuffix)
    1186             {
    1187                 DWORD dwAttribs = GetFileAttributesW(pwszPath);
    1188                 if (dwAttribs != INVALID_FILE_ATTRIBUTES)
    1189                     return mkWinChildDuplicateUtf16String(pwszPath, cwcPath + 4, ppwszImagePath);
    1190             }
    1191             else
    1192             {
    1193                 /*
    1194                  * No suffix, so try open it first to see if it's shell fooder.
    1195                  * Otherwise, append a .exe suffix and check if it exists.
    1196                  */
    1197                 hFile = CreateFileW(pwszPath, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_DELETE | FILE_SHARE_WRITE,
    1198                                     NULL /*pSecAttr*/, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
    1199                 if (hFile != INVALID_HANDLE_VALUE)
     1238            if (!fHasExeSuffix)
     1239            {
     1240                pwszPath[cwcPath - 1] = L'.';
     1241                pwszPath[cwcPath    ] = L'e';
     1242                pwszPath[cwcPath + 1] = L'x';
     1243                pwszPath[cwcPath + 2] = L'e';
     1244                pwszPath[cwcPath + 3] = L'\0';
     1245            }
     1246
     1247#ifdef KMK
     1248            if (utf16_regular_file_p(pwszPath))
     1249#else
     1250            if (GetFileAttributesW(pwszPath) != INVALID_FILE_ATTRIBUTES)
     1251#endif
     1252                return mkWinChildDuplicateUtf16String(pwszPath, cwcPath + 4, ppwszImagePath);
     1253
     1254            /*
     1255             * If no suffix was specified, try without .exe too, but now we need
     1256             * to see if it's for the shell or CreateProcess.
     1257             */
     1258            if (!fHasExeSuffix)
     1259            {
     1260                pwszPath[cwcPath - 1] = L'\0';
     1261#ifdef KMK
     1262                if (utf16_regular_file_p(pwszPath))
     1263#endif
    12001264                {
    1201                     *pfNeedShell = mkWinChildcareWorkerCheckIfNeedShell(hFile);
    1202                     CloseHandle(hFile);
    1203                     if (!*pfNeedShell)
    1204                         return mkWinChildDuplicateUtf16String(pwszPath, cwcPath, ppwszImagePath);
    1205                 }
    1206                 /* Append the .exe suffix and check if it exists. */
    1207                 else
    1208                 {
    1209                     DWORD dwAttribs;
    1210                     pwszPath[cwcPath - 1] = L'.';
    1211                     pwszPath[cwcPath    ] = L'e';
    1212                     pwszPath[cwcPath + 1] = L'x';
    1213                     pwszPath[cwcPath + 2] = L'e';
    1214                     pwszPath[cwcPath + 3] = L'\0';
    1215                     dwAttribs = GetFileAttributesW(pwszPath);
    1216                     if (dwAttribs != INVALID_FILE_ATTRIBUTES)
    1217                         return mkWinChildDuplicateUtf16String(pwszPath, cwcPath + 4, ppwszImagePath);
     1265                    hFile = CreateFileW(pwszPath, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_DELETE | FILE_SHARE_WRITE,
     1266                                        NULL /*pSecAttr*/, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
     1267                    if (hFile != INVALID_HANDLE_VALUE)
     1268                    {
     1269                        *pfNeedShell = mkWinChildcareWorkerCheckIfNeedShell(hFile);
     1270                        CloseHandle(hFile);
     1271                        if (!*pfNeedShell)
     1272                            return mkWinChildDuplicateUtf16String(pwszPath, cwcPath, ppwszImagePath);
     1273                    }
    12181274                }
    12191275            }
     
    12741330                if (cwcComponent > 0 && cwcCombined <= MKWINCHILD_MAX_PATH)
    12751331                {
     1332#ifndef KMK
    12761333                    DWORD dwAttribs;
     1334#endif
    12771335
    12781336                    /* Copy the component into wszPathBuf, maybe abspath'ing it. */
     
    13271385                        wszPathBuf[cwcCombined + 3] = L'\0';
    13281386                    }
     1387#ifdef KMK
     1388                    if (utf16_regular_file_p(wszPathBuf))
     1389#else
    13291390                    dwAttribs = GetFileAttributesW(wszPathBuf);
    13301391                    if (   dwAttribs != INVALID_FILE_ATTRIBUTES
    13311392                        && !(dwAttribs & FILE_ATTRIBUTE_DIRECTORY))
     1393#endif
    13321394                        return mkWinChildDuplicateUtf16String(wszPathBuf, cwcCombined + (fHasExeSuffix ? 0 : 4), ppwszImagePath);
    13331395                    if (!fHasExeSuffix)
    13341396                    {
    13351397                        wszPathBuf[cwcCombined - 1] = L'\0';
    1336 
    1337                         /*
    1338                          * Check if the file exists w/o the added '.exe' suffix.  If it does,
    1339                          * we need to check if we can pass it to CreateProcess or need the shell.
    1340                          */
    1341                         hFile = CreateFileW(wszPathBuf, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_DELETE | FILE_SHARE_WRITE,
    1342                                             NULL /*pSecAttr*/, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
    1343                         if (hFile != INVALID_HANDLE_VALUE)
     1398#ifdef KMK
     1399                        if (utf16_regular_file_p(wszPathBuf))
     1400#endif
    13441401                        {
    1345                             *pfNeedShell = mkWinChildcareWorkerCheckIfNeedShell(hFile);
    1346                             CloseHandle(hFile);
    1347                             if (!*pfNeedShell)
    1348                                 return mkWinChildDuplicateUtf16String(wszPathBuf, cwcCombined, ppwszImagePath);
    1349                             break;
     1402                            /*
     1403                             * Check if the file exists w/o the added '.exe' suffix.  If it does,
     1404                             * we need to check if we can pass it to CreateProcess or need the shell.
     1405                             */
     1406                            hFile = CreateFileW(wszPathBuf, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_DELETE | FILE_SHARE_WRITE,
     1407                                                NULL /*pSecAttr*/, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
     1408                            if (hFile != INVALID_HANDLE_VALUE)
     1409                            {
     1410                                *pfNeedShell = mkWinChildcareWorkerCheckIfNeedShell(hFile);
     1411                                CloseHandle(hFile);
     1412                                if (!*pfNeedShell)
     1413                                    return mkWinChildDuplicateUtf16String(wszPathBuf, cwcCombined, ppwszImagePath);
     1414                                break;
     1415                            }
    13501416                        }
    13511417                    }
     
    13851451        {
    13861452            fprintf(stderr, "%s: not found!\n", pszArg0);
     1453//__debugbreak();
    13871454            dwErr = ERROR_FILE_NOT_FOUND;
    13881455        }
     
    16031670                 * Wait for the child to complete.
    16041671                 */
    1605                 mkWinChildcareWorkerWaitForProcess(pWorker, pChild, pChild->u.Process.hProcess);
     1672                mkWinChildcareWorkerWaitForProcess(pWorker, pChild, pChild->u.Process.hProcess, pwszImageName);
    16061673            }
    16071674            else
     
    17201787static void mkWinChildcareWorkerThreadHandleRedirect(PWINCHILDCAREWORKER pWorker, PWINCHILD pChild)
    17211788{
    1722     mkWinChildcareWorkerWaitForProcess(pWorker, pChild, pChild->u.Redirect.hProcess);
     1789    mkWinChildcareWorkerWaitForProcess(pWorker, pChild, pChild->u.Redirect.hProcess, L"kmk_redirect");
    17231790}
    17241791
     
    19261993    for (i = 0; i < cStrings; i++)
    19271994    {
    1928         size_t cbString = strlen(papszSrc[i]) + 1;
    1929         papszDstArray[i] = (char *)memcpy(pszDstStr, papszSrc[i], cbString);
    1930         pszDstStr += cbString;
     1995        const char *pszSource = papszSrc[i];
     1996        size_t      cchString = strlen(pszSource);
     1997        papszDstArray[i] = pszDstStr;
     1998        memcpy(pszDstStr, pszSource, cchString);
     1999        pszDstStr += cchString;
     2000        *pszDstStr++ = '\0';
    19312001    }
    19322002    *pszDstStr = '\0';
     
    21452215            assert(0);
    21462216            mkWinChildDelete(pChild);
    2147             return dwErr ? dwErr : -1;
     2217            return dwErr ? dwErr : -20;
    21482218        }
    21492219        pOldChild = pCurChild;
     
    23622432 * Interface used to kill process when processing Ctrl-C and fatal errors.
    23632433 *
    2364  * @returns 0 on success, -1+errno on error.
     2434 * @returns 0 on success, -1 & errno on error.
    23652435 * @param   pid                 The process to kill (PWINCHILD).
    23662436 * @param   iSignal             What to kill it with.
Note: See TracChangeset for help on using the changeset viewer.