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