rl.h 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020
  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_COUNT
  171. };
  172. extern const char * const TestInfoKindName[];
  173. struct TestInfo
  174. {
  175. BOOL hasData[_TIK_COUNT];
  176. char * data[_TIK_COUNT];
  177. };
  178. struct Tags
  179. {
  180. Tags * next;
  181. const char * str;
  182. BOOL fInclude;
  183. };
  184. struct ConditionNodeList
  185. {
  186. ConditionNodeList * next;
  187. Xml::Node * node;
  188. };
  189. enum FILE_STATUS
  190. {
  191. FS_NONE, FS_EXCLUDED, FS_INCLUDED
  192. };
  193. enum PROCESS_CONFIG_STATUS
  194. {
  195. PCS_OK, PCS_ERROR, PCS_FILE_NOT_FOUND
  196. };
  197. enum FILE_CONFIG_STATUS
  198. {
  199. FCS_USER_SPECIFIED, FCS_US_FLAGS, FCS_READ
  200. };
  201. struct StringList
  202. {
  203. StringList * next;
  204. char * string;
  205. };
  206. struct TestVariant
  207. {
  208. TestVariant() : next(NULL), optFlags(NULL) {}
  209. TestVariant * next;
  210. // Exe optimization flags.
  211. char * optFlags;
  212. // Test-specific info.
  213. TestInfo testInfo;
  214. };
  215. struct Test
  216. {
  217. Test * next;
  218. // For tests
  219. StringList * files;
  220. // For directories
  221. char * name;
  222. char * fullPath;
  223. int num;
  224. // Common.
  225. ConditionNodeList * conditionNodeList;
  226. TestInfo defaultTestInfo;
  227. TestVariant * variants;
  228. };
  229. struct TestList
  230. {
  231. Test * first;
  232. Test * last;
  233. };
  234. // Time options. Can do multiple types of timings, so do it bitwise
  235. #define TIME_NOTHING 0x0
  236. #define TIME_DIR 0x1
  237. #define TIME_TEST 0x2
  238. #define TIME_VARIATION 0x4
  239. #define TIME_ALL 0x7 // bitmask of all timing options
  240. typedef int TIME_OPTION; // could be enum, but C++ doesn't like |= on enum
  241. extern TIME_OPTION Timing;
  242. /////////////////////////////////////////////////////////////////////////
  243. //
  244. // Class declarations. Non-inline member functions are defined in rlmp.cpp.
  245. //
  246. /////////////////////////////////////////////////////////////////////////
  247. class CProtectedLong;
  248. class CHandle;
  249. class CDirectory;
  250. class CDirectoryQueue;
  251. class CThreadInfo;
  252. class COutputBuffer;
  253. /////////////////////////////////////////////////////////////////////////
  254. // CProtectedLong: a single value protected by a critical section. This is
  255. // used for things like test counts which are accessed by both worker threads
  256. // and the display thread.
  257. class CProtectedLong {
  258. CRITICAL_SECTION _cs;
  259. int32 _value;
  260. public:
  261. CProtectedLong() : _value(0)
  262. {
  263. InitializeCriticalSection(&_cs);
  264. }
  265. ~CProtectedLong()
  266. {
  267. DeleteCriticalSection(&_cs);
  268. }
  269. int32 operator++(int)
  270. {
  271. EnterCriticalSection(&_cs);
  272. int32 tmp = _value++;
  273. LeaveCriticalSection(&_cs);
  274. return tmp;
  275. }
  276. int32 operator--(int)
  277. {
  278. EnterCriticalSection(&_cs);
  279. int32 tmp = _value--;
  280. LeaveCriticalSection(&_cs);
  281. return tmp;
  282. }
  283. int32 operator+=(int32 incr)
  284. {
  285. EnterCriticalSection(&_cs);
  286. int32 tmp = (_value += incr);
  287. LeaveCriticalSection(&_cs);
  288. return tmp;
  289. }
  290. int32 operator=(int32 val)
  291. {
  292. EnterCriticalSection(&_cs);
  293. _value = val;
  294. LeaveCriticalSection(&_cs);
  295. return val;
  296. }
  297. bool operator==(CProtectedLong& rhs)
  298. {
  299. return _value == rhs._value;
  300. }
  301. operator int() { return _value; }
  302. };
  303. /////////////////////////////////////////////////////////////////////////
  304. // CHandle: a convenience class for storing HANDLE objects. When destructed
  305. // or set to another value, the current handle is closed. Helps prevent
  306. // handle leaks.
  307. class CHandle {
  308. HANDLE _h;
  309. public:
  310. CHandle() : _h(INVALID_HANDLE_VALUE) {}
  311. ~CHandle()
  312. {
  313. if (_h != INVALID_HANDLE_VALUE && _h != NULL)
  314. CloseHandle(_h);
  315. }
  316. HANDLE operator=(HANDLE h)
  317. {
  318. if (_h != INVALID_HANDLE_VALUE && _h != NULL)
  319. CloseHandle(_h);
  320. _h = h;
  321. return _h;
  322. }
  323. BOOL operator==(HANDLE h) { return h == _h ? TRUE : FALSE; }
  324. BOOL operator!=(HANDLE h) { return h != _h ? TRUE : FALSE; }
  325. operator HANDLE() { return _h; };
  326. };
  327. /////////////////////////////////////////////////////////////////////////
  328. // WorkObject: a wrapper class for elements used by WorkQueue. Requires
  329. // children classes to implement Dump if debug and keeps track of a _next
  330. // for use by WorkQueue.
  331. template <typename TWorkObject>
  332. class WorkObject {
  333. public:
  334. TWorkObject* _next;
  335. public:
  336. #ifndef NODEBUG
  337. virtual void Dump() = 0;
  338. #endif
  339. };
  340. /////////////////////////////////////////////////////////////////////////
  341. // WorkQueue: a generic class for keeping track of WorkObjects which need
  342. // to be queued and worked on.
  343. template <typename TWorkObject>
  344. class WorkQueue {
  345. protected:
  346. int _length;
  347. TWorkObject* _head;
  348. TWorkObject* _tail;
  349. CRITICAL_SECTION _cs; // ensure proper synchronized access
  350. CHandle _hWorkAvailSem; // signalled whenever there's work on the list
  351. CHandle _hMaxWorkQueueSem; // used to control length of work queue
  352. public:
  353. WorkQueue()
  354. : _head(NULL), _tail(NULL), _length(0)
  355. {
  356. SECURITY_ATTRIBUTES sa;
  357. InitializeCriticalSection(&_cs);
  358. /*
  359. * Create the semaphores for the work lists
  360. */
  361. memset(&sa, 0, sizeof(sa));
  362. sa.nLength = sizeof(sa);
  363. sa.lpSecurityDescriptor = NULL;
  364. sa.bInheritHandle = TRUE;
  365. _hWorkAvailSem = CreateSemaphoreW(&sa, 0, 100000, NULL);
  366. if (_hWorkAvailSem == NULL)
  367. Fatal("Unable to create semaphore (err %u)!\n", GetLastError());
  368. _hMaxWorkQueueSem = CreateSemaphoreW(&sa, MAXQUEUE, MAXQUEUE, NULL);
  369. if (_hMaxWorkQueueSem == NULL)
  370. Fatal("Unable to create queue length semaphore (err %u)!\n", GetLastError());
  371. }
  372. ~WorkQueue()
  373. {
  374. // The CHandle objects clean up after themselves.
  375. DeleteCriticalSection(&_cs);
  376. }
  377. virtual TWorkObject* Pop() = 0;
  378. TWorkObject* Append(TWorkObject* pNew)
  379. {
  380. if (WaitForSingleObject(_hMaxWorkQueueSem, INFINITE) != WAIT_OBJECT_0) {
  381. Fatal("Semaphore wait failed, can't add to work list");
  382. }
  383. EnterCriticalSection(&_cs);
  384. if (_tail == NULL) {
  385. _head = _tail = pNew;
  386. } else {
  387. _tail->_next = pNew;
  388. _tail = pNew;
  389. }
  390. pNew->_next = NULL;
  391. ++_length;
  392. LeaveCriticalSection(&_cs);
  393. ReleaseSemaphore(_hWorkAvailSem, 1, NULL);
  394. return pNew;
  395. }
  396. int Length()
  397. {
  398. int tmp;
  399. EnterCriticalSection(&_cs);
  400. tmp = _length;
  401. LeaveCriticalSection(&_cs);
  402. return tmp;
  403. }
  404. DWORD WaitForWork(DWORD dwMilliseconds)
  405. {
  406. return WaitForSingleObject(_hWorkAvailSem, dwMilliseconds);
  407. }
  408. // The queue work available semaphore has a count for every
  409. // directory. When the queue is exhausted, each thread waits on
  410. // this semaphore again. So at the end, everyone will still be waiting!
  411. // So, add the number of threads to the count, so each thread
  412. // notices, one by one, that everything's done.
  413. void AdjustWaitForThreadCount()
  414. {
  415. ReleaseSemaphore(_hWorkAvailSem, (int)NumberOfThreads, NULL);
  416. }
  417. TWorkObject* GetNextItem()
  418. {
  419. DWORD dwWait = 0;
  420. TWorkObject* toReturn = NULL;
  421. while (TRUE)
  422. {
  423. dwWait = this->WaitForWork(1000);
  424. if (dwWait == WAIT_OBJECT_0) {
  425. // pick an item off the head of the work list
  426. toReturn = this->Pop();
  427. break;
  428. } else if (dwWait == WAIT_TIMEOUT) {
  429. if (bThreadStop)
  430. break;
  431. } else {
  432. LogError("Thread %d: Semaphore wait failed\n", ThreadId);
  433. break;
  434. }
  435. }
  436. if (dwWait != WAIT_OBJECT_0)
  437. return NULL;
  438. if (bThreadStop)
  439. return NULL;
  440. return toReturn;
  441. }
  442. TWorkObject* GetNextItem_NoBlock(DWORD waitTime)
  443. {
  444. DWORD dwWait = 0;
  445. TWorkObject* toReturn = NULL;
  446. dwWait = this->WaitForWork(waitTime);
  447. if(dwWait == WAIT_OBJECT_0) {
  448. // pick an item off the head of the work list
  449. toReturn = this->Pop();
  450. }
  451. return toReturn;
  452. }
  453. #ifndef NODEBUG
  454. void Dump()
  455. {
  456. TWorkObject* tmp;
  457. EnterCriticalSection(&_cs);
  458. printf("WorkQueue, length %d\n", _length);
  459. for (tmp = _head; tmp != NULL; tmp = tmp->_next) {
  460. tmp->Dump();
  461. }
  462. LeaveCriticalSection(&_cs);
  463. }
  464. #endif
  465. };
  466. /////////////////////////////////////////////////////////////////////////
  467. // CDirectory: represents a single directory and the tests that need to
  468. // be run within it.
  469. class CDirectory : public WorkObject<CDirectory> {
  470. friend class CDirectoryQueue;
  471. TestList _testList; // list of files in directory
  472. Test * _pDir; // directory info
  473. CHandle _dirLock; // the directory lock file
  474. bool _isDiffDirectory; // directory is for doing diffs, not masters
  475. bool _isDirStarted; // indicates if the directory has begun executing
  476. time_t start_dir; // time when dir began executing
  477. time_t elapsed_dir; // time taken for dir to execute.
  478. // initialized to 0 but set to a value upon directory finish.
  479. CRITICAL_SECTION _cs; // ensure proper synchronized access
  480. // Try to lock the directory. If we successfully got the lock without
  481. // waiting, return true.
  482. // Note that since we use FILE_FLAG_DELETE_ON_CLOSE, the lock file should
  483. // go away if the process dies because of ctrl-c.
  484. bool TryLock();
  485. // Lock the directory; wait on the lock until it's available
  486. void WaitLock();
  487. // Output begin/finish summaries if all tests in the directory are executed.
  488. void WriteDirectoryBeginSummary();
  489. void WriteDirectoryFinishSummary();
  490. public:
  491. // Multiple threads can be working in a single directory,
  492. // we'll need to make these CProtectedLong.
  493. CProtectedLong NumVariations, NumVariationsRun, NumFailures, NumDiffs;
  494. RL_STATS stat; // which mode stat to update
  495. CDirectory(Test * pDir, TestList testList)
  496. : _pDir(pDir), _testList(testList), _isDiffDirectory(false), _isDirStarted(false), elapsed_dir(0)
  497. {
  498. InitializeCriticalSection(&_cs);
  499. }
  500. ~CDirectory();
  501. TestList * GetTestList() { return &_testList; }
  502. char* GetDirectoryName() { return _pDir->name; }
  503. char* GetDirectoryPath() { return _pDir->fullPath; }
  504. int GetDirectoryNumber() { return _pDir->num; }
  505. bool IsBaseline() { return !_isDiffDirectory; }
  506. void SetDiffFlag() { _isDiffDirectory = true; }
  507. void InitStats(int run);
  508. int32 IncRun(int inc = 1);
  509. int32 IncFailures(int inc = 1);
  510. int32 IncDiffs();
  511. // Trigger update of directory state.
  512. void UpdateState();
  513. void TryBeginDirectory();
  514. void TryEndDirectory();
  515. int Count(); // return count of tests in the directory
  516. #ifndef NODEBUG
  517. void Dump();
  518. #endif
  519. };
  520. /////////////////////////////////////////////////////////////////////////
  521. // CDirectoryQueue: a queue of directories that need to have work done.
  522. class CDirectoryQueue : public WorkQueue<CDirectory> {
  523. public:
  524. ~CDirectoryQueue();
  525. // Return a directory to use. Normally, just peel the first one off the
  526. // work queue. However, if that directory is locked by another copy of
  527. // rl.exe, then skip it and try the next directory, until there are no
  528. // directories left. If that happens, just wait on the first locked
  529. // directory.
  530. CDirectory* Pop();
  531. };
  532. /////////////////////////////////////////////////////////////////////////
  533. // CDirectoryAndTestCase: Keep track of directory and test case in a class for
  534. // use in CDirectoryAndTestCaseQueue.
  535. // Reuse CDirectory because it has all the nice profiling data already.
  536. class CDirectoryAndTestCase : public WorkObject<CDirectoryAndTestCase> {
  537. public:
  538. CDirectory* _pDir;
  539. Test* _pTest;
  540. public:
  541. CDirectoryAndTestCase(CDirectory* pDir, Test* pTest)
  542. : _pDir(pDir), _pTest(pTest)
  543. {
  544. _next = NULL;
  545. }
  546. ~CDirectoryAndTestCase()
  547. {
  548. // This class is just a container for CDirectory and Test.
  549. // We don't want to clean up the objects here,
  550. // CDirectory will be cleaned up via ~CDirectoryQueue.
  551. }
  552. #ifndef NODEBUG
  553. void Dump()
  554. {
  555. _pDir->Dump();
  556. }
  557. #endif
  558. };
  559. /////////////////////////////////////////////////////////////////////////
  560. // CDirectoryAndTestCaseQueue: a simple queue to hold CDirectoryAndTestCase objects.
  561. class CDirectoryAndTestCaseQueue : public WorkQueue<CDirectoryAndTestCase> {
  562. public:
  563. CDirectoryAndTestCase* Pop();
  564. };
  565. /////////////////////////////////////////////////////////////////////////
  566. // CThreadInfo: a class with various bits of information about the current
  567. // state of a thread. An array of these objects is created before the worker
  568. // threads are started. This array is accessed like this: ThreadInfo[ThreadId],
  569. // where ThreadId is a __declspec(thread) TLS variable. The status update
  570. // thread uses the info here to construct the title bar.
  571. class CThreadInfo
  572. {
  573. CRITICAL_SECTION _cs;
  574. char _currentTest[BUFFER_SIZE];
  575. bool _isDone;
  576. struct TmpFileList
  577. {
  578. TmpFileList* _next;
  579. char* const _fullPath;
  580. TmpFileList(TmpFileList* next, char* fullPath)
  581. : _next(next), _fullPath(_strdup(fullPath))
  582. {
  583. }
  584. ~TmpFileList()
  585. {
  586. free(_fullPath);
  587. }
  588. TmpFileList(const TmpFileList&) = delete;
  589. void operator=(const TmpFileList&) = delete;
  590. };
  591. TmpFileList* _head;
  592. public:
  593. CThreadInfo()
  594. : _head(NULL), _isDone(false)
  595. {
  596. InitializeCriticalSection(&_cs);
  597. _currentTest[0] = '\0';
  598. }
  599. ~CThreadInfo()
  600. {
  601. ClearTmpFileList();
  602. DeleteCriticalSection(&_cs);
  603. }
  604. bool IsDone() { return _isDone; }
  605. void Done();
  606. // Track current test, for use in creating the title bar
  607. void SetCurrentTest(char* dir, char* test, bool isBaseline);
  608. template <size_t bufSize>
  609. void GetCurrentTest(char (&currentTest)[bufSize])
  610. {
  611. EnterCriticalSection(&_cs);
  612. strcpy_s(currentTest, _currentTest);
  613. LeaveCriticalSection(&_cs);
  614. }
  615. // Track currently in-use temp files, so we can clean them up if we exit
  616. // by ctrl-c.
  617. void AddToTmpFileList(char* fullPath);
  618. void ClearTmpFileList();
  619. void DeleteTmpFileList();
  620. };
  621. /////////////////////////////////////////////////////////////////////////
  622. // COutputBuffer: a buffered output class. Store up output so it can
  623. // all be flushed at once. Used to keep per-thread output from
  624. // interleaving too much and becoming unreadable. This class is
  625. // not synchronized. It is expected that there is one of these objects per
  626. // output location (stdout, file, etc) per thread. Flushing the output *is*
  627. // synchronized on a critical section that should be used around *all*
  628. // worker thread stdio. (Actually, all normal output should go through this
  629. // class.) A NULL file or filename is allowed, in which case everything
  630. // happens as normal, but the Flush() operation doesn't display anything or
  631. // send anything to disk.
  632. class COutputBuffer
  633. {
  634. char* _start;
  635. char* _end;
  636. bool _buffered; // true == buffer output; false == flush immediately (e.g., primary thread)
  637. bool _textGrabbed; // true == someone grabbed the text, used for asserting
  638. size_t _bufSize;
  639. enum { OUT_ILLEGAL=0, OUT_FILE, OUT_FILENAME } _type;
  640. union { // output type info
  641. FILE* _pfile; // OUT_FILE
  642. char* _filename; // OUT_FILENAME
  643. };
  644. // Set the pointers to indicate the buffer is empty. Don't reallocate
  645. // or free the buffer, though---it will get reused.
  646. void Reset();
  647. // Flush the output; synchronizes printf output using csStdio
  648. void Flush(FILE* pfile);
  649. public:
  650. COutputBuffer(char* logfile, bool buffered = true);
  651. COutputBuffer(FILE* pfile, bool buffered = true);
  652. ~COutputBuffer();
  653. const char *GetText() { ASSERTNR(_type == OUT_FILE); _textGrabbed = true; return _start; }
  654. // Add without doing varargs formatting (avoids local buffer size problems)
  655. void AddDirect(char* string);
  656. // Add text to the output buffer. Just like printf.
  657. void Add(const char* fmt, ...);
  658. // Flush the output to wherever it's going
  659. void Flush();
  660. };
  661. /////////////////////////////////////////////////////////////////////////
  662. extern char *REGRESS, *MASTER_DIR, *DIFF_DIR;
  663. extern char *REGR_CL, *REGR_DIFF, *REGR_ASM, *REGR_SHOWD;
  664. extern char *EXTRA_CC_FLAGS, *EXEC_TESTS_FLAGS, *TARGET_VM;
  665. extern char *LINKER, *LINKFLAGS;
  666. extern char *JCBinary;
  667. extern BOOL FBaseline;
  668. extern BOOL FRebase; // Whether creates .rebase file if testout mismatches baseline
  669. extern BOOL FDiff;
  670. extern BOOL FBaseDiff;
  671. extern BOOL FVerbose;
  672. extern BOOL FSummary;
  673. extern BOOL FNoDelete;
  674. extern BOOL FCopyOnFail;
  675. extern BOOL FParallel;
  676. extern BOOL FSyncEnumDirs;
  677. extern BOOL FNogpfnt;
  678. extern BOOL FTest;
  679. extern BOOL FAppendTestNameToExtraCCFlags;
  680. #define MAXOPTIONS 60
  681. extern char *OptFlags[MAXOPTIONS + 1], *PogoOptFlags[MAXOPTIONS + 1];
  682. #ifndef NODEBUG
  683. extern BOOL FDebug;
  684. #endif
  685. extern BOOL bThreadStop;
  686. extern BOOL FSyncImmediate;
  687. extern BOOL FSyncVariation;
  688. extern BOOL FSyncTest;
  689. extern BOOL FSyncDir;
  690. extern BOOL FNoThreadId;
  691. extern char* BaseCompiler;
  692. extern char* DiffCompiler;
  693. extern CDirectoryQueue DiffDirectoryQueue;
  694. extern unsigned NumberOfThreads;
  695. extern CRITICAL_SECTION csCurrentDirectory; // used when changing current directory
  696. extern CRITICAL_SECTION csStdio; // for printf / fprintf synchronization
  697. extern __declspec(thread) int ThreadId;
  698. extern __declspec(thread) char *TargetVM;
  699. extern __declspec(thread) COutputBuffer* ThreadOut; // stdout
  700. extern __declspec(thread) COutputBuffer* ThreadLog; // log file
  701. extern __declspec(thread) COutputBuffer* ThreadFull; // full log file
  702. extern CThreadInfo* ThreadInfo;
  703. extern CProtectedLong NumVariationsRun[RLS_COUNT];
  704. extern CProtectedLong NumVariationsTotal[RLS_COUNT];
  705. extern CProtectedLong NumFailuresTotal[RLS_COUNT];
  706. extern CProtectedLong NumDiffsTotal[RLS_COUNT];
  707. extern BOOL FRLFE;
  708. extern char *RLFEOpts;
  709. extern const char * const ModeNames[];
  710. // rl.cpp
  711. extern void __cdecl Fatal(const char *fmt, ...);
  712. extern void __cdecl Warning(const char *fmt, ...);
  713. extern void __cdecl Message(const char *fmt, ...);
  714. extern void __cdecl WriteLog(const char *fmt, ...);
  715. extern void __cdecl LogOut(const char *fmt, ...);
  716. extern void __cdecl LogError(const char *fmt, ...);
  717. extern void FlushOutput(void);
  718. extern char *mytmpnam(char* directory, char *prefix, char *filename);
  719. extern int DoCompare(char *file1, char *file2);
  720. extern void UpdateTitleStatus();
  721. extern int mystrcmp(char *a, char *b);
  722. extern char * mystrtok(char *s, char *delim, char *term);
  723. extern void FreeTestList(TestList * pTestList);
  724. #ifndef NODEBUG
  725. extern void DumpTestList(TestList * pTestList);
  726. #endif
  727. extern void DeleteMultipleFiles(CDirectory* pDir, char *pattern);
  728. extern char *GetFilenamePtr(char *path);
  729. extern const char* GetFilenameExt(const char *path);
  730. extern void DeleteFileMsg(char *filename);
  731. extern BOOL DeleteFileIfFound(char *filename);
  732. extern void DeleteFileRetryMsg(char *filename);
  733. extern StringList * ParseStringList(char* p, char* delim);
  734. extern StringList * AppendStringList(StringList * stringList, StringList * appendList);
  735. extern StringList * AppendStringListCopy(StringList * stringList, StringList * appendList);
  736. extern void PrintTagsList(Tags* pTagsList);
  737. extern void AddTagToTagsList(Tags** pTagsList, Tags** pTagsLast, const char* str, BOOL fInclude);
  738. extern BOOL
  739. SuppressNoGPF(
  740. Test * pTest
  741. );
  742. extern BOOL
  743. HasInfo
  744. (
  745. const char * szInfoList,
  746. const char * delim,
  747. const char * szInfo
  748. );
  749. extern BOOL
  750. HasInfoList
  751. (
  752. const char * szInfoList1,
  753. const char * delim1,
  754. const char * szInfoList2,
  755. const char * delim2,
  756. bool allMustMatch
  757. );
  758. extern BOOL
  759. GetTestInfoFromNode
  760. (
  761. const char * fileName,
  762. Xml::Node * node,
  763. TestInfo * testInfo
  764. );
  765. extern char * getenv_unsafe(const char *);
  766. extern FILE * fopen_unsafe(const char *, const char *);
  767. extern char* strerror_unsafe(int errnum);
  768. // rlregr.cpp
  769. extern void RegrInit(void);
  770. extern BOOL RegrStartDir(char* path);
  771. extern BOOL RegrEndDir(char* path);
  772. extern int RegrFile(CDirectory* pDir, Test * pTest, TestVariant * pTestVariant);
  773. // rlrun.cpp
  774. extern void RunInit(void);
  775. extern BOOL IsPogoTest(Test * pFilename);
  776. extern BOOL RunStartDir(char *dir);
  777. extern int ExecTest(CDirectory* pDir, Test * pTest, TestVariant * pTestVariant);
  778. // rlmp.cpp
  779. extern int ExecuteCommand(char* path, char* CommandLine, DWORD millisecTimeout = INFINITE, void* localEnvVars = NULL);
  780. extern int DoOneExternalTest(
  781. CDirectory* pDir,
  782. TestVariant* pTestVariant,
  783. char *optFlags,
  784. char *inCCFlags,
  785. char *inLinkFlags,
  786. char *testCmd,
  787. ExternalTestKind kind,
  788. BOOL fSyncVariationWhenFinished,
  789. BOOL fCleanBefore,
  790. BOOL fCleanAfter,
  791. BOOL fSuppressNoGPF,
  792. void *localEnvVars = NULL
  793. );
  794. extern void
  795. WriteSummary(
  796. const char *name,
  797. BOOL fBaseline,
  798. int tests,
  799. int diffs,
  800. int failures
  801. );
  802. // rlfeint.cpp
  803. extern void RLFEInit(BYTE numThreads, int numDirs);
  804. extern void RLFEAddRoot(RL_STATS stat, DWORD total);
  805. extern void RLFEAddTest(RL_STATS stat, CDirectory *pDir);
  806. extern void RLFEAddLog(CDirectory *pDir, RLFE_STATUS rlfeStatus, const char *testName, const char *subTestName, const char *logText);
  807. extern void RLFETestStatus(CDirectory *pDir);
  808. extern void RLFEThreadDir(CDirectory *pDir, BYTE num);
  809. extern void RLFEThreadStatus(BYTE num, const char *text);
  810. extern BOOL RLFEConnect(const char *prefix);
  811. extern void RLFEDisconnect(BOOL fKilled);