From 52eb2f8bdbd7c4170cd8d5047e2c597f31a4015e Mon Sep 17 00:00:00 2001 From: Vladimir Todorov Date: Wed, 20 Feb 2019 11:01:31 +0200 Subject: [PATCH] event dispacher poll optimization --- .../corelib/kernel/qeventdispatcher_unix.cpp | 234 +++++++++++++++++- .../corelib/kernel/qeventdispatcher_unix_p.h | 70 ++++++ 2 files changed, 303 insertions(+), 1 deletion(-) mode change 100644 => 100755 qtbase/src/corelib/kernel/qeventdispatcher_unix.cpp mode change 100644 => 100755 qtbase/src/corelib/kernel/qeventdispatcher_unix_p.h diff --git a/qtbase/src/corelib/kernel/qeventdispatcher_unix.cpp b/qtbase/src/corelib/kernel/qeventdispatcher_unix.cpp old mode 100644 new mode 100755 index 535f86fefe..1abd4e109b --- a/qtbase/src/corelib/kernel/qeventdispatcher_unix.cpp +++ b/qtbase/src/corelib/kernel/qeventdispatcher_unix.cpp @@ -224,8 +224,10 @@ int QThreadPipe::check(const pollfd &pfd) QEventDispatcherUNIXPrivate::QEventDispatcherUNIXPrivate() { +#if !defined(Q_OS_INTEGRITY) if (Q_UNLIKELY(threadPipe.init() == false)) qFatal("QEventDispatcherUNIXPrivate(): Can not continue without a thread pipe"); +#endif } QEventDispatcherUNIXPrivate::~QEventDispatcherUNIXPrivate() @@ -411,6 +413,17 @@ void QEventDispatcherUNIX::registerSocketNotifier(QSocketNotifier *notifier) qWarning("%s: Multiple socket notifiers for same socket %d and type %s", Q_FUNC_INFO, sockfd, socketType(type)); +#if defined(Q_OS_INTEGRITY) + if (sn_set.isEmpty()) + { + sn_set.integrityPollItem = new SocketPollItem(); + sn_set.integrityPollItem->wrapSocket(sockfd); + } + else + { + sn_set.integrityPollItem->cancelPoll(); + } +#endif sn_set.notifiers[type] = notifier; } @@ -452,6 +465,18 @@ void QEventDispatcherUNIX::unregisterSocketNotifier(QSocketNotifier *notifier) sn_set.notifiers[type] = nullptr; +#if defined(Q_OS_INTEGRITY) + if (sn_set.isEmpty()) + { + sn_set.integrityPollItem->destroy(); + delete sn_set.integrityPollItem; + } + else + { + sn_set.integrityPollItem->cancelPoll(); + } +#endif + if (sn_set.isEmpty()) d->socketNotifiers.erase(i); } @@ -461,6 +486,10 @@ bool QEventDispatcherUNIX::processEvents(QEventLoop::ProcessEventsFlags flags) Q_D(QEventDispatcherUNIX); d->interrupt.store(0); +#if defined(Q_OS_INTEGRITY) + d->integrityPoll.init(); +#endif + // we are awake, broadcast it emit awake(); QCoreApplicationPrivate::sendPostedEvents(0, 0, d->threadData); @@ -490,8 +519,19 @@ bool QEventDispatcherUNIX::processEvents(QEventLoop::ProcessEventsFlags flags) 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())); +#if !defined(Q_OS_INTEGRITY) + d->pollfds.append(qt_make_pollfd(it.key(), mask)); +#else + { + short mask = it.value().events(); + if(it.value().integrityPollItem != 0) + { + it.value().integrityPollItem->startPoll(mask); + } + } +#endif +#if !defined(Q_OS_INTEGRITY) // This must be last, as it's popped off the end below d->pollfds.append(d->threadPipe.prepare()); @@ -509,6 +549,39 @@ bool QEventDispatcherUNIX::processEvents(QEventLoop::ProcessEventsFlags flags) nevents += d->activateSocketNotifiers(); break; } +#else + + int nevents = 0; + + if(tm != nullptr) + { + d->integrityPoll.startAlarm(tm); + } + else + { + d->integrityPoll.cancelAlarm(); + } + + int pollFd = d->integrityPoll.poll(); + if(0 == pollFd) // interrupted by wakeup + { + nevents++; + } + else if(1 < pollFd && include_notifiers) // socket + { + if(d->socketNotifiers.contains(pollFd)) + { + short outMask; + if(d->socketNotifiers[pollFd].integrityPollItem != 0) + { + d->socketNotifiers[pollFd].integrityPollItem->finishPoll(outMask); + struct pollfd pfd = { pollFd, 0, outMask}; + d->pollfds.append(pfd); + nevents += d->activateSocketNotifiers(); + } + } + } +#endif if (include_timers) nevents += d->activateTimers(); @@ -539,7 +612,11 @@ int QEventDispatcherUNIX::remainingTime(int timerId) void QEventDispatcherUNIX::wakeUp() { Q_D(QEventDispatcherUNIX); +#if !defined(Q_OS_INTEGRITY) d->threadPipe.wakeUp(); +#else + d->integrityPoll.wakeUp(); +#endif } void QEventDispatcherUNIX::interrupt() @@ -552,6 +629,161 @@ void QEventDispatcherUNIX::interrupt() void QEventDispatcherUNIX::flush() { } +#if defined(Q_OS_INTEGRITY) + +#define CHECK_INTEGRITY_CALL0(F) do { err = F; if(err != Success) { printf("QT Integrity Critical error %d in " #F "\n", err); return; } } while(0) + +void SocketPollItem::wrapSocket(int fd) +{ + socketFd = fd; + isPollingStarted = false; + Error err; + CHECK_INTEGRITY_CALL0(CreatePollItem(CurrentTask(), 1, false, socketFd, &pollItem)); +} + +void SocketPollItem::destroy() +{ + ClosePollItem(pollItem); + isPollingStarted = false; + socketFd = -1; +} + +void SocketPollItem::startPoll(short mask) +{ + if(!isPollingStarted) + { + StartAsyncPoll(pollItem, socketFd, mask, &outMask); + isPollingStarted = true; + } +} + +void SocketPollItem::cancelPoll() +{ + if(isPollingStarted) + { + CancelAsyncPoll(pollItem); + isPollingStarted = false; + } +} + +void SocketPollItem::finishPoll(short& rmask) +{ + if(isPollingStarted) + { + FinishAsyncPoll(pollItem); + rmask = outMask; + isPollingStarted = false; + } + else + { + rmask = 0; + } +} + +bool IntegrityPollPrivate::isIntegrityAsyncInit = false; + +IntegrityPollPrivate::IntegrityPollPrivate() +{ + isInit = false; +} + +IntegrityPollPrivate::~IntegrityPollPrivate() +{ + if(isInit) + { + CloseSemaphore(wakeUpSem); + CloseActivity(wakeupSemActivity); + CloseClock(pollTimeoutAlarm); + CloseActivity(pollTimeoutAlarmActivity); + } +} + +void IntegrityPollPrivate::init() +{ + if(!isInit) + { + Error err; + + // allow the sem (initial = 1) to go through once, just to avoid race conditions with wakeup which is working only since the + // the event thread has been ran + CHECK_INTEGRITY_CALL0(CreateSemaphore(1, &wakeUpSem)); + CHECK_INTEGRITY_CALL0(CreateActivity(CurrentTask(), 1, false, 0, &wakeupSemActivity)); + CHECK_INTEGRITY_CALL0(AsynchronousReceive(wakeupSemActivity, (Object)wakeUpSem, NULL)); + + CHECK_INTEGRITY_CALL0(CreateVirtualClock(HighestResStandardClock, CLOCK_ALARM, &pollTimeoutAlarm)); + CHECK_INTEGRITY_CALL0(CreateActivity(CurrentTask(), 1, false, 1, &pollTimeoutAlarmActivity)); + + isAlarmActive = false; + isInit = true; + + if(IntegrityPollPrivate::isIntegrityAsyncInit == false) + { + IntegrityPollPrivate::isIntegrityAsyncInit = true; + InitAsyncPoll(127); + } + } +} + +void IntegrityPollPrivate::wakeUp() +{ + if(isInit) + { + Error err; + CHECK_INTEGRITY_CALL0(ReleaseSemaphore(wakeUpSem)); + } +} + +void IntegrityPollPrivate::startAlarm(timespec* ts) +{ + if(isInit) + { + Error err; + Value v; + ClearClockAlarmOverruns(pollTimeoutAlarm, &v); + + Time tim; + tim.Seconds = ts->tv_sec / 1000; + tim.Fraction = (0xFFFFFFFFUL / 1000) * (ts->tv_nsec / 1000 / 1000 - ts->tv_sec * 1000); + + ResetActivity(pollTimeoutAlarmActivity); + CHECK_INTEGRITY_CALL0(SetClockAlarm(pollTimeoutAlarm, 0, 0, &tim)); + CHECK_INTEGRITY_CALL0(AsynchronousReceive(pollTimeoutAlarmActivity, (Object)pollTimeoutAlarm, 0)); + isAlarmActive = true; + } +} + +void IntegrityPollPrivate::cancelAlarm() +{ + if(isInit && isAlarmActive) + { + Error err; + ResetActivity(pollTimeoutAlarmActivity); + CHECK_INTEGRITY_CALL0(SetClockAlarm(pollTimeoutAlarm, 0, 0, 0)); + isAlarmActive = false; + } +} + +int IntegrityPollPrivate::poll() +{ + Value Id; + Error Status; + SignedValue sv = 0; + WaitForActivityAndReturnStatus(&Id, &Status); + + if(Id == 0) // wakeup call + { + // Clear the wakeup semaphore (avoid useless wakeups) + TryToClearSemaphore(wakeUpSem, &sv); + AsynchronousReceive(wakeupSemActivity, (Object)wakeUpSem, NULL); + } + + return (int)Id; +} + +#endif + + QT_END_NAMESPACE #include "moc_qeventdispatcher_unix_p.cpp" + diff --git a/qtbase/src/corelib/kernel/qeventdispatcher_unix_p.h b/qtbase/src/corelib/kernel/qeventdispatcher_unix_p.h old mode 100644 new mode 100755 index 0fd068b074..3108bc1a5d --- a/qtbase/src/corelib/kernel/qeventdispatcher_unix_p.h +++ b/qtbase/src/corelib/kernel/qeventdispatcher_unix_p.h @@ -58,10 +58,71 @@ #include "QtCore/qvarlengtharray.h" #include "private/qtimerinfo_unix_p.h" +#if defined(Q_OS_INTEGRITY) +extern "C" +{ +#include +#include +} +#endif + QT_BEGIN_NAMESPACE class QEventDispatcherUNIXPrivate; +#if defined(Q_OS_INTEGRITY) + +// Wraps posix socket, together with some INTEGRITY stuffs used to poll the socket. +class SocketPollItem +{ +public: + void wrapSocket(int fd); + void destroy(); + void startPoll(short mask); + void cancelPoll(); + void finishPoll(short& rmask); + +private: + PollItem pollItem; + bool isPollingStarted; + short outMask; + int socketFd; +}; + +class IntegrityPollPrivate +{ +public: + IntegrityPollPrivate(); + ~IntegrityPollPrivate(); + + // Must be called in the context of event dispatcher thread + // Can be called multiple times, does initialization once + void init(); + + void wakeUp(); + void startAlarm(timespec* ts); + void cancelAlarm(); + + // returns file description, where 0 = wakeup reason, 1 timer reason, > 1 socket reason + int poll(); + +private: + + // Semaphore used to implement "wakeup" for "poll" (instead of fifo) + Semaphore wakeUpSem; + Activity wakeupSemActivity; + + // Alarm used to implement "timeout" for "poll" + Clock pollTimeoutAlarm; + Activity pollTimeoutAlarmActivity; + + bool isAlarmActive; + bool isInit; + + static bool isIntegrityAsyncInit; +}; +#endif + struct Q_CORE_EXPORT QSocketNotifierSetUNIX final { inline QSocketNotifierSetUNIX() Q_DECL_NOTHROW; @@ -70,6 +131,10 @@ struct Q_CORE_EXPORT QSocketNotifierSetUNIX final inline short events() const Q_DECL_NOTHROW; QSocketNotifier *notifiers[3]; + +#if defined(Q_OS_INTEGRITY) + SocketPollItem* integrityPollItem; +#endif }; Q_DECLARE_TYPEINFO(QSocketNotifierSetUNIX, Q_PRIMITIVE_TYPE); @@ -148,6 +213,10 @@ public: QTimerInfoList timerList; QAtomicInt interrupt; // bool + +#if defined(Q_OS_INTEGRITY) + IntegrityPollPrivate integrityPoll; +#endif }; inline QSocketNotifierSetUNIX::QSocketNotifierSetUNIX() Q_DECL_NOTHROW @@ -181,3 +250,4 @@ inline short QSocketNotifierSetUNIX::events() const Q_DECL_NOTHROW QT_END_NAMESPACE #endif // QEVENTDISPATCHER_UNIX_P_H + -- 2.17.1