diff options
Diffstat (limited to 'src/gui/kernel/qeventdispatcher_qpa.cpp')
-rw-r--r-- | src/gui/kernel/qeventdispatcher_qpa.cpp | 186 |
1 files changed, 171 insertions, 15 deletions
diff --git a/src/gui/kernel/qeventdispatcher_qpa.cpp b/src/gui/kernel/qeventdispatcher_qpa.cpp index 5740548..f7f3db3 100644 --- a/src/gui/kernel/qeventdispatcher_qpa.cpp +++ b/src/gui/kernel/qeventdispatcher_qpa.cpp @@ -44,24 +44,135 @@ #include "qeventdispatcher_qpa_p.h" #include "private/qeventdispatcher_unix_p.h" #include "qapplication_p.h" -#ifndef QT_NO_THREAD -# include "qmutex.h" -#endif +#include "qplatformeventloopintegration_qpa.h" + #include <QWindowSystemInterface> +#include <QtCore/QElapsedTimer> +#include <QtCore/QAtomicInt> +#include <QtCore/QSemaphore> #include <errno.h> + QT_BEGIN_NAMESPACE QT_USE_NAMESPACE +class Rendezvous +{ +public: + void checkpoint() + { + if (state.testAndSetOrdered(0,1)) { + semaphore.acquire(); + } else if (state.testAndSetAcquire(1,0)) { + semaphore.release(); + } else { + qWarning("Barrier internal error"); + } + } +private: + QSemaphore semaphore; + QAtomicInt state; +}; + +class SelectWorker : public QThread +{ +public: + SelectWorker(QEventDispatcherQPAPrivate *eventDispatcherPrivate) + : QThread(), + m_edPrivate(eventDispatcherPrivate), + m_retVal(0) + { + } + + void setSelectValues(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds) + { + m_nfds = nfds; + m_readfds = readfds; + m_writefds = writefds; + m_exceptfds = exceptfds; + + + } + + int retVal() const { + return m_retVal; + } + +protected: + void run(); + +private: + QEventDispatcherQPAPrivate *m_edPrivate; + int m_retVal; + + int m_nfds; + fd_set *m_readfds, *m_writefds, *m_exceptfds; +}; + class QEventDispatcherQPAPrivate : public QEventDispatcherUNIXPrivate { Q_DECLARE_PUBLIC(QEventDispatcherQPA) public: - inline QEventDispatcherQPAPrivate() - { } -}; + QEventDispatcherQPAPrivate() + : eventLoopIntegration(0), + barrierBeforeBlocking(0), + barrierReturnValue(0), + selectReturnMutex(0), + selectWorkerNeedsSync(true), + selectWorkerHasResult(false), + m_integrationInitialised(false), + m_hasIntegration(false) + { + } + + ~QEventDispatcherQPAPrivate() + { + delete selectWorker; + delete eventLoopIntegration; + delete barrierBeforeBlocking; + delete barrierReturnValue; + delete selectReturnMutex; + } + + bool hasIntegration() const + { + if (!m_integrationInitialised) { + QEventDispatcherQPAPrivate *that = const_cast<QEventDispatcherQPAPrivate *>(this); + if (qApp && (qApp->thread() == QThread::currentThread())) { // guiThread + if (QApplicationPrivate::platformIntegration()) { + that->eventLoopIntegration = QApplicationPrivate::platformIntegration()->createEventLoopIntegration(); + if (that->eventLoopIntegration) { + that->selectWorker = new SelectWorker(that); + that->barrierBeforeBlocking = new Rendezvous; + that->barrierReturnValue = new Rendezvous; + that->selectReturnMutex = new QMutex; + that->selectWorker->start(); + that->m_hasIntegration = true; + if (!QElapsedTimer::isMonotonic()) + qWarning("Having eventloop integration without monotonic timers can lead to undefined behaviour"); + } + } + } + that->m_integrationInitialised = true; + } + return m_hasIntegration; + } + + QPlatformEventLoopIntegration *eventLoopIntegration; + Rendezvous *barrierBeforeBlocking; + Rendezvous *barrierReturnValue; + + QMutex *selectReturnMutex; + bool selectWorkerNeedsSync; + bool selectWorkerHasResult; + + SelectWorker *selectWorker; +private: + bool m_integrationInitialised; + bool m_hasIntegration; +}; QEventDispatcherQPA::QEventDispatcherQPA(QObject *parent) : QEventDispatcherUNIX(*new QEventDispatcherQPAPrivate, parent) @@ -70,10 +181,6 @@ QEventDispatcherQPA::QEventDispatcherQPA(QObject *parent) QEventDispatcherQPA::~QEventDispatcherQPA() { } - - -//#define ZERO_FOR_THE_MOMENT - bool QEventDispatcherQPA::processEvents(QEventLoop::ProcessEventsFlags flags) { Q_D(QEventDispatcherQPA); @@ -115,17 +222,24 @@ bool QEventDispatcherQPA::processEvents(QEventLoop::ProcessEventsFlags flags) bool QEventDispatcherQPA::hasPendingEvents() { extern uint qGlobalPostedEventsCount(); // from qapplication.cpp - return qGlobalPostedEventsCount() || QWindowSystemInterfacePrivate::userEventsQueued();; + return qGlobalPostedEventsCount() || QWindowSystemInterfacePrivate::userEventsQueued(); } -void QEventDispatcherQPA::startingUp() +void QEventDispatcherQPA::registerSocketNotifier(QSocketNotifier *notifier) { + Q_D(QEventDispatcherQPA); + QEventDispatcherUNIX::registerSocketNotifier(notifier); + if (d->hasIntegration()) + wakeUp(); } -void QEventDispatcherQPA::closingDown() +void QEventDispatcherQPA::unregisterSocketNotifier(QSocketNotifier *notifier) { - + Q_D(QEventDispatcherQPA); + QEventDispatcherUNIX::unregisterSocketNotifier(notifier); + if (d->hasIntegration()) + wakeUp(); } void QEventDispatcherQPA::flush() @@ -138,7 +252,49 @@ void QEventDispatcherQPA::flush() int QEventDispatcherQPA::select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, timeval *timeout) { - return QEventDispatcherUNIX::select(nfds, readfds, writefds, exceptfds, timeout); + Q_D(QEventDispatcherQPA); + int retVal = 0; + if (d->hasIntegration()) { + qint64 timeoutmsec = timeout->tv_sec * 1000 + (timeout->tv_usec/1000); + d->selectReturnMutex->lock(); + if (d->selectWorkerNeedsSync) { + if (d->selectWorkerHasResult) { + retVal = d->selectWorker->retVal(); + d->selectWorkerHasResult = false; + + d->selectReturnMutex->unlock(); + d->barrierReturnValue->checkpoint(); + return retVal; + } else { + d->selectWorkerNeedsSync = false; + d->selectWorker->setSelectValues(nfds,readfds, writefds, exceptfds); + d->barrierBeforeBlocking->checkpoint(); + } + } + d->selectReturnMutex->unlock(); + d->eventLoopIntegration->processEvents(timeoutmsec); + retVal = 0; //is 0 if select has not returned + } else { + retVal = QEventDispatcherUNIX::select(nfds, readfds, writefds, exceptfds, timeout); + } + return retVal; } +void SelectWorker::run() +{ + while(true) { + m_retVal = 0; + m_edPrivate->barrierBeforeBlocking->checkpoint(); // wait for mainthread + int tmpRet = qt_safe_select(m_nfds,m_readfds,m_writefds,m_exceptfds,0); + m_edPrivate->selectReturnMutex->lock(); + m_edPrivate->eventLoopIntegration->wakeup(); + + m_edPrivate->selectWorkerNeedsSync = true; + m_edPrivate->selectWorkerHasResult = true; + m_retVal = tmpRet; + + m_edPrivate->selectReturnMutex->unlock(); + m_edPrivate->barrierReturnValue->checkpoint(); + } +} QT_END_NAMESPACE |