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