| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568 |
- //-------------------------------------------------------------------------------------------------------
- // Copyright (C) Microsoft. All rights reserved.
- // Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.
- //-------------------------------------------------------------------------------------------------------
- #undef UNICODE
- #undef _UNICODE
- #include <windows.h>
- #include <stdio.h>
- #include "rl.h"
- //#define TRACE
- char *RLFEOpts = NULL;
- BOOL FRLFE = FALSE;
- static HANDLE HPipe = INVALID_HANDLE_VALUE;
- static CRITICAL_SECTION CS;
- static BOOL FConnected = FALSE;
- static void SendCommand(RLFE_COMMAND command, DWORD dataLen);
- static int
- SpawnRLFE(
- const char *options
- )
- {
- char cmd[1024];
- char *str = "Unexpected error";
- enum SD_STATUS {
- SD_NONE, SD_IN, SD_ERR, SD_OUT, SD_CREATE
- } status;
- STARTUPINFO si;
- PROCESS_INFORMATION pi;
- SECURITY_ATTRIBUTES sa;
- HANDLE NULStderr = 0, NULStdout = 0, NULStdin = 0;
- sprintf_s(cmd, "rlfe %s", options);
- if (strlen(cmd) > 1023) {
- printf("cmd buffer too small\n");
- return -2;
- }
- sa.nLength = sizeof(sa);
- sa.lpSecurityDescriptor = NULL;
- sa.bInheritHandle = TRUE;
- status = SD_IN;
- NULStdin = CreateFile("NUL", GENERIC_READ,
- FILE_SHARE_READ | FILE_SHARE_WRITE,
- NULL, OPEN_ALWAYS, 0, INVALID_HANDLE_VALUE);
- if (NULStdin == INVALID_HANDLE_VALUE)
- goto cleanup;
- status = SD_ERR;
- NULStderr = CreateFile("NUL", GENERIC_WRITE,
- FILE_SHARE_READ | FILE_SHARE_WRITE,
- NULL, OPEN_ALWAYS, 0, INVALID_HANDLE_VALUE);
- if (NULStderr == INVALID_HANDLE_VALUE)
- goto cleanup;
- status = SD_OUT;
- NULStdout = CreateFile("NUL", GENERIC_WRITE,
- FILE_SHARE_READ | FILE_SHARE_WRITE,
- NULL, OPEN_ALWAYS, 0, INVALID_HANDLE_VALUE);
- if (NULStdout == INVALID_HANDLE_VALUE)
- goto cleanup;
- memset(&si, 0, sizeof(si));
- si.cb = sizeof(si);
- si.dwFlags = STARTF_USESTDHANDLES;
- si.hStdOutput = NULStdout;
- si.hStdError = NULStderr;
- si.hStdInput = NULStdin;
- #ifdef TRACE
- printf("Spawning RLFE (%s)\n", cmd);
- #endif
- status = SD_CREATE;
- if (!CreateProcess(NULL,
- cmd,
- NULL,
- NULL,
- TRUE,
- DETACHED_PROCESS,
- NULL,
- NULL,
- &si,
- &pi))
- goto cleanup;
- status = SD_NONE;
- // Close handles.
- CloseHandle(NULStdin);
- CloseHandle(NULStderr);
- CloseHandle(NULStdout);
- #ifdef TRACE
- printf("Successful spawn\n");
- #endif
- return 0;
- cleanup:
- switch (status) {
- case SD_CREATE:
- CloseHandle(NULStdout);
- case SD_OUT:
- CloseHandle(NULStderr);
- case SD_ERR:
- CloseHandle(NULStdin);
- case SD_IN:
- break;
- }
- switch (status) {
- case SD_CREATE:
- str = "Unable to spawn RL";
- break;
- case SD_ERR:
- case SD_IN:
- case SD_OUT:
- str = "Unable to obtain file handle";
- break;
- }
- printf("%s\n", str);
- return 1;
- }
- // This function takes care of creating the pipe between RL and RLFE and
- // starts RLFE.
- BOOL
- RLFEConnect(
- const char *prefix
- )
- {
- char pipeName[32];
- char options[512], *pOpt, *s;
- char pipeID[9], *pID;
- DWORD id = 0;
- pOpt = options;
- pID = NULL;
- // Parse RLFE options.
- while (RLFEOpts && *RLFEOpts) {
- s = strchr(RLFEOpts, ',');
- if (s)
- *s++ = '\0';
- if (!_stricmp(RLFEOpts, "min"))
- pOpt += sprintf_s(pOpt, REMAININGARRAYLEN(options, pOpt), " -min");
- else if (!_strnicmp(RLFEOpts, "pipe", 4))
- pID = RLFEOpts + 4;
- RLFEOpts = s;
- }
- if (pID == NULL) {
- id = GetCurrentProcessId();
- sprintf_s(pipeID, "%08x", id);
- pID = pipeID;
- }
- sprintf_s(pipeName, "%s%s", PIPE_NAME, pID);
- if (strlen(pipeName) > 31) {
- printf("RLFE pipename buffer too small\n");
- return FALSE;
- }
- pOpt += sprintf_s(pOpt, REMAININGARRAYLEN(options, pOpt), " -pipe %s", pID);
- if (prefix)
- pOpt += sprintf_s(pOpt, REMAININGARRAYLEN(options, pOpt), " -prefix \"%s\"", prefix);
- HPipe = CreateNamedPipe(
- pipeName,
- PIPE_ACCESS_OUTBOUND | FILE_FLAG_WRITE_THROUGH,
- PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_WAIT,
- 1,
- 2048,
- 2048,
- 5 * 1000,
- NULL);
- if (HPipe == INVALID_HANDLE_VALUE) {
- fprintf(stderr, "RLFE pipe creation failed\n");
- return FALSE;
- }
- if (id) {
- if (strlen(options) > 511) {
- printf("RLFE options buffer too small\n");
- return FALSE;
- }
- if (SpawnRLFE(options)) {
- CloseHandle(HPipe);
- return FALSE;
- }
- }
- else {
- printf("Please launch RLFE manually with -pipe %s\n", pID);
- }
- if (!ConnectNamedPipe(HPipe, NULL)) {
- CloseHandle(HPipe);
- fprintf(stderr, "RLFE failed to connected\n");
- return FALSE;
- }
- FConnected = TRUE;
- return TRUE;
- }
- void
- RLFEDisconnect(
- BOOL fKilled
- )
- {
- if (FConnected) {
- if (!fKilled) {
- SendCommand(RLFE_DONE, 0);
- FlushFileBuffers(HPipe);
- }
- DeleteCriticalSection(&CS);
- CloseHandle(HPipe);
- HPipe = INVALID_HANDLE_VALUE;
- FConnected = FALSE;
- }
- FRLFE = FALSE;
- }
- BOOL
- RLFEEnterCritSec(
- void
- )
- {
- EnterCriticalSection(&CS);
- return FRLFE;
- }
- void
- RLFELeaveCritSec(
- void
- )
- {
- LeaveCriticalSection(&CS);
- }
- static void
- SendData(
- BYTE *buf,
- DWORD len
- )
- {
- DWORD wb;
- if (!WriteFile(HPipe, buf, len, &wb, NULL) || (wb != len)) {
- fprintf(stderr, "Write to RLFE pipe failed; RLFE output disabled\n");
- RLFEDisconnect(TRUE);
- }
- }
- static void
- SendCommand(
- RLFE_COMMAND command,
- DWORD dataLen
- )
- {
- BYTE cmdBuf[3];
- cmdBuf[0] = (char)command;
- cmdBuf[1] = BYTE(dataLen / 256);
- cmdBuf[2] = BYTE(dataLen % 256);
- if (RLFEEnterCritSec()) {
- SendData(cmdBuf, 3);
- RLFELeaveCritSec();
- }
- }
- static void
- SendDataWithLen(
- BYTE *data,
- DWORD len
- )
- {
- BYTE lenBuf[2];
- lenBuf[0] = BYTE(len / 256);
- lenBuf[1] = BYTE(len % 256);
- if (RLFEEnterCritSec()) {
- SendData(lenBuf, 2);
- if (len)
- SendData(data, len);
- RLFELeaveCritSec();
- }
- }
- void
- RLFEInit(
- BYTE numThreads,
- int numDirs
- )
- {
- BYTE buf[4];
- ASSERTNR((SHORT)numDirs == numDirs);
- InitializeCriticalSection(&CS);
- #ifdef TRACE
- printf("RLFEAddInit: %d, %d\n", numDirs, numThreads);
- #endif
- *(SHORT *)buf = (SHORT)numDirs;
- buf[2] = numThreads;
- buf[3] = (BYTE)RLFE_VERSION;
- SendCommand(RLFE_INIT, 4);
- SendData(buf, 4);
- }
- static const char *
- StatString(
- RL_STATS stat
- )
- {
- switch (stat) {
- case RLS_TOTAL:
- return "";
- case RLS_EXE:
- return "Exec";
- case RLS_BASELINES:
- return "Baselines";
- case RLS_DIFFS:
- return "Diffs";
- }
- return "RL_ERROR";
- }
- void
- RLFEAddRoot(
- RL_STATS stat,
- DWORD total
- )
- {
- int len;
- const char *path;
- path = StatString(stat);
- len = (int)strlen(path) + 5;
- #ifdef TRACE
- printf("RLFEAddRoot: %d, %d\n", stat, total);
- #endif
- if (RLFEEnterCritSec()) {
- SendCommand(RLFE_ADD_ROOT, len);
- SendData((BYTE *)path, len - 5);
- SendData((BYTE *)&total, 4);
- SendData((BYTE *)&stat, 1);
- RLFELeaveCritSec();
- }
- }
- void
- RLFEAddTest(
- RL_STATS stat,
- CDirectory *pDir
- )
- {
- char *path;
- int len, num;
- path = pDir->GetDirectoryName();
- num = pDir->GetDirectoryNumber();
- ASSERTNR((SHORT)num == num);
- #ifdef TRACE
- printf("RLFEAddTest: %d, %s, %d, %d\n", stat,
- path, num, pDir->NumVariations);
- #endif
- len = (int)strlen(path) + 7;
- if (RLFEEnterCritSec()) {
- SendCommand(RLFE_ADD_TEST, len);
- SendData((BYTE *)path, len - 7);
- SendData((BYTE *)&pDir->NumVariations, 4);
- SendData((BYTE *)&stat, 1);
- SendData((BYTE *)&num, 2);
- RLFELeaveCritSec();
- }
- }
- void
- RLFEAddLog(
- CDirectory *pDir,
- RLFE_STATUS status,
- const char *testName,
- const char *subTestName,
- const char *logText
- )
- {
- int pathLen, logLen, num;
- BYTE buf[4];
- char pathBuf[BUFFER_SIZE], *path;
- ASSERTNR(testName || subTestName);
- ASSERTNR(logText);
- path = pathBuf;
- if (testName)
- path += sprintf_s(path, REMAININGARRAYLEN(pathBuf, path), "%c%s", PIPE_SEP_CHAR, testName);
- if (subTestName)
- path += sprintf_s(path, REMAININGARRAYLEN(pathBuf, path), "%c%s", PIPE_SEP_CHAR, subTestName);
- // String has a leading PIPE_SEP_CHAR, so chop that off.
- path = pathBuf + 1;
- pathLen = (int)strlen(path);
- ASSERTNR(pathLen < BUFFER_SIZE - 1);
- logLen = (int)strlen(logText);
- num = pDir->GetDirectoryNumber();
- ASSERTNR((SHORT)num == num);
- *(SHORT *)buf = (SHORT)num;
- buf[2] = (BYTE)pDir->stat;
- buf[3] = (BYTE)status;
- #ifdef TRACE
- printf("RLFEAddLog: %d, %d, %s, %s\n", pDir->stat, num, path, logText);
- #endif
- if (RLFEEnterCritSec()) {
- SendCommand(RLFE_ADD_LOG, 2 + pathLen + 4 + logLen);
- SendDataWithLen((BYTE *)path, pathLen);
- SendData(buf, 4);
- SendData((BYTE *)logText, logLen);
- RLFELeaveCritSec();
- }
- }
- void
- RLFETestStatus(
- CDirectory *pDir
- )
- {
- DWORD *d;
- BYTE buf[3];
- BYTE statBuf[3 * 4];
- DWORD dataLen;
- int num;
- num = pDir->GetDirectoryNumber();
- ASSERTNR((SHORT)num == num);
- if (pDir->stat == RLS_DIFFS)
- dataLen = 3 * 4;
- else
- dataLen = 2 * 4;
- d = (DWORD *)statBuf;
- *d++ = (int) pDir->NumVariationsRun;
- *d++ = (int) pDir->NumFailures;
- if (pDir->stat == RLS_DIFFS)
- *d++ = (int) pDir->NumDiffs;
- *(SHORT *)buf = (SHORT)num;
- buf[2] = (BYTE)pDir->stat;
- #ifdef TRACE
- printf("RLFETestStatus: %d, %d, %d, %d, %d\n",
- pDir->stat, num, pDir->NumVariationsRun, pDir->NumFailures,
- pDir->NumDiffs);
- #endif
- if (RLFEEnterCritSec()) {
- SendCommand(RLFE_TEST_STATUS, 2 + 1 + dataLen);
- SendData((BYTE *)&buf, 3);
- SendData(statBuf, dataLen);
- RLFELeaveCritSec();
- }
- }
- void
- RLFEThreadDir(
- CDirectory *pDir,
- BYTE threadNum
- )
- {
- BYTE buf[4];
- int num;
- if (pDir) {
- num = pDir->GetDirectoryNumber();
- ASSERTNR((SHORT)num == num);
- }
- else {
- num = 0;
- }
- --threadNum; // RL is 1-based, RLFE is 0-based
- *(SHORT *)buf = (SHORT)num;
- buf[2] = threadNum;
- if (pDir)
- buf[3] = (BYTE)pDir->stat;
- #ifdef TRACE
- printf("RLFEThreadDir: %d, %d, %d\n", num, threadNum, buf[3]);
- #endif
- if (RLFEEnterCritSec()) {
- SendCommand(RLFE_THREAD_DIR, 4);
- SendData(buf, 4);
- RLFELeaveCritSec();
- }
- }
- void
- RLFEThreadStatus(
- BYTE num,
- const char *text
- )
- {
- DWORD len;
- --num; // RL is 1-based, RLFE is 0-based
- len = (DWORD)strlen(text);
- #ifdef TRACE
- printf("RLFEThreadStatus: %d, %s\n", num, text);
- #endif
- if (RLFEEnterCritSec()) {
- SendCommand(RLFE_THREAD_STATUS, len + 1);
- SendData(&num, 1);
- SendData((BYTE *)text, len);
- RLFELeaveCritSec();
- }
- }
|