void SetLogPathName() { // NOTE: under PAL, we don't get the comand line, so we depend on the random number generator to give us a unique // filename. WCHAR* OriginalExecutableName = GetCommandLineW(); // TODO-Cleanup: not cool to write to the process view of commandline.... size_t len = wcslen(OriginalExecutableName); WCHAR* ExecutableName = new WCHAR[len + 1]; wcscpy_s(ExecutableName, len + 1, OriginalExecutableName); ExecutableName[len] = W('\0'); WCHAR* quote1 = NULL; // if there are any quotes in filename convert them to spaces. while ((quote1 = wcsstr(ExecutableName, W("\""))) != NULL) *quote1 = W(' '); // remove any illegal or annoying characters from file name by converting them to underscores while ((quote1 = wcspbrk(ExecutableName, W("=<>:\"/\\|?! *.,"))) != NULL) *quote1 = W('_'); const WCHAR* DataFileExtension = W(".mc"); size_t ExecutableNameLength = wcslen(ExecutableName); size_t DataFileExtensionLength = wcslen(DataFileExtension); size_t logPathLength = wcslen(g_logPath); size_t dataFileNameLength = logPathLength + 1 + ExecutableNameLength + 1 + DataFileExtensionLength + 1; const size_t MaxAcceptablePathLength = MAX_PATH - 20; // subtract 20 to leave buffer, for possible random number addition if (dataFileNameLength >= MaxAcceptablePathLength) { // The path name is too long; creating the file will fail. This can happen because we use the command line, // which for ngen includes lots of environment variables, for example. // Assume (!) the extra space is all in the ExecutableName, so shorten that. ExecutableNameLength -= dataFileNameLength - MaxAcceptablePathLength; dataFileNameLength = MaxAcceptablePathLength; } // Always add a random number, just in case the above doesn't give us a unique filename. #ifdef FEATURE_PAL unsigned __int64 randNumber = 0; const size_t RandNumberLength = sizeof(randNumber) * 2 + 1; // 16 hex digits + null WCHAR RandNumberString[RandNumberLength]; PAL_Random(&randNumber, sizeof(randNumber)); swprintf_s(RandNumberString, RandNumberLength, W("%016llX"), randNumber); #else // !FEATURE_PAL unsigned int randNumber = 0; const size_t RandNumberLength = sizeof(randNumber) * 2 + 1; // 8 hex digits + null WCHAR RandNumberString[RandNumberLength]; rand_s(&randNumber); swprintf_s(RandNumberString, RandNumberLength, W("%08X"), randNumber); #endif // !FEATURE_PAL dataFileNameLength += RandNumberLength - 1; // Construct the full pathname we're going to use. g_dataFileName = new WCHAR[dataFileNameLength]; g_dataFileName[0] = 0; wcsncat_s(g_dataFileName, dataFileNameLength, g_logPath, logPathLength); wcsncat_s(g_dataFileName, dataFileNameLength, DIRECTORY_SEPARATOR_STR_W, 1); wcsncat_s(g_dataFileName, dataFileNameLength, ExecutableName, ExecutableNameLength); if (RandNumberLength > 0) { wcsncat_s(g_dataFileName, dataFileNameLength, RandNumberString, RandNumberLength); } wcsncat_s(g_dataFileName, dataFileNameLength, DataFileExtension, DataFileExtensionLength); }
int doParallelSuperPMI(CommandLine::Options& o) { HRESULT hr = E_FAIL; SimpleTimer st; st.Start(); #ifndef FEATURE_PAL // TODO-Porting: handle Ctrl-C signals gracefully on Unix //Register a ConsoleCtrlHandler if (!SetConsoleCtrlHandler(CtrlHandler, TRUE)) { LogError("Failed to set control handler."); return 1; } #endif // !FEATURE_PAL char tempPath[MAX_PATH]; if (!GetTempPath(MAX_PATH, tempPath)) { LogError("Failed to get path to temp folder."); return 1; } if (o.workerCount <= 0) { //Use the default value which is the number of processors on the machine. SYSTEM_INFO sysinfo; GetSystemInfo(&sysinfo); o.workerCount = sysinfo.dwNumberOfProcessors; //If we ever execute on a machine which has more than MAXIMUM_WAIT_OBJECTS(64) CPU cores //we still can't spawn more than the max supported by WaitForMultipleObjects() if (o.workerCount > MAXIMUM_WAIT_OBJECTS) o.workerCount = MAXIMUM_WAIT_OBJECTS; } // Obtain the folder path of the current executable, which we will use to spawn ourself. char* spmiFilename = new char[MAX_PATH]; if (!GetModuleFileName(NULL, spmiFilename, MAX_PATH)) { LogError("Failed to get current exe path."); return 1; } char* spmiArgs = ConstructChildProcessArgs(o); // TODO: merge all this output to a single call to LogVerbose to avoid all the newlines. LogVerbose("Using child (%s) with args (%s)", spmiFilename, spmiArgs); if (o.mclFilename != nullptr) LogVerbose(" failingMCList=%s", o.mclFilename); if (o.diffMCLFilename != nullptr) LogVerbose(" diffMCLFilename=%s", o.diffMCLFilename); LogVerbose(" workerCount=%d, skipCleanup=%d.", o.workerCount, o.skipCleanup); HANDLE *hProcesses = new HANDLE[o.workerCount]; HANDLE *hStdOutput = new HANDLE[o.workerCount]; HANDLE *hStdError = new HANDLE[o.workerCount]; char** arrFailingMCListPath = new char*[o.workerCount]; char** arrDiffMCListPath = new char*[o.workerCount]; char** arrStdOutputPath = new char*[o.workerCount]; char** arrStdErrorPath = new char*[o.workerCount]; // Add a random number to the temporary file names to allow multiple parallel SuperPMI to happen at once. unsigned int randNumber = 0; #ifdef FEATURE_PAL PAL_Random(/* bStrong */ FALSE, &randNumber, sizeof(randNumber)); #else // !FEATURE_PAL rand_s(&randNumber); #endif // !FEATURE_PAL for (int i = 0; i < o.workerCount; i++) { if (o.mclFilename != nullptr) { arrFailingMCListPath[i] = new char[MAX_PATH]; sprintf_s(arrFailingMCListPath[i], MAX_PATH, "%sParallelSuperPMI-%u-%d.mcl", tempPath, randNumber, i); } else { arrFailingMCListPath[i] = nullptr; } if (o.diffMCLFilename != nullptr) { arrDiffMCListPath[i] = new char[MAX_PATH]; sprintf_s(arrDiffMCListPath[i], MAX_PATH, "%sParallelSuperPMI-Diff-%u-%d.mcl", tempPath, randNumber, i); } else { arrDiffMCListPath[i] = nullptr; } arrStdOutputPath[i] = new char[MAX_PATH]; arrStdErrorPath[i] = new char[MAX_PATH]; sprintf_s(arrStdOutputPath[i], MAX_PATH, "%sParallelSuperPMI-stdout-%u-%d.txt", tempPath, randNumber, i); sprintf_s(arrStdErrorPath[i], MAX_PATH, "%sParallelSuperPMI-stderr-%u-%d.txt", tempPath, randNumber, i); } char cmdLine[MAX_CMDLINE_SIZE]; cmdLine[0] = '\0'; int bytesWritten; for (int i = 0; i < o.workerCount; i++) { bytesWritten = sprintf_s(cmdLine, MAX_CMDLINE_SIZE, "%s -stride %d %d", spmiFilename, i + 1, o.workerCount); if (o.mclFilename != nullptr) { bytesWritten += sprintf_s(cmdLine + bytesWritten, MAX_CMDLINE_SIZE - bytesWritten, " -failingMCList %s", arrFailingMCListPath[i]); } if (o.diffMCLFilename != nullptr) { bytesWritten += sprintf_s(cmdLine + bytesWritten, MAX_CMDLINE_SIZE - bytesWritten, " -diffMCList %s", arrDiffMCListPath[i]); } bytesWritten += sprintf_s(cmdLine + bytesWritten, MAX_CMDLINE_SIZE - bytesWritten, " -v ewmin %s", spmiArgs); SECURITY_ATTRIBUTES sa; sa.nLength = sizeof(sa); sa.lpSecurityDescriptor = NULL; sa.bInheritHandle = TRUE; // Let newly created stdout/stderr handles be inherited. LogDebug("stdout %i=%s", i, arrStdOutputPath[i]); hStdOutput[i] = CreateFileA(arrStdOutputPath[i], GENERIC_WRITE, FILE_SHARE_READ, &sa, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); if (hStdOutput[i] == INVALID_HANDLE_VALUE) { LogError("Unable to open '%s'. GetLastError()=%u", arrStdOutputPath[i], GetLastError()); return -1; } LogDebug("stderr %i=%s", i, arrStdErrorPath[i]); hStdError[i] = CreateFileA(arrStdErrorPath[i], GENERIC_WRITE, FILE_SHARE_READ, &sa, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); if (hStdError[i] == INVALID_HANDLE_VALUE) { LogError("Unable to open '%s'. GetLastError()=%u", arrStdErrorPath[i], GetLastError()); return -1; } //Create a SuperPMI worker process and redirect its output to file if (!StartProcess(cmdLine, hStdOutput[i], hStdError[i], &hProcesses[i])) { return -1; } } WaitForMultipleObjects(o.workerCount, hProcesses, true, INFINITE); // Close stdout/stderr for (int i = 0; i < o.workerCount; i++) { CloseHandle(hStdOutput[i]); CloseHandle(hStdError[i]); } DWORD exitCode = 0; // 0 == assume success if (!closeRequested) { // Figure out the error code to use. We use the largest magnitude error code of the children. // Mainly, if any child returns non-zero, we want to return non-zero, to indicate failure. for (int i = 0; i < o.workerCount; i++) { DWORD exitCodeTmp; BOOL ok = GetExitCodeProcess(hProcesses[i], &exitCodeTmp); if (ok && (exitCodeTmp > exitCode)) { exitCode = exitCodeTmp; } } bool usageError = false; //variable to flag if we hit a usage error in SuperPMI int loaded = 0, jitted = 0, failed = 0, diffs = 0; //Read the stderr files and log them as errors //Read the stdout files and parse them for counts and log any MISSING or ISSUE errors for (int i = 0; i < o.workerCount; i++) { ProcessChildStdErr(arrStdErrorPath[i]); ProcessChildStdOut(o, arrStdOutputPath[i], &loaded, &jitted, &failed, &diffs, &usageError); if (usageError) break; } if (o.mclFilename != nullptr && !usageError) { //Concat the resulting .mcl files MergeWorkerMCLs(o.mclFilename, arrFailingMCListPath, o.workerCount); } if (o.diffMCLFilename != nullptr && !usageError) { //Concat the resulting diff .mcl files MergeWorkerMCLs(o.diffMCLFilename, arrDiffMCListPath, o.workerCount); } if (!usageError) { if (o.applyDiff) { LogInfo(g_AsmDiffsSummaryFormatString, loaded, jitted, failed, diffs); } else { LogInfo(g_SummaryFormatString, loaded, jitted, failed); } } st.Stop(); LogVerbose("Total time: %fms", st.GetMilliseconds()); } if (!o.skipCleanup) { // Delete all temporary files generated for (int i = 0; i < o.workerCount; i++) { if (arrFailingMCListPath[i] != nullptr) { DeleteFile(arrFailingMCListPath[i]); } if (arrDiffMCListPath[i] != nullptr) { DeleteFile(arrDiffMCListPath[i]); } DeleteFile(arrStdOutputPath[i]); DeleteFile(arrStdErrorPath[i]); } } return (int)exitCode; }
HRESULT SetDownLoadDir() { HRESULT hr = S_OK; LPWSTR pszCacheLoc = NULL; if(FAILED(hr = GetCacheLoc(ASM_CACHE_DOWNLOAD, &pszCacheLoc))) goto exit; if( (lstrlen(pszCacheLoc) + lstrlen(FUSION_CACHE_DIR_DOWNLOADED_SZ)) > MAX_PATH ) { hr = HRESULT_FROM_WIN32(FUSION_E_INVALID_NAME); goto exit; } StrCpy(g_DownloadDir, pszCacheLoc); PathRemoveBackslash(g_DownloadDir); StrCat(g_DownloadDir, FUSION_CACHE_DIR_DOWNLOADED_SZ); PathAddBackslash(g_DownloadDir); #define DOWNLOAD_CACHE_OBFUSCATION_LENGTH 16 WIN32_FIND_DATA findData; WCHAR wzPath[MAX_PATH]; HANDLE hFind; BOOL bFoundObfuscated; if (lstrlenW(g_DownloadDir) + (DOWNLOAD_CACHE_OBFUSCATION_LENGTH * 2) + 1 >= MAX_PATH) { hr = HRESULT_FROM_WIN32(ERROR_BUFFER_OVERFLOW); goto exit; } bFoundObfuscated = FALSE; memset(&findData, 0, sizeof(findData)); wnsprintfW(wzPath, MAX_PATH, L"%ws*.*", g_DownloadDir); hFind = FindFirstFile(wzPath, &findData); if (hFind != INVALID_HANDLE_VALUE) { do { if (!lstrcmpW(findData.cFileName, L".") || !lstrcmpW(findData.cFileName, L"..")) { continue; } if (findData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) { lstrcatW(g_DownloadDir, findData.cFileName); bFoundObfuscated = TRUE; break; } } while (FindNextFile(hFind, &findData)); FindClose(hFind); } if (!bFoundObfuscated) { WCHAR wzRandom[(DOWNLOAD_CACHE_OBFUSCATION_LENGTH * 2) + 1]; BYTE bBuffer[DOWNLOAD_CACHE_OBFUSCATION_LENGTH]; if (!PAL_Random(FALSE, bBuffer, DOWNLOAD_CACHE_OBFUSCATION_LENGTH)) { hr = HRESULT_FROM_WIN32(GetLastError()); goto exit; } wzRandom[0] = L'\0'; CParseUtils::BinToUnicodeHex(bBuffer, DOWNLOAD_CACHE_OBFUSCATION_LENGTH, wzRandom); lstrcatW(g_DownloadDir, wzRandom); } // StrCat(g_DownloadDir, szCorVer); exit : return hr; }