rl.h 28 KB

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