⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 ecostest.cpp

📁 基于ecos的redboot
💻 CPP
📖 第 1 页 / 共 4 页
字号:
//####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){

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -