📄 vk_process.cpp
字号:
/* ---------------------------------------------------------------------- * Implementation of class VKProcess vk_process.h * --------------------------------------------------------------------- * This file is part of Valkyrie, a front-end for Valgrind * Copyright (c) 2005-2006, OpenWorks LLP <info@open-works.co.uk> * This program is released under the terms of the GNU GPL v.2 * See the file LICENSE.GPL for the full license details. * --------------------------------------------------------------------- * This file is a re-implementation of QProcess: * ** ($Id: qt/qprocess_unix.cpp 3.3.4 edited Dec 23 11:57 $) * ** Created : 20000905 * ** * ** Copyright (C) 1992-2003 Trolltech AS. All rights reserved. * ** * ** This file may be distributed and/or modified under the terms of the * ** GNU General Public License version 2 as published by the Free Software * ** Foundation and appearing in the file LICENSE.GPL included in the * ** packaging of this file. */#include <qplatformdefs.h>// Solaris redefines connect -> __xnet_connect with _XOPEN_SOURCE_EXTENDED.#if defined(connect)#undef connect#endif#include "vk_process.h"#include "vk_utils.h"#include <qapplication.h>#include <qptrlist.h>#include <qtimer.h>#include <qcleanuphandler.h>#include <qregexp.h>#include <stdlib.h>#include <errno.h>#include <sys/types.h>#ifdef __MIPSEL__# ifndef SOCK_DGRAM# define SOCK_DGRAM 1# endif# ifndef SOCK_STREAM# define SOCK_STREAM 2# endif#endif#ifdef Q_C_CALLBACKSextern "C" {#endif // Q_C_CALLBACKSQT_SIGNAL_RETTYPE qt_C_sigchldHnd(QT_SIGNAL_ARGS);#ifdef Q_C_CALLBACKS}#endif // Q_C_CALLBACKS//#define VK_PROCESS_DEBUG/* class VKMembuf - Reimplementation of QMembuf, from qt/kernel/qinternal_p.h*//* This class implements an efficient buffering of data that is often used by asynchronous IO classes like QSocket, QHttp and QProcess. */VKMembuf::VKMembuf() : _size(0), _index(0){ buf = new QPtrList<QByteArray>; buf->setAutoDelete( true );}VKMembuf::~VKMembuf(){ delete buf; }/* This function consumes nbytes bytes of data from the buffer and copies it into sink. If sink is a 0 pointer the data goes into the nirvana. */bool VKMembuf::consumeBytes( Q_ULONG nbytes, char *sink ){ if ( nbytes <= 0 || nbytes > _size ) return false; _size -= nbytes; for ( ;; ) { QByteArray *a = buf->first(); if ( _index + nbytes >= a->size() ) { // Here we skip the whole byte array and get the next later int len = a->size() - _index; if ( sink ) { memcpy( sink, a->data()+_index, len ); sink += len; } nbytes -= len; buf->remove(); _index = 0; if ( nbytes == 0 ) break; } else { // Here we skip only a part of the first byte array if ( sink ) memcpy( sink, a->data()+_index, nbytes ); _index += nbytes; break; } } return true;}/* Scans for any occurrence of '\n' in the buffer. If store is not 0 the text up to the first '\n' (or terminating 0) is written to store, and a terminating 0 is appended to store if necessary. Returns true if a '\n' was found; otherwise returns false. */bool VKMembuf::scanNewline( QByteArray *store ){ if ( _size == 0 ) return false; int i = 0; // index into 'store' QByteArray *a = 0; char *p; int n; for ( ;; ) { if ( !a ) { a = buf->first(); if ( !a || a->size() == 0 ) return false; p = a->data() + _index; n = a->size() - _index; } else { a = buf->next(); if ( !a || a->size() == 0 ) return false; p = a->data(); n = a->size(); } if ( store ) { while ( n-- > 0 ) { *(store->data()+i) = *p; if ( ++i == (int)store->size() ) store->resize( (store->size() < 256) ? (1024) : (store->size()*4) ); switch ( *p ) { case '\0': store->resize( i ); return false; case '\n': *(store->data()+i) = '\0'; store->resize( i ); return true; } p++; } } else { while ( n-- > 0 ) { switch ( *p++ ) { case '\0': return false; case '\n': return true; } } } }}int VKMembuf::ungetch( int ch ){ if ( buf->isEmpty() || _index==0 ) { // we need a new QByteArray QByteArray *ba = new QByteArray( 1 ); buf->insert( 0, ba ); _size++; ba->at( 0 ) = ch; } else { // we can reuse a place in the buffer QByteArray *ba = buf->first(); _index--; _size++; ba->at( _index ) = ch; } return ch;}/* class VKProc -------------------------------------------------------------- */VKProc::VKProc( pid_t p, VKProcess *proc/*=0*/ ) : pid(p), process(proc){#if defined(VK_PROCESS_DEBUG) qDebug( "VKProc: Constructor for pid %d and VKProcess %p", pid, process );#endif socketFDin = 0; socketFDout = 0; socketStdin = 0; socketStdout = 0; socketStderr = 0;}VKProc::~VKProc(){#if defined(VK_PROCESS_DEBUG) qDebug( "VKProc: Destructor for pid %d and VKProcess %p", pid, process );#endif if ( process ) { if ( process->d->notifierFDin ) process->d->notifierFDin->setEnabled( false ); if ( process->d->notifierFDout ) process->d->notifierFDout->setEnabled( false ); if ( process->d->notifierStdin ) process->d->notifierStdin->setEnabled( false ); if ( process->d->notifierStdout ) process->d->notifierStdout->setEnabled( false ); if ( process->d->notifierStderr ) process->d->notifierStderr->setEnabled( false ); process->d->proc = 0; } if ( socketFDin ) ::close( socketFDin ); if ( socketFDout ) ::close( socketFDout ); if ( socketStdin ) ::close( socketStdin ); if ( socketStdout ) ::close( socketStdout ); if ( socketStderr ) ::close( socketStderr );}/*---------------------------------------------------------------------------- * Helper functions ----------------------------------------------------------------------------- */static void vkprocess_cleanup(){ delete VKProcessPrivate::procManager; VKProcessPrivate::procManager = 0;}#ifdef Q_OS_QNX6#define BAILOUT close(tmpSocket);close(socketFD[1]);return -1;int qnx6SocketPairReplacement (int socketFD[2]) { int tmpSocket; tmpSocket = socket (AF_INET, SOCK_STREAM, 0); if (tmpSocket == -1) return -1; socketFD[1] = socket(AF_INET, SOCK_STREAM, 0); if (socketFD[1] == -1) { BAILOUT }; sockaddr_in ipAddr; memset(&ipAddr, 0, sizeof(ipAddr)); ipAddr.sin_family = AF_INET; ipAddr.sin_addr.s_addr = INADDR_ANY; int socketOptions = 1; setsockopt(tmpSocket, SOL_SOCKET, SO_REUSEADDR, &socketOptions, sizeof(int)); bool found = false; for (int socketIP = 2000; (socketIP < 2500) && !(found); socketIP++) { ipAddr.sin_port = htons(socketIP); if (bind(tmpSocket, (struct sockaddr *)&ipAddr, sizeof(ipAddr))) found = true; } if (listen(tmpSocket, 5)) { BAILOUT }; // Select non-blocking mode int originalFlags = fcntl(socketFD[1], F_GETFL, 0); fcntl(socketFD[1], F_SETFL, originalFlags | O_NONBLOCK); // Request connection if (connect(socketFD[1], (struct sockaddr*)&ipAddr, sizeof(ipAddr))) if (errno != EINPROGRESS) { BAILOUT }; // Accept connection socketFD[0] = accept(tmpSocket, (struct sockaddr *)NULL, (size_t *)NULL); if (socketFD[0] == -1) { BAILOUT }; // We're done close(tmpSocket); // Restore original flags , ie return to blocking fcntl(socketFD[1], F_SETFL, originalFlags); return 0;}#undef BAILOUT#endif/* sigchld handler callback */QT_SIGNAL_RETTYPE qt_C_sigchldHnd( QT_SIGNAL_ARGS ){ if ( VKProcessPrivate::procManager == 0 ) return; if ( VKProcessPrivate::procManager->sigchldFd[0] == 0 ) return; char a = 1; ::write( VKProcessPrivate::procManager->sigchldFd[0], &a, sizeof(a) );}/* class VKProcessManager ---------------------------------------------------- */VKProcessManager::VKProcessManager() : sn(0){ procList = new QPtrList<VKProc>; procList->setAutoDelete( true ); /* The SIGCHLD handler writes to a socket to tell the manager that something happened. This is done to get the processing in sync with the event reporting. */#ifndef Q_OS_QNX6 if ( ::socketpair( AF_UNIX, SOCK_STREAM, 0, sigchldFd ) ) {#else if ( qnx6SocketPairReplacement (sigchldFd) ) {#endif sigchldFd[0] = 0; sigchldFd[1] = 0; } else {#if defined(VK_PROCESS_DEBUG) qDebug( "VKProcessManager: install socket notifier (%d)", sigchldFd[1] );#endif sn = new QSocketNotifier( sigchldFd[1], QSocketNotifier::Read, this ); connect( sn, SIGNAL(activated(int)), this, SLOT(sigchldHnd(int)) ); sn->setEnabled( true ); } // install a SIGCHLD handler and ignore SIGPIPE struct sigaction act;#if defined(VK_PROCESS_DEBUG) qDebug( "VKProcessManager: install a SIGCHLD handler" );#endif act.sa_handler = qt_C_sigchldHnd; sigemptyset( &(act.sa_mask) ); sigaddset( &(act.sa_mask), SIGCHLD ); act.sa_flags = SA_NOCLDSTOP;#if defined(SA_RESTART) act.sa_flags |= SA_RESTART;#endif if ( sigaction( SIGCHLD, &act, &oldactChld ) != 0 ) qWarning( "Error installing SIGCHLD handler" );
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -