source: ogBrowser-Git/qtermwidget/src/k3processcontroller.cpp

qndtest
Last change on this file was 8ab4781, checked in by adelcastillo <adelcastillo@…>, 15 years ago

Cambiando a qmake de nuevo.

git-svn-id: https://opengnsys.es/svn/trunk@518 a21b9725-9963-47de-94b9-378ad31fedc9

  • Property mode set to 100644
File size: 7.7 KB
Line 
1/* This file is part of the KDE libraries
2    Copyright (C) 1997 Christian Czezakte (e9025461@student.tuwien.ac.at)
3
4    Rewritten for QT4 by e_k <e_k at users.sourceforge.net>, Copyright (C)2008
5
6    This library is free software; you can redistribute it and/or
7    modify it under the terms of the GNU Library General Public
8    License as published by the Free Software Foundation; either
9    version 2 of the License, or (at your option) any later version.
10
11    This library is distributed in the hope that it will be useful,
12    but WITHOUT ANY WARRANTY; without even the implied warranty of
13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14    Library General Public License for more details.
15
16    You should have received a copy of the GNU Library General Public License
17    along with this library; see the file COPYING.LIB.  If not, write to
18    the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
19    Boston, MA 02110-1301, USA.
20*/
21
22#include "k3processcontroller.h"
23#include "k3process.h"
24
25//#include <config.h>
26
27#include <sys/time.h>
28#include <sys/types.h>
29#include <sys/wait.h>
30#include <unistd.h>
31#include <errno.h>
32#include <fcntl.h>
33#include <stdio.h>
34#include <stdlib.h>
35
36#include <QtCore/QSocketNotifier>
37
38
39class K3ProcessController::Private
40{
41public:
42    Private()
43        : needcheck( false ),
44          notifier( 0 )
45    {
46    }
47
48    ~Private()
49    {
50        delete notifier;
51    }
52
53    int fd[2];
54    bool needcheck;
55    QSocketNotifier *notifier;
56    QList<K3Process*> kProcessList;
57    QList<int> unixProcessList;
58    static struct sigaction oldChildHandlerData;
59    static bool handlerSet;
60    static int refCount;
61    static K3ProcessController* instance;
62};
63
64K3ProcessController *K3ProcessController::Private::instance = 0;
65int K3ProcessController::Private::refCount = 0;
66
67void K3ProcessController::ref()
68{
69    if ( !Private::refCount ) {
70        Private::instance = new K3ProcessController;
71        setupHandlers();
72    }
73    Private::refCount++;
74}
75
76void K3ProcessController::deref()
77{
78    Private::refCount--;
79    if( !Private::refCount ) {
80        resetHandlers();
81        delete Private::instance;
82        Private::instance = 0;
83    }
84}
85
86K3ProcessController* K3ProcessController::instance()
87{
88    /*
89     * there were no safety guards in previous revisions, is that ok?
90    if ( !Private::instance ) {
91        ref();
92    }
93     */
94
95    return Private::instance;
96}
97
98K3ProcessController::K3ProcessController()
99  : d( new Private )
100{
101  if( pipe( d->fd ) )
102  {
103    perror( "pipe" );
104    abort();
105  }
106
107  fcntl( d->fd[0], F_SETFL, O_NONBLOCK ); // in case slotDoHousekeeping is called without polling first
108  fcntl( d->fd[1], F_SETFL, O_NONBLOCK ); // in case it fills up
109  fcntl( d->fd[0], F_SETFD, FD_CLOEXEC );
110  fcntl( d->fd[1], F_SETFD, FD_CLOEXEC );
111
112  d->notifier = new QSocketNotifier( d->fd[0], QSocketNotifier::Read );
113  d->notifier->setEnabled( true );
114  QObject::connect( d->notifier, SIGNAL(activated(int)),
115                    SLOT(slotDoHousekeeping()));
116}
117
118K3ProcessController::~K3ProcessController()
119{
120#ifndef Q_OS_MAC
121/* not sure why, but this is causing lockups */
122  close( d->fd[0] );
123  close( d->fd[1] );
124#else
125#warning FIXME: why does close() freeze up destruction?
126#endif
127
128  delete d;
129}
130
131
132extern "C" {
133static void theReaper( int num )
134{
135  K3ProcessController::theSigCHLDHandler( num );
136}
137}
138
139#ifdef Q_OS_UNIX
140struct sigaction K3ProcessController::Private::oldChildHandlerData;
141#endif
142bool K3ProcessController::Private::handlerSet = false;
143
144void K3ProcessController::setupHandlers()
145{
146  if( Private::handlerSet )
147      return;
148  Private::handlerSet = true;
149
150#ifdef Q_OS_UNIX
151  struct sigaction act;
152  sigemptyset( &act.sa_mask );
153
154  act.sa_handler = SIG_IGN;
155  act.sa_flags = 0;
156  sigaction( SIGPIPE, &act, 0L );
157
158  act.sa_handler = theReaper;
159  act.sa_flags = SA_NOCLDSTOP;
160  // CC: take care of SunOS which automatically restarts interrupted system
161  // calls (and thus does not have SA_RESTART)
162#ifdef SA_RESTART
163  act.sa_flags |= SA_RESTART;
164#endif
165  sigaction( SIGCHLD, &act, &Private::oldChildHandlerData );
166
167  sigaddset( &act.sa_mask, SIGCHLD );
168  // Make sure we don't block this signal. gdb tends to do that :-(
169  sigprocmask( SIG_UNBLOCK, &act.sa_mask, 0 );
170#else
171  //TODO: win32
172#endif
173}
174
175void K3ProcessController::resetHandlers()
176{
177  if( !Private::handlerSet )
178      return;
179  Private::handlerSet = false;
180
181#ifdef Q_OS_UNIX
182  sigset_t mask, omask;
183  sigemptyset( &mask );
184  sigaddset( &mask, SIGCHLD );
185  sigprocmask( SIG_BLOCK, &mask, &omask );
186
187  struct sigaction act;
188  sigaction( SIGCHLD, &Private::oldChildHandlerData, &act );
189  if (act.sa_handler != theReaper) {
190     sigaction( SIGCHLD, &act, 0 );
191     Private::handlerSet = true;
192  }
193
194  sigprocmask( SIG_SETMASK, &omask, 0 );
195#else
196  //TODO: win32
197#endif
198  // there should be no problem with SIGPIPE staying SIG_IGN
199}
200
201// the pipe is needed to sync the child reaping with our event processing,
202// as otherwise there are race conditions, locking requirements, and things
203// generally get harder
204void K3ProcessController::theSigCHLDHandler( int arg )
205{
206  int saved_errno = errno;
207
208  char dummy = 0;
209  ::write( instance()->d->fd[1], &dummy, 1 );
210
211#ifdef Q_OS_UNIX
212    if ( Private::oldChildHandlerData.sa_handler != SIG_IGN &&
213         Private::oldChildHandlerData.sa_handler != SIG_DFL ) {
214        Private::oldChildHandlerData.sa_handler( arg ); // call the old handler
215    }
216#else
217  //TODO: win32
218#endif
219
220  errno = saved_errno;
221}
222
223int K3ProcessController::notifierFd() const
224{
225  return d->fd[0];
226}
227
228void K3ProcessController::unscheduleCheck()
229{
230  char dummy[16]; // somewhat bigger - just in case several have queued up
231  if( ::read( d->fd[0], dummy, sizeof(dummy) ) > 0 )
232    d->needcheck = true;
233}
234
235void
236K3ProcessController::rescheduleCheck()
237{
238  if( d->needcheck )
239  {
240    d->needcheck = false;
241    char dummy = 0;
242    ::write( d->fd[1], &dummy, 1 );
243  }
244}
245
246void K3ProcessController::slotDoHousekeeping()
247{
248  char dummy[16]; // somewhat bigger - just in case several have queued up
249  ::read( d->fd[0], dummy, sizeof(dummy) );
250
251  int status;
252 again:
253  QList<K3Process*>::iterator it( d->kProcessList.begin() );
254  QList<K3Process*>::iterator eit( d->kProcessList.end() );
255  while( it != eit )
256  {
257    K3Process *prc = *it;
258    if( prc->runs && waitpid( prc->pid_, &status, WNOHANG ) > 0 )
259    {
260      prc->processHasExited( status );
261      // the callback can nuke the whole process list and even 'this'
262      if (!instance())
263        return;
264      goto again;
265    }
266    ++it;
267  }
268  QList<int>::iterator uit( d->unixProcessList.begin() );
269  QList<int>::iterator ueit( d->unixProcessList.end() );
270  while( uit != ueit )
271  {
272    if( waitpid( *uit, 0, WNOHANG ) > 0 )
273    {
274      uit = d->unixProcessList.erase( uit );
275      deref(); // counterpart to addProcess, can invalidate 'this'
276    } else
277      ++uit;
278  }
279}
280
281bool K3ProcessController::waitForProcessExit( int timeout )
282{
283#ifdef Q_OS_UNIX
284  for(;;)
285  {
286    struct timeval tv, *tvp;
287    if (timeout < 0)
288      tvp = 0;
289    else
290    {
291      tv.tv_sec = timeout;
292      tv.tv_usec = 0;
293      tvp = &tv;
294    }
295
296    fd_set fds;
297    FD_ZERO( &fds );
298    FD_SET( d->fd[0], &fds );
299
300    switch( select( d->fd[0]+1, &fds, 0, 0, tvp ) )
301    {
302    case -1:
303      if( errno == EINTR )
304        continue;
305      // fall through; should never happen
306    case 0:
307      return false;
308    default:
309      slotDoHousekeeping();
310      return true;
311    }
312  }
313#else
314  //TODO: win32
315  return false;
316#endif
317}
318
319void K3ProcessController::addKProcess( K3Process* p )
320{
321  d->kProcessList.append( p );
322}
323
324void K3ProcessController::removeKProcess( K3Process* p )
325{
326  d->kProcessList.removeAll( p );
327}
328
329void K3ProcessController::addProcess( int pid )
330{
331  d->unixProcessList.append( pid );
332  ref(); // make sure we stay around when the K3Process goes away
333}
334
335//#include "moc_k3processcontroller.cpp"
Note: See TracBrowser for help on using the repository browser.