The repository does not have any commits yet

1
/****************************************************************************
2
**
3
** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
4
** All rights reserved.
5
** Contact: Nokia Corporation (qt-info@nokia.com)
6
**
7
** This file is part of the QtCore module of the Qt Toolkit.
8
**
9
** $QT_BEGIN_LICENSE:LGPL$
10
** GNU Lesser General Public License Usage
11
** This file may be used under the terms of the GNU Lesser General Public
12
** License version 2.1 as published by the Free Software Foundation and
13
** appearing in the file LICENSE.LGPL included in the packaging of this
14
** file. Please review the following information to ensure the GNU Lesser
15
** General Public License version 2.1 requirements will be met:
16
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
17
**
18
** In addition, as a special exception, Nokia gives you certain additional
19
** rights. These rights are described in the Nokia Qt LGPL Exception
20
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
21
**
22
** GNU General Public License Usage
23
** Alternatively, this file may be used under the terms of the GNU General
24
** Public License version 3.0 as published by the Free Software Foundation
25
** and appearing in the file LICENSE.GPL included in the packaging of this
26
** file. Please review the following information to ensure the GNU General
27
** Public License version 3.0 requirements will be met:
28
** http://www.gnu.org/copyleft/gpl.html.
29
**
30
** Other Usage
31
** Alternatively, this file may be used in accordance with the terms and
32
** conditions contained in a signed written agreement between you and Nokia.
33
**
34
**
35
**
36
**
37
**
38
** $QT_END_LICENSE$
39
**
40
****************************************************************************/
41
42
#include "qplatformdefs.h"
43
44
#include "qcoreapplication.h"
45
#include "qpair.h"
46
#include "qsocketnotifier.h"
47
#include "qthread.h"
48
#include "qelapsedtimer.h"
49
50
#include "qeventdispatcher_unix_p.h"
51
#include <private/qthread_p.h>
52
#include <private/qcoreapplication_p.h>
53
#include <private/qcore_unix_p.h>
54
55
#include <errno.h>
56
#include <stdio.h>
57
#include <stdlib.h>
58
59
// VxWorks doesn't correctly set the _POSIX_... options
60
#if defined(Q_OS_VXWORKS)
61
#  if defined(_POSIX_MONOTONIC_CLOCK) && (_POSIX_MONOTONIC_CLOCK <= 0)
62
#    undef _POSIX_MONOTONIC_CLOCK
63
#    define _POSIX_MONOTONIC_CLOCK 1
64
#  endif
65
#  include <pipeDrv.h>
66
#  include <selectLib.h>
67
#endif
68
69
#if (_POSIX_MONOTONIC_CLOCK-0 <= 0) || defined(QT_BOOTSTRAPPED)
70
#  include <sys/times.h>
71
#endif
72
73
QT_BEGIN_NAMESPACE
74
75
Q_CORE_EXPORT bool qt_disable_lowpriority_timers=false;
76
77
/*****************************************************************************
78
 UNIX signal handling
79
 *****************************************************************************/
80
81
static sig_atomic_t signal_received;
82
static sig_atomic_t signals_fired[NSIG];
83
84
static void signalHandler(int sig)
85
{
86
    signals_fired[sig] = 1;
87
    signal_received = 1;
88
}
89
90
91
#if defined(Q_OS_INTEGRITY) || defined(Q_OS_VXWORKS)
92
static void initThreadPipeFD(int fd)
93
{
94
    int ret = fcntl(fd, F_SETFD, FD_CLOEXEC);
95
    if (ret == -1)
96
        perror("QEventDispatcherUNIXPrivate: Unable to init thread pipe");
97
98
    int flags = fcntl(fd, F_GETFL);
99
    if (flags == -1)
100
        perror("QEventDispatcherUNIXPrivate: Unable to get flags on thread pipe");
101
102
    ret = fcntl(fd, F_SETFL, flags | O_NONBLOCK);
103
    if (ret == -1)
104
        perror("QEventDispatcherUNIXPrivate: Unable to set flags on thread pipe");
105
}
106
#endif
107
108
QEventDispatcherUNIXPrivate::QEventDispatcherUNIXPrivate()
109
{
110
    extern Qt::HANDLE qt_application_thread_id;
111
    mainThread = (QThread::currentThreadId() == qt_application_thread_id);
112
    bool pipefail = false;
113
114
    // initialize the common parts of the event loop
115
#if defined(Q_OS_NACL)
116
   // do nothing.
117
#elif defined(Q_OS_INTEGRITY)
118
    // INTEGRITY doesn't like a "select" on pipes, so use socketpair instead
119
    if (socketpair(AF_INET, SOCK_STREAM, 0, thread_pipe) == -1) {
120
        perror("QEventDispatcherUNIXPrivate(): Unable to create socket pair");
121
        pipefail = true;
122
    } else {
123
        initThreadPipeFD(thread_pipe[0]);
124
        initThreadPipeFD(thread_pipe[1]);
125
    }
126
#elif defined(Q_OS_VXWORKS)
127
    char name[20];
128
    qsnprintf(name, sizeof(name), "/pipe/qt_%08x", int(taskIdCurrent));
129
130
    // make sure there is no pipe with this name
131
    pipeDevDelete(name, true);
132
    // create the pipe
133
    if (pipeDevCreate(name, 128 /*maxMsg*/, 1 /*maxLength*/) != OK) {
134
        perror("QEventDispatcherUNIXPrivate(): Unable to create thread pipe device");
135
        pipefail = true;
136
    } else {
137
        if ((thread_pipe[0] = open(name, O_RDWR, 0)) < 0) {
138
            perror("QEventDispatcherUNIXPrivate(): Unable to create thread pipe");
139
            pipefail = true;
140
        } else {
141
            initThreadPipeFD(thread_pipe[0]);
142
            thread_pipe[1] = thread_pipe[0];
143
        }
144
    }
145
#else
146
    if (qt_safe_pipe(thread_pipe, O_NONBLOCK) == -1) {
147
        perror("QEventDispatcherUNIXPrivate(): Unable to create thread pipe");
148
        pipefail = true;
149
    }
150
#endif
151
152
    if (pipefail)
153
        qFatal("QEventDispatcherUNIXPrivate(): Can not continue without a thread pipe");
154
155
    sn_highest = -1;
156
157
    interrupt = false;
158
}
159
160
QEventDispatcherUNIXPrivate::~QEventDispatcherUNIXPrivate()
161
{
162
#if defined(Q_OS_NACL)
163
   // do nothing.
164
#elif defined(Q_OS_VXWORKS)
165
    close(thread_pipe[0]);
166
167
    char name[20];
168
    qsnprintf(name, sizeof(name), "/pipe/qt_%08x", int(taskIdCurrent));
169
170
    pipeDevDelete(name, true);
171
#else
172
    // cleanup the common parts of the event loop
173
    close(thread_pipe[0]);
174
    close(thread_pipe[1]);
175
#endif
176
177
    // cleanup timers
178
    qDeleteAll(timerList);
179
}
180
181
int QEventDispatcherUNIXPrivate::doSelect(QEventLoop::ProcessEventsFlags flags, timeval *timeout)
182
{
183
    Q_Q(QEventDispatcherUNIX);
184
185
    // needed in QEventDispatcherUNIX::select()
186
    timerList.updateCurrentTime();
187
188
    int nsel;
189
    do {
190
        if (mainThread) {
191
            while (signal_received) {
192
                signal_received = 0;
193
                for (int i = 0; i < NSIG; ++i) {
194
                    if (signals_fired[i]) {
195
                        signals_fired[i] = 0;
196
                        emit QCoreApplication::instance()->unixSignal(i);
197
                    }
198
                }
199
            }
200
        }
201
202
        // Process timers and socket notifiers - the common UNIX stuff
203
        int highest = 0;
204
        if (! (flags & QEventLoop::ExcludeSocketNotifiers) && (sn_highest >= 0)) {
205
            // return the highest fd we can wait for input on
206
                sn_vec[0].select_fds = sn_vec[0].enabled_fds;
207
                sn_vec[1].select_fds = sn_vec[1].enabled_fds;
208
                sn_vec[2].select_fds = sn_vec[2].enabled_fds;
209
            highest = sn_highest;
210
        } else {
211
            FD_ZERO(&sn_vec[0].select_fds);
212
            FD_ZERO(&sn_vec[1].select_fds);
213
            FD_ZERO(&sn_vec[2].select_fds);
214
        }
215
216
        FD_SET(thread_pipe[0], &sn_vec[0].select_fds);
217
        highest = qMax(highest, thread_pipe[0]);
218
219
        nsel = q->select(highest + 1,
220
                         &sn_vec[0].select_fds,
221
                         &sn_vec[1].select_fds,
222
                         &sn_vec[2].select_fds,
223
                         timeout);
224
    } while (nsel == -1 && (errno == EINTR || errno == EAGAIN));
225
226
    if (nsel == -1) {
227
        if (errno == EBADF) {
228
            // it seems a socket notifier has a bad fd... find out
229
            // which one it is and disable it
230
            fd_set fdset;
231
            timeval tm;
232
            tm.tv_sec = tm.tv_usec = 0l;
233
234
            for (int type = 0; type < 3; ++type) {
235
                QSockNotType::List &list = sn_vec[type].list;
236
                if (list.size() == 0)
237
                    continue;
238
239
                for (int i = 0; i < list.size(); ++i) {
240
                    QSockNot *sn = list[i];
241
242
                    FD_ZERO(&fdset);
243
                    FD_SET(sn->fd, &fdset);
244
245
                    int ret = -1;
246
                    do {
247
                        switch (type) {
248
                        case 0: // read
249
                            ret = select(sn->fd + 1, &fdset, 0, 0, &tm);
250
                            break;
251
                        case 1: // write
252
                            ret = select(sn->fd + 1, 0, &fdset, 0, &tm);
253
                            break;
254
                        case 2: // except
255
                            ret = select(sn->fd + 1, 0, 0, &fdset, &tm);
256
                            break;
257
                        }
258
                    } while (ret == -1 && (errno == EINTR || errno == EAGAIN));
259
260
                    if (ret == -1 && errno == EBADF) {
261
                        // disable the invalid socket notifier
262
                        static const char *t[] = { "Read", "Write", "Exception" };
263
                        qWarning("QSocketNotifier: Invalid socket %d and type '%s', disabling...",
264
                                 sn->fd, t[type]);
265
                        sn->obj->setEnabled(false);
266
                    }
267
                }
268
            }
269
        } else {
270
            // EINVAL... shouldn't happen, so let's complain to stderr
271
            // and hope someone sends us a bug report
272
            perror("select");
273
        }
274
    }
275
276
    // some other thread woke us up... consume the data on the thread pipe so that
277
    // select doesn't immediately return next time
278
    int nevents = 0;
279
    if (nsel > 0 && FD_ISSET(thread_pipe[0], &sn_vec[0].select_fds)) {
280
#if defined(Q_OS_VXWORKS)
281
        char c[16];
282
        ::read(thread_pipe[0], c, sizeof(c));
283
        ::ioctl(thread_pipe[0], FIOFLUSH, 0);
284
#else
285
        char c[16];
286
        while (::read(thread_pipe[0], c, sizeof(c)) > 0)
287
            ;
288
#endif
289
        if (!wakeUps.testAndSetRelease(1, 0)) {
290
            // hopefully, this is dead code
291
            qWarning("QEventDispatcherUNIX: internal error, wakeUps.testAndSetRelease(1, 0) failed!");
292
        }
293
        ++nevents;
294
    }
295
296
    // activate socket notifiers
297
    if (! (flags & QEventLoop::ExcludeSocketNotifiers) && nsel > 0 && sn_highest >= 0) {
298
        // if select says data is ready on any socket, then set the socket notifier
299
        // to pending
300
        for (int i=0; i<3; i++) {
301
            QSockNotType::List &list = sn_vec[i].list;
302
            for (int j = 0; j < list.size(); ++j) {
303
                QSockNot *sn = list[j];
304
                if (FD_ISSET(sn->fd, &sn_vec[i].select_fds))
305
                    q->setSocketNotifierPending(sn->obj);
306
            }
307
        }
308
    }
309
    return (nevents + q->activateSocketNotifiers());
310
}
311
312
/*
313
 * Internal functions for manipulating timer data structures.  The
314
 * timerBitVec array is used for keeping track of timer identifiers.
315
 */
316
317
QTimerInfoList::QTimerInfoList()
318
{
319
#if (_POSIX_MONOTONIC_CLOCK-0 <= 0) && !defined(Q_OS_MAC) && !defined(Q_OS_NACL)
320
    if (!QElapsedTimer::isMonotonic()) {
321
        // not using monotonic timers, initialize the timeChanged() machinery
322
        previousTime = qt_gettime();
323
324
        tms unused;
325
        previousTicks = times(&unused);
326
327
        ticksPerSecond = sysconf(_SC_CLK_TCK);
328
        msPerTick = 1000/ticksPerSecond;
329
    } else {
330
        // detected monotonic timers
331
        previousTime.tv_sec = previousTime.tv_usec = 0;
332
        previousTicks = 0;
333
        ticksPerSecond = 0;
334
        msPerTick = 0;
335
    }
336
#endif
337
338
    firstTimerInfo = 0;
339
}
340
341
timeval QTimerInfoList::updateCurrentTime()
342
{
343
    return (currentTime = qt_gettime());
344
}
345
346
#if ((_POSIX_MONOTONIC_CLOCK-0 <= 0) && !defined(Q_OS_MAC) && !defined(Q_OS_INTEGRITY)) || defined(QT_BOOTSTRAPPED)
347
348
template <>
349
timeval qAbs(const timeval &t)
350
{
351
    timeval tmp = t;
352
    if (tmp.tv_sec < 0) {
353
        tmp.tv_sec = -tmp.tv_sec - 1;
354
        tmp.tv_usec -= 1000000;
355
    }
356
    if (tmp.tv_sec == 0 && tmp.tv_usec < 0) {
357
        tmp.tv_usec = -tmp.tv_usec;
358
    }
359
    return normalizedTimeval(tmp);
360
}
361
362
/*
363
  Returns true if the real time clock has changed by more than 10%
364
  relative to the processor time since the last time this function was
365
  called. This presumably means that the system time has been changed.
366
367
  If /a delta is nonzero, delta is set to our best guess at how much the system clock was changed.
368
*/
369
bool QTimerInfoList::timeChanged(timeval *delta)
370
{
371
#ifdef Q_OS_NACL
372
    Q_UNUSED(delta)
373
    return false; // Calling "times" crashes.
374
#endif
375
    struct tms unused;
376
    clock_t currentTicks = times(&unused);
377
378
    clock_t elapsedTicks = currentTicks - previousTicks;
379
    timeval elapsedTime = currentTime - previousTime;
380
381
    timeval elapsedTimeTicks;
382
    elapsedTimeTicks.tv_sec = elapsedTicks / ticksPerSecond;
383
    elapsedTimeTicks.tv_usec = (((elapsedTicks * 1000) / ticksPerSecond) % 1000) * 1000;
384
385
    timeval dummy;
386
    if (!delta)
387
        delta = &dummy;
388
    *delta = elapsedTime - elapsedTimeTicks;
389
390
    previousTicks = currentTicks;
391
    previousTime = currentTime;
392
393
    // If tick drift is more than 10% off compared to realtime, we assume that the clock has
394
    // been set. Of course, we have to allow for the tick granularity as well.
395
    timeval tickGranularity;
396
    tickGranularity.tv_sec = 0;
397
    tickGranularity.tv_usec = msPerTick * 1000;
398
    return elapsedTimeTicks < ((qAbs(*delta) - tickGranularity) * 10);
399
}
400
401
void QTimerInfoList::repairTimersIfNeeded()
402
{
403
    if (QElapsedTimer::isMonotonic())
404
        return;
405
    timeval delta;
406
    if (timeChanged(&delta))
407
        timerRepair(delta);
408
}
409
410
#else // !(_POSIX_MONOTONIC_CLOCK-0 <= 0) && !defined(QT_BOOTSTRAPPED)
411
412
void QTimerInfoList::repairTimersIfNeeded()
413
{
414
}
415
416
#endif
417
418
/*
419
  insert timer info into list
420
*/
421
void QTimerInfoList::timerInsert(QTimerInfo *ti)
422
{
423
    int index = size();
424
    while (index--) {
425
        register const QTimerInfo * const t = at(index);
426
        if (!(ti->timeout < t->timeout))
427
            break;
428
    }
429
    insert(index+1, ti);
430
}
431
432
/*
433
  repair broken timer
434
*/
435
void QTimerInfoList::timerRepair(const timeval &diff)
436
{
437
    // repair all timers
438
    for (int i = 0; i < size(); ++i) {
439
        register QTimerInfo *t = at(i);
440
        t->timeout = t->timeout + diff;
441
    }
442
}
443
444
/*
445
  Returns the time to wait for the next timer, or null if no timers
446
  are waiting.
447
*/
448
bool QTimerInfoList::timerWait(timeval &tm)
449
{
450
    timeval currentTime = updateCurrentTime();
451
    repairTimersIfNeeded();
452
453
    // Find first waiting timer not already active
454
    QTimerInfo *t = 0;
455
    for (QTimerInfoList::const_iterator it = constBegin(); it != constEnd(); ++it) {
456
        if (!(*it)->activateRef) {
457
            t = *it;
458
            break;
459
        }
460
    }
461
462
    if (!t)
463
      return false;
464
465
    if (currentTime < t->timeout) {
466
        // time to wait
467
        tm = t->timeout - currentTime;
468
    } else {
469
        // no time to wait
470
        tm.tv_sec  = 0;
471
        tm.tv_usec = 0;
472
    }
473
474
    return true;
475
}
476
477
void QTimerInfoList::registerTimer(int timerId, int interval, QObject *object)
478
{
479
    QTimerInfo *t = new QTimerInfo;
480
    t->id = timerId;
481
    t->interval.tv_sec  = interval / 1000;
482
    t->interval.tv_usec = (interval % 1000) * 1000;
483
    t->timeout = updateCurrentTime() + t->interval;
484
    t->obj = object;
485
    t->activateRef = 0;
486
487
    timerInsert(t);
488
}
489
490
bool QTimerInfoList::unregisterTimer(int timerId)
491
{
492
    // set timer inactive
493
    for (int i = 0; i < count(); ++i) {
494
        register QTimerInfo *t = at(i);
495
        if (t->id == timerId) {
496
            // found it
497
            removeAt(i);
498
            if (t == firstTimerInfo)
499
                firstTimerInfo = 0;
500
            if (t->activateRef)
501
                *(t->activateRef) = 0;
502
503
            // release the timer id
504
            if (!QObjectPrivate::get(t->obj)->inThreadChangeEvent)
505
                QAbstractEventDispatcherPrivate::releaseTimerId(timerId);
506
507
            delete t;
508
            return true;
509
        }
510
    }
511
    // id not found
512
    return false;
513
}
514
515
bool QTimerInfoList::unregisterTimers(QObject *object)
516
{
517
    if (isEmpty())
518
        return false;
519
    for (int i = 0; i < count(); ++i) {
520
        register QTimerInfo *t = at(i);
521
        if (t->obj == object) {
522
            // object found
523
            removeAt(i);
524
            if (t == firstTimerInfo)
525
                firstTimerInfo = 0;
526
            if (t->activateRef)
527
                *(t->activateRef) = 0;
528
529
            // release the timer id
530
            if (!QObjectPrivate::get(t->obj)->inThreadChangeEvent)
531
                QAbstractEventDispatcherPrivate::releaseTimerId(t->id);
532
533
            delete t;
534
            // move back one so that we don't skip the new current item
535
            --i;
536
        }
537
    }
538
    return true;
539
}
540
541
QList<QPair<int, int> > QTimerInfoList::registeredTimers(QObject *object) const
542
{
543
    QList<QPair<int, int> > list;
544
    for (int i = 0; i < count(); ++i) {
545
        register const QTimerInfo * const t = at(i);
546
        if (t->obj == object)
547
            list << QPair<int, int>(t->id, t->interval.tv_sec * 1000 + t->interval.tv_usec / 1000);
548
    }
549
    return list;
550
}
551
552
/*
553
    Activate pending timers, returning how many where activated.
554
*/
555
int QTimerInfoList::activateTimers()
556
{
557
    if (qt_disable_lowpriority_timers || isEmpty())
558
        return 0; // nothing to do
559
560
    int n_act = 0, maxCount = 0;
561
    firstTimerInfo = 0;
562
563
    timeval currentTime = updateCurrentTime();
564
    repairTimersIfNeeded();
565
566
567
    // Find out how many timer have expired
568
    for (QTimerInfoList::const_iterator it = constBegin(); it != constEnd(); ++it) {
569
        if (currentTime < (*it)->timeout)
570
            break;
571
        maxCount++;
572
    }
573
574
    //fire the timers.
575
    while (maxCount--) {
576
        if (isEmpty())
577
            break;
578
579
        QTimerInfo *currentTimerInfo = first();
580
        if (currentTime < currentTimerInfo->timeout)
581
            break; // no timer has expired
582
583
        if (!firstTimerInfo) {
584
            firstTimerInfo = currentTimerInfo;
585
        } else if (firstTimerInfo == currentTimerInfo) {
586
            // avoid sending the same timer multiple times
587
            break;
588
        } else if (currentTimerInfo->interval <  firstTimerInfo->interval
589
                   || currentTimerInfo->interval == firstTimerInfo->interval) {
590
            firstTimerInfo = currentTimerInfo;
591
        }
592
593
        // remove from list
594
        removeFirst();
595
596
        // determine next timeout time
597
        currentTimerInfo->timeout += currentTimerInfo->interval;
598
        if (currentTimerInfo->timeout < currentTime)
599
            currentTimerInfo->timeout = currentTime + currentTimerInfo->interval;
600
601
        // reinsert timer
602
        timerInsert(currentTimerInfo);
603
        if (currentTimerInfo->interval.tv_usec > 0 || currentTimerInfo->interval.tv_sec > 0)
604
            n_act++;
605
606
        if (!currentTimerInfo->activateRef) {
607
            // send event, but don't allow it to recurse
608
            currentTimerInfo->activateRef = &currentTimerInfo;
609
610
            QTimerEvent e(currentTimerInfo->id);
611
            QCoreApplication::sendEvent(currentTimerInfo->obj, &e);
612
613
            if (currentTimerInfo)
614
                currentTimerInfo->activateRef = 0;
615
        }
616
    }
617
618
    firstTimerInfo = 0;
619
    return n_act;
620
}
621
622
QEventDispatcherUNIX::QEventDispatcherUNIX(QObject *parent)
623
    : QAbstractEventDispatcher(*new QEventDispatcherUNIXPrivate, parent)
624
{ }
625
626
QEventDispatcherUNIX::QEventDispatcherUNIX(QEventDispatcherUNIXPrivate &dd, QObject *parent)
627
    : QAbstractEventDispatcher(dd, parent)
628
{ }
629
630
QEventDispatcherUNIX::~QEventDispatcherUNIX()
631
{
632
    Q_D(QEventDispatcherUNIX);
633
    d->threadData->eventDispatcher = 0;
634
}
635
636
int QEventDispatcherUNIX::select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds,
637
                                 timeval *timeout)
638
{
639
    return qt_safe_select(nfds, readfds, writefds, exceptfds, timeout);
640
}
641
642
/*!
643
    \internal
644
*/
645
void QEventDispatcherUNIX::registerTimer(int timerId, int interval, QObject *obj)
646
{
647
#ifndef QT_NO_DEBUG
648
    if (timerId < 1 || interval < 0 || !obj) {
649
        qWarning("QEventDispatcherUNIX::registerTimer: invalid arguments");
650
        return;
651
    } else if (obj->thread() != thread() || thread() != QThread::currentThread()) {
652
        qWarning("QObject::startTimer: timers cannot be started from another thread");
653
        return;
654
    }
655
#endif
656
657
    Q_D(QEventDispatcherUNIX);
658
    d->timerList.registerTimer(timerId, interval, obj);
659
}
660
661
/*!
662
    \internal
663
*/
664
bool QEventDispatcherUNIX::unregisterTimer(int timerId)
665
{
666
#ifndef QT_NO_DEBUG
667
    if (timerId < 1) {
668
        qWarning("QEventDispatcherUNIX::unregisterTimer: invalid argument");
669
        return false;
670
    } else if (thread() != QThread::currentThread()) {
671
        qWarning("QObject::killTimer: timers cannot be stopped from another thread");
672
        return false;
673
    }
674
#endif
675
676
    Q_D(QEventDispatcherUNIX);
677
    return d->timerList.unregisterTimer(timerId);
678
}
679
680
/*!
681
    \internal
682
*/
683
bool QEventDispatcherUNIX::unregisterTimers(QObject *object)
684
{
685
#ifndef QT_NO_DEBUG
686
    if (!object) {
687
        qWarning("QEventDispatcherUNIX::unregisterTimers: invalid argument");
688
        return false;
689
    } else if (object->thread() != thread() || thread() != QThread::currentThread()) {
690
        qWarning("QObject::killTimers: timers cannot be stopped from another thread");
691
        return false;
692
    }
693
#endif
694
695
    Q_D(QEventDispatcherUNIX);
696
    return d->timerList.unregisterTimers(object);
697
}
698
699
QList<QEventDispatcherUNIX::TimerInfo>
700
QEventDispatcherUNIX::registeredTimers(QObject *object) const
701
{
702
    if (!object) {
703
        qWarning("QEventDispatcherUNIX:registeredTimers: invalid argument");
704
        return QList<TimerInfo>();
705
    }
706
707
    Q_D(const QEventDispatcherUNIX);
708
    return d->timerList.registeredTimers(object);
709
}
710
711
/*****************************************************************************
712
 Socket notifier type
713
 *****************************************************************************/
714
QSockNotType::QSockNotType()
715
{
716
    FD_ZERO(&select_fds);
717
    FD_ZERO(&enabled_fds);
718
    FD_ZERO(&pending_fds);
719
}
720
721
QSockNotType::~QSockNotType()
722
{
723
    for (int i = 0; i < list.size(); ++i)
724
        delete list[i];
725
}
726
727
/*****************************************************************************
728
 QEventDispatcher implementations for UNIX
729
 *****************************************************************************/
730
731
void QEventDispatcherUNIX::registerSocketNotifier(QSocketNotifier *notifier)
732
{
733
    Q_ASSERT(notifier);
734
    int sockfd = notifier->socket();
735
    int type = notifier->type();
736
#ifndef QT_NO_DEBUG
737
    if (sockfd < 0
738
        || unsigned(sockfd) >= FD_SETSIZE) {
739
        qWarning("QSocketNotifier: Internal error");
740
        return;
741
    } else if (notifier->thread() != thread()
742
               || thread() != QThread::currentThread()) {
743
        qWarning("QSocketNotifier: socket notifiers cannot be enabled from another thread");
744
        return;
745
    }
746
#endif
747
748
    Q_D(QEventDispatcherUNIX);
749
    QSockNotType::List &list = d->sn_vec[type].list;
750
    fd_set *fds  = &d->sn_vec[type].enabled_fds;
751
    QSockNot *sn;
752
753
    sn = new QSockNot;
754
    sn->obj = notifier;
755
    sn->fd = sockfd;
756
    sn->queue = &d->sn_vec[type].pending_fds;
757
758
    int i;
759
    for (i = 0; i < list.size(); ++i) {
760
        QSockNot *p = list[i];
761
        if (p->fd < sockfd)
762
            break;
763
        if (p->fd == sockfd) {
764
            static const char *t[] = { "Read", "Write", "Exception" };
765
            qWarning("QSocketNotifier: Multiple socket notifiers for "
766
                      "same socket %d and type %s", sockfd, t[type]);
767
        }
768
    }
769
    list.insert(i, sn);
770
771
    FD_SET(sockfd, fds);
772
    d->sn_highest = qMax(d->sn_highest, sockfd);
773
}
774
775
void QEventDispatcherUNIX::unregisterSocketNotifier(QSocketNotifier *notifier)
776
{
777
    Q_ASSERT(notifier);
778
    int sockfd = notifier->socket();
779
    int type = notifier->type();
780
#ifndef QT_NO_DEBUG
781
    if (sockfd < 0
782
        || unsigned(sockfd) >= FD_SETSIZE) {
783
        qWarning("QSocketNotifier: Internal error");
784
        return;
785
    } else if (notifier->thread() != thread()
786
               || thread() != QThread::currentThread()) {
787
        qWarning("QSocketNotifier: socket notifiers cannot be disabled from another thread");
788
        return;
789
    }
790
#endif
791
792
    Q_D(QEventDispatcherUNIX);
793
    QSockNotType::List &list = d->sn_vec[type].list;
794
    fd_set *fds  =  &d->sn_vec[type].enabled_fds;
795
    QSockNot *sn = 0;
796
    int i;
797
    for (i = 0; i < list.size(); ++i) {
798
        sn = list[i];
799
        if(sn->obj == notifier && sn->fd == sockfd)
800
            break;
801
    }
802
    if (i == list.size()) // not found
803
        return;
804
805
    FD_CLR(sockfd, fds);                        // clear fd bit
806
    FD_CLR(sockfd, sn->queue);
807
    d->sn_pending_list.removeAll(sn);                // remove from activation list
808
    list.removeAt(i);                                // remove notifier found above
809
    delete sn;
810
811
    if (d->sn_highest == sockfd) {                // find highest fd
812
        d->sn_highest = -1;
813
        for (int i=0; i<3; i++) {
814
            if (!d->sn_vec[i].list.isEmpty())
815
                d->sn_highest = qMax(d->sn_highest,  // list is fd-sorted
816
                                     d->sn_vec[i].list[0]->fd);
817
        }
818
    }
819
}
820
821
void QEventDispatcherUNIX::setSocketNotifierPending(QSocketNotifier *notifier)
822
{
823
    Q_ASSERT(notifier);
824
    int sockfd = notifier->socket();
825
    int type = notifier->type();
826
#ifndef QT_NO_DEBUG
827
    if (sockfd < 0
828
        || unsigned(sockfd) >= FD_SETSIZE) {
829
        qWarning("QSocketNotifier: Internal error");
830
        return;
831
    }
832
    Q_ASSERT(notifier->thread() == thread() && thread() == QThread::currentThread());
833
#endif
834
835
    Q_D(QEventDispatcherUNIX);
836
    QSockNotType::List &list = d->sn_vec[type].list;
837
    QSockNot *sn = 0;
838
    int i;
839
    for (i = 0; i < list.size(); ++i) {
840
        sn = list[i];
841
        if(sn->obj == notifier && sn->fd == sockfd)
842
            break;
843
    }
844
    if (i == list.size()) // not found
845
        return;
846
847
    // We choose a random activation order to be more fair under high load.
848
    // If a constant order is used and a peer early in the list can
849
    // saturate the IO, it might grab our attention completely.
850
    // Also, if we're using a straight list, the callback routines may
851
    // delete other entries from the list before those other entries are
852
    // processed.
853
    if (! FD_ISSET(sn->fd, sn->queue)) {
854
        if (d->sn_pending_list.isEmpty()) {
855
            d->sn_pending_list.append(sn);
856
        } else {
857
            d->sn_pending_list.insert((qrand() & 0xff) %
858
                                      (d->sn_pending_list.size()+1), sn);
859
        }
860
        FD_SET(sn->fd, sn->queue);
861
    }
862
}
863
864
int QEventDispatcherUNIX::activateTimers()
865
{
866
    Q_ASSERT(thread() == QThread::currentThread());
867
    Q_D(QEventDispatcherUNIX);
868
    return d->timerList.activateTimers();
869
}
870
871
int QEventDispatcherUNIX::activateSocketNotifiers()
872
{
873
    Q_D(QEventDispatcherUNIX);
874
    if (d->sn_pending_list.isEmpty())
875
        return 0;
876
877
    // activate entries
878
    int n_act = 0;
879
    QEvent event(QEvent::SockAct);
880
    while (!d->sn_pending_list.isEmpty()) {
881
        QSockNot *sn = d->sn_pending_list.takeFirst();
882
        if (FD_ISSET(sn->fd, sn->queue)) {
883
            FD_CLR(sn->fd, sn->queue);
884
            QCoreApplication::sendEvent(sn->obj, &event);
885
            ++n_act;
886
        }
887
    }
888
    return n_act;
889
}
890
891
bool QEventDispatcherUNIX::processEvents(QEventLoop::ProcessEventsFlags flags)
892
{
893
    Q_D(QEventDispatcherUNIX);
894
    d->interrupt = false;
895
896
    // we are awake, broadcast it
897
    emit awake();
898
    QCoreApplicationPrivate::sendPostedEvents(0, 0, d->threadData);
899
900
    int nevents = 0;
901
    const bool canWait = (d->threadData->canWait
902
                          && !d->interrupt
903
                          && (flags & QEventLoop::WaitForMoreEvents));
904
905
    if (canWait)
906
        emit aboutToBlock();
907
908
    if (!d->interrupt) {
909
        // return the maximum time we can wait for an event.
910
        timeval *tm = 0;
911
        timeval wait_tm = { 0l, 0l };
912
        if (!(flags & QEventLoop::X11ExcludeTimers)) {
913
            if (d->timerList.timerWait(wait_tm))
914
                tm = &wait_tm;
915
        }
916
917
        if (!canWait) {
918
            if (!tm)
919
                tm = &wait_tm;
920
921
            // no time to wait
922
            tm->tv_sec  = 0l;
923
            tm->tv_usec = 0l;
924
        }
925
926
        nevents = d->doSelect(flags, tm);
927
928
        // activate timers
929
        if (! (flags & QEventLoop::X11ExcludeTimers)) {
930
            nevents += activateTimers();
931
        }
932
    }
933
    // return true if we handled events, false otherwise
934
    return (nevents > 0);
935
}
936
937
bool QEventDispatcherUNIX::hasPendingEvents()
938
{
939
    extern uint qGlobalPostedEventsCount(); // from qapplication.cpp
940
    return qGlobalPostedEventsCount();
941
}
942
943
void QEventDispatcherUNIX::wakeUp()
944
{
945
    Q_D(QEventDispatcherUNIX);
946
    if (d->wakeUps.testAndSetAcquire(0, 1)) {
947
        char c = 0;
948
        qt_safe_write( d->thread_pipe[1], &c, 1 );
949
    }
950
}
951
952
void QEventDispatcherUNIX::interrupt()
953
{
954
    Q_D(QEventDispatcherUNIX);
955
    d->interrupt = true;
956
    wakeUp();
957
}
958
959
void QEventDispatcherUNIX::flush()
960
{ }
961
962
963
964
965
void QCoreApplication::watchUnixSignal(int sig, bool watch)
966
{
967
    if (sig < NSIG) {
968
        struct sigaction sa;
969
        sigemptyset(&(sa.sa_mask));
970
        sa.sa_flags = 0;
971
        if (watch)
972
            sa.sa_handler = signalHandler;
973
        else
974
            sa.sa_handler = SIG_DFL;
975
        sigaction(sig, &sa, 0);
976
    }
977
}
978
979
QT_END_NAMESPACE