1e5c31af7Sopenharmony_ci/*------------------------------------------------------------------------- 2e5c31af7Sopenharmony_ci * drawElements Quality Program Execution Server 3e5c31af7Sopenharmony_ci * --------------------------------------------- 4e5c31af7Sopenharmony_ci * 5e5c31af7Sopenharmony_ci * Copyright 2014 The Android Open Source Project 6e5c31af7Sopenharmony_ci * 7e5c31af7Sopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License"); 8e5c31af7Sopenharmony_ci * you may not use this file except in compliance with the License. 9e5c31af7Sopenharmony_ci * You may obtain a copy of the License at 10e5c31af7Sopenharmony_ci * 11e5c31af7Sopenharmony_ci * http://www.apache.org/licenses/LICENSE-2.0 12e5c31af7Sopenharmony_ci * 13e5c31af7Sopenharmony_ci * Unless required by applicable law or agreed to in writing, software 14e5c31af7Sopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS, 15e5c31af7Sopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16e5c31af7Sopenharmony_ci * See the License for the specific language governing permissions and 17e5c31af7Sopenharmony_ci * limitations under the License. 18e5c31af7Sopenharmony_ci * 19e5c31af7Sopenharmony_ci *//*! 20e5c31af7Sopenharmony_ci * \file 21e5c31af7Sopenharmony_ci * \brief TestProcess implementation for Unix-like systems. 22e5c31af7Sopenharmony_ci *//*--------------------------------------------------------------------*/ 23e5c31af7Sopenharmony_ci 24e5c31af7Sopenharmony_ci#include "xsPosixTestProcess.hpp" 25e5c31af7Sopenharmony_ci#include "deFilePath.hpp" 26e5c31af7Sopenharmony_ci#include "deClock.h" 27e5c31af7Sopenharmony_ci 28e5c31af7Sopenharmony_ci#include <string.h> 29e5c31af7Sopenharmony_ci#include <stdio.h> 30e5c31af7Sopenharmony_ci 31e5c31af7Sopenharmony_ciusing std::string; 32e5c31af7Sopenharmony_ciusing std::vector; 33e5c31af7Sopenharmony_ci 34e5c31af7Sopenharmony_cinamespace xs 35e5c31af7Sopenharmony_ci{ 36e5c31af7Sopenharmony_ci 37e5c31af7Sopenharmony_cinamespace posix 38e5c31af7Sopenharmony_ci{ 39e5c31af7Sopenharmony_ci 40e5c31af7Sopenharmony_ciCaseListWriter::CaseListWriter (void) 41e5c31af7Sopenharmony_ci : m_file (DE_NULL) 42e5c31af7Sopenharmony_ci , m_run (false) 43e5c31af7Sopenharmony_ci{ 44e5c31af7Sopenharmony_ci} 45e5c31af7Sopenharmony_ci 46e5c31af7Sopenharmony_ciCaseListWriter::~CaseListWriter (void) 47e5c31af7Sopenharmony_ci{ 48e5c31af7Sopenharmony_ci} 49e5c31af7Sopenharmony_ci 50e5c31af7Sopenharmony_civoid CaseListWriter::start (const char* caseList, deFile* dst) 51e5c31af7Sopenharmony_ci{ 52e5c31af7Sopenharmony_ci DE_ASSERT(!isStarted()); 53e5c31af7Sopenharmony_ci m_file = dst; 54e5c31af7Sopenharmony_ci m_run = true; 55e5c31af7Sopenharmony_ci 56e5c31af7Sopenharmony_ci int caseListSize = (int)strlen(caseList)+1; 57e5c31af7Sopenharmony_ci m_caseList.resize(caseListSize); 58e5c31af7Sopenharmony_ci std::copy(caseList, caseList+caseListSize, m_caseList.begin()); 59e5c31af7Sopenharmony_ci 60e5c31af7Sopenharmony_ci // Set to non-blocking mode. 61e5c31af7Sopenharmony_ci if (!deFile_setFlags(m_file, DE_FILE_NONBLOCKING)) 62e5c31af7Sopenharmony_ci XS_FAIL("Failed to set non-blocking mode"); 63e5c31af7Sopenharmony_ci 64e5c31af7Sopenharmony_ci de::Thread::start(); 65e5c31af7Sopenharmony_ci} 66e5c31af7Sopenharmony_ci 67e5c31af7Sopenharmony_civoid CaseListWriter::run (void) 68e5c31af7Sopenharmony_ci{ 69e5c31af7Sopenharmony_ci deInt64 pos = 0; 70e5c31af7Sopenharmony_ci 71e5c31af7Sopenharmony_ci while (m_run && pos < (deInt64)m_caseList.size()) 72e5c31af7Sopenharmony_ci { 73e5c31af7Sopenharmony_ci deInt64 numWritten = 0; 74e5c31af7Sopenharmony_ci deFileResult result = deFile_write(m_file, &m_caseList[0] + pos, m_caseList.size()-pos, &numWritten); 75e5c31af7Sopenharmony_ci 76e5c31af7Sopenharmony_ci if (result == DE_FILERESULT_SUCCESS) 77e5c31af7Sopenharmony_ci pos += numWritten; 78e5c31af7Sopenharmony_ci else if (result == DE_FILERESULT_WOULD_BLOCK) 79e5c31af7Sopenharmony_ci deSleep(1); // Yield. 80e5c31af7Sopenharmony_ci else 81e5c31af7Sopenharmony_ci break; // Error. 82e5c31af7Sopenharmony_ci } 83e5c31af7Sopenharmony_ci} 84e5c31af7Sopenharmony_ci 85e5c31af7Sopenharmony_civoid CaseListWriter::stop (void) 86e5c31af7Sopenharmony_ci{ 87e5c31af7Sopenharmony_ci if (!isStarted()) 88e5c31af7Sopenharmony_ci return; // Nothing to do. 89e5c31af7Sopenharmony_ci 90e5c31af7Sopenharmony_ci m_run = false; 91e5c31af7Sopenharmony_ci 92e5c31af7Sopenharmony_ci // Join thread. 93e5c31af7Sopenharmony_ci join(); 94e5c31af7Sopenharmony_ci 95e5c31af7Sopenharmony_ci m_file = DE_NULL; 96e5c31af7Sopenharmony_ci} 97e5c31af7Sopenharmony_ci 98e5c31af7Sopenharmony_ciPipeReader::PipeReader (ThreadedByteBuffer* dst) 99e5c31af7Sopenharmony_ci : m_file (DE_NULL) 100e5c31af7Sopenharmony_ci , m_buf (dst) 101e5c31af7Sopenharmony_ci{ 102e5c31af7Sopenharmony_ci} 103e5c31af7Sopenharmony_ci 104e5c31af7Sopenharmony_ciPipeReader::~PipeReader (void) 105e5c31af7Sopenharmony_ci{ 106e5c31af7Sopenharmony_ci} 107e5c31af7Sopenharmony_ci 108e5c31af7Sopenharmony_civoid PipeReader::start (deFile* file) 109e5c31af7Sopenharmony_ci{ 110e5c31af7Sopenharmony_ci DE_ASSERT(!isStarted()); 111e5c31af7Sopenharmony_ci 112e5c31af7Sopenharmony_ci // Set to non-blocking mode. 113e5c31af7Sopenharmony_ci if (!deFile_setFlags(file, DE_FILE_NONBLOCKING)) 114e5c31af7Sopenharmony_ci XS_FAIL("Failed to set non-blocking mode"); 115e5c31af7Sopenharmony_ci 116e5c31af7Sopenharmony_ci m_file = file; 117e5c31af7Sopenharmony_ci 118e5c31af7Sopenharmony_ci de::Thread::start(); 119e5c31af7Sopenharmony_ci} 120e5c31af7Sopenharmony_ci 121e5c31af7Sopenharmony_civoid PipeReader::run (void) 122e5c31af7Sopenharmony_ci{ 123e5c31af7Sopenharmony_ci std::vector<deUint8> tmpBuf (FILEREADER_TMP_BUFFER_SIZE); 124e5c31af7Sopenharmony_ci deInt64 numRead = 0; 125e5c31af7Sopenharmony_ci 126e5c31af7Sopenharmony_ci while (!m_buf->isCanceled()) 127e5c31af7Sopenharmony_ci { 128e5c31af7Sopenharmony_ci deFileResult result = deFile_read(m_file, &tmpBuf[0], (deInt64)tmpBuf.size(), &numRead); 129e5c31af7Sopenharmony_ci 130e5c31af7Sopenharmony_ci if (result == DE_FILERESULT_SUCCESS) 131e5c31af7Sopenharmony_ci { 132e5c31af7Sopenharmony_ci // Write to buffer. 133e5c31af7Sopenharmony_ci try 134e5c31af7Sopenharmony_ci { 135e5c31af7Sopenharmony_ci m_buf->write((int)numRead, &tmpBuf[0]); 136e5c31af7Sopenharmony_ci m_buf->flush(); 137e5c31af7Sopenharmony_ci } 138e5c31af7Sopenharmony_ci catch (const ThreadedByteBuffer::CanceledException&) 139e5c31af7Sopenharmony_ci { 140e5c31af7Sopenharmony_ci // Canceled. 141e5c31af7Sopenharmony_ci break; 142e5c31af7Sopenharmony_ci } 143e5c31af7Sopenharmony_ci } 144e5c31af7Sopenharmony_ci else if (result == DE_FILERESULT_END_OF_FILE || 145e5c31af7Sopenharmony_ci result == DE_FILERESULT_WOULD_BLOCK) 146e5c31af7Sopenharmony_ci { 147e5c31af7Sopenharmony_ci // Wait for more data. 148e5c31af7Sopenharmony_ci deSleep(FILEREADER_IDLE_SLEEP); 149e5c31af7Sopenharmony_ci } 150e5c31af7Sopenharmony_ci else 151e5c31af7Sopenharmony_ci break; // Error. 152e5c31af7Sopenharmony_ci } 153e5c31af7Sopenharmony_ci} 154e5c31af7Sopenharmony_ci 155e5c31af7Sopenharmony_civoid PipeReader::stop (void) 156e5c31af7Sopenharmony_ci{ 157e5c31af7Sopenharmony_ci if (!isStarted()) 158e5c31af7Sopenharmony_ci return; // Nothing to do. 159e5c31af7Sopenharmony_ci 160e5c31af7Sopenharmony_ci // Buffer must be in canceled state or otherwise stopping reader might block. 161e5c31af7Sopenharmony_ci DE_ASSERT(m_buf->isCanceled()); 162e5c31af7Sopenharmony_ci 163e5c31af7Sopenharmony_ci // Join thread. 164e5c31af7Sopenharmony_ci join(); 165e5c31af7Sopenharmony_ci 166e5c31af7Sopenharmony_ci m_file = DE_NULL; 167e5c31af7Sopenharmony_ci} 168e5c31af7Sopenharmony_ci 169e5c31af7Sopenharmony_ci} // unix 170e5c31af7Sopenharmony_ci 171e5c31af7Sopenharmony_ciPosixTestProcess::PosixTestProcess (void) 172e5c31af7Sopenharmony_ci : m_process (DE_NULL) 173e5c31af7Sopenharmony_ci , m_processStartTime (0) 174e5c31af7Sopenharmony_ci , m_infoBuffer (INFO_BUFFER_BLOCK_SIZE, INFO_BUFFER_NUM_BLOCKS) 175e5c31af7Sopenharmony_ci , m_stdOutReader (&m_infoBuffer) 176e5c31af7Sopenharmony_ci , m_stdErrReader (&m_infoBuffer) 177e5c31af7Sopenharmony_ci , m_logReader (LOG_BUFFER_BLOCK_SIZE, LOG_BUFFER_NUM_BLOCKS) 178e5c31af7Sopenharmony_ci{ 179e5c31af7Sopenharmony_ci} 180e5c31af7Sopenharmony_ci 181e5c31af7Sopenharmony_ciPosixTestProcess::~PosixTestProcess (void) 182e5c31af7Sopenharmony_ci{ 183e5c31af7Sopenharmony_ci delete m_process; 184e5c31af7Sopenharmony_ci} 185e5c31af7Sopenharmony_ci 186e5c31af7Sopenharmony_civoid PosixTestProcess::start (const char* name, const char* params, const char* workingDir, const char* caseList) 187e5c31af7Sopenharmony_ci{ 188e5c31af7Sopenharmony_ci bool hasCaseList = strlen(caseList) > 0; 189e5c31af7Sopenharmony_ci 190e5c31af7Sopenharmony_ci XS_CHECK(!m_process); 191e5c31af7Sopenharmony_ci 192e5c31af7Sopenharmony_ci de::FilePath logFilePath = de::FilePath::join(workingDir, "TestResults.qpa"); 193e5c31af7Sopenharmony_ci m_logFileName = logFilePath.getPath(); 194e5c31af7Sopenharmony_ci 195e5c31af7Sopenharmony_ci // Remove old file if such exists. 196e5c31af7Sopenharmony_ci if (deFileExists(m_logFileName.c_str())) 197e5c31af7Sopenharmony_ci { 198e5c31af7Sopenharmony_ci if (!deDeleteFile(m_logFileName.c_str()) || deFileExists(m_logFileName.c_str())) 199e5c31af7Sopenharmony_ci throw TestProcessException(string("Failed to remove '") + m_logFileName + "'"); 200e5c31af7Sopenharmony_ci } 201e5c31af7Sopenharmony_ci 202e5c31af7Sopenharmony_ci // Construct command line. 203e5c31af7Sopenharmony_ci string cmdLine = de::FilePath(name).isAbsolutePath() ? name : de::FilePath::join(workingDir, name).getPath(); 204e5c31af7Sopenharmony_ci cmdLine += string(" --deqp-log-filename=") + logFilePath.getBaseName(); 205e5c31af7Sopenharmony_ci 206e5c31af7Sopenharmony_ci if (hasCaseList) 207e5c31af7Sopenharmony_ci cmdLine += " --deqp-stdin-caselist"; 208e5c31af7Sopenharmony_ci 209e5c31af7Sopenharmony_ci if (strlen(params) > 0) 210e5c31af7Sopenharmony_ci cmdLine += string(" ") + params; 211e5c31af7Sopenharmony_ci 212e5c31af7Sopenharmony_ci DE_ASSERT(!m_process); 213e5c31af7Sopenharmony_ci m_process = new de::Process(); 214e5c31af7Sopenharmony_ci 215e5c31af7Sopenharmony_ci try 216e5c31af7Sopenharmony_ci { 217e5c31af7Sopenharmony_ci m_process->start(cmdLine.c_str(), strlen(workingDir) > 0 ? workingDir : DE_NULL); 218e5c31af7Sopenharmony_ci } 219e5c31af7Sopenharmony_ci catch (const de::ProcessError& e) 220e5c31af7Sopenharmony_ci { 221e5c31af7Sopenharmony_ci delete m_process; 222e5c31af7Sopenharmony_ci m_process = DE_NULL; 223e5c31af7Sopenharmony_ci throw TestProcessException(e.what()); 224e5c31af7Sopenharmony_ci } 225e5c31af7Sopenharmony_ci 226e5c31af7Sopenharmony_ci m_processStartTime = deGetMicroseconds(); 227e5c31af7Sopenharmony_ci 228e5c31af7Sopenharmony_ci // Create stdout & stderr readers. 229e5c31af7Sopenharmony_ci if (m_process->getStdOut()) 230e5c31af7Sopenharmony_ci m_stdOutReader.start(m_process->getStdOut()); 231e5c31af7Sopenharmony_ci 232e5c31af7Sopenharmony_ci if (m_process->getStdErr()) 233e5c31af7Sopenharmony_ci m_stdErrReader.start(m_process->getStdErr()); 234e5c31af7Sopenharmony_ci 235e5c31af7Sopenharmony_ci // Start case list writer. 236e5c31af7Sopenharmony_ci if (hasCaseList) 237e5c31af7Sopenharmony_ci { 238e5c31af7Sopenharmony_ci deFile* dst = m_process->getStdIn(); 239e5c31af7Sopenharmony_ci if (dst) 240e5c31af7Sopenharmony_ci m_caseListWriter.start(caseList, dst); 241e5c31af7Sopenharmony_ci else 242e5c31af7Sopenharmony_ci { 243e5c31af7Sopenharmony_ci cleanup(); 244e5c31af7Sopenharmony_ci throw TestProcessException("Failed to write case list"); 245e5c31af7Sopenharmony_ci } 246e5c31af7Sopenharmony_ci } 247e5c31af7Sopenharmony_ci} 248e5c31af7Sopenharmony_ci 249e5c31af7Sopenharmony_civoid PosixTestProcess::terminate (void) 250e5c31af7Sopenharmony_ci{ 251e5c31af7Sopenharmony_ci if (m_process) 252e5c31af7Sopenharmony_ci { 253e5c31af7Sopenharmony_ci try 254e5c31af7Sopenharmony_ci { 255e5c31af7Sopenharmony_ci m_process->kill(); 256e5c31af7Sopenharmony_ci } 257e5c31af7Sopenharmony_ci catch (const std::exception& e) 258e5c31af7Sopenharmony_ci { 259e5c31af7Sopenharmony_ci printf("PosixTestProcess::terminate(): Failed to kill process: %s\n", e.what()); 260e5c31af7Sopenharmony_ci } 261e5c31af7Sopenharmony_ci } 262e5c31af7Sopenharmony_ci} 263e5c31af7Sopenharmony_ci 264e5c31af7Sopenharmony_civoid PosixTestProcess::cleanup (void) 265e5c31af7Sopenharmony_ci{ 266e5c31af7Sopenharmony_ci m_caseListWriter.stop(); 267e5c31af7Sopenharmony_ci m_logReader.stop(); 268e5c31af7Sopenharmony_ci 269e5c31af7Sopenharmony_ci // \note Info buffer must be canceled before stopping pipe readers. 270e5c31af7Sopenharmony_ci m_infoBuffer.cancel(); 271e5c31af7Sopenharmony_ci 272e5c31af7Sopenharmony_ci m_stdErrReader.stop(); 273e5c31af7Sopenharmony_ci m_stdOutReader.stop(); 274e5c31af7Sopenharmony_ci 275e5c31af7Sopenharmony_ci // Reset info buffer. 276e5c31af7Sopenharmony_ci m_infoBuffer.clear(); 277e5c31af7Sopenharmony_ci 278e5c31af7Sopenharmony_ci if (m_process) 279e5c31af7Sopenharmony_ci { 280e5c31af7Sopenharmony_ci try 281e5c31af7Sopenharmony_ci { 282e5c31af7Sopenharmony_ci if (m_process->isRunning()) 283e5c31af7Sopenharmony_ci { 284e5c31af7Sopenharmony_ci m_process->kill(); 285e5c31af7Sopenharmony_ci m_process->waitForFinish(); 286e5c31af7Sopenharmony_ci } 287e5c31af7Sopenharmony_ci } 288e5c31af7Sopenharmony_ci catch (const de::ProcessError& e) 289e5c31af7Sopenharmony_ci { 290e5c31af7Sopenharmony_ci printf("PosixTestProcess::stop(): Failed to kill process: %s\n", e.what()); 291e5c31af7Sopenharmony_ci } 292e5c31af7Sopenharmony_ci 293e5c31af7Sopenharmony_ci delete m_process; 294e5c31af7Sopenharmony_ci m_process = DE_NULL; 295e5c31af7Sopenharmony_ci } 296e5c31af7Sopenharmony_ci} 297e5c31af7Sopenharmony_ci 298e5c31af7Sopenharmony_cibool PosixTestProcess::isRunning (void) 299e5c31af7Sopenharmony_ci{ 300e5c31af7Sopenharmony_ci if (m_process) 301e5c31af7Sopenharmony_ci return m_process->isRunning(); 302e5c31af7Sopenharmony_ci else 303e5c31af7Sopenharmony_ci return false; 304e5c31af7Sopenharmony_ci} 305e5c31af7Sopenharmony_ci 306e5c31af7Sopenharmony_ciint PosixTestProcess::getExitCode (void) const 307e5c31af7Sopenharmony_ci{ 308e5c31af7Sopenharmony_ci if (m_process) 309e5c31af7Sopenharmony_ci return m_process->getExitCode(); 310e5c31af7Sopenharmony_ci else 311e5c31af7Sopenharmony_ci return -1; 312e5c31af7Sopenharmony_ci} 313e5c31af7Sopenharmony_ci 314e5c31af7Sopenharmony_ciint PosixTestProcess::readTestLog (deUint8* dst, int numBytes) 315e5c31af7Sopenharmony_ci{ 316e5c31af7Sopenharmony_ci if (!m_logReader.isRunning()) 317e5c31af7Sopenharmony_ci { 318e5c31af7Sopenharmony_ci if (deGetMicroseconds() - m_processStartTime > LOG_FILE_TIMEOUT*1000) 319e5c31af7Sopenharmony_ci { 320e5c31af7Sopenharmony_ci // Timeout, kill process. 321e5c31af7Sopenharmony_ci terminate(); 322e5c31af7Sopenharmony_ci return 0; // \todo [2013-08-13 pyry] Throw exception? 323e5c31af7Sopenharmony_ci } 324e5c31af7Sopenharmony_ci 325e5c31af7Sopenharmony_ci if (!deFileExists(m_logFileName.c_str())) 326e5c31af7Sopenharmony_ci return 0; 327e5c31af7Sopenharmony_ci 328e5c31af7Sopenharmony_ci // Start reader. 329e5c31af7Sopenharmony_ci m_logReader.start(m_logFileName.c_str()); 330e5c31af7Sopenharmony_ci } 331e5c31af7Sopenharmony_ci 332e5c31af7Sopenharmony_ci DE_ASSERT(m_logReader.isRunning()); 333e5c31af7Sopenharmony_ci return m_logReader.read(dst, numBytes); 334e5c31af7Sopenharmony_ci} 335e5c31af7Sopenharmony_ci 336e5c31af7Sopenharmony_ci} // xs 337