Changeset 3185 for trunk/src/kmk
- Timestamp:
- Mar 23, 2018, 11:40:03 PM (7 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/kmk/w32/winchildren.c
r3182 r3185 63 63 * processor groups, using a very simple algorithm (see details in code). 64 64 * 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. 65 86 */ 66 87 … … 71 92 #include "../makeint.h" 72 93 #include "../job.h" 94 #include "../filedef.h" 73 95 #include "../debug.h" 74 96 #include "../kmkbuiltin.h" … … 576 598 * @param pChild The child. 577 599 * @param hProcess The process handle. 578 */ 579 static void mkWinChildcareWorkerWaitForProcess(PWINCHILDCAREWORKER pWorker, PWINCHILD pChild, HANDLE hProcess) 580 { 600 * @param pwszJob The job name. 601 */ 602 static void mkWinChildcareWorkerWaitForProcess(PWINCHILDCAREWORKER pWorker, PWINCHILD pChild, HANDLE hProcess, 603 WCHAR const *pwszJob) 604 { 605 DWORD const msStart = GetTickCount(); 606 DWORD msNextMsg = msStart + 15000; 581 607 for (;;) 582 608 { 583 609 DWORD dwExitCode = -42; 584 DWORD dwStatus = WaitForSingleObject(hProcess, INFINITE);610 DWORD dwStatus = WaitForSingleObject(hProcess, 15001 /*ms*/); 585 611 assert(dwStatus != WAIT_FAILED); 586 612 if (dwStatus == WAIT_OBJECT_0) … … 593 619 } 594 620 } 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 } 598 648 599 649 /* Something failed. */ … … 1030 1080 { 1031 1081 fprintf(stderr, "%s: not found!\n", papszArgs[0]); 1082 //__debugbreak(); 1032 1083 return ERROR_FILE_NOT_FOUND; 1033 1084 } … … 1175 1226 if (cwcAbsPath > 0) 1176 1227 { 1177 cwc AbsPath = cwcPath + 1; /* include terminator, like MultiByteToWideChar does. */1228 cwcPath = cwcAbsPath + 1; /* include terminator, like MultiByteToWideChar does. */ 1178 1229 pwszPath = wszPathBuf; 1179 1230 } … … 1181 1232 1182 1233 /* 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. 1184 1237 */ 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 1200 1264 { 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 } 1218 1274 } 1219 1275 } … … 1274 1330 if (cwcComponent > 0 && cwcCombined <= MKWINCHILD_MAX_PATH) 1275 1331 { 1332 #ifndef KMK 1276 1333 DWORD dwAttribs; 1334 #endif 1277 1335 1278 1336 /* Copy the component into wszPathBuf, maybe abspath'ing it. */ … … 1327 1385 wszPathBuf[cwcCombined + 3] = L'\0'; 1328 1386 } 1387 #ifdef KMK 1388 if (utf16_regular_file_p(wszPathBuf)) 1389 #else 1329 1390 dwAttribs = GetFileAttributesW(wszPathBuf); 1330 1391 if ( dwAttribs != INVALID_FILE_ATTRIBUTES 1331 1392 && !(dwAttribs & FILE_ATTRIBUTE_DIRECTORY)) 1393 #endif 1332 1394 return mkWinChildDuplicateUtf16String(wszPathBuf, cwcCombined + (fHasExeSuffix ? 0 : 4), ppwszImagePath); 1333 1395 if (!fHasExeSuffix) 1334 1396 { 1335 1397 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 1344 1401 { 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 } 1350 1416 } 1351 1417 } … … 1385 1451 { 1386 1452 fprintf(stderr, "%s: not found!\n", pszArg0); 1453 //__debugbreak(); 1387 1454 dwErr = ERROR_FILE_NOT_FOUND; 1388 1455 } … … 1603 1670 * Wait for the child to complete. 1604 1671 */ 1605 mkWinChildcareWorkerWaitForProcess(pWorker, pChild, pChild->u.Process.hProcess );1672 mkWinChildcareWorkerWaitForProcess(pWorker, pChild, pChild->u.Process.hProcess, pwszImageName); 1606 1673 } 1607 1674 else … … 1720 1787 static void mkWinChildcareWorkerThreadHandleRedirect(PWINCHILDCAREWORKER pWorker, PWINCHILD pChild) 1721 1788 { 1722 mkWinChildcareWorkerWaitForProcess(pWorker, pChild, pChild->u.Redirect.hProcess );1789 mkWinChildcareWorkerWaitForProcess(pWorker, pChild, pChild->u.Redirect.hProcess, L"kmk_redirect"); 1723 1790 } 1724 1791 … … 1926 1993 for (i = 0; i < cStrings; i++) 1927 1994 { 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'; 1931 2001 } 1932 2002 *pszDstStr = '\0'; … … 2145 2215 assert(0); 2146 2216 mkWinChildDelete(pChild); 2147 return dwErr ? dwErr : - 1;2217 return dwErr ? dwErr : -20; 2148 2218 } 2149 2219 pOldChild = pCurChild; … … 2362 2432 * Interface used to kill process when processing Ctrl-C and fatal errors. 2363 2433 * 2364 * @returns 0 on success, -1 +errno on error.2434 * @returns 0 on success, -1 & errno on error. 2365 2435 * @param pid The process to kill (PWINCHILD). 2366 2436 * @param iSignal What to kill it with.
Note:
See TracChangeset
for help on using the changeset viewer.