URL
https://opencores.org/ocsvn/openrisc/openrisc/trunk
Subversion Repositories openrisc
[/] [openrisc/] [trunk/] [rtos/] [ecos-2.0/] [tools/] [src/] [tools/] [Utils/] [common/] [Subprocess.cpp] - Rev 174
Compare with Previous | Blame | View Log
//####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#### //=========================================================================== //=========================================================================== //#####DESCRIPTIONBEGIN#### // // Author(s): sdf // Contact(s): sdf // Date: 1998/08/11 // Version: 0.01 // Purpose: // Description: This is the implementation of the class which allows for spawning subprocesses // // Requires: // Provides: // See also: // Known bugs: // Usage: // //####DESCRIPTIONEND#### // //=========================================================================== #include "eCosTrace.h" #include "Subprocess.h" #ifdef _WIN32 #include <tlhelp32.h> HINSTANCE CSubprocess::hInstLib1 = VER_PLATFORM_WIN32_NT==CSubprocess::GetPlatform()?LoadLibrary(_T("PSAPI.DLL")):LoadLibrary(_T("Kernel32.DLL")) ; HINSTANCE CSubprocess::hInstLib2 = VER_PLATFORM_WIN32_NT==CSubprocess::GetPlatform()?LoadLibrary(_T("NTDLL.DLL")):NULL; #endif //#define CloseHandle(x) TRACE(_T("CSubprocess::CloseHandle %x\n"),x);::CloseHandle(x) const unsigned int CSubprocess::PROCESS_KILL_EXIT_CODE=0xCCFFCCFF; CSubprocess::CSubprocess(bool bAutoDelete): m_pfnContinue(DefaultContinuationFunc), m_pContinuationFuncParam(0), m_bAutoDelete(bAutoDelete), m_bThreadTerminated(true), m_bVerbose(false), m_nExitCode(-1), m_idProcess(0), m_pLogparam(0), m_pfnLogfunc(0), m_bKillThread(false) { #ifdef _WIN32 m_hProcess=0; #endif } CSubprocess::~CSubprocess() { Kill(); if(!CeCosThreadUtils::WaitFor(m_bThreadTerminated,1000)){ m_bKillThread=true; CeCosThreadUtils::WaitFor(m_bThreadTerminated); } #ifdef _WIN32 if(m_hProcess){ CloseHandle(m_hProcess); } #endif } bool CSubprocess::Run(LogFunc *pfnLog,void * pLogparam, LPCTSTR pszCmd,bool bBlock/*=true*/) { bool rc; if(!m_bThreadTerminated){ rc=false; } else { m_pfnLogfunc=pfnLog; m_pLogparam=pLogparam; #ifdef _WIN32 // UNIX does it from the thread func. WIN32 could too, but it's nice to know at the time // of calling run whether the process is successfully created. if(m_hProcess){ // Normally done in the dtor CloseHandle(m_hProcess); } rc=CreateProcess(pszCmd); #else m_strCmd=pszCmd; rc=true; #endif if(rc){ m_bKillThread=false; if(bBlock){ // When using RunThread, the manipulation of this Boolean is taken care of. // Here we must do it ourselves. m_bThreadTerminated=false; ThreadFunc(); m_bThreadTerminated=true; } else { CeCosThreadUtils::RunThread(SThreadFunc,this,&m_bThreadTerminated,String::SFormat(_T("subprocess %d read"),m_idProcess)); } } } return rc; } #ifdef _WIN32 bool CSubprocess::CreateProcess(LPCTSTR pszCmdline) { STARTUPINFO si; // For CreateProcess call HANDLE hrPipe,hwPipe,hwPipe2,m_hrPipeTemp,m_hwPipeTemp; // Create the anonymous pipe SECURITY_ATTRIBUTES saPipe; // Security for anonymous pipe saPipe.nLength = sizeof(SECURITY_ATTRIBUTES); saPipe.lpSecurityDescriptor = NULL; saPipe.bInheritHandle = true; ::CreatePipe(&m_hrPipeTemp,&hwPipe,&saPipe,10240); // In most cases you can get away with using the same anonymous // pipe write handle for both the child's standard output and // standard error, but this may cause problems if the child app // explicitly closes one of its standard output or error handles. If // that happens, the anonymous pipe will close, since the child's // standard output and error handles are really the same handle. The // child won't be able to write to the other write handle since the // pipe is now gone, and parent reads from the pipe will return // ERROR_BROKEN_PIPE and child output will be lost. To solve this // problem, simply duplicate the write end of the pipe to create // another distinct, separate handle to the write end of the pipe. // One pipe write handle will serve as standard out, the other as // standard error. Now *both* write handles must be closed before the // write end of the pipe actually closes. ::DuplicateHandle(::GetCurrentProcess(), // Source process hwPipe, // Handle to duplicate ::GetCurrentProcess(), // Destination process &hwPipe2, // New handle, used as stderr by child 0, // New access flags - ignored since DUPLICATE_SAME_ACCESS true, // It's inheritable DUPLICATE_SAME_ACCESS); ::CreatePipe(&hrPipe,&m_hwPipeTemp,&saPipe,10240); // Create new output read handle and the input write handles, setting // the Properties to FALSE. Otherwise, the child inherits the // properties and, as a result, non-closeable handles to the pipes // are created. DuplicateHandle(GetCurrentProcess(),m_hrPipeTemp, GetCurrentProcess(), &m_hrPipe, // Address of new handle. 0,FALSE, // Make it uninheritable. DUPLICATE_SAME_ACCESS); DuplicateHandle(GetCurrentProcess(),m_hwPipeTemp, GetCurrentProcess(), &m_hwPipe, // Address of new handle. 0,FALSE, // Make it uninheritable. DUPLICATE_SAME_ACCESS); // Close inheritable copies of the handles we do not want to be inherited: CloseHandle(m_hrPipeTemp); CloseHandle(m_hwPipeTemp); memset(&si, 0, sizeof(si)); si.cb = sizeof(si); si.hStdOutput = hwPipe; si.hStdError = hwPipe2; si.hStdInput = hrPipe; si.dwFlags = STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW; si.wShowWindow = SW_SHOW; LPCTSTR pszDir; if(m_strDir.empty()){ pszDir=NULL; // current directory } else { pszDir=m_strDir; } PROCESS_INFORMATION pi; String strCmd(pszCmdline); String strOrigpath; if(!m_strPath.empty()){ int nSize=GetEnvironmentVariable(_T("PATH"), NULL, 0); if(nSize>0){ GetEnvironmentVariable(_T("PATH"),strOrigpath.GetBuffer(nSize),nSize); strOrigpath.ReleaseBuffer(); SetEnvironmentVariable(_T("PATH"),m_strPath); } } bool rc=(TRUE==::CreateProcess(NULL,strCmd.GetBuffer(),NULL,NULL,true,DETACHED_PROCESS|CREATE_NEW_PROCESS_GROUP,NULL,pszDir,&si,&pi)); if(!m_strPath.empty()){ SetEnvironmentVariable(_T("PATH"),strOrigpath); } m_nErr=GetLastError(); strCmd.ReleaseBuffer(); if(rc){ m_idProcess=pi.dwProcessId; m_hProcess=pi.hProcess; if(m_bVerbose){ Output(String::SFormat(_T("*** Process %d created \"%s\"\n"),m_idProcess,pszCmdline)); } TRACE(String::SFormat(_T("Process %d created \"%s\"\n"),m_idProcess,pszCmdline)); m_nExitCode=STILL_ACTIVE; CloseHandle(pi.hThread); } else { m_idProcess=0; if(m_bVerbose){ Output(String::SFormat(_T("*** Failed to create process \"%s\" %s\n"),pszCmdline,(LPCTSTR)ErrorString())); } TRACE(String::SFormat(_T("Failed to create process \"%s\" %s\n"),pszCmdline,(LPCTSTR)ErrorString())); m_nExitCode=GetLastError(); CloseHandle(m_hrPipe);m_hrPipe=INVALID_HANDLE_VALUE; CloseHandle(m_hwPipe);m_hwPipe=INVALID_HANDLE_VALUE; } CloseHandle(hrPipe); CloseHandle(hwPipe); CloseHandle(hwPipe2); return rc; } void CSubprocess::ThreadFunc() { TRACE(_T("Reading from process %d\n"),m_idProcess); DWORD dwAvail; DWORD dwExitCode; while (!m_bKillThread && m_pfnContinue(m_pContinuationFuncParam) && ::PeekNamedPipe(m_hrPipe, NULL, 0, 0, &dwAvail, NULL)){ //TRACE(_T("P%d\n"),dwAvail); if(dwAvail){ dwAvail=MIN(dwAvail,80); // Read a maximum of 80 characters at a time DWORD dwRead; char *buf=new char[dwAvail+1]; //TRACE(_T("R%d\n"),dwAvail); if(!::ReadFile(m_hrPipe, buf, dwAvail, &dwRead, NULL)){ TRACE(_T("ReadFile returns false\n")); delete [] buf; break; } buf[dwRead]='\0'; Output(String::CStrToUnicodeStr(buf)); delete [] buf; } else if (!ProcessAlive()) { TRACE(_T("m_bThreadTerminated=%d\n"),m_bThreadTerminated); break; } // Fix for hanging in an endless loop under Windows ME, by Bill Diehls <billabloke@yahoo.com> else if (::GetExitCodeProcess(m_hProcess, &dwExitCode) && dwExitCode!=STILL_ACTIVE) { break; } else { CeCosThreadUtils::Sleep(250); } } ::GetExitCodeProcess(m_hProcess, &dwExitCode); m_nExitCode=dwExitCode; #ifdef _DEBUG String str; switch(dwExitCode){ case STILL_ACTIVE: str=_T("still alive"); if(m_bKillThread){ str+=_T(" - requested to stop reading"); } break; case PROCESS_KILL_EXIT_CODE: str=_T("killed"); break; default: str.Format(_T("terminated rc=%d"),dwExitCode); break; } TRACE(_T("Finished reading from process %d (%s)\n"),m_idProcess,(LPCTSTR)str); #endif CloseHandle(m_hrPipe);m_hrPipe=INVALID_HANDLE_VALUE; CloseHandle(m_hwPipe);m_hwPipe=INVALID_HANDLE_VALUE; if(m_bAutoDelete){ m_bThreadTerminated=true; // or else the dtor will block delete this; } } #else // UNIX bool CSubprocess::CreateProcess(LPCTSTR pszCmdline) { m_idProcess=0; int fdchild=-1; // the file descriptor for the child (slave) half of the pseudo-tty pair // Get a free /dev/ptyp0 (master) and /dev/ttyp0 (slave) tty pair String strMasterTty,strChildTty; for(unsigned int c=0;c<64;c++){ strMasterTty.Format("/dev/pty%c%x",'p'+c/16,c%16); m_tty=open(strMasterTty, O_RDWR | O_NOCTTY); if (-1!=m_tty) { strChildTty.Format("/dev/tty%c%x",'p'+c/16,c%16); fdchild = open(strChildTty, O_RDWR); if (-1==fdchild) { close(m_tty); m_tty=fdchild=-1; } else { VTRACE("opened %s - fd=%d\n",(LPCTSTR)strMasterTty,m_tty); break; } } } if(-1==m_tty){ ERROR(_T("Failed to get a pty\n")); return false; } TRACE(_T("Master pty %s (fd %d) slave pty %s (fd %d)\n"),(LPCTSTR)strMasterTty,m_tty,(LPCTSTR)strChildTty,fdchild); m_idProcess=fork(); switch (m_idProcess) { // Fork failed case -1: TRACE(_T("Failed to create process - %s\n"),strerror(errno)); m_idProcess=0; break; case 0: // Process is created (we're the child) { // Close all descriptors except the slave side of the pseudo-terminal for (int fd = 0; fd < (int) sysconf(_SC_OPEN_MAX); fd++) { if(fd!=fdchild){ close(fd); } } setsid(); dup2(fdchild, 0); dup2(fdchild, 1); dup2(fdchild, 2); close(fdchild); if(!m_strDir.empty()){ if(0!=chdir(m_strDir)){ if(m_bVerbose){ fprintf(stderr,_T("*** Failed to change directory to %s\n"),(LPCTSTR)m_strDir); } exit (5); } } if(m_bVerbose){ fprintf(stderr,_T("*** Process %d created \"%s\"\n"),m_idProcess,pszCmdline); } StringArray ar; int argc=String(pszCmdline).Chop(ar,_TCHAR(' '),true); TCHAR **argv=new TCHAR *[1+argc]; for(int i=0;i<argc;i++){ argv[i]=new TCHAR[1+strlen(ar[i])]; strcpy(argv[i],ar[i]); } argv[argc]=0; if(!m_strPath.empty()){ _tputenv(String::SFormat(_T("PATH=%s"),(LPCTSTR)m_strPath)); } _texecvp(argv[0], argv); } fprintf(stderr,"exec error - %s\n",strerror(errno)); exit(4); default: // Process is created (we're the parent) TRACE(_T("Closing fd %d\n"),fdchild); close(fdchild); TRACE(_T("Forked to create process %s - process id <%d>\n"), pszCmdline, m_idProcess); break; } return 0!=m_idProcess; } void CSubprocess::ThreadFunc() { if(!CreateProcess(m_strCmd)){ ERROR(_T("Failed to create process for %s\n"),(LPCTSTR)m_strCmd); } else { fcntl(m_tty,F_SETFL,O_NONBLOCK); int rc; do { TCHAR buf[4096]; rc=read(m_tty, buf, sizeof(buf)-1); if(rc>=0){ buf[rc]='\0'; } switch(rc){ case -1: if(EAGAIN==errno){ CeCosThreadUtils::Sleep(250); } else { goto Done; } break; case 0: goto Done; continue; default: buf[rc]=_TCHAR('\0'); Output(String::CStrToUnicodeStr(buf)); continue; } } while(!m_bKillThread && m_pfnContinue(m_pContinuationFuncParam)); Done: TRACE(_T("Closing fd %d\n"),m_tty); close (m_tty); switch(waitpid(m_idProcess,&m_nExitCode,WNOHANG)); } if(m_bAutoDelete){ delete this; } } #endif void CSubprocess::Output (LPCTSTR psz) { m_pfnLogfunc(m_pLogparam,psz); } void CSubprocess::Send(LPCTSTR str) { char *psz=String(str).GetCString(); int nToWrite=strlen(psz); const char *c=psz; do { #ifdef _WIN32 DWORD dwWritten; if(!::WriteFile(m_hwPipe,psz,nToWrite,&dwWritten,0)){ break; } #else int dwWritten = write(m_tty, c, nToWrite); if(-1==dwWritten){ break; } #endif nToWrite-=(int)dwWritten; c+=(int)dwWritten; } while (nToWrite>0); //::FlushFileBuffers(m_hwPipe); delete [] psz; } bool CSubprocess::Kill(bool bRecurse) { TRACE(_T("CSubprocess::Kill pid %d recurse=%d\n"),m_idProcess,bRecurse); PInfoArray arPinfo; bool rc=false; if(m_idProcess && -1!=m_idProcess){ // Start of with the easy one: if(bRecurse) { // Need to gather this information before we orphan our grandchildren: PSExtract(arPinfo); } #ifdef _WIN32 if(m_hProcess){ TRACE(_T("Terminate process %s\n"),(LPCTSTR)Name(m_idProcess)); rc=(TRUE==::TerminateProcess(m_hProcess,PROCESS_KILL_EXIT_CODE)); // dtor's (or subsequent Run's) responsibility to close the handle } #else rc=(0==kill(m_idProcess,SIGTERM)); int status; waitpid(m_idProcess,&status,WNOHANG); #endif if(bRecurse) { // kill process *and* its children // FIXME: needs to be top-down for(int i=0;i<(signed)arPinfo.size();i++){ if(arPinfo[i].IsChildOf(m_idProcess)){ #ifdef _WIN32 // begin hack const String strName(Name(arPinfo[i].PID)); if(_tcsstr(strName,_T("eCosTest")) || _tcsstr(strName,_T("cmd.EXE")) || _tcsstr(strName,_T("CMD.EXE")) || arPinfo[i].PID==(signed)GetCurrentProcessId()){ continue; } // end hack HANDLE hProcess=::OpenProcess(PROCESS_TERMINATE,false,arPinfo[i].PID); if(hProcess){ TRACE(_T("Terminate process %s\n"),(LPCTSTR)Name(arPinfo[i].PID)); rc&=(TRUE==::TerminateProcess(hProcess,PROCESS_KILL_EXIT_CODE)); CloseHandle(hProcess); } else { rc=false; } #else rc&=(0==kill(arPinfo[i].PID,SIGTERM)); int status; waitpid(arPinfo[i].PID,&status,WNOHANG); #endif } } } } return rc; } Time CSubprocess::CpuTime(bool bRecurse) const { Time t=0; // kill process *and* its children // FIXME: needs to be top-down #ifdef _WIN32 __int64 ftCreation,ftExit,ftKernel,ftUser; if(m_hProcess && ::GetProcessTimes (m_hProcess,(FILETIME *)&ftCreation,(FILETIME *)&ftExit,(FILETIME *)&ftKernel,(FILETIME *)&ftUser)){ t+=Time((ftKernel+ftUser)/10000); } if(bRecurse){ PInfoArray arPinfo; PSExtract(arPinfo); if(m_idProcess && -1!=m_idProcess){ for(int i=0;i<(signed)arPinfo.size();i++){ if(arPinfo[i].IsChildOf(m_idProcess)){ t+=arPinfo[i].tCpu; } } } } #else PInfoArray arPinfo; PSExtract(arPinfo); for(int i=0;i<(signed)arPinfo.size();i++){ if(arPinfo[i].PID==m_idProcess || arPinfo[i].IsChildOf(m_idProcess)){ t+=arPinfo[i].tCpu; } } #endif return t; } #ifdef _WIN32 bool CSubprocess::PSExtract(CSubprocess::PInfoArray &arPinfo) { bool rc=false; arPinfo.clear(); // If Windows NT: switch(GetPlatform()) { case VER_PLATFORM_WIN32_NT: if(hInstLib1) { // Get procedure addresses. static BOOL (WINAPI *lpfEnumProcesses)( DWORD *, DWORD cb, DWORD * ) = (BOOL(WINAPI *)(DWORD *,DWORD,DWORD*))GetProcAddress( hInstLib1, "EnumProcesses" ) ; if( lpfEnumProcesses) { if(hInstLib2) { static DWORD (WINAPI *lpfNtQueryInformationProcess)( HANDLE, int, void *, DWORD, LPDWORD ) = (DWORD(WINAPI *)(HANDLE, int, void *, DWORD, LPDWORD)) GetProcAddress( hInstLib2,"NtQueryInformationProcess" ) ; if(lpfNtQueryInformationProcess){ DWORD dwMaxPids=256; DWORD dwPidSize; DWORD *arPids = NULL ; do { delete [] arPids; arPids=new DWORD[dwMaxPids]; } while(lpfEnumProcesses(arPids, dwMaxPids, &dwPidSize) && dwPidSize/sizeof(DWORD)==dwMaxPids) ; if(dwPidSize/sizeof(DWORD)<dwMaxPids){ rc=true; for( DWORD dwIndex = 0 ; (signed)dwIndex < dwPidSize/sizeof(DWORD); dwIndex++ ) { // Regardless of OpenProcess success or failure, we // still call the enum func with the ProcID. DWORD pid=arPids[dwIndex]; HANDLE hProcess=::OpenProcess( PROCESS_QUERY_INFORMATION, FALSE, pid ); if (hProcess ) { struct { DWORD ExitStatus; // receives process termination status DWORD PebBaseAddress; // receives process environment block address DWORD AffinityMask; // receives process affinity mask DWORD BasePriority; // receives process priority class ULONG UniqueProcessId; // receives process identifier ULONG InheritedFromUniqueProcessId; // receives parent process identifier } pbi; memset( &pbi, 0, sizeof(pbi)); DWORD retLen; __int64 ftCreation,ftExit,ftKernel,ftUser; if(lpfNtQueryInformationProcess(hProcess, 0 /*ProcessBasicInformation*/, &pbi, sizeof(pbi), &retLen)>=0 && TRUE==::GetProcessTimes (hProcess,(FILETIME *)&ftCreation,(FILETIME *)&ftExit,(FILETIME *)&ftKernel,(FILETIME *)&ftUser)){ // The second test is important. It excludes orphaned processes who appear to have been adopted by virtue of a new // process having been created with the same ID as their original parent. PInfo p; p.PID=pid; p.PPID=pbi.InheritedFromUniqueProcessId; p.tCreation=ftCreation; p.tCpu=Time((ftKernel+ftUser)/10000); arPinfo.push_back(p); } CloseHandle(hProcess); } } } delete [] arPids; } } } } break; case VER_PLATFORM_WIN32_WINDOWS: if( hInstLib1) { static HANDLE (WINAPI *lpfCreateToolhelp32Snapshot)(DWORD,DWORD)= (HANDLE(WINAPI *)(DWORD,DWORD))GetProcAddress( hInstLib1,"CreateToolhelp32Snapshot" ) ; static BOOL (WINAPI *lpfProcess32First)(HANDLE,LPPROCESSENTRY32)= (BOOL(WINAPI *)(HANDLE,LPPROCESSENTRY32))GetProcAddress( hInstLib1, "Process32First" ) ; static BOOL (WINAPI *lpfProcess32Next)(HANDLE,LPPROCESSENTRY32)= (BOOL(WINAPI *)(HANDLE,LPPROCESSENTRY32))GetProcAddress( hInstLib1, "Process32Next" ) ; if( lpfProcess32Next && lpfProcess32First && lpfCreateToolhelp32Snapshot) { // Get a handle to a Toolhelp snapshot of the systems // processes. HANDLE hSnapShot = lpfCreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0) ; if(INVALID_HANDLE_VALUE != hSnapShot) { // Get the first process' information. PROCESSENTRY32 procentry; procentry.dwSize = sizeof(PROCESSENTRY32) ; if(lpfProcess32First( hSnapShot, &procentry )){ rc=true; do { PInfo p; p.PID=procentry.th32ProcessID; p.PPID=procentry.th32ParentProcessID; arPinfo.push_back(p); } while(lpfProcess32Next( hSnapShot, &procentry )); } CloseHandle(hSnapShot); } } } break; default: break; } SetParents(arPinfo); if(!rc){ ERROR(_T("Couldn't get process information!\n")); } return rc; } #else // UNIX bool CSubprocess::PSExtract(CSubprocess::PInfoArray &arPinfo) { arPinfo.clear(); int i; FILE *f=popen("ps -l",_T("r") MODE_TEXT); if(f){ char buf[100]; while(fgets(buf,sizeof(buf)-1,f)){ TCHAR discard[100]; PInfo p; // Output is in the form // F S UID PID PPID C PRI NI ADDR SZ WCHAN TTY TIME CMD //100 S 490 877 876 0 70 0 - 368 wait4 pts/0 00:00:00 bash int F,UID,C,PRI,NI,SZ,HH,MM,SS; bool rc=(15==_stscanf(buf,_T("%d %s %d %d %d %d %d %d %s %d %s %s %d:%d:%d"),&F,discard,&UID,&p.PID,&p.PPID,&C,&PRI,&NI,discard,&SZ,discard,discard,&HH,&MM,&SS)); if(rc){ p.tCpu=1000*(SS+60*(60*HH+MM)); arPinfo.push_back(p); } } pclose(f); for(i=0;i<(signed)arPinfo.size();i++){ int pid=arPinfo[i].PPID; arPinfo[i].pParent=0; for(int j=0;j<(signed)arPinfo.size();j++){ if(i!=j && arPinfo[j].PID==pid){ arPinfo[i].pParent=&arPinfo[j]; break; } } } } else { ERROR(_T("Failed to run ps -l\n")); } return true; //FIXME } #endif void CSubprocess::SetParents(CSubprocess::PInfoArray &arPinfo) { int i; for(i=0;i<(signed)arPinfo.size();i++){ PInfo &p=arPinfo[i]; p.pParent=0; for(int j=0;j<(signed)arPinfo.size();j++){ if(arPinfo[j].PID==p.PPID #ifdef _WIN32 && arPinfo[j].tCreation<p.tCreation #endif ) { arPinfo[i].pParent=&arPinfo[j]; break; } } } // Check for circularity bool bCircularity=false; for(i=0;i<(signed)arPinfo.size();i++){ PInfo *p=&arPinfo[i]; for(int j=0;j<(signed)arPinfo.size() && p;j++){ p=p->pParent; } // If all is well, p should be NULL here. Otherwise we have a loop. if(p){ // Make sure it can't foul things up: arPinfo[i].pParent=0; bCircularity=true; } } if(bCircularity){ ERROR(_T("!!! Circularly linked process list at index %d\n"),i); for(int k=0;k<(signed)arPinfo.size();k++){ const PInfo &p=arPinfo[k]; ERROR(_T("%d: %s ppid=%4d\n"),k,(LPCTSTR)Name(p.PID),p.PPID); } } } bool CSubprocess::PInfo::IsChildOf(int pid) const { for(PInfo *p=pParent;p && p!=this;p=p->pParent) { // guard against circular linkage if(p->PID==pid){ return true; } } return false; } const String CSubprocess::Name(int pid) { String str(String::SFormat(_T("id=%d"),pid)); #ifdef _DEBUG #ifdef _WIN32 if(VER_PLATFORM_WIN32_NT==GetPlatform() && hInstLib1){ static BOOL (WINAPI *lpfEnumProcessModules)( HANDLE, HMODULE *, DWORD, LPDWORD ) = (BOOL(WINAPI *)(HANDLE, HMODULE *, DWORD, LPDWORD)) GetProcAddress( hInstLib1,"EnumProcessModules" ) ; static DWORD (WINAPI *lpfGetModuleFileNameEx)( HANDLE, HMODULE, LPTSTR, DWORD )= (DWORD (WINAPI *)(HANDLE, HMODULE,LPTSTR, DWORD )) GetProcAddress( hInstLib1,"GetModuleFileNameExA" ) ; if( lpfEnumProcessModules && lpfGetModuleFileNameEx ) { HANDLE hProcess=::OpenProcess(PROCESS_ALL_ACCESS,false,pid); if(hProcess) { HMODULE hMod; DWORD dwSize; if(lpfEnumProcessModules( hProcess, &hMod, sizeof(HMODULE), &dwSize ) ){ // Get Full pathname: TCHAR buf[1+MAX_PATH]; lpfGetModuleFileNameEx( hProcess, hMod, buf, MAX_PATH); str+=_TCHAR(' '); str+=buf; } CloseHandle(hProcess); } } } #endif #endif return str; } #ifdef _WIN32 DWORD CSubprocess::GetPlatform() { OSVERSIONINFO osver; osver.dwOSVersionInfoSize = sizeof( osver ) ; return GetVersionEx( &osver ) ? osver.dwPlatformId : (DWORD)-1; } #endif bool CSubprocess::ProcessAlive() { return !m_bThreadTerminated; } void CSubprocess::CloseInput() { #ifdef _WIN32 CloseHandle(m_hwPipe);m_hwPipe=INVALID_HANDLE_VALUE; #else close(m_tty); #endif } bool CSubprocess::Wait(Duration dTimeout) { return CeCosThreadUtils::WaitFor(m_bThreadTerminated,dTimeout); } const String CSubprocess::ErrorString() const { #ifdef _WIN32 TCHAR *pszMsg; FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, NULL, m_nErr, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language (LPTSTR)&pszMsg, 0, NULL ); return pszMsg; #else return strerror(errno); #endif }