• Skip to content
  • Skip to link menu
  • KDE API Reference
  • kdelibs-4.14.38 API Reference
  • KDE Home
  • Contact Us
 

KDE3Support

  • kde3support
  • kdecore
k3processcontroller.cpp
Go to the documentation of this file.
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., 51 Franklin Street, Fifth Floor,
17 Boston, MA 02110-1301, USA.
18*/
19
20#include "k3processcontroller.h"
21#include "k3process.h"
22
23#include <config.h>
24
25#include <sys/time.h>
26#include <sys/types.h>
27#include <sys/wait.h>
28#include <unistd.h>
29#include <errno.h>
30#include <fcntl.h>
31#include <stdio.h>
32#include <stdlib.h>
33
34#include <QtCore/QSocketNotifier>
35
36class K3ProcessController::Private
37{
38public:
39 Private()
40 : needcheck( false ),
41 notifier( 0 )
42 {
43 }
44
45 ~Private()
46 {
47 delete notifier;
48 }
49
50 int fd[2];
51 bool needcheck;
52 QSocketNotifier *notifier;
53 QList<K3Process*> kProcessList;
54 QList<int> unixProcessList;
55 static struct sigaction oldChildHandlerData;
56 static bool handlerSet;
57 static int refCount;
58 static K3ProcessController* instance;
59};
60
61K3ProcessController *K3ProcessController::Private::instance = 0;
62int K3ProcessController::Private::refCount = 0;
63
64void K3ProcessController::ref()
65{
66 if ( !Private::refCount ) {
67 Private::instance = new K3ProcessController;
68 setupHandlers();
69 }
70 Private::refCount++;
71}
72
73void K3ProcessController::deref()
74{
75 Private::refCount--;
76 if( !Private::refCount ) {
77 resetHandlers();
78 delete Private::instance;
79 Private::instance = 0;
80 }
81}
82
83K3ProcessController* K3ProcessController::instance()
84{
85 /*
86 * there were no safety guards in previous revisions, is that ok?
87 if ( !Private::instance ) {
88 ref();
89 }
90 */
91
92 return Private::instance;
93}
94
95K3ProcessController::K3ProcessController()
96 : d( new Private )
97{
98 if( pipe( d->fd ) )
99 {
100 perror( "pipe" );
101 abort();
102 }
103
104 fcntl( d->fd[0], F_SETFL, O_NONBLOCK ); // in case slotDoHousekeeping is called without polling first
105 fcntl( d->fd[1], F_SETFL, O_NONBLOCK ); // in case it fills up
106 fcntl( d->fd[0], F_SETFD, FD_CLOEXEC );
107 fcntl( d->fd[1], F_SETFD, FD_CLOEXEC );
108
109 d->notifier = new QSocketNotifier( d->fd[0], QSocketNotifier::Read );
110 d->notifier->setEnabled( true );
111 QObject::connect( d->notifier, SIGNAL(activated(int)),
112 SLOT(slotDoHousekeeping()));
113}
114
115K3ProcessController::~K3ProcessController()
116{
117#ifndef Q_OS_MAC
118/* not sure why, but this is causing lockups */
119 close( d->fd[0] );
120 close( d->fd[1] );
121#else
122#warning FIXME: why does close() freeze up destruction?
123#endif
124
125 delete d;
126}
127
128
129extern "C" {
130static void theReaper( int num )
131{
132 K3ProcessController::theSigCHLDHandler( num );
133}
134}
135
136#ifdef Q_OS_UNIX
137struct sigaction K3ProcessController::Private::oldChildHandlerData;
138#endif
139bool K3ProcessController::Private::handlerSet = false;
140
141void K3ProcessController::setupHandlers()
142{
143 if( Private::handlerSet )
144 return;
145 Private::handlerSet = true;
146
147#ifdef Q_OS_UNIX
148 struct sigaction act;
149 sigemptyset( &act.sa_mask );
150
151 act.sa_handler = SIG_IGN;
152 act.sa_flags = 0;
153 sigaction( SIGPIPE, &act, 0L );
154
155 act.sa_handler = theReaper;
156 act.sa_flags = SA_NOCLDSTOP;
157 // CC: take care of SunOS which automatically restarts interrupted system
158 // calls (and thus does not have SA_RESTART)
159#ifdef SA_RESTART
160 act.sa_flags |= SA_RESTART;
161#endif
162 sigaction( SIGCHLD, &act, &Private::oldChildHandlerData );
163
164 sigaddset( &act.sa_mask, SIGCHLD );
165 // Make sure we don't block this signal. gdb tends to do that :-(
166 sigprocmask( SIG_UNBLOCK, &act.sa_mask, 0 );
167#else
168 //TODO: win32
169#endif
170}
171
172void K3ProcessController::resetHandlers()
173{
174 if( !Private::handlerSet )
175 return;
176 Private::handlerSet = false;
177
178#ifdef Q_OS_UNIX
179 sigset_t mask, omask;
180 sigemptyset( &mask );
181 sigaddset( &mask, SIGCHLD );
182 sigprocmask( SIG_BLOCK, &mask, &omask );
183
184 struct sigaction act;
185 sigaction( SIGCHLD, &Private::oldChildHandlerData, &act );
186 if (act.sa_handler != theReaper) {
187 sigaction( SIGCHLD, &act, 0 );
188 Private::handlerSet = true;
189 }
190
191 sigprocmask( SIG_SETMASK, &omask, 0 );
192#else
193 //TODO: win32
194#endif
195 // there should be no problem with SIGPIPE staying SIG_IGN
196}
197
198// the pipe is needed to sync the child reaping with our event processing,
199// as otherwise there are race conditions, locking requirements, and things
200// generally get harder
201void K3ProcessController::theSigCHLDHandler( int arg )
202{
203 int saved_errno = errno;
204
205 char dummy = 0;
206 ::write( instance()->d->fd[1], &dummy, 1 );
207
208#ifdef Q_OS_UNIX
209 if ( Private::oldChildHandlerData.sa_handler != SIG_IGN &&
210 Private::oldChildHandlerData.sa_handler != SIG_DFL ) {
211 Private::oldChildHandlerData.sa_handler( arg ); // call the old handler
212 }
213#else
214 //TODO: win32
215#endif
216
217 errno = saved_errno;
218}
219
220int K3ProcessController::notifierFd() const
221{
222 return d->fd[0];
223}
224
225void K3ProcessController::unscheduleCheck()
226{
227 char dummy[16]; // somewhat bigger - just in case several have queued up
228 if( ::read( d->fd[0], dummy, sizeof(dummy) ) > 0 )
229 d->needcheck = true;
230}
231
232void
233K3ProcessController::rescheduleCheck()
234{
235 if( d->needcheck )
236 {
237 d->needcheck = false;
238 char dummy = 0;
239 ::write( d->fd[1], &dummy, 1 );
240 }
241}
242
243void K3ProcessController::slotDoHousekeeping()
244{
245 char dummy[16]; // somewhat bigger - just in case several have queued up
246 ::read( d->fd[0], dummy, sizeof(dummy) );
247
248 int status;
249 again:
250 QList<K3Process*>::iterator it( d->kProcessList.begin() );
251 QList<K3Process*>::iterator eit( d->kProcessList.end() );
252 while( it != eit )
253 {
254 K3Process *prc = *it;
255 if( prc->runs && waitpid( prc->pid_, &status, WNOHANG ) > 0 )
256 {
257 prc->processHasExited( status );
258 // the callback can nuke the whole process list and even 'this'
259 if (!instance())
260 return;
261 goto again;
262 }
263 ++it;
264 }
265 QList<int>::iterator uit( d->unixProcessList.begin() );
266 QList<int>::iterator ueit( d->unixProcessList.end() );
267 while( uit != ueit )
268 {
269 if( waitpid( *uit, 0, WNOHANG ) > 0 )
270 {
271 uit = d->unixProcessList.erase( uit );
272 deref(); // counterpart to addProcess, can invalidate 'this'
273 } else
274 ++uit;
275 }
276}
277
278bool K3ProcessController::waitForProcessExit( int timeout )
279{
280#ifdef Q_OS_UNIX
281 for(;;)
282 {
283 struct timeval tv, *tvp;
284 if (timeout < 0)
285 tvp = 0;
286 else
287 {
288 tv.tv_sec = timeout;
289 tv.tv_usec = 0;
290 tvp = &tv;
291 }
292
293 fd_set fds;
294 FD_ZERO( &fds );
295 FD_SET( d->fd[0], &fds );
296
297 switch( select( d->fd[0]+1, &fds, 0, 0, tvp ) )
298 {
299 case -1:
300 if( errno == EINTR )
301 continue;
302 // fall through; should never happen
303 case 0:
304 return false;
305 default:
306 slotDoHousekeeping();
307 return true;
308 }
309 }
310#else
311 //TODO: win32
312 return false;
313#endif
314}
315
316void K3ProcessController::addKProcess( K3Process* p )
317{
318 d->kProcessList.append( p );
319}
320
321void K3ProcessController::removeKProcess( K3Process* p )
322{
323 d->kProcessList.removeAll( p );
324}
325
326void K3ProcessController::addProcess( int pid )
327{
328 d->unixProcessList.append( pid );
329 ref(); // make sure we stay around when the K3Process goes away
330}
331
332#include "k3processcontroller.moc"
K3ProcessController
Used internally by K3Process.
Definition: k3processcontroller.h:38
K3ProcessController::waitForProcessExit
bool waitForProcessExit(int timeout)
Wait for any process to exit and handle their exit without starting an event loop.
Definition: k3processcontroller.cpp:278
K3ProcessController::deref
static void deref()
Destroy the instance if one exists and it is not referenced any more.
Definition: k3processcontroller.cpp:73
K3ProcessController::ref
static void ref()
Create an instance if none exists yet.
Definition: k3processcontroller.cpp:64
K3ProcessController::notifierFd
int notifierFd() const
Definition: k3processcontroller.cpp:220
K3ProcessController::instance
static K3ProcessController * instance()
Only a single instance of this class is allowed at a time.
Definition: k3processcontroller.cpp:83
K3ProcessController::rescheduleCheck
void rescheduleCheck()
This function must be called at some point after calling unscheduleCheck().
Definition: k3processcontroller.cpp:233
K3ProcessController::unscheduleCheck
void unscheduleCheck()
Call this function to defer processing of the data that became available on notifierFd().
Definition: k3processcontroller.cpp:225
K3ProcessController::removeKProcess
void removeKProcess(K3Process *)
Definition: k3processcontroller.cpp:321
K3ProcessController::theSigCHLDHandler
static void theSigCHLDHandler(int signal)
Automatically called upon SIGCHLD.
Definition: k3processcontroller.cpp:201
K3ProcessController::addProcess
void addProcess(int pid)
Definition: k3processcontroller.cpp:326
K3ProcessController::addKProcess
void addKProcess(K3Process *)
Definition: k3processcontroller.cpp:316
K3Process
Definition: k3process.h:128
K3Process::processHasExited
virtual void processHasExited(int state)
Immediately called after a successfully started process in NotifyOnExit mode has exited.
Definition: k3process.cpp:747
K3Process::runs
bool runs
true if the process is currently running.
Definition: k3process.h:664
K3Process::pid_
pid_t pid_
The PID of the currently running process.
Definition: k3process.h:673
QList
k3process.h
theReaper
static void theReaper(int num)
Definition: k3processcontroller.cpp:130
k3processcontroller.h
mask
#define mask
dummy
static int dummy
Definition: k3syntaxhighlighter.cpp:41
perror
QDebug perror(QDebug s, KDebugTag)
timeout
int timeout
close
KAction * close(const QObject *recvr, const char *slot, QObject *parent)
This file is part of the KDE documentation.
Documentation copyright © 1996-2023 The KDE developers.
Generated on Mon Feb 20 2023 00:00:00 by doxygen 1.9.6 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.

KDE3Support

Skip menu "KDE3Support"
  • Main Page
  • Namespace List
  • Namespace Members
  • Alphabetical List
  • Class List
  • Class Hierarchy
  • Class Members
  • File List
  • File Members
  • Related Pages

kdelibs-4.14.38 API Reference

Skip menu "kdelibs-4.14.38 API Reference"
  • DNSSD
  • Interfaces
  •   KHexEdit
  •   KMediaPlayer
  •   KSpeech
  •   KTextEditor
  • kconf_update
  • KDE3Support
  •   KUnitTest
  • KDECore
  • KDED
  • KDEsu
  • KDEUI
  • KDEWebKit
  • KDocTools
  • KFile
  • KHTML
  • KImgIO
  • KInit
  • kio
  • KIOSlave
  • KJS
  •   KJS-API
  •   WTF
  • kjsembed
  • KNewStuff
  • KParts
  • KPty
  • Kross
  • KUnitConversion
  • KUtils
  • Nepomuk
  • Plasma
  • Solid
  • Sonnet
  • ThreadWeaver
Report problems with this website to our bug tracking system.
Contact the specific authors with questions and comments about the page contents.

KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal