diff options
Diffstat (limited to 'src/corelib/kernel/qeventdispatcher_unix.cpp')
-rw-r--r-- | src/corelib/kernel/qeventdispatcher_unix.cpp | 629 |
1 files changed, 257 insertions, 372 deletions
diff --git a/src/corelib/kernel/qeventdispatcher_unix.cpp b/src/corelib/kernel/qeventdispatcher_unix.cpp index 155f7b7aa2..9afbb84abf 100644 --- a/src/corelib/kernel/qeventdispatcher_unix.cpp +++ b/src/corelib/kernel/qeventdispatcher_unix.cpp @@ -1,31 +1,38 @@ /**************************************************************************** ** -** Copyright (C) 2015 The Qt Company Ltd. -** Contact: http://www.qt.io/licensing/ +** Copyright (C) 2016 The Qt Company Ltd. +** Copyright (C) 2016 Intel Corporation. +** Contact: https://www.qt.io/licensing/ ** ** This file is part of the QtCore module of the Qt Toolkit. ** -** $QT_BEGIN_LICENSE:LGPL21$ +** $QT_BEGIN_LICENSE:LGPL$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms -** and conditions see http://www.qt.io/terms-conditions. For further -** information use the contact form at http://www.qt.io/contact-us. +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 2.1 or version 3 as published by the Free -** Software Foundation and appearing in the file LICENSE.LGPLv21 and -** LICENSE.LGPLv3 included in the packaging of this file. Please review the -** following information to ensure the GNU Lesser General Public License -** requirements will be met: https://www.gnu.org/licenses/lgpl.html and -** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** -** As a special exception, The Qt Company gives you certain additional -** rights. These rights are described in The Qt Company LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** @@ -59,7 +66,7 @@ # define _POSIX_MONOTONIC_CLOCK 1 # endif # include <pipeDrv.h> -# include <selectLib.h> +# include <sys/time.h> #endif #if (_POSIX_MONOTONIC_CLOCK-0 <= 0) || defined(QT_BOOTSTRAPPED) @@ -68,7 +75,43 @@ QT_BEGIN_NAMESPACE -#if defined(Q_OS_INTEGRITY) || defined(Q_OS_VXWORKS) +static const char *socketType(QSocketNotifier::Type type) +{ + switch (type) { + case QSocketNotifier::Read: + return "Read"; + case QSocketNotifier::Write: + return "Write"; + case QSocketNotifier::Exception: + return "Exception"; + } + + Q_UNREACHABLE(); +} + +QThreadPipe::QThreadPipe() +{ + fds[0] = -1; + fds[1] = -1; +#if defined(Q_OS_VXWORKS) + name[0] = '\0'; +#endif +} + +QThreadPipe::~QThreadPipe() +{ + if (fds[0] >= 0) + close(fds[0]); + + if (fds[1] >= 0) + close(fds[1]); + +#if defined(Q_OS_VXWORKS) + pipeDevDelete(name, true); +#endif +} + +#if defined(Q_OS_VXWORKS) static void initThreadPipeFD(int fd) { int ret = fcntl(fd, F_SETFD, FD_CLOEXEC); @@ -85,221 +128,184 @@ static void initThreadPipeFD(int fd) } #endif -QEventDispatcherUNIXPrivate::QEventDispatcherUNIXPrivate() +bool QThreadPipe::init() { - extern Qt::HANDLE qt_application_thread_id; - mainThread = (QThread::currentThreadId() == qt_application_thread_id); - bool pipefail = false; - - // initialize the common parts of the event loop -#if defined(Q_OS_NACL) || defined (Q_OS_BLACKBERRY) +#if defined(Q_OS_NACL) // do nothing. -#elif defined(Q_OS_INTEGRITY) - // INTEGRITY doesn't like a "select" on pipes, so use socketpair instead - if (socketpair(AF_INET, SOCK_STREAM, 0, thread_pipe) == -1) { - perror("QEventDispatcherUNIXPrivate(): Unable to create socket pair"); - pipefail = true; - } else { - initThreadPipeFD(thread_pipe[0]); - initThreadPipeFD(thread_pipe[1]); - } #elif defined(Q_OS_VXWORKS) - char name[20]; qsnprintf(name, sizeof(name), "/pipe/qt_%08x", int(taskIdSelf())); // make sure there is no pipe with this name pipeDevDelete(name, true); + // create the pipe if (pipeDevCreate(name, 128 /*maxMsg*/, 1 /*maxLength*/) != OK) { - perror("QEventDispatcherUNIXPrivate(): Unable to create thread pipe device"); - pipefail = true; - } else { - if ((thread_pipe[0] = open(name, O_RDWR, 0)) < 0) { - perror("QEventDispatcherUNIXPrivate(): Unable to create thread pipe"); - pipefail = true; - } else { - initThreadPipeFD(thread_pipe[0]); - thread_pipe[1] = thread_pipe[0]; - } + perror("QThreadPipe: Unable to create thread pipe device %s", name); + return false; + } + + if ((fds[0] = open(name, O_RDWR, 0)) < 0) { + perror("QThreadPipe: Unable to open pipe device %s", name); + return false; } + + initThreadPipeFD(fds[0]); + fds[1] = fds[0]; #else # ifndef QT_NO_EVENTFD - thread_pipe[0] = eventfd(0, EFD_NONBLOCK | EFD_CLOEXEC); - if (thread_pipe[0] != -1) - thread_pipe[1] = -1; - else // fall through the next "if" + if ((fds[0] = eventfd(0, EFD_NONBLOCK | EFD_CLOEXEC)) >= 0) + return true; # endif - if (qt_safe_pipe(thread_pipe, O_NONBLOCK) == -1) { - perror("QEventDispatcherUNIXPrivate(): Unable to create thread pipe"); - pipefail = true; + if (qt_safe_pipe(fds, O_NONBLOCK) == -1) { + perror("QThreadPipe: Unable to create pipe"); + return false; } #endif - if (pipefail) - qFatal("QEventDispatcherUNIXPrivate(): Can not continue without a thread pipe"); - - sn_highest = -1; + return true; } -QEventDispatcherUNIXPrivate::~QEventDispatcherUNIXPrivate() +pollfd QThreadPipe::prepare() const { -#if defined(Q_OS_NACL) || defined (Q_OS_BLACKBERRY) - // do nothing. -#elif defined(Q_OS_VXWORKS) - close(thread_pipe[0]); - - char name[20]; - qsnprintf(name, sizeof(name), "/pipe/qt_%08x", int(taskIdSelf())); - - pipeDevDelete(name, true); -#else - // cleanup the common parts of the event loop - close(thread_pipe[0]); - if (thread_pipe[1] != -1) - close(thread_pipe[1]); -#endif - - // cleanup timers - qDeleteAll(timerList); + return qt_make_pollfd(fds[0], POLLIN); } -int QEventDispatcherUNIXPrivate::doSelect(QEventLoop::ProcessEventsFlags flags, timespec *timeout) +void QThreadPipe::wakeUp() { - Q_Q(QEventDispatcherUNIX); - - // needed in QEventDispatcherUNIX::select() - timerList.updateCurrentTime(); - - int nsel; - do { - // Process timers and socket notifiers - the common UNIX stuff - int highest = 0; - if (! (flags & QEventLoop::ExcludeSocketNotifiers) && (sn_highest >= 0)) { - // return the highest fd we can wait for input on - sn_vec[0].select_fds = sn_vec[0].enabled_fds; - sn_vec[1].select_fds = sn_vec[1].enabled_fds; - sn_vec[2].select_fds = sn_vec[2].enabled_fds; - highest = sn_highest; - } else { - FD_ZERO(&sn_vec[0].select_fds); - FD_ZERO(&sn_vec[1].select_fds); - FD_ZERO(&sn_vec[2].select_fds); - } - - int wakeUpFd = initThreadWakeUp(); - highest = qMax(highest, wakeUpFd); - - nsel = q->select(highest + 1, - &sn_vec[0].select_fds, - &sn_vec[1].select_fds, - &sn_vec[2].select_fds, - timeout); - } while (nsel == -1 && (errno == EINTR || errno == EAGAIN)); - - if (nsel == -1) { - if (errno == EBADF) { - // it seems a socket notifier has a bad fd... find out - // which one it is and disable it - fd_set fdset; - timeval tm; - tm.tv_sec = tm.tv_usec = 0l; - - for (int type = 0; type < 3; ++type) { - QSockNotType::List &list = sn_vec[type].list; - if (list.size() == 0) - continue; - - for (int i = 0; i < list.size(); ++i) { - QSockNot *sn = list[i]; - - FD_ZERO(&fdset); - FD_SET(sn->fd, &fdset); - - int ret = -1; - do { - switch (type) { - case 0: // read - ret = select(sn->fd + 1, &fdset, 0, 0, &tm); - break; - case 1: // write - ret = select(sn->fd + 1, 0, &fdset, 0, &tm); - break; - case 2: // except - ret = select(sn->fd + 1, 0, 0, &fdset, &tm); - break; - } - } while (ret == -1 && (errno == EINTR || errno == EAGAIN)); - - if (ret == -1 && errno == EBADF) { - // disable the invalid socket notifier - static const char *t[] = { "Read", "Write", "Exception" }; - qWarning("QSocketNotifier: Invalid socket %d and type '%s', disabling...", - sn->fd, t[type]); - sn->obj->setEnabled(false); - } - } - } - } else { - // EINVAL... shouldn't happen, so let's complain to stderr - // and hope someone sends us a bug report - perror("select"); - } - } - - int nevents = processThreadWakeUp(nsel); - - // activate socket notifiers - if (! (flags & QEventLoop::ExcludeSocketNotifiers) && nsel > 0 && sn_highest >= 0) { - // if select says data is ready on any socket, then set the socket notifier - // to pending - for (int i=0; i<3; i++) { - QSockNotType::List &list = sn_vec[i].list; - for (int j = 0; j < list.size(); ++j) { - QSockNot *sn = list[j]; - if (FD_ISSET(sn->fd, &sn_vec[i].select_fds)) - q->setSocketNotifierPending(sn->obj); - } + if (wakeUps.testAndSetAcquire(0, 1)) { +#ifndef QT_NO_EVENTFD + if (fds[1] == -1) { + // eventfd + eventfd_t value = 1; + int ret; + EINTR_LOOP(ret, eventfd_write(fds[0], value)); + return; } +#endif + char c = 0; + qt_safe_write(fds[1], &c, 1); } - return (nevents + q->activateSocketNotifiers()); } -int QEventDispatcherUNIXPrivate::initThreadWakeUp() +int QThreadPipe::check(const pollfd &pfd) { - FD_SET(thread_pipe[0], &sn_vec[0].select_fds); - return thread_pipe[0]; -} + Q_ASSERT(pfd.fd == fds[0]); -int QEventDispatcherUNIXPrivate::processThreadWakeUp(int nsel) -{ - if (nsel > 0 && FD_ISSET(thread_pipe[0], &sn_vec[0].select_fds)) { - // some other thread woke us up... consume the data on the thread pipe so that - // select doesn't immediately return next time + char c[16]; + const int readyread = pfd.revents & POLLIN; + + if (readyread) { + // consume the data on the thread pipe so that + // poll doesn't immediately return next time #if defined(Q_OS_VXWORKS) - char c[16]; - ::read(thread_pipe[0], c, sizeof(c)); - ::ioctl(thread_pipe[0], FIOFLUSH, 0); + ::read(fds[0], c, sizeof(c)); + ::ioctl(fds[0], FIOFLUSH, 0); #else # ifndef QT_NO_EVENTFD - if (thread_pipe[1] == -1) { + if (fds[1] == -1) { // eventfd eventfd_t value; - eventfd_read(thread_pipe[0], &value); + eventfd_read(fds[0], &value); } else # endif { - char c[16]; - while (::read(thread_pipe[0], c, sizeof(c)) > 0) { - } + while (::read(fds[0], c, sizeof(c)) > 0) {} } #endif + if (!wakeUps.testAndSetRelease(1, 0)) { // hopefully, this is dead code - qWarning("QEventDispatcherUNIX: internal error, wakeUps.testAndSetRelease(1, 0) failed!"); + qWarning("QThreadPipe: internal error, wakeUps.testAndSetRelease(1, 0) failed!"); + } + } + + return readyread; +} + +QEventDispatcherUNIXPrivate::QEventDispatcherUNIXPrivate() +{ + if (Q_UNLIKELY(threadPipe.init() == false)) + qFatal("QEventDispatcherUNIXPrivate(): Can not continue without a thread pipe"); +} + +QEventDispatcherUNIXPrivate::~QEventDispatcherUNIXPrivate() +{ + // cleanup timers + qDeleteAll(timerList); +} + +void QEventDispatcherUNIXPrivate::setSocketNotifierPending(QSocketNotifier *notifier) +{ + Q_ASSERT(notifier); + + if (pendingNotifiers.contains(notifier)) + return; + + pendingNotifiers << notifier; +} + +int QEventDispatcherUNIXPrivate::activateTimers() +{ + return timerList.activateTimers(); +} + +void QEventDispatcherUNIXPrivate::markPendingSocketNotifiers() +{ + for (const pollfd &pfd : qAsConst(pollfds)) { + if (pfd.fd < 0 || pfd.revents == 0) + continue; + + auto it = socketNotifiers.find(pfd.fd); + Q_ASSERT(it != socketNotifiers.end()); + + const QSocketNotifierSetUNIX &sn_set = it.value(); + + static const struct { + QSocketNotifier::Type type; + short flags; + } notifiers[] = { + { QSocketNotifier::Read, POLLIN | POLLHUP | POLLERR }, + { QSocketNotifier::Write, POLLOUT | POLLHUP | POLLERR }, + { QSocketNotifier::Exception, POLLPRI | POLLHUP | POLLERR } + }; + + for (const auto &n : notifiers) { + QSocketNotifier *notifier = sn_set.notifiers[n.type]; + + if (!notifier) + continue; + + if (pfd.revents & POLLNVAL) { + qWarning("QSocketNotifier: Invalid socket %d with type %s, disabling...", + it.key(), socketType(n.type)); + notifier->setEnabled(false); + } + + if (pfd.revents & n.flags) + setSocketNotifierPending(notifier); } - return 1; } - return 0; + + pollfds.clear(); +} + +int QEventDispatcherUNIXPrivate::activateSocketNotifiers() +{ + markPendingSocketNotifiers(); + + if (pendingNotifiers.isEmpty()) + return 0; + + int n_activated = 0; + QEvent event(QEvent::SockAct); + + while (!pendingNotifiers.isEmpty()) { + QSocketNotifier *notifier = pendingNotifiers.takeFirst(); + QCoreApplication::sendEvent(notifier, &event); + ++n_activated; + } + + return n_activated; } QEventDispatcherUNIX::QEventDispatcherUNIX(QObject *parent) @@ -311,14 +317,7 @@ QEventDispatcherUNIX::QEventDispatcherUNIX(QEventDispatcherUNIXPrivate &dd, QObj { } QEventDispatcherUNIX::~QEventDispatcherUNIX() -{ -} - -int QEventDispatcherUNIX::select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, - timespec *timeout) -{ - return qt_safe_select(nfds, readfds, writefds, exceptfds, timeout); -} +{ } /*! \internal @@ -390,22 +389,6 @@ QEventDispatcherUNIX::registeredTimers(QObject *object) const } /***************************************************************************** - Socket notifier type - *****************************************************************************/ -QSockNotType::QSockNotType() -{ - FD_ZERO(&select_fds); - FD_ZERO(&enabled_fds); - FD_ZERO(&pending_fds); -} - -QSockNotType::~QSockNotType() -{ - for (int i = 0; i < list.size(); ++i) - delete list[i]; -} - -/***************************************************************************** QEventDispatcher implementations for UNIX *****************************************************************************/ @@ -413,160 +396,59 @@ void QEventDispatcherUNIX::registerSocketNotifier(QSocketNotifier *notifier) { Q_ASSERT(notifier); int sockfd = notifier->socket(); - int type = notifier->type(); + QSocketNotifier::Type type = notifier->type(); #ifndef QT_NO_DEBUG - if (sockfd < 0 - || unsigned(sockfd) >= FD_SETSIZE) { - qWarning("QSocketNotifier: Internal error"); - return; - } else if (notifier->thread() != thread() - || thread() != QThread::currentThread()) { + if (notifier->thread() != thread() || thread() != QThread::currentThread()) { qWarning("QSocketNotifier: socket notifiers cannot be enabled from another thread"); return; } #endif Q_D(QEventDispatcherUNIX); - QSockNotType::List &list = d->sn_vec[type].list; - fd_set *fds = &d->sn_vec[type].enabled_fds; - QSockNot *sn; - - sn = new QSockNot; - sn->obj = notifier; - sn->fd = sockfd; - sn->queue = &d->sn_vec[type].pending_fds; - - int i; - for (i = 0; i < list.size(); ++i) { - QSockNot *p = list[i]; - if (p->fd < sockfd) - break; - if (p->fd == sockfd) { - static const char *t[] = { "Read", "Write", "Exception" }; - qWarning("QSocketNotifier: Multiple socket notifiers for " - "same socket %d and type %s", sockfd, t[type]); - } - } - list.insert(i, sn); + QSocketNotifierSetUNIX &sn_set = d->socketNotifiers[sockfd]; + + if (sn_set.notifiers[type] && sn_set.notifiers[type] != notifier) + qWarning("%s: Multiple socket notifiers for same socket %d and type %s", + Q_FUNC_INFO, sockfd, socketType(type)); - FD_SET(sockfd, fds); - d->sn_highest = qMax(d->sn_highest, sockfd); + sn_set.notifiers[type] = notifier; } void QEventDispatcherUNIX::unregisterSocketNotifier(QSocketNotifier *notifier) { Q_ASSERT(notifier); int sockfd = notifier->socket(); - int type = notifier->type(); + QSocketNotifier::Type type = notifier->type(); #ifndef QT_NO_DEBUG - if (sockfd < 0 - || unsigned(sockfd) >= FD_SETSIZE) { - qWarning("QSocketNotifier: Internal error"); - return; - } else if (notifier->thread() != thread() - || thread() != QThread::currentThread()) { + if (notifier->thread() != thread() || thread() != QThread::currentThread()) { qWarning("QSocketNotifier: socket notifiers cannot be disabled from another thread"); return; } #endif Q_D(QEventDispatcherUNIX); - QSockNotType::List &list = d->sn_vec[type].list; - fd_set *fds = &d->sn_vec[type].enabled_fds; - QSockNot *sn = 0; - int i; - for (i = 0; i < list.size(); ++i) { - sn = list[i]; - if(sn->obj == notifier && sn->fd == sockfd) - break; - } - if (i == list.size()) // not found - return; - FD_CLR(sockfd, fds); // clear fd bit - FD_CLR(sockfd, sn->queue); - d->sn_pending_list.removeAll(sn); // remove from activation list - list.removeAt(i); // remove notifier found above - delete sn; - - if (d->sn_highest == sockfd) { // find highest fd - d->sn_highest = -1; - for (int i=0; i<3; i++) { - if (!d->sn_vec[i].list.isEmpty()) - d->sn_highest = qMax(d->sn_highest, // list is fd-sorted - d->sn_vec[i].list[0]->fd); - } - } -} + d->pendingNotifiers.removeOne(notifier); -void QEventDispatcherUNIX::setSocketNotifierPending(QSocketNotifier *notifier) -{ - Q_ASSERT(notifier); - int sockfd = notifier->socket(); - int type = notifier->type(); -#ifndef QT_NO_DEBUG - if (sockfd < 0 - || unsigned(sockfd) >= FD_SETSIZE) { - qWarning("QSocketNotifier: Internal error"); + auto i = d->socketNotifiers.find(sockfd); + if (i == d->socketNotifiers.end()) return; - } - Q_ASSERT(notifier->thread() == thread() && thread() == QThread::currentThread()); -#endif - Q_D(QEventDispatcherUNIX); - QSockNotType::List &list = d->sn_vec[type].list; - QSockNot *sn = 0; - int i; - for (i = 0; i < list.size(); ++i) { - sn = list[i]; - if(sn->obj == notifier && sn->fd == sockfd) - break; - } - if (i == list.size()) // not found + QSocketNotifierSetUNIX &sn_set = i.value(); + + if (sn_set.notifiers[type] == nullptr) return; - // We choose a random activation order to be more fair under high load. - // If a constant order is used and a peer early in the list can - // saturate the IO, it might grab our attention completely. - // Also, if we're using a straight list, the callback routines may - // delete other entries from the list before those other entries are - // processed. - if (! FD_ISSET(sn->fd, sn->queue)) { - if (d->sn_pending_list.isEmpty()) { - d->sn_pending_list.append(sn); - } else { - d->sn_pending_list.insert((qrand() & 0xff) % - (d->sn_pending_list.size()+1), sn); - } - FD_SET(sn->fd, sn->queue); + if (sn_set.notifiers[type] != notifier) { + qWarning("%s: Multiple socket notifiers for same socket %d and type %s", + Q_FUNC_INFO, sockfd, socketType(type)); + return; } -} -int QEventDispatcherUNIX::activateTimers() -{ - Q_ASSERT(thread() == QThread::currentThread()); - Q_D(QEventDispatcherUNIX); - return d->timerList.activateTimers(); -} - -int QEventDispatcherUNIX::activateSocketNotifiers() -{ - Q_D(QEventDispatcherUNIX); - if (d->sn_pending_list.isEmpty()) - return 0; + sn_set.notifiers[type] = nullptr; - // activate entries - int n_act = 0; - QEvent event(QEvent::SockAct); - while (!d->sn_pending_list.isEmpty()) { - QSockNot *sn = d->sn_pending_list.takeFirst(); - if (FD_ISSET(sn->fd, sn->queue)) { - FD_CLR(sn->fd, sn->queue); - QCoreApplication::sendEvent(sn->obj, &event); - ++n_act; - } - } - return n_act; + if (sn_set.isEmpty()) + d->socketNotifiers.erase(i); } bool QEventDispatcherUNIX::processEvents(QEventLoop::ProcessEventsFlags flags) @@ -578,39 +460,54 @@ bool QEventDispatcherUNIX::processEvents(QEventLoop::ProcessEventsFlags flags) emit awake(); QCoreApplicationPrivate::sendPostedEvents(0, 0, d->threadData); - int nevents = 0; + const bool include_timers = (flags & QEventLoop::X11ExcludeTimers) == 0; + const bool include_notifiers = (flags & QEventLoop::ExcludeSocketNotifiers) == 0; + const bool wait_for_events = flags & QEventLoop::WaitForMoreEvents; + const bool canWait = (d->threadData->canWaitLocked() && !d->interrupt.load() - && (flags & QEventLoop::WaitForMoreEvents)); + && wait_for_events); if (canWait) emit aboutToBlock(); - if (!d->interrupt.load()) { - // return the maximum time we can wait for an event. - timespec *tm = 0; - timespec wait_tm = { 0l, 0l }; - if (!(flags & QEventLoop::X11ExcludeTimers)) { - if (d->timerList.timerWait(wait_tm)) - tm = &wait_tm; - } + if (d->interrupt.load()) + return false; - if (!canWait) { - if (!tm) - tm = &wait_tm; + timespec *tm = nullptr; + timespec wait_tm = { 0, 0 }; - // no time to wait - tm->tv_sec = 0l; - tm->tv_nsec = 0l; - } + if (!canWait || (include_timers && d->timerList.timerWait(wait_tm))) + tm = &wait_tm; - nevents = d->doSelect(flags, tm); + d->pollfds.clear(); + d->pollfds.reserve(1 + (include_notifiers ? d->socketNotifiers.size() : 0)); - // activate timers - if (! (flags & QEventLoop::X11ExcludeTimers)) { - nevents += activateTimers(); - } + if (include_notifiers) + for (auto it = d->socketNotifiers.cbegin(); it != d->socketNotifiers.cend(); ++it) + d->pollfds.append(qt_make_pollfd(it.key(), it.value().events())); + + // This must be last, as it's popped off the end below + d->pollfds.append(d->threadPipe.prepare()); + + int nevents = 0; + + switch (qt_safe_poll(d->pollfds.data(), d->pollfds.size(), tm)) { + case -1: + perror("qt_safe_poll"); + break; + case 0: + break; + default: + nevents += d->threadPipe.check(d->pollfds.takeLast()); + if (include_notifiers) + nevents += d->activateSocketNotifiers(); + break; } + + if (include_timers) + nevents += d->activateTimers(); + // return true if we handled events, false otherwise return (nevents > 0); } @@ -637,19 +534,7 @@ int QEventDispatcherUNIX::remainingTime(int timerId) void QEventDispatcherUNIX::wakeUp() { Q_D(QEventDispatcherUNIX); - if (d->wakeUps.testAndSetAcquire(0, 1)) { -#ifndef QT_NO_EVENTFD - if (d->thread_pipe[1] == -1) { - // eventfd - eventfd_t value = 1; - int ret; - EINTR_LOOP(ret, eventfd_write(d->thread_pipe[0], value)); - return; - } -#endif - char c = 0; - qt_safe_write( d->thread_pipe[1], &c, 1 ); - } + d->threadPipe.wakeUp(); } void QEventDispatcherUNIX::interrupt() |