source: ogBrowser-Git/qtermwidget/src/k3processcontroller.cpp @ 9d8d163

jenkinsmain
Last change on this file since 9d8d163 was 050d67a, checked in by adelcastillo <adelcastillo@…>, 16 years ago

Ahora el browser tiene consola en vez del output.
Pasado todo el sistema de compilacion a cmake.

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