rlfeint.cpp 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568
  1. //-------------------------------------------------------------------------------------------------------
  2. // Copyright (C) Microsoft. All rights reserved.
  3. // Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.
  4. //-------------------------------------------------------------------------------------------------------
  5. #undef UNICODE
  6. #undef _UNICODE
  7. #include <windows.h>
  8. #include <stdio.h>
  9. #include "rl.h"
  10. //#define TRACE
  11. char *RLFEOpts = NULL;
  12. BOOL FRLFE = FALSE;
  13. static HANDLE HPipe = INVALID_HANDLE_VALUE;
  14. static CRITICAL_SECTION CS;
  15. static BOOL FConnected = FALSE;
  16. static void SendCommand(RLFE_COMMAND command, DWORD dataLen);
  17. static int
  18. SpawnRLFE(
  19. const char *options
  20. )
  21. {
  22. char cmd[1024];
  23. const char *str = "Unexpected error";
  24. enum SD_STATUS {
  25. SD_NONE, SD_IN, SD_ERR, SD_OUT, SD_CREATE
  26. } status;
  27. STARTUPINFO si;
  28. PROCESS_INFORMATION pi;
  29. SECURITY_ATTRIBUTES sa;
  30. HANDLE NULStderr = 0, NULStdout = 0, NULStdin = 0;
  31. sprintf_s(cmd, "rlfe %s", options);
  32. if (strlen(cmd) > 1023) {
  33. printf("cmd buffer too small\n");
  34. return -2;
  35. }
  36. sa.nLength = sizeof(sa);
  37. sa.lpSecurityDescriptor = NULL;
  38. sa.bInheritHandle = TRUE;
  39. status = SD_IN;
  40. NULStdin = CreateFile("NUL", GENERIC_READ,
  41. FILE_SHARE_READ | FILE_SHARE_WRITE,
  42. NULL, OPEN_ALWAYS, 0, INVALID_HANDLE_VALUE);
  43. if (NULStdin == INVALID_HANDLE_VALUE)
  44. goto cleanup;
  45. status = SD_ERR;
  46. NULStderr = CreateFile("NUL", GENERIC_WRITE,
  47. FILE_SHARE_READ | FILE_SHARE_WRITE,
  48. NULL, OPEN_ALWAYS, 0, INVALID_HANDLE_VALUE);
  49. if (NULStderr == INVALID_HANDLE_VALUE)
  50. goto cleanup;
  51. status = SD_OUT;
  52. NULStdout = CreateFile("NUL", GENERIC_WRITE,
  53. FILE_SHARE_READ | FILE_SHARE_WRITE,
  54. NULL, OPEN_ALWAYS, 0, INVALID_HANDLE_VALUE);
  55. if (NULStdout == INVALID_HANDLE_VALUE)
  56. goto cleanup;
  57. memset(&si, 0, sizeof(si));
  58. si.cb = sizeof(si);
  59. si.dwFlags = STARTF_USESTDHANDLES;
  60. si.hStdOutput = NULStdout;
  61. si.hStdError = NULStderr;
  62. si.hStdInput = NULStdin;
  63. #ifdef TRACE
  64. printf("Spawning RLFE (%s)\n", cmd);
  65. #endif
  66. status = SD_CREATE;
  67. if (!CreateProcess(NULL,
  68. cmd,
  69. NULL,
  70. NULL,
  71. TRUE,
  72. DETACHED_PROCESS,
  73. NULL,
  74. NULL,
  75. &si,
  76. &pi))
  77. goto cleanup;
  78. status = SD_NONE;
  79. // Close handles.
  80. CloseHandle(NULStdin);
  81. CloseHandle(NULStderr);
  82. CloseHandle(NULStdout);
  83. #ifdef TRACE
  84. printf("Successful spawn\n");
  85. #endif
  86. return 0;
  87. cleanup:
  88. switch (status) {
  89. case SD_CREATE:
  90. CloseHandle(NULStdout);
  91. case SD_OUT:
  92. CloseHandle(NULStderr);
  93. case SD_ERR:
  94. CloseHandle(NULStdin);
  95. case SD_IN:
  96. break;
  97. }
  98. switch (status) {
  99. case SD_CREATE:
  100. str = "Unable to spawn RL";
  101. break;
  102. case SD_ERR:
  103. case SD_IN:
  104. case SD_OUT:
  105. str = "Unable to obtain file handle";
  106. break;
  107. }
  108. printf("%s\n", str);
  109. return 1;
  110. }
  111. // This function takes care of creating the pipe between RL and RLFE and
  112. // starts RLFE.
  113. BOOL
  114. RLFEConnect(
  115. const char *prefix
  116. )
  117. {
  118. char pipeName[32];
  119. char options[512], *pOpt, *s;
  120. char pipeID[9], *pID;
  121. DWORD id = 0;
  122. pOpt = options;
  123. pID = NULL;
  124. // Parse RLFE options.
  125. while (RLFEOpts && *RLFEOpts) {
  126. s = strchr(RLFEOpts, ',');
  127. if (s)
  128. *s++ = '\0';
  129. if (!_stricmp(RLFEOpts, "min"))
  130. pOpt += sprintf_s(pOpt, REMAININGARRAYLEN(options, pOpt), " -min");
  131. else if (!_strnicmp(RLFEOpts, "pipe", 4))
  132. pID = RLFEOpts + 4;
  133. RLFEOpts = s;
  134. }
  135. if (pID == NULL) {
  136. id = GetCurrentProcessId();
  137. sprintf_s(pipeID, "%08x", id);
  138. pID = pipeID;
  139. }
  140. sprintf_s(pipeName, "%s%s", PIPE_NAME, pID);
  141. if (strlen(pipeName) > 31) {
  142. printf("RLFE pipename buffer too small\n");
  143. return FALSE;
  144. }
  145. pOpt += sprintf_s(pOpt, REMAININGARRAYLEN(options, pOpt), " -pipe %s", pID);
  146. if (prefix)
  147. pOpt += sprintf_s(pOpt, REMAININGARRAYLEN(options, pOpt), " -prefix \"%s\"", prefix);
  148. HPipe = CreateNamedPipe(
  149. pipeName,
  150. PIPE_ACCESS_OUTBOUND | FILE_FLAG_WRITE_THROUGH,
  151. PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_WAIT,
  152. 1,
  153. 2048,
  154. 2048,
  155. 5 * 1000,
  156. NULL);
  157. if (HPipe == INVALID_HANDLE_VALUE) {
  158. fprintf(stderr, "RLFE pipe creation failed\n");
  159. return FALSE;
  160. }
  161. if (id) {
  162. if (strlen(options) > 511) {
  163. printf("RLFE options buffer too small\n");
  164. return FALSE;
  165. }
  166. if (SpawnRLFE(options)) {
  167. CloseHandle(HPipe);
  168. return FALSE;
  169. }
  170. }
  171. else {
  172. printf("Please launch RLFE manually with -pipe %s\n", pID);
  173. }
  174. if (!ConnectNamedPipe(HPipe, NULL)) {
  175. CloseHandle(HPipe);
  176. fprintf(stderr, "RLFE failed to connected\n");
  177. return FALSE;
  178. }
  179. FConnected = TRUE;
  180. return TRUE;
  181. }
  182. void
  183. RLFEDisconnect(
  184. BOOL fKilled
  185. )
  186. {
  187. if (FConnected) {
  188. if (!fKilled) {
  189. SendCommand(RLFE_DONE, 0);
  190. FlushFileBuffers(HPipe);
  191. }
  192. DeleteCriticalSection(&CS);
  193. CloseHandle(HPipe);
  194. HPipe = INVALID_HANDLE_VALUE;
  195. FConnected = FALSE;
  196. }
  197. FRLFE = FALSE;
  198. }
  199. BOOL
  200. RLFEEnterCritSec(
  201. void
  202. )
  203. {
  204. EnterCriticalSection(&CS);
  205. return FRLFE;
  206. }
  207. void
  208. RLFELeaveCritSec(
  209. void
  210. )
  211. {
  212. LeaveCriticalSection(&CS);
  213. }
  214. static void
  215. SendData(
  216. BYTE *buf,
  217. DWORD len
  218. )
  219. {
  220. DWORD wb;
  221. if (!WriteFile(HPipe, buf, len, &wb, NULL) || (wb != len)) {
  222. fprintf(stderr, "Write to RLFE pipe failed; RLFE output disabled\n");
  223. RLFEDisconnect(TRUE);
  224. }
  225. }
  226. static void
  227. SendCommand(
  228. RLFE_COMMAND command,
  229. DWORD dataLen
  230. )
  231. {
  232. BYTE cmdBuf[3];
  233. cmdBuf[0] = (char)command;
  234. cmdBuf[1] = BYTE(dataLen / 256);
  235. cmdBuf[2] = BYTE(dataLen % 256);
  236. if (RLFEEnterCritSec()) {
  237. SendData(cmdBuf, 3);
  238. RLFELeaveCritSec();
  239. }
  240. }
  241. static void
  242. SendDataWithLen(
  243. BYTE *data,
  244. DWORD len
  245. )
  246. {
  247. BYTE lenBuf[2];
  248. lenBuf[0] = BYTE(len / 256);
  249. lenBuf[1] = BYTE(len % 256);
  250. if (RLFEEnterCritSec()) {
  251. SendData(lenBuf, 2);
  252. if (len)
  253. SendData(data, len);
  254. RLFELeaveCritSec();
  255. }
  256. }
  257. void
  258. RLFEInit(
  259. BYTE numThreads,
  260. int numDirs
  261. )
  262. {
  263. BYTE buf[4];
  264. ASSERTNR((SHORT)numDirs == numDirs);
  265. InitializeCriticalSection(&CS);
  266. #ifdef TRACE
  267. printf("RLFEAddInit: %d, %d\n", numDirs, numThreads);
  268. #endif
  269. *(SHORT *)buf = (SHORT)numDirs;
  270. buf[2] = numThreads;
  271. buf[3] = (BYTE)RLFE_VERSION;
  272. SendCommand(RLFE_INIT, 4);
  273. SendData(buf, 4);
  274. }
  275. static const char *
  276. StatString(
  277. RL_STATS stat
  278. )
  279. {
  280. switch (stat) {
  281. case RLS_TOTAL:
  282. return "";
  283. case RLS_EXE:
  284. return "Exec";
  285. case RLS_BASELINES:
  286. return "Baselines";
  287. case RLS_DIFFS:
  288. return "Diffs";
  289. }
  290. return "RL_ERROR";
  291. }
  292. void
  293. RLFEAddRoot(
  294. RL_STATS stat,
  295. DWORD total
  296. )
  297. {
  298. int len;
  299. const char *path;
  300. path = StatString(stat);
  301. len = (int)strlen(path) + 5;
  302. #ifdef TRACE
  303. printf("RLFEAddRoot: %d, %d\n", stat, total);
  304. #endif
  305. if (RLFEEnterCritSec()) {
  306. SendCommand(RLFE_ADD_ROOT, len);
  307. SendData((BYTE *)path, len - 5);
  308. SendData((BYTE *)&total, 4);
  309. SendData((BYTE *)&stat, 1);
  310. RLFELeaveCritSec();
  311. }
  312. }
  313. void
  314. RLFEAddTest(
  315. RL_STATS stat,
  316. CDirectory *pDir
  317. )
  318. {
  319. const char *path;
  320. int len, num;
  321. path = pDir->GetDirectoryName();
  322. num = pDir->GetDirectoryNumber();
  323. ASSERTNR((SHORT)num == num);
  324. #ifdef TRACE
  325. printf("RLFEAddTest: %d, %s, %d, %d\n", stat,
  326. path, num, pDir->NumVariations);
  327. #endif
  328. len = (int)strlen(path) + 7;
  329. if (RLFEEnterCritSec()) {
  330. SendCommand(RLFE_ADD_TEST, len);
  331. SendData((BYTE *)path, len - 7);
  332. SendData((BYTE *)&pDir->NumVariations, 4);
  333. SendData((BYTE *)&stat, 1);
  334. SendData((BYTE *)&num, 2);
  335. RLFELeaveCritSec();
  336. }
  337. }
  338. void
  339. RLFEAddLog(
  340. CDirectory *pDir,
  341. RLFE_STATUS status,
  342. const char *testName,
  343. const char *subTestName,
  344. const char *logText
  345. )
  346. {
  347. int pathLen, logLen, num;
  348. BYTE buf[4];
  349. char pathBuf[BUFFER_SIZE], *path;
  350. ASSERTNR(testName || subTestName);
  351. ASSERTNR(logText);
  352. path = pathBuf;
  353. if (testName)
  354. path += sprintf_s(path, REMAININGARRAYLEN(pathBuf, path), "%c%s", PIPE_SEP_CHAR, testName);
  355. if (subTestName)
  356. path += sprintf_s(path, REMAININGARRAYLEN(pathBuf, path), "%c%s", PIPE_SEP_CHAR, subTestName);
  357. // String has a leading PIPE_SEP_CHAR, so chop that off.
  358. path = pathBuf + 1;
  359. pathLen = (int)strlen(path);
  360. ASSERTNR(pathLen < BUFFER_SIZE - 1);
  361. logLen = (int)strlen(logText);
  362. num = pDir->GetDirectoryNumber();
  363. ASSERTNR((SHORT)num == num);
  364. *(SHORT *)buf = (SHORT)num;
  365. buf[2] = (BYTE)pDir->stat;
  366. buf[3] = (BYTE)status;
  367. #ifdef TRACE
  368. printf("RLFEAddLog: %d, %d, %s, %s\n", pDir->stat, num, path, logText);
  369. #endif
  370. if (RLFEEnterCritSec()) {
  371. SendCommand(RLFE_ADD_LOG, 2 + pathLen + 4 + logLen);
  372. SendDataWithLen((BYTE *)path, pathLen);
  373. SendData(buf, 4);
  374. SendData((BYTE *)logText, logLen);
  375. RLFELeaveCritSec();
  376. }
  377. }
  378. void
  379. RLFETestStatus(
  380. CDirectory *pDir
  381. )
  382. {
  383. DWORD *d;
  384. BYTE buf[3];
  385. BYTE statBuf[3 * 4];
  386. DWORD dataLen;
  387. int num;
  388. num = pDir->GetDirectoryNumber();
  389. ASSERTNR((SHORT)num == num);
  390. if (pDir->stat == RLS_DIFFS)
  391. dataLen = 3 * 4;
  392. else
  393. dataLen = 2 * 4;
  394. d = (DWORD *)statBuf;
  395. *d++ = (int) pDir->NumVariationsRun;
  396. *d++ = (int) pDir->NumFailures;
  397. if (pDir->stat == RLS_DIFFS)
  398. *d++ = (int) pDir->NumDiffs;
  399. *(SHORT *)buf = (SHORT)num;
  400. buf[2] = (BYTE)pDir->stat;
  401. #ifdef TRACE
  402. printf("RLFETestStatus: %d, %d, %d, %d, %d\n",
  403. pDir->stat, num, pDir->NumVariationsRun, pDir->NumFailures,
  404. pDir->NumDiffs);
  405. #endif
  406. if (RLFEEnterCritSec()) {
  407. SendCommand(RLFE_TEST_STATUS, 2 + 1 + dataLen);
  408. SendData((BYTE *)&buf, 3);
  409. SendData(statBuf, dataLen);
  410. RLFELeaveCritSec();
  411. }
  412. }
  413. void
  414. RLFEThreadDir(
  415. CDirectory *pDir,
  416. BYTE threadNum
  417. )
  418. {
  419. BYTE buf[4];
  420. int num;
  421. if (pDir) {
  422. num = pDir->GetDirectoryNumber();
  423. ASSERTNR((SHORT)num == num);
  424. }
  425. else {
  426. num = 0;
  427. }
  428. --threadNum; // RL is 1-based, RLFE is 0-based
  429. *(SHORT *)buf = (SHORT)num;
  430. buf[2] = threadNum;
  431. if (pDir)
  432. buf[3] = (BYTE)pDir->stat;
  433. #ifdef TRACE
  434. printf("RLFEThreadDir: %d, %d, %d\n", num, threadNum, buf[3]);
  435. #endif
  436. if (RLFEEnterCritSec()) {
  437. SendCommand(RLFE_THREAD_DIR, 4);
  438. SendData(buf, 4);
  439. RLFELeaveCritSec();
  440. }
  441. }
  442. void
  443. RLFEThreadStatus(
  444. BYTE num,
  445. const char *text
  446. )
  447. {
  448. DWORD len;
  449. --num; // RL is 1-based, RLFE is 0-based
  450. len = (DWORD)strlen(text);
  451. #ifdef TRACE
  452. printf("RLFEThreadStatus: %d, %s\n", num, text);
  453. #endif
  454. if (RLFEEnterCritSec()) {
  455. SendCommand(RLFE_THREAD_STATUS, len + 1);
  456. SendData(&num, 1);
  457. SendData((BYTE *)text, len);
  458. RLFELeaveCritSec();
  459. }
  460. }