- Timestamp:
- Sep 22, 2009, 10:44:03 PM (16 years ago)
- Location:
- trunk/src/corelib/io
- Files:
-
- 3 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/corelib/io/qprocess.cpp
r72 r190 437 437 serial = 0; 438 438 #endif 439 #ifdef Q_OS_OS2 440 init(); 441 #endif 439 442 } 440 443 … … 443 446 QProcessPrivate::~QProcessPrivate() 444 447 { 448 #ifdef Q_OS_OS2 449 uninit(); 450 #endif 445 451 if (stdinChannel.process) 446 452 stdinChannel.process->stdoutChannel.clear(); … … 744 750 processError = QProcess::FailedToStart; 745 751 emit q->error(processError); 746 #if def Q_OS_UNIX752 #if defined(Q_OS_UNIX) || defined(Q_OS_OS2) 747 753 // make sure the process manager removes this entry 748 754 waitForDeadChild(); … … 801 807 waitForFinished(); 802 808 } 803 #if def Q_OS_UNIX809 #if defined(Q_OS_UNIX) || defined(Q_OS_OS2) 804 810 // make sure the process manager removes this entry 805 811 d->findExitCode(); -
trunk/src/corelib/io/qprocess_os2.cpp
r181 r190 51 51 #include <ctype.h> 52 52 53 #include <qthread.h> 54 53 55 /* 54 56 Returns a human readable representation of the first \a len … … 122 124 ::fcntl(pipe[0], F_SETFD, FD_CLOEXEC); 123 125 ::fcntl(pipe[1], F_SETFD, FD_CLOEXEC); 126 } 127 128 129 class QProcessManager : public QThread 130 { 131 public: 132 133 static void addRef(); 134 static void release(); 135 136 static void addProcess(QProcess *process); 137 static void removeProcess(QProcess *process); 138 139 private: 140 141 QProcessManager(); 142 ~QProcessManager(); 143 144 void installSigHandler(); 145 void uninstallSigHandler(); 146 void run(); 147 148 int refcnt; 149 bool finish; 150 151 HEV eventSem; 152 QAtomicInt eventSemGuard; 153 154 typedef QList<QProcess *> ProcessList; 155 ProcessList processes; 156 157 void (*sa_old_sigchld_handler)(int); 158 159 static void sa_sigchld_handler(int signum); 160 161 static QProcessManager *instance; 162 static QMutex mutex; 163 }; 164 165 // static 166 QProcessManager *QProcessManager::instance = 0; 167 QMutex QProcessManager::mutex; 168 169 // static 170 void QProcessManager::sa_sigchld_handler(int signum) 171 { 172 #if defined (QPROCESS_DEBUG) 173 fprintf(stderr, "*** SIGCHLD\n"); 174 #endif 175 176 Q_ASSERT(instance); 177 178 // eventSemGuard is used as follows: 179 // 0 - QProcessManager is not operational 180 // 1 - QProcessManager is being run, eventSem is fine 181 // 2 - another signal handler is in action 182 183 if (!instance->eventSemGuard.testAndSetAcquire(1, 2)) 184 return; 185 186 APIRET rc = DosPostEventSem(instance->eventSem); 187 Q_ASSERT(rc == NO_ERROR); 188 189 instance->eventSemGuard.testAndSetRelease(2, 1); 190 191 if (instance->sa_old_sigchld_handler && 192 instance->sa_old_sigchld_handler != SIG_IGN) 193 instance->sa_old_sigchld_handler(signum); 194 } 195 196 // static 197 void QProcessManager::addRef() 198 { 199 QMutexLocker locker(&mutex); 200 201 if (instance == 0) { 202 instance = new QProcessManager(); 203 } 204 205 ++instance->refcnt; 206 } 207 208 // static 209 void QProcessManager::release() 210 { 211 QMutexLocker locker(&mutex); 212 213 Q_ASSERT(instance); 214 215 if (--instance->refcnt == 0) { 216 // make sure we don't globally exist anymore before leaving the lock 217 QProcessManager *instance = QProcessManager::instance; 218 QProcessManager::instance = 0; 219 // disable the signal handler 220 while (!instance->eventSemGuard.testAndSetAcquire(1, 0)) 221 DosSleep(0); 222 instance->uninstallSigHandler(); 223 // stop the thread 224 instance->finish = true; 225 locker.unlock(); 226 DosPostEventSem(instance->eventSem); 227 instance->wait(); 228 delete instance; 229 } 230 } 231 232 // static 233 void QProcessManager::addProcess(QProcess *process) 234 { 235 #if defined (QPROCESS_DEBUG) 236 qDebug() << "QProcessManager::addProcess()"; 237 #endif 238 239 QMutexLocker locker(&mutex); 240 Q_ASSERT(instance); 241 242 // lazily enable SIGCHLD handler and start the worker 243 if (instance->eventSemGuard.testAndSetAcquire(0, 1)) { 244 instance->installSigHandler(); 245 instance->start(); 246 } 247 248 instance->processes.append(process); 249 } 250 251 // static 252 void QProcessManager::removeProcess(QProcess *process) 253 { 254 #if defined (QPROCESS_DEBUG) 255 qDebug() << "QProcessManager::removeProcess()"; 256 #endif 257 258 QMutexLocker locker(&mutex); 259 Q_ASSERT(instance); 260 261 instance->processes.removeAll(process); 262 } 263 264 QProcessManager::QProcessManager() 265 : refcnt(0), finish(false), eventSem(NULLHANDLE), sa_old_sigchld_handler(0) 266 { 267 #if defined (QPROCESS_DEBUG) 268 qDebug() << "QProcessManager::QProcessManager()"; 269 #endif 270 271 APIRET rc = DosCreateEventSem(NULL, &eventSem, DCE_AUTORESET | DCE_POSTONE, FALSE); 272 Q_ASSERT(rc == NO_ERROR); 273 } 274 275 QProcessManager::~QProcessManager() 276 { 277 #if defined (QPROCESS_DEBUG) 278 qDebug() << "QProcessManager::~QProcessManager()"; 279 #endif 280 281 Q_ASSERT(!refcnt); 282 Q_ASSERT(!processes.size()); 283 284 DosCloseEventSem(eventSem); 285 } 286 287 void QProcessManager::installSigHandler() 288 { 289 // set up the SIGCHLD handler, which calls _q_processDied on all 290 // known QProcessPrivate instances every time a child dies. 291 struct sigaction oldAction; 292 struct sigaction action; 293 memset(&action, 0, sizeof(action)); 294 action.sa_handler = sa_sigchld_handler; 295 action.sa_flags = SA_NOCLDSTOP; 296 ::sigaction(SIGCHLD, &action, &oldAction); 297 if (oldAction.sa_handler != sa_sigchld_handler) 298 sa_old_sigchld_handler = oldAction.sa_handler; 299 } 300 301 void QProcessManager::uninstallSigHandler() 302 { 303 struct sigaction oldAction; 304 struct sigaction action; 305 memset(&action, 0, sizeof(action)); 306 action.sa_handler = sa_old_sigchld_handler; 307 action.sa_flags = SA_NOCLDSTOP; 308 ::sigaction(SIGCHLD, &action, &oldAction); 309 if (oldAction.sa_handler != sa_sigchld_handler) { 310 ::sigaction(SIGCHLD, &oldAction, 0); 311 } 312 } 313 314 void QProcessManager::run() 315 { 316 #if defined (QPROCESS_DEBUG) 317 qDebug() << "QProcessManager::run() BEGIN"; 318 #endif 319 320 // Note: the rationale behind using a worker thread so far is that 321 // calling complex functions from a signal handler is not really a good 322 // idea unless there is a 100% guarantee that they are reentrant. So, the 323 // handler only posts a semaphore (I *hope* DosPostEventSem is reentrant) 324 // and all complex work is done here asynchronously. 325 326 QMutexLocker locker(&mutex); 327 APIRET arc; 328 329 do { 330 locker.unlock(); 331 arc = DosWaitEventSem(eventSem, SEM_INDEFINITE_WAIT); 332 locker.relock(); 333 if (finish) 334 break; 335 336 #if defined (QPROCESS_DEBUG) 337 qDebug() << "QProcessManager::run() signaled"; 338 #endif 339 foreach (QProcess *proc, processes) { 340 QMetaObject::invokeMethod(proc, "_q_processDied", Qt::QueuedConnection); 341 } 342 343 } while (true); 344 345 #if defined (QPROCESS_DEBUG) 346 qDebug() << "QProcessManager::run() END"; 347 #endif 348 } 349 350 351 void QProcessPrivate::init() 352 { 353 QProcessManager::addRef(); 354 } 355 356 void QProcessPrivate::uninit() 357 { 358 QProcessManager::release(); 124 359 } 125 360 … … 372 607 return; 373 608 609 QProcessManager::addProcess(q); 610 374 611 // Start the process (platform dependent) 375 612 q->setProcessState(QProcess::Starting); … … 424 661 .arg(qPrintable(qt_error_string(errno)))); 425 662 emit q->error(processError); 663 removeProcess(q); 426 664 cleanup(); 427 665 return; … … 452 690 ::fcntl(stderrChannel.pipe[0], F_SETFL, ::fcntl(stderrChannel.pipe[0], F_GETFL) | O_NONBLOCK); 453 691 454 q->setProcessState(QProcess::Running);455 // User can call kill()/terminate() from the stateChanged() slot456 // so check before proceeding457 if (!pid)458 return;459 460 692 // give the process a chance to start ... 461 693 DosSleep(100); 694 462 695 _q_startupNotification(); 463 696 } … … 465 698 bool QProcessPrivate::processStarted() 466 699 { 467 return processState == QProcess::Running; 700 // we don't actually wait for any notification from the child process 701 // assuming it has been started as long as spawnvpe() returns success 702 return processState == QProcess::Starting; 468 703 } 469 704 … … 589 824 Q_Q(QProcess); 590 825 591 if (processSta rted())826 if (processState == QProcess::Running) 592 827 return true; 593 828 … … 820 1055 void QProcessPrivate::findExitCode() 821 1056 { 1057 // note: this method is unconditionally called from QProcess destructor 1058 // to make sure the process manager removes the watcher even in such a rare 1059 // case when the process is still running after killing it and waiting 1060 // for termination (in which case the child termination code path that 1061 // normally calls findExitCode() won't be walked) 1062 1063 Q_Q(QProcess); 1064 QProcessManager::removeProcess(q); 822 1065 } 823 1066 … … 838 1081 #if defined QPROCESS_DEBUG 839 1082 qDebug() << "QProcessPrivate::waitForDeadChild() not dead!"; 1083 if (waitResult == -1) 1084 qDebug() << "QProcessPrivate::waitForDeadChild()" << strerror(errno); 840 1085 #endif 841 1086 return false; -
trunk/src/corelib/io/qprocess_p.h
r72 r190 195 195 qint64 pipeWriterBytesToWrite() const; 196 196 #endif 197 #ifdef Q_OS_OS2 198 void init(); 199 void uninit(); 200 #endif 197 201 198 202 static bool startDetached(const QString &program, const QStringList &arguments, const QString &workingDirectory = QString(),
Note:
See TracChangeset
for help on using the changeset viewer.