Home | History | Annotate | Download | only in execserver
      1 /*-------------------------------------------------------------------------
      2  * drawElements Quality Program Execution Server
      3  * ---------------------------------------------
      4  *
      5  * Copyright 2014 The Android Open Source Project
      6  *
      7  * Licensed under the Apache License, Version 2.0 (the "License");
      8  * you may not use this file except in compliance with the License.
      9  * You may obtain a copy of the License at
     10  *
     11  *      http://www.apache.org/licenses/LICENSE-2.0
     12  *
     13  * Unless required by applicable law or agreed to in writing, software
     14  * distributed under the License is distributed on an "AS IS" BASIS,
     15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     16  * See the License for the specific language governing permissions and
     17  * limitations under the License.
     18  *
     19  *//*!
     20  * \file
     21  * \brief TestProcess implementation for Win32.
     22  *//*--------------------------------------------------------------------*/
     23 
     24 #include "xsWin32TestProcess.hpp"
     25 #include "deFilePath.hpp"
     26 #include "deString.h"
     27 #include "deMemory.h"
     28 #include "deClock.h"
     29 #include "deFile.h"
     30 
     31 #include <sstream>
     32 #include <string.h>
     33 
     34 using std::string;
     35 using std::vector;
     36 
     37 namespace xs
     38 {
     39 
     40 enum
     41 {
     42 	MAX_OLD_LOGFILE_DELETE_ATTEMPTS		= 20,	//!< How many times execserver tries to delete old log file
     43 	LOGFILE_DELETE_SLEEP_MS				= 50	//!< Sleep time (in ms) between log file delete attempts
     44 };
     45 
     46 namespace win32
     47 {
     48 
     49 // Error
     50 
     51 static std::string formatErrMsg (DWORD error, const char* msg)
     52 {
     53 	std::ostringstream	str;
     54 	LPSTR				msgBuf;
     55 
     56 #if defined(UNICODE)
     57 #	error Unicode not supported.
     58 #endif
     59 
     60 	if (FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER|FORMAT_MESSAGE_FROM_SYSTEM|FORMAT_MESSAGE_IGNORE_INSERTS,
     61 					  NULL, error, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPSTR)&msgBuf, 0, DE_NULL) > 0)
     62 		str << msg << ", error " << error << ": " << msgBuf;
     63 	else
     64 		str << msg << ", error " << error;
     65 
     66 	return str.str();
     67 }
     68 
     69 Error::Error (DWORD error, const char* msg)
     70 	: std::runtime_error(formatErrMsg(error, msg))
     71 	, m_error			(error)
     72 {
     73 }
     74 
     75 // Event
     76 
     77 Event::Event (bool manualReset, bool initialState)
     78 	: m_handle(0)
     79 {
     80 	m_handle = CreateEvent(NULL, manualReset ? TRUE : FALSE, initialState ? TRUE : FALSE, NULL);
     81 	if (!m_handle)
     82 		throw Error(GetLastError(), "CreateEvent() failed");
     83 }
     84 
     85 Event::~Event (void)
     86 {
     87 	CloseHandle(m_handle);
     88 }
     89 
     90 void Event::setSignaled (void)
     91 {
     92 	if (!SetEvent(m_handle))
     93 		throw Error(GetLastError(), "SetEvent() failed");
     94 }
     95 
     96 void Event::reset (void)
     97 {
     98 	if (!ResetEvent(m_handle))
     99 		throw Error(GetLastError(), "ResetEvent() failed");
    100 }
    101 
    102 // CaseListWriter
    103 
    104 CaseListWriter::CaseListWriter (void)
    105 	: m_dst			(INVALID_HANDLE_VALUE)
    106 	, m_cancelEvent	(true, false)
    107 {
    108 }
    109 
    110 CaseListWriter::~CaseListWriter (void)
    111 {
    112 }
    113 
    114 void CaseListWriter::start (const char* caseList, HANDLE dst)
    115 {
    116 	DE_ASSERT(!isStarted());
    117 
    118 	m_dst = dst;
    119 
    120 	int caseListSize = (int)strlen(caseList)+1;
    121 	m_caseList.resize(caseListSize);
    122 	std::copy(caseList, caseList+caseListSize, m_caseList.begin());
    123 
    124 	de::Thread::start();
    125 }
    126 
    127 void CaseListWriter::run (void)
    128 {
    129 	try
    130 	{
    131 		Event		ioEvent			(true, false); // Manual reset, non-signaled state.
    132 		HANDLE		waitHandles[]	= { ioEvent.getHandle(), m_cancelEvent.getHandle() };
    133 		OVERLAPPED	overlapped;
    134 		int			curPos = 0;
    135 
    136 		deMemset(&overlapped, 0, sizeof(overlapped));
    137 		overlapped.hEvent = ioEvent.getHandle();
    138 
    139 		while (curPos < (int)m_caseList.size())
    140 		{
    141 			const int	maxWriteSize	= 4096;
    142 			const int	numToWrite		= de::min(maxWriteSize, (int)m_caseList.size() - curPos);
    143 			DWORD		waitRes			= 0;
    144 
    145 			if (!WriteFile(m_dst, &m_caseList[curPos], (DWORD)numToWrite, NULL, &overlapped))
    146 			{
    147 				DWORD err = GetLastError();
    148 				if (err != ERROR_IO_PENDING)
    149 					throw Error(err, "WriteFile() failed");
    150 			}
    151 
    152 			waitRes = WaitForMultipleObjects(DE_LENGTH_OF_ARRAY(waitHandles), &waitHandles[0], FALSE, INFINITE);
    153 
    154 			if (waitRes == WAIT_OBJECT_0)
    155 			{
    156 				DWORD numBytesWritten = 0;
    157 
    158 				// \note GetOverlappedResult() will fail with ERROR_IO_INCOMPLETE if IO event is not complete (should be).
    159 				if (!GetOverlappedResult(m_dst, &overlapped, &numBytesWritten, FALSE))
    160 					throw Error(GetLastError(), "GetOverlappedResult() failed");
    161 
    162 				if (numBytesWritten == 0)
    163 					throw Error(GetLastError(), "Writing to pipe failed (pipe closed?)");
    164 
    165 				curPos += (int)numBytesWritten;
    166 			}
    167 			else if (waitRes == WAIT_OBJECT_0 + 1)
    168 			{
    169 				// Cancel.
    170 				if (!CancelIo(m_dst))
    171 					throw Error(GetLastError(), "CancelIo() failed");
    172 				break;
    173 			}
    174 			else
    175 				throw Error(GetLastError(), "WaitForMultipleObjects() failed");
    176 		}
    177 	}
    178 	catch (const std::exception& e)
    179 	{
    180 		// \todo [2013-08-13 pyry] What to do about this?
    181 		printf("win32::CaseListWriter::run(): %s\n", e.what());
    182 	}
    183 }
    184 
    185 void CaseListWriter::stop (void)
    186 {
    187 	if (!isStarted())
    188 		return; // Nothing to do.
    189 
    190 	m_cancelEvent.setSignaled();
    191 
    192 	// Join thread.
    193 	join();
    194 
    195 	m_cancelEvent.reset();
    196 
    197 	m_dst = INVALID_HANDLE_VALUE;
    198 }
    199 
    200 // FileReader
    201 
    202 FileReader::FileReader (ThreadedByteBuffer* dst)
    203 	: m_dstBuf		(dst)
    204 	, m_handle		(INVALID_HANDLE_VALUE)
    205 	, m_cancelEvent	(false, false)
    206 {
    207 }
    208 
    209 FileReader::~FileReader (void)
    210 {
    211 }
    212 
    213 void FileReader::start (HANDLE file)
    214 {
    215 	DE_ASSERT(!isStarted());
    216 
    217 	m_handle = file;
    218 
    219 	de::Thread::start();
    220 }
    221 
    222 void FileReader::run (void)
    223 {
    224 	try
    225 	{
    226 		Event					ioEvent			(true, false); // Manual reset, not signaled state.
    227 		HANDLE					waitHandles[]	= { ioEvent.getHandle(), m_cancelEvent.getHandle() };
    228 		OVERLAPPED				overlapped;
    229 		std::vector<deUint8>	tmpBuf			(FILEREADER_TMP_BUFFER_SIZE);
    230 		deUint64				offset			= 0; // Overlapped IO requires manual offset keeping.
    231 
    232 		deMemset(&overlapped, 0, sizeof(overlapped));
    233 		overlapped.hEvent = ioEvent.getHandle();
    234 
    235 		for (;;)
    236 		{
    237 			DWORD	numBytesRead	= 0;
    238 			DWORD	waitRes;
    239 
    240 			overlapped.Offset		= (DWORD)(offset & 0xffffffffu);
    241 			overlapped.OffsetHigh	= (DWORD)(offset >> 32);
    242 
    243 			if (!ReadFile(m_handle, &tmpBuf[0], (DWORD)tmpBuf.size(), NULL, &overlapped))
    244 			{
    245 				DWORD err = GetLastError();
    246 
    247 				if (err == ERROR_BROKEN_PIPE)
    248 					break;
    249 				else if (err == ERROR_HANDLE_EOF)
    250 				{
    251 					if (m_dstBuf->isCanceled())
    252 						break;
    253 
    254 					deSleep(FILEREADER_IDLE_SLEEP);
    255 
    256 					if (m_dstBuf->isCanceled())
    257 						break;
    258 					else
    259 						continue;
    260 				}
    261 				else if (err != ERROR_IO_PENDING)
    262 					throw Error(err, "ReadFile() failed");
    263 			}
    264 
    265 			waitRes = WaitForMultipleObjects(DE_LENGTH_OF_ARRAY(waitHandles), &waitHandles[0], FALSE, INFINITE);
    266 
    267 			if (waitRes == WAIT_OBJECT_0)
    268 			{
    269 				// \note GetOverlappedResult() will fail with ERROR_IO_INCOMPLETE if IO event is not complete (should be).
    270 				if (!GetOverlappedResult(m_handle, &overlapped, &numBytesRead, FALSE))
    271 				{
    272 					DWORD err = GetLastError();
    273 
    274 					if (err == ERROR_HANDLE_EOF)
    275 					{
    276 						// End of file - for now.
    277 						// \note Should check for end of buffer here, or otherwise may end up in infinite loop.
    278 						if (m_dstBuf->isCanceled())
    279 							break;
    280 
    281 						deSleep(FILEREADER_IDLE_SLEEP);
    282 
    283 						if (m_dstBuf->isCanceled())
    284 							break;
    285 						else
    286 							continue;
    287 					}
    288 					else if (err == ERROR_BROKEN_PIPE)
    289 						break;
    290 					else
    291 						throw Error(err, "GetOverlappedResult() failed");
    292 				}
    293 
    294 				if (numBytesRead == 0)
    295 					throw Error(GetLastError(), "Reading from file failed");
    296 				else
    297 					offset += (deUint64)numBytesRead;
    298 			}
    299 			else if (waitRes == WAIT_OBJECT_0 + 1)
    300 			{
    301 				// Cancel.
    302 				if (!CancelIo(m_handle))
    303 					throw Error(GetLastError(), "CancelIo() failed");
    304 				break;
    305 			}
    306 			else
    307 				throw Error(GetLastError(), "WaitForMultipleObjects() failed");
    308 
    309 			try
    310 			{
    311 				m_dstBuf->write((int)numBytesRead, &tmpBuf[0]);
    312 				m_dstBuf->flush();
    313 			}
    314 			catch (const ThreadedByteBuffer::CanceledException&)
    315 			{
    316 				// Canceled.
    317 				break;
    318 			}
    319 		}
    320 	}
    321 	catch (const std::exception& e)
    322 	{
    323 		// \todo [2013-08-13 pyry] What to do?
    324 		printf("win32::FileReader::run(): %s\n", e.what());
    325 	}
    326 }
    327 
    328 void FileReader::stop (void)
    329 {
    330 	if (!isStarted())
    331 		return; // Nothing to do.
    332 
    333 	m_cancelEvent.setSignaled();
    334 
    335 	// Join thread.
    336 	join();
    337 
    338 	m_cancelEvent.reset();
    339 
    340 	m_handle = INVALID_HANDLE_VALUE;
    341 }
    342 
    343 // TestLogReader
    344 
    345 TestLogReader::TestLogReader (void)
    346 	: m_logBuffer	(LOG_BUFFER_BLOCK_SIZE, LOG_BUFFER_NUM_BLOCKS)
    347 	, m_logFile		(INVALID_HANDLE_VALUE)
    348 	, m_reader		(&m_logBuffer)
    349 {
    350 }
    351 
    352 TestLogReader::~TestLogReader (void)
    353 {
    354 	if (m_logFile != INVALID_HANDLE_VALUE)
    355 		CloseHandle(m_logFile);
    356 }
    357 
    358 void TestLogReader::start (const char* filename)
    359 {
    360 	DE_ASSERT(m_logFile == INVALID_HANDLE_VALUE && !m_reader.isStarted());
    361 
    362 	m_logFile = CreateFile(filename,
    363 						   GENERIC_READ,
    364 						   FILE_SHARE_DELETE|FILE_SHARE_READ|FILE_SHARE_WRITE,
    365 						   DE_NULL,
    366 						   OPEN_EXISTING,
    367 						   FILE_ATTRIBUTE_NORMAL|FILE_FLAG_OVERLAPPED,
    368 						   DE_NULL);
    369 
    370 	if (m_logFile == INVALID_HANDLE_VALUE)
    371 		throw Error(GetLastError(), "Failed to open log file");
    372 
    373 	m_reader.start(m_logFile);
    374 }
    375 
    376 void TestLogReader::stop (void)
    377 {
    378 	if (!m_reader.isStarted())
    379 		return; // Nothing to do.
    380 
    381 	m_logBuffer.cancel();
    382 	m_reader.stop();
    383 
    384 	CloseHandle(m_logFile);
    385 	m_logFile = INVALID_HANDLE_VALUE;
    386 
    387 	m_logBuffer.clear();
    388 }
    389 
    390 // Process
    391 
    392 Process::Process (void)
    393 	: m_state		(STATE_NOT_STARTED)
    394 	, m_exitCode	(0)
    395 	, m_standardIn	(INVALID_HANDLE_VALUE)
    396 	, m_standardOut	(INVALID_HANDLE_VALUE)
    397 	, m_standardErr	(INVALID_HANDLE_VALUE)
    398 {
    399 	deMemset(&m_procInfo, 0, sizeof(m_procInfo));
    400 }
    401 
    402 Process::~Process (void)
    403 {
    404 	try
    405 	{
    406 		if (isRunning())
    407 		{
    408 			kill();
    409 			waitForFinish();
    410 		}
    411 	}
    412 	catch (...)
    413 	{
    414 	}
    415 
    416 	cleanupHandles();
    417 }
    418 
    419 void Process::cleanupHandles (void)
    420 {
    421 	DE_ASSERT(!isRunning());
    422 
    423 	if (m_standardErr != INVALID_HANDLE_VALUE)
    424 		CloseHandle(m_standardErr);
    425 
    426 	if (m_standardOut != INVALID_HANDLE_VALUE)
    427 		CloseHandle(m_standardOut);
    428 
    429 	if (m_standardIn != INVALID_HANDLE_VALUE)
    430 		CloseHandle(m_standardIn);
    431 
    432 	if (m_procInfo.hProcess)
    433 		CloseHandle(m_procInfo.hProcess);
    434 
    435 	if (m_procInfo.hThread)
    436 		CloseHandle(m_procInfo.hThread);
    437 
    438 	m_standardErr	= INVALID_HANDLE_VALUE;
    439 	m_standardOut	= INVALID_HANDLE_VALUE;
    440 	m_standardIn	= INVALID_HANDLE_VALUE;
    441 
    442 	deMemset(&m_procInfo, 0, sizeof(m_procInfo));
    443 }
    444 
    445 __declspec(thread) static int t_pipeNdx = 0;
    446 
    447 static void createPipeWithOverlappedIO (HANDLE* readHandleOut, HANDLE* writeHandleOut, deUint32 readMode, deUint32 writeMode, SECURITY_ATTRIBUTES* securityAttr)
    448 {
    449 	const int	defaultBufSize	= 4096;
    450 	char		pipeName[128];
    451 	HANDLE		readHandle;
    452 	HANDLE		writeHandle;
    453 
    454 	DE_ASSERT(((readMode | writeMode) & ~FILE_FLAG_OVERLAPPED) == 0);
    455 
    456 	deSprintf(pipeName, sizeof(pipeName), "\\\\.\\Pipe\\dEQP-ExecServer-%08x-%08x-%08x",
    457 			  GetCurrentProcessId(),
    458 			  GetCurrentThreadId(),
    459 			  t_pipeNdx++);
    460 
    461 	readHandle = CreateNamedPipe(pipeName,						/* Pipe name.				*/
    462 								 PIPE_ACCESS_INBOUND|readMode,	/* Open mode.				*/
    463 								 PIPE_TYPE_BYTE|PIPE_WAIT,		/* Pipe flags.				*/
    464 								 1,								/* Max number of instances.	*/
    465 								 defaultBufSize,				/* Output buffer size.		*/
    466 								 defaultBufSize,				/* Input buffer size.		*/
    467 								 0,								/* Use default timeout.		*/
    468 								 securityAttr);
    469 
    470 	if (readHandle == INVALID_HANDLE_VALUE)
    471 		throw Error(GetLastError(), "CreateNamedPipe() failed");
    472 
    473 	writeHandle = CreateFile(pipeName,
    474 							 GENERIC_WRITE,						/* Access mode.				*/
    475 							 0,									/* No sharing.				*/
    476 							 securityAttr,
    477 							 OPEN_EXISTING,						/* Assume existing object.	*/
    478 							 FILE_ATTRIBUTE_NORMAL|writeMode,	/* Open mode / flags.		*/
    479 							 DE_NULL							/* Template file.			*/);
    480 
    481 	if (writeHandle == INVALID_HANDLE_VALUE)
    482 	{
    483 		DWORD openErr = GetLastError();
    484 		CloseHandle(readHandle);
    485 		throw Error(openErr, "Failed to open created pipe, CreateFile() failed");
    486 	}
    487 
    488 	*readHandleOut	= readHandle;
    489 	*writeHandleOut	= writeHandle;
    490 }
    491 
    492 void Process::start (const char* commandLine, const char* workingDirectory)
    493 {
    494 	// Pipes.
    495 	HANDLE		stdInRead	= INVALID_HANDLE_VALUE;
    496 	HANDLE		stdInWrite	= INVALID_HANDLE_VALUE;
    497 	HANDLE		stdOutRead	= INVALID_HANDLE_VALUE;
    498 	HANDLE		stdOutWrite	= INVALID_HANDLE_VALUE;
    499 	HANDLE		stdErrRead	= INVALID_HANDLE_VALUE;
    500 	HANDLE		stdErrWrite	= INVALID_HANDLE_VALUE;
    501 
    502 	if (m_state == STATE_RUNNING)
    503 		throw std::runtime_error("Process already running");
    504 	else if (m_state == STATE_FINISHED)
    505 	{
    506 		// Process finished, clean up old cruft.
    507 		cleanupHandles();
    508 		m_state = STATE_NOT_STARTED;
    509 	}
    510 
    511 	// Create pipes
    512 	try
    513 	{
    514 		SECURITY_ATTRIBUTES	securityAttr;
    515 		STARTUPINFO			startInfo;
    516 
    517 		deMemset(&startInfo, 0, sizeof(startInfo));
    518 		deMemset(&securityAttr, 0, sizeof(securityAttr));
    519 
    520 		// Security attributes for inheriting handle.
    521 		securityAttr.nLength				= sizeof(SECURITY_ATTRIBUTES);
    522 		securityAttr.bInheritHandle			= TRUE;
    523 		securityAttr.lpSecurityDescriptor	= DE_NULL;
    524 
    525 		createPipeWithOverlappedIO(&stdInRead,	&stdInWrite,	0, FILE_FLAG_OVERLAPPED, &securityAttr);
    526 		createPipeWithOverlappedIO(&stdOutRead,	&stdOutWrite,	FILE_FLAG_OVERLAPPED, 0, &securityAttr);
    527 		createPipeWithOverlappedIO(&stdErrRead,	&stdErrWrite,	FILE_FLAG_OVERLAPPED, 0, &securityAttr);
    528 
    529 		if (!SetHandleInformation(stdInWrite, HANDLE_FLAG_INHERIT, 0) ||
    530 			!SetHandleInformation(stdOutRead, HANDLE_FLAG_INHERIT, 0) ||
    531 			!SetHandleInformation(stdErrRead, HANDLE_FLAG_INHERIT, 0))
    532 			throw Error(GetLastError(), "SetHandleInformation() failed");
    533 
    534 		// Startup info for process.
    535 		startInfo.cb			= sizeof(startInfo);
    536 		startInfo.hStdError		 = stdErrWrite;
    537 		startInfo.hStdOutput	 = stdOutWrite;
    538 		startInfo.hStdInput		 = stdInRead;
    539 		startInfo.dwFlags		|= STARTF_USESTDHANDLES;
    540 
    541 		if (!CreateProcess(DE_NULL, (LPTSTR)commandLine, DE_NULL, DE_NULL, TRUE /* inherit handles */, 0, DE_NULL, workingDirectory, &startInfo, &m_procInfo))
    542 			throw Error(GetLastError(), "CreateProcess() failed");
    543 	}
    544 	catch (...)
    545 	{
    546 		if (stdInRead	!= INVALID_HANDLE_VALUE)	CloseHandle(stdInRead);
    547 		if (stdInWrite	!= INVALID_HANDLE_VALUE)	CloseHandle(stdInWrite);
    548 		if (stdOutRead	!= INVALID_HANDLE_VALUE)	CloseHandle(stdOutRead);
    549 		if (stdOutWrite	!= INVALID_HANDLE_VALUE)	CloseHandle(stdOutWrite);
    550 		if (stdErrRead	!= INVALID_HANDLE_VALUE)	CloseHandle(stdErrRead);
    551 		if (stdErrWrite	!= INVALID_HANDLE_VALUE)	CloseHandle(stdErrWrite);
    552 		throw;
    553 	}
    554 
    555 	// Store handles to be kept.
    556 	m_standardIn	= stdInWrite;
    557 	m_standardOut	= stdOutRead;
    558 	m_standardErr	= stdErrRead;
    559 
    560 	// Close other ends of handles.
    561 	CloseHandle(stdErrWrite);
    562 	CloseHandle(stdOutWrite);
    563 	CloseHandle(stdInRead);
    564 
    565 	m_state = STATE_RUNNING;
    566 }
    567 
    568 bool Process::isRunning (void)
    569 {
    570 	if (m_state == STATE_RUNNING)
    571 	{
    572 		int exitCode;
    573 		BOOL result = GetExitCodeProcess(m_procInfo.hProcess, (LPDWORD)&exitCode);
    574 
    575 		if (result != TRUE)
    576 			throw Error(GetLastError(), "GetExitCodeProcess() failed");
    577 
    578 		if (exitCode == STILL_ACTIVE)
    579 			return true;
    580 		else
    581 		{
    582 			// Done.
    583 			m_exitCode	= exitCode;
    584 			m_state		= STATE_FINISHED;
    585 			return false;
    586 		}
    587 	}
    588 	else
    589 		return false;
    590 }
    591 
    592 void Process::waitForFinish (void)
    593 {
    594 	if (m_state == STATE_RUNNING)
    595 	{
    596 		if (WaitForSingleObject(m_procInfo.hProcess, INFINITE) != WAIT_OBJECT_0)
    597 			throw Error(GetLastError(), "Waiting for process failed, WaitForSingleObject() failed");
    598 
    599 		if (isRunning())
    600 			throw std::runtime_error("Process is still alive");
    601 	}
    602 	else
    603 		throw std::runtime_error("Process is not running");
    604 }
    605 
    606 void Process::stopProcess (bool kill)
    607 {
    608 	if (m_state == STATE_RUNNING)
    609 	{
    610 		if (!TerminateProcess(m_procInfo.hProcess, kill ? -1 : 0))
    611 			throw Error(GetLastError(), "TerminateProcess() failed");
    612 	}
    613 	else
    614 		throw std::runtime_error("Process is not running");
    615 }
    616 
    617 void Process::terminate (void)
    618 {
    619 	stopProcess(false);
    620 }
    621 
    622 void Process::kill (void)
    623 {
    624 	stopProcess(true);
    625 }
    626 
    627 } // win32
    628 
    629 Win32TestProcess::Win32TestProcess (void)
    630 	: m_process				(DE_NULL)
    631 	, m_processStartTime	(0)
    632 	, m_infoBuffer			(INFO_BUFFER_BLOCK_SIZE, INFO_BUFFER_NUM_BLOCKS)
    633 	, m_stdOutReader		(&m_infoBuffer)
    634 	, m_stdErrReader		(&m_infoBuffer)
    635 {
    636 }
    637 
    638 Win32TestProcess::~Win32TestProcess (void)
    639 {
    640 	delete m_process;
    641 }
    642 
    643 void Win32TestProcess::start (const char* name, const char* params, const char* workingDir, const char* caseList)
    644 {
    645 	bool hasCaseList = strlen(caseList) > 0;
    646 
    647 	XS_CHECK(!m_process);
    648 
    649 	de::FilePath logFilePath = de::FilePath::join(workingDir, "TestResults.qpa");
    650 	m_logFileName = logFilePath.getPath();
    651 
    652 	// Remove old file if such exists.
    653 	// \note Sometimes on Windows the test process dies slowly and may not release handle to log file
    654 	//		 until a bit later.
    655 	// \todo [2013-07-15 pyry] This should be solved by improving deProcess and killing all child processes as well.
    656 	{
    657 		int tryNdx = 0;
    658 		while (tryNdx < MAX_OLD_LOGFILE_DELETE_ATTEMPTS && deFileExists(m_logFileName.c_str()))
    659 		{
    660 			if (deDeleteFile(m_logFileName.c_str()))
    661 				break;
    662 			deSleep(LOGFILE_DELETE_SLEEP_MS);
    663 			tryNdx += 1;
    664 		}
    665 
    666 		if (deFileExists(m_logFileName.c_str()))
    667 			throw TestProcessException(string("Failed to remove '") + m_logFileName + "'");
    668 	}
    669 
    670 	// Construct command line.
    671 	string cmdLine = de::FilePath(name).isAbsolutePath() ? name : de::FilePath::join(workingDir, name).normalize().getPath();
    672 	cmdLine += string(" --deqp-log-filename=") + logFilePath.getBaseName();
    673 
    674 	if (hasCaseList)
    675 		cmdLine += " --deqp-stdin-caselist";
    676 
    677 	if (strlen(params) > 0)
    678 		cmdLine += string(" ") + params;
    679 
    680 	DE_ASSERT(!m_process);
    681 	m_process = new win32::Process();
    682 
    683 	try
    684 	{
    685 		m_process->start(cmdLine.c_str(), strlen(workingDir) > 0 ? workingDir : DE_NULL);
    686 	}
    687 	catch (const std::exception& e)
    688 	{
    689 		delete m_process;
    690 		m_process = DE_NULL;
    691 		throw TestProcessException(e.what());
    692 	}
    693 
    694 	m_processStartTime = deGetMicroseconds();
    695 
    696 	// Create stdout & stderr readers.
    697 	m_stdOutReader.start(m_process->getStdOut());
    698 	m_stdErrReader.start(m_process->getStdErr());
    699 
    700 	// Start case list writer.
    701 	if (hasCaseList)
    702 		m_caseListWriter.start(caseList, m_process->getStdIn());
    703 }
    704 
    705 void Win32TestProcess::terminate (void)
    706 {
    707 	if (m_process)
    708 	{
    709 		try
    710 		{
    711 			m_process->kill();
    712 		}
    713 		catch (const std::exception& e)
    714 		{
    715 			printf("Win32TestProcess::terminate(): Failed to kill process: %s\n", e.what());
    716 		}
    717 	}
    718 }
    719 
    720 void Win32TestProcess::cleanup (void)
    721 {
    722 	m_caseListWriter.stop();
    723 
    724 	// \note Buffers must be canceled before stopping readers.
    725 	m_infoBuffer.cancel();
    726 
    727 	m_stdErrReader.stop();
    728 	m_stdOutReader.stop();
    729 	m_testLogReader.stop();
    730 
    731 	// Reset buffers.
    732 	m_infoBuffer.clear();
    733 
    734 	if (m_process)
    735 	{
    736 		try
    737 		{
    738 			if (m_process->isRunning())
    739 			{
    740 				m_process->kill();
    741 				m_process->waitForFinish();
    742 			}
    743 		}
    744 		catch (const std::exception& e)
    745 		{
    746 			printf("Win32TestProcess::cleanup(): Failed to kill process: %s\n", e.what());
    747 		}
    748 
    749 		delete m_process;
    750 		m_process = DE_NULL;
    751 	}
    752 }
    753 
    754 int Win32TestProcess::readTestLog (deUint8* dst, int numBytes)
    755 {
    756 	if (!m_testLogReader.isRunning())
    757 	{
    758 		if (deGetMicroseconds() - m_processStartTime > LOG_FILE_TIMEOUT*1000)
    759 		{
    760 			// Timeout, kill process.
    761 			terminate();
    762 			return 0; // \todo [2013-08-13 pyry] Throw exception?
    763 		}
    764 
    765 		if (!deFileExists(m_logFileName.c_str()))
    766 			return 0;
    767 
    768 		// Start reader.
    769 		m_testLogReader.start(m_logFileName.c_str());
    770 	}
    771 
    772 	DE_ASSERT(m_testLogReader.isRunning());
    773 	return m_testLogReader.read(dst, numBytes);
    774 }
    775 
    776 bool Win32TestProcess::isRunning (void)
    777 {
    778 	if (m_process)
    779 		return m_process->isRunning();
    780 	else
    781 		return false;
    782 }
    783 
    784 int Win32TestProcess::getExitCode (void) const
    785 {
    786 	if (m_process)
    787 		return m_process->getExitCode();
    788 	else
    789 		return -1;
    790 }
    791 
    792 } // xs
    793