ecostest.cpp

来自「基于ecos的redboot」· C++ 代码 · 共 1,792 行 · 第 1/4 页

CPP
1,792
字号
        Log(_T("Could not create %s - %s\n"),(LPCTSTR)m_strExecutable,strerror(errno));
        bCanRun=false;
      }
      unsigned int nBufSize=MIN(100000,m_nFileSize);
      Buffer b(nBufSize);
      unsigned int nWritten=0;
      unsigned int nRead=0;
      while(nRead<m_nFileSize){
        int nToRead=MIN(nBufSize,m_nFileSize-nRead);
        if(!recv( b.Data(), nToRead, _T("executable"))){
          break;
        }
        nRead+=nToRead;
        if(0!=f2){
          char *c=(char *)b.Data();
          while(nToRead>0){
            int w=fwrite(c,1,nToRead,f2);
            if(-1==w){
              Log(_T("Write error on %s - %s\n"),(LPCTSTR)m_strExecutable,strerror(errno));
              bCanRun=false;
              break;
            }
            nWritten+=w;
            c+=w;
            nToRead-=w;
          }
        }
      }
      TRACE(_T("Accept - done reading [%d bytes read, %d bytes written]\n"),nRead,nWritten);
      if(0!=f2){
        fclose(f2);
        _tchmod(m_strExecutable,00700); // user read, write and execute
      } 
      if(0!=f2 && m_nFileSize!=nWritten){
        Log(_T("Failed to create %s correctly [%d/%d bytes written]\n"),(LPCTSTR)m_strExecutable, nWritten, m_nFileSize);
        bCanRun=false;
      }
      SetExecutable(m_strExecutable); // to set stripped length and title
      RunLocal();
      _tunlink(m_strExecutable);
    }
    sendResult();
    m_pSock->recvInteger(n); // receive an ack
  } else {
    // Client-side GDB
    bool bTargetReady;
    if(_TCHAR('\0')==*(m_pResource->ResetString())){
      bTargetReady=true;
      TRACE(_T("No reset possible\n"));
    } else {
      Log(_T("Resetting target using %s"),(LPCTSTR)m_pResource->ResetString());
      bTargetReady=(CResetAttributes::RESET_OK==m_pResource->Reset(ResetLogFunc,this));
    }
    TRACE(_T("Send Target Ready indicator=%d\n"),bTargetReady);
    m_pSock->sendInteger(bTargetReady,_T("target ready indicator"));
    
    int nAck=-1;
    
    if(bTargetReady){
      if(CeCosSocket::IsLegalHostPort(m_pResource->Serial())){
        TRACE(_T("Sending %s\n"),(LPCTSTR)m_pResource->Serial());
        if(m_pSock->sendString(m_pResource->Serial(),_T("Serial name")) && m_pSock->recvInteger(nAck,_T("Terminating ack"),CeCosSocket::NOTIMEOUT)){
          TRACE(_T("Terminating ack=%d\n"),nAck);
        }
      } else {
        String strHostPort(CeCosSocket::HostPort(CeCosSocket::MyHostName(),m_nAuxPort));
        
        TRACE(_T("Using %s\n"),(LPCTSTR)strHostPort);
        
        if(m_pSock->sendString(strHostPort,_T("host:port"))){
          
          // This Boolean signifies that the serial<-->tcp/ip conversation is done.  It may be set
          // on completion of the ConnectSocketToSerial thread (which is why we pass it to runthread)
          // and also set by us to *cause* the thread to complete.
          
          bool bConnectSocketToSerialThreadDone=false; // Indication of termination of ConnectSocketToSerial thread
          m_bStopConnectSocketToSerial=false; // Used to tap ConnectSocketToSerial thread on the shoulder
          
          CeCosThreadUtils::RunThread(SConnectSocketToSerialThreadFunc,this,&bConnectSocketToSerialThreadDone,_T("SConnectSocketToSerialThreadFunc")); 
          
          // Wait for either client or the ConnectSocketToSerial thread to finish.
          if(m_pSock->recv(&nAck,sizeof(int),_T("Terminating ack"),CeCosSocket::NOTIMEOUT,DerefBool,&bConnectSocketToSerialThreadDone)){
            TRACE(_T("Session terminated by request of client (%s)\n"),(LPCTSTR)Image((StatusType)nAck));
          } else if(0!=m_pSock->SocketError()){
            TRACE(_T("Session terminated by socket error - %s\n"),(LPCTSTR)m_pSock->SocketErrString());
          }
          if(!bConnectSocketToSerialThreadDone){
            // Tap ConnectSocketToSerial thread on the shoulder
            TRACE(_T("Waiting for ConnectSocketToSerial thread to terminate...\n"));
            m_bStopConnectSocketToSerial=true;
            CeCosThreadUtils::WaitFor(bConnectSocketToSerialThreadDone);
          }
        }
      }
    }
  }
  delete this;
}

bool CeCosTest::send(const void *pData,unsigned int nLength,LPCTSTR pszMsg,Duration dTimeout)
{
  return m_pSock->send(pData,nLength,pszMsg,dTimeout,IsCancelled,this);
}

bool CeCosTest::recv(const void *pData,unsigned int nLength,LPCTSTR pszMsg,Duration dTimeout)
{
  return m_pSock->recv(pData,nLength,pszMsg,dTimeout,IsCancelled,this);
}

void CeCosTest::Log(LPCTSTR  pszFormat, ...)
{
  va_list args;
  va_start(args, pszFormat);
  String str;
  str.vFormat(pszFormat,args);
  va_end(args);
  LogString(str);
}

void CeCosTest::LogString(LPCTSTR psz)
{
  if(*psz){
    ENTERCRITICAL;
    m_strOutput+=psz;
    LEAVECRITICAL;
    if(CeCosTrace::IsInteractive()){
      CeCosTrace::Out(psz);
    } else {
      TRACE(_T("%s"),psz);
    }
  }
}

bool CeCosTest::sendResult(Duration dTimeout)
{
  bool rc=
    m_pSock->sendInteger(m_Status,_T("result"),dTimeout) &&
    m_pSock->sendInteger(m_nDownloadTime,_T("result"),dTimeout) &&
    m_pSock->sendInteger(m_nTotalTime,_T("result"),dTimeout) &&
    m_pSock->sendInteger(m_nMaxInactiveTime,_T("result"),dTimeout) &&
    m_pSock->sendString (m_strOutput,_T("result"),dTimeout);
  return rc;
}

bool CeCosTest::recvResult(Duration dTimeout)
{
  String strOutput;
  int nStatus=StatusTypeMax;
  bool rc=
    m_pSock->recvInteger(nStatus,_T("result"),dTimeout) &&
    m_pSock->recvInteger(m_nDownloadTime,_T("result"),dTimeout) &&
    m_pSock->recvInteger(m_nTotalTime,_T("result"),dTimeout) &&
    m_pSock->recvInteger(m_nMaxInactiveTime,_T("result"),dTimeout) &&
    m_pSock->recvString (strOutput,_T("result"),dTimeout);
  m_Status=(StatusType)MIN(nStatus,StatusTypeMax);
  LogString(strOutput);
  return rc;
}

// Return time used by inferior gdb process - CPU for sim, wallclock otherwise
Time CeCosTest::InferiorTime() const
{
  if(*(m_pResource->Serial())){
    return Now();
  }
  if(!m_psp){
    return 0;
  }
  Time now=Now();
  if(now-m_tPrevSample>1000){
    m_tPrevSample=now;
    m_tInferiorCpuTime=m_psp->CpuTime();
  }
  return m_tInferiorCpuTime;
}

bool CeCosTest::CheckForTimeout()
{
  bool rc=(Cancelled!=Status());
  if(TimeOut!=m_Status && DownloadTimeOut!=m_Status){
    Time t=InferiorTime();
    if(t){
      // We have been able to measure the time
      if(m_bDownloading){
        m_nDownloadTime=MAX(m_nDownloadTime,Duration(InferiorTime()-m_tBase));
        if(m_nDownloadTime>m_ep.DownloadTimeout()){
          Log(_T("\n*** Timeout - download time ") WFS _T(" exceeds limit of ") WFS _T("\n"),WF(m_nDownloadTime),WF(m_ep.DownloadTimeout()));
          rc=false;
        }
      } else {
        m_nMaxInactiveTime=MAX(m_nMaxInactiveTime,Duration(InferiorTime()-m_tBase));
        if (m_nMaxInactiveTime>m_ep.ActiveTimeout()) {
          Log(_T("\n*** Timeout - inactive time ") WFS _T(" exceeds limit of ") WFS _T("\n"),WF(m_nMaxInactiveTime),WF(m_ep.ActiveTimeout()));
          rc=false;
        }
      }
    }
    m_nTotalTime=Duration(Now()-m_tWallClock0);
/*
    if(m_nTotalTime>m_ep.ElapsedTimeout()){
      Log(_T("\n*** Timeout - total time ") WFS _T(" exceeds limit of ") WFS _T("\n"),   WF(m_nTotalTime),WF(m_ep.ElapsedTimeout()));
      rc=false;
    }
*/
    if(!rc){
      SetStatus(m_bDownloading?DownloadTimeOut:TimeOut);
    }
  }
  return rc;
}

// Convert a path to something a cygwin tool will understand.  Used when invoking -size and -gdb
String CeCosTest::CygPath (LPCTSTR pszPath)
{
#ifdef _WIN32
  String str;
  TCHAR *buf=str.GetBuffer(2+MAX_PATH);
  TCHAR *pszFname;
  if(::GetFullPathName(pszPath,MAX_PATH,1+buf, &pszFname)){
    GetShortPathName(1+buf,1+buf,MAX_PATH); // ignore errors
    buf[0]=_TCHAR('/');
    buf[2]=buf[1];
    buf[1]=_TCHAR('/');
    for(int i=3;buf[i];i++){
      if(_TCHAR('\\')==buf[i]){
        buf[i]=_TCHAR('/');
      }
    }
    str.ReleaseBuffer();
    return str;
  } else {
    str.ReleaseBuffer();
    return pszPath;
  }
#endif
  return pszPath;
}

void CeCosTest::SetExecutable(LPCTSTR pszExecutable)
{
  m_strOutput=_T("");
  if(pszExecutable){
    m_strExecutable=pszExecutable;
    if(m_ep.Platform()){
      GetSizes();
    } else {
      ERROR(_T("Don't know how to get sizes of this platform type\n"));
    }
  } else {
    m_strExecutable=_T("");
  }
}

// Calculate the sizes of the given file.  The target parameter is necessary in order to 
// determine which -size executable to use to do the job.
bool CeCosTest::GetSizes()
{
TRACE(_T("GetSizes %s\n"),(LPCTSTR)Executable());
  bool rc=false;
  m_nStrippedSize=m_nFileSize=0;
  LPCTSTR pszPrefix=m_ep.Platform()->Prefix();
  struct _stat buf;
  if(-1==_tstat(Executable(),&buf)){
    Log(_T("%s does not exist\n"),(LPCTSTR)Executable());
  } else if (_TCHAR('\0')==*pszPrefix){
    LogString(_T("No prefix to run a size program\n"));
  } else {
    m_nFileSize=buf.st_size;
    const String strSizeCmd(String::SFormat(_T("%s-size %s"),pszPrefix,(LPCTSTR)CygPath(Executable())));
    String strOut;
    CSubprocess sp;
    if(!sp.Run(strOut,strSizeCmd)){
      Log(_T("Failed to run \"%s\" - %s\n"),(LPCTSTR)strSizeCmd,(LPCTSTR)sp.ErrorString());
    } else {
      const TCHAR *c=_tcschr(strOut,_TCHAR('\n'));
      if(c){
        c++;
      }
      int s1=0;
      int s2=0;
      if(c && 2==_stscanf(c,_T(" %d %d"),&s1,&s2)){
        rc=true;
        m_nStrippedSize=s1+s2;
      }
      TRACE(_T("GetSizes %s rc=%d file size=%d stripped size=%d\n"),(LPCTSTR)Executable(),rc,m_nFileSize,m_nStrippedSize);
    }
  }
  return rc;
}

void CeCosTest::SetTimeouts (Duration dActive,Duration dDownload/*,Duration dElapsed*/)
{
  m_ep.SetActiveTimeout  (dActive);
  m_ep.SetDownloadTimeout(dDownload);
/*
  m_ep.SetElapsedTimeout (dElapsed);
*/
}

void CeCosTest::CloseSocket (){
  delete m_pSock;
  m_pSock=0;
}

bool CeCosTest::AtPrompt()
{
  const String strPrompt(m_ep.Platform()->Prompt());
  unsigned int nPromptLen=_tcslen(strPrompt);
  return
    nPromptLen>0 &&
    m_strOutput.size()>=nPromptLen && 
    0==_tcscmp((LPCTSTR)m_strOutput+m_strOutput.size()-nPromptLen,strPrompt);
}

#ifdef _WIN32
BOOL WINAPI HandlerRoutine(
                           DWORD dwCtrlType   //  control signal type
                           )
{
  dwCtrlType; // eliminate compiler warning
  return TRUE;
}
#endif


bool CeCosTest::InteractiveInferior(LPCTSTR pszHostPort,TCHAR **argv)
{
  bool rc=false;
  if(_TCHAR('\0')!=*pszHostPort){
    if(!CeCosSocket::IsLegalHostPort(pszHostPort)){
      ERROR(_T("Illegal host:port '%s'\n"),pszHostPort);
      return false;
    } else {
      m_strExecutionHostPort=pszHostPort;
      Log(_T("Waiting to connect to %s...\n"),(LPCTSTR)m_strExecutionHostPort);
    }
  } else {
    Log(_T("Waiting to connect to a server...\n"));
  }
  
  ConnectForExecution();
  
  Log(_T("Connected to %s - waiting for target reset\n"),(LPCTSTR)m_strExecutionHostPort);
  String strHostPort,strOutput;
  // We read:
  //     target ready indicator
  //     any output so far
  //     (if target ready) host:port
  if(GetTargetReady(strHostPort)){
    Log(_T("Use %s\n"),(LPCTSTR)strHostPort);
    String strInferior(m_ep.Platform()->Prefix());
    strInferior+=_T("-gdb");
#ifdef _WIN32
    SetConsoleCtrlHandler(HandlerRoutine,TRUE);
    int n=_tspawnvp(_P_WAIT,strInferior,argv);
    if(-1==n){
      Log(_T("Failed to spawn %s\n"),(LPCTSTR)strInferior);
    } else {
      rc=(0==n);
    }   
    SetConsoleCtrlHandler(HandlerRoutine,FALSE);
#else // UNIX
    
    int pid=fork();
    switch(pid){
    case -1:
      _ftprintf(stderr,_T("fork failed\n"));
      pid=0;
      break;  
    case 0:
      // Process is created (we're the child)
      execvp(strInferior,argv);
      Log(_T("Error invoking %s - %s\n"),(LPCTSTR)strInferior,strerror(errno));
      exit(1);
      break;
    default:
      // Process is created (we're the parent)
      {
        signal(SIGINT,SIG_IGN);
        int stat;
        waitpid(pid,&stat,0);
        rc=(0==stat);
        signal(SIGINT,SIG_DFL);
      }
      break;
    }
#endif
    Log(_T("Inferior terminated\n"));
    // Tell the server we're through
    m_pSock->sendInteger(123,_T("Terminating ack"));
  }
  return rc;
}

void CALLBACK CeCosTest::ResetLogFunc(void *pParam, LPCTSTR psz) 
{
  CeCosTest *pTest=(CeCosTest *)pParam;
  TRACE(_T("Send Target Ready indicator=2\n"));
  pTest->m_pSock->sendInteger(2,_T("target ready indicator"));
  TRACE(_T("Send %s\n"),psz);
  pTest->m_pSock->sendString(psz,_T("output so far"));
}

CeCosTest::ExecutionParameters::RequestType CeCosTest::ExecutionParameters::RequestTypeValue(LPCTSTR psz)
{
  int r;
  for(r=0;r<RequestTypeMax;r++){
    if(0==_tcsicmp(psz,arRequestImage[r])){
      break;
    }
  }
  return (RequestType)r;
}

void CeCosTest::InferiorOutputFunc(LPCTSTR pszMsg)
{
  LogString(pszMsg);

  m_nOutputLen+=_tcslen(pszMsg);

  if(m_pspPipe){
    m_pspPipe->Send(pszMsg);
  }

  if(m_nOutputLen>20000){
    LogString(_T("\n>>>> Infra FAIL\n*** too much output ***\n>>>>\n"));
    SetStatus(Fail);
    m_psp->Kill();
  }
  
  m_tBase=InferiorTime(); // We are seeing life, so reset the clock for timeouts
  
  if(AtPrompt()){
    
    // gdb's output included one or more prompts
    // Send another command along
    if(m_nCmdIndex>=m_arstrInferiorCmds.size()){
      // Nothing further to say to gdb - exit
      
      m_psp->Kill(); // case 3
    } else {

      if(m_nCmdIndex>0 && 0==_tcscmp(_T("load"),m_arstrInferiorCmds[m_nCmdIndex-1])){
        // load command was previous command - we are no longer downloading
        m_bDownloading=false;
      }

      String strCmd(m_arstrInferiorCmds[m_nCmdIndex++]);

⌨️ 快捷键说明

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