rl.h 26 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025
  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. // rl.h
  6. // Header file for rl
  7. #undef UNICODE
  8. #undef _UNICODE
  9. #include <windows.h>
  10. #include <process.h>
  11. #include <io.h>
  12. #include <fcntl.h>
  13. #include <direct.h>
  14. #include <stdio.h>
  15. #include <stdlib.h>
  16. #include <string.h>
  17. #include <time.h>
  18. #include <sys/stat.h>
  19. #include "xmlreader.h"
  20. #include "rlfeint.h"
  21. #pragma warning(disable:4127) // expression is constant, e.g., while(TRUE)
  22. #define LOCAL static
  23. typedef __int32 int32;
  24. typedef unsigned __int32 uint32;
  25. #define BUFFER_SIZE 1024
  26. #define MAXQUEUE 10000
  27. extern void assert(char *file, int line);
  28. #define ASSERT(ex) ((ex) ? (void)0 : assert(__FILE__, __LINE__))
  29. #define ASSERTNR ASSERT
  30. #define UNREACHED FALSE
  31. #define ARRAYLEN(x) (sizeof(x) / sizeof((x)[0]))
  32. #define REMAININGARRAYLEN(a, p) (ASSERT(a <= p && p <= a + ARRAYLEN(a)), ((sizeof(a) - (p - a)) / sizeof((a)[0])))
  33. // Target machines
  34. typedef struct tagTARGETINFO {
  35. char * name;
  36. BOOL fRL_MACHINEonly;
  37. BOOL fAutoCrossCompilation;
  38. BOOL fUseNoGPF;
  39. char * TARGET_VM;
  40. char * LINKFLAGS;
  41. char * NotTags;
  42. } TARGETINFO;
  43. extern TARGETINFO TargetInfo[];
  44. // Any changes made here should have corresponding name added
  45. // to TargetInfo in rl.cpp. NOTE: The TARGET_MACHINES enum is in exactly
  46. // the same order as the TargetInfo array is initialized
  47. typedef enum {
  48. TM_UNKNOWN,
  49. TM_X86,
  50. TM_PPCWCE,
  51. TM_WVM,
  52. TM_WVMCEE,
  53. TM_WVMX86,
  54. TM_MIPS,
  55. TM_ARM,
  56. TM_THUMB,
  57. TM_ARM64,
  58. TM_SH3,
  59. TM_SH4,
  60. TM_SH5C,
  61. TM_SH5M,
  62. TM_IA64,
  63. TM_AMD64,
  64. TM_AMD64SYS,
  65. TM_WVM64,
  66. TM_AM33,
  67. TM_M32R,
  68. TM_MSIL,
  69. TM_ALL
  70. } TARGET_MACHINES;
  71. extern TARGET_MACHINES TargetMachine;
  72. extern TARGET_MACHINES RLMachine;
  73. // Any changes made here should have corresponding name added
  74. // to TargetOSNames in rl.cpp. NOTE: The TARGET_OS enum is in exactly
  75. // the same order as the TargetOSNames array is initialized
  76. typedef enum {
  77. TO_UNKNOWN,
  78. TO_WIN7,
  79. TO_WIN8,
  80. TO_WINBLUE,
  81. TO_WIN10,
  82. TO_WP8,
  83. TO_ALL
  84. } TARGET_OS;
  85. extern TARGET_OS TargetOS;
  86. #define DEFAULT_OS TO_WIN7
  87. #define CFG_ERROR_EX(file,line,fmt,args) fprintf(stderr, "Error: %s(%d) - " ##fmt "\n", file, line, args)
  88. #define CFG_WARNING_EX(file,line,fmt,args) do { if (!FQuiet) printf("Warning: %s(%d) - " ##fmt "\n", file, line, (args)); } while (0)
  89. // Parsing delimiters
  90. #define OPT_DELIM " \t"
  91. #define XML_DELIM ","
  92. #define POGO_TEST_PREFIX "Pogo:"
  93. // Set default target machine based on the host machine
  94. // NOTE: this should be done dynamically, using getenv("PROCESSOR_ARCHITECTURE")
  95. #if defined(_M_IX86)
  96. #define DEFAULT_TM TM_X86
  97. #elif defined(_M_PPC)
  98. #define DEFAULT_TM TM_PPCWCE
  99. #elif defined(_M_MIPS)
  100. #define DEFAULT_TM TM_MIPS
  101. #elif defined(_M_ARM)
  102. #define DEFAULT_TM TM_ARM
  103. #elif defined(_M_ARM64)
  104. #define DEFAULT_TM TM_ARM64
  105. #elif defined(_M_THUMB)
  106. #define DEFAULT_TM TM_THUMB
  107. #elif defined(_M_SH)
  108. #define DEFAULT_TM TM_SH
  109. #elif defined(_M_IA64)
  110. #define DEFAULT_TM TM_IA64
  111. #else
  112. #define DEFAULT_TM TM_X86
  113. #endif
  114. #define RL_PRE_ENV_VAR "RL"
  115. #define RL_POST_ENV_VAR "_RL_"
  116. enum RLMODE
  117. {
  118. RM_ASM, RM_EXE, RM_DIR
  119. };
  120. extern RLMODE Mode;
  121. #define DEFAULT_RLMODE RM_EXE
  122. #define DEFAULT_ASM_DCFG "rlexedirs.xml"
  123. #define DEFAULT_ASM_CFG "rlexe.xml"
  124. #define DEFAULT_ASM_CMD "rl"
  125. #define DEFAULT_EXE_DCFG "rlexedirs.xml"
  126. #define DEFAULT_EXE_CFG "rlexe.xml"
  127. #define DEFAULT_EXE_CMD "rl"
  128. #define DEFAULT_TESTLST_DCFG "test.lst"
  129. #define DEFAULT_ENVLST_CFG "env.lst"
  130. #define DEFAULT_REGR_CL "cl"
  131. #define DEFAULT_REGR_DIFF "diff"
  132. #define DEFAULT_LOG_FILE "rl.log"
  133. #define DEFAULT_FULL_LOG_FILE "rl.full.log"
  134. #define DEFAULT_RESULTS_LOG_FILE "rl.results.log"
  135. #define DEFAULT_CROSS_TARGET_VM "issuerun -id:%d"
  136. #define DEFAULT_LINKER "link"
  137. #define DEFAULT_EXEC_TESTS_FLAGS ";"
  138. #define DEFAULT_TEST_TIMEOUT 60000
  139. #define DIR_LOCKFILE "regrlock.txt"
  140. // Statistics index.
  141. #ifndef _RL_STATS_DEFINED
  142. #define _RL_STATS_DEFINED
  143. typedef enum RL_STATS {
  144. RLS_TOTAL = 0, // overall stats
  145. RLS_EXE, // should == RLS_TOTAL at this time
  146. RLS_BASELINES, // baseline stats (== total if FBaseline && !FDiff)
  147. RLS_DIFFS, // diff stats (== total if FDiff && !FBaseline)
  148. RLS_COUNT
  149. };
  150. #endif
  151. enum ExternalTestKind
  152. {
  153. TK_MAKEFILE,
  154. TK_CMDSCRIPT,
  155. TK_JSCRIPT,
  156. TK_HTML,
  157. TK_COMMAND,
  158. };
  159. enum TestInfoKind
  160. {
  161. TIK_FILES = 0,
  162. TIK_BASELINE,
  163. TIK_COMPILE_FLAGS,
  164. TIK_LINK_FLAGS,
  165. TIK_TAGS,
  166. TIK_RL_DIRECTIVES,
  167. TIK_ENV,
  168. TIK_COMMAND,
  169. TIK_TIMEOUT,
  170. TIK_SOURCE_PATH,
  171. _TIK_COUNT
  172. };
  173. extern const char * const TestInfoKindName[];
  174. struct TestInfo
  175. {
  176. BOOL hasData[_TIK_COUNT];
  177. char * data[_TIK_COUNT];
  178. };
  179. struct Tags
  180. {
  181. Tags * next;
  182. const char * str;
  183. BOOL fInclude;
  184. };
  185. struct ConditionNodeList
  186. {
  187. ConditionNodeList * next;
  188. Xml::Node * node;
  189. };
  190. enum FILE_STATUS
  191. {
  192. FS_NONE, FS_EXCLUDED, FS_INCLUDED
  193. };
  194. enum PROCESS_CONFIG_STATUS
  195. {
  196. PCS_OK, PCS_ERROR, PCS_FILE_NOT_FOUND
  197. };
  198. enum FILE_CONFIG_STATUS
  199. {
  200. FCS_USER_SPECIFIED, FCS_US_FLAGS, FCS_READ
  201. };
  202. struct StringList
  203. {
  204. StringList * next;
  205. char * string;
  206. };
  207. struct TestVariant
  208. {
  209. TestVariant() : next(NULL), optFlags(NULL) {}
  210. TestVariant * next;
  211. // Exe optimization flags.
  212. char * optFlags;
  213. // Test-specific info.
  214. TestInfo testInfo;
  215. };
  216. struct Test
  217. {
  218. Test * next;
  219. // For tests
  220. StringList * files;
  221. // For directories
  222. char * name;
  223. char * fullPath;
  224. int num;
  225. // Common.
  226. ConditionNodeList * conditionNodeList;
  227. TestInfo defaultTestInfo;
  228. TestVariant * variants;
  229. };
  230. struct TestList
  231. {
  232. Test * first;
  233. Test * last;
  234. };
  235. // Time options. Can do multiple types of timings, so do it bitwise
  236. #define TIME_NOTHING 0x0
  237. #define TIME_DIR 0x1
  238. #define TIME_TEST 0x2
  239. #define TIME_VARIATION 0x4
  240. #define TIME_ALL 0x7 // bitmask of all timing options
  241. typedef int TIME_OPTION; // could be enum, but C++ doesn't like |= on enum
  242. extern TIME_OPTION Timing;
  243. /////////////////////////////////////////////////////////////////////////
  244. //
  245. // Class declarations. Non-inline member functions are defined in rlmp.cpp.
  246. //
  247. /////////////////////////////////////////////////////////////////////////
  248. class CProtectedLong;
  249. class CHandle;
  250. class CDirectory;
  251. class CDirectoryQueue;
  252. class CThreadInfo;
  253. class COutputBuffer;
  254. /////////////////////////////////////////////////////////////////////////
  255. // CProtectedLong: a single value protected by a critical section. This is
  256. // used for things like test counts which are accessed by both worker threads
  257. // and the display thread.
  258. class CProtectedLong {
  259. CRITICAL_SECTION _cs;
  260. int32 _value;
  261. public:
  262. CProtectedLong() : _value(0)
  263. {
  264. InitializeCriticalSection(&_cs);
  265. }
  266. ~CProtectedLong()
  267. {
  268. DeleteCriticalSection(&_cs);
  269. }
  270. int32 operator++(int)
  271. {
  272. EnterCriticalSection(&_cs);
  273. int32 tmp = _value++;
  274. LeaveCriticalSection(&_cs);
  275. return tmp;
  276. }
  277. int32 operator--(int)
  278. {
  279. EnterCriticalSection(&_cs);
  280. int32 tmp = _value--;
  281. LeaveCriticalSection(&_cs);
  282. return tmp;
  283. }
  284. int32 operator+=(int32 incr)
  285. {
  286. EnterCriticalSection(&_cs);
  287. int32 tmp = (_value += incr);
  288. LeaveCriticalSection(&_cs);
  289. return tmp;
  290. }
  291. int32 operator=(int32 val)
  292. {
  293. EnterCriticalSection(&_cs);
  294. _value = val;
  295. LeaveCriticalSection(&_cs);
  296. return val;
  297. }
  298. bool operator==(CProtectedLong& rhs)
  299. {
  300. return _value == rhs._value;
  301. }
  302. operator int() { return _value; }
  303. };
  304. /////////////////////////////////////////////////////////////////////////
  305. // CHandle: a convenience class for storing HANDLE objects. When destructed
  306. // or set to another value, the current handle is closed. Helps prevent
  307. // handle leaks.
  308. class CHandle {
  309. HANDLE _h;
  310. public:
  311. CHandle() : _h(INVALID_HANDLE_VALUE) {}
  312. ~CHandle()
  313. {
  314. if (_h != INVALID_HANDLE_VALUE && _h != NULL)
  315. CloseHandle(_h);
  316. }
  317. HANDLE operator=(HANDLE h)
  318. {
  319. if (_h != INVALID_HANDLE_VALUE && _h != NULL)
  320. CloseHandle(_h);
  321. _h = h;
  322. return _h;
  323. }
  324. BOOL operator==(HANDLE h) { return h == _h ? TRUE : FALSE; }
  325. BOOL operator!=(HANDLE h) { return h != _h ? TRUE : FALSE; }
  326. operator HANDLE() { return _h; };
  327. };
  328. /////////////////////////////////////////////////////////////////////////
  329. // WorkObject: a wrapper class for elements used by WorkQueue. Requires
  330. // children classes to implement Dump if debug and keeps track of a _next
  331. // for use by WorkQueue.
  332. template <typename TWorkObject>
  333. class WorkObject {
  334. public:
  335. TWorkObject* _next;
  336. public:
  337. #ifndef NODEBUG
  338. virtual void Dump() = 0;
  339. #endif
  340. };
  341. /////////////////////////////////////////////////////////////////////////
  342. // WorkQueue: a generic class for keeping track of WorkObjects which need
  343. // to be queued and worked on.
  344. template <typename TWorkObject>
  345. class WorkQueue {
  346. protected:
  347. int _length;
  348. TWorkObject* _head;
  349. TWorkObject* _tail;
  350. CRITICAL_SECTION _cs; // ensure proper synchronized access
  351. CHandle _hWorkAvailSem; // signalled whenever there's work on the list
  352. CHandle _hMaxWorkQueueSem; // used to control length of work queue
  353. public:
  354. WorkQueue()
  355. : _head(NULL), _tail(NULL), _length(0)
  356. {
  357. SECURITY_ATTRIBUTES sa;
  358. InitializeCriticalSection(&_cs);
  359. /*
  360. * Create the semaphores for the work lists
  361. */
  362. memset(&sa, 0, sizeof(sa));
  363. sa.nLength = sizeof(sa);
  364. sa.lpSecurityDescriptor = NULL;
  365. sa.bInheritHandle = TRUE;
  366. _hWorkAvailSem = CreateSemaphoreW(&sa, 0, 100000, NULL);
  367. if (_hWorkAvailSem == NULL)
  368. Fatal("Unable to create semaphore (err %u)!\n", GetLastError());
  369. _hMaxWorkQueueSem = CreateSemaphoreW(&sa, MAXQUEUE, MAXQUEUE, NULL);
  370. if (_hMaxWorkQueueSem == NULL)
  371. Fatal("Unable to create queue length semaphore (err %u)!\n", GetLastError());
  372. }
  373. ~WorkQueue()
  374. {
  375. // The CHandle objects clean up after themselves.
  376. DeleteCriticalSection(&_cs);
  377. }
  378. virtual TWorkObject* Pop() = 0;
  379. TWorkObject* Append(TWorkObject* pNew)
  380. {
  381. if (WaitForSingleObject(_hMaxWorkQueueSem, INFINITE) != WAIT_OBJECT_0) {
  382. Fatal("Semaphore wait failed, can't add to work list");
  383. }
  384. EnterCriticalSection(&_cs);
  385. if (_tail == NULL) {
  386. _head = _tail = pNew;
  387. } else {
  388. _tail->_next = pNew;
  389. _tail = pNew;
  390. }
  391. pNew->_next = NULL;
  392. ++_length;
  393. LeaveCriticalSection(&_cs);
  394. ReleaseSemaphore(_hWorkAvailSem, 1, NULL);
  395. return pNew;
  396. }
  397. int Length()
  398. {
  399. int tmp;
  400. EnterCriticalSection(&_cs);
  401. tmp = _length;
  402. LeaveCriticalSection(&_cs);
  403. return tmp;
  404. }
  405. DWORD WaitForWork(DWORD dwMilliseconds)
  406. {
  407. return WaitForSingleObject(_hWorkAvailSem, dwMilliseconds);
  408. }
  409. // The queue work available semaphore has a count for every
  410. // directory. When the queue is exhausted, each thread waits on
  411. // this semaphore again. So at the end, everyone will still be waiting!
  412. // So, add the number of threads to the count, so each thread
  413. // notices, one by one, that everything's done.
  414. void AdjustWaitForThreadCount()
  415. {
  416. ReleaseSemaphore(_hWorkAvailSem, (int)NumberOfThreads, NULL);
  417. }
  418. TWorkObject* GetNextItem()
  419. {
  420. DWORD dwWait = 0;
  421. TWorkObject* toReturn = NULL;
  422. while (TRUE)
  423. {
  424. dwWait = this->WaitForWork(1000);
  425. if (dwWait == WAIT_OBJECT_0) {
  426. // pick an item off the head of the work list
  427. toReturn = this->Pop();
  428. break;
  429. } else if (dwWait == WAIT_TIMEOUT) {
  430. if (bThreadStop)
  431. break;
  432. } else {
  433. LogError("Thread %d: Semaphore wait failed\n", ThreadId);
  434. break;
  435. }
  436. }
  437. if (dwWait != WAIT_OBJECT_0)
  438. return NULL;
  439. if (bThreadStop)
  440. return NULL;
  441. return toReturn;
  442. }
  443. TWorkObject* GetNextItem_NoBlock(DWORD waitTime)
  444. {
  445. DWORD dwWait = 0;
  446. TWorkObject* toReturn = NULL;
  447. dwWait = this->WaitForWork(waitTime);
  448. if(dwWait == WAIT_OBJECT_0) {
  449. // pick an item off the head of the work list
  450. toReturn = this->Pop();
  451. }
  452. return toReturn;
  453. }
  454. #ifndef NODEBUG
  455. void Dump()
  456. {
  457. TWorkObject* tmp;
  458. EnterCriticalSection(&_cs);
  459. printf("WorkQueue, length %d\n", _length);
  460. for (tmp = _head; tmp != NULL; tmp = tmp->_next) {
  461. tmp->Dump();
  462. }
  463. LeaveCriticalSection(&_cs);
  464. }
  465. #endif
  466. };
  467. /////////////////////////////////////////////////////////////////////////
  468. // CDirectory: represents a single directory and the tests that need to
  469. // be run within it.
  470. class CDirectory : public WorkObject<CDirectory> {
  471. friend class CDirectoryQueue;
  472. TestList _testList; // list of files in directory
  473. Test * _pDir; // directory info
  474. CHandle _dirLock; // the directory lock file
  475. bool _isDiffDirectory; // directory is for doing diffs, not masters
  476. bool _isDirStarted; // indicates if the directory has begun executing
  477. time_t start_dir; // time when dir began executing
  478. time_t elapsed_dir; // time taken for dir to execute.
  479. // initialized to 0 but set to a value upon directory finish.
  480. CRITICAL_SECTION _cs; // ensure proper synchronized access
  481. // Try to lock the directory. If we successfully got the lock without
  482. // waiting, return true.
  483. // Note that since we use FILE_FLAG_DELETE_ON_CLOSE, the lock file should
  484. // go away if the process dies because of ctrl-c.
  485. bool TryLock();
  486. // Lock the directory; wait on the lock until it's available
  487. void WaitLock();
  488. // Output begin/finish summaries if all tests in the directory are executed.
  489. void WriteDirectoryBeginSummary();
  490. void WriteDirectoryFinishSummary();
  491. public:
  492. // Multiple threads can be working in a single directory,
  493. // we'll need to make these CProtectedLong.
  494. CProtectedLong NumVariations, NumVariationsRun, NumFailures, NumDiffs;
  495. RL_STATS stat; // which mode stat to update
  496. CDirectory(Test * pDir, TestList testList)
  497. : _pDir(pDir), _testList(testList), _isDiffDirectory(false), _isDirStarted(false), elapsed_dir(0)
  498. {
  499. InitializeCriticalSection(&_cs);
  500. }
  501. ~CDirectory();
  502. TestList * GetTestList() { return &_testList; }
  503. char* GetDirectoryName() { return _pDir->name; }
  504. char* GetDirectoryPath() { return _pDir->fullPath; }
  505. int GetDirectoryNumber() { return _pDir->num; }
  506. BOOL HasTestInfoData(TestInfoKind testInfoKind) { return _pDir->defaultTestInfo.hasData[testInfoKind]; }
  507. char* GetTestInfoData(TestInfoKind testInfoKind) { return _pDir->defaultTestInfo.data[testInfoKind]; }
  508. char* GetFullPathFromSourceOrDirectory() { return HasTestInfoData(TIK_SOURCE_PATH) ? GetTestInfoData(TIK_SOURCE_PATH) : GetDirectoryPath(); }
  509. bool IsBaseline() { return !_isDiffDirectory; }
  510. void SetDiffFlag() { _isDiffDirectory = true; }
  511. void InitStats(int run);
  512. int32 IncRun(int inc = 1);
  513. int32 IncFailures(int inc = 1);
  514. int32 IncDiffs();
  515. // Trigger update of directory state.
  516. void UpdateState();
  517. void TryBeginDirectory();
  518. void TryEndDirectory();
  519. int Count(); // return count of tests in the directory
  520. #ifndef NODEBUG
  521. void Dump();
  522. #endif
  523. };
  524. /////////////////////////////////////////////////////////////////////////
  525. // CDirectoryQueue: a queue of directories that need to have work done.
  526. class CDirectoryQueue : public WorkQueue<CDirectory> {
  527. public:
  528. ~CDirectoryQueue();
  529. // Return a directory to use. Normally, just peel the first one off the
  530. // work queue. However, if that directory is locked by another copy of
  531. // rl.exe, then skip it and try the next directory, until there are no
  532. // directories left. If that happens, just wait on the first locked
  533. // directory.
  534. CDirectory* Pop();
  535. };
  536. /////////////////////////////////////////////////////////////////////////
  537. // CDirectoryAndTestCase: Keep track of directory and test case in a class for
  538. // use in CDirectoryAndTestCaseQueue.
  539. // Reuse CDirectory because it has all the nice profiling data already.
  540. class CDirectoryAndTestCase : public WorkObject<CDirectoryAndTestCase> {
  541. public:
  542. CDirectory* _pDir;
  543. Test* _pTest;
  544. public:
  545. CDirectoryAndTestCase(CDirectory* pDir, Test* pTest)
  546. : _pDir(pDir), _pTest(pTest)
  547. {
  548. _next = NULL;
  549. }
  550. ~CDirectoryAndTestCase()
  551. {
  552. // This class is just a container for CDirectory and Test.
  553. // We don't want to clean up the objects here,
  554. // CDirectory will be cleaned up via ~CDirectoryQueue.
  555. }
  556. #ifndef NODEBUG
  557. void Dump()
  558. {
  559. _pDir->Dump();
  560. }
  561. #endif
  562. };
  563. /////////////////////////////////////////////////////////////////////////
  564. // CDirectoryAndTestCaseQueue: a simple queue to hold CDirectoryAndTestCase objects.
  565. class CDirectoryAndTestCaseQueue : public WorkQueue<CDirectoryAndTestCase> {
  566. public:
  567. CDirectoryAndTestCase* Pop();
  568. };
  569. /////////////////////////////////////////////////////////////////////////
  570. // CThreadInfo: a class with various bits of information about the current
  571. // state of a thread. An array of these objects is created before the worker
  572. // threads are started. This array is accessed like this: ThreadInfo[ThreadId],
  573. // where ThreadId is a __declspec(thread) TLS variable. The status update
  574. // thread uses the info here to construct the title bar.
  575. class CThreadInfo
  576. {
  577. CRITICAL_SECTION _cs;
  578. char _currentTest[BUFFER_SIZE];
  579. bool _isDone;
  580. struct TmpFileList
  581. {
  582. TmpFileList* _next;
  583. char* const _fullPath;
  584. TmpFileList(TmpFileList* next, char* fullPath)
  585. : _next(next), _fullPath(_strdup(fullPath))
  586. {
  587. }
  588. ~TmpFileList()
  589. {
  590. free(_fullPath);
  591. }
  592. TmpFileList(const TmpFileList&) = delete;
  593. void operator=(const TmpFileList&) = delete;
  594. };
  595. TmpFileList* _head;
  596. public:
  597. CThreadInfo()
  598. : _head(NULL), _isDone(false)
  599. {
  600. InitializeCriticalSection(&_cs);
  601. _currentTest[0] = '\0';
  602. }
  603. ~CThreadInfo()
  604. {
  605. ClearTmpFileList();
  606. DeleteCriticalSection(&_cs);
  607. }
  608. bool IsDone() { return _isDone; }
  609. void Done();
  610. // Track current test, for use in creating the title bar
  611. void SetCurrentTest(char* dir, char* test, bool isBaseline);
  612. template <size_t bufSize>
  613. void GetCurrentTest(char (&currentTest)[bufSize])
  614. {
  615. EnterCriticalSection(&_cs);
  616. strcpy_s(currentTest, _currentTest);
  617. LeaveCriticalSection(&_cs);
  618. }
  619. // Track currently in-use temp files, so we can clean them up if we exit
  620. // by ctrl-c.
  621. void AddToTmpFileList(char* fullPath);
  622. void ClearTmpFileList();
  623. void DeleteTmpFileList();
  624. };
  625. /////////////////////////////////////////////////////////////////////////
  626. // COutputBuffer: a buffered output class. Store up output so it can
  627. // all be flushed at once. Used to keep per-thread output from
  628. // interleaving too much and becoming unreadable. This class is
  629. // not synchronized. It is expected that there is one of these objects per
  630. // output location (stdout, file, etc) per thread. Flushing the output *is*
  631. // synchronized on a critical section that should be used around *all*
  632. // worker thread stdio. (Actually, all normal output should go through this
  633. // class.) A NULL file or filename is allowed, in which case everything
  634. // happens as normal, but the Flush() operation doesn't display anything or
  635. // send anything to disk.
  636. class COutputBuffer
  637. {
  638. char* _start;
  639. char* _end;
  640. bool _buffered; // true == buffer output; false == flush immediately (e.g., primary thread)
  641. bool _textGrabbed; // true == someone grabbed the text, used for asserting
  642. size_t _bufSize;
  643. enum { OUT_ILLEGAL=0, OUT_FILE, OUT_FILENAME } _type;
  644. union { // output type info
  645. FILE* _pfile; // OUT_FILE
  646. char* _filename; // OUT_FILENAME
  647. };
  648. // Set the pointers to indicate the buffer is empty. Don't reallocate
  649. // or free the buffer, though---it will get reused.
  650. void Reset();
  651. // Flush the output; synchronizes printf output using csStdio
  652. void Flush(FILE* pfile);
  653. public:
  654. COutputBuffer(char* logfile, bool buffered = true);
  655. COutputBuffer(FILE* pfile, bool buffered = true);
  656. ~COutputBuffer();
  657. const char *GetText() { ASSERTNR(_type == OUT_FILE); _textGrabbed = true; return _start; }
  658. // Add without doing varargs formatting (avoids local buffer size problems)
  659. void AddDirect(char* string);
  660. // Add text to the output buffer. Just like printf.
  661. void Add(const char* fmt, ...);
  662. // Flush the output to wherever it's going
  663. void Flush();
  664. };
  665. /////////////////////////////////////////////////////////////////////////
  666. extern char *REGRESS, *MASTER_DIR, *DIFF_DIR;
  667. extern char *REGR_CL, *REGR_DIFF, *REGR_ASM, *REGR_SHOWD;
  668. extern char *EXTRA_CC_FLAGS, *EXEC_TESTS_FLAGS, *TARGET_VM;
  669. extern char *LINKER, *LINKFLAGS;
  670. extern char *JCBinary;
  671. extern BOOL FBaseline;
  672. extern BOOL FRebase; // Whether creates .rebase file if testout mismatches baseline
  673. extern BOOL FDiff;
  674. extern BOOL FBaseDiff;
  675. extern BOOL FVerbose;
  676. extern BOOL FSummary;
  677. extern BOOL FNoDelete;
  678. extern BOOL FCopyOnFail;
  679. extern BOOL FParallel;
  680. extern BOOL FSyncEnumDirs;
  681. extern BOOL FNogpfnt;
  682. extern BOOL FTest;
  683. extern BOOL FAppendTestNameToExtraCCFlags;
  684. #define MAXOPTIONS 60
  685. extern char *OptFlags[MAXOPTIONS + 1], *PogoOptFlags[MAXOPTIONS + 1];
  686. #ifndef NODEBUG
  687. extern BOOL FDebug;
  688. #endif
  689. extern BOOL bThreadStop;
  690. extern BOOL FSyncImmediate;
  691. extern BOOL FSyncVariation;
  692. extern BOOL FSyncTest;
  693. extern BOOL FSyncDir;
  694. extern BOOL FNoThreadId;
  695. extern char* BaseCompiler;
  696. extern char* DiffCompiler;
  697. extern CDirectoryQueue DiffDirectoryQueue;
  698. extern unsigned NumberOfThreads;
  699. extern CRITICAL_SECTION csCurrentDirectory; // used when changing current directory
  700. extern CRITICAL_SECTION csStdio; // for printf / fprintf synchronization
  701. extern __declspec(thread) int ThreadId;
  702. extern __declspec(thread) char *TargetVM;
  703. extern __declspec(thread) COutputBuffer* ThreadOut; // stdout
  704. extern __declspec(thread) COutputBuffer* ThreadLog; // log file
  705. extern __declspec(thread) COutputBuffer* ThreadFull; // full log file
  706. extern CThreadInfo* ThreadInfo;
  707. extern CProtectedLong NumVariationsRun[RLS_COUNT];
  708. extern CProtectedLong NumVariationsTotal[RLS_COUNT];
  709. extern CProtectedLong NumFailuresTotal[RLS_COUNT];
  710. extern CProtectedLong NumDiffsTotal[RLS_COUNT];
  711. extern BOOL FRLFE;
  712. extern char *RLFEOpts;
  713. extern const char * const ModeNames[];
  714. // rl.cpp
  715. extern void __cdecl Fatal(const char *fmt, ...);
  716. extern void __cdecl Warning(const char *fmt, ...);
  717. extern void __cdecl Message(const char *fmt, ...);
  718. extern void __cdecl WriteLog(const char *fmt, ...);
  719. extern void __cdecl LogOut(const char *fmt, ...);
  720. extern void __cdecl LogError(const char *fmt, ...);
  721. extern void FlushOutput(void);
  722. extern char *mytmpnam(char* directory, char *prefix, char *filename);
  723. extern int DoCompare(char *file1, char *file2);
  724. extern void UpdateTitleStatus();
  725. extern int mystrcmp(char *a, char *b);
  726. extern char * mystrtok(char *s, char *delim, char *term);
  727. extern void FreeTestList(TestList * pTestList);
  728. #ifndef NODEBUG
  729. extern void DumpTestList(TestList * pTestList);
  730. #endif
  731. extern void DeleteMultipleFiles(CDirectory* pDir, char *pattern);
  732. extern char *GetFilenamePtr(char *path);
  733. extern const char* GetFilenameExt(const char *path);
  734. extern void DeleteFileMsg(char *filename);
  735. extern BOOL DeleteFileIfFound(char *filename);
  736. extern void DeleteFileRetryMsg(char *filename);
  737. extern StringList * ParseStringList(char* p, char* delim);
  738. extern StringList * AppendStringList(StringList * stringList, StringList * appendList);
  739. extern StringList * AppendStringListCopy(StringList * stringList, StringList * appendList);
  740. extern void PrintTagsList(Tags* pTagsList);
  741. extern void AddTagToTagsList(Tags** pTagsList, Tags** pTagsLast, const char* str, BOOL fInclude);
  742. extern BOOL
  743. SuppressNoGPF(
  744. Test * pTest
  745. );
  746. extern BOOL
  747. HasInfo
  748. (
  749. const char * szInfoList,
  750. const char * delim,
  751. const char * szInfo
  752. );
  753. extern BOOL
  754. HasInfoList
  755. (
  756. const char * szInfoList1,
  757. const char * delim1,
  758. const char * szInfoList2,
  759. const char * delim2,
  760. bool allMustMatch
  761. );
  762. extern BOOL
  763. GetTestInfoFromNode
  764. (
  765. const char * fileName,
  766. Xml::Node * node,
  767. TestInfo * testInfo
  768. );
  769. extern char * getenv_unsafe(const char *);
  770. extern FILE * fopen_unsafe(const char *, const char *);
  771. extern char* strerror_unsafe(int errnum);
  772. // rlregr.cpp
  773. extern void RegrInit(void);
  774. extern BOOL RegrStartDir(char* path);
  775. extern BOOL RegrEndDir(char* path);
  776. extern int RegrFile(CDirectory* pDir, Test * pTest, TestVariant * pTestVariant);
  777. // rlrun.cpp
  778. extern void RunInit(void);
  779. extern BOOL IsPogoTest(Test * pFilename);
  780. extern BOOL RunStartDir(char *dir);
  781. extern int ExecTest(CDirectory* pDir, Test * pTest, TestVariant * pTestVariant);
  782. // rlmp.cpp
  783. extern int ExecuteCommand(char* path, char* CommandLine, DWORD millisecTimeout = INFINITE, void* localEnvVars = NULL);
  784. extern int DoOneExternalTest(
  785. CDirectory* pDir,
  786. TestVariant* pTestVariant,
  787. char *optFlags,
  788. char *inCCFlags,
  789. char *inLinkFlags,
  790. char *testCmd,
  791. ExternalTestKind kind,
  792. BOOL fSyncVariationWhenFinished,
  793. BOOL fCleanBefore,
  794. BOOL fCleanAfter,
  795. BOOL fSuppressNoGPF,
  796. void *localEnvVars = NULL
  797. );
  798. extern void
  799. WriteSummary(
  800. const char *name,
  801. BOOL fBaseline,
  802. int tests,
  803. int diffs,
  804. int failures
  805. );
  806. // rlfeint.cpp
  807. extern void RLFEInit(BYTE numThreads, int numDirs);
  808. extern void RLFEAddRoot(RL_STATS stat, DWORD total);
  809. extern void RLFEAddTest(RL_STATS stat, CDirectory *pDir);
  810. extern void RLFEAddLog(CDirectory *pDir, RLFE_STATUS rlfeStatus, const char *testName, const char *subTestName, const char *logText);
  811. extern void RLFETestStatus(CDirectory *pDir);
  812. extern void RLFEThreadDir(CDirectory *pDir, BYTE num);
  813. extern void RLFEThreadStatus(BYTE num, const char *text);
  814. extern BOOL RLFEConnect(const char *prefix);
  815. extern void RLFEDisconnect(BOOL fKilled);