Home | History | Annotate | Download | only in execserver
      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 
     67 	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 
    119 	bool					isRunning			(void) const					{ return m_reader.isStarted();					}
    120 
    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);
    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 
    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);
    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