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 |