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