From 25ed3acf3daa1141e7ae5ac65f6456b9af9b451a Mon Sep 17 00:00:00 2001 From: Gareth Stockwell Date: Fri, 30 Apr 2010 12:32:38 +0100 Subject: Fixed incorrect runtime platform version check in Phonon MMF backend In S60 3.2, CMdaAudioPlayerUtility::SetVolume(TInt) was changed from having a void return type to returning TInt. The code in the Phonon MMF backend which calls this function uses a runtime platform version check to ensure that only on S60 3.2 and above is the return value from SetVolume treated as valid. This check was previously testing for the wrong platform version (5.0 rather than 3.2). Reviewed-by: Shane Kearns --- src/3rdparty/phonon/mmf/audioplayer.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/3rdparty/phonon/mmf/audioplayer.cpp b/src/3rdparty/phonon/mmf/audioplayer.cpp index 77a0964..f49e898 100644 --- a/src/3rdparty/phonon/mmf/audioplayer.cpp +++ b/src/3rdparty/phonon/mmf/audioplayer.cpp @@ -99,7 +99,7 @@ int MMF::AudioPlayer::setDeviceVolume(int mmfVolume) * stack by doing a runtime check of the SDK version. */ #if !defined(__SERIES60_31__) const int err = m_player->SetVolume(mmfVolume); - if (QSysInfo::s60Version() >= QSysInfo::SV_S60_5_0) + if (QSysInfo::s60Version() >= QSysInfo::SV_S60_3_2) return err; else return KErrNone; -- cgit v0.12 From accde4c624fc0fc7a3942925922fc981888c4ac4 Mon Sep 17 00:00:00 2001 From: mread Date: Fri, 30 Apr 2010 14:27:08 +0100 Subject: Event dispatcher slow down using delays rather than thread priority The Symbian event dispatcher has a mechanism to slow down the Qt app to prevent viewsrv crashes and keep the device responsive. This was implemented using a thread priority drop. But that has some bad side effects, such as app and system performance instability. This new implementation of a slow down mechanism uses a separate low priority thread to test when the system is getting too busy. Adaptive millisecond waits are used to slow the app down just enough to let the low prioirity thread to run. In practice this avoids the performance instability of the previous method, and results in much better system stability where the system stays more responsive with fewer viewsrv panics when heavy Qt apps are running. The slow down code kicks in after 2 seconds of busy time. The delays grow 1ms at a time to a maximum of 1/4 of average event run time. This updated version of the fix used an RSemaphore rather than RFastlock, which should not have been used for cross-thread signalling. Task-number: QTBUG-9489 Reviewed-by: Shane Kearns --- src/corelib/kernel/qeventdispatcher_symbian.cpp | 127 +++++++++++++++++------- src/corelib/kernel/qeventdispatcher_symbian_p.h | 5 +- 2 files changed, 95 insertions(+), 37 deletions(-) diff --git a/src/corelib/kernel/qeventdispatcher_symbian.cpp b/src/corelib/kernel/qeventdispatcher_symbian.cpp index 8c96057..c85d1be 100644 --- a/src/corelib/kernel/qeventdispatcher_symbian.cpp +++ b/src/corelib/kernel/qeventdispatcher_symbian.cpp @@ -43,7 +43,6 @@ #include #include #include -#include #include #include @@ -636,6 +635,74 @@ void QSocketActiveObject::deleteLater() } } +#ifdef QT_SYMBIAN_PRIORITY_DROP +class QIdleDetectorThread +{ +public: + QIdleDetectorThread() + : m_state(STATE_RUN), m_stop(false) + { + qt_symbian_throwIfError(m_lock.CreateLocal(0)); + TInt err = m_idleDetectorThread.Create(KNullDesC(), &idleDetectorThreadFunc, 1024, NULL, this); + if (err != KErrNone) + m_lock.Close(); + qt_symbian_throwIfError(err); + m_idleDetectorThread.SetPriority(EPriorityAbsoluteBackgroundNormal); + m_idleDetectorThread.Resume(); + } + + ~QIdleDetectorThread() + { + // close down the idle thread because if corelib is loaded temporarily, this would leak threads into the host process + m_stop = true; + m_lock.Signal(); + m_idleDetectorThread.SetPriority(EPriorityNormal); + TRequestStatus s; + m_idleDetectorThread.Logon(s); + User::WaitForRequest(s); + m_idleDetectorThread.Close(); + m_lock.Close(); + } + + void kick() + { + m_state = STATE_KICKED; + m_lock.Signal(); + } + + bool hasRun() + { + return m_state == STATE_RUN; + } + +private: + static TInt idleDetectorThreadFunc(TAny* self) + { + static_cast(self)->IdleLoop(); + return KErrNone; + } + + void IdleLoop() + { + while (!m_stop) { + m_lock.Wait(); + m_state = STATE_RUN; + } + } + +private: + enum IdleStates {STATE_KICKED, STATE_RUN} m_state; + bool m_stop; + RThread m_idleDetectorThread; + RSemaphore m_lock; +}; + +Q_GLOBAL_STATIC(QIdleDetectorThread, idleDetectorThread); + +const int maxBusyTime = 2000; // maximum time we allow idle detector to be blocked before worrying, in milliseconds +const int baseDelay = 1000; // minimum delay time used when backing off to allow idling, in microseconds +#endif + QEventDispatcherSymbian::QEventDispatcherSymbian(QObject *parent) : QAbstractEventDispatcher(parent), m_activeScheduler(0), @@ -646,11 +713,15 @@ QEventDispatcherSymbian::QEventDispatcherSymbian(QObject *parent) m_iterationCount(0), m_noSocketEvents(false) { +#ifdef QT_SYMBIAN_PRIORITY_DROP + m_delay = baseDelay; + m_avgEventTime = 0; + idleDetectorThread(); +#endif } QEventDispatcherSymbian::~QEventDispatcherSymbian() { - m_processHandle.Close(); } void QEventDispatcherSymbian::startingUp() @@ -711,23 +782,7 @@ bool QEventDispatcherSymbian::processEvents ( QEventLoop::ProcessEventsFlags fla m_interrupt = false; #ifdef QT_SYMBIAN_PRIORITY_DROP - /* - * This QTime variable is used to measure the time it takes to finish - * the event loop. If we take too long in the loop, other processes - * may be starved and killed. After the first event has completed, we - * take the current time, and if the remaining events take longer than - * a preset time, we temporarily lower the priority to force a context - * switch. For applications that do not take unecessarily long in the - * event loop, the priority will not be altered. - */ - QTime time; - enum { - FirstRun, - SubsequentRun, - TimeStarted - } timeState = FirstRun; - - TProcessPriority priority; + QTime eventTimer; #endif while (1) { @@ -743,10 +798,18 @@ bool QEventDispatcherSymbian::processEvents ( QEventLoop::ProcessEventsFlags fla } #ifdef QT_SYMBIAN_PRIORITY_DROP - if (timeState == SubsequentRun) { - time.start(); - timeState = TimeStarted; + if (idleDetectorThread()->hasRun()) { + if (m_delay > baseDelay) + m_delay -= baseDelay; + m_lastIdleRequestTimer.start(); + idleDetectorThread()->kick(); + } else if (m_lastIdleRequestTimer.elapsed() > maxBusyTime) { + User::AfterHighRes(m_delay); + // allow delay to be up to 1/4 of execution time + if (!idleDetectorThread()->hasRun() && m_delay*3 < m_avgEventTime) + m_delay += baseDelay; } + eventTimer.start(); #endif TInt error; @@ -756,6 +819,12 @@ bool QEventDispatcherSymbian::processEvents ( QEventLoop::ProcessEventsFlags fla CActiveScheduler::Current()->Error(error); } +#ifdef QT_SYMBIAN_PRIORITY_DROP + int eventDur = eventTimer.elapsed()*1000; + // average is calcualted as a 5% decaying exponential average + m_avgEventTime = (m_avgEventTime * 95 + eventDur * 5) / 100; +#endif + if (!handledSymbianEvent) { qFatal("QEventDispatcherSymbian::processEvents(): Caught Symbian stray signal"); } @@ -764,20 +833,6 @@ bool QEventDispatcherSymbian::processEvents ( QEventLoop::ProcessEventsFlags fla break; } block = false; -#ifdef QT_SYMBIAN_PRIORITY_DROP - if (timeState == TimeStarted && time.elapsed() > 100) { - priority = m_processHandle.Priority(); - m_processHandle.SetPriority(EPriorityBackground); - time.start(); - // Slight chance of race condition in the next lines, but nothing fatal - // will happen, just wrong priority. - if (m_processHandle.Priority() == EPriorityBackground) { - m_processHandle.SetPriority(priority); - } - } - if (timeState == FirstRun) - timeState = SubsequentRun; -#endif }; emit awake(); diff --git a/src/corelib/kernel/qeventdispatcher_symbian_p.h b/src/corelib/kernel/qeventdispatcher_symbian_p.h index 1ab31cc..8a9c9a0 100644 --- a/src/corelib/kernel/qeventdispatcher_symbian_p.h +++ b/src/corelib/kernel/qeventdispatcher_symbian_p.h @@ -62,6 +62,7 @@ #include #include #include +#include #include @@ -279,7 +280,9 @@ private: QList m_deferredActiveObjects; - RProcess m_processHandle; + int m_delay; + int m_avgEventTime; + QTime m_lastIdleRequestTimer; }; #ifdef QT_DEBUG -- cgit v0.12