?? ecostest.cpp
字號(hào):
//####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 above
LPCTSTR 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 locally
bool 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){
?? 快捷鍵說(shuō)明
復(fù)制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號(hào)
Ctrl + =
減小字號(hào)
Ctrl + -