?? qprocess_unix.cpp
字號(hào):
if (&channel == &stdinChannel) { channel.notifier = new QSocketNotifier(channel.pipe[1], QSocketNotifier::Write, q); channel.notifier->setEnabled(false); QObject::connect(channel.notifier, SIGNAL(activated(int)), q, SLOT(_q_canWrite())); } else { channel.notifier = new QSocketNotifier(channel.pipe[0], QSocketNotifier::Read, q); const char *receiver; if (&channel == &stdoutChannel) receiver = SLOT(_q_canReadStandardOutput()); else receiver = SLOT(_q_canReadStandardError()); QObject::connect(channel.notifier, SIGNAL(activated(int)), q, receiver); } } return true; } else if (channel.type == Channel::Redirect) { // we're redirecting the channel to/from a file QByteArray fname = QFile::encodeName(channel.file); if (&channel == &stdinChannel) { // try to open in read-only mode channel.pipe[1] = -1; if ( (channel.pipe[0] = open(fname, O_RDONLY)) != -1) return true; // success q->setErrorString(QLatin1String(QT_TRANSLATE_NOOP(QProcess, "Could not open input redirection for reading"))); } else { int mode = O_WRONLY | O_CREAT; if (channel.append) mode |= O_APPEND; else mode |= O_TRUNC; channel.pipe[0] = -1; if ( (channel.pipe[1] = open(fname, mode, 0666)) != -1) return true; // success q->setErrorString(QLatin1String(QT_TRANSLATE_NOOP(QProcess, "Could not open output redirection for writing"))); } // could not open file processError = QProcess::FailedToStart; emit q->error(processError); cleanup(); return false; } else { Q_ASSERT_X(channel.process, "QProcess::start", "Internal error"); Channel *source; Channel *sink; if (channel.type == Channel::PipeSource) { // we are the source source = &channel; sink = &channel.process->stdinChannel; Q_ASSERT(source == &stdoutChannel); Q_ASSERT(sink->process == this && sink->type == Channel::PipeSink); } else { // we are the sink; source = &channel.process->stdoutChannel; sink = &channel; Q_ASSERT(sink == &stdinChannel); Q_ASSERT(source->process == this && source->type == Channel::PipeSource); } if (source->pipe[1] != INVALID_Q_PIPE || sink->pipe[0] != INVALID_Q_PIPE) { // already created, do nothing return true; } else { Q_ASSERT(source->pipe[0] == INVALID_Q_PIPE && source->pipe[1] == INVALID_Q_PIPE); Q_ASSERT(sink->pipe[0] == INVALID_Q_PIPE && sink->pipe[1] == INVALID_Q_PIPE); Q_PIPE pipe[2] = { -1, -1 }; qt_create_pipe(pipe); sink->pipe[0] = pipe[0]; source->pipe[1] = pipe[1]; return true; } }}void QProcessPrivate::startProcess(){ Q_Q(QProcess);#if defined (QPROCESS_DEBUG) qDebug("QProcessPrivate::startProcess()");#endif processManager()->start(); // Initialize pipes qt_create_pipe(childStartedPipe); if (threadData->eventDispatcher) { startupSocketNotifier = new QSocketNotifier(childStartedPipe[0], QSocketNotifier::Read, q); QObject::connect(startupSocketNotifier, SIGNAL(activated(int)), q, SLOT(_q_startupNotification())); } qt_create_pipe(deathPipe); ::fcntl(deathPipe[0], F_SETFD, FD_CLOEXEC); ::fcntl(deathPipe[1], F_SETFD, FD_CLOEXEC); if (threadData->eventDispatcher) { deathNotifier = new QSocketNotifier(deathPipe[0], QSocketNotifier::Read, q); QObject::connect(deathNotifier, SIGNAL(activated(int)), q, SLOT(_q_processDied())); } if (!createChannel(stdinChannel) || !createChannel(stdoutChannel) || !createChannel(stderrChannel)) return; // Start the process (platform dependent) processState = QProcess::Starting; emit q->stateChanged(processState); QByteArray encodedProg = QFile::encodeName(program); processManager()->lock(); pid_t childPid = fork(); if (childPid < 0) { // Cleanup, report error and return processManager()->unlock(); processState = QProcess::NotRunning; emit q->stateChanged(processState); processError = QProcess::FailedToStart; q->setErrorString(QLatin1String(QT_TRANSLATE_NOOP(QProcess, "Resource error (fork failure)"))); emit q->error(processError); cleanup(); return; } if (childPid == 0) { execChild(encodedProg); ::_exit(-1); } processManager()->add(childPid, q); pid = Q_PID(childPid); processManager()->unlock(); // parent // close the ends we don't use and make all pipes non-blocking ::fcntl(deathPipe[0], F_SETFL, ::fcntl(deathPipe[0], F_GETFL) | O_NONBLOCK); qt_native_close(childStartedPipe[1]); childStartedPipe[1] = -1; if (stdinChannel.pipe[0] != -1) { qt_native_close(stdinChannel.pipe[0]); stdinChannel.pipe[0] = -1; } if (stdinChannel.pipe[1] != -1) ::fcntl(stdinChannel.pipe[1], F_SETFL, ::fcntl(stdinChannel.pipe[1], F_GETFL) | O_NONBLOCK); if (stdoutChannel.pipe[1] != -1) { qt_native_close(stdoutChannel.pipe[1]); stdoutChannel.pipe[1] = -1; } if (stdoutChannel.pipe[0] != -1) ::fcntl(stdoutChannel.pipe[0], F_SETFL, ::fcntl(stdoutChannel.pipe[0], F_GETFL) | O_NONBLOCK); if (stderrChannel.pipe[1] != -1) { qt_native_close(stderrChannel.pipe[1]); stderrChannel.pipe[1] = -1; } if (stderrChannel.pipe[0] != -1) ::fcntl(stderrChannel.pipe[0], F_SETFL, ::fcntl(stderrChannel.pipe[0], F_GETFL) | O_NONBLOCK);}void QProcessPrivate::execChild(const QByteArray &programName){ ::signal(SIGPIPE, SIG_DFL); // reset the signal that we ignored QByteArray encodedProgramName = programName; Q_Q(QProcess); // create argument list with right number of elements, and set the // final one to 0. char **argv = new char *[arguments.count() + 2]; argv[arguments.count() + 1] = 0; // allow invoking of .app bundles on the Mac.#ifdef Q_OS_MAC QFileInfo fileInfo(encodedProgramName); if (encodedProgramName.endsWith(".app") && fileInfo.isDir()) { QCFType<CFURLRef> url = CFURLCreateWithFileSystemPath(0, QCFString(fileInfo.absoluteFilePath()), kCFURLPOSIXPathStyle, true); QCFType<CFBundleRef> bundle = CFBundleCreate(0, url); url = CFBundleCopyExecutableURL(bundle); if (url) { QCFString str = CFURLCopyFileSystemPath(url, kCFURLPOSIXPathStyle); encodedProgramName += "/Contents/MacOS/" + static_cast<QString>(str).toUtf8(); } }#endif // add the program name argv[0] = ::strdup(encodedProgramName.constData()); // add every argument to the list for (int i = 0; i < arguments.count(); ++i) { QString arg = arguments.at(i);#ifdef Q_OS_MAC argv[i + 1] = ::strdup(arg.toUtf8().constData());#else argv[i + 1] = ::strdup(arg.toLocal8Bit().constData());#endif } // copy the stdin socket qt_native_dup2(stdinChannel.pipe[0], fileno(stdin)); // copy the stdout and stderr if asked to if (processChannelMode != QProcess::ForwardedChannels) { qt_native_dup2(stdoutChannel.pipe[1], fileno(stdout)); // merge stdout and stderr if asked to if (processChannelMode == QProcess::MergedChannels) { qt_native_dup2(fileno(stdout), fileno(stderr)); } else { qt_native_dup2(stderrChannel.pipe[1], fileno(stderr)); } } // make sure this fd is closed if execvp() succeeds qt_native_close(childStartedPipe[0]); ::fcntl(childStartedPipe[1], F_SETFD, FD_CLOEXEC); // enter the working directory if (!workingDirectory.isEmpty()) qt_native_chdir(QFile::encodeName(workingDirectory).constData()); // this is a virtual call, and it base behavior is to do nothing. q->setupChildProcess(); // execute the process if (environment.isEmpty()) { qt_native_execvp(argv[0], argv); } else { // if LD_LIBRARY_PATH exists in the current environment, but // not in the environment list passed by the programmer, then // copy it over.#if defined(Q_OS_MAC) static const char libraryPath[] = "DYLD_LIBRARY_PATH";#else static const char libraryPath[] = "LD_LIBRARY_PATH";#endif const QString libraryPathString = QLatin1String(libraryPath); QStringList matches = environment.filter( QRegExp(QLatin1Char('^') + libraryPathString + QLatin1Char('='))); const QString envLibraryPath = QString::fromLocal8Bit(::getenv(libraryPath)); if (matches.isEmpty() && !envLibraryPath.isEmpty()) { QString entry = libraryPathString; entry += QLatin1Char('='); entry += envLibraryPath; environment << libraryPathString + QLatin1Char('=') + envLibraryPath; } char **envp = new char *[environment.count() + 1]; envp[environment.count()] = 0; for (int j = 0; j < environment.count(); ++j) { QString item = environment.at(j); envp[j] = ::strdup(item.toLocal8Bit().constData()); } if (!encodedProgramName.contains("/")) { const QString path = QString::fromLocal8Bit(::getenv("PATH")); if (!path.isEmpty()) { QStringList pathEntries = path.split(QLatin1Char(':')); for (int k = 0; k < pathEntries.size(); ++k) { QByteArray tmp = QFile::encodeName(pathEntries.at(k)); if (!tmp.endsWith('/')) tmp += '/'; tmp += encodedProgramName; argv[0] = tmp.data();#if defined (QPROCESS_DEBUG) fprintf(stderr, "QProcessPrivate::execChild() searching / starting %s\n", argv[0]);#endif qt_native_execve(argv[0], argv, envp); } } } else {#if defined (QPROCESS_DEBUG) fprintf(stderr, "QProcessPrivate::execChild() starting %s\n", argv[0]);#endif qt_native_execve(argv[0], argv, envp); } } // notify failure#if defined (QPROCESS_DEBUG) fprintf(stderr, "QProcessPrivate::execChild() failed, notifying parent process\n");#endif qt_native_write(childStartedPipe[1], "", 1); qt_native_close(childStartedPipe[1]); childStartedPipe[1] = -1;}bool QProcessPrivate::processStarted(){ char c; int i = qt_native_read(childStartedPipe[0], &c, 1); if (startupSocketNotifier) { startupSocketNotifier->setEnabled(false); delete startupSocketNotifier; startupSocketNotifier = 0; } qt_native_close(childStartedPipe[0]); childStartedPipe[0] = -1;#if defined (QPROCESS_DEBUG) qDebug("QProcessPrivate::processStarted() == %s", i <= 0 ? "true" : "false");#endif return i <= 0;}qint64 QProcessPrivate::bytesAvailableFromStdout() const{ size_t nbytes = 0; qint64 available = 0; if (::ioctl(stdoutChannel.pipe[0], FIONREAD, (char *) &nbytes) >= 0) available = (qint64) *((int *) &nbytes);#if defined (QPROCESS_DEBUG) qDebug("QProcessPrivate::bytesAvailableFromStdout() == %lld", available);#endif return available;}qint64 QProcessPrivate::bytesAvailableFromStderr() const{ size_t nbytes = 0; qint64 available = 0; if (::ioctl(stderrChannel.pipe[0], FIONREAD, (char *) &nbytes) >= 0) available = (qint64) *((int *) &nbytes);#if defined (QPROCESS_DEBUG) qDebug("QProcessPrivate::bytesAvailableFromStderr() == %lld", available);#endif return available;}qint64 QProcessPrivate::readFromStdout(char *data, qint64 maxlen){ qint64 bytesRead = qt_native_read(stdoutChannel.pipe[0], data, maxlen);#if defined QPROCESS_DEBUG qDebug("QProcessPrivate::readFromStdout(%p \"%s\", %lld) == %lld", data, qt_prettyDebug(data, bytesRead, 16).constData(), maxlen, bytesRead);#endif return bytesRead;}qint64 QProcessPrivate::readFromStderr(char *data, qint64 maxlen){ qint64 bytesRead = qt_native_read(stderrChannel.pipe[0], data, maxlen);#if defined QPROCESS_DEBUG qDebug("QProcessPrivate::readFromStderr(%p \"%s\", %lld) == %lld", data, qt_prettyDebug(data, bytesRead, 16).constData(), maxlen, bytesRead);#endif return bytesRead;}static void qt_ignore_sigpipe(){ // Set to ignore SIGPIPE once only. static QBasicAtomic atom = Q_ATOMIC_INIT(0); if (atom.testAndSet(0, 1)) { struct sigaction noaction; memset(&noaction, 0, sizeof(noaction)); noaction.sa_handler = SIG_IGN; qt_native_sigaction(SIGPIPE, &noaction, 0); }}qint64 QProcessPrivate::writeToStdin(const char *data, qint64 maxlen){ qt_ignore_sigpipe(); qint64 written = qt_native_write(stdinChannel.pipe[1], data, maxlen);#if defined QPROCESS_DEBUG qDebug("QProcessPrivate::writeToStdin(%p \"%s\", %lld) == %lld", data, qt_prettyDebug(data, maxlen, 16).constData(), maxlen, written);#endif return written;}void QProcessPrivate::terminateProcess(){#if defined (QPROCESS_DEBUG) qDebug("QProcessPrivate::killProcess()");#endif if (pid) ::kill(pid_t(pid), SIGTERM);}void QProcessPrivate::killProcess(){#if defined (QPROCESS_DEBUG) qDebug("QProcessPrivate::killProcess()");#endif if (pid) ::kill(pid_t(pid), SIGKILL);}
?? 快捷鍵說明
復(fù)制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號(hào)
Ctrl + =
減小字號(hào)
Ctrl + -