KDECore
kprocctrl.cpp
Go to the documentation of this file.00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020 #include "kprocess.h"
00021 #include "kprocctrl.h"
00022
00023 #include <config.h>
00024
00025 #include <sys/time.h>
00026 #include <sys/types.h>
00027 #include <sys/wait.h>
00028 #include <unistd.h>
00029 #include <errno.h>
00030 #include <fcntl.h>
00031 #include <stdio.h>
00032 #include <stdlib.h>
00033
00034 #include <qsocketnotifier.h>
00035
00036 KProcessController *KProcessController::theKProcessController;
00037 int KProcessController::refCount;
00038
00039 void KProcessController::ref()
00040 {
00041 if( !refCount ) {
00042 theKProcessController = new KProcessController;
00043 setupHandlers();
00044 }
00045 refCount++;
00046 }
00047
00048 void KProcessController::deref()
00049 {
00050 refCount--;
00051 if( !refCount ) {
00052 resetHandlers();
00053 delete theKProcessController;
00054 theKProcessController = 0;
00055 }
00056 }
00057
00058 KProcessController::KProcessController()
00059 : needcheck( false )
00060 {
00061 if( pipe( fd ) )
00062 {
00063 perror( "pipe" );
00064 abort();
00065 }
00066
00067 fcntl( fd[0], F_SETFL, O_NONBLOCK );
00068 fcntl( fd[1], F_SETFL, O_NONBLOCK );
00069 fcntl( fd[0], F_SETFD, FD_CLOEXEC );
00070 fcntl( fd[1], F_SETFD, FD_CLOEXEC );
00071
00072 notifier = new QSocketNotifier( fd[0], QSocketNotifier::Read );
00073 notifier->setEnabled( true );
00074 QObject::connect( notifier, SIGNAL(activated(int)),
00075 SLOT(slotDoHousekeeping()));
00076 }
00077
00078 KProcessController::~KProcessController()
00079 {
00080 delete notifier;
00081
00082 close( fd[0] );
00083 close( fd[1] );
00084 }
00085
00086
00087 extern "C" {
00088 static void theReaper( int num )
00089 {
00090 KProcessController::theSigCHLDHandler( num );
00091 }
00092 }
00093
00094 #ifdef Q_OS_UNIX
00095 struct sigaction KProcessController::oldChildHandlerData;
00096 #endif
00097 bool KProcessController::handlerSet = false;
00098
00099 void KProcessController::setupHandlers()
00100 {
00101 if( handlerSet )
00102 return;
00103 handlerSet = true;
00104
00105 #ifdef Q_OS_UNIX
00106 struct sigaction act;
00107 sigemptyset( &act.sa_mask );
00108
00109 act.sa_handler = SIG_IGN;
00110 act.sa_flags = 0;
00111 sigaction( SIGPIPE, &act, 0L );
00112
00113 act.sa_handler = theReaper;
00114 act.sa_flags = SA_NOCLDSTOP;
00115
00116
00117 #ifdef SA_RESTART
00118 act.sa_flags |= SA_RESTART;
00119 #endif
00120 sigaction( SIGCHLD, &act, &oldChildHandlerData );
00121
00122 sigaddset( &act.sa_mask, SIGCHLD );
00123
00124 sigprocmask( SIG_UNBLOCK, &act.sa_mask, 0 );
00125 #else
00126
00127 #endif
00128 }
00129
00130 void KProcessController::resetHandlers()
00131 {
00132 if( !handlerSet )
00133 return;
00134 handlerSet = false;
00135
00136 #ifdef Q_OS_UNIX
00137 sigaction( SIGCHLD, &oldChildHandlerData, 0 );
00138 #else
00139
00140 #endif
00141
00142 }
00143
00144
00145
00146
00147 void KProcessController::theSigCHLDHandler( int arg )
00148 {
00149 int saved_errno = errno;
00150
00151 char dummy = 0;
00152 ::write( theKProcessController->fd[1], &dummy, 1 );
00153
00154 #ifdef Q_OS_UNIX
00155 if( oldChildHandlerData.sa_handler != SIG_IGN &&
00156 oldChildHandlerData.sa_handler != SIG_DFL )
00157 oldChildHandlerData.sa_handler( arg );
00158 #else
00159
00160 #endif
00161
00162 errno = saved_errno;
00163 }
00164
00165 int KProcessController::notifierFd() const
00166 {
00167 return fd[0];
00168 }
00169
00170 void KProcessController::unscheduleCheck()
00171 {
00172 char dummy[16];
00173 if( ::read( fd[0], dummy, sizeof(dummy) ) > 0 )
00174 needcheck = true;
00175 }
00176
00177 void
00178 KProcessController::rescheduleCheck()
00179 {
00180 if( needcheck )
00181 {
00182 needcheck = false;
00183 char dummy = 0;
00184 ::write( fd[1], &dummy, 1 );
00185 }
00186 }
00187
00188 void KProcessController::slotDoHousekeeping()
00189 {
00190 char dummy[16];
00191 ::read( fd[0], dummy, sizeof(dummy) );
00192
00193 int status;
00194 again:
00195 QValueListIterator<KProcess*> it( kProcessList.begin() );
00196 QValueListIterator<KProcess*> eit( kProcessList.end() );
00197 while( it != eit )
00198 {
00199 KProcess *prc = *it;
00200 if( prc->runs && waitpid( prc->pid_, &status, WNOHANG ) > 0 )
00201 {
00202 prc->processHasExited( status );
00203
00204 if (!theKProcessController)
00205 return;
00206 goto again;
00207 }
00208 ++it;
00209 }
00210 QValueListIterator<int> uit( unixProcessList.begin() );
00211 QValueListIterator<int> ueit( unixProcessList.end() );
00212 while( uit != ueit )
00213 {
00214 if( waitpid( *uit, 0, WNOHANG ) > 0 )
00215 {
00216 uit = unixProcessList.remove( uit );
00217 deref();
00218 } else
00219 ++uit;
00220 }
00221 }
00222
00223 bool KProcessController::waitForProcessExit( int timeout )
00224 {
00225 #ifdef Q_OS_UNIX
00226 for(;;)
00227 {
00228 struct timeval tv, *tvp;
00229 if (timeout < 0)
00230 tvp = 0;
00231 else
00232 {
00233 tv.tv_sec = timeout;
00234 tv.tv_usec = 0;
00235 tvp = &tv;
00236 }
00237
00238 fd_set fds;
00239 FD_ZERO( &fds );
00240 FD_SET( fd[0], &fds );
00241
00242 switch( select( fd[0]+1, &fds, 0, 0, tvp ) )
00243 {
00244 case -1:
00245 if( errno == EINTR )
00246 continue;
00247
00248 case 0:
00249 return false;
00250 default:
00251 slotDoHousekeeping();
00252 return true;
00253 }
00254 }
00255 #else
00256
00257 return false;
00258 #endif
00259 }
00260
00261 void KProcessController::addKProcess( KProcess* p )
00262 {
00263 kProcessList.append( p );
00264 }
00265
00266 void KProcessController::removeKProcess( KProcess* p )
00267 {
00268 kProcessList.remove( p );
00269 }
00270
00271 void KProcessController::addProcess( int pid )
00272 {
00273 unixProcessList.append( pid );
00274 ref();
00275 }
00276
00277 #include "kprocctrl.moc"