• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
formatErrMsg(DWORD error,const char * msg)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 
Error(DWORD error,const char * msg)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 
Event(bool manualReset,bool initialState)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 
~Event(void)85 Event::~Event (void)
86 {
87 	CloseHandle(m_handle);
88 }
89 
setSignaled(void)90 void Event::setSignaled (void)
91 {
92 	if (!SetEvent(m_handle))
93 		throw Error(GetLastError(), "SetEvent() failed");
94 }
95 
reset(void)96 void Event::reset (void)
97 {
98 	if (!ResetEvent(m_handle))
99 		throw Error(GetLastError(), "ResetEvent() failed");
100 }
101 
102 // CaseListWriter
103 
CaseListWriter(void)104 CaseListWriter::CaseListWriter (void)
105 	: m_dst			(INVALID_HANDLE_VALUE)
106 	, m_cancelEvent	(true, false)
107 {
108 }
109 
~CaseListWriter(void)110 CaseListWriter::~CaseListWriter (void)
111 {
112 }
113 
start(const char * caseList,HANDLE dst)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 
run(void)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 
stop(void)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 
FileReader(ThreadedByteBuffer * dst)202 FileReader::FileReader (ThreadedByteBuffer* dst)
203 	: m_dstBuf		(dst)
204 	, m_handle		(INVALID_HANDLE_VALUE)
205 	, m_cancelEvent	(false, false)
206 {
207 }
208 
~FileReader(void)209 FileReader::~FileReader (void)
210 {
211 }
212 
start(HANDLE file)213 void FileReader::start (HANDLE file)
214 {
215 	DE_ASSERT(!isStarted());
216 
217 	m_handle = file;
218 
219 	de::Thread::start();
220 }
221 
run(void)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 
stop(void)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 
TestLogReader(void)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 
~TestLogReader(void)352 TestLogReader::~TestLogReader (void)
353 {
354 	if (m_logFile != INVALID_HANDLE_VALUE)
355 		CloseHandle(m_logFile);
356 }
357 
start(const char * filename)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 
stop(void)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 
Process(void)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 
~Process(void)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 
cleanupHandles(void)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 
createPipeWithOverlappedIO(HANDLE * readHandleOut,HANDLE * writeHandleOut,deUint32 readMode,deUint32 writeMode,SECURITY_ATTRIBUTES * securityAttr)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 
start(const char * commandLine,const char * workingDirectory)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 
isRunning(void)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 
waitForFinish(void)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 
stopProcess(bool kill)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 
terminate(void)617 void Process::terminate (void)
618 {
619 	stopProcess(false);
620 }
621 
kill(void)622 void Process::kill (void)
623 {
624 	stopProcess(true);
625 }
626 
627 } // win32
628 
Win32TestProcess(void)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 
~Win32TestProcess(void)638 Win32TestProcess::~Win32TestProcess (void)
639 {
640 	delete m_process;
641 }
642 
start(const char * name,const char * params,const char * workingDir,const char * caseList)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 
terminate(void)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 
cleanup(void)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 
readTestLog(deUint8 * dst,int numBytes)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 
isRunning(void)776 bool Win32TestProcess::isRunning (void)
777 {
778 	if (m_process)
779 		return m_process->isRunning();
780 	else
781 		return false;
782 }
783 
getExitCode(void) const784 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