src/corelib/kernel/qeventdispatcher_symbian.cpp
branchRCL_3
changeset 15 b25b6dc3ff8b
parent 8 740e5562c97f
equal deleted inserted replaced
14:8c4229025c0b 15:b25b6dc3ff8b
    41 
    41 
    42 #include "qeventdispatcher_symbian_p.h"
    42 #include "qeventdispatcher_symbian_p.h"
    43 #include <private/qthread_p.h>
    43 #include <private/qthread_p.h>
    44 #include <qcoreapplication.h>
    44 #include <qcoreapplication.h>
    45 #include <private/qcoreapplication_p.h>
    45 #include <private/qcoreapplication_p.h>
    46 #include <qdatetime.h>
       
    47 
    46 
    48 #include <unistd.h>
    47 #include <unistd.h>
    49 #include <errno.h>
    48 #include <errno.h>
    50 
    49 
    51 QT_BEGIN_NAMESPACE
    50 QT_BEGIN_NAMESPACE
   634     } else {
   633     } else {
   635         delete this;
   634         delete this;
   636     }
   635     }
   637 }
   636 }
   638 
   637 
       
   638 #ifdef QT_SYMBIAN_PRIORITY_DROP
       
   639 class QIdleDetectorThread
       
   640 {
       
   641 public:
       
   642     QIdleDetectorThread()
       
   643     : m_state(STATE_RUN), m_stop(false)
       
   644     {
       
   645         qt_symbian_throwIfError(m_lock.CreateLocal());
       
   646         TInt err = m_idleDetectorThread.Create(KNullDesC(), &idleDetectorThreadFunc, 1024, &User::Allocator(), this);
       
   647         if (err != KErrNone)
       
   648             m_lock.Close();
       
   649         qt_symbian_throwIfError(err);
       
   650         m_idleDetectorThread.SetPriority(EPriorityAbsoluteBackgroundNormal);
       
   651         m_idleDetectorThread.Resume();
       
   652     }
       
   653 
       
   654     ~QIdleDetectorThread()
       
   655     {
       
   656         // close down the idle thread because if corelib is loaded temporarily, this would leak threads into the host process
       
   657         m_stop = true;
       
   658         m_lock.Signal();
       
   659         m_idleDetectorThread.SetPriority(EPriorityNormal);
       
   660         TRequestStatus s;
       
   661         m_idleDetectorThread.Logon(s);
       
   662         User::WaitForRequest(s);
       
   663         m_idleDetectorThread.Close();
       
   664         m_lock.Close();
       
   665     }
       
   666 
       
   667     void kick()
       
   668     {
       
   669         m_state = STATE_KICKED;
       
   670         m_lock.Signal();
       
   671     }
       
   672 
       
   673     bool hasRun()
       
   674     {
       
   675         return m_state == STATE_RUN;
       
   676     }
       
   677 
       
   678 private:
       
   679     static TInt idleDetectorThreadFunc(TAny* self)
       
   680     {
       
   681         static_cast<QIdleDetectorThread*>(self)->IdleLoop();
       
   682         return KErrNone;
       
   683     }
       
   684 
       
   685     void IdleLoop()
       
   686     {
       
   687         while (!m_stop) {
       
   688             m_lock.Wait();
       
   689             m_state = STATE_RUN;
       
   690         }
       
   691     }
       
   692 
       
   693 private:
       
   694     enum IdleStates {STATE_KICKED, STATE_RUN} m_state;
       
   695     bool m_stop;
       
   696     RThread m_idleDetectorThread;
       
   697     RFastLock m_lock;
       
   698 };
       
   699 
       
   700 Q_GLOBAL_STATIC(QIdleDetectorThread, idleDetectorThread);
       
   701 
       
   702 const int maxBusyTime = 2000; // maximum time we allow idle detector to be blocked before worrying, in milliseconds
       
   703 const int baseDelay = 1000; // minimum delay time used when backing off to allow idling, in microseconds
       
   704 #endif
       
   705 
   639 QEventDispatcherSymbian::QEventDispatcherSymbian(QObject *parent)
   706 QEventDispatcherSymbian::QEventDispatcherSymbian(QObject *parent)
   640     : QAbstractEventDispatcher(parent),
   707     : QAbstractEventDispatcher(parent),
   641       m_activeScheduler(0),
   708       m_activeScheduler(0),
   642       m_wakeUpAO(0),
   709       m_wakeUpAO(0),
   643       m_completeDeferredAOs(0),
   710       m_completeDeferredAOs(0),
   644       m_interrupt(false),
   711       m_interrupt(false),
   645       m_wakeUpDone(0),
   712       m_wakeUpDone(0),
   646       m_iterationCount(0),
   713       m_iterationCount(0),
   647       m_noSocketEvents(false)
   714       m_noSocketEvents(false)
   648 {
   715 {
       
   716 #ifdef QT_SYMBIAN_PRIORITY_DROP
       
   717     m_delay = baseDelay;
       
   718     m_avgEventTime = 0;
       
   719     idleDetectorThread();
       
   720 #endif
   649 }
   721 }
   650 
   722 
   651 QEventDispatcherSymbian::~QEventDispatcherSymbian()
   723 QEventDispatcherSymbian::~QEventDispatcherSymbian()
   652 {
   724 {
   653     m_processHandle.Close();
       
   654 }
   725 }
   655 
   726 
   656 void QEventDispatcherSymbian::startingUp()
   727 void QEventDispatcherSymbian::startingUp()
   657 {
   728 {
   658     if( !CActiveScheduler::Current() ) {
   729     if( !CActiveScheduler::Current() ) {
   709 
   780 
   710         bool handledSymbianEvent = false;
   781         bool handledSymbianEvent = false;
   711         m_interrupt = false;
   782         m_interrupt = false;
   712 
   783 
   713 #ifdef QT_SYMBIAN_PRIORITY_DROP
   784 #ifdef QT_SYMBIAN_PRIORITY_DROP
   714         /*
   785         QTime eventTimer;
   715          * This QTime variable is used to measure the time it takes to finish
       
   716          * the event loop. If we take too long in the loop, other processes
       
   717          * may be starved and killed. After the first event has completed, we
       
   718          * take the current time, and if the remaining events take longer than
       
   719          * a preset time, we temporarily lower the priority to force a context
       
   720          * switch. For applications that do not take unecessarily long in the
       
   721          * event loop, the priority will not be altered.
       
   722          */
       
   723         QTime time;
       
   724         enum {
       
   725             FirstRun,
       
   726             SubsequentRun,
       
   727             TimeStarted
       
   728         } timeState = FirstRun;
       
   729 
       
   730         TProcessPriority priority;
       
   731 #endif
   786 #endif
   732 
   787 
   733         while (1) {
   788         while (1) {
   734             if (block) {
   789             if (block) {
   735                 // This is where Qt will spend most of its time.
   790                 // This is where Qt will spend most of its time.
   741                 // This one should return without delay.
   796                 // This one should return without delay.
   742                 CActiveScheduler::Current()->WaitForAnyRequest();
   797                 CActiveScheduler::Current()->WaitForAnyRequest();
   743             }
   798             }
   744 
   799 
   745 #ifdef QT_SYMBIAN_PRIORITY_DROP
   800 #ifdef QT_SYMBIAN_PRIORITY_DROP
   746             if (timeState == SubsequentRun) {
   801             if (idleDetectorThread()->hasRun()) {
   747                 time.start();
   802                 if (m_delay > baseDelay)
   748                 timeState = TimeStarted;
   803                     m_delay -= baseDelay;
       
   804                 m_lastIdleRequestTimer.start();
       
   805                 idleDetectorThread()->kick();
       
   806             } else if (m_lastIdleRequestTimer.elapsed() > maxBusyTime) {
       
   807                 User::AfterHighRes(m_delay);
       
   808                 // allow delay to be up to 1/4 of execution time
       
   809                 if (!idleDetectorThread()->hasRun() && m_delay*3 < m_avgEventTime)
       
   810                     m_delay += baseDelay;
   749             }
   811             }
       
   812             eventTimer.start();
   750 #endif
   813 #endif
   751 
   814 
   752             TInt error;
   815             TInt error;
   753             handledSymbianEvent = CActiveScheduler::RunIfReady(error, KMinTInt);
   816             handledSymbianEvent = CActiveScheduler::RunIfReady(error, KMinTInt);
   754             if (error) {
   817             if (error) {
   755                 qWarning("CActiveScheduler::RunIfReady() returned error: %i\n", error);
   818                 qWarning("CActiveScheduler::RunIfReady() returned error: %i\n", error);
   756                 CActiveScheduler::Current()->Error(error);
   819                 CActiveScheduler::Current()->Error(error);
   757             }
   820             }
       
   821 
       
   822 #ifdef QT_SYMBIAN_PRIORITY_DROP
       
   823             int eventDur = eventTimer.elapsed()*1000;
       
   824             // average is calcualted as a 5% decaying exponential average
       
   825             m_avgEventTime = (m_avgEventTime * 95 + eventDur * 5) / 100;
       
   826 #endif
   758 
   827 
   759             if (!handledSymbianEvent) {
   828             if (!handledSymbianEvent) {
   760                 qFatal("QEventDispatcherSymbian::processEvents(): Caught Symbian stray signal");
   829                 qFatal("QEventDispatcherSymbian::processEvents(): Caught Symbian stray signal");
   761             }
   830             }
   762             handledAnyEvent = true;
   831             handledAnyEvent = true;
   763             if (m_interrupt) {
   832             if (m_interrupt) {
   764                 break;
   833                 break;
   765             }
   834             }
   766             block = false;
   835             block = false;
   767 #ifdef QT_SYMBIAN_PRIORITY_DROP
       
   768             if (timeState == TimeStarted && time.elapsed() > 100) {
       
   769                 priority = m_processHandle.Priority();
       
   770                 m_processHandle.SetPriority(EPriorityBackground);
       
   771                 time.start();
       
   772                 // Slight chance of race condition in the next lines, but nothing fatal
       
   773                 // will happen, just wrong priority.
       
   774                 if (m_processHandle.Priority() == EPriorityBackground) {
       
   775                     m_processHandle.SetPriority(priority);
       
   776                 }
       
   777             }
       
   778             if (timeState == FirstRun)
       
   779                 timeState = SubsequentRun;
       
   780 #endif
       
   781         };
   836         };
   782 
   837 
   783         emit awake();
   838         emit awake();
   784     } QT_CATCH (const std::exception& ex) {
   839     } QT_CATCH (const std::exception& ex) {
   785 #ifndef QT_NO_EXCEPTIONS
   840 #ifndef QT_NO_EXCEPTIONS