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

📄 q3process_unix.cpp

📁 奇趣公司比较新的qt/emd版本
💻 CPP
📖 第 1 页 / 共 3 页
字号:
/******************************************************************************** Copyright (C) 1992-2007 Trolltech ASA. All rights reserved.**** This file is part of the Qt3Support module of the Qt Toolkit.**** This file may be used under the terms of the GNU General Public** License version 2.0 as published by the Free Software Foundation** and appearing in the file LICENSE.GPL included in the packaging of** this file.  Please review the following information to ensure GNU** General Public Licensing requirements will be met:** http://trolltech.com/products/qt/licenses/licensing/opensource/**** If you are unsure which license is appropriate for your use, please** review the following information:** http://trolltech.com/products/qt/licenses/licensing/licensingoverview** or contact the sales department at sales@trolltech.com.**** In addition, as a special exception, Trolltech gives you certain** additional rights. These rights are described in the Trolltech GPL** Exception version 1.0, which can be found at** http://www.trolltech.com/products/qt/gplexception/ and in the file** GPL_EXCEPTION.txt in this package.**** In addition, as a special exception, Trolltech, as the sole copyright** holder for Qt Designer, grants users of the Qt/Eclipse Integration** plug-in the right for the Qt/Eclipse Integration to link to** functionality provided by Qt Designer and its related libraries.**** Trolltech reserves all rights not expressly granted herein.**** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.******************************************************************************/#include "qplatformdefs.h"// Solaris redefines connect -> __xnet_connect with _XOPEN_SOURCE_EXTENDED.#if defined(connect)#undef connect#endif#include "q3process.h"#ifndef QT_NO_PROCESS#include "qapplication.h"#include "q3cstring.h"#include "q3ptrqueue.h"#include "q3ptrlist.h"#include "qsocketnotifier.h"#include "qtimer.h"#include "q3cleanuphandler.h"#include "qregexp.h"#include "private/q3membuf_p.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//#define QT_Q3PROCESS_DEBUG#ifdef Q_C_CALLBACKSextern "C" {#endif // Q_C_CALLBACKS    static QT_SIGNAL_RETTYPE qt_C_sigchldHnd(QT_SIGNAL_ARGS);#ifdef Q_C_CALLBACKS}#endif // Q_C_CALLBACKSclass QProc;class Q3ProcessManager;class Q3ProcessPrivate{public:    Q3ProcessPrivate();    ~Q3ProcessPrivate();    void closeOpenSocketsForChild();    void newProc( pid_t pid, Q3Process *process );    Q3Membuf bufStdout;    Q3Membuf bufStderr;    Q3PtrQueue<QByteArray> stdinBuf;    QSocketNotifier *notifierStdin;    QSocketNotifier *notifierStdout;    QSocketNotifier *notifierStderr;    ssize_t stdinBufRead;    QProc *proc;    bool exitValuesCalculated;    bool socketReadCalled;    static Q3ProcessManager *procManager;};/*********************************************************************** * * QProc * **********************************************************************//*  The class Q3Process does not necessarily map exactly to the running  child processes: if the process is finished, the Q3Process class may still be  there; furthermore a user can use Q3Process to start more than one process.  The helper-class QProc has the semantics that one instance of this class maps  directly to a running child process.*/class QProc{public:    QProc( pid_t p, Q3Process *proc=0 ) : pid(p), process(proc)    {#if defined(QT_Q3PROCESS_DEBUG)	qDebug( "QProc: Constructor for pid %d and Q3Process %p", pid, process );#endif	socketStdin = 0;	socketStdout = 0;	socketStderr = 0;    }    ~QProc()    {#if defined(QT_Q3PROCESS_DEBUG)	qDebug( "QProc: Destructor for pid %d and Q3Process %p", pid, process );#endif	if ( process ) {	    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( socketStdin )	    ::close( socketStdin );	if( socketStdout )	    ::close( socketStdout );	if( socketStderr )	    ::close( socketStderr );    }    pid_t pid;    int socketStdin;    int socketStdout;    int socketStderr;    Q3Process *process;};/*********************************************************************** * * Q3ProcessManager * **********************************************************************/class Q3ProcessManager : public QObject{    Q_OBJECTpublic:    Q3ProcessManager();    ~Q3ProcessManager();    void append( QProc *p );    void remove( QProc *p );    void cleanup();public slots:    void removeMe();    void sigchldHnd( int );public:    struct sigaction oldactChld;    struct sigaction oldactPipe;    Q3PtrList<QProc> *procList;    int sigchldFd[2];private:    QSocketNotifier *sn;};static void q3process_cleanup(){    delete Q3ProcessPrivate::procManager;    Q3ProcessPrivate::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#endifQ3ProcessManager::Q3ProcessManager() : sn(0){    procList = new Q3PtrList<QProc>;    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(QT_Q3PROCESS_DEBUG)	qDebug( "Q3ProcessManager: 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(QT_Q3PROCESS_DEBUG)    qDebug( "Q3ProcessManager: 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" );#if defined(QT_Q3PROCESS_DEBUG)    qDebug( "Q3ProcessManager: 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" );}Q3ProcessManager::~Q3ProcessManager(){    delete procList;    if ( sigchldFd[0] != 0 )	::close( sigchldFd[0] );    if ( sigchldFd[1] != 0 )	::close( sigchldFd[1] );    // restore SIGCHLD handler#if defined(QT_Q3PROCESS_DEBUG)    qDebug( "Q3ProcessManager: restore old sigchild handler" );#endif    if ( sigaction( SIGCHLD, &oldactChld, 0 ) != 0 )	qWarning( "Error restoring SIGCHLD handler" );#if defined(QT_Q3PROCESS_DEBUG)    qDebug( "Q3ProcessManager: restore old sigpipe handler" );#endif    if ( sigaction( SIGPIPE, &oldactPipe, 0 ) != 0 )	qWarning( "Error restoring SIGPIPE handler" );}void Q3ProcessManager::append( QProc *p ){    procList->append( p );#if defined(QT_Q3PROCESS_DEBUG)    qDebug( "Q3ProcessManager: append process (procList.count(): %d)", procList->count() );#endif}void Q3ProcessManager::remove( QProc *p ){    procList->remove( p );#if defined(QT_Q3PROCESS_DEBUG)    qDebug( "Q3ProcessManager: remove process (procList.count(): %d)", procList->count() );#endif    cleanup();}void Q3ProcessManager::cleanup(){    if ( procList->count() == 0 ) {	QTimer::singleShot( 0, this, SLOT(removeMe()) );    }}void Q3ProcessManager::removeMe(){    if ( procList->count() == 0 ) {	qRemovePostRoutine(q3process_cleanup);	Q3ProcessPrivate::procManager = 0;	delete this;    }}void Q3ProcessManager::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(QT_Q3PROCESS_DEBUG)    qDebug( "Q3ProcessManager::sigchldHnd()" );#endif    QProc *proc;    Q3Process *process;    bool removeProc;    proc = procList->first();    while ( proc != 0 ) {	removeProc = false;	process = proc->process;	if ( process != 0 ) {	    if ( !process->isRunning() ) {#if defined(QT_Q3PROCESS_DEBUG)		qDebug( "Q3ProcessManager::sigchldHnd() (PID: %d): process exited (Q3Process 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->socketStdout && ::ioctl(proc->socketStdout, FIONREAD, (char*)&nbytes)==0 && nbytes>0 ) {#if defined(QT_Q3PROCESS_DEBUG)		    qDebug( "Q3ProcessManager::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(QT_Q3PROCESS_DEBUG)		    qDebug( "Q3ProcessManager::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->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(QT_Q3PROCESS_DEBUG)		qDebug( "Q3ProcessManager::sigchldHnd() (PID: %d): process exited (Q3Process not available)", proc->pid );#endif		removeProc = true;	    }	}	if ( removeProc ) {	    QProc *oldproc = proc;	    proc = procList->next();	    remove( oldproc );	} else {	    proc = procList->next();	}    }    if ( sn )	sn->setEnabled( true );}#include "q3process_unix.moc"

⌨️ 快捷键说明

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