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