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

KDE3Support

  • sources
  • kde-4.14
  • kdelibs
  • 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 
36 class K3ProcessController::Private
37 {
38 public:
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 
61 K3ProcessController *K3ProcessController::Private::instance = 0;
62 int K3ProcessController::Private::refCount = 0;
63 
64 void K3ProcessController::ref()
65 {
66  if ( !Private::refCount ) {
67  Private::instance = new K3ProcessController;
68  setupHandlers();
69  }
70  Private::refCount++;
71 }
72 
73 void K3ProcessController::deref()
74 {
75  Private::refCount--;
76  if( !Private::refCount ) {
77  resetHandlers();
78  delete Private::instance;
79  Private::instance = 0;
80  }
81 }
82 
83 K3ProcessController* 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 
95 K3ProcessController::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 
115 K3ProcessController::~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 
129 extern "C" {
130 static void theReaper( int num )
131 {
132  K3ProcessController::theSigCHLDHandler( num );
133 }
134 }
135 
136 #ifdef Q_OS_UNIX
137 struct sigaction K3ProcessController::Private::oldChildHandlerData;
138 #endif
139 bool K3ProcessController::Private::handlerSet = false;
140 
141 void 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 
172 void 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
201 void 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 
220 int K3ProcessController::notifierFd() const
221 {
222  return d->fd[0];
223 }
224 
225 void 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 
232 void
233 K3ProcessController::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 
243 void 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 
278 bool 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 
316 void K3ProcessController::addKProcess( K3Process* p )
317 {
318  d->kProcessList.append( p );
319 }
320 
321 void K3ProcessController::removeKProcess( K3Process* p )
322 {
323  d->kProcessList.removeAll( p );
324 }
325 
326 void 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::notifierFd
int notifierFd() const
Definition: k3processcontroller.cpp:220
K3Process::processHasExited
virtual void processHasExited(int state)
Immediately called after a successfully started process in NotifyOnExit mode has exited.
Definition: k3process.cpp:747
theReaper
static void theReaper(int num)
Definition: k3processcontroller.cpp:130
perror
QDebug perror(QDebug s, KDebugTag)
k3processcontroller.h
QSocketNotifier
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::removeKProcess
void removeKProcess(K3Process *)
Definition: k3processcontroller.cpp:321
K3ProcessController
Used internally by K3Process.
Definition: k3processcontroller.h:37
mask
#define mask
K3ProcessController::deref
static void deref()
Destroy the instance if one exists and it is not referenced any more.
Definition: k3processcontroller.cpp:73
k3process.h
K3ProcessController::ref
static void ref()
Create an instance if none exists yet.
Definition: k3processcontroller.cpp:64
K3ProcessController::addProcess
void addProcess(int pid)
Definition: k3processcontroller.cpp:326
dummy
static int dummy
Definition: k3syntaxhighlighter.cpp:41
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::addKProcess
void addKProcess(K3Process *)
Definition: k3processcontroller.cpp:316
QList< K3Process * >
K3Process::pid_
pid_t pid_
The PID of the currently running process.
Definition: k3process.h:673
K3ProcessController::theSigCHLDHandler
static void theSigCHLDHandler(int signal)
Automatically called upon SIGCHLD.
Definition: k3processcontroller.cpp:201
Phonon::BackendCapabilities::notifier
Notifier * notifier()
K3Process
Definition: k3process.h:127
bool
K3ProcessController::instance
static K3ProcessController * instance()
Only a single instance of this class is allowed at a time.
Definition: k3processcontroller.cpp:83
QObject::connect
bool connect(const QObject *sender, const char *signal, const QObject *receiver, const char *method, Qt::ConnectionType type)
K3Process::runs
bool runs
true if the process is currently running.
Definition: k3process.h:664
close
KAction * close(const QObject *recvr, const char *slot, QObject *parent)
This file is part of the KDE documentation.
Documentation copyright © 1996-2020 The KDE developers.
Generated on Mon Jun 22 2020 13:26:48 by doxygen 1.8.7 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 API Reference

Skip menu "kdelibs 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

Search



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