1 /****************************************************************************
2 **
3 ** Copyright (C) 2015 The Qt Company Ltd.
4 ** Contact: http://www.qt.io/licensing/
5 **
6 ** This file is part of the QtCore module of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** Commercial License Usage
10 ** Licensees holding valid commercial Qt licenses may use this file in
11 ** accordance with the commercial license agreement provided with the
12 ** Software or, alternatively, in accordance with the terms contained in
13 ** a written agreement between you and The Qt Company. For licensing terms
14 ** and conditions see http://www.qt.io/terms-conditions. For further
15 ** information use the contact form at http://www.qt.io/contact-us.
16 **
17 ** GNU Lesser General Public License Usage
18 ** Alternatively, this file may be used under the terms of the GNU Lesser
19 ** General Public License version 2.1 or version 3 as published by the Free
20 ** Software Foundation and appearing in the file LICENSE.LGPLv21 and
21 ** LICENSE.LGPLv3 included in the packaging of this file. Please review the
22 ** following information to ensure the GNU Lesser General Public License
23 ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
24 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
25 **
26 ** As a special exception, The Qt Company gives you certain additional
27 ** rights. These rights are described in The Qt Company LGPL Exception
28 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
29 **
30 ** GNU General Public License Usage
31 ** Alternatively, this file may be used under the terms of the GNU
32 ** General Public License version 3.0 as published by the Free Software
33 ** Foundation and appearing in the file LICENSE.GPL included in the
34 ** packaging of this file.  Please review the following information to
35 ** ensure the GNU General Public License version 3.0 requirements will be
36 ** met: http://www.gnu.org/copyleft/gpl.html.
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 
signalHandler(int sig)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)
initThreadPipeFD(int fd)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 
QEventDispatcherUNIXPrivate()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) || defined (Q_OS_BLACKBERRY)
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(taskIdSelf()));
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 
~QEventDispatcherUNIXPrivate()160 QEventDispatcherUNIXPrivate::~QEventDispatcherUNIXPrivate()
161 {
162 #if defined(Q_OS_NACL) || defined (Q_OS_BLACKBERRY)
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(taskIdSelf()));
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 
doSelect(QEventLoop::ProcessEventsFlags flags,timeval * timeout)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         int wakeUpFd = initThreadWakeUp();
217         highest = qMax(highest, wakeUpFd);
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     int nevents = processThreadWakeUp(nsel);
277 
278     // activate socket notifiers
279     if (! (flags & QEventLoop::ExcludeSocketNotifiers) && nsel > 0 && sn_highest >= 0) {
280         // if select says data is ready on any socket, then set the socket notifier
281         // to pending
282         for (int i=0; i<3; i++) {
283             QSockNotType::List &list = sn_vec[i].list;
284             for (int j = 0; j < list.size(); ++j) {
285                 QSockNot *sn = list[j];
286                 if (FD_ISSET(sn->fd, &sn_vec[i].select_fds))
287                     q->setSocketNotifierPending(sn->obj);
288             }
289         }
290     }
291     return (nevents + q->activateSocketNotifiers());
292 }
293 
initThreadWakeUp()294 int QEventDispatcherUNIXPrivate::initThreadWakeUp()
295 {
296     FD_SET(thread_pipe[0], &sn_vec[0].select_fds);
297     return thread_pipe[0];
298 }
299 
processThreadWakeUp(int nsel)300 int QEventDispatcherUNIXPrivate::processThreadWakeUp(int nsel)
301 {
302     if (nsel > 0 && FD_ISSET(thread_pipe[0], &sn_vec[0].select_fds)) {
303         // some other thread woke us up... consume the data on the thread pipe so that
304         // select doesn't immediately return next time
305 #if defined(Q_OS_VXWORKS)
306         char c[16];
307         ::read(thread_pipe[0], c, sizeof(c));
308         ::ioctl(thread_pipe[0], FIOFLUSH, 0);
309 #else
310         char c[16];
311         while (::read(thread_pipe[0], c, sizeof(c)) > 0)
312             ;
313 #endif
314         if (!wakeUps.testAndSetRelease(1, 0)) {
315             // hopefully, this is dead code
316             qWarning("QEventDispatcherUNIX: internal error, wakeUps.testAndSetRelease(1, 0) failed!");
317         }
318         return 1;
319     }
320     return 0;
321 }
322 
323 /*
324  * Internal functions for manipulating timer data structures.  The
325  * timerBitVec array is used for keeping track of timer identifiers.
326  */
327 
QTimerInfoList()328 QTimerInfoList::QTimerInfoList()
329 {
330 #if (_POSIX_MONOTONIC_CLOCK-0 <= 0) && !defined(Q_OS_MAC) && !defined(Q_OS_NACL)
331     if (!QElapsedTimer::isMonotonic()) {
332         // not using monotonic timers, initialize the timeChanged() machinery
333         previousTime = qt_gettime();
334 
335         tms unused;
336         previousTicks = times(&unused);
337 
338         ticksPerSecond = sysconf(_SC_CLK_TCK);
339         msPerTick = 1000/ticksPerSecond;
340     } else {
341         // detected monotonic timers
342         previousTime.tv_sec = previousTime.tv_usec = 0;
343         previousTicks = 0;
344         ticksPerSecond = 0;
345         msPerTick = 0;
346     }
347 #endif
348 
349     firstTimerInfo = 0;
350 }
351 
updateCurrentTime()352 timeval QTimerInfoList::updateCurrentTime()
353 {
354     return (currentTime = qt_gettime());
355 }
356 
357 #if ((_POSIX_MONOTONIC_CLOCK-0 <= 0) && !defined(Q_OS_MAC) && !defined(Q_OS_INTEGRITY)) || defined(QT_BOOTSTRAPPED)
358 
qAbsTimeval(const timeval & t)359 timeval qAbsTimeval(const timeval &t)
360 {
361     timeval tmp = t;
362     if (tmp.tv_sec < 0) {
363         tmp.tv_sec = -tmp.tv_sec - 1;
364         tmp.tv_usec -= 1000000;
365     }
366     if (tmp.tv_sec == 0 && tmp.tv_usec < 0) {
367         tmp.tv_usec = -tmp.tv_usec;
368     }
369     return normalizedTimeval(tmp);
370 }
371 
372 /*
373   Returns true if the real time clock has changed by more than 10%
374   relative to the processor time since the last time this function was
375   called. This presumably means that the system time has been changed.
376 
377   If /a delta is nonzero, delta is set to our best guess at how much the system clock was changed.
378 */
timeChanged(timeval * delta)379 bool QTimerInfoList::timeChanged(timeval *delta)
380 {
381 #ifdef Q_OS_NACL
382     Q_UNUSED(delta)
383     return false; // Calling "times" crashes.
384 #endif
385     struct tms unused;
386     clock_t currentTicks = times(&unused);
387 
388     clock_t elapsedTicks = currentTicks - previousTicks;
389     timeval elapsedTime = currentTime - previousTime;
390 
391     timeval elapsedTimeTicks;
392     elapsedTimeTicks.tv_sec = elapsedTicks / ticksPerSecond;
393     elapsedTimeTicks.tv_usec = (((elapsedTicks * 1000) / ticksPerSecond) % 1000) * 1000;
394 
395     timeval dummy;
396     if (!delta)
397         delta = &dummy;
398     *delta = elapsedTime - elapsedTimeTicks;
399 
400     previousTicks = currentTicks;
401     previousTime = currentTime;
402 
403     // If tick drift is more than 10% off compared to realtime, we assume that the clock has
404     // been set. Of course, we have to allow for the tick granularity as well.
405     timeval tickGranularity;
406     tickGranularity.tv_sec = 0;
407     tickGranularity.tv_usec = msPerTick * 1000;
408     return elapsedTimeTicks < ((qAbsTimeval(*delta) - tickGranularity) * 10);
409 }
410 
repairTimersIfNeeded()411 void QTimerInfoList::repairTimersIfNeeded()
412 {
413     if (QElapsedTimer::isMonotonic())
414         return;
415     timeval delta;
416     if (timeChanged(&delta))
417         timerRepair(delta);
418 }
419 
420 #else // !(_POSIX_MONOTONIC_CLOCK-0 <= 0) && !defined(QT_BOOTSTRAPPED)
421 
repairTimersIfNeeded()422 void QTimerInfoList::repairTimersIfNeeded()
423 {
424 }
425 
426 #endif
427 
428 /*
429   insert timer info into list
430 */
timerInsert(QTimerInfo * ti)431 void QTimerInfoList::timerInsert(QTimerInfo *ti)
432 {
433     int index = size();
434     while (index--) {
435         register const QTimerInfo * const t = at(index);
436         if (!(ti->timeout < t->timeout))
437             break;
438     }
439     insert(index+1, ti);
440 }
441 
442 /*
443   repair broken timer
444 */
timerRepair(const timeval & diff)445 void QTimerInfoList::timerRepair(const timeval &diff)
446 {
447     // repair all timers
448     for (int i = 0; i < size(); ++i) {
449         register QTimerInfo *t = at(i);
450         t->timeout = t->timeout + diff;
451     }
452 }
453 
454 /*
455   Returns the time to wait for the next timer, or null if no timers
456   are waiting.
457 */
timerWait(timeval & tm)458 bool QTimerInfoList::timerWait(timeval &tm)
459 {
460     timeval currentTime = updateCurrentTime();
461     repairTimersIfNeeded();
462 
463     // Find first waiting timer not already active
464     QTimerInfo *t = 0;
465     for (QTimerInfoList::const_iterator it = constBegin(); it != constEnd(); ++it) {
466         if (!(*it)->activateRef) {
467             t = *it;
468             break;
469         }
470     }
471 
472     if (!t)
473       return false;
474 
475     if (currentTime < t->timeout) {
476         // time to wait
477         tm = t->timeout - currentTime;
478     } else {
479         // no time to wait
480         tm.tv_sec  = 0;
481         tm.tv_usec = 0;
482     }
483 
484     return true;
485 }
486 
registerTimer(int timerId,int interval,QObject * object)487 void QTimerInfoList::registerTimer(int timerId, int interval, QObject *object)
488 {
489     QTimerInfo *t = new QTimerInfo;
490     t->id = timerId;
491     t->interval.tv_sec  = interval / 1000;
492     t->interval.tv_usec = (interval % 1000) * 1000;
493     t->timeout = updateCurrentTime() + t->interval;
494     t->obj = object;
495     t->activateRef = 0;
496 
497     timerInsert(t);
498 }
499 
unregisterTimer(int timerId)500 bool QTimerInfoList::unregisterTimer(int timerId)
501 {
502     // set timer inactive
503     for (int i = 0; i < count(); ++i) {
504         register QTimerInfo *t = at(i);
505         if (t->id == timerId) {
506             // found it
507             removeAt(i);
508             if (t == firstTimerInfo)
509                 firstTimerInfo = 0;
510             if (t->activateRef)
511                 *(t->activateRef) = 0;
512 
513             // release the timer id
514             if (!QObjectPrivate::get(t->obj)->inThreadChangeEvent)
515                 QAbstractEventDispatcherPrivate::releaseTimerId(timerId);
516 
517             delete t;
518             return true;
519         }
520     }
521     // id not found
522     return false;
523 }
524 
unregisterTimers(QObject * object)525 bool QTimerInfoList::unregisterTimers(QObject *object)
526 {
527     if (isEmpty())
528         return false;
529     for (int i = 0; i < count(); ++i) {
530         register QTimerInfo *t = at(i);
531         if (t->obj == object) {
532             // object found
533             removeAt(i);
534             if (t == firstTimerInfo)
535                 firstTimerInfo = 0;
536             if (t->activateRef)
537                 *(t->activateRef) = 0;
538 
539             // release the timer id
540             if (!QObjectPrivate::get(t->obj)->inThreadChangeEvent)
541                 QAbstractEventDispatcherPrivate::releaseTimerId(t->id);
542 
543             delete t;
544             // move back one so that we don't skip the new current item
545             --i;
546         }
547     }
548     return true;
549 }
550 
registeredTimers(QObject * object) const551 QList<QPair<int, int> > QTimerInfoList::registeredTimers(QObject *object) const
552 {
553     QList<QPair<int, int> > list;
554     for (int i = 0; i < count(); ++i) {
555         register const QTimerInfo * const t = at(i);
556         if (t->obj == object)
557             list << QPair<int, int>(t->id, t->interval.tv_sec * 1000 + t->interval.tv_usec / 1000);
558     }
559     return list;
560 }
561 
562 /*
563     Activate pending timers, returning how many where activated.
564 */
activateTimers()565 int QTimerInfoList::activateTimers()
566 {
567     if (qt_disable_lowpriority_timers || isEmpty())
568         return 0; // nothing to do
569 
570     int n_act = 0, maxCount = 0;
571     firstTimerInfo = 0;
572 
573     timeval currentTime = updateCurrentTime();
574     repairTimersIfNeeded();
575 
576 
577     // Find out how many timer have expired
578     for (QTimerInfoList::const_iterator it = constBegin(); it != constEnd(); ++it) {
579         if (currentTime < (*it)->timeout)
580             break;
581         maxCount++;
582     }
583 
584     //fire the timers.
585     while (maxCount--) {
586         if (isEmpty())
587             break;
588 
589         QTimerInfo *currentTimerInfo = first();
590         if (currentTime < currentTimerInfo->timeout)
591             break; // no timer has expired
592 
593         if (!firstTimerInfo) {
594             firstTimerInfo = currentTimerInfo;
595         } else if (firstTimerInfo == currentTimerInfo) {
596             // avoid sending the same timer multiple times
597             break;
598         } else if (currentTimerInfo->interval <  firstTimerInfo->interval
599                    || currentTimerInfo->interval == firstTimerInfo->interval) {
600             firstTimerInfo = currentTimerInfo;
601         }
602 
603         // remove from list
604         removeFirst();
605 
606         // determine next timeout time
607         currentTimerInfo->timeout += currentTimerInfo->interval;
608         if (currentTimerInfo->timeout < currentTime)
609             currentTimerInfo->timeout = currentTime + currentTimerInfo->interval;
610 
611         // reinsert timer
612         timerInsert(currentTimerInfo);
613         if (currentTimerInfo->interval.tv_usec > 0 || currentTimerInfo->interval.tv_sec > 0)
614             n_act++;
615 
616         if (!currentTimerInfo->activateRef) {
617             // send event, but don't allow it to recurse
618             currentTimerInfo->activateRef = &currentTimerInfo;
619 
620             QTimerEvent e(currentTimerInfo->id);
621             QCoreApplication::sendEvent(currentTimerInfo->obj, &e);
622 
623             if (currentTimerInfo)
624                 currentTimerInfo->activateRef = 0;
625         }
626     }
627 
628     firstTimerInfo = 0;
629     return n_act;
630 }
631 
QEventDispatcherUNIX(QObject * parent)632 QEventDispatcherUNIX::QEventDispatcherUNIX(QObject *parent)
633     : QAbstractEventDispatcher(*new QEventDispatcherUNIXPrivate, parent)
634 { }
635 
QEventDispatcherUNIX(QEventDispatcherUNIXPrivate & dd,QObject * parent)636 QEventDispatcherUNIX::QEventDispatcherUNIX(QEventDispatcherUNIXPrivate &dd, QObject *parent)
637     : QAbstractEventDispatcher(dd, parent)
638 { }
639 
~QEventDispatcherUNIX()640 QEventDispatcherUNIX::~QEventDispatcherUNIX()
641 {
642     Q_D(QEventDispatcherUNIX);
643     d->threadData->eventDispatcher = 0;
644 }
645 
select(int nfds,fd_set * readfds,fd_set * writefds,fd_set * exceptfds,timeval * timeout)646 int QEventDispatcherUNIX::select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds,
647                                  timeval *timeout)
648 {
649     return qt_safe_select(nfds, readfds, writefds, exceptfds, timeout);
650 }
651 
652 /*!
653     \internal
654 */
registerTimer(int timerId,int interval,QObject * obj)655 void QEventDispatcherUNIX::registerTimer(int timerId, int interval, QObject *obj)
656 {
657 #ifndef QT_NO_DEBUG
658     if (timerId < 1 || interval < 0 || !obj) {
659         qWarning("QEventDispatcherUNIX::registerTimer: invalid arguments");
660         return;
661     } else if (obj->thread() != thread() || thread() != QThread::currentThread()) {
662         qWarning("QObject::startTimer: timers cannot be started from another thread");
663         return;
664     }
665 #endif
666 
667     Q_D(QEventDispatcherUNIX);
668     d->timerList.registerTimer(timerId, interval, obj);
669 }
670 
671 /*!
672     \internal
673 */
unregisterTimer(int timerId)674 bool QEventDispatcherUNIX::unregisterTimer(int timerId)
675 {
676 #ifndef QT_NO_DEBUG
677     if (timerId < 1) {
678         qWarning("QEventDispatcherUNIX::unregisterTimer: invalid argument");
679         return false;
680     } else if (thread() != QThread::currentThread()) {
681         qWarning("QObject::killTimer: timers cannot be stopped from another thread");
682         return false;
683     }
684 #endif
685 
686     Q_D(QEventDispatcherUNIX);
687     return d->timerList.unregisterTimer(timerId);
688 }
689 
690 /*!
691     \internal
692 */
unregisterTimers(QObject * object)693 bool QEventDispatcherUNIX::unregisterTimers(QObject *object)
694 {
695 #ifndef QT_NO_DEBUG
696     if (!object) {
697         qWarning("QEventDispatcherUNIX::unregisterTimers: invalid argument");
698         return false;
699     } else if (object->thread() != thread() || thread() != QThread::currentThread()) {
700         qWarning("QObject::killTimers: timers cannot be stopped from another thread");
701         return false;
702     }
703 #endif
704 
705     Q_D(QEventDispatcherUNIX);
706     return d->timerList.unregisterTimers(object);
707 }
708 
709 QList<QEventDispatcherUNIX::TimerInfo>
registeredTimers(QObject * object) const710 QEventDispatcherUNIX::registeredTimers(QObject *object) const
711 {
712     if (!object) {
713         qWarning("QEventDispatcherUNIX:registeredTimers: invalid argument");
714         return QList<TimerInfo>();
715     }
716 
717     Q_D(const QEventDispatcherUNIX);
718     return d->timerList.registeredTimers(object);
719 }
720 
721 /*****************************************************************************
722  Socket notifier type
723  *****************************************************************************/
QSockNotType()724 QSockNotType::QSockNotType()
725 {
726     FD_ZERO(&select_fds);
727     FD_ZERO(&enabled_fds);
728     FD_ZERO(&pending_fds);
729 }
730 
~QSockNotType()731 QSockNotType::~QSockNotType()
732 {
733     for (int i = 0; i < list.size(); ++i)
734         delete list[i];
735 }
736 
737 /*****************************************************************************
738  QEventDispatcher implementations for UNIX
739  *****************************************************************************/
740 
registerSocketNotifier(QSocketNotifier * notifier)741 void QEventDispatcherUNIX::registerSocketNotifier(QSocketNotifier *notifier)
742 {
743     Q_ASSERT(notifier);
744     int sockfd = notifier->socket();
745     int type = notifier->type();
746 #ifndef QT_NO_DEBUG
747     if (sockfd < 0
748         || unsigned(sockfd) >= FD_SETSIZE) {
749         qWarning("QSocketNotifier: Internal error");
750         return;
751     } else if (notifier->thread() != thread()
752                || thread() != QThread::currentThread()) {
753         qWarning("QSocketNotifier: socket notifiers cannot be enabled from another thread");
754         return;
755     }
756 #endif
757 
758     Q_D(QEventDispatcherUNIX);
759     QSockNotType::List &list = d->sn_vec[type].list;
760     fd_set *fds  = &d->sn_vec[type].enabled_fds;
761     QSockNot *sn;
762 
763     sn = new QSockNot;
764     sn->obj = notifier;
765     sn->fd = sockfd;
766     sn->queue = &d->sn_vec[type].pending_fds;
767 
768     int i;
769     for (i = 0; i < list.size(); ++i) {
770         QSockNot *p = list[i];
771         if (p->fd < sockfd)
772             break;
773         if (p->fd == sockfd) {
774             static const char *t[] = { "Read", "Write", "Exception" };
775             qWarning("QSocketNotifier: Multiple socket notifiers for "
776                       "same socket %d and type %s", sockfd, t[type]);
777         }
778     }
779     list.insert(i, sn);
780 
781     FD_SET(sockfd, fds);
782     d->sn_highest = qMax(d->sn_highest, sockfd);
783 }
784 
unregisterSocketNotifier(QSocketNotifier * notifier)785 void QEventDispatcherUNIX::unregisterSocketNotifier(QSocketNotifier *notifier)
786 {
787     Q_ASSERT(notifier);
788     int sockfd = notifier->socket();
789     int type = notifier->type();
790 #ifndef QT_NO_DEBUG
791     if (sockfd < 0
792         || unsigned(sockfd) >= FD_SETSIZE) {
793         qWarning("QSocketNotifier: Internal error");
794         return;
795     } else if (notifier->thread() != thread()
796                || thread() != QThread::currentThread()) {
797         qWarning("QSocketNotifier: socket notifiers cannot be disabled from another thread");
798         return;
799     }
800 #endif
801 
802     Q_D(QEventDispatcherUNIX);
803     QSockNotType::List &list = d->sn_vec[type].list;
804     fd_set *fds  =  &d->sn_vec[type].enabled_fds;
805     QSockNot *sn = 0;
806     int i;
807     for (i = 0; i < list.size(); ++i) {
808         sn = list[i];
809         if(sn->obj == notifier && sn->fd == sockfd)
810             break;
811     }
812     if (i == list.size()) // not found
813         return;
814 
815     FD_CLR(sockfd, fds);                        // clear fd bit
816     FD_CLR(sockfd, sn->queue);
817     d->sn_pending_list.removeAll(sn);                // remove from activation list
818     list.removeAt(i);                                // remove notifier found above
819     delete sn;
820 
821     if (d->sn_highest == sockfd) {                // find highest fd
822         d->sn_highest = -1;
823         for (int i=0; i<3; i++) {
824             if (!d->sn_vec[i].list.isEmpty())
825                 d->sn_highest = qMax(d->sn_highest,  // list is fd-sorted
826                                      d->sn_vec[i].list[0]->fd);
827         }
828     }
829 }
830 
setSocketNotifierPending(QSocketNotifier * notifier)831 void QEventDispatcherUNIX::setSocketNotifierPending(QSocketNotifier *notifier)
832 {
833     Q_ASSERT(notifier);
834     int sockfd = notifier->socket();
835     int type = notifier->type();
836 #ifndef QT_NO_DEBUG
837     if (sockfd < 0
838         || unsigned(sockfd) >= FD_SETSIZE) {
839         qWarning("QSocketNotifier: Internal error");
840         return;
841     }
842     Q_ASSERT(notifier->thread() == thread() && thread() == QThread::currentThread());
843 #endif
844 
845     Q_D(QEventDispatcherUNIX);
846     QSockNotType::List &list = d->sn_vec[type].list;
847     QSockNot *sn = 0;
848     int i;
849     for (i = 0; i < list.size(); ++i) {
850         sn = list[i];
851         if(sn->obj == notifier && sn->fd == sockfd)
852             break;
853     }
854     if (i == list.size()) // not found
855         return;
856 
857     // We choose a random activation order to be more fair under high load.
858     // If a constant order is used and a peer early in the list can
859     // saturate the IO, it might grab our attention completely.
860     // Also, if we're using a straight list, the callback routines may
861     // delete other entries from the list before those other entries are
862     // processed.
863     if (! FD_ISSET(sn->fd, sn->queue)) {
864         if (d->sn_pending_list.isEmpty()) {
865             d->sn_pending_list.append(sn);
866         } else {
867             d->sn_pending_list.insert((qrand() & 0xff) %
868                                       (d->sn_pending_list.size()+1), sn);
869         }
870         FD_SET(sn->fd, sn->queue);
871     }
872 }
873 
activateTimers()874 int QEventDispatcherUNIX::activateTimers()
875 {
876     Q_ASSERT(thread() == QThread::currentThread());
877     Q_D(QEventDispatcherUNIX);
878     return d->timerList.activateTimers();
879 }
880 
activateSocketNotifiers()881 int QEventDispatcherUNIX::activateSocketNotifiers()
882 {
883     Q_D(QEventDispatcherUNIX);
884     if (d->sn_pending_list.isEmpty())
885         return 0;
886 
887     // activate entries
888     int n_act = 0;
889     QEvent event(QEvent::SockAct);
890     while (!d->sn_pending_list.isEmpty()) {
891         QSockNot *sn = d->sn_pending_list.takeFirst();
892         if (FD_ISSET(sn->fd, sn->queue)) {
893             FD_CLR(sn->fd, sn->queue);
894             QCoreApplication::sendEvent(sn->obj, &event);
895             ++n_act;
896         }
897     }
898     return n_act;
899 }
900 
processEvents(QEventLoop::ProcessEventsFlags flags)901 bool QEventDispatcherUNIX::processEvents(QEventLoop::ProcessEventsFlags flags)
902 {
903     Q_D(QEventDispatcherUNIX);
904     d->interrupt = false;
905 
906     // we are awake, broadcast it
907     emit awake();
908     QCoreApplicationPrivate::sendPostedEvents(0, 0, d->threadData);
909 
910     int nevents = 0;
911     const bool canWait = (d->threadData->canWaitLocked()
912                           && !d->interrupt
913                           && (flags & QEventLoop::WaitForMoreEvents));
914 
915     if (canWait)
916         emit aboutToBlock();
917 
918     if (!d->interrupt) {
919         // return the maximum time we can wait for an event.
920         timeval *tm = 0;
921         timeval wait_tm = { 0l, 0l };
922         if (!(flags & QEventLoop::X11ExcludeTimers)) {
923             if (d->timerList.timerWait(wait_tm))
924                 tm = &wait_tm;
925         }
926 
927         if (!canWait) {
928             if (!tm)
929                 tm = &wait_tm;
930 
931             // no time to wait
932             tm->tv_sec  = 0l;
933             tm->tv_usec = 0l;
934         }
935 
936         nevents = d->doSelect(flags, tm);
937 
938         // activate timers
939         if (! (flags & QEventLoop::X11ExcludeTimers)) {
940             nevents += activateTimers();
941         }
942     }
943     // return true if we handled events, false otherwise
944     return (nevents > 0);
945 }
946 
hasPendingEvents()947 bool QEventDispatcherUNIX::hasPendingEvents()
948 {
949     extern uint qGlobalPostedEventsCount(); // from qapplication.cpp
950     return qGlobalPostedEventsCount();
951 }
952 
wakeUp()953 void QEventDispatcherUNIX::wakeUp()
954 {
955     Q_D(QEventDispatcherUNIX);
956     if (d->wakeUps.testAndSetAcquire(0, 1)) {
957         char c = 0;
958         qt_safe_write( d->thread_pipe[1], &c, 1 );
959     }
960 }
961 
interrupt()962 void QEventDispatcherUNIX::interrupt()
963 {
964     Q_D(QEventDispatcherUNIX);
965     d->interrupt = true;
966     wakeUp();
967 }
968 
flush()969 void QEventDispatcherUNIX::flush()
970 { }
971 
972 
973 
974 
watchUnixSignal(int sig,bool watch)975 void QCoreApplication::watchUnixSignal(int sig, bool watch)
976 {
977     if (sig < NSIG) {
978         struct sigaction sa;
979         sigemptyset(&(sa.sa_mask));
980         sa.sa_flags = 0;
981         if (watch)
982             sa.sa_handler = signalHandler;
983         else
984             sa.sa_handler = SIG_DFL;
985         sigaction(sig, &sa, 0);
986     }
987 }
988 
989 QT_END_NAMESPACE
990