📄 vk_process.cpp
字号:
#if defined(VK_PROCESS_DEBUG) qDebug( "VKProcessManager: install a SIGPIPE handler (SIG_IGN)" );#endif act.sa_handler = QT_SIGNAL_IGNORE; sigemptyset( &(act.sa_mask) ); sigaddset( &(act.sa_mask), SIGPIPE ); act.sa_flags = 0; if ( sigaction( SIGPIPE, &act, &oldactPipe ) != 0 ) qWarning( "Error installing SIGPIPE handler" ); } VKProcessManager::~VKProcessManager() { delete procList; if ( sigchldFd[0] != 0 ) ::close( sigchldFd[0] ); if ( sigchldFd[1] != 0 ) ::close( sigchldFd[1] ); // restore SIGCHLD handler#if defined(VK_PROCESS_DEBUG) qDebug( "VKProcessManager: restore old sigchild handler" );#endif if ( sigaction( SIGCHLD, &oldactChld, 0 ) != 0 ) qWarning( "Error restoring SIGCHLD handler" );#if defined(VK_PROCESS_DEBUG) qDebug( "VKProcessManager: restore old sigpipe handler" );#endif if ( sigaction( SIGPIPE, &oldactPipe, 0 ) != 0 ) qWarning( "Error restoring SIGPIPE handler" ); } void VKProcessManager::append( VKProc *p ) { procList->append( p );#if defined(VK_PROCESS_DEBUG) qDebug( "VKProcessManager: append process (procList.count(): %d)", procList->count() );#endif } void VKProcessManager::remove( VKProc *p ) { procList->remove( p );#if defined(VK_PROCESS_DEBUG) qDebug( "VKProcessManager: remove process (procList.count(): %d)", procList->count() );#endif cleanup(); } void VKProcessManager::cleanup() { if ( procList->count() == 0 ) { QTimer::singleShot( 0, this, SLOT(removeMe()) ); } } void VKProcessManager::removeMe() { if ( procList->count() == 0 ) { qRemovePostRoutine(vkprocess_cleanup); VKProcessPrivate::procManager = 0; delete this; } } void VKProcessManager::sigchldHnd( int fd ) { /* Disable the socket notifier to make sure that this function is not called recursively -- this can happen, if you enter the event loop in the slot connected to the processExited() signal (e.g. by showing a modal dialog) and there are more than one process which exited in the meantime. */ if ( sn ) { if ( !sn->isEnabled() ) return; sn->setEnabled( false ); } char tmp; ::read( fd, &tmp, sizeof(tmp) );#if defined(VK_PROCESS_DEBUG) qDebug( "VKProcessManager::sigchldHnd()" );#endif VKProc *proc; VKProcess *process; bool removeProc; proc = procList->first(); while ( proc != 0 ) { removeProc = false; process = proc->process; if ( process != 0 ) { if ( !process->isRunning() ) {#if defined(VK_PROCESS_DEBUG) qDebug( "VKProcessManager::sigchldHnd() (PID: %d): process exited (VKProcess available)", proc->pid );#endif /* Apparently, there is not consistency among different operating systems on how to use FIONREAD. FreeBSD, Linux and Solaris all expect the 3rd argument to ioctl() to be an int, which is normally 32-bit even on 64-bit machines. IRIX, on the other hand, expects a size_t, which is 64-bit on 64-bit machines. So, the solution is to use size_t initialized to zero to make sure all bits are set to zero, preventing underflow with the FreeBSD/Linux/Solaris ioctls. */ size_t nbytes = 0; // read pending data if ( proc->socketFDout && ::ioctl(proc->socketFDout, FIONREAD, (char*)&nbytes)==0 && nbytes>0 ) {#if defined(VK_PROCESS_DEBUG) qDebug( "VKProcessManager::sigchldHnd() (PID: %d): reading %d bytes of pending data on FDout(%d)", proc->pid, nbytes, process->getFDout() );#endif process->socketRead( proc->socketFDout ); } nbytes = 0; if ( proc->socketStdout && ::ioctl(proc->socketStdout, FIONREAD, (char*)&nbytes)==0 && nbytes>0 ) {#if defined(VK_PROCESS_DEBUG) qDebug( "VKProcessManager::sigchldHnd() (PID: %d): reading %d bytes of pending data on stdout", proc->pid, nbytes );#endif process->socketRead( proc->socketStdout ); } nbytes = 0; if ( proc->socketStderr && ::ioctl(proc->socketStderr, FIONREAD, (char*)&nbytes)==0 && nbytes>0 ) {#if defined(VK_PROCESS_DEBUG) qDebug( "VKProcessManager::sigchldHnd() (PID: %d): reading %d bytes of pending data on stderr", proc->pid, nbytes );#endif process->socketRead( proc->socketStderr ); } /* close filedescriptors if open, and disable the socket notifiers */ if ( proc->socketFDout ) { ::close( proc->socketFDout ); proc->socketFDout = 0; if (process->d->notifierFDout) process->d->notifierFDout->setEnabled(false); } if ( proc->socketStdout ) { ::close( proc->socketStdout ); proc->socketStdout = 0; if (process->d->notifierStdout) process->d->notifierStdout->setEnabled(false); } if ( proc->socketStderr ) { ::close( proc->socketStderr ); proc->socketStderr = 0; if (process->d->notifierStderr) process->d->notifierStderr->setEnabled(false); } if ( process->notifyOnExit ) emit process->processExited(); removeProc = true; } } else { int status; if ( ::waitpid( proc->pid, &status, WNOHANG ) == proc->pid ) {#if defined(VK_PROCESS_DEBUG) qDebug( "VKProcessManager::sigchldHnd() (PID: %d): process exited (VKProcess not available)", proc->pid );#endif removeProc = true; } } if ( removeProc ) { VKProc *oldproc = proc; proc = procList->next(); remove( oldproc ); } else { proc = procList->next(); } } if ( sn ) sn->setEnabled( true ); } /* class VKProcessPrivate ---------------------------------------------------- */ VKProcessManager *VKProcessPrivate::procManager = 0; VKProcessPrivate::VKProcessPrivate() {#if defined(VK_PROCESS_DEBUG) qDebug( "VKProcessPrivate: Constructor" );#endif fdinBufRead = 0; stdinBufRead = 0; notifierFDin = 0; notifierFDout = 0; notifierStdin = 0; notifierStdout = 0; notifierStderr = 0; exitValuesCalculated = false; socketReadCalled = false; proc = 0; } VKProcessPrivate::~VKProcessPrivate() {#if defined(VK_PROCESS_DEBUG) qDebug( "VKProcessPrivate: Destructor" );#endif if ( proc != 0 ) { if ( proc->socketFDin != 0 ) { ::close( proc->socketFDin ); proc->socketFDin = 0; } if ( proc->socketStdin != 0 ) { ::close( proc->socketStdin ); proc->socketStdin = 0; } proc->process = 0; } while ( !fdinBuf.isEmpty() ) { delete fdinBuf.dequeue(); } while ( !stdinBuf.isEmpty() ) { delete stdinBuf.dequeue(); } if (notifierFDin) { delete notifierFDin; notifierFDin = 0; } if (notifierStdin) { delete notifierStdin; notifierStdin = 0; } if (notifierFDout) { delete notifierFDout; notifierFDout = 0; } if (notifierStdout) { delete notifierStdout; notifierStdout = 0; } if (notifierStderr) { delete notifierStderr; notifierStderr = 0; } } /* Closes all open sockets in the child process that are not needed by the child process. Otherwise one child may have an open socket on standard input, etc. of another child. */ void VKProcessPrivate::closeOpenSocketsForChild() { if ( procManager != 0 ) { if ( procManager->sigchldFd[0] != 0 ) ::close( procManager->sigchldFd[0] ); if ( procManager->sigchldFd[1] != 0 ) ::close( procManager->sigchldFd[1] ); // close also the sockets from other VKProcess instances for ( VKProc *p=procManager->procList->first(); p!=0; p=procManager->procList->next() ) { ::close( p->socketFDin ); ::close( p->socketStdin ); ::close( p->socketFDout ); ::close( p->socketStdout ); ::close( p->socketStderr ); } } } void VKProcessPrivate::newProc( pid_t pid, VKProcess *process ) { proc = new VKProc( pid, process ); if ( procManager == 0 ) { procManager = new VKProcessManager; qAddPostRoutine(vkprocess_cleanup); } // the VKProcessManager takes care of deleting the VKProc instances procManager->append( proc ); } /* class VKProcess ----------------------------------------------------------- Constructs a VKProcess object. The parent and name parameters are passed to the QObject constructor. */ VKProcess::VKProcess( QObject* parent, const char* name ) : QObject( parent, name ), ioRedirection( false ), notifyOnExit( false ), wroteToFDinConnected( false ), wroteToStdinConnected( false ), readFDoutCalled( false ), readStdoutCalled( false ), readStderrCalled( false ), comms( Stdin|Stdout|Stderr ), filedesc_in( 0 ), filedesc_out( 1 ), disabledStdin( false ), disabledStdout( false ), disabledStderr( false ) { init(); } /* Constructs a VKProcess with arg0 as the command to be executed. The parent and name parameters are passed to the QObject constructor. The process is not started. You must call start() or launch() to start the process. */ VKProcess::VKProcess( const QString& arg0, QObject *parent, const char *name ) : QObject( parent, name ), ioRedirection( false ), notifyOnExit( false ), wroteToFDinConnected( false ), wroteToStdinConnected( false ), readFDoutCalled( false ), readStdoutCalled( false ), readStderrCalled( false ), comms( Stdin|Stdout|Stderr ), filedesc_in( 0 ), filedesc_out( 1 ), disabledStdin( false ), disabledStdout( false ), disabledStderr( false ) { init(); addArgument( arg0 ); } /* Constructs a VKProcess with args as the arguments of the process. The first element in the list is the command to be executed. The other elements in the list are the arguments to this command. The parent and name parameters are passed to the QObject constructor. The process is not started. You must call start() or launch() to start the process. */ VKProcess::VKProcess( const QStringList& args, QObject *parent, const char *name ) : QObject( parent, name ), ioRedirection( false ), notifyOnExit( false ), wroteToFDinConnected( false ), wroteToStdinConnected( false ), readFDoutCalled( false ), readStdoutCalled( false ), readStderrCalled( false ), comms( Stdin|Stdout|Stderr ), filedesc_in( 0 ), filedesc_out( 1 ), disabledStdin( false ), disabledStdout( false ), disabledStderr( false ) { init(); setArguments( args ); } /* This private class does basic initialization. */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -