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