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

📄 subprocess.cpp

📁 移植到WLIT项目的redboot源代码
💻 CPP
📖 第 1 页 / 共 2 页
字号:
//####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 _WIN32bool 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;    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;    } else {      CeCosThreadUtils::Sleep(250);    }  }  DWORD dwExitCode;  ::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 // UNIXbool 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;          }

⌨️ 快捷键说明

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