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