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