Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1244 lines
25 KiB

  1. /*++
  2. Copyright (c) 2000 Microsoft Corporation
  3. Module Name:
  4. vststprocess.cxx
  5. Abstract:
  6. Implementation of test message classes
  7. Brian Berkowitz [brianb] 05/24/2000
  8. TBD:
  9. Revision History:
  10. Name Date Comments
  11. brianb 05/24/2000 Created
  12. --*/
  13. #include <stdafx.h>
  14. #include <vststprocess.hxx>
  15. #include <vststmsg.hxx>
  16. #include <tstiniconfig.hxx>
  17. void LogUnexpectedFailure(LPCWSTR, ...);
  18. CVsTstProcessList::CVsTstProcessList() :
  19. m_processId(0L),
  20. m_processList(NULL),
  21. m_bcsProcessListInitialized(false),
  22. m_bNoMoreProcessesAreCreated(false),
  23. m_bShuttingDown(true)
  24. {
  25. }
  26. CVsTstProcessList::~CVsTstProcessList()
  27. {
  28. m_bShuttingDown = true;
  29. if (WaitForSingleObject(m_hThreadMonitor, INFINITE) == WAIT_FAILED)
  30. {
  31. LogUnexpectedFailure(L"WaitForSingleObject failed for reason %d.\n", GetLastError());
  32. // wait for 1 minute for everything to shut down
  33. Sleep(60000);
  34. }
  35. CloseHandle(m_hThreadMonitor);
  36. if (m_bcsProcessListInitialized)
  37. m_csProcessList.Term();
  38. }
  39. void CVsTstProcessList::LinkIntoProcessList(CVsTstProcess *process)
  40. {
  41. m_csProcessList.Lock();
  42. VSTST_ASSERT(m_processList == NULL || m_processList->m_prev == NULL);
  43. process->m_next = m_processList;
  44. process->m_prev = NULL;
  45. if (m_processList != NULL)
  46. m_processList->m_prev = process;
  47. m_processList = process;
  48. m_csProcessList.Unlock();
  49. }
  50. void CVsTstProcessList::UnlinkFromProcessList(CVsTstProcess *process)
  51. {
  52. m_csProcessList.Lock();
  53. VSTST_ASSERT(m_processList);
  54. VSTST_ASSERT(m_processList->m_prev == NULL);
  55. if (process == m_processList)
  56. {
  57. m_processList = process->m_next;
  58. if (m_processList)
  59. {
  60. VSTST_ASSERT(m_processList->m_prev == process);
  61. m_processList->m_prev = NULL;
  62. }
  63. }
  64. else
  65. {
  66. VSTST_ASSERT(process->m_prev != NULL);
  67. process->m_prev->m_next = process->m_next;
  68. if (process->m_next)
  69. {
  70. VSTST_ASSERT(process->m_next->m_prev == process);
  71. process->m_next->m_prev = process->m_prev;
  72. }
  73. }
  74. m_csProcessList.Unlock();
  75. delete process;
  76. }
  77. HRESULT CVsTstProcessList::Initialize
  78. (
  79. UINT maxLifetime,
  80. HANDLE hevtTermination
  81. )
  82. {
  83. try
  84. {
  85. m_csProcessList.Init();
  86. m_bcsProcessListInitialized = true;
  87. }
  88. catch(...)
  89. {
  90. return E_UNEXPECTED;
  91. }
  92. time_t timeCur;
  93. time(&timeCur);
  94. m_timeTerminateTest = timeCur + maxLifetime;
  95. m_hevtTermination = hevtTermination;
  96. DWORD tid;
  97. m_hThreadMonitor = CreateThread
  98. (
  99. NULL,
  100. 256*1024,
  101. StartupMonitorThread,
  102. this,
  103. 0,
  104. &tid
  105. );
  106. if (m_hThreadMonitor == NULL)
  107. return HRESULT_FROM_WIN32(GetLastError());
  108. return S_OK;
  109. }
  110. DWORD CVsTstProcessList::StartupMonitorThread(void *pv)
  111. {
  112. CVsTstProcessList *processList = (CVsTstProcessList *) pv;
  113. try
  114. {
  115. processList->MonitorFunc();
  116. if (processList->m_hevtTermination)
  117. {
  118. if (!SetEvent(processList->m_hevtTermination))
  119. LogUnexpectedFailure(L"SetEvent failed with error %d", GetLastError());
  120. }
  121. }
  122. catch(...)
  123. {
  124. }
  125. return 0;
  126. }
  127. //
  128. void CVsTstProcessList::MonitorFunc()
  129. {
  130. while(TRUE)
  131. {
  132. time_t timeNow;
  133. Sleep(5000);
  134. time(&timeNow);
  135. if (timeNow > m_timeTerminateTest)
  136. {
  137. StartTermination();
  138. break;
  139. }
  140. else
  141. {
  142. m_csProcessList.Lock();
  143. // check if there are no processes and no more proceses
  144. // are created
  145. if (m_processList == NULL && m_bNoMoreProcessesAreCreated)
  146. {
  147. m_csProcessList.Unlock();
  148. break;
  149. }
  150. CVsTstProcess *process = m_processList;
  151. while(process != NULL)
  152. {
  153. CVsTstProcess *processNext = process->m_next;
  154. m_csProcessList.Unlock();
  155. if (process->HasProcessExpired())
  156. process->DoTerminateProcess(false);
  157. m_csProcessList.Lock();
  158. process = processNext;
  159. }
  160. m_csProcessList.Unlock();
  161. }
  162. }
  163. }
  164. // start process termination
  165. void CVsTstProcessList::StartTermination()
  166. {
  167. m_bNoMoreProcessesAreCreated = true;
  168. while(TRUE)
  169. {
  170. m_csProcessList.Lock();
  171. CVsTstProcess *process = m_processList;
  172. if (process == NULL)
  173. {
  174. m_csProcessList.Unlock();
  175. return;
  176. }
  177. while(process != NULL)
  178. {
  179. CVsTstProcess *processNext = process->m_next;
  180. m_csProcessList.Unlock();
  181. process->DoTerminateProcess(m_bShuttingDown);
  182. m_csProcessList.Lock();
  183. process = processNext;
  184. }
  185. // unlock list before going to sleep
  186. m_csProcessList.Unlock();
  187. Sleep(5000);
  188. }
  189. }
  190. // constructor
  191. CVsTstProcess::CVsTstProcess(CVsTstProcessList *list) :
  192. m_hProcess(NULL),
  193. m_hevtGracefullyTerminate(NULL),
  194. m_hevtNotifyProcessTermination(NULL),
  195. m_pvPrivateData(NULL),
  196. m_next(NULL),
  197. m_prev(NULL),
  198. m_bLinked(false),
  199. m_processList(list),
  200. m_bGracefullyTerminated(false)
  201. {
  202. }
  203. // deastructor
  204. CVsTstProcess::~CVsTstProcess()
  205. {
  206. if (m_bLinked)
  207. m_processList->UnlinkFromProcessList(this);
  208. if (m_hevtGracefullyTerminate)
  209. CloseHandle(m_hevtGracefullyTerminate);
  210. }
  211. HRESULT CVsTstProcess::InitializeConformingExe
  212. (
  213. ULONGLONG processId,
  214. VSTST_PROCESS_TYPE type,
  215. VSTST_ACCOUNT_TYPE account,
  216. LPCWSTR wszExecutableName,
  217. LPCWSTR wszScenarioFile,
  218. LPCWSTR wszSection,
  219. DWORD seed,
  220. UINT lifetime,
  221. bool bAbnormalTermination,
  222. HANDLE hevtNotify
  223. )
  224. {
  225. WCHAR buf[256];
  226. SECURITY_ATTRIBUTES attributes;
  227. m_processId = processId;
  228. m_type = type;
  229. m_account = account;
  230. m_bConforming = true;
  231. attributes.nLength = sizeof(SECURITY_ATTRIBUTES);
  232. attributes.lpSecurityDescriptor = NULL;
  233. attributes.bInheritHandle = true;
  234. m_hevtGracefullyTerminate = CreateEvent(&attributes, TRUE, FALSE, NULL);
  235. if (m_hevtGracefullyTerminate == NULL)
  236. return HRESULT_FROM_WIN32(GetLastError());
  237. UINT pidLow = (UINT) (m_processId & 0xffffffff);
  238. UINT pidHigh = (UINT) (m_processId >> 32);
  239. swprintf
  240. (
  241. buf,
  242. L"%s -pidLow=%d -pidHigh=%d -scenario={%s} -section={%s} -seed=%u -lifetime=%d -event=0x%08x",
  243. wszExecutableName,
  244. pidLow,
  245. pidHigh,
  246. wszScenarioFile,
  247. wszSection,
  248. seed,
  249. lifetime,
  250. m_hevtGracefullyTerminate
  251. );
  252. PROCESS_INFORMATION info;
  253. STARTUPINFO startup;
  254. memset(&startup, 0, sizeof(STARTUPINFO));
  255. startup.cb = sizeof(STARTUPINFO);
  256. if (!CreateProcess
  257. (
  258. NULL,
  259. buf,
  260. NULL,
  261. NULL,
  262. TRUE,
  263. NORMAL_PRIORITY_CLASS,
  264. NULL,
  265. NULL,
  266. &startup,
  267. &info
  268. ))
  269. {
  270. DWORD dwErr = GetLastError();
  271. CloseHandle(m_hevtGracefullyTerminate);
  272. m_hevtGracefullyTerminate = NULL;
  273. return HRESULT_FROM_WIN32(dwErr);
  274. }
  275. m_hProcess = info.hProcess;
  276. m_hevtNotifyProcessTermination = hevtNotify;
  277. m_bAbnormallyTerminate = bAbnormalTermination;
  278. time(&m_timeProcessStart);
  279. m_timeProcessTerminate = m_timeProcessStart + lifetime;
  280. m_processList->LinkIntoProcessList(this);
  281. return S_OK;
  282. }
  283. // startup a process associated with a non-conforming executable
  284. HRESULT CVsTstProcess::InitializeNonConformingExe
  285. (
  286. ULONGLONG processId,
  287. VSTST_PROCESS_TYPE type,
  288. VSTST_ACCOUNT_TYPE account,
  289. LPCWSTR wszCommandLine,
  290. UINT lifetime,
  291. HANDLE hevtNotify
  292. )
  293. {
  294. m_processId = processId;
  295. m_type = type;
  296. m_account = account;
  297. m_bConforming = false;
  298. PROCESS_INFORMATION info;
  299. STARTUPINFO startup;
  300. memset(&startup, 0, sizeof(STARTUPINFO));
  301. startup.cb = sizeof(STARTUPINFO);
  302. if (!CreateProcess
  303. (
  304. NULL,
  305. (LPWSTR) wszCommandLine,
  306. NULL,
  307. NULL,
  308. TRUE,
  309. NORMAL_PRIORITY_CLASS,
  310. NULL,
  311. NULL,
  312. &startup,
  313. &info
  314. ))
  315. return HRESULT_FROM_WIN32(GetLastError());
  316. m_hProcess = info.hProcess;
  317. m_hevtNotifyProcessTermination = hevtNotify;
  318. m_bAbnormallyTerminate = true;
  319. time(&m_timeProcessStart);
  320. m_timeProcessTerminate = m_timeProcessStart + lifetime;
  321. m_processList->LinkIntoProcessList(this);
  322. return S_OK;
  323. }
  324. void CVsTstProcess::DoTerminateProcess(bool bAgressive)
  325. {
  326. if (m_bAbnormallyTerminate)
  327. ForceTerminateProcess();
  328. else if (!m_bGracefullyTerminated)
  329. GracefullyTerminateProcess(bAgressive);
  330. else
  331. {
  332. // see if process is terminated
  333. DWORD dwErr = WaitForSingleObject(m_hProcess, 0);
  334. if (dwErr == WAIT_FAILED)
  335. ForceTerminateProcess();
  336. else if (dwErr == WAIT_TIMEOUT)
  337. {
  338. time_t timeCur;
  339. time(&timeCur);
  340. if (m_timeProcessTerminationExpiration < timeCur)
  341. // forcefully terminate the process
  342. ForceTerminateProcess();
  343. // if we are shutting down, give the process 10 seconds
  344. // to shut down before we forcefully terminate it
  345. if (bAgressive && m_timeProcessTerminationExpiration > timeCur + 10)
  346. m_timeProcessTerminationExpiration = timeCur + 10;
  347. }
  348. else
  349. CleanupProcess();
  350. }
  351. }
  352. // has process expired
  353. bool CVsTstProcess::HasProcessExpired()
  354. {
  355. // see if process is terminated
  356. DWORD dwErr = WaitForSingleObject(m_hProcess, 0);
  357. if (dwErr == WAIT_OBJECT_0)
  358. {
  359. CleanupProcess();
  360. return false;
  361. }
  362. time_t timeVal;
  363. time(&timeVal);
  364. return timeVal > m_timeProcessTerminate;
  365. }
  366. // cleanup process at termination
  367. void CVsTstProcess::CleanupProcess()
  368. {
  369. if (m_hevtNotifyProcessTermination)
  370. {
  371. if (!SetEvent(m_hevtNotifyProcessTermination))
  372. LogUnexpectedFailure(L"SetEvent failed with error %d", GetLastError());
  373. }
  374. m_processList->UnlinkFromProcessList(this);
  375. }
  376. // forceably terminate the process
  377. void CVsTstProcess::ForceTerminateProcess()
  378. {
  379. if (!TerminateProcess(m_hProcess, 0))
  380. LogUnexpectedFailure(L"Terminate process failed with error %d", GetLastError());
  381. CleanupProcess();
  382. }
  383. // try terminating the process gracefully
  384. void CVsTstProcess::GracefullyTerminateProcess(bool bAgressive)
  385. {
  386. VSTST_ASSERT(m_hevtGracefullyTerminate);
  387. if (!SetEvent(m_hevtGracefullyTerminate))
  388. LogUnexpectedFailure(L"SetEvent failed with error %d", GetLastError());
  389. m_bGracefullyTerminated = true;
  390. time(&m_timeProcessStartTermination);
  391. // allow 2 minutes for the process to gracefully terminate, 10 seconds if
  392. // if we are agressive
  393. m_timeProcessTerminationExpiration = m_timeProcessStartTermination + bAgressive ? 10 : 120;
  394. }
  395. HRESULT CVsTstProcessList::CreateConformingExe
  396. (
  397. VSTST_PROCESS_TYPE type,
  398. VSTST_ACCOUNT_TYPE account,
  399. LPCWSTR wszExecutableName,
  400. LPCWSTR wszScenarioFile,
  401. LPCWSTR wszSectionName,
  402. DWORD seed,
  403. UINT lifetime,
  404. bool bAbnormalTerminate,
  405. HANDLE hevtNotify,
  406. ULONGLONG &processId
  407. )
  408. {
  409. processId = AllocateProcessId();
  410. CVsTstProcess *process = new CVsTstProcess(this);
  411. if (process == NULL)
  412. return E_OUTOFMEMORY;
  413. HRESULT hr = process->InitializeConformingExe
  414. (
  415. processId,
  416. type,
  417. account,
  418. wszExecutableName,
  419. wszScenarioFile,
  420. wszSectionName,
  421. seed,
  422. lifetime,
  423. bAbnormalTerminate,
  424. hevtNotify
  425. );
  426. if (FAILED(hr))
  427. delete process;
  428. return hr;
  429. }
  430. // create a process for a non-conforming executable
  431. HRESULT CVsTstProcessList::CreateNonConformingExe
  432. (
  433. VSTST_PROCESS_TYPE type,
  434. VSTST_ACCOUNT_TYPE account,
  435. LPCWSTR wszCommandLine,
  436. UINT lifetime,
  437. HANDLE hevtNotify,
  438. ULONGLONG &processId
  439. )
  440. {
  441. processId = AllocateProcessId();
  442. CVsTstProcess *process = new CVsTstProcess(this);
  443. if (process == NULL)
  444. return E_OUTOFMEMORY;
  445. HRESULT hr = process->InitializeNonConformingExe
  446. (
  447. processId,
  448. type,
  449. account,
  450. wszCommandLine,
  451. lifetime,
  452. hevtNotify
  453. );
  454. if (FAILED(hr))
  455. delete process;
  456. return hr;
  457. }
  458. // find a specific process
  459. CVsTstProcess *CVsTstProcessList::FindProcess(ULONGLONG processId)
  460. {
  461. m_csProcessList.Lock();
  462. CVsTstProcess *process = m_processList;
  463. while(process != NULL)
  464. {
  465. if (process->m_processId == processId)
  466. {
  467. m_csProcessList.Unlock();
  468. return process;
  469. }
  470. process = process->m_next;
  471. }
  472. return NULL;
  473. }
  474. // get private data associated with a process
  475. void *CVsTstProcessList::GetProcessPrivateData(LONGLONG processId)
  476. {
  477. CVsTstProcess *process = FindProcess(processId);
  478. if (process == NULL)
  479. return NULL;
  480. else
  481. return process->GetPrivateData();
  482. }
  483. // set private data associated with a process
  484. void CVsTstProcessList::SetProcessPrivateData(LONGLONG processId, void *pv)
  485. {
  486. CVsTstProcess *process = FindProcess(processId);
  487. if (process != NULL)
  488. process->SetPrivateData(pv);
  489. }
  490. // indicate that no more processes will be created
  491. void CVsTstProcessList::EndOfProcessCreation()
  492. {
  493. m_bNoMoreProcessesAreCreated = true;
  494. }
  495. ULONGLONG CVsTstProcessList::AllocateProcessId()
  496. {
  497. m_csProcessList.Lock();
  498. ULONGLONG processId = ++m_processId;
  499. m_csProcessList.Unlock();
  500. return processId;
  501. }
  502. static VSTST_CMDDESC x_rgCommands[] =
  503. {
  504. {
  505. L"scenario",
  506. VSTST_CT_STRING,
  507. VSTST_CP_SCENARIOFILE
  508. },
  509. {
  510. L"testseries",
  511. VSTST_CT_STRING,
  512. VSTST_CP_TESTSERIES
  513. },
  514. {
  515. L"section",
  516. VSTST_CT_STRING,
  517. VSTST_CP_SECTIONNAME
  518. },
  519. {
  520. L"seed",
  521. VSTST_CT_UINT,
  522. VSTST_CP_SEED
  523. },
  524. {
  525. L"lifetime",
  526. VSTST_CT_UINT,
  527. VSTST_CP_LIFETIME,
  528. },
  529. {
  530. L"event",
  531. VSTST_CT_HANDLE,
  532. VSTST_CP_TERMINATIONEVENT
  533. },
  534. {
  535. L"pidLow",
  536. VSTST_CT_UINT,
  537. VSTST_CP_PIDLOW
  538. },
  539. {
  540. L"pidHigh",
  541. VSTST_CT_UINT,
  542. VSTST_CP_PIDHIGH
  543. }
  544. };
  545. static UINT x_cCommands = sizeof(x_rgCommands)/sizeof(x_rgCommands[0]);
  546. // constructor
  547. CVsTstParams::CVsTstParams() :
  548. m_wszScenarioFile(NULL),
  549. m_wszSectionName(NULL),
  550. m_wszTestSeries(NULL),
  551. m_supplied(0)
  552. {
  553. }
  554. // destructor
  555. CVsTstParams::~CVsTstParams()
  556. {
  557. delete m_wszScenarioFile;
  558. delete m_wszSectionName;
  559. }
  560. // parse the command line
  561. bool CVsTstParams::ParseCommandLine(WCHAR **argv, UINT argc)
  562. {
  563. for(UINT iarg = 1; iarg < argc; iarg++)
  564. {
  565. WCHAR *wsz = argv[iarg];
  566. if (wsz[0] != '-')
  567. return false;
  568. wsz++;
  569. WCHAR *pwc = wsz;
  570. while(*pwc != L'\0' && *pwc != L'=')
  571. pwc++;
  572. if (*pwc != '=')
  573. return false;
  574. *pwc++ = '\0';
  575. for(UINT icmd = 0; icmd < x_cCommands; icmd++)
  576. {
  577. if (wcscmp(wsz, x_rgCommands[icmd].wszParam) == 0)
  578. break;
  579. }
  580. if (icmd == x_cCommands)
  581. return false;
  582. VSTST_CMDDESC *pCommand = &x_rgCommands[icmd];
  583. UINT ulVal;
  584. LPWSTR wszVal;
  585. HANDLE hVal;
  586. switch(pCommand->type)
  587. {
  588. default:
  589. VSTST_ASSERT(FALSE && "shouldn't get here");
  590. return false;
  591. case VSTST_CT_UINT:
  592. if (!ParseUINT(pwc, &ulVal))
  593. return false;
  594. switch(pCommand->param)
  595. {
  596. default:
  597. VSTST_ASSERT(FALSE && "shouldn't get here");
  598. return false;
  599. case VSTST_CP_SEED:
  600. SetSeed(ulVal);
  601. break;
  602. case VSTST_CP_LIFETIME:
  603. SetLifetime(ulVal);
  604. break;
  605. case VSTST_CP_PIDLOW:
  606. SetPidLow(ulVal);
  607. break;
  608. case VSTST_CP_PIDHIGH:
  609. SetPidHigh(ulVal);
  610. break;
  611. }
  612. break;
  613. case VSTST_CT_HANDLE:
  614. if (!ParseHandle(pwc, &hVal))
  615. return false;
  616. if (pCommand->param == VSTST_CP_TERMINATIONEVENT)
  617. SetTerminationEvent(hVal);
  618. else
  619. {
  620. VSTST_ASSERT(FALSE && "shouldn't get here");
  621. return false;
  622. }
  623. break;
  624. case VSTST_CT_STRING:
  625. if (!ParseString(pwc, &wszVal))
  626. return false;
  627. switch(pCommand->param)
  628. {
  629. default:
  630. VSTST_ASSERT(FALSE && "shouldn't get here");
  631. return false;
  632. case VSTST_CP_SCENARIOFILE:
  633. SetScenarioFile(wszVal);
  634. break;
  635. case VSTST_CP_TESTSERIES:
  636. SetTestSeries(wszVal);
  637. break;
  638. case VSTST_CP_SECTIONNAME:
  639. SetSectionName(wszVal);
  640. break;
  641. }
  642. break;
  643. }
  644. }
  645. m_hTestTerminationEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
  646. if (m_hTerminationEvent == NULL)
  647. return false;
  648. m_supplied |= VSTST_CP_TESTTERMINATIONEVENT;
  649. return true;
  650. }
  651. bool CVsTstParams::ParseUINT(LPCWSTR wsz, UINT *pulVal)
  652. {
  653. UINT ulVal = 0;
  654. if (*wsz == L'\0')
  655. return false;
  656. do
  657. {
  658. WCHAR wc = *wsz++;
  659. if (wc < L'0' || wc > L'9')
  660. return false;
  661. UINT ulValNew = ulVal * 10 + (wc - L'0');
  662. if (ulValNew < ulVal)
  663. return false;
  664. ulVal = ulValNew;
  665. } while(*wsz != L'\0');
  666. *pulVal = ulVal;
  667. return true;
  668. }
  669. // parse a string value of the form "..."
  670. bool CVsTstParams::ParseString(LPCWSTR wsz, LPWSTR *pwszVal)
  671. {
  672. if (*wsz != L'{')
  673. return false;
  674. wsz++;
  675. LPCWSTR wszStart = wsz;
  676. while(*wsz != L'\0' && *wsz != '}')
  677. wsz++;
  678. if (*wsz != L'}')
  679. return false;
  680. UINT cwc = (UINT)( wsz - wszStart );
  681. LPWSTR wszRet = new WCHAR[cwc + 1];
  682. memcpy(wszRet, wszStart, cwc * sizeof(WCHAR));
  683. wszRet[cwc] = L'\0';
  684. *pwszVal = wszRet;
  685. return true;
  686. }
  687. bool CVsTstParams::ParseHandle(LPCWSTR wsz, HANDLE *phVal)
  688. {
  689. UINT ulVal = 0;
  690. if (*wsz++ != L'0')
  691. return false;
  692. if (*wsz++ != L'x')
  693. return false;
  694. if (*wsz == L'\0')
  695. return false;
  696. do
  697. {
  698. WCHAR wc = *wsz++;
  699. UINT digit;
  700. if (wc >= L'0' && wc <= L'9')
  701. digit = wc - L'0';
  702. else if (wc >= L'a' && wc <= L'f')
  703. digit = wc - L'a' + 10;
  704. else if (wc >= L'A' && wc <= L'F')
  705. digit = wc - L'A' + 10;
  706. else
  707. return false;
  708. if (ulVal & 0xf0000000)
  709. return false;
  710. ulVal = ulVal << 4 | digit;
  711. } while(*wsz != L'\0');
  712. *phVal = (HANDLE)(ULONGLONG) ulVal;
  713. return true;
  714. }
  715. bool CVsTstParams::GetScenarioFileName(LPCWSTR *pwszScenarioFile)
  716. {
  717. if ((m_supplied & VSTST_CP_SCENARIOFILE) == 0)
  718. {
  719. *pwszScenarioFile = NULL;
  720. return false;
  721. }
  722. else
  723. {
  724. *pwszScenarioFile = m_wszScenarioFile;
  725. return true;
  726. }
  727. }
  728. bool CVsTstParams::GetTestSeries(LPCWSTR *pwszTestSeries)
  729. {
  730. if ((m_supplied & VSTST_CP_TESTSERIES) == 0)
  731. {
  732. *pwszTestSeries = NULL;
  733. return false;
  734. }
  735. else
  736. {
  737. *pwszTestSeries = m_wszTestSeries;
  738. return true;
  739. }
  740. }
  741. bool CVsTstParams::GetSectionName(LPCWSTR *pwszSectionName)
  742. {
  743. if ((m_supplied & VSTST_CP_SECTIONNAME) == 0)
  744. {
  745. *pwszSectionName = NULL;
  746. return false;
  747. }
  748. else
  749. {
  750. *pwszSectionName = m_wszSectionName;
  751. return true;
  752. }
  753. }
  754. bool CVsTstParams::GetRandomSeed(UINT *pSeed)
  755. {
  756. if ((m_supplied & VSTST_CP_SEED) == 0)
  757. return false;
  758. else
  759. {
  760. *pSeed = m_seed;
  761. return true;
  762. }
  763. }
  764. bool CVsTstParams::GetLifetime(UINT *pLifetime)
  765. {
  766. if ((m_supplied & VSTST_CP_LIFETIME) == 0)
  767. return false;
  768. else
  769. {
  770. *pLifetime = m_lifetime;
  771. return true;
  772. }
  773. }
  774. bool CVsTstParams::GetTerminationEvent(HANDLE *pHandle)
  775. {
  776. if ((m_supplied & VSTST_CP_TERMINATIONEVENT) == 0)
  777. {
  778. *pHandle = NULL;
  779. return false;
  780. }
  781. else
  782. {
  783. *pHandle = m_hTerminationEvent;
  784. return true;
  785. }
  786. }
  787. bool CVsTstParams::GetTestTerminationEvent(HANDLE *pHandle)
  788. {
  789. if ((m_supplied & VSTST_CP_TESTTERMINATIONEVENT) == 0)
  790. {
  791. *pHandle = NULL;
  792. return false;
  793. }
  794. else
  795. {
  796. *pHandle = m_hTestTerminationEvent;
  797. return true;
  798. }
  799. }
  800. bool CVsTstParams::GetProcessId(ULONGLONG *pid)
  801. {
  802. if ((m_supplied & VSTST_CP_PIDLOW) == 0)
  803. return false;
  804. else if ((m_supplied & VSTST_CP_PIDHIGH) == 0)
  805. {
  806. *pid = m_pidLow;
  807. return true;
  808. }
  809. else
  810. {
  811. *pid = (((ULONGLONG) m_pidHigh) << 32) + m_pidLow;
  812. return true;
  813. }
  814. }
  815. void CVsTstParams::SetSeed(UINT ulVal)
  816. {
  817. if (ulVal != 0)
  818. {
  819. m_supplied |= VSTST_CP_SEED;
  820. m_seed = ulVal;
  821. }
  822. }
  823. void CVsTstParams::SetLifetime(UINT ulVal)
  824. {
  825. if (ulVal != 0)
  826. {
  827. m_supplied |= VSTST_CP_LIFETIME;
  828. m_lifetime = ulVal;
  829. }
  830. }
  831. void CVsTstParams::SetPidLow(UINT ulVal)
  832. {
  833. m_supplied |= VSTST_CP_PIDLOW;
  834. m_pidLow = ulVal;
  835. }
  836. void CVsTstParams::SetPidHigh(UINT ulVal)
  837. {
  838. m_supplied |= VSTST_CP_PIDHIGH;
  839. m_pidHigh = ulVal;
  840. }
  841. void CVsTstParams::SetTerminationEvent(HANDLE hEvent)
  842. {
  843. if (hEvent != NULL)
  844. {
  845. m_supplied |= VSTST_CP_TERMINATIONEVENT;
  846. m_hTerminationEvent = hEvent;
  847. }
  848. }
  849. void CVsTstParams::SetScenarioFile(LPWSTR wsz)
  850. {
  851. m_supplied |= VSTST_CP_SCENARIOFILE;
  852. m_wszScenarioFile = wsz;
  853. }
  854. void CVsTstParams::SetTestSeries(LPWSTR wsz)
  855. {
  856. m_supplied |= VSTST_CP_TESTSERIES;
  857. m_wszTestSeries = wsz;
  858. }
  859. void CVsTstParams::SetSectionName(LPWSTR wsz)
  860. {
  861. m_supplied |= VSTST_CP_SECTIONNAME;
  862. m_wszSectionName = wsz;
  863. }
  864. // arguments to the test termination thread
  865. typedef struct _TerminationThreadParams
  866. {
  867. CVsTstParams *pParams;
  868. IVsTstRunningTest *pTest;
  869. } TerminationThreadParams;
  870. static LPCWSTR x_wszVssTestController = L"VssTestController.";
  871. static LPCWSTR x_wszVssTestRequestor = L"VssTestRequestor.";
  872. static LPCWSTR x_wszVssTestWriter = L"VssTestWriter.";
  873. // toplevel routine to run a test
  874. // it parses the parameters
  875. // creates a configuration file parser
  876. // creates a message pipe to the server
  877. // creates a thread to terminate the test
  878. // calls the supplied test
  879. //
  880. HRESULT CVsTstRunner::RunVsTest
  881. (
  882. WCHAR **argv,
  883. UINT argc,
  884. IVsTstRunningTest *pTest,
  885. bool bCreateTerminationThread
  886. )
  887. {
  888. CVsTstParams params;
  889. params.ParseCommandLine(argv, argc);
  890. LPCWSTR wszScenarioFile, wszSectionName, wszQualifier;
  891. if (!params.GetScenarioFileName(&wszScenarioFile) ||
  892. !params.GetSectionName(&wszSectionName))
  893. {
  894. VSTST_ASSERT(FALSE && "missing scenario");
  895. return E_FAIL;
  896. }
  897. EVsTstINISectionType sectionType;
  898. if (memcmp(wszSectionName, x_wszVssTestWriter, wcslen(x_wszVssTestWriter) * sizeof(WCHAR)) == 0)
  899. {
  900. sectionType = eVsTstSectionType_TestWriter;
  901. wszQualifier = wszSectionName + wcslen(x_wszVssTestWriter);
  902. }
  903. else if (memcmp(wszSectionName, x_wszVssTestRequestor, wcslen(x_wszVssTestRequestor)) == 0)
  904. {
  905. sectionType = eVsTstSectionType_TestRequesterApp;
  906. wszQualifier = wszSectionName + wcslen(x_wszVssTestRequestor);
  907. }
  908. else if (memcmp(wszSectionName, x_wszVssTestController, wcslen(x_wszVssTestController)) == 0)
  909. {
  910. sectionType = eVsTstSectionType_TestCoordinator;
  911. wszQualifier = wszSectionName + wcslen(x_wszVssTestController);
  912. }
  913. else
  914. {
  915. VSTST_ASSERT(FALSE && "bad test type");
  916. return E_FAIL;
  917. }
  918. HRESULT hr = S_OK;
  919. DWORD tid;
  920. TerminationThreadParams *pTTParm = NULL;
  921. HANDLE hTerminationThread = NULL;
  922. if (bCreateTerminationThread)
  923. {
  924. pTTParm = new TerminationThreadParams;
  925. if (pTTParm == NULL)
  926. {
  927. VSTST_ASSERT(FALSE && "Out of memory");
  928. return E_OUTOFMEMORY;
  929. }
  930. pTTParm->pParams = &params;
  931. pTTParm->pTest = pTest;
  932. hTerminationThread = CreateThread
  933. (
  934. NULL,
  935. 32*1024,
  936. CVsTstRunner::StartupTerminationThread,
  937. pTTParm,
  938. 0,
  939. &tid
  940. );
  941. if(hTerminationThread == NULL)
  942. {
  943. VSTST_ASSERT(FALSE && "Thread creation failed");
  944. delete pTTParm;
  945. return HRESULT_FROM_WIN32(GetLastError());
  946. }
  947. }
  948. try
  949. {
  950. InitMsgTypes();
  951. unsigned cwc = (unsigned)wcslen(wszScenarioFile);
  952. WCHAR *wszFileName = new WCHAR[cwc * 2];
  953. if (!ExpandEnvironmentStrings(wszScenarioFile, wszFileName, cwc * 2))
  954. {
  955. VSTST_ASSERT(FALSE && "ExpandEnvironmentStrings failed");
  956. LogUnexpectedFailure(L"ExpandEnvironmentStrings failed with error %d", GetLastError());
  957. throw E_UNEXPECTED;
  958. }
  959. CVsTstINIConfig config(sectionType, wszQualifier, FALSE, wszFileName);
  960. CVsTstClientMsg client;
  961. ULONGLONG processId;
  962. if (!params.GetProcessId(&processId))
  963. {
  964. VSTST_ASSERT(FALSE && "no process id");
  965. throw(E_FAIL);
  966. }
  967. client.Init(processId, 1024, false);
  968. hr = pTest->RunTest(&config, &client, &params);
  969. }
  970. catch(...)
  971. {
  972. VSTST_ASSERT(FALSE && "unexpected exception");
  973. hr = E_FAIL;
  974. }
  975. HANDLE hTestTerminationEvent;
  976. if (!params.GetTestTerminationEvent(&hTestTerminationEvent))
  977. LogUnexpectedFailure(L"Test Termination Event wasn't created");
  978. else if (!SetEvent(hTestTerminationEvent))
  979. LogUnexpectedFailure(L"SetEvent failed with error %d", GetLastError());
  980. else
  981. {
  982. if (hTerminationThread != NULL &&
  983. WaitForSingleObject(hTerminationThread, INFINITE) == WAIT_FAILED)
  984. LogUnexpectedFailure(L"WaitForSingleObject failed with error %d", GetLastError());
  985. }
  986. if (hTerminationThread != NULL)
  987. CloseHandle(hTerminationThread);
  988. return hr;
  989. }
  990. // termination thread routine waits until either
  991. // test lifetime is exceeded
  992. // termination event is set by controller
  993. // test termination event is set when test completes
  994. //
  995. DWORD CVsTstRunner::StartupTerminationThread(void *pv)
  996. {
  997. TerminationThreadParams *pTTParms = (TerminationThreadParams *) pv;
  998. CVsTstParams *pParams = pTTParms->pParams;
  999. IVsTstRunningTest *pTest = pTTParms->pTest;
  1000. delete pTTParms;
  1001. HANDLE hTestTerminationEvent;
  1002. HANDLE hTerminationEvent = NULL;
  1003. if (!pParams->GetTestTerminationEvent(&hTestTerminationEvent))
  1004. {
  1005. LogUnexpectedFailure(L"No Test Termination event was created.");
  1006. return 0xffffffff;
  1007. }
  1008. pParams->GetTerminationEvent(&hTerminationEvent);
  1009. UINT ulLifetime;
  1010. bool bLifetime = pParams->GetLifetime(&ulLifetime);
  1011. // more than one months worth of lifetime is infinite
  1012. if (bLifetime && ulLifetime < 3600 * 24 * 30)
  1013. ulLifetime = ulLifetime * 1000;
  1014. else
  1015. ulLifetime = INFINITE;
  1016. HANDLE rghEvt[2];
  1017. unsigned cEvt = 1;
  1018. rghEvt[0] = hTestTerminationEvent;
  1019. if (hTerminationEvent != NULL)
  1020. {
  1021. rghEvt[1] = hTerminationEvent;
  1022. cEvt++;
  1023. }
  1024. DWORD dwWait = WaitForMultipleObjects(cEvt, rghEvt, FALSE, ulLifetime);
  1025. if (dwWait == WAIT_FAILED)
  1026. LogUnexpectedFailure(L"Wait failed for reason %d", GetLastError());
  1027. else if (dwWait == WAIT_TIMEOUT)
  1028. pTest->ShutdownTest(VSTST_SR_LIFETIME_EXCEEDED);
  1029. else if (dwWait == WAIT_OBJECT_0 + 1)
  1030. pTest->ShutdownTest(VSTST_SR_CONTROLLER_SIGNALLED);
  1031. return 0;
  1032. }