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);
}
Example #2
0
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;
}
Example #3
0
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;
}