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 + -
显示快捷键?