summaryrefslogtreecommitdiff
path: root/libopie/oprocctrl.cpp
Unidiff
Diffstat (limited to 'libopie/oprocctrl.cpp') (more/less context) (ignore whitespace changes)
-rw-r--r--libopie/oprocctrl.cpp267
1 files changed, 0 insertions, 267 deletions
diff --git a/libopie/oprocctrl.cpp b/libopie/oprocctrl.cpp
deleted file mode 100644
index df8da1e..0000000
--- a/libopie/oprocctrl.cpp
+++ b/dev/null
@@ -1,267 +0,0 @@
1/* This file is part of the KDE libraries
2 Copyright (C) 1997 Christian Czezakte (e9025461@student.tuwien.ac.at)
3
4 This library is free software; you can redistribute it and/or
5 modify it under the terms of the GNU Library General Public
6 License as published by the Free Software Foundation; either
7 version 2 of the License, or (at your option) any later version.
8
9 This library is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 Library General Public License for more details.
13
14 You should have received a copy of the GNU Library General Public License
15 along with this library; see the file COPYING.LIB. If not, write to
16 the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17 Boston, MA 02111-1307, USA.
18*/
19//
20// KPROCESSCONTROLLER -- A helper class for KProcess
21//
22// version 0.3.1, Jan, 8th 1997
23//
24// (C) Christian Czezatke
25// e9025461@student.tuwien.ac.at
26// Ported by Holger Freyther
27//
28
29//#include <config.h>
30
31#include <sys/types.h>
32#include <sys/socket.h>
33
34#include <errno.h>
35#include <fcntl.h>
36#include <stdio.h>
37#include <string.h>
38#include <unistd.h>
39#include <assert.h>
40
41#include <qsocketnotifier.h>
42#include "oprocctrl.h"
43
44OProcessController *OProcessController::theOProcessController = 0;
45
46struct sigaction OProcessController::oldChildHandlerData;
47bool OProcessController::handlerSet = false;
48
49OProcessController::OProcessController()
50{
51 assert( theOProcessController == 0 );
52
53 if (0 > pipe(fd))
54 printf(strerror(errno));
55
56 notifier = new QSocketNotifier(fd[0], QSocketNotifier::Read);
57 notifier->setEnabled(true);
58 QObject::connect(notifier, SIGNAL(activated(int)),
59 this, SLOT(slotDoHousekeeping(int)));
60 connect( &delayedChildrenCleanupTimer, SIGNAL( timeout()),
61 SLOT( delayedChildrenCleanup()));
62
63 theOProcessController = this;
64
65 setupHandlers();
66}
67
68
69void OProcessController::setupHandlers()
70{
71 if( handlerSet )
72 return;
73 struct sigaction act;
74 act.sa_handler=theSigCHLDHandler;
75 sigemptyset(&(act.sa_mask));
76 sigaddset(&(act.sa_mask), SIGCHLD);
77 // Make sure we don't block this signal. gdb tends to do that :-(
78 sigprocmask(SIG_UNBLOCK, &(act.sa_mask), 0);
79
80 act.sa_flags = SA_NOCLDSTOP;
81
82 // CC: take care of SunOS which automatically restarts interrupted system
83 // calls (and thus does not have SA_RESTART)
84
85#ifdef SA_RESTART
86 act.sa_flags |= SA_RESTART;
87#endif
88
89 sigaction( SIGCHLD, &act, &oldChildHandlerData );
90
91 act.sa_handler=SIG_IGN;
92 sigemptyset(&(act.sa_mask));
93 sigaddset(&(act.sa_mask), SIGPIPE);
94 act.sa_flags = 0;
95 sigaction( SIGPIPE, &act, 0L);
96 handlerSet = true;
97}
98
99void OProcessController::resetHandlers()
100{
101 if( !handlerSet )
102 return;
103 sigaction( SIGCHLD, &oldChildHandlerData, 0 );
104 // there should be no problem with SIGPIPE staying SIG_IGN
105 handlerSet = false;
106}
107
108// block SIGCHLD handler, because it accesses processList
109void OProcessController::addOProcess( OProcess* p )
110{
111 sigset_t newset, oldset;
112 sigemptyset( &newset );
113 sigaddset( &newset, SIGCHLD );
114 sigprocmask( SIG_BLOCK, &newset, &oldset );
115 processList.append( p );
116 sigprocmask( SIG_SETMASK, &oldset, 0 );
117}
118
119void OProcessController::removeOProcess( OProcess* p )
120{
121 sigset_t newset, oldset;
122 sigemptyset( &newset );
123 sigaddset( &newset, SIGCHLD );
124 sigprocmask( SIG_BLOCK, &newset, &oldset );
125 processList.remove( p );
126 sigprocmask( SIG_SETMASK, &oldset, 0 );
127}
128
129//using a struct which contains both the pid and the status makes it easier to write
130//and read the data into the pipe
131//especially this solves a problem which appeared on my box where slotDoHouseKeeping() received
132//only 4 bytes (with some debug output around the write()'s it received all 8 bytes)
133//don't know why this happened, but when writing all 8 bytes at once it works here, aleXXX
134struct waitdata
135{
136 pid_t pid;
137 int status;
138};
139
140void OProcessController::theSigCHLDHandler(int arg)
141{
142 struct waitdata wd;
143// int status;
144// pid_t this_pid;
145 int saved_errno;
146
147 saved_errno = errno;
148 // since waitpid and write change errno, we have to save it and restore it
149 // (Richard Stevens, Advanced programming in the Unix Environment)
150
151 bool found = false;
152 if( theOProcessController != 0 ) {
153 // iterating the list doesn't perform any system call
154 for( QValueList<OProcess*>::ConstIterator it = theOProcessController->processList.begin();
155 it != theOProcessController->processList.end();
156 ++it )
157 {
158 if( !(*it)->isRunning())
159 continue;
160 wd.pid = waitpid( (*it)->pid(), &wd.status, WNOHANG );
161 if ( wd.pid > 0 ) {
162 ::write(theOProcessController->fd[1], &wd, sizeof(wd));
163 found = true;
164 }
165 }
166 }
167 if( !found && oldChildHandlerData.sa_handler != SIG_IGN
168 && oldChildHandlerData.sa_handler != SIG_DFL )
169 oldChildHandlerData.sa_handler( arg ); // call the old handler
170 // handle the rest
171 if( theOProcessController != 0 ) {
172 static const struct waitdata dwd = { 0, 0 }; // delayed waitpid()
173 ::write(theOProcessController->fd[1], &dwd, sizeof(dwd));
174 } else {
175 int dummy;
176 while( waitpid( -1, &dummy, WNOHANG ) > 0 )
177 ;
178 }
179
180 errno = saved_errno;
181}
182
183
184
185void OProcessController::slotDoHousekeeping(int )
186{
187 unsigned int bytes_read = 0;
188 unsigned int errcnt=0;
189 // read pid and status from the pipe.
190 struct waitdata wd;
191 while ((bytes_read < sizeof(wd)) && (errcnt < 50)) {
192 int r = ::read(fd[0], ((char *)&wd) + bytes_read, sizeof(wd) - bytes_read);
193 if (r > 0) bytes_read += r;
194 else if (r < 0) errcnt++;
195 }
196 if (errcnt >= 50) {
197 fprintf(stderr,
198 "Error: Max. error count for pipe read "
199 "exceeded in OProcessController::slotDoHousekeeping\n");
200 return; // it makes no sense to continue here!
201 }
202 if (bytes_read != sizeof(wd)) {
203 fprintf(stderr,
204 "Error: Could not read info from signal handler %d <> %d!\n",
205 bytes_read, sizeof(wd));
206 return; // it makes no sense to continue here!
207 }
208 if (wd.pid==0) { // special case, see delayedChildrenCleanup()
209 delayedChildrenCleanupTimer.start( 1000, true );
210 return;
211 }
212
213 for( QValueList<OProcess*>::ConstIterator it = processList.begin();
214 it != processList.end();
215 ++it ) {
216 OProcess* proc = *it;
217 if (proc->pid() == wd.pid) {
218 // process has exited, so do emit the respective events
219 if (proc->run_mode == OProcess::Block) {
220 // If the reads are done blocking then set the status in proc
221 // but do nothing else because OProcess will perform the other
222 // actions of processHasExited.
223 proc->status = wd.status;
224 proc->runs = false;
225 } else {
226 proc->processHasExited(wd.status);
227 }
228 return;
229 }
230 }
231}
232
233// this is needed e.g. for popen(), which calls waitpid() checking
234// for its forked child, if we did waitpid() directly in the SIGCHLD
235// handler, popen()'s waitpid() call would fail
236void OProcessController::delayedChildrenCleanup()
237{
238 struct waitdata wd;
239 while(( wd.pid = waitpid( -1, &wd.status, WNOHANG ) ) > 0 ) {
240 for( QValueList<OProcess*>::ConstIterator it = processList.begin();
241 it != processList.end();
242 ++it )
243 {
244 if( !(*it)->isRunning() || (*it)->pid() != wd.pid )
245 continue;
246 // it's OProcess, handle it
247 ::write(fd[1], &wd, sizeof(wd));
248 break;
249 }
250 }
251}
252
253OProcessController::~OProcessController()
254{
255 assert( theOProcessController == this );
256 resetHandlers();
257
258 notifier->setEnabled(false);
259
260 close(fd[0]);
261 close(fd[1]);
262
263 delete notifier;
264 theOProcessController = 0;
265}
266
267//#include "kprocctrl.moc"