?? ecostest.cpp
字號:
//####COPYRIGHTBEGIN####// // ----------------------------------------------------------------------------// Copyright (C) 1998, 1999, 2000 Red Hat, Inc.//// This program is part of the eCos host tools.//// This program is free software; you can redistribute it and/or modify it // under the terms of the GNU General Public License as published by the Free // Software Foundation; either version 2 of the License, or (at your option) // any later version.// // This program is distributed in the hope that it will be useful, but WITHOUT // ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or // FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for // more details.// // You should have received a copy of the GNU General Public License along with// this program; if not, write to the Free Software Foundation, Inc., // 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.//// ----------------------------------------------------------------------------// //####COPYRIGHTEND####//=================================================================//// eCosTest.cpp//// Test class////=================================================================//=================================================================//#####DESCRIPTIONBEGIN####//// Author(s): sdf// Contributors: sdf// Date: 1999-04-01// Description: This class abstracts a test for use in the testing infrastructure// Usage:////####DESCRIPTIONEND####///////////////////////////////////////////////////////////////////////////////#include "eCosStd.h"#include "eCosTest.h"#include "eCosTestPlatform.h"#include "eCosTrace.h"#include "TestResource.h"#include "eCosTestUtils.h"#include "eCosSocket.h"#include "eCosSerial.h"#include "eCosTestSerialFilter.h"#include "eCosTestDownloadFilter.h"#include "Properties.h"#include "Subprocess.h"#define WF(n) (n+50)/1000,((n+50)%1000)/100 // Present n as whole and fractional part. Round to nearest least significant digit#define WFS _T("%u.%u") // The format string to output the aboveLPCTSTR const CeCosTest::arResultImage[1+CeCosTest::StatusTypeMax]={_T("NotStarted"), _T("NoResult"), _T("Inapplicable"), _T("Pass"), _T("DTimeout"), _T("Timeout"), _T("Cancelled"), _T("Fail"), _T("AssertFail"), _T("Unknown")};CeCosTest *CeCosTest::pFirstInstance=0;int CeCosTest::InstanceCount=0;LPCTSTR const CeCosTest::arServerStatusImage[1+CeCosTest::ServerStatusMax]={ _T("Busy"), _T("Ready"), _T("Can't run"), _T("Connection failed"), _T("Locked"), _T("Bad server status")};LPCTSTR CeCosTest::ExecutionParameters::arRequestImage [1+ExecutionParameters::RequestTypeMax]={ _T("Run"), _T("Query"), _T("Lock"), _T("Unlock"), _T("Stop"), _T("Bad request") }; static bool CALLBACK IsCancelled(void *pThis){ return CeCosTest::Cancelled==((CeCosTest *)pThis)->Status();}// Ctors and dtors:CeCosTest::CeCosTest(const ExecutionParameters &e, LPCTSTR pszExecutable,LPCTSTR pszTitle): m_pspPipe(0), m_nStrippedSize(0), m_nFileSize(0), m_bDownloading(false), m_pSock(0), m_ep(e), m_strTitle(pszTitle), m_Status(NotStarted), m_nDownloadTime(0), m_nTotalTime(0), m_nMaxInactiveTime(0), m_pResource(0), m_psp(0){ assert(e.Platform()); SetExecutable (pszExecutable); TRACE(_T("%%%% Create test instance %08x count:=%d\n"),this,InstanceCount+1); // By recording the path now, we ensure processes are always run in the context in which the test instance // is created (important for the ConfigTool to be able to call PrepareEnvironment).#ifdef _WIN32 // for some reason _tgetenv() doesn't return the PATH set // by PrepareEnvironment() so use GetEnvironmentVariable() instead // JLD - 2000-06-09 String strPath; int nSize=GetEnvironmentVariable(_T("PATH"), NULL, 0); GetEnvironmentVariable(_T("PATH"), strPath.GetBuffer(nSize), nSize); strPath.ReleaseBuffer(); m_strPath=strPath;#else LPCTSTR pszPath=_tgetenv(_T("PATH")); if(pszPath){ m_strPath=pszPath; }#endif ENTERCRITICAL; InstanceCount++; m_pNextInstance=pFirstInstance; if(m_pNextInstance){ m_pNextInstance->m_pPrevInstance=this; } m_pPrevInstance=0; pFirstInstance=this; LEAVECRITICAL; }CeCosTest::~CeCosTest(){ for(int i=0;i<(signed)m_arpExecsp.size();i++){ delete (CSubprocess *)m_arpExecsp[i]; } delete m_pspPipe; TRACE(_T("%%%% Delete test instance %08x\n"),this); Cancel(); CloseSocket(); if(m_pResource){ m_pResource->Release(); //delete m_pResource; //m_pResource=0; } VTRACE(_T("~CeCosTest(): EnterCritical and decrease instance count\n")); ENTERCRITICAL; InstanceCount--; TRACE(_T("%%%% Destroy instance. Instance count:=%d\n"),InstanceCount); if(pFirstInstance==this){ pFirstInstance=m_pNextInstance; } if(m_pPrevInstance){ m_pPrevInstance->m_pNextInstance=m_pNextInstance; } if(m_pNextInstance){ m_pNextInstance->m_pPrevInstance=m_pPrevInstance; } LEAVECRITICAL;}bool CeCosTest::RunRemote (LPCTSTR pszRemoteHostPort){ bool rc=false; TRACE(_T("RunRemote\n")); m_strExecutionHostPort=pszRemoteHostPort; m_Status=NotStarted; VTRACE(_T("RemoteThreadFunc()\n")); // Find a server. ConnectForExecution(); if(Cancelled!=Status()){ if(m_ep.Platform()->ServerSideGdb()){ // The executable is transmitted to the server for execution. // Send file size if(m_pSock->sendInteger(m_nFileSize,_T("file size"))&&m_nFileSize>0){ int nBufSize=MIN(10000,m_nFileSize); Buffer b(nBufSize); TRACE(_T("Sending [%d bytes]\n"), m_nFileSize); int nToSend=m_nFileSize; FILE *f1=_tfopen(m_strExecutable,_T("rb")); if(0==f1){ Log(_T("Failed to open %s - %s\n"),(LPCTSTR)m_strExecutable,strerror(errno)); } else { while (nToSend>0){ int nRead=fread( b.Data(), 1, nBufSize, f1); if(nRead<=0){ Log(_T("Failure reading %s - %s\n"),(LPCTSTR)m_strExecutable,strerror(errno)); break; } if(!send( b.Data(), nRead, _T("executable"))){ Log(_T("Failure sending %s - %s\n"),(LPCTSTR)m_strExecutable,(LPCTSTR)m_pSock->SocketErrString()); break; } nToSend-=nRead; } fclose(f1); f1=0; if(nToSend>0){ TRACE(_T("done [%d bytes sent]\n"),m_nFileSize-nToSend); Log(_T("Failed to transmit %s - %d/%d bytes sent\n"),(LPCTSTR)m_strExecutable,m_nFileSize-nToSend,m_nFileSize); } else { TRACE(_T("done\n")); rc=true; } } if(!recvResult(9*1000*60)){ // nine minutes Log(_T("Failed to receive result from remote server\n")); rc=false; } m_pSock->sendInteger(456); // send an ack [n'importe quoi] CloseSocket(); } } else { // The server sets up a connection between port and tcp/ip socket, and gdb is run locally // Big timeout here because we have to wait for the target to be reset // We do this: // do { // target ready indicator (0==fail, 1==ready, 2==fail and will retry) // any output so far // } while (2==target ready indicator) // read host:port String strHostPort; if(GetTargetReady(strHostPort)){ // Fix up a resource to represent permission to use the host:port we have been told about CTestResource resource; resource.SetTarget(m_ep.PlatformName()); resource.SetDownload(strHostPort,0); m_pResource=&resource; RunLocal(); m_pResource=0; m_pSock->sendInteger(Status(),_T("Terminating ack")); m_pSock->Close(); rc=true; } } } TRACE(_T("RemoteThreadFunc - exiting\n")); return rc;}// Run the test locallybool CeCosTest::RunLocal(){ bool rc=false; TRACE(_T("RunLocal %s\n"),(LPCTSTR)Executable()); if(!CeCosTestUtils::IsFile(Executable())){ Log(_T("Cannot run - %s is not a file\n"),(LPCTSTR)Executable()); } else if(0==m_pResource && 0==CTestResource::Count(m_ep)){ Log(_T("Cannot run a %s test\n"),(LPCTSTR)m_ep.PlatformName()); } else { m_Status=NotStarted; TRACE(_T("LocalThreadFunc - target=%s\n"),(LPCTSTR)m_ep.PlatformName()); // Acquire a port (our caller may have done this for us) VTRACE(_T("LocalThreadFunc():Trying to acquire a port\n")); if(0==m_pResource){ for(;;){ m_pResource=CTestResource::GetResource(m_ep); if(m_pResource||Cancelled==Status()){ break; } CeCosThreadUtils::Sleep(2000); TRACE(_T("Waiting for a port\n")); } } VTRACE(_T("\nPort acquired!\n")); if(Cancelled!=Status()){ // This means we have acquired a local port bool bTargetReady=false; if(!m_pResource->HasReset()){ bTargetReady=true; } else { bTargetReady=(CResetAttributes::RESET_OK==m_pResource->Reset(0,this)); } // we may proceed to execute the test if(bTargetReady){ SetStatus(NotStarted); if(NOTIMEOUT==m_ep.DownloadTimeout()){ // No elapsed timeout given - calculate from knowledge of executable size and baud rate // 10 baud ~= 1 byte/sec, but we halve this to account for download in hex :-( // We use a minimum of 30 seconds and double the calculated result for safety // Note that the baud rate is generally unknown on the client side. int nBaud=m_pResource->Baud(); if(0==nBaud){ CTestResource *pExecutionResource=CTestResource::Lookup(m_strExecutionHostPort); if(pExecutionResource){ nBaud=pExecutionResource->Baud(); } } if(0==nBaud){ nBaud=38400; } int nBytesPerSec=(nBaud/10)/2; // division by 2 assumes download in "ascii" (2 bytes/char) m_ep.SetDownloadTimeout (1000*MAX(30,2*(m_nStrippedSize/nBytesPerSec))); TRACE(_T("Estimated download time %d sec (%d bytes @ %d bytes/sec [%d baud])\n"),m_nStrippedSize/nBytesPerSec,m_nStrippedSize,nBytesPerSec,nBaud); } TRACE(_T("Active timeout=%d download timeout=%d\n"),m_ep.ActiveTimeout(), m_ep.DownloadTimeout()); GetInferiorCommands(m_arstrInferiorCmds); String strInferior(m_ep.Platform()->Inferior()); strInferior.Replace(_T("%e"),CygPath(m_strExecutable),true); RunInferior(strInferior); rc=true; } } if(m_pResource){ m_pResource->Release(); m_pResource=0; } TRACE(_T("RunLocal - exiting\n")); } return rc;}void CeCosTest::Cancel (){ SetStatus(Cancelled);}CeCosTest::ServerStatus CeCosTest::Connect (LPCTSTR pszHostPort, CeCosSocket *&pSock, const ExecutionParameters &e,String &strInfo,Duration dTimeout){ // Find out whether this host is receptive ServerStatus s=CONNECTION_FAILED; pSock=new CeCosSocket(pszHostPort,dTimeout); int nStatus; if(pSock->Ok() && pSock->sendString(e.Image(), _T("execution parameters")) && pSock->recvInteger(nStatus,_T("ready status")) && pSock->recvString(strInfo)){ s=(ServerStatus)MIN(nStatus,ServerStatusMax); } if(SERVER_READY!=s || ExecutionParameters::RUN!=e.Request()){ delete pSock; pSock=0; } return s;}// Initiate a connection to hostName:nPort and acquire the ready status [retry until this is achieved]// The socket (m_pSock) is left open.// This function is either called with m_strExecutionHostPort already set to a desired server// or else m_strExecutionHostPort empty (in which case the server is / dynamically)void CeCosTest::ConnectForExecution (){ bool bSchedule=(0==m_strExecutionHostPort.size()); Duration nDelay=2000; m_pSock=0; bool *arbHostTried=0; while(Cancelled!=Status()){ StringArray arstrHostPort,arstrTries; int nChoices; if(bSchedule){ if(!CTestResource::GetMatches(m_ep,arstrHostPort)){ Log(_T("Could not establish matches\n")); continue; } nChoices=arstrHostPort.size(); if(nChoices>0){ TRACE(_T("ConnectForExecution: choices are:\n")); for(int i=0;i<nChoices;i++){ TRACE(_T("\t%s\n"),(LPCTSTR)arstrHostPort[i]); } } } else { // Server has already been picked by caller nChoices=1; String str; arstrHostPort.push_back(m_strExecutionHostPort); } if(nChoices>0){ delete [] arbHostTried; arbHostTried=new bool[nChoices]; for(int i=0;i<nChoices;i++){ arbHostTried[i]=false; } // Loop around the choices for(int nUntried=nChoices;nUntried>0;nUntried--) { // Select one we haven't tried already: int nChoice; do { nChoice=rand() % nChoices; } while (arbHostTried[nChoice]); m_strExecutionHostPort=arstrHostPort[nChoice]; TRACE(_T("ConnectForExecution: chosen %s\n"),(LPCTSTR)m_strExecutionHostPort); if(CeCosSocket::IsLegalHostPort(m_strExecutionHostPort)){ // If we're using the resource server we had better check that the host // we are about to lock has not been resource-locked (the other match checks // will of course always succeed) String strInfo; ServerStatus s=bSchedule && !CTestResource::Matches(m_strExecutionHostPort,m_ep)?SERVER_LOCKED: Connect(m_strExecutionHostPort,m_pSock,m_ep,strInfo); arbHostTried[nChoice]=true; TRACE(_T("Connect: %s says %s %s\n"),(LPCTSTR)m_strExecutionHostPort,(LPCTSTR)Image(s),(LPCTSTR)strInfo); CTestResource *pResource=CTestResource::Lookup(m_strExecutionHostPort); if(pResource){ String str; str.Format(_T("%s %s %s"),(LPCTSTR)pResource->Image(),(LPCTSTR)strInfo,(LPCTSTR)Image(s)); arstrTries.push_back(str); } if(SERVER_READY==s){ // So that's ok then. We're outta here. INTERACTIVE(_T("Connected to %s\n"),(LPCTSTR)m_strExecutionHostPort); goto Done; } else { delete m_pSock; m_pSock=0; } } } } INTERACTIVE(_T("Warning - could not connect to any test servers:\n")); if(arstrTries.size()>0){ for(unsigned int i=0;i<arstrTries.size();i++){ INTERACTIVE(_T(" %s\n"),(LPCTSTR)arstrTries[i]); } } else { INTERACTIVE(_T("No servers available to execute %s test:\n"),(LPCTSTR)m_ep.PlatformName()); ENTERCRITICAL; for(CTestResource *pResource=CTestResource::First();pResource;pResource=pResource->Next()){ INTERACTIVE(_T(" %s\n"),(LPCTSTR)pResource->Image()); } LEAVECRITICAL; } INTERACTIVE(_T("Retry in %d seconds...\n"),nDelay/1000); // We have tried all possibilities - sleep before retrying CeCosThreadUtils::Sleep(nDelay); if(Cancelled==m_Status){ TRACE(_T("ConnectForExecution : cancelled\n")); goto Done;
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -