Home | History | Annotate | Download | only in executor
      1 /*-------------------------------------------------------------------------
      2  * drawElements Quality Program Test Executor
      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 Tcp/Ip link that manages execserver process.
     22  *//*--------------------------------------------------------------------*/
     23 
     24 #include "xeLocalTcpIpLink.hpp"
     25 #include "deClock.h"
     26 #include "deThread.h"
     27 
     28 #include <sstream>
     29 
     30 enum
     31 {
     32 	SERVER_START_TIMEOUT	= 1000,
     33 	SERVER_START_IDLE_SLEEP	= 50
     34 };
     35 
     36 namespace xe
     37 {
     38 
     39 LocalTcpIpLink::LocalTcpIpLink (void)
     40 	: m_process(DE_NULL)
     41 {
     42 }
     43 
     44 LocalTcpIpLink::~LocalTcpIpLink (void)
     45 {
     46 	stop();
     47 }
     48 
     49 void LocalTcpIpLink::start (const char* execServerPath, const char* workDir, int port)
     50 {
     51 	XE_CHECK(!m_process);
     52 
     53 	std::ostringstream cmdLine;
     54 	cmdLine << execServerPath << " --single --port=" << port;
     55 
     56 	m_process = deProcess_create();
     57 	XE_CHECK(m_process);
     58 
     59 	if (deProcess_start(m_process, cmdLine.str().c_str(), workDir) != DE_TRUE)
     60 	{
     61 		std::string err = deProcess_getLastError(m_process);
     62 		deProcess_destroy(m_process);
     63 		m_process = DE_NULL;
     64 
     65 		XE_FAIL((std::string("Failed to start server: ") + err).c_str());
     66 	}
     67 
     68 	try
     69 	{
     70 		de::SocketAddress address;
     71 		address.setFamily	(DE_SOCKETFAMILY_INET4);
     72 		address.setProtocol	(DE_SOCKETPROTOCOL_TCP);
     73 		address.setHost		("127.0.0.1");
     74 		address.setPort		(port);
     75 
     76 		// Wait until server has started - \todo [2012-07-19 pyry] This could be improved by having server to signal when it is ready.
     77 		deUint64 waitStart = deGetMicroseconds();
     78 		for (;;)
     79 		{
     80 			if (!deProcess_isRunning(m_process))
     81 				XE_FAIL("ExecServer died");
     82 
     83 			try
     84 			{
     85 				m_link.connect(address);
     86 				break;
     87 			}
     88 			catch (const de::SocketError&)
     89 			{
     90 				if (deGetMicroseconds()-waitStart > SERVER_START_TIMEOUT*1000)
     91 					XE_FAIL("Server start timeout");
     92 
     93 				deSleep(SERVER_START_IDLE_SLEEP);
     94 			}
     95 		}
     96 
     97 		// Close stdout/stderr or otherwise process will hang once OS pipe buffers are full.
     98 		// \todo [2012-07-19 pyry] Read and store stdout/stderr from execserver.
     99 		XE_CHECK(deProcess_closeStdOut(m_process));
    100 		XE_CHECK(deProcess_closeStdErr(m_process));
    101 	}
    102 	catch (const std::exception&)
    103 	{
    104 		stop();
    105 		throw;
    106 	}
    107 }
    108 
    109 void LocalTcpIpLink::stop (void)
    110 {
    111 	if (m_process)
    112 	{
    113 		try
    114 		{
    115 			m_link.disconnect();
    116 		}
    117 		catch (...)
    118 		{
    119 			// Silently ignore since this is called in destructor.
    120 		}
    121 
    122 		// \note --single flag is used so execserver should kill itself once one connection is handled.
    123 		//		 This is here to make sure it dies even in case of hang.
    124 		deProcess_terminate		(m_process);
    125 		deProcess_waitForFinish	(m_process);
    126 		deProcess_destroy		(m_process);
    127 
    128 		m_process = DE_NULL;
    129 	}
    130 }
    131 
    132 void LocalTcpIpLink::reset (void)
    133 {
    134 	m_link.reset();
    135 }
    136 
    137 CommLinkState LocalTcpIpLink::getState (void) const
    138 {
    139 	if (!m_process)
    140 		return COMMLINKSTATE_ERROR;
    141 	else
    142 		return m_link.getState();
    143 }
    144 
    145 CommLinkState LocalTcpIpLink::getState (std::string& error) const
    146 {
    147 	if (!m_process)
    148 	{
    149 		error = "Not started";
    150 		return COMMLINKSTATE_ERROR;
    151 	}
    152 	else
    153 		return m_link.getState();
    154 }
    155 
    156 void LocalTcpIpLink::setCallbacks (StateChangedFunc stateChangedCallback, LogDataFunc testLogDataCallback, LogDataFunc infoLogDataCallback, void* userPtr)
    157 {
    158 	m_link.setCallbacks(stateChangedCallback, testLogDataCallback, infoLogDataCallback, userPtr);
    159 }
    160 
    161 void LocalTcpIpLink::startTestProcess (const char* name, const char* params, const char* workingDir, const char* caseList)
    162 {
    163 	if (m_process)
    164 		m_link.startTestProcess(name, params, workingDir, caseList);
    165 	else
    166 		XE_FAIL("Not started");
    167 }
    168 
    169 void LocalTcpIpLink::stopTestProcess (void)
    170 {
    171 	if (m_process)
    172 		m_link.stopTestProcess();
    173 	else
    174 		XE_FAIL("Not started");
    175 }
    176 
    177 } // xe
    178