1 #ifndef _XSWIN32TESTPROCESS_HPP
2 #define _XSWIN32TESTPROCESS_HPP
3 /*-------------------------------------------------------------------------
4  * drawElements Quality Program Execution Server
5  * ---------------------------------------------
6  *
7  * Copyright 2014 The Android Open Source Project
8  *
9  * Licensed under the Apache License, Version 2.0 (the "License");
10  * you may not use this file except in compliance with the License.
11  * You may obtain a copy of the License at
12  *
13  *      http://www.apache.org/licenses/LICENSE-2.0
14  *
15  * Unless required by applicable law or agreed to in writing, software
16  * distributed under the License is distributed on an "AS IS" BASIS,
17  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18  * See the License for the specific language governing permissions and
19  * limitations under the License.
20  *
21  *//*!
22  * \file
23  * \brief TestProcess implementation for Win32.
24  *//*--------------------------------------------------------------------*/
25 
26 #include "xsDefs.hpp"
27 #include "xsTestProcess.hpp"
28 #include "deThread.hpp"
29 
30 #include <vector>
31 #include <string>
32 
33 #if !defined(VC_EXTRALEAN)
34 #	define VC_EXTRALEAN 1
35 #endif
36 #if !defined(WIN32_LEAN_AND_MEAN)
37 #	define WIN32_LEAN_AND_MEAN 1
38 #endif
39 #if !defined(NOMINMAX)
40 #	define NOMINMAX 1
41 #endif
42 #include <windows.h>
43 
44 namespace xs
45 {
46 namespace win32
47 {
48 
49 class Error : public std::runtime_error
50 {
51 public:
52 							Error				(DWORD error, const char* msg);
53 
54 private:
55 	DWORD					m_error;
56 };
57 
58 class Event
59 {
60 public:
61 							Event				(bool manualReset, bool initialState);
62 							~Event				(void);
63 
64 	void					setSignaled			(void);
65 	void					reset				(void);
66 
getHandle(void) const67 	HANDLE					getHandle			(void) const { return m_handle; }
68 
69 private:
70 							Event				(const Event& other);
71 	Event&					operator=			(const Event& other);
72 
73 	HANDLE					m_handle;
74 };
75 
76 class CaseListWriter : public de::Thread
77 {
78 public:
79 							CaseListWriter		(void);
80 							~CaseListWriter		(void);
81 
82 	void					start				(const char* caseList, HANDLE dst);
83 	void					stop				(void);
84 
85 	void					run					(void);
86 
87 private:
88 	std::vector<char>		m_caseList;
89 	HANDLE					m_dst;
90 	Event					m_cancelEvent;
91 };
92 
93 class FileReader : public de::Thread
94 {
95 public:
96 							FileReader			(ThreadedByteBuffer* dst);
97 							~FileReader			(void);
98 
99 	void					start				(HANDLE file);
100 	void					stop				(void);
101 
102 	void					run					(void);
103 
104 private:
105 	ThreadedByteBuffer*		m_dstBuf;
106 	HANDLE					m_handle;
107 	Event					m_cancelEvent;
108 };
109 
110 class TestLogReader
111 {
112 public:
113 							TestLogReader		(void);
114 							~TestLogReader		(void);
115 
116 	void					start				(const char* filename);
117 	void					stop				(void);
118 
isRunning(void) const119 	bool					isRunning			(void) const					{ return m_reader.isStarted();					}
120 
read(deUint8 * dst,int numBytes)121 	int						read				(deUint8* dst, int numBytes)	{ return m_logBuffer.tryRead(numBytes, dst);	}
122 
123 private:
124 	ThreadedByteBuffer		m_logBuffer;
125 	HANDLE					m_logFile;
126 
127 	FileReader				m_reader;
128 };
129 
130 // \note deProcess uses anonymous pipes that don't have overlapped IO available.
131 //		 For ExecServer purposes we need overlapped IO, and it makes the handles
132 //		 incompatible with deFile. Thus separate Process implementation is used for now.
133 class Process
134 {
135 public:
136 							Process				(void);
137 							~Process			(void);
138 
139 	void					start				(const char* commandLine, const char* workingDirectory);
140 
141 	void					waitForFinish		(void);
142 	void					terminate			(void);
143 	void					kill				(void);
144 
145 	bool					isRunning			(void);
getExitCode(void) const146 	int						getExitCode			(void) const { return m_exitCode;		}
147 
getStdIn(void) const148 	HANDLE					getStdIn			(void) const { return m_standardIn;		}
getStdOut(void) const149 	HANDLE					getStdOut			(void) const { return m_standardOut;	}
getStdErr(void) const150 	HANDLE					getStdErr			(void) const { return m_standardErr;	}
151 
152 private:
153 							Process				(const Process& other);
154 	Process&				operator=			(const Process& other);
155 
156 	void					stopProcess			(bool kill);
157 	void					cleanupHandles		(void);
158 
159 	enum State
160 	{
161 		STATE_NOT_STARTED = 0,
162 		STATE_RUNNING,
163 		STATE_FINISHED,
164 
165 		STATE_LAST
166 	};
167 
168 	State					m_state;
169 	int						m_exitCode;
170 
171 	PROCESS_INFORMATION		m_procInfo;
172 	HANDLE					m_standardIn;
173 	HANDLE					m_standardOut;
174 	HANDLE					m_standardErr;
175 };
176 
177 } // win32
178 
179 class Win32TestProcess : public TestProcess
180 {
181 public:
182 							Win32TestProcess		(void);
183 	virtual					~Win32TestProcess		(void);
184 
185 	virtual void			start					(const char* name, const char* params, const char* workingDir, const char* caseList);
186 	virtual void			terminate				(void);
187 	virtual void			cleanup					(void);
188 
189 	virtual bool			isRunning				(void);
190 	virtual int				getExitCode				(void) const;
191 
192 	virtual int				readTestLog				(deUint8* dst, int numBytes);
readInfoLog(deUint8 * dst,int numBytes)193 	virtual int				readInfoLog				(deUint8* dst, int numBytes) { return m_infoBuffer.tryRead(numBytes, dst); }
194 
195 private:
196 							Win32TestProcess		(const Win32TestProcess& other);
197 	Win32TestProcess&		operator=				(const Win32TestProcess& other);
198 
199 	win32::Process*			m_process;
200 	deUint64				m_processStartTime;
201 	std::string				m_logFileName;
202 
203 	ThreadedByteBuffer		m_infoBuffer;
204 
205 	// Threads.
206 	win32::CaseListWriter	m_caseListWriter;
207 	win32::FileReader		m_stdOutReader;
208 	win32::FileReader		m_stdErrReader;
209 	win32::TestLogReader	m_testLogReader;
210 };
211 
212 } // xs
213 
214 #endif // _XSWIN32TESTPROCESS_HPP
215