Changeset 3159 for trunk/src/kmk/w32/winchildren.c
- Timestamp:
- Mar 19, 2018, 2:37:13 PM (7 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/kmk/w32/winchildren.c
r3158 r3159 25 25 26 26 /* No GNU coding style here atm, convert if upstreamed. */ 27 28 /** @page pg_win_children Windows child process creation and managment 29 * 30 * This new implementation aims at addressing the following: 31 * 32 * 1. Speed up process creation by doing the expensive CreateProcess call 33 * in a worker thread. 34 * 35 * 2. No 64 process limit imposed by WaitForMultipleObjects. 36 * 37 * 3. Better distribute jobs among processor groups. 38 * 39 * 4. Offloading more expensive kmkbuiltin operations to worker threads, 40 * making the main thread focus on managing child processes. 41 * 42 * 5. Output synchronization using reusable pipes [not yet implemented]. 43 * 44 * 45 * To be quite honest, the first item (CreateProcess expense) didn't occur to me 46 * at first and was more of a sideeffect discovered along the way. A test 47 * rebuilding IPRT went from 4m52s to 3m19s on a 8 thread system. 48 * 49 * The 2nd and 3rd goals are related to newer build servers that have lots of 50 * CPU threads and various Windows NT (aka NT OS/2 at the time) design choices 51 * made in the late 1980ies. 52 * 53 * WaitForMultipleObjects does not support waiting for more than 64 objects, 54 * unlike poll and select. This is just something everyone ends up having to 55 * work around in the end. 56 * 57 * Affinity masks are uintptr_t sized, so 64-bit hosts can only manage 64 58 * processors and 32-bit only 32. Workaround was introduced with Windows 7 59 * (IIRC) and is called processor groups. The CPU threads are grouped into 1 or 60 * more groups of up to 64 processors. Processes are generally scheduled to a 61 * signle processor group at first, but threads may be changed to be scheduled 62 * on different groups. This code will try distribute children evenly among the 63 * processor groups, using a very simple algorithm (see details in code). 64 * 65 */ 66 27 67 28 68 /********************************************************************************************************************************* … … 66 106 /** Normal child process. */ 67 107 WINCHILDTYPE_PROCESS, 108 #ifdef KMK 68 109 /** kmkbuiltin command. */ 69 110 WINCHILDTYPE_BUILTIN, … … 72 113 /** kmk_redirect job. */ 73 114 WINCHILDTYPE_REDIRECT, 115 #endif 74 116 /** End of valid child types. */ 75 117 WINCHILDTYPE_END … … 247 289 static unsigned volatile g_idxLastChildcareWorker = 0; 248 290 291 /** Temporary RW lock for serializing kmkbuiltin_redirect and CreateProcess. */ 292 static SRWLOCK g_RWLock; 249 293 250 294 … … 320 364 } 321 365 } 366 367 /* Temporary: */ 368 InitializeSRWLock(&g_RWLock); 322 369 } 323 370 … … 1205 1252 if (rc == 0) 1206 1253 { 1254 AcquireSRWLockShared(&g_RWLock); /* temporary */ 1255 1207 1256 /* 1208 1257 * Populate startup info. … … 1248 1297 TRUE /*fInheritHandles*/, fFlags, pwszzEnvironment, NULL /*pwsz*/, &StartupInfo, &ProcInfo); 1249 1298 rc = GetLastError(); 1299 ReleaseSRWLockShared(&g_RWLock); /* temporary */ 1250 1300 if (fRet) 1251 1301 { … … 1315 1365 } 1316 1366 1367 #ifdef KMK 1368 1317 1369 /** 1318 1370 * Childcare worker: handle builtin command. … … 1366 1418 mkWinChildcareWorkerWaitForProcess(pWorker, pChild, pChild->u.Redirect.hProcess); 1367 1419 } 1420 1421 #endif /* KMK */ 1368 1422 1369 1423 /** … … 1435 1489 mkWinChildcareWorkerThreadHandleProcess(pWorker, pChild); 1436 1490 break; 1491 #ifdef KMK 1437 1492 case WINCHILDTYPE_BUILTIN: 1438 1493 mkWinChildcareWorkerThreadHandleBuiltin(pWorker, pChild); … … 1444 1499 mkWinChildcareWorkerThreadHandleRedirect(pWorker, pChild); 1445 1500 break; 1501 #endif 1502 default: 1503 assert(0); 1446 1504 } 1447 1505 … … 1638 1696 } 1639 1697 1698 #ifdef KMK 1699 1640 1700 case WINCHILDTYPE_BUILTIN: 1641 1701 assert(0); … … 1657 1717 } 1658 1718 break; 1719 1720 #endif /* KMK */ 1721 1722 default: 1723 assert(0); 1659 1724 } 1660 1725 … … 1890 1955 } 1891 1956 1957 #ifdef KMK 1958 1892 1959 /** 1893 1960 * Interface used by kSubmit.c for registering stuff to wait on. … … 1919 1986 return mkWinChildPushToCareWorker(pChild, pPid); 1920 1987 } 1988 1989 #endif /* CONFIG_NEW_WIN_CHILDREN */ 1921 1990 1922 1991 /** … … 1943 2012 pChild->iSignal = iSignal; 1944 2013 break; 2014 2015 #ifdef KMK 1945 2016 1946 2017 case WINCHILDTYPE_SUBMIT: … … 1958 2029 case WINCHILDTYPE_BUILTIN: 1959 2030 break; 2031 2032 #endif /* KMK */ 2033 2034 default: 2035 assert(0); 1960 2036 } 1961 2037 } … … 2015 2091 case WINCHILDTYPE_PROCESS: 2016 2092 break; 2093 #ifdef KMK 2017 2094 case WINCHILDTYPE_BUILTIN: 2018 2095 break; … … 2021 2098 case WINCHILDTYPE_REDIRECT: 2022 2099 break; 2100 #endif /* KMK */ 2023 2101 default: 2024 2102 assert(0); 2025 2103 } 2026 2104 mkWinChildDelete(pChild); 2105 2106 #ifdef KMK 2107 /* Flush the volatile directory cache. */ 2108 dir_cache_invalid_after_job(); 2109 #endif 2027 2110 return 0; 2028 2111 } 2029 2112 2030 2113 /** 2114 * Get the child completed event handle. 2115 * 2116 * Needed when w32os.c is waiting for a job token to become available, given 2117 * that completed children is the typical source of these tokens (esp. for kmk). 2118 * 2119 * @returns Event handle. 2120 */ 2031 2121 intptr_t MkWinChildGetCompleteEventHandle(void) 2032 2122 { 2033 2123 return (intptr_t)g_hEvtWaitChildren; 2034 2124 } 2035 2036 2125 2037 2126 /** … … 2053 2142 int rc; 2054 2143 2055 /** @todo this code needs testing... */2056 2057 2144 /* 2058 2145 * Get the executable name. … … 2084 2171 GetStartupInfoW(&StartupInfo); 2085 2172 if (!CreateProcessW(wszImageName, pwszCommandLine, NULL /*pProcSecAttr*/, NULL /*pThreadSecAttr*/, 2086 TRUE /*fInheritHandles*/, 0 /*fFlags*/, pwszzEnvironment, NULL /*pwsz*/,2173 TRUE /*fInheritHandles*/, CREATE_UNICODE_ENVIRONMENT, pwszzEnvironment, NULL /*pwsz*/, 2087 2174 &StartupInfo, &ProcInfo)) 2088 2175 ON(fatal, NILF, _("MkWinChildReExecMake: CreateProcessW failed: %u\n"), GetLastError()); … … 2103 2190 if (dwStatus == WAIT_OBJECT_0) 2104 2191 { 2105 if (GetExitCodeProcess(ProcInfo.hProcess, &dwExitCode)) 2192 if (!GetExitCodeProcess(ProcInfo.hProcess, &dwExitCode)) 2193 { 2106 2194 ON(fatal, NILF, _("MkWinChildReExecMake: GetExitCodeProcess failed: %u\n"), GetLastError()); 2107 else2108 2195 dwExitCode = -2222; 2196 } 2109 2197 } 2110 2198 else if (dwStatus) … … 2117 2205 } 2118 2206 2119 2207 /** Temporary serialization with kmkbuiltin_redirect. */ 2208 void MkWinChildExclusiveAcquire(void) 2209 { 2210 AcquireSRWLockExclusive(&g_RWLock); 2211 } 2212 2213 /** Temporary serialization with kmkbuiltin_redirect. */ 2214 void MkWinChildExclusiveRelease(void) 2215 { 2216 ReleaseSRWLockExclusive(&g_RWLock); 2217 } 2218 2219 /** 2220 * Implementation of the CLOSE_ON_EXEC macro. 2221 * 2222 * @returns errno value. 2223 * @param fd The file descriptor to hide from children. 2224 */ 2120 2225 int MkWinChildUnrelatedCloseOnExec(int fd) 2121 2226 { … … 2128 2233 return 0; 2129 2234 } 2235 return errno; 2130 2236 } 2131 2237 return EINVAL; 2132 2238 } 2133 2239 2134 2135
Note:
See TracChangeset
for help on using the changeset viewer.