📄 ecostest.cpp
字号:
// Do not spawn a thread while in possession of a mutex ENTERCRITICAL; Trace("csl=%d\n",CeCosTestUtils::m_nCriticalSectionLock); assert(1==CeCosTestUtils::m_nCriticalSectionLock); LEAVECRITICAL; THREAD_ID hThread; SetPath(m_strPath); if(0==cb.m_pProc && 0==cb.m_pParam){ Trace("RunThread: - blocking call\n"); // No callback, so no need to create a thread: (this->*pThreadFunc)(pParam); hThread=(THREAD_ID)-1; } else { ThreadInfo *pInfo=new ThreadInfo; // SThreadFunc will delete pInfo->pTest=this; pInfo->pFunc=pThreadFunc; pInfo->pParam=pParam; // Param to pass to pThreadFunc pInfo->cb=cb;#ifdef _WIN32 DWORD dwID; hThread=pInfo->hThread=CreateThread (0,0,SThreadFunc, pInfo, 0, &dwID); Trace("RunThread: - non-blocking call (new thread=%x)\n",dwID);#else VTRACE("RunThread():Calling pthread_create()\n"); int pc_rc, pd_rc; pc_rc = pthread_create(&pInfo->hThread, NULL, SThreadFunc, pInfo); Trace("RunThread: - non-blocking call (new thread=%x)\n",pInfo->hThread); VTRACE("RunThread(): pthread_create() returned <%d>\n", pc_rc); if (pc_rc != 0) { VTRACE("RunThread(): pthread_create failed\n"); perror("RunThread(): pthread_create failed with : "); hThread=pInfo->hThread=0; } else { VTRACE("RunThread(): Calling pthread_detach\n"); pd_rc = pthread_detach(pInfo->hThread); VTRACE("RunThread(): pthread_detach returned <%d>\n", pd_rc); if (pd_rc != 0) { Trace("RunThread(): pthread_detach failed\n"); perror("RunThread(): pthread_detach failed with : "); hThread=pInfo->hThread=0; } } VTRACE("RunThread(): returned from pthread calls - exiting RunThread()\n");#endif } return hThread;}THREADFUNC CeCosTest::SThreadFunc (void *pParam){ VTRACE("SThreadFunc()\n"); ThreadInfo *pInfo=(ThreadInfo*)pParam; #ifdef _WIN32 __try { // Call what we are instructed to (e.g. LocalThreadFunc): (pInfo->pTest->*pInfo->pFunc)(pInfo->pParam); } __except ( CeCosTestUtils::FilterFunction(GetExceptionInformation() )) { TRACE("Handling exception...\n"); } #else try { // Call what we are instructed to (e.g. LocalThreadFunc): (pInfo->pTest->*pInfo->pFunc)(pInfo->pParam); } catch (...){ TRACE("Exception caught!!!\n"); } #endif // Call the Callback: VTRACE("SThreadFunc(): Calling InvokeCallback()\n"); pInfo->pTest->InvokeCallback(pInfo->cb); // No more references to pInfo->pTest from now on... VTRACE("SThreadFunc(): deleting (ThreadInfo)pInfo\n"); #ifdef _WIN32 CloseHandle(pInfo->hThread); #endif delete pInfo; TRACE("Thread exiting\n"); return 0;}// Call the given Callback function with the given argument:void CeCosTest::InvokeCallback(const CeCosTest::Callback &cb){ if(cb.m_pProc){ cb.m_pProc (this, cb.m_pParam); } else if (cb.m_pParam) { // No function - just a flag: *(char *)cb.m_pParam=1; }}// This function may be run as a thread (win32) or called (unix)void CeCosTest::DriveGdb(void *pParam){ const CeCosTestUtils::String *arstrCmd=(const CeCosTestUtils::String *)pParam; int nCmdIndex=0; SetStatus(NotStarted); m_nMaxInactiveTime=0; m_nTotalTime=0; m_nDownloadTime=0; m_bDownloading=!Sim(); m_tBase=GdbTime(); m_tBase0=GdbTime(); m_tWallClock0=CeCosTestUtils::Time::Now(); TRACE("DriveGdb()\n"); bool bBlockingReads; int nLastGdbInst=0; #ifdef _WIN32 bBlockingReads=true; #else bBlockingReads=false; #endif // Loop until 1 of: // 1. Timeout detected // 2. Gdb process is dead // 3. At a gdb prompt and no more commands to send to gdb // 4. Pipe read failure // 5. Pipe write failure do { CeCosTestUtils::String str; int readrc=ReadPipe(m_rPipeHandle,str,bBlockingReads); #ifdef _WIN32 VTRACE("Blocking read returned %d\n",readrc); #endif switch(readrc){ case 0: CeCosTestUtils::Sleep(250); // only unix will execute this break; case -1: goto Done; // case 4 break; default: LogTimeStampedOutput(str); if(m_strOutput.GetLength()>20000){ LogString("\n>>>> Infra FAIL\n*** too much output ***\n>>>>\n"); SetStatus(Fail); goto Done; } if(strstr(m_strOutput,Sim()?"Starting program: ":"Continuing.")){ SetStatus(NoResult); } m_tBase=GdbTime(); if(!BreakpointsOperational() && strstr(m_strOutput,"EXIT:")){ goto Done; } if(AtGdbPrompt()){ m_tBase=GdbTime(); VTRACE("DriveGdb(): Got gdb prompt\n"); // gdb's output included one or more prompts // Send another command along if(0==arstrCmd[nCmdIndex].GetLength()){ // Nothing further to say to gdb - exit VTRACE("DriveGdb():No more commands to send gdb - exit\n"); goto Done; // case 3 } else { CeCosTestUtils::String strCmd(arstrCmd[nCmdIndex++]); // If at a prompt and we can see a GDB instruction, send it down const char *pszGdbcmd=strstr(nLastGdbInst+(const char *)m_strOutput,"GDB:"); if(pszGdbcmd){ pszGdbcmd+=4; char cTerm; if('<'==*pszGdbcmd){ cTerm='>'; pszGdbcmd++; } else { cTerm='\n'; } const char *c=strchr(pszGdbcmd,cTerm); if(c){ int nLen=c-pszGdbcmd; nLastGdbInst=c+1-(const char *)m_strOutput; char *buf=strCmd.GetBuffer(nLen); strncpy(buf,pszGdbcmd,nLen); buf[nLen]='\0'; nCmdIndex--; // undo increment above } } strCmd+='\n'; LogString(strCmd); if(!WritePipe(m_wPipeHandle,strCmd)){ Trace("Writepipe returned error\n"); goto Done; // case 5 } if(0==strcmp(strCmd,"run\n")||0==strcmp(strCmd,"cont\n")){ m_tBase=GdbTime(); m_bDownloading=false; } } } break; } if (Sim() && GdbTime()-m_tBase>PRIORITYLATCH){ VTRACE("DriveGdb(): Calling LowerGdbPriority()\n"); LowerGdbPriority(); } } while (GdbProcessAlive() && CheckForTimeout()); // cases 2 and 1 Done: Trace("DriveGdb() - done\n"); Suck(); if(GdbProcessAlive() && AtGdbPrompt()){ LogString("bt\n"); WritePipe(m_wPipeHandle,"bt\n"); Suck(); } // Read anything gdb has to say [within limits] Suck(); // order is important in case (for example to cater for cases // in which FAIL follows PASS in output) static const char *arpszKeepAlive[]={"FAIL:","NOTAPPLICABLE:", "PASS:"}; SetStatus(NoResult); for(int i=0;i<sizeof arpszKeepAlive/sizeof arpszKeepAlive[0];i++){ const char *pszInfo=strstr(m_strOutput,arpszKeepAlive[i]); if(0!=pszInfo){ Trace("DriveGdb: saw '%s'\n",arpszKeepAlive[i]); // Reset the active timeout base if we see one of these: switch(pszInfo[0]){ case 'F': // fail SetStatus(Fail); break; case 'N': // notapplicable SetStatus(Inapplicable); break; case 'P': // pass SetStatus(Pass); break; } } } // Certain output spells failure... if(CeCosTest::Fail!=Status()){ if(OutputContains("cyg_assert_fail (")) SetStatus(Fail); } else { static const char *arpszSignals[]={"SIGBUS", "SIGSEGV", "SIGILL", "SIGFPE", "SIGSYS", "SIGTRAP"}; for(int i=0;i<sizeof arpszSignals/sizeof arpszSignals[0];i++){ CeCosTestUtils::String str1,str2; str1.Format("signal %s",arpszSignals[i]); str2.Format("handle %s nostop",arpszSignals[i]); if(OutputContains(str1)&&!OutputContains(str2)){ SetStatus(Fail); break; } } } // Check for expect: strings static const char szExpect[]="EXPECT:"; static const int nExpectLen=sizeof szExpect-1; for(const char*c=strstr(m_strOutput,szExpect);c;c=strstr(c,szExpect)){ c+=nExpectLen; if('<'==*c){ c++; const char *d=strchr(c,'>'); if(d){ unsigned int nLen=d-c; do { d++; } while (isspace(*d)); // Skip timestamp if('<'==*d){ d=strchr(d,'>'); if(0==d){ continue; } do { d++; } while (isspace(*d)); } // Now d points to output of length nLen expected to compare equal to that at c if(strlen(d)>=nLen && 0!=strncmp(c,d,nLen) && '\n'==d[nLen]) { LogString("EXPECT:<> failure\n"); SetStatus(Fail); } } } } m_nTotalTime=CeCosTestUtils::Time::Now()-m_tWallClock0; Trace("Exiting DriveGdb()\n");}CeCosTestUtils::Time CeCosTest::GdbTime(){ return Sim()?GdbCpuTime():CeCosTestUtils::Time::Now();}bool CeCosTest::CheckForTimeout(){ bool rc=false; if(TimeOut!=m_Status && DownloadTimeOut!=m_Status){ CeCosTestUtils::Duration &dTime=m_bDownloading?m_nDownloadTime:m_nMaxInactiveTime; dTime=max(dTime,GdbTime()-m_tBase); CeCosTestUtils::Duration dTimeout=m_bDownloading?ElapsedTimeout():ActiveTimeout(); if(dTimeout!=NOTIMEOUT && dTime>dTimeout) { Log("\n*** Timeout - %s time " WFS " exceeds limit of " WFS "\n", m_bDownloading?"download":"max inactive",WF(dTime),WF(dTimeout)); SetStatus(m_bDownloading?DownloadTimeOut:TimeOut); } else if(CeCosTestUtils::Time::Now()-m_tWallClock0>max(3*dTimeout,15*60*1000)){ Log("\n*** Timeout - total time " WFS " exceeds limit of " WFS "\n", WF(CeCosTestUtils::Time::Now()-m_tWallClock0),WF(max(3*dTimeout,15*60*1000))); SetStatus(m_bDownloading?DownloadTimeOut:TimeOut); } else { rc=true; } } return rc;}void CeCosTest::Trace(const char * pszFormat, ...){ if(CeCosTestUtils::IsTracingEnabled()){ va_list marker; va_start (marker, pszFormat); CeCosTestUtils::String str; str.vFormat(pszFormat,marker); va_end
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -