Changeset 72


Ignore:
Timestamp:
Jul 9, 2009, 1:43:12 PM (16 years ago)
Author:
Dmitry A. Kuminov
Message:

corelib: OS/2: Reimplemented QProcess using libc pipes (#7).

Location:
trunk/src/corelib/io
Files:
4 edited
1 copied

Legend:

Unmodified
Added
Removed
  • TabularUnified trunk/src/corelib/io/io.pri

    r60 r72  
    6262} else:os2 {
    6363        SOURCES += io/qsettings_os2.cpp
    64         # @todo later
    65 #        SOURCES += io/qprocess_os2.cpp
     64        SOURCES += io/qprocess_os2.cpp
    6665        SOURCES += io/qfsfileengine_os2.cpp
    6766
  • TabularUnified trunk/src/corelib/io/qprocess.cpp

    r71 r72  
    231231    \snippet doc/src/snippets/process/process.cpp 0
    232232
    233     \section1 Notes for Windows Users
    234 
    235     Some Windows commands (for example, \c dir) are not provided by
    236     separate applications, but by the command interpreter itself.
     233    \section1 Notes for Windows and OS/2 Users
     234
     235    Some Windows and OS/2 commands (for example, \c dir) are not provided
     236    by separate applications, but by the command interpreter itself.
    237237    If you attempt to use QProcess to execute these commands directly,
    238238    it won't work. One possible solution is to execute the command
     
    413413    processError = QProcess::UnknownError;
    414414    processState = QProcess::NotRunning;
    415 #ifdef Q_OS_OS2
    416     pid = PID_NULL;
    417 #else
    418415    pid = 0;
    419 #endif
    420416    sequenceNumber = 0;
    421417    exitCode = 0;
     
    458454{
    459455    q_func()->setProcessState(QProcess::NotRunning);
    460 #if !defined(Q_OS_OS2)
    461456#ifdef Q_OS_WIN
    462457    if (pid) {
     
    474469#endif
    475470    pid = 0;
    476 #else
    477     pid = PID_NULL;
    478 #endif
    479471    sequenceNumber = 0;
    480472    dying = false;
    481473
    482 #if !defined(Q_OS_OS2)
    483474    if (stdoutChannel.notifier) {
    484475        stdoutChannel.notifier->setEnabled(false);
     
    513504    destroyPipe(stderrChannel.pipe);
    514505    destroyPipe(stdinChannel.pipe);
    515 #else
    516     destroyPipe(stdoutChannel);
    517     destroyPipe(stderrChannel);
    518     destroyPipe(stdinChannel);
    519 #endif
    520 #if !defined(Q_OS_OS2)
    521506    destroyPipe(childStartedPipe);
    522507    destroyPipe(deathPipe);
    523 #endif
    524508#ifdef Q_OS_UNIX
    525509    serial = 0;
     
    534518    qint64 available = bytesAvailableFromStdout();
    535519    if (available == 0) {
    536 #if !defined(Q_OS_OS2)
    537520        if (stdoutChannel.notifier)
    538521            stdoutChannel.notifier->setEnabled(false);
    539522        destroyPipe(stdoutChannel.pipe);
    540 #else
    541         destroyPipe(stdoutChannel);
    542 #endif
    543523#if defined QPROCESS_DEBUG
    544524        qDebug("QProcessPrivate::canReadStandardOutput(), 0 bytes available");
     
    593573    qint64 available = bytesAvailableFromStderr();
    594574    if (available == 0) {
    595 #if !defined(Q_OS_OS2)
    596575        if (stderrChannel.notifier)
    597576            stderrChannel.notifier->setEnabled(false);
    598577        destroyPipe(stderrChannel.pipe);
    599 #else
    600         destroyPipe(stderrChannel);
    601 #endif
    602578        return false;
    603579    }
     
    652628                                      writeBuffer.nextDataBlockSize());
    653629    if (written < 0) {
    654 #if !defined(Q_OS_OS2)
    655630        destroyPipe(stdinChannel.pipe);
    656 #else
    657         destroyPipe(stdinChannel);
    658 #endif
    659631        processError = QProcess::WriteError;
    660632        q->setErrorString(QProcess::tr("Error writing to process"));
     
    691663    qDebug("QProcessPrivate::_q_processDied()");
    692664#endif
    693 #ifdef Q_OS_UNIX
     665#if defined(Q_OS_UNIX) || defined(Q_OS_OS2)
    694666    if (!waitForDeadChild())
    695667        return false;
     
    801773    flushPipeWriter();
    802774#endif
    803 #if !defined(Q_OS_OS2)
    804775    destroyPipe(stdinChannel.pipe);
    805 #else
    806     destroyPipe(stdinChannel);
    807 #endif
    808776}
    809777
     
    11071075/*!
    11081076    Returns the native process identifier for the running process, if
    1109     available.  If no process is currently running, 0 is returned on all
    1110     platforms except OS/2 which returns PID_NULL in this case.
     1077    available.  If no process is currently running, 0 is returned.
    11111078*/
    11121079Q_PID QProcess::pid() const
  • TabularUnified trunk/src/corelib/io/qprocess.h

    r71 r72  
    5757typedef qint64 Q_PID;
    5858#elif defined(Q_OS_OS2)
    59 typedef PID Q_PID;
    60 #define PID_NULL PID(~0)
     59typedef int Q_PID;
    6160#else
    6261QT_END_NAMESPACE
  • TabularUnified trunk/src/corelib/io/qprocess_os2.cpp

    r63 r72  
    33** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
    44** Contact: Qt Software Information (qt-info@nokia.com)
     5**
     6** Copyright (C) 2009 netlabs.org. OS/2 parts.
    57**
    68** This file is part of the QtCore module of the Qt Toolkit.
     
    8688#include "qprocess_p.h"
    8789
    88 #ifdef Q_OS_MAC
    89 #include <private/qcore_mac_p.h>
    90 #endif
     90#include <QtCore/qt_os2.h>
    9191
    9292#include <private/qcoreapplication_p.h>
     
    100100#include <qsemaphore.h>
    101101#include <qsocketnotifier.h>
    102 #include <qthread.h>
     102#include <qdir.h>
    103103
    104104#include <errno.h>
    105 #include <stdlib.h>
    106 #include <string.h>
     105#include <sys/filio.h>
    107106
    108107QT_BEGIN_NAMESPACE
    109108
    110 #ifdef Q_OS_INTEGRITY
    111 static inline char *strdup(const char *data)
    112 {
    113     return qstrdup(data);
    114 }
    115 #endif
    116 
    117 static qint64 qt_native_read(int fd, char *data, qint64 maxlen)
    118 {
    119     qint64 ret = 0;
    120     do {
    121         ret = ::read(fd, data, maxlen);
    122     } while (ret == -1 && errno == EINTR);
    123     return ret;
    124 }
    125 
    126 static qint64 qt_native_write(int fd, const char *data, qint64 len)
    127 {
    128     qint64 ret = 0;
    129     do {
    130         ret = ::write(fd, data, len);
    131     } while (ret == -1 && errno == EINTR);
    132     return ret;
    133 }
    134 
    135 static void qt_native_close(int fd)
    136 {
    137     int ret;
    138     do {
    139         ret = ::close(fd);
    140     } while (ret == -1 && errno == EINTR);
    141 }
    142 
    143 static void qt_native_sigaction(int signum, const struct sigaction *act,
    144                                 struct sigaction *oldact)
    145 {
    146     int ret;
    147     do {
    148         ret = ::sigaction(signum, act, oldact);
    149     } while (ret == -1 && errno == EINTR);
    150 }
    151 
    152 static void qt_native_dup2(int oldfd, int newfd)
    153 {
    154     int ret;
    155     do {
    156         ret = ::dup2(oldfd, newfd);
    157     } while (ret == -1 && errno == EINTR);
    158 }
    159 
    160 static void qt_native_chdir(const char *path)
    161 {
    162     int ret;
    163     do {
    164         ret = ::chdir(path);
    165     } while (ret == -1 && errno == EINTR);
    166 }
    167 
    168 static void qt_native_execve(const char *filename, char *const argv[],
    169                               char *const envp[])
    170 {
    171     int ret;
    172     do {
    173         ret = ::execve(filename, argv, envp);
    174     } while (ret == -1 && errno == EINTR);
    175 }
    176 
    177 static void qt_native_execv(const char *path, char *const argv[])
    178 {
    179     int ret;
    180     do {
    181         ret = ::execv(path, argv);
    182     } while (ret == -1 && errno == EINTR);
    183 }
    184 
    185 static void qt_native_execvp(const char *file, char *const argv[])
    186 {
    187     int ret;
    188     do {
    189         ret = ::execvp(file, argv);
    190     } while (ret == -1 && errno == EINTR);
    191 }
    192 
    193 static int qt_qprocess_deadChild_pipe[2];
    194 static void (*qt_sa_old_sigchld_handler)(int) = 0;
    195 static void qt_sa_sigchld_handler(int signum)
    196 {
    197     qt_native_write(qt_qprocess_deadChild_pipe[1], "", 1);
    198 #if defined (QPROCESS_DEBUG)
    199     fprintf(stderr, "*** SIGCHLD\n");
    200 #endif
    201 
    202     if (qt_sa_old_sigchld_handler && qt_sa_old_sigchld_handler != SIG_IGN)
    203         qt_sa_old_sigchld_handler(signum);
    204 }
    205 
    206 struct QProcessInfo {
    207     QProcess *process;
    208     int deathPipe;
    209     int exitResult;
    210     pid_t pid;
    211     int serialNumber;
    212 };
    213 
    214 class QProcessManager : public QThread
    215 {
    216     Q_OBJECT
    217 public:
    218     QProcessManager();
    219     ~QProcessManager();
    220 
    221     void run();
    222     void catchDeadChildren();
    223     void add(pid_t pid, QProcess *process);
    224     void remove(QProcess *process);
    225     void lock();
    226     void unlock();
    227 
    228 private:
    229     QMutex mutex;
    230     QMap<int, QProcessInfo *> children;
    231 };
    232 
    233 Q_GLOBAL_STATIC(QProcessManager, processManager)
    234 
    235 QProcessManager::QProcessManager()
    236 {
    237 #if defined (QPROCESS_DEBUG)
    238     qDebug() << "QProcessManager::QProcessManager()";
    239 #endif
    240     // initialize the dead child pipe and make it non-blocking. in the
    241     // extremely unlikely event that the pipe fills up, we do not under any
    242     // circumstances want to block.
    243     ::pipe(qt_qprocess_deadChild_pipe);
    244     ::fcntl(qt_qprocess_deadChild_pipe[0], F_SETFD, FD_CLOEXEC);
    245     ::fcntl(qt_qprocess_deadChild_pipe[1], F_SETFD, FD_CLOEXEC);
    246     ::fcntl(qt_qprocess_deadChild_pipe[0], F_SETFL,
    247             ::fcntl(qt_qprocess_deadChild_pipe[0], F_GETFL) | O_NONBLOCK);
    248     ::fcntl(qt_qprocess_deadChild_pipe[1], F_SETFL,
    249             ::fcntl(qt_qprocess_deadChild_pipe[1], F_GETFL) | O_NONBLOCK);
    250 
    251     // set up the SIGCHLD handler, which writes a single byte to the dead
    252     // child pipe every time a child dies.
    253     struct sigaction oldAction;
    254     struct sigaction action;
    255     memset(&action, 0, sizeof(action));
    256     action.sa_handler = qt_sa_sigchld_handler;
    257     action.sa_flags = SA_NOCLDSTOP;
    258     qt_native_sigaction(SIGCHLD, &action, &oldAction);
    259     if (oldAction.sa_handler != qt_sa_sigchld_handler)
    260         qt_sa_old_sigchld_handler = oldAction.sa_handler;
    261 }
    262 
    263 QProcessManager::~QProcessManager()
    264 {
    265     // notify the thread that we're shutting down.
    266     qt_native_write(qt_qprocess_deadChild_pipe[1], "@", 1);
    267     qt_native_close(qt_qprocess_deadChild_pipe[1]);
    268     wait();
    269 
    270     // on certain unixes, closing the reading end of the pipe will cause
    271     // select in run() to block forever, rather than return with EBADF.
    272     qt_native_close(qt_qprocess_deadChild_pipe[0]);
    273 
    274     qt_qprocess_deadChild_pipe[0] = -1;
    275     qt_qprocess_deadChild_pipe[1] = -1;
    276 
    277     qDeleteAll(children.values());
    278     children.clear();
    279 
    280     struct sigaction oldAction;
    281     struct sigaction action;
    282     memset(&action, 0, sizeof(action));
    283     action.sa_handler = qt_sa_old_sigchld_handler;
    284     action.sa_flags = SA_NOCLDSTOP;
    285     qt_native_sigaction(SIGCHLD, &action, &oldAction);
    286     if (oldAction.sa_handler != qt_sa_sigchld_handler) {
    287         qt_native_sigaction(SIGCHLD, &oldAction, 0);
    288     }
    289 }
    290 
    291 void QProcessManager::run()
    292 {
    293     forever {
    294         fd_set readset;
    295         FD_ZERO(&readset);
    296         FD_SET(qt_qprocess_deadChild_pipe[0], &readset);
    297 
    298 #if defined (QPROCESS_DEBUG)
    299         qDebug() << "QProcessManager::run() waiting for children to die";
    300 #endif
    301 
    302         // block forever, or until activity is detected on the dead child
    303         // pipe. the only other peers are the SIGCHLD signal handler, and the
    304         // QProcessManager destructor.
    305         int nselect = select(qt_qprocess_deadChild_pipe[0] + 1, &readset, 0, 0, 0);
    306         if (nselect < 0) {
    307             if (errno == EINTR)
    308                 continue;
    309             break;
    310         }
    311 
    312         // empty only one byte from the pipe, even though several SIGCHLD
    313         // signals may have been delivered in the meantime, to avoid race
    314         // conditions.
    315         char c;
    316         if (qt_native_read(qt_qprocess_deadChild_pipe[0], &c, 1) < 0 || c == '@')
    317             break;
    318 
    319         // catch any and all children that we can.
    320         catchDeadChildren();
    321     }
    322 }
    323 
    324 void QProcessManager::catchDeadChildren()
    325 {
    326     QMutexLocker locker(&mutex);
    327 
    328     // try to catch all children whose pid we have registered, and whose
    329     // deathPipe is still valid (i.e, we have not already notified it).
    330     QMap<int, QProcessInfo *>::Iterator it = children.begin();
    331     while (it != children.end()) {
    332         // notify all children that they may have died. they need to run
    333         // waitpid() in their own thread.
    334         QProcessInfo *info = it.value();
    335         qt_native_write(info->deathPipe, "", 1);
    336 
    337 #if defined (QPROCESS_DEBUG)
    338         qDebug() << "QProcessManager::run() sending death notice to" << info->process;
    339 #endif
    340         ++it;
    341     }
    342 }
    343 
    344 static QBasicAtomicInt idCounter = Q_BASIC_ATOMIC_INITIALIZER(1);
    345 
    346 void QProcessManager::add(pid_t pid, QProcess *process)
    347 {
    348 #if defined (QPROCESS_DEBUG)
    349     qDebug() << "QProcessManager::add() adding pid" << pid << "process" << process;
    350 #endif
    351 
    352     // insert a new info structure for this process
    353     QProcessInfo *info = new QProcessInfo;
    354     info->process = process;
    355     info->deathPipe = process->d_func()->deathPipe[1];
    356     info->exitResult = 0;
    357     info->pid = pid;
    358 
    359     int serial = idCounter.fetchAndAddRelaxed(1);
    360     process->d_func()->serial = serial;
    361     children.insert(serial, info);
    362 }
    363 
    364 void QProcessManager::remove(QProcess *process)
    365 {
    366     QMutexLocker locker(&mutex);
    367 
    368     int serial = process->d_func()->serial;
    369     QProcessInfo *info = children.value(serial);
    370     if (!info)
    371         return;
    372 
    373 #if defined (QPROCESS_DEBUG)
    374     qDebug() << "QProcessManager::remove() removing pid" << info->pid << "process" << info->process;
    375 #endif
    376 
    377     children.remove(serial);
    378     delete info;
    379 }
    380 
    381 void QProcessManager::lock()
    382 {
    383     mutex.lock();
    384 }
    385 
    386 void QProcessManager::unlock()
    387 {
    388     mutex.unlock();
    389 }
    390 
    391109static void qt_create_pipe(int *pipe)
    392110{
    393111    if (pipe[0] != -1)
    394         qt_native_close(pipe[0]);
     112        ::close(pipe[0]);
    395113    if (pipe[1] != -1)
    396         qt_native_close(pipe[1]);
    397 #ifdef Q_OS_IRIX
    398     if (::socketpair(AF_UNIX, SOCK_STREAM, 0, pipe) == -1) {
    399         qWarning("QProcessPrivate::createPipe: Cannot create pipe %p: %s",
    400                  pipe, qPrintable(qt_error_string(errno)));
    401     }
    402 #else
     114        ::close(pipe[1]);
    403115    if (::pipe(pipe) != 0) {
    404116        qWarning("QProcessPrivate::createPipe: Cannot create pipe %p: %s",
    405117                 pipe, qPrintable(qt_error_string(errno)));
    406118    }
    407 #endif
    408119    ::fcntl(pipe[0], F_SETFD, FD_CLOEXEC);
    409120    ::fcntl(pipe[1], F_SETFD, FD_CLOEXEC);
     
    413124{
    414125    if (pipe[1] != -1) {
    415         qt_native_close(pipe[1]);
     126        ::close(pipe[1]);
    416127        pipe[1] = -1;
    417128    }
    418129    if (pipe[0] != -1) {
    419         qt_native_close(pipe[0]);
     130        ::close(pipe[0]);
    420131        pipe[0] = -1;
    421132    }
     
    470181            // try to open in read-only mode
    471182            channel.pipe[1] = -1;
    472             if ( (channel.pipe[0] = QT_OPEN(fname, O_RDONLY)) != -1)
     183            if ( (channel.pipe[0] = ::open(fname, O_RDONLY)) != -1)
    473184                return true;    // success
    474185
     
    482193
    483194            channel.pipe[0] = -1;
    484             if ( (channel.pipe[1] = QT_OPEN(fname, mode, 0666)) != -1)
     195            if ( (channel.pipe[1] = ::open(fname, mode, 0666)) != -1)
    485196                return true; // success
    486197
     
    532243}
    533244
    534 static char **_q_dupEnvironment(const QStringList &environment, int *envc)
    535 {
    536     // if LD_LIBRARY_PATH exists in the current environment, but
    537     // not in the environment list passed by the programmer, then
    538     // copy it over.
    539 #if defined(Q_OS_MAC)
    540     static const char libraryPath[] = "DYLD_LIBRARY_PATH";
    541 #else
    542     static const char libraryPath[] = "LD_LIBRARY_PATH";
    543 #endif
    544     const QString libraryPathString = QLatin1String(libraryPath);
    545     QStringList env = environment;
    546     QStringList matches = env.filter(
    547         QRegExp(QLatin1Char('^') + libraryPathString + QLatin1Char('=')));
    548     const QString envLibraryPath = QString::fromLocal8Bit(::getenv(libraryPath));
    549     if (matches.isEmpty() && !envLibraryPath.isEmpty()) {
    550         QString entry = libraryPathString;
    551         entry += QLatin1Char('=');
    552         entry += envLibraryPath;
    553         env << libraryPathString + QLatin1Char('=') + envLibraryPath;
    554     }
    555 
    556     char **envp = new char *[env.count() + 1];
    557     envp[env.count()] = 0;
    558 
    559     for (int j = 0; j < env.count(); ++j) {
    560         QString item = env.at(j);
    561         envp[j] = ::strdup(item.toLocal8Bit().constData());
    562     }
    563 
    564     *envc = env.count();
    565     return envp;
    566 }
    567 
    568 // under QNX RTOS we have to use vfork() when multithreading
    569 inline pid_t qt_fork()
    570 {
    571 #if defined(Q_OS_QNX)
    572     return vfork();
    573 #else
    574     return fork();
    575 #endif
    576 }
    577 
    578 #ifdef Q_OS_MAC
    579 Q_GLOBAL_STATIC(QMutex, cfbundleMutex);
    580 #endif
    581 
    582245void QProcessPrivate::startProcess()
    583246{
     
    588251#endif
    589252
    590     processManager()->start();
    591 
    592253    // Initialize pipes
    593     qt_create_pipe(childStartedPipe);
    594     if (threadData->eventDispatcher) {
    595         startupSocketNotifier = new QSocketNotifier(childStartedPipe[0],
    596                                                     QSocketNotifier::Read, q);
    597         QObject::connect(startupSocketNotifier, SIGNAL(activated(int)),
    598                          q, SLOT(_q_startupNotification()));
    599     }
    600 
    601     qt_create_pipe(deathPipe);
    602     ::fcntl(deathPipe[0], F_SETFD, FD_CLOEXEC);
    603     ::fcntl(deathPipe[1], F_SETFD, FD_CLOEXEC);
    604     if (threadData->eventDispatcher) {
    605         deathNotifier = new QSocketNotifier(deathPipe[0],
    606                                             QSocketNotifier::Read, q);
    607         QObject::connect(deathNotifier, SIGNAL(activated(int)),
    608                          q, SLOT(_q_processDied()));
    609     }
    610 
    611254    if (!createChannel(stdinChannel) ||
    612255        !createChannel(stdoutChannel) ||
     
    617260    q->setProcessState(QProcess::Starting);
    618261
     262    // save & copy the stdin socket
     263    int stdin_copy = ::dup(fileno(stdin));
     264    ::dup2(stdinChannel.pipe[0], fileno(stdin));
     265
     266    // save & copy the stdout and stderr if asked to
     267    int stdout_copy = -1, stderr_copy = -1;
     268    if (processChannelMode != QProcess::ForwardedChannels) {
     269        stdout_copy = ::dup(fileno(stdout));
     270        ::dup2(stdoutChannel.pipe[1], fileno(stdout));
     271
     272        // merge stdout and stderr if asked to
     273        stderr_copy = ::dup(fileno(stderr));
     274        if (processChannelMode == QProcess::MergedChannels) {
     275            ::dup2(fileno(stdout), fileno(stderr));
     276        } else {
     277            ::dup2(stderrChannel.pipe[1], fileno(stderr));
     278        }
     279    }
     280
    619281    // Create argument list with right number of elements, and set the final
    620282    // one to 0.
     
    624286    // Encode the program name.
    625287    QByteArray encodedProgramName = QFile::encodeName(program);
    626 #ifdef Q_OS_MAC
    627     // allow invoking of .app bundles on the Mac.
    628     QFileInfo fileInfo(QString::fromUtf8(encodedProgramName.constData()));
    629     if (encodedProgramName.endsWith(".app") && fileInfo.isDir()) {
    630         QCFType<CFURLRef> url = CFURLCreateWithFileSystemPath(0,
    631                                                           QCFString(fileInfo.absoluteFilePath()),
    632                                                           kCFURLPOSIXPathStyle, true);
    633         {
    634             // CFBundle is not reentrant, since CFBundleCreate might return a reference
    635             // to a cached bundle object. Protect the bundle calls with a mutex lock.
    636             QMutexLocker lock(cfbundleMutex());
    637             QCFType<CFBundleRef> bundle = CFBundleCreate(0, url);
    638             url = CFBundleCopyExecutableURL(bundle);
    639         }
    640         if (url) {
    641             QCFString str = CFURLCopyFileSystemPath(url, kCFURLPOSIXPathStyle);
    642             encodedProgramName += "/Contents/MacOS/" + static_cast<QString>(str).toUtf8();
    643         }
    644     }
    645 #endif
    646288
    647289    // Add the program name to the argument list.
    648     char *dupProgramName = ::strdup(encodedProgramName.constData());
    649     argv[0] = dupProgramName;
     290    argv[0] = encodedProgramName.data();
    650291
    651292    // Add every argument to the list
    652293    for (int i = 0; i < arguments.count(); ++i) {
    653294        QString arg = arguments.at(i);
    654 #ifdef Q_OS_MAC
    655         // Mac OS X uses UTF8 for exec, regardless of the system locale.
    656         argv[i + 1] = ::strdup(arg.toUtf8().constData());
    657 #else
    658         argv[i + 1] = ::strdup(arg.toLocal8Bit().constData());
    659 #endif
     295        argv[i + 1] = qstrdup(arg.toLocal8Bit().constData());
    660296    }
    661297
    662298    // Duplicate the environment.
    663299    int envc = 0;
    664     char **envp = _q_dupEnvironment(environment, &envc);
    665 
    666     // Encode the working directory if it's non-empty, otherwise just pass 0.
    667     const char *workingDirPtr = 0;
    668     QByteArray encodedWorkingDirectory;
     300    char **envv;
     301    if (environment.count()) {
     302        bool seenPATH = false;
     303        bool seenCOMSPEC = false;
     304
     305        envv = new char *[environment.count() + 1 + 2 /* may be PATH + COMSPEC */];
     306        for (; envc < environment.count(); ++envc) {
     307            QString item = environment.at(envc);
     308            envv[envc] = qstrdup(item.toLocal8Bit().constData());
     309            if (!seenPATH)
     310                seenPATH = !qstrncmp(envv[envc], "PATH=", 4);
     311            if (!seenCOMSPEC)
     312                seenCOMSPEC = !qstrncmp(envv[envc], "COMSPEC=", 8);
     313        }
     314        if (!seenPATH) {
     315            // inherit PATH if missing (for convenience)
     316            // (note that BEGINLIBPATH and ENDLIBPATH, if any, are automatically
     317            // inherited, while LIBPATH is always a global setting)
     318            QByteArray path = qgetenv("PATH");
     319            path.prepend("PATH=");
     320            envv[envc++] = qstrdup(path);
     321        }
     322        // inherit COMSPEC if missing (to let the child start .cmd and .bat)
     323        if (!seenCOMSPEC) {
     324            QByteArray comspec = qgetenv("COMSPEC");
     325            comspec.prepend("COMSPEC=");
     326            envv[envc++] = qstrdup(comspec);
     327        }
     328        envv[envc] = 0;
     329    } else {
     330        // inherit the parent environment
     331        envv = environ;
     332    }
     333
     334    // Set the working directory if it's non-empty
     335    QString curDir;
    669336    if (!workingDirectory.isEmpty()) {
    670         encodedWorkingDirectory = QFile::encodeName(workingDirectory);
    671         workingDirPtr = encodedWorkingDirectory.constData();
    672     }
    673 
    674     // If the program does not specify a path, generate a list of possible
    675     // locations for the binary using the PATH environment variable.
    676     char **path = 0;
    677     int pathc = 0;
    678     if (!program.contains(QLatin1Char('/'))) {
    679         const QString pathEnv = QString::fromLocal8Bit(::getenv("PATH"));
    680         if (!pathEnv.isEmpty()) {
    681             QStringList pathEntries = pathEnv.split(QLatin1Char(':'), QString::SkipEmptyParts);
    682             if (!pathEntries.isEmpty()) {
    683                 pathc = pathEntries.size();
    684                 path = new char *[pathc + 1];
    685                 path[pathc] = 0;
    686 
    687                 for (int k = 0; k < pathEntries.size(); ++k) {
    688                     QByteArray tmp = QFile::encodeName(pathEntries.at(k));
    689                     if (!tmp.endsWith('/')) tmp += '/';
    690                     tmp += encodedProgramName;
    691                     path[k] = ::strdup(tmp.constData());
    692                 }
    693             }
    694         }
    695     }
    696 
    697     // Start the process manager, and fork off the child process.
    698     processManager()->lock();
    699     pid_t childPid = qt_fork();
    700     int lastForkErrno = errno;
    701     if (childPid != 0) {
    702         // Clean up duplicated memory.
    703         free(dupProgramName);
    704         for (int i = 1; i <= arguments.count(); ++i)
    705             free(argv[i]);
     337        curDir = QDir::currentPath();
     338        QDir::setCurrent(workingDirectory);
     339    }
     340
     341    // start the program
     342    int pid = spawnvpe(P_NOWAIT | P_DEFAULT, encodedProgramName, argv, envv);
     343
     344    // if spawnvpe() couldn't find the executable, try .CMD and .BAT
     345    // extensions (in order of CMD.EXE precedence); spawnvpe() knows how to
     346    // locate and run them (i.e. using CMD.EXE /c)
     347    if ( pid == -1 && errno == ENOENT ) {
     348        encodedProgramName += ".cmd";
     349        argv[0] = encodedProgramName.data();
     350        pid = spawnvpe(P_NOWAIT | P_DEFAULT, encodedProgramName, argv, envv);
     351        if ( pid == -1 && errno == ENOENT ) {
     352            qstrcpy(encodedProgramName.data() + encodedProgramName.length() - 4, ".bat");
     353            argv[0] = encodedProgramName.data();
     354            pid = spawnvpe(P_NOWAIT | P_DEFAULT, encodedProgramName, argv, envv);
     355        }
     356    }
     357
     358    // Clean up duplicated memory.
     359    for (int i = 1 /* 0 is encodedProgramName */; i <= arguments.count(); ++i)
     360        delete [] argv[i];
     361    delete [] argv;
     362    if (envv != environ) {
    706363        for (int i = 0; i < envc; ++i)
    707             free(envp[i]);
    708         for (int i = 0; i < pathc; ++i)
    709             free(path[i]);
    710         delete [] argv;
    711         delete [] envp;
    712         delete [] path;
    713     }
    714     if (childPid < 0) {
     364            delete [] envv[i];
     365        delete [] envv;
     366    }
     367
     368    // restore the current directory
     369    QDir::setCurrent(curDir);
     370
     371    // restore stdin/stdout/stderr
     372    if (stdin_copy != -1) {
     373        ::dup2(stdin_copy, fileno(stdin));
     374        ::close(stdin_copy);
     375    }
     376    if (stdout_copy != -1) {
     377        ::dup2(stdout_copy, fileno(stdout));
     378        ::close(stdout_copy);
     379    }
     380    if (stderr_copy != -1) {
     381        ::dup2(stderr_copy, fileno(stderr));
     382        ::close(stderr_copy);
     383    }
     384
     385    if (pid == -1) {
    715386        // Cleanup, report error and return
    716387#if defined (QPROCESS_DEBUG)
    717         qDebug("qt_fork failed: %s", qt_error_string(lastForkErrno));
    718 #endif
    719         processManager()->unlock();
     388        qDebug("spawnvpe failed: %s", qt_error_string(errno));
     389#endif
    720390        q->setProcessState(QProcess::NotRunning);
    721391        processError = QProcess::FailedToStart;
    722         q->setErrorString(QProcess::tr("Resource error (fork failure): %1").arg(qt_error_string(lastForkErrno)));
     392        q->setErrorString(QProcess::tr("Process failed to start: %1").arg(qt_error_string(errno)));
    723393        emit q->error(processError);
    724394        cleanup();
     
    726396    }
    727397
    728     // Start the child.
    729     if (childPid == 0) {
    730         execChild(workingDirPtr, path, argv, envp);
    731         ::_exit(-1);
    732     }
    733 
    734     // Register the child. In the mean time, we can get a SIGCHLD, so we need
    735     // to keep the lock held to avoid a race to catch the child.
    736     processManager()->add(childPid, q);
    737     pid = Q_PID(childPid);
    738     processManager()->unlock();
    739 
    740     // parent
     398    this->pid = Q_PID(pid);
     399
    741400    // close the ends we don't use and make all pipes non-blocking
    742     ::fcntl(deathPipe[0], F_SETFL, ::fcntl(deathPipe[0], F_GETFL) | O_NONBLOCK);
    743     qt_native_close(childStartedPipe[1]);
    744     childStartedPipe[1] = -1;
    745 
    746401    if (stdinChannel.pipe[0] != -1) {
    747         qt_native_close(stdinChannel.pipe[0]);
     402        ::close(stdinChannel.pipe[0]);
    748403        stdinChannel.pipe[0] = -1;
    749404    }
    750 
    751405    if (stdinChannel.pipe[1] != -1)
    752406        ::fcntl(stdinChannel.pipe[1], F_SETFL, ::fcntl(stdinChannel.pipe[1], F_GETFL) | O_NONBLOCK);
    753407
    754408    if (stdoutChannel.pipe[1] != -1) {
    755         qt_native_close(stdoutChannel.pipe[1]);
     409        ::close(stdoutChannel.pipe[1]);
    756410        stdoutChannel.pipe[1] = -1;
    757411    }
    758 
    759412    if (stdoutChannel.pipe[0] != -1)
    760413        ::fcntl(stdoutChannel.pipe[0], F_SETFL, ::fcntl(stdoutChannel.pipe[0], F_GETFL) | O_NONBLOCK);
    761414
    762415    if (stderrChannel.pipe[1] != -1) {
    763         qt_native_close(stderrChannel.pipe[1]);
     416        ::close(stderrChannel.pipe[1]);
    764417        stderrChannel.pipe[1] = -1;
    765418    }
    766419    if (stderrChannel.pipe[0] != -1)
    767420        ::fcntl(stderrChannel.pipe[0], F_SETFL, ::fcntl(stderrChannel.pipe[0], F_GETFL) | O_NONBLOCK);
    768 }
    769 
    770 void QProcessPrivate::execChild(const char *workingDir, char **path, char **argv, char **envp)
    771 {
    772     ::signal(SIGPIPE, SIG_DFL);         // reset the signal that we ignored
    773 
    774     Q_Q(QProcess);
    775 
    776     // copy the stdin socket
    777     qt_native_dup2(stdinChannel.pipe[0], fileno(stdin));
    778 
    779     // copy the stdout and stderr if asked to
    780     if (processChannelMode != QProcess::ForwardedChannels) {
    781         qt_native_dup2(stdoutChannel.pipe[1], fileno(stdout));
    782 
    783         // merge stdout and stderr if asked to
    784         if (processChannelMode == QProcess::MergedChannels) {
    785             qt_native_dup2(fileno(stdout), fileno(stderr));
    786         } else {
    787             qt_native_dup2(stderrChannel.pipe[1], fileno(stderr));
    788         }
    789     }
    790 
    791     // make sure this fd is closed if execvp() succeeds
    792     qt_native_close(childStartedPipe[0]);
    793     ::fcntl(childStartedPipe[1], F_SETFD, FD_CLOEXEC);
    794 
    795     // enter the working directory
    796     if (workingDir)
    797         qt_native_chdir(workingDir);
    798 
    799     // this is a virtual call, and it base behavior is to do nothing.
    800     q->setupChildProcess();
    801 
    802     // execute the process
    803     if (environment.isEmpty()) {
    804         qt_native_execvp(argv[0], argv);
    805     } else {
    806         if (path) {
    807             char **arg = path;
    808             while (*arg) {
    809                 argv[0] = *arg;
    810 #if defined (QPROCESS_DEBUG)
    811                 fprintf(stderr, "QProcessPrivate::execChild() searching / starting %s\n", argv[0]);
    812 #endif
    813                 qt_native_execve(argv[0], argv, envp);
    814                 ++arg;
    815             }
    816         } else {
    817 #if defined (QPROCESS_DEBUG)
    818             fprintf(stderr, "QProcessPrivate::execChild() starting %s\n", argv[0]);
    819 #endif
    820             qt_native_execve(argv[0], argv, envp);
    821         }
    822     }
    823 
    824     // notify failure
    825 #if defined (QPROCESS_DEBUG)
    826     fprintf(stderr, "QProcessPrivate::execChild() failed, notifying parent process\n");
    827 #endif
    828     qt_native_write(childStartedPipe[1], "", 1);
    829     qt_native_close(childStartedPipe[1]);
    830     childStartedPipe[1] = -1;
     421
     422    q->setProcessState(QProcess::Running);
     423    // User can call kill()/terminate() from the stateChanged() slot
     424    // so check before proceeding
     425    if (!pid)
     426        return;
     427
     428    // give the process a chance to start ...
     429    DosSleep(100);
     430    _q_startupNotification();
    831431}
    832432
    833433bool QProcessPrivate::processStarted()
    834434{
    835     char c;
    836     int i = qt_native_read(childStartedPipe[0], &c, 1);
    837     if (startupSocketNotifier) {
    838         startupSocketNotifier->setEnabled(false);
    839         startupSocketNotifier->deleteLater();
    840         startupSocketNotifier = 0;
    841     }
    842     qt_native_close(childStartedPipe[0]);
    843     childStartedPipe[0] = -1;
    844 
    845 #if defined (QPROCESS_DEBUG)
    846     qDebug("QProcessPrivate::processStarted() == %s", i <= 0 ? "true" : "false");
    847 #endif
    848     return i <= 0;
     435    return processState == QProcess::Running;
    849436}
    850437
     
    875462qint64 QProcessPrivate::readFromStdout(char *data, qint64 maxlen)
    876463{
    877     qint64 bytesRead = qt_native_read(stdoutChannel.pipe[0], data, maxlen);
     464    qint64 bytesRead = ::read(stdoutChannel.pipe[0], data, maxlen);
    878465#if defined QPROCESS_DEBUG
    879466    qDebug("QProcessPrivate::readFromStdout(%p \"%s\", %lld) == %lld",
     
    885472qint64 QProcessPrivate::readFromStderr(char *data, qint64 maxlen)
    886473{
    887     qint64 bytesRead = qt_native_read(stderrChannel.pipe[0], data, maxlen);
     474    qint64 bytesRead = ::read(stderrChannel.pipe[0], data, maxlen);
    888475#if defined QPROCESS_DEBUG
    889476    qDebug("QProcessPrivate::readFromStderr(%p \"%s\", %lld) == %lld",
     
    893480}
    894481
    895 static void qt_ignore_sigpipe()
    896 {
    897     // Set to ignore SIGPIPE once only.
    898     static QBasicAtomicInt atom = Q_BASIC_ATOMIC_INITIALIZER(0);
    899     if (atom.testAndSetRelaxed(0, 1)) {
    900         struct sigaction noaction;
    901         memset(&noaction, 0, sizeof(noaction));
    902         noaction.sa_handler = SIG_IGN;
    903         qt_native_sigaction(SIGPIPE, &noaction, 0);
    904     }
    905 }
    906 
    907482qint64 QProcessPrivate::writeToStdin(const char *data, qint64 maxlen)
    908483{
    909     qt_ignore_sigpipe();
    910 
    911     qint64 written = qt_native_write(stdinChannel.pipe[1], data, maxlen);
     484    qint64 written = ::write(stdinChannel.pipe[1], data, maxlen);
    912485#if defined QPROCESS_DEBUG
    913486    qDebug("QProcessPrivate::writeToStdin(%p \"%s\", %lld) == %lld",
     
    920493{
    921494#if defined (QPROCESS_DEBUG)
    922     qDebug("QProcessPrivate::killProcess()");
    923 #endif
    924     if (pid)
    925         ::kill(pid_t(pid), SIGTERM);
     495    qDebug("QProcessPrivate::terminateProcess()");
     496#endif
     497    if (pid) {
     498        HSWITCH hswitch = WinQuerySwitchHandle(NULL, pid);
     499        if (hswitch != NULLHANDLE) {
     500            SWCNTRL swcntrl = { 0 };
     501            APIRET rc = WinQuerySwitchEntry(hswitch,  &swcntrl);
     502            // WinQuerySwitchEntry will return a switch entry of the parent
     503            // process if the specfied one doesn't have a separate session
     504            // (running a plain CMD.EXE is an example); ignore this case.
     505            if (rc == NO_ERROR && swcntrl.idProcess == pid)
     506            {
     507                // first, ensure that the Close action is enabled in the main frame
     508                // window (otherwise WM_SYSCOMMAND/SC_CLOSE will be ignored)
     509                HWND hwndSysMenu = WinWindowFromID(swcntrl.hwnd, FID_SYSMENU);
     510                if (hwndSysMenu) {
     511                    WinPostMsg(hwndSysMenu, MM_SETITEMATTR,
     512                               MPFROM2SHORT(SC_CLOSE, TRUE),
     513                               MPFROM2SHORT(MIA_DISABLED, 0));
     514                }
     515                WinPostMsg(swcntrl.hwnd, WM_SYSCOMMAND,
     516                           MPFROM2SHORT(SC_CLOSE, CMDSRC_OTHER),
     517                           MPFROMLONG(FALSE));
     518            }
     519        }
     520    }
    926521}
    927522
     
    932527#endif
    933528    if (pid)
    934         ::kill(pid_t(pid), SIGKILL);
    935 }
    936 
    937 static int qt_native_select(fd_set *fdread, fd_set *fdwrite, int timeout)
    938 {
    939     struct timeval tv;
    940     tv.tv_sec = timeout / 1000;
    941     tv.tv_usec = (timeout % 1000) * 1000;
    942 
    943     int ret;
    944     do {
    945         ret = select(FD_SETSIZE, fdread, fdwrite, 0, timeout < 0 ? 0 : &tv);
    946     } while (ret < 0 && (errno == EINTR));
    947     return ret;
     529        DosKillProcess(DKP_PROCESS, pid);
    948530}
    949531
     
    961543}
    962544
     545static int qt_select(fd_set *fdread, fd_set *fdwrite, int timeout)
     546{
     547    struct timeval tv;
     548    tv.tv_sec = timeout / 1000;
     549    tv.tv_usec = (timeout % 1000) * 1000;
     550
     551    int ret = select(FD_SETSIZE, fdread, fdwrite, 0, timeout < 0 ? 0 : &tv);
     552    return ret;
     553}
     554
    963555bool QProcessPrivate::waitForStarted(int msecs)
    964556{
    965557    Q_Q(QProcess);
    966558
    967 #if defined (QPROCESS_DEBUG)
    968     qDebug("QProcessPrivate::waitForStarted(%d) waiting for child to start (fd = %d)", msecs,
    969            childStartedPipe[0]);
    970 #endif
    971 
    972     fd_set fds;
    973     FD_ZERO(&fds);
    974     FD_SET(childStartedPipe[0], &fds);
    975     int ret;
    976     do {
    977         ret = qt_native_select(&fds, 0, msecs);
    978     } while (ret < 0 && errno == EINTR);
    979     if (ret == 0) {
    980         processError = QProcess::Timedout;
    981         q->setErrorString(QProcess::tr("Process operation timed out"));
    982 #if defined (QPROCESS_DEBUG)
    983         qDebug("QProcessPrivate::waitForStarted(%d) == false (timed out)", msecs);
    984 #endif
     559    if (processStarted())
     560        return true;
     561
     562    if (processError == QProcess::FailedToStart)
    985563        return false;
    986     }
    987 
    988     bool startedEmitted = _q_startupNotification();
    989 #if defined (QPROCESS_DEBUG)
    990     qDebug("QProcessPrivate::waitForStarted() == %s", startedEmitted ? "true" : "false");
    991 #endif
    992     return startedEmitted;
     564
     565    processError = QProcess::Timedout;
     566    q->setErrorString(QProcess::tr("Process operation timed out"));
     567    return false;
    993568}
    994569
     
    1009584        FD_ZERO(&fdread);
    1010585        FD_ZERO(&fdwrite);
    1011 
    1012         if (processState == QProcess::Starting)
    1013             FD_SET(childStartedPipe[0], &fdread);
    1014586
    1015587        if (stdoutChannel.pipe[0] != -1)
     
    1018590            FD_SET(stderrChannel.pipe[0], &fdread);
    1019591
    1020         FD_SET(deathPipe[0], &fdread);
    1021 
    1022592        if (!writeBuffer.isEmpty() && stdinChannel.pipe[1] != -1)
    1023593            FD_SET(stdinChannel.pipe[1], &fdwrite);
    1024594
    1025595        int timeout = qt_timeout_value(msecs, stopWatch.elapsed());
    1026         int ret = qt_native_select(&fdread, &fdwrite, timeout);
     596        int ret = qt_select(&fdread, &fdwrite, timeout);
    1027597        if (ret < 0) {
    1028             if (errno == EINTR)
    1029                 continue;
    1030598            break;
    1031599        }
     
    1033601            processError = QProcess::Timedout;
    1034602            q->setErrorString(QProcess::tr("Process operation timed out"));
    1035             return false;
    1036         }
    1037 
    1038         if (childStartedPipe[0] != -1 && FD_ISSET(childStartedPipe[0], &fdread)) {
    1039             if (!_q_startupNotification())
    1040                 return false;
    1041         }
     603            return false;
     604        }
    1042605
    1043606        bool readyReadEmitted = false;
    1044         if (stdoutChannel.pipe[0] != -1 && FD_ISSET(stdoutChannel.pipe[0], &fdread)) {
    1045             bool canRead = _q_canReadStandardOutput();
     607        if (stdoutChannel.pipe[0] != -1 && FD_ISSET(stdoutChannel.pipe[0], &fdread)) {
     608            bool canRead = _q_canReadStandardOutput();
    1046609            if (processChannel == QProcess::StandardOutput && canRead)
    1047610                readyReadEmitted = true;
    1048         }
    1049         if (stderrChannel.pipe[0] != -1 && FD_ISSET(stderrChannel.pipe[0], &fdread)) {
    1050             bool canRead = _q_canReadStandardError();
     611        }
     612        if (stderrChannel.pipe[0] != -1 && FD_ISSET(stderrChannel.pipe[0], &fdread)) {
     613            bool canRead = _q_canReadStandardError();
    1051614            if (processChannel == QProcess::StandardError && canRead)
    1052615                readyReadEmitted = true;
    1053         }
     616        }
    1054617        if (readyReadEmitted)
    1055618            return true;
    1056619
    1057         if (stdinChannel.pipe[1] != -1 && FD_ISSET(stdinChannel.pipe[1], &fdwrite))
    1058             _q_canWrite();
    1059 
    1060         if (deathPipe[0] == -1 || FD_ISSET(deathPipe[0], &fdread)) {
    1061             if (_q_processDied())
    1062                 return false;
    1063         }
     620        if (stdinChannel.pipe[1] != -1 && FD_ISSET(stdinChannel.pipe[1], &fdwrite))
     621            _q_canWrite();
     622
     623        if (!pid)
     624            return false;
     625        if (_q_processDied())
     626            return false;
    1064627    }
    1065628    return false;
     
    1082645        FD_ZERO(&fdread);
    1083646        FD_ZERO(&fdwrite);
    1084 
    1085         if (processState == QProcess::Starting)
    1086             FD_SET(childStartedPipe[0], &fdread);
    1087647
    1088648        if (stdoutChannel.pipe[0] != -1)
     
    1091651            FD_SET(stderrChannel.pipe[0], &fdread);
    1092652
    1093         FD_SET(deathPipe[0], &fdread);
    1094 
    1095653        if (!writeBuffer.isEmpty() && stdinChannel.pipe[1] != -1)
    1096654            FD_SET(stdinChannel.pipe[1], &fdwrite);
    1097655
    1098         int timeout = qt_timeout_value(msecs, stopWatch.elapsed());
    1099         int ret = qt_native_select(&fdread, &fdwrite, timeout);
     656        int timeout = qt_timeout_value(msecs, stopWatch.elapsed());
     657        int ret = qt_select(&fdread, &fdwrite, timeout);
    1100658        if (ret < 0) {
    1101             if (errno == EINTR)
    1102                 continue;
    1103659            break;
    1104660        }
    1105 
    1106661        if (ret == 0) {
    1107             processError = QProcess::Timedout;
    1108             q->setErrorString(QProcess::tr("Process operation timed out"));
    1109             return false;
    1110         }
    1111 
    1112         if (childStartedPipe[0] != -1 && FD_ISSET(childStartedPipe[0], &fdread)) {
    1113             if (!_q_startupNotification())
    1114                 return false;
    1115         }
    1116 
    1117         if (stdinChannel.pipe[1] != -1 && FD_ISSET(stdinChannel.pipe[1], &fdwrite))
    1118             return _q_canWrite();
    1119 
    1120         if (stdoutChannel.pipe[0] != -1 && FD_ISSET(stdoutChannel.pipe[0], &fdread))
    1121             _q_canReadStandardOutput();
    1122 
    1123         if (stderrChannel.pipe[0] != -1 && FD_ISSET(stderrChannel.pipe[0], &fdread))
    1124             _q_canReadStandardError();
    1125 
    1126         if (deathPipe[0] == -1 || FD_ISSET(deathPipe[0], &fdread)) {
    1127             if (_q_processDied())
    1128                 return false;
    1129         }
     662            processError = QProcess::Timedout;
     663            q->setErrorString(QProcess::tr("Process operation timed out"));
     664            return false;
     665        }
     666
     667        if (stdinChannel.pipe[1] != -1 && FD_ISSET(stdinChannel.pipe[1], &fdwrite))
     668            return _q_canWrite();
     669
     670        if (stdoutChannel.pipe[0] != -1 && FD_ISSET(stdoutChannel.pipe[0], &fdread))
     671            _q_canReadStandardOutput();
     672
     673        if (stderrChannel.pipe[0] != -1 && FD_ISSET(stderrChannel.pipe[0], &fdread))
     674            _q_canReadStandardError();
     675
     676        if (!pid)
     677            return false;
     678        if (_q_processDied())
     679            return false;
    1130680    }
    1131681
     
    1149699        FD_ZERO(&fdread);
    1150700        FD_ZERO(&fdwrite);
    1151 
    1152         if (processState == QProcess::Starting)
    1153             FD_SET(childStartedPipe[0], &fdread);
    1154701
    1155702        if (stdoutChannel.pipe[0] != -1)
     
    1158705            FD_SET(stderrChannel.pipe[0], &fdread);
    1159706
    1160         if (processState == QProcess::Running)
    1161             FD_SET(deathPipe[0], &fdread);
    1162 
    1163707        if (!writeBuffer.isEmpty() && stdinChannel.pipe[1] != -1)
    1164708            FD_SET(stdinChannel.pipe[1], &fdwrite);
    1165709
    1166         int timeout = qt_timeout_value(msecs, stopWatch.elapsed());
    1167         int ret = qt_native_select(&fdread, &fdwrite, timeout);
     710        int timeout = qt_timeout_value(msecs, stopWatch.elapsed());
     711        int ret = qt_select(&fdread, &fdwrite, timeout);
    1168712        if (ret < 0) {
    1169             if (errno == EINTR)
    1170                 continue;
    1171713            break;
    1172714        }
    1173         if (ret == 0) {
    1174             processError = QProcess::Timedout;
    1175             q->setErrorString(QProcess::tr("Process operation timed out"));
    1176             return false;
    1177         }
    1178 
    1179         if (childStartedPipe[0] != -1 && FD_ISSET(childStartedPipe[0], &fdread)) {
    1180             if (!_q_startupNotification())
    1181                 return false;
    1182         }
    1183         if (stdinChannel.pipe[1] != -1 && FD_ISSET(stdinChannel.pipe[1], &fdwrite))
    1184             _q_canWrite();
    1185 
    1186         if (stdoutChannel.pipe[0] != -1 && FD_ISSET(stdoutChannel.pipe[0], &fdread))
    1187             _q_canReadStandardOutput();
    1188 
    1189         if (stderrChannel.pipe[0] != -1 && FD_ISSET(stderrChannel.pipe[0], &fdread))
    1190             _q_canReadStandardError();
    1191 
    1192         if (deathPipe[0] == -1 || FD_ISSET(deathPipe[0], &fdread)) {
    1193             if (_q_processDied())
    1194                 return true;
    1195         }
     715        if (ret == 0) {
     716            processError = QProcess::Timedout;
     717            q->setErrorString(QProcess::tr("Process operation timed out"));
     718            return false;
     719        }
     720
     721        if (stdinChannel.pipe[1] != -1 && FD_ISSET(stdinChannel.pipe[1], &fdwrite))
     722            _q_canWrite();
     723
     724        if (stdoutChannel.pipe[0] != -1 && FD_ISSET(stdoutChannel.pipe[0], &fdread))
     725            _q_canReadStandardOutput();
     726
     727        if (stderrChannel.pipe[0] != -1 && FD_ISSET(stderrChannel.pipe[0], &fdread))
     728            _q_canReadStandardError();
     729
     730        if (!pid)
     731            return true;
     732        if (_q_processDied())
     733            return true;
    1196734    }
    1197735    return false;
     
    1204742    FD_SET(stdinChannel.pipe[1], &fdwrite);
    1205743
    1206     int ret;
    1207     do {
    1208         ret = qt_native_select(0, &fdwrite, msecs < 0 ? 0 : msecs) == 1;
    1209     } while (ret < 0 && errno == EINTR);
     744    int ret = qt_select(0, &fdwrite, msecs < 0 ? 0 : msecs) == 1;
    1210745    return ret == 1;
    1211746}
     
    1213748void QProcessPrivate::findExitCode()
    1214749{
    1215     Q_Q(QProcess);
    1216     processManager()->remove(q);
    1217750}
    1218751
    1219752bool QProcessPrivate::waitForDeadChild()
    1220753{
    1221     Q_Q(QProcess);
    1222 
    1223     // read a byte from the death pipe
    1224     char c;
    1225     qt_native_read(deathPipe[0], &c, 1);
    1226 
    1227754    // check if our process is dead
    1228755    int exitStatus;
    1229     pid_t waitResult = 0;
    1230     do {
    1231         waitResult = waitpid(pid_t(pid), &exitStatus, WNOHANG);
    1232     } while ((waitResult == -1 && errno == EINTR));
     756    pid_t waitResult = waitpid(pid, &exitStatus, WNOHANG);
    1233757    if (waitResult > 0) {
    1234         processManager()->remove(q);
    1235758        crashed = !WIFEXITED(exitStatus);
    1236759        exitCode = WEXITSTATUS(exitStatus);
     
    1255778bool QProcessPrivate::startDetached(const QString &program, const QStringList &arguments, const QString &workingDirectory, qint64 *pid)
    1256779{
     780// @todo later
     781#if 0
    1257782    processManager()->start();
    1258783
     
    1367892    qt_native_close(pidPipe[0]);
    1368893    return success;
    1369 }
    1370 
    1371 void QProcessPrivate::initializeProcessManager()
    1372 {
    1373     (void) processManager();
     894#endif
    1374895}
    1375896
    1376897QT_END_NAMESPACE
    1377898
    1378 #include "qprocess_unix.moc"
    1379 
    1380899#endif // QT_NO_PROCESS
  • TabularUnified trunk/src/corelib/io/qprocess_p.h

    r71 r72  
    5959#include "private/qiodevice_p.h"
    6060
    61 #if defined(Q_OS_WIN)
     61#ifdef Q_OS_WIN
    6262#include "QtCore/qt_windows.h"
    6363typedef HANDLE Q_PIPE;
    6464#define INVALID_Q_PIPE INVALID_HANDLE_VALUE
    65 #elif defined(Q_OS_OS2)
    66 #include "QtCore/qt_os2.h"
    67 #define HP_NULL HPIPE(~0)
    68 #define HF_NULL HFILE(~0)
    6965#else
    7066typedef int Q_PIPE;
     
    9793        Channel() : process(0), notifier(0), type(Normal), closed(false), append(false)
    9894        {
    99 #if !defined(Q_OS_OS2)
    10095            pipe[0] = INVALID_Q_PIPE;
    10196            pipe[1] = INVALID_Q_PIPE;
    102 #else
    103             pipe = HP_NULL;
    104             file = HF_NULL;
    105 #endif
    10697        }
    10798
     
    132123        QString file;
    133124        QProcessPrivate *process;
    134 #if !defined(Q_OS_OS2)
    135125        QSocketNotifier *notifier;
    136126        Q_PIPE pipe[2];
    137 #else
    138         HPIPE pipe;
    139         HFILE file;
    140 #endif
    141127
    142128        unsigned type : 2;
     
    182168    QRingBuffer writeBuffer;
    183169
    184 #if !defined(Q_OS_OS2)
    185170    Q_PIPE childStartedPipe[2];
    186171    Q_PIPE deathPipe[2];
     
    194179    QWindowsPipeWriter *pipeWriter;
    195180    QWinEventNotifier *processFinishedNotifier;
    196 #else
    197     void destroyPipe(Channel &channel);
    198 #endif
    199181
    200182    void startProcess();
     
    206188    void killProcess();
    207189    void findExitCode();
    208 #ifdef Q_OS_UNIX
     190#if defined(Q_OS_UNIX) || defined(Q_OS_OS2)
    209191    bool waitForDeadChild();
    210192#endif
Note: See TracChangeset for help on using the changeset viewer.