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
44namespace xs
45{
46namespace win32
47{
48
49class Error : public std::runtime_error
50{
51public:
52							Error				(DWORD error, const char* msg);
53
54private:
55	DWORD					m_error;
56};
57
58class Event
59{
60public:
61							Event				(bool manualReset, bool initialState);
62							~Event				(void);
63
64	void					setSignaled			(void);
65	void					reset				(void);
66
67	HANDLE					getHandle			(void) const { return m_handle; }
68
69private:
70							Event				(const Event& other);
71	Event&					operator=			(const Event& other);
72
73	HANDLE					m_handle;
74};
75
76class CaseListWriter : public de::Thread
77{
78public:
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
87private:
88	std::vector<char>		m_caseList;
89	HANDLE					m_dst;
90	Event					m_cancelEvent;
91};
92
93class FileReader : public de::Thread
94{
95public:
96							FileReader			(ThreadedByteBuffer* dst);
97							~FileReader			(void);
98
99	void					start				(HANDLE file);
100	void					stop				(void);
101
102	void					run					(void);
103
104private:
105	ThreadedByteBuffer*		m_dstBuf;
106	HANDLE					m_handle;
107	Event					m_cancelEvent;
108};
109
110class TestLogReader
111{
112public:
113							TestLogReader		(void);
114							~TestLogReader		(void);
115
116	void					start				(const char* filename);
117	void					stop				(void);
118
119	bool					isRunning			(void) const					{ return m_reader.isStarted();					}
120
121	int						read				(deUint8* dst, int numBytes)	{ return m_logBuffer.tryRead(numBytes, dst);	}
122
123private:
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.
133class Process
134{
135public:
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);
146	int						getExitCode			(void) const { return m_exitCode;		}
147
148	HANDLE					getStdIn			(void) const { return m_standardIn;		}
149	HANDLE					getStdOut			(void) const { return m_standardOut;	}
150	HANDLE					getStdErr			(void) const { return m_standardErr;	}
151
152private:
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
179class Win32TestProcess : public TestProcess
180{
181public:
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);
193	virtual int				readInfoLog				(deUint8* dst, int numBytes) { return m_infoBuffer.tryRead(numBytes, dst); }
194
195private:
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