Changeset 72
- Timestamp:
- Jul 9, 2009, 1:43:12 PM (16 years ago)
- Location:
- trunk/src/corelib/io
- Files:
-
- 4 edited
- 1 copied
Legend:
- Unmodified
- Added
- Removed
-
TabularUnified trunk/src/corelib/io/io.pri ¶
r60 r72 62 62 } else:os2 { 63 63 SOURCES += io/qsettings_os2.cpp 64 # @todo later 65 # SOURCES += io/qprocess_os2.cpp 64 SOURCES += io/qprocess_os2.cpp 66 65 SOURCES += io/qfsfileengine_os2.cpp 67 66 -
TabularUnified trunk/src/corelib/io/qprocess.cpp ¶
r71 r72 231 231 \snippet doc/src/snippets/process/process.cpp 0 232 232 233 \section1 Notes for Windows Users234 235 Some Windows commands (for example, \c dir) are not provided by236 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. 237 237 If you attempt to use QProcess to execute these commands directly, 238 238 it won't work. One possible solution is to execute the command … … 413 413 processError = QProcess::UnknownError; 414 414 processState = QProcess::NotRunning; 415 #ifdef Q_OS_OS2416 pid = PID_NULL;417 #else418 415 pid = 0; 419 #endif420 416 sequenceNumber = 0; 421 417 exitCode = 0; … … 458 454 { 459 455 q_func()->setProcessState(QProcess::NotRunning); 460 #if !defined(Q_OS_OS2)461 456 #ifdef Q_OS_WIN 462 457 if (pid) { … … 474 469 #endif 475 470 pid = 0; 476 #else477 pid = PID_NULL;478 #endif479 471 sequenceNumber = 0; 480 472 dying = false; 481 473 482 #if !defined(Q_OS_OS2)483 474 if (stdoutChannel.notifier) { 484 475 stdoutChannel.notifier->setEnabled(false); … … 513 504 destroyPipe(stderrChannel.pipe); 514 505 destroyPipe(stdinChannel.pipe); 515 #else516 destroyPipe(stdoutChannel);517 destroyPipe(stderrChannel);518 destroyPipe(stdinChannel);519 #endif520 #if !defined(Q_OS_OS2)521 506 destroyPipe(childStartedPipe); 522 507 destroyPipe(deathPipe); 523 #endif524 508 #ifdef Q_OS_UNIX 525 509 serial = 0; … … 534 518 qint64 available = bytesAvailableFromStdout(); 535 519 if (available == 0) { 536 #if !defined(Q_OS_OS2)537 520 if (stdoutChannel.notifier) 538 521 stdoutChannel.notifier->setEnabled(false); 539 522 destroyPipe(stdoutChannel.pipe); 540 #else541 destroyPipe(stdoutChannel);542 #endif543 523 #if defined QPROCESS_DEBUG 544 524 qDebug("QProcessPrivate::canReadStandardOutput(), 0 bytes available"); … … 593 573 qint64 available = bytesAvailableFromStderr(); 594 574 if (available == 0) { 595 #if !defined(Q_OS_OS2)596 575 if (stderrChannel.notifier) 597 576 stderrChannel.notifier->setEnabled(false); 598 577 destroyPipe(stderrChannel.pipe); 599 #else600 destroyPipe(stderrChannel);601 #endif602 578 return false; 603 579 } … … 652 628 writeBuffer.nextDataBlockSize()); 653 629 if (written < 0) { 654 #if !defined(Q_OS_OS2)655 630 destroyPipe(stdinChannel.pipe); 656 #else657 destroyPipe(stdinChannel);658 #endif659 631 processError = QProcess::WriteError; 660 632 q->setErrorString(QProcess::tr("Error writing to process")); … … 691 663 qDebug("QProcessPrivate::_q_processDied()"); 692 664 #endif 693 #if def Q_OS_UNIX665 #if defined(Q_OS_UNIX) || defined(Q_OS_OS2) 694 666 if (!waitForDeadChild()) 695 667 return false; … … 801 773 flushPipeWriter(); 802 774 #endif 803 #if !defined(Q_OS_OS2)804 775 destroyPipe(stdinChannel.pipe); 805 #else806 destroyPipe(stdinChannel);807 #endif808 776 } 809 777 … … 1107 1075 /*! 1108 1076 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. 1111 1078 */ 1112 1079 Q_PID QProcess::pid() const -
TabularUnified trunk/src/corelib/io/qprocess.h ¶
r71 r72 57 57 typedef qint64 Q_PID; 58 58 #elif defined(Q_OS_OS2) 59 typedef PID Q_PID; 60 #define PID_NULL PID(~0) 59 typedef int Q_PID; 61 60 #else 62 61 QT_END_NAMESPACE -
TabularUnified trunk/src/corelib/io/qprocess_os2.cpp ¶
r63 r72 3 3 ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). 4 4 ** Contact: Qt Software Information (qt-info@nokia.com) 5 ** 6 ** Copyright (C) 2009 netlabs.org. OS/2 parts. 5 7 ** 6 8 ** This file is part of the QtCore module of the Qt Toolkit. … … 86 88 #include "qprocess_p.h" 87 89 88 #ifdef Q_OS_MAC 89 #include <private/qcore_mac_p.h> 90 #endif 90 #include <QtCore/qt_os2.h> 91 91 92 92 #include <private/qcoreapplication_p.h> … … 100 100 #include <qsemaphore.h> 101 101 #include <qsocketnotifier.h> 102 #include <q thread.h>102 #include <qdir.h> 103 103 104 104 #include <errno.h> 105 #include <stdlib.h> 106 #include <string.h> 105 #include <sys/filio.h> 107 106 108 107 QT_BEGIN_NAMESPACE 109 108 110 #ifdef Q_OS_INTEGRITY111 static inline char *strdup(const char *data)112 {113 return qstrdup(data);114 }115 #endif116 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 #endif201 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 QThread215 {216 Q_OBJECT217 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 #endif240 // initialize the dead child pipe and make it non-blocking. in the241 // extremely unlikely event that the pipe fills up, we do not under any242 // 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 dead252 // 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 cause271 // 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 #endif301 302 // block forever, or until activity is detected on the dead child303 // pipe. the only other peers are the SIGCHLD signal handler, and the304 // 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 SIGCHLD313 // signals may have been delivered in the meantime, to avoid race314 // 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 whose329 // 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 run333 // 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 #endif340 ++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 #endif351 352 // insert a new info structure for this process353 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 #endif376 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 391 109 static void qt_create_pipe(int *pipe) 392 110 { 393 111 if (pipe[0] != -1) 394 qt_native_close(pipe[0]);112 ::close(pipe[0]); 395 113 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]); 403 115 if (::pipe(pipe) != 0) { 404 116 qWarning("QProcessPrivate::createPipe: Cannot create pipe %p: %s", 405 117 pipe, qPrintable(qt_error_string(errno))); 406 118 } 407 #endif408 119 ::fcntl(pipe[0], F_SETFD, FD_CLOEXEC); 409 120 ::fcntl(pipe[1], F_SETFD, FD_CLOEXEC); … … 413 124 { 414 125 if (pipe[1] != -1) { 415 qt_native_close(pipe[1]);126 ::close(pipe[1]); 416 127 pipe[1] = -1; 417 128 } 418 129 if (pipe[0] != -1) { 419 qt_native_close(pipe[0]);130 ::close(pipe[0]); 420 131 pipe[0] = -1; 421 132 } … … 470 181 // try to open in read-only mode 471 182 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) 473 184 return true; // success 474 185 … … 482 193 483 194 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) 485 196 return true; // success 486 197 … … 532 243 } 533 244 534 static char **_q_dupEnvironment(const QStringList &environment, int *envc)535 {536 // if LD_LIBRARY_PATH exists in the current environment, but537 // not in the environment list passed by the programmer, then538 // copy it over.539 #if defined(Q_OS_MAC)540 static const char libraryPath[] = "DYLD_LIBRARY_PATH";541 #else542 static const char libraryPath[] = "LD_LIBRARY_PATH";543 #endif544 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 multithreading569 inline pid_t qt_fork()570 {571 #if defined(Q_OS_QNX)572 return vfork();573 #else574 return fork();575 #endif576 }577 578 #ifdef Q_OS_MAC579 Q_GLOBAL_STATIC(QMutex, cfbundleMutex);580 #endif581 582 245 void QProcessPrivate::startProcess() 583 246 { … … 588 251 #endif 589 252 590 processManager()->start();591 592 253 // 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 611 254 if (!createChannel(stdinChannel) || 612 255 !createChannel(stdoutChannel) || … … 617 260 q->setProcessState(QProcess::Starting); 618 261 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 619 281 // Create argument list with right number of elements, and set the final 620 282 // one to 0. … … 624 286 // Encode the program name. 625 287 QByteArray encodedProgramName = QFile::encodeName(program); 626 #ifdef Q_OS_MAC627 // 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 reference635 // 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 #endif646 288 647 289 // Add the program name to the argument list. 648 char *dupProgramName = ::strdup(encodedProgramName.constData()); 649 argv[0] = dupProgramName; 290 argv[0] = encodedProgramName.data(); 650 291 651 292 // Add every argument to the list 652 293 for (int i = 0; i < arguments.count(); ++i) { 653 294 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()); 660 296 } 661 297 662 298 // Duplicate the environment. 663 299 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; 669 336 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) { 706 363 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) { 715 386 // Cleanup, report error and return 716 387 #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 720 390 q->setProcessState(QProcess::NotRunning); 721 391 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))); 723 393 emit q->error(processError); 724 394 cleanup(); … … 726 396 } 727 397 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 741 400 // 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 746 401 if (stdinChannel.pipe[0] != -1) { 747 qt_native_close(stdinChannel.pipe[0]);402 ::close(stdinChannel.pipe[0]); 748 403 stdinChannel.pipe[0] = -1; 749 404 } 750 751 405 if (stdinChannel.pipe[1] != -1) 752 406 ::fcntl(stdinChannel.pipe[1], F_SETFL, ::fcntl(stdinChannel.pipe[1], F_GETFL) | O_NONBLOCK); 753 407 754 408 if (stdoutChannel.pipe[1] != -1) { 755 qt_native_close(stdoutChannel.pipe[1]);409 ::close(stdoutChannel.pipe[1]); 756 410 stdoutChannel.pipe[1] = -1; 757 411 } 758 759 412 if (stdoutChannel.pipe[0] != -1) 760 413 ::fcntl(stdoutChannel.pipe[0], F_SETFL, ::fcntl(stdoutChannel.pipe[0], F_GETFL) | O_NONBLOCK); 761 414 762 415 if (stderrChannel.pipe[1] != -1) { 763 qt_native_close(stderrChannel.pipe[1]);416 ::close(stderrChannel.pipe[1]); 764 417 stderrChannel.pipe[1] = -1; 765 418 } 766 419 if (stderrChannel.pipe[0] != -1) 767 420 ::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(); 831 431 } 832 432 833 433 bool QProcessPrivate::processStarted() 834 434 { 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; 849 436 } 850 437 … … 875 462 qint64 QProcessPrivate::readFromStdout(char *data, qint64 maxlen) 876 463 { 877 qint64 bytesRead = qt_native_read(stdoutChannel.pipe[0], data, maxlen);464 qint64 bytesRead = ::read(stdoutChannel.pipe[0], data, maxlen); 878 465 #if defined QPROCESS_DEBUG 879 466 qDebug("QProcessPrivate::readFromStdout(%p \"%s\", %lld) == %lld", … … 885 472 qint64 QProcessPrivate::readFromStderr(char *data, qint64 maxlen) 886 473 { 887 qint64 bytesRead = qt_native_read(stderrChannel.pipe[0], data, maxlen);474 qint64 bytesRead = ::read(stderrChannel.pipe[0], data, maxlen); 888 475 #if defined QPROCESS_DEBUG 889 476 qDebug("QProcessPrivate::readFromStderr(%p \"%s\", %lld) == %lld", … … 893 480 } 894 481 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 907 482 qint64 QProcessPrivate::writeToStdin(const char *data, qint64 maxlen) 908 483 { 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); 912 485 #if defined QPROCESS_DEBUG 913 486 qDebug("QProcessPrivate::writeToStdin(%p \"%s\", %lld) == %lld", … … 920 493 { 921 494 #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 } 926 521 } 927 522 … … 932 527 #endif 933 528 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); 948 530 } 949 531 … … 961 543 } 962 544 545 static 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 963 555 bool QProcessPrivate::waitForStarted(int msecs) 964 556 { 965 557 Q_Q(QProcess); 966 558 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) 985 563 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; 993 568 } 994 569 … … 1009 584 FD_ZERO(&fdread); 1010 585 FD_ZERO(&fdwrite); 1011 1012 if (processState == QProcess::Starting)1013 FD_SET(childStartedPipe[0], &fdread);1014 586 1015 587 if (stdoutChannel.pipe[0] != -1) … … 1018 590 FD_SET(stderrChannel.pipe[0], &fdread); 1019 591 1020 FD_SET(deathPipe[0], &fdread);1021 1022 592 if (!writeBuffer.isEmpty() && stdinChannel.pipe[1] != -1) 1023 593 FD_SET(stdinChannel.pipe[1], &fdwrite); 1024 594 1025 595 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); 1027 597 if (ret < 0) { 1028 if (errno == EINTR)1029 continue;1030 598 break; 1031 599 } … … 1033 601 processError = QProcess::Timedout; 1034 602 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 } 1042 605 1043 606 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(); 1046 609 if (processChannel == QProcess::StandardOutput && canRead) 1047 610 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(); 1051 614 if (processChannel == QProcess::StandardError && canRead) 1052 615 readyReadEmitted = true; 1053 }616 } 1054 617 if (readyReadEmitted) 1055 618 return true; 1056 619 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; 1064 627 } 1065 628 return false; … … 1082 645 FD_ZERO(&fdread); 1083 646 FD_ZERO(&fdwrite); 1084 1085 if (processState == QProcess::Starting)1086 FD_SET(childStartedPipe[0], &fdread);1087 647 1088 648 if (stdoutChannel.pipe[0] != -1) … … 1091 651 FD_SET(stderrChannel.pipe[0], &fdread); 1092 652 1093 FD_SET(deathPipe[0], &fdread);1094 1095 653 if (!writeBuffer.isEmpty() && stdinChannel.pipe[1] != -1) 1096 654 FD_SET(stdinChannel.pipe[1], &fdwrite); 1097 655 1098 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); 1100 658 if (ret < 0) { 1101 if (errno == EINTR)1102 continue;1103 659 break; 1104 660 } 1105 1106 661 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; 1130 680 } 1131 681 … … 1149 699 FD_ZERO(&fdread); 1150 700 FD_ZERO(&fdwrite); 1151 1152 if (processState == QProcess::Starting)1153 FD_SET(childStartedPipe[0], &fdread);1154 701 1155 702 if (stdoutChannel.pipe[0] != -1) … … 1158 705 FD_SET(stderrChannel.pipe[0], &fdread); 1159 706 1160 if (processState == QProcess::Running)1161 FD_SET(deathPipe[0], &fdread);1162 1163 707 if (!writeBuffer.isEmpty() && stdinChannel.pipe[1] != -1) 1164 708 FD_SET(stdinChannel.pipe[1], &fdwrite); 1165 709 1166 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); 1168 712 if (ret < 0) { 1169 if (errno == EINTR)1170 continue;1171 713 break; 1172 714 } 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; 1196 734 } 1197 735 return false; … … 1204 742 FD_SET(stdinChannel.pipe[1], &fdwrite); 1205 743 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; 1210 745 return ret == 1; 1211 746 } … … 1213 748 void QProcessPrivate::findExitCode() 1214 749 { 1215 Q_Q(QProcess);1216 processManager()->remove(q);1217 750 } 1218 751 1219 752 bool QProcessPrivate::waitForDeadChild() 1220 753 { 1221 Q_Q(QProcess);1222 1223 // read a byte from the death pipe1224 char c;1225 qt_native_read(deathPipe[0], &c, 1);1226 1227 754 // check if our process is dead 1228 755 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); 1233 757 if (waitResult > 0) { 1234 processManager()->remove(q);1235 758 crashed = !WIFEXITED(exitStatus); 1236 759 exitCode = WEXITSTATUS(exitStatus); … … 1255 778 bool QProcessPrivate::startDetached(const QString &program, const QStringList &arguments, const QString &workingDirectory, qint64 *pid) 1256 779 { 780 // @todo later 781 #if 0 1257 782 processManager()->start(); 1258 783 … … 1367 892 qt_native_close(pidPipe[0]); 1368 893 return success; 1369 } 1370 1371 void QProcessPrivate::initializeProcessManager() 1372 { 1373 (void) processManager(); 894 #endif 1374 895 } 1375 896 1376 897 QT_END_NAMESPACE 1377 898 1378 #include "qprocess_unix.moc"1379 1380 899 #endif // QT_NO_PROCESS -
TabularUnified trunk/src/corelib/io/qprocess_p.h ¶
r71 r72 59 59 #include "private/qiodevice_p.h" 60 60 61 #if defined(Q_OS_WIN)61 #ifdef Q_OS_WIN 62 62 #include "QtCore/qt_windows.h" 63 63 typedef HANDLE Q_PIPE; 64 64 #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)69 65 #else 70 66 typedef int Q_PIPE; … … 97 93 Channel() : process(0), notifier(0), type(Normal), closed(false), append(false) 98 94 { 99 #if !defined(Q_OS_OS2)100 95 pipe[0] = INVALID_Q_PIPE; 101 96 pipe[1] = INVALID_Q_PIPE; 102 #else103 pipe = HP_NULL;104 file = HF_NULL;105 #endif106 97 } 107 98 … … 132 123 QString file; 133 124 QProcessPrivate *process; 134 #if !defined(Q_OS_OS2)135 125 QSocketNotifier *notifier; 136 126 Q_PIPE pipe[2]; 137 #else138 HPIPE pipe;139 HFILE file;140 #endif141 127 142 128 unsigned type : 2; … … 182 168 QRingBuffer writeBuffer; 183 169 184 #if !defined(Q_OS_OS2)185 170 Q_PIPE childStartedPipe[2]; 186 171 Q_PIPE deathPipe[2]; … … 194 179 QWindowsPipeWriter *pipeWriter; 195 180 QWinEventNotifier *processFinishedNotifier; 196 #else197 void destroyPipe(Channel &channel);198 #endif199 181 200 182 void startProcess(); … … 206 188 void killProcess(); 207 189 void findExitCode(); 208 #if def Q_OS_UNIX190 #if defined(Q_OS_UNIX) || defined(Q_OS_OS2) 209 191 bool waitForDeadChild(); 210 192 #endif
Note:
See TracChangeset
for help on using the changeset viewer.