1 /****************************************************************************
2 **
3 ** Copyright (C) 2016 The Qt Company Ltd.
4 ** Copyright (C) 2016 Intel Corporation.
5 ** Contact: https://www.qt.io/licensing/
6 **
7 ** This file is part of the QtCore module of the Qt Toolkit.
8 **
9 ** $QT_BEGIN_LICENSE:LGPL$
10 ** Commercial License Usage
11 ** Licensees holding valid commercial Qt licenses may use this file in
12 ** accordance with the commercial license agreement provided with the
13 ** Software or, alternatively, in accordance with the terms contained in
14 ** a written agreement between you and The Qt Company. For licensing terms
15 ** and conditions see https://www.qt.io/terms-conditions. For further
16 ** information use the contact form at https://www.qt.io/contact-us.
17 **
18 ** GNU Lesser General Public License Usage
19 ** Alternatively, this file may be used under the terms of the GNU Lesser
20 ** General Public License version 3 as published by the Free Software
21 ** Foundation and appearing in the file LICENSE.LGPL3 included in the
22 ** packaging of this file. Please review the following information to
23 ** ensure the GNU Lesser General Public License version 3 requirements
24 ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
25 **
26 ** GNU General Public License Usage
27 ** Alternatively, this file may be used under the terms of the GNU
28 ** General Public License version 2.0 or (at your option) the GNU General
29 ** Public license version 3 or any later version approved by the KDE Free
30 ** Qt Foundation. The licenses are as published by the Free Software
31 ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
32 ** included in the packaging of this file. Please review the following
33 ** information to ensure the GNU General Public License requirements will
34 ** be met: https://www.gnu.org/licenses/gpl-2.0.html and
35 ** https://www.gnu.org/licenses/gpl-3.0.html.
36 **
37 ** $QT_END_LICENSE$
38 **
39 ****************************************************************************/
40 
41 #include "qplatformdefs.h"
42 
43 #include "qcoreapplication.h"
44 #include "qpair.h"
45 #include "qsocketnotifier.h"
46 #include "qthread.h"
47 #include "qelapsedtimer.h"
48 
49 #include "qeventdispatcher_unix_p.h"
50 #include <private/qthread_p.h>
51 #include <private/qcoreapplication_p.h>
52 #include <private/qcore_unix_p.h>
53 
54 #include <errno.h>
55 #include <stdio.h>
56 #include <stdlib.h>
57 
58 #ifndef QT_NO_EVENTFD
59 #  include <sys/eventfd.h>
60 #endif
61 
62 // VxWorks doesn't correctly set the _POSIX_... options
63 #if defined(Q_OS_VXWORKS)
64 #  if defined(_POSIX_MONOTONIC_CLOCK) && (_POSIX_MONOTONIC_CLOCK <= 0)
65 #    undef _POSIX_MONOTONIC_CLOCK
66 #    define _POSIX_MONOTONIC_CLOCK 1
67 #  endif
68 #  include <pipeDrv.h>
69 #  include <sys/time.h>
70 #endif
71 
72 #if (_POSIX_MONOTONIC_CLOCK-0 <= 0) || defined(QT_BOOTSTRAPPED)
73 #  include <sys/times.h>
74 #endif
75 
76 QT_BEGIN_NAMESPACE
77 
socketType(QSocketNotifier::Type type)78 static const char *socketType(QSocketNotifier::Type type)
79 {
80     switch (type) {
81     case QSocketNotifier::Read:
82         return "Read";
83     case QSocketNotifier::Write:
84         return "Write";
85     case QSocketNotifier::Exception:
86         return "Exception";
87     }
88 
89     Q_UNREACHABLE();
90 }
91 
QThreadPipe()92 QThreadPipe::QThreadPipe()
93 {
94     fds[0] = -1;
95     fds[1] = -1;
96 #if defined(Q_OS_VXWORKS)
97     name[0] = '\0';
98 #endif
99 }
100 
~QThreadPipe()101 QThreadPipe::~QThreadPipe()
102 {
103     if (fds[0] >= 0)
104         close(fds[0]);
105 
106     if (fds[1] >= 0)
107         close(fds[1]);
108 
109 #if defined(Q_OS_VXWORKS)
110     pipeDevDelete(name, true);
111 #endif
112 }
113 
114 #if defined(Q_OS_VXWORKS)
initThreadPipeFD(int fd)115 static void initThreadPipeFD(int fd)
116 {
117     int ret = fcntl(fd, F_SETFD, FD_CLOEXEC);
118     if (ret == -1)
119         perror("QEventDispatcherUNIXPrivate: Unable to init thread pipe");
120 
121     int flags = fcntl(fd, F_GETFL);
122     if (flags == -1)
123         perror("QEventDispatcherUNIXPrivate: Unable to get flags on thread pipe");
124 
125     ret = fcntl(fd, F_SETFL, flags | O_NONBLOCK);
126     if (ret == -1)
127         perror("QEventDispatcherUNIXPrivate: Unable to set flags on thread pipe");
128 }
129 #endif
130 
init()131 bool QThreadPipe::init()
132 {
133 #if defined(Q_OS_NACL) || defined(Q_OS_WASM)
134    // do nothing.
135 #elif defined(Q_OS_VXWORKS)
136     qsnprintf(name, sizeof(name), "/pipe/qt_%08x", int(taskIdSelf()));
137 
138     // make sure there is no pipe with this name
139     pipeDevDelete(name, true);
140 
141     // create the pipe
142     if (pipeDevCreate(name, 128 /*maxMsg*/, 1 /*maxLength*/) != OK) {
143         perror("QThreadPipe: Unable to create thread pipe device %s", name);
144         return false;
145     }
146 
147     if ((fds[0] = open(name, O_RDWR, 0)) < 0) {
148         perror("QThreadPipe: Unable to open pipe device %s", name);
149         return false;
150     }
151 
152     initThreadPipeFD(fds[0]);
153     fds[1] = fds[0];
154 #else
155 #  ifndef QT_NO_EVENTFD
156     if ((fds[0] = eventfd(0, EFD_NONBLOCK | EFD_CLOEXEC)) >= 0)
157         return true;
158 #  endif
159     if (qt_safe_pipe(fds, O_NONBLOCK) == -1) {
160         perror("QThreadPipe: Unable to create pipe");
161         return false;
162     }
163 #endif
164 
165     return true;
166 }
167 
prepare() const168 pollfd QThreadPipe::prepare() const
169 {
170     return qt_make_pollfd(fds[0], POLLIN);
171 }
172 
wakeUp()173 void QThreadPipe::wakeUp()
174 {
175     if (wakeUps.testAndSetAcquire(0, 1)) {
176 #ifndef QT_NO_EVENTFD
177         if (fds[1] == -1) {
178             // eventfd
179             eventfd_t value = 1;
180             int ret;
181             EINTR_LOOP(ret, eventfd_write(fds[0], value));
182             return;
183         }
184 #endif
185         char c = 0;
186         qt_safe_write(fds[1], &c, 1);
187     }
188 }
189 
check(const pollfd & pfd)190 int QThreadPipe::check(const pollfd &pfd)
191 {
192     Q_ASSERT(pfd.fd == fds[0]);
193 
194     char c[16];
195     const int readyread = pfd.revents & POLLIN;
196 
197     if (readyread) {
198         // consume the data on the thread pipe so that
199         // poll doesn't immediately return next time
200 #if defined(Q_OS_VXWORKS)
201         ::read(fds[0], c, sizeof(c));
202         ::ioctl(fds[0], FIOFLUSH, 0);
203 #else
204 #  ifndef QT_NO_EVENTFD
205         if (fds[1] == -1) {
206             // eventfd
207             eventfd_t value;
208             eventfd_read(fds[0], &value);
209         } else
210 #  endif
211         {
212             while (::read(fds[0], c, sizeof(c)) > 0) {}
213         }
214 #endif
215 
216         if (!wakeUps.testAndSetRelease(1, 0)) {
217             // hopefully, this is dead code
218             qWarning("QThreadPipe: internal error, wakeUps.testAndSetRelease(1, 0) failed!");
219         }
220     }
221 
222     return readyread;
223 }
224 
QEventDispatcherUNIXPrivate()225 QEventDispatcherUNIXPrivate::QEventDispatcherUNIXPrivate()
226 {
227     if (Q_UNLIKELY(threadPipe.init() == false))
228         qFatal("QEventDispatcherUNIXPrivate(): Cannot continue without a thread pipe");
229 }
230 
~QEventDispatcherUNIXPrivate()231 QEventDispatcherUNIXPrivate::~QEventDispatcherUNIXPrivate()
232 {
233     // cleanup timers
234     qDeleteAll(timerList);
235 }
236 
setSocketNotifierPending(QSocketNotifier * notifier)237 void QEventDispatcherUNIXPrivate::setSocketNotifierPending(QSocketNotifier *notifier)
238 {
239     Q_ASSERT(notifier);
240 
241     if (pendingNotifiers.contains(notifier))
242         return;
243 
244     pendingNotifiers << notifier;
245 }
246 
activateTimers()247 int QEventDispatcherUNIXPrivate::activateTimers()
248 {
249     return timerList.activateTimers();
250 }
251 
markPendingSocketNotifiers()252 void QEventDispatcherUNIXPrivate::markPendingSocketNotifiers()
253 {
254     for (const pollfd &pfd : qAsConst(pollfds)) {
255         if (pfd.fd < 0 || pfd.revents == 0)
256             continue;
257 
258         auto it = socketNotifiers.find(pfd.fd);
259         Q_ASSERT(it != socketNotifiers.end());
260 
261         const QSocketNotifierSetUNIX &sn_set = it.value();
262 
263         static const struct {
264             QSocketNotifier::Type type;
265             short flags;
266         } notifiers[] = {
267             { QSocketNotifier::Read,      POLLIN  | POLLHUP | POLLERR },
268             { QSocketNotifier::Write,     POLLOUT | POLLHUP | POLLERR },
269             { QSocketNotifier::Exception, POLLPRI | POLLHUP | POLLERR }
270         };
271 
272         for (const auto &n : notifiers) {
273             QSocketNotifier *notifier = sn_set.notifiers[n.type];
274 
275             if (!notifier)
276                 continue;
277 
278             if (pfd.revents & POLLNVAL) {
279                 qWarning("QSocketNotifier: Invalid socket %d with type %s, disabling...",
280                          it.key(), socketType(n.type));
281                 notifier->setEnabled(false);
282             }
283 
284             if (pfd.revents & n.flags)
285                 setSocketNotifierPending(notifier);
286         }
287     }
288 
289     pollfds.clear();
290 }
291 
activateSocketNotifiers()292 int QEventDispatcherUNIXPrivate::activateSocketNotifiers()
293 {
294     markPendingSocketNotifiers();
295 
296     if (pendingNotifiers.isEmpty())
297         return 0;
298 
299     int n_activated = 0;
300     QEvent event(QEvent::SockAct);
301 
302     while (!pendingNotifiers.isEmpty()) {
303         QSocketNotifier *notifier = pendingNotifiers.takeFirst();
304         QCoreApplication::sendEvent(notifier, &event);
305         ++n_activated;
306     }
307 
308     return n_activated;
309 }
310 
QEventDispatcherUNIX(QObject * parent)311 QEventDispatcherUNIX::QEventDispatcherUNIX(QObject *parent)
312     : QAbstractEventDispatcher(*new QEventDispatcherUNIXPrivate, parent)
313 { }
314 
QEventDispatcherUNIX(QEventDispatcherUNIXPrivate & dd,QObject * parent)315 QEventDispatcherUNIX::QEventDispatcherUNIX(QEventDispatcherUNIXPrivate &dd, QObject *parent)
316     : QAbstractEventDispatcher(dd, parent)
317 { }
318 
~QEventDispatcherUNIX()319 QEventDispatcherUNIX::~QEventDispatcherUNIX()
320 { }
321 
322 /*!
323     \internal
324 */
registerTimer(int timerId,int interval,Qt::TimerType timerType,QObject * obj)325 void QEventDispatcherUNIX::registerTimer(int timerId, int interval, Qt::TimerType timerType, QObject *obj)
326 {
327 #ifndef QT_NO_DEBUG
328     if (timerId < 1 || interval < 0 || !obj) {
329         qWarning("QEventDispatcherUNIX::registerTimer: invalid arguments");
330         return;
331     } else if (obj->thread() != thread() || thread() != QThread::currentThread()) {
332         qWarning("QEventDispatcherUNIX::registerTimer: timers cannot be started from another thread");
333         return;
334     }
335 #endif
336 
337     Q_D(QEventDispatcherUNIX);
338     d->timerList.registerTimer(timerId, interval, timerType, obj);
339 }
340 
341 /*!
342     \internal
343 */
unregisterTimer(int timerId)344 bool QEventDispatcherUNIX::unregisterTimer(int timerId)
345 {
346 #ifndef QT_NO_DEBUG
347     if (timerId < 1) {
348         qWarning("QEventDispatcherUNIX::unregisterTimer: invalid argument");
349         return false;
350     } else if (thread() != QThread::currentThread()) {
351         qWarning("QEventDispatcherUNIX::unregisterTimer: timers cannot be stopped from another thread");
352         return false;
353     }
354 #endif
355 
356     Q_D(QEventDispatcherUNIX);
357     return d->timerList.unregisterTimer(timerId);
358 }
359 
360 /*!
361     \internal
362 */
unregisterTimers(QObject * object)363 bool QEventDispatcherUNIX::unregisterTimers(QObject *object)
364 {
365 #ifndef QT_NO_DEBUG
366     if (!object) {
367         qWarning("QEventDispatcherUNIX::unregisterTimers: invalid argument");
368         return false;
369     } else if (object->thread() != thread() || thread() != QThread::currentThread()) {
370         qWarning("QEventDispatcherUNIX::unregisterTimers: timers cannot be stopped from another thread");
371         return false;
372     }
373 #endif
374 
375     Q_D(QEventDispatcherUNIX);
376     return d->timerList.unregisterTimers(object);
377 }
378 
379 QList<QEventDispatcherUNIX::TimerInfo>
registeredTimers(QObject * object) const380 QEventDispatcherUNIX::registeredTimers(QObject *object) const
381 {
382     if (!object) {
383         qWarning("QEventDispatcherUNIX:registeredTimers: invalid argument");
384         return QList<TimerInfo>();
385     }
386 
387     Q_D(const QEventDispatcherUNIX);
388     return d->timerList.registeredTimers(object);
389 }
390 
391 /*****************************************************************************
392  QEventDispatcher implementations for UNIX
393  *****************************************************************************/
394 
registerSocketNotifier(QSocketNotifier * notifier)395 void QEventDispatcherUNIX::registerSocketNotifier(QSocketNotifier *notifier)
396 {
397     Q_ASSERT(notifier);
398     int sockfd = notifier->socket();
399     QSocketNotifier::Type type = notifier->type();
400 #ifndef QT_NO_DEBUG
401     if (notifier->thread() != thread() || thread() != QThread::currentThread()) {
402         qWarning("QSocketNotifier: socket notifiers cannot be enabled from another thread");
403         return;
404     }
405 #endif
406 
407     Q_D(QEventDispatcherUNIX);
408     QSocketNotifierSetUNIX &sn_set = d->socketNotifiers[sockfd];
409 
410     if (sn_set.notifiers[type] && sn_set.notifiers[type] != notifier)
411         qWarning("%s: Multiple socket notifiers for same socket %d and type %s",
412                  Q_FUNC_INFO, sockfd, socketType(type));
413 
414     sn_set.notifiers[type] = notifier;
415 }
416 
unregisterSocketNotifier(QSocketNotifier * notifier)417 void QEventDispatcherUNIX::unregisterSocketNotifier(QSocketNotifier *notifier)
418 {
419     Q_ASSERT(notifier);
420     int sockfd = notifier->socket();
421     QSocketNotifier::Type type = notifier->type();
422 #ifndef QT_NO_DEBUG
423     if (notifier->thread() != thread() || thread() != QThread::currentThread()) {
424         qWarning("QSocketNotifier: socket notifier (fd %d) cannot be disabled from another thread.\n"
425                 "(Notifier's thread is %s(%p), event dispatcher's thread is %s(%p), current thread is %s(%p))",
426                 sockfd,
427                 notifier->thread() ? notifier->thread()->metaObject()->className() : "QThread", notifier->thread(),
428                 thread() ? thread()->metaObject()->className() : "QThread", thread(),
429                 QThread::currentThread() ? QThread::currentThread()->metaObject()->className() : "QThread", QThread::currentThread());
430         return;
431     }
432 #endif
433 
434     Q_D(QEventDispatcherUNIX);
435 
436     d->pendingNotifiers.removeOne(notifier);
437 
438     auto i = d->socketNotifiers.find(sockfd);
439     if (i == d->socketNotifiers.end())
440         return;
441 
442     QSocketNotifierSetUNIX &sn_set = i.value();
443 
444     if (sn_set.notifiers[type] == nullptr)
445         return;
446 
447     if (sn_set.notifiers[type] != notifier) {
448         qWarning("%s: Multiple socket notifiers for same socket %d and type %s",
449                  Q_FUNC_INFO, sockfd, socketType(type));
450         return;
451     }
452 
453     sn_set.notifiers[type] = nullptr;
454 
455     if (sn_set.isEmpty())
456         d->socketNotifiers.erase(i);
457 }
458 
processEvents(QEventLoop::ProcessEventsFlags flags)459 bool QEventDispatcherUNIX::processEvents(QEventLoop::ProcessEventsFlags flags)
460 {
461     Q_D(QEventDispatcherUNIX);
462     d->interrupt.storeRelaxed(0);
463 
464     // we are awake, broadcast it
465     emit awake();
466 
467     auto threadData = d->threadData.loadRelaxed();
468     QCoreApplicationPrivate::sendPostedEvents(nullptr, 0, threadData);
469 
470     const bool include_timers = (flags & QEventLoop::X11ExcludeTimers) == 0;
471     const bool include_notifiers = (flags & QEventLoop::ExcludeSocketNotifiers) == 0;
472     const bool wait_for_events = flags & QEventLoop::WaitForMoreEvents;
473 
474     const bool canWait = (threadData->canWaitLocked()
475                           && !d->interrupt.loadRelaxed()
476                           && wait_for_events);
477 
478     if (canWait)
479         emit aboutToBlock();
480 
481     if (d->interrupt.loadRelaxed())
482         return false;
483 
484     timespec *tm = nullptr;
485     timespec wait_tm = { 0, 0 };
486 
487     if (!canWait || (include_timers && d->timerList.timerWait(wait_tm)))
488         tm = &wait_tm;
489 
490     d->pollfds.clear();
491     d->pollfds.reserve(1 + (include_notifiers ? d->socketNotifiers.size() : 0));
492 
493     if (include_notifiers)
494         for (auto it = d->socketNotifiers.cbegin(); it != d->socketNotifiers.cend(); ++it)
495             d->pollfds.append(qt_make_pollfd(it.key(), it.value().events()));
496 
497     // This must be last, as it's popped off the end below
498     d->pollfds.append(d->threadPipe.prepare());
499 
500     int nevents = 0;
501 
502     switch (qt_safe_poll(d->pollfds.data(), d->pollfds.size(), tm)) {
503     case -1:
504         perror("qt_safe_poll");
505         break;
506     case 0:
507         break;
508     default:
509         nevents += d->threadPipe.check(d->pollfds.takeLast());
510         if (include_notifiers)
511             nevents += d->activateSocketNotifiers();
512         break;
513     }
514 
515     if (include_timers)
516         nevents += d->activateTimers();
517 
518     // return true if we handled events, false otherwise
519     return (nevents > 0);
520 }
521 
hasPendingEvents()522 bool QEventDispatcherUNIX::hasPendingEvents()
523 {
524     extern uint qGlobalPostedEventsCount(); // from qapplication.cpp
525     return qGlobalPostedEventsCount();
526 }
527 
remainingTime(int timerId)528 int QEventDispatcherUNIX::remainingTime(int timerId)
529 {
530 #ifndef QT_NO_DEBUG
531     if (timerId < 1) {
532         qWarning("QEventDispatcherUNIX::remainingTime: invalid argument");
533         return -1;
534     }
535 #endif
536 
537     Q_D(QEventDispatcherUNIX);
538     return d->timerList.timerRemainingTime(timerId);
539 }
540 
wakeUp()541 void QEventDispatcherUNIX::wakeUp()
542 {
543     Q_D(QEventDispatcherUNIX);
544     d->threadPipe.wakeUp();
545 }
546 
interrupt()547 void QEventDispatcherUNIX::interrupt()
548 {
549     Q_D(QEventDispatcherUNIX);
550     d->interrupt.storeRelaxed(1);
551     wakeUp();
552 }
553 
flush()554 void QEventDispatcherUNIX::flush()
555 { }
556 
557 QT_END_NAMESPACE
558 
559 #include "moc_qeventdispatcher_unix_p.cpp"
560