2
0

rlfeint.cpp 11 KB

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