00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031 #include <sys/types.h>
00032 #include <sys/socket.h>
00033
00034 #include <errno.h>
00035 #include <fcntl.h>
00036 #include <stdio.h>
00037 #include <string.h>
00038 #include <unistd.h>
00039 #include <assert.h>
00040
00041 #include <qsocketnotifier.h>
00042 #include "oprocess.h"
00043 #include "oprocctrl.h"
00044
00045 OProcessController *OProcessController::theOProcessController = 0;
00046
00047 struct sigaction OProcessController::oldChildHandlerData;
00048 bool OProcessController::handlerSet = false;
00049
00050 OProcessController::OProcessController()
00051 {
00052 assert( theOProcessController == 0 );
00053
00054 if (0 > pipe(fd))
00055 printf(strerror(errno));
00056
00057 notifier = new QSocketNotifier(fd[0], QSocketNotifier::Read);
00058 notifier->setEnabled(true);
00059 QObject::connect(notifier, SIGNAL(activated(int)),
00060 this, SLOT(slotDoHousekeeping(int)));
00061 connect( &delayedChildrenCleanupTimer, SIGNAL( timeout()),
00062 SLOT( delayedChildrenCleanup()));
00063
00064 theOProcessController = this;
00065
00066 setupHandlers();
00067 }
00068
00069
00070 void OProcessController::setupHandlers()
00071 {
00072 if( handlerSet )
00073 return;
00074 struct sigaction act;
00075 act.sa_handler=theSigCHLDHandler;
00076 sigemptyset(&(act.sa_mask));
00077 sigaddset(&(act.sa_mask), SIGCHLD);
00078
00079 sigprocmask(SIG_UNBLOCK, &(act.sa_mask), 0);
00080
00081 act.sa_flags = SA_NOCLDSTOP;
00082
00083
00084
00085
00086 #ifdef SA_RESTART
00087 act.sa_flags |= SA_RESTART;
00088 #endif
00089
00090 sigaction( SIGCHLD, &act, &oldChildHandlerData );
00091
00092 act.sa_handler=SIG_IGN;
00093 sigemptyset(&(act.sa_mask));
00094 sigaddset(&(act.sa_mask), SIGPIPE);
00095 act.sa_flags = 0;
00096 sigaction( SIGPIPE, &act, 0L);
00097 handlerSet = true;
00098 }
00099
00100 void OProcessController::resetHandlers()
00101 {
00102 if( !handlerSet )
00103 return;
00104 sigaction( SIGCHLD, &oldChildHandlerData, 0 );
00105
00106 handlerSet = false;
00107 }
00108
00109
00110 void OProcessController::addOProcess( OProcess* p )
00111 {
00112 sigset_t newset, oldset;
00113 sigemptyset( &newset );
00114 sigaddset( &newset, SIGCHLD );
00115 sigprocmask( SIG_BLOCK, &newset, &oldset );
00116 processList.append( p );
00117 sigprocmask( SIG_SETMASK, &oldset, 0 );
00118 }
00119
00120 void OProcessController::removeOProcess( OProcess* p )
00121 {
00122 sigset_t newset, oldset;
00123 sigemptyset( &newset );
00124 sigaddset( &newset, SIGCHLD );
00125 sigprocmask( SIG_BLOCK, &newset, &oldset );
00126 processList.remove( p );
00127 sigprocmask( SIG_SETMASK, &oldset, 0 );
00128 }
00129
00130
00131
00132
00133
00134
00135 struct waitdata
00136 {
00137 pid_t pid;
00138 int status;
00139 };
00140
00141 void OProcessController::theSigCHLDHandler(int arg)
00142 {
00143 struct waitdata wd;
00144
00145
00146 int saved_errno;
00147
00148 saved_errno = errno;
00149
00150
00151
00152 bool found = false;
00153 if( theOProcessController != 0 ) {
00154
00155 for( QValueList<OProcess*>::ConstIterator it = theOProcessController->processList.begin();
00156 it != theOProcessController->processList.end();
00157 ++it )
00158 {
00159 if( !(*it)->isRunning())
00160 continue;
00161 wd.pid = waitpid( (*it)->pid(), &wd.status, WNOHANG );
00162 if ( wd.pid > 0 ) {
00163 ::write(theOProcessController->fd[1], &wd, sizeof(wd));
00164 found = true;
00165 }
00166 }
00167 }
00168 if( !found && oldChildHandlerData.sa_handler != SIG_IGN
00169 && oldChildHandlerData.sa_handler != SIG_DFL )
00170 oldChildHandlerData.sa_handler( arg );
00171
00172 if( theOProcessController != 0 ) {
00173 static const struct waitdata dwd = { 0, 0 };
00174 ::write(theOProcessController->fd[1], &dwd, sizeof(dwd));
00175 } else {
00176 int dummy;
00177 while( waitpid( -1, &dummy, WNOHANG ) > 0 )
00178 ;
00179 }
00180
00181 errno = saved_errno;
00182 }
00183
00184
00185
00186 void OProcessController::slotDoHousekeeping(int )
00187 {
00188 unsigned int bytes_read = 0;
00189 unsigned int errcnt=0;
00190
00191 struct waitdata wd;
00192 while ((bytes_read < sizeof(wd)) && (errcnt < 50)) {
00193 int r = ::read(fd[0], ((char *)&wd) + bytes_read, sizeof(wd) - bytes_read);
00194 if (r > 0) bytes_read += r;
00195 else if (r < 0) errcnt++;
00196 }
00197 if (errcnt >= 50) {
00198 fprintf(stderr,
00199 "Error: Max. error count for pipe read "
00200 "exceeded in OProcessController::slotDoHousekeeping\n");
00201 return;
00202 }
00203 if (bytes_read != sizeof(wd)) {
00204 fprintf(stderr,
00205 "Error: Could not read info from signal handler %d <> %d!\n",
00206 bytes_read, sizeof(wd));
00207 return;
00208 }
00209 if (wd.pid==0) {
00210 delayedChildrenCleanupTimer.start( 1000, true );
00211 return;
00212 }
00213
00214 for( QValueList<OProcess*>::ConstIterator it = processList.begin();
00215 it != processList.end();
00216 ++it ) {
00217 OProcess* proc = *it;
00218 if (proc->pid() == wd.pid) {
00219
00220 if (proc->run_mode == OProcess::Block) {
00221
00222
00223
00224 proc->status = wd.status;
00225 proc->runs = false;
00226 } else {
00227 proc->processHasExited(wd.status);
00228 }
00229 return;
00230 }
00231 }
00232 }
00233
00234
00235
00236
00237 void OProcessController::delayedChildrenCleanup()
00238 {
00239 struct waitdata wd;
00240 while(( wd.pid = waitpid( -1, &wd.status, WNOHANG ) ) > 0 ) {
00241 for( QValueList<OProcess*>::ConstIterator it = processList.begin();
00242 it != processList.end();
00243 ++it )
00244 {
00245 if( !(*it)->isRunning() || (*it)->pid() != wd.pid )
00246 continue;
00247
00248 ::write(fd[1], &wd, sizeof(wd));
00249 break;
00250 }
00251 }
00252 }
00253
00254 OProcessController::~OProcessController()
00255 {
00256 assert( theOProcessController == this );
00257 resetHandlers();
00258
00259 notifier->setEnabled(false);
00260
00261 close(fd[0]);
00262 close(fd[1]);
00263
00264 delete notifier;
00265 theOProcessController = 0;
00266 }
00267
00268