diff options
author | David Boddie <david.boddie@nokia.com> | 2011-05-03 16:25:39 (GMT) |
---|---|---|
committer | David Boddie <david.boddie@nokia.com> | 2011-05-03 16:25:39 (GMT) |
commit | ac0a7503d58946b38d4d18bb077dd9530ccbb6f9 (patch) | |
tree | 3e16b713e0269147f9d362e7c1384768e98b2c1e /src/corelib/kernel | |
parent | bf0926fff333398660fd51ae6b08699783100057 (diff) | |
parent | 399782c7911c11bba80dd37276f8de0b171c52f8 (diff) | |
download | Qt-ac0a7503d58946b38d4d18bb077dd9530ccbb6f9.zip Qt-ac0a7503d58946b38d4d18bb077dd9530ccbb6f9.tar.gz Qt-ac0a7503d58946b38d4d18bb077dd9530ccbb6f9.tar.bz2 |
Merge branch 'master' of scm.dev.nokia.troll.no:qt/qt
Diffstat (limited to 'src/corelib/kernel')
-rw-r--r-- | src/corelib/kernel/qabstracteventdispatcher.cpp | 67 | ||||
-rw-r--r-- | src/corelib/kernel/qcore_symbian_p.cpp | 104 | ||||
-rw-r--r-- | src/corelib/kernel/qcore_symbian_p.h | 101 | ||||
-rw-r--r-- | src/corelib/kernel/qeventdispatcher_symbian.cpp | 196 | ||||
-rw-r--r-- | src/corelib/kernel/qeventdispatcher_symbian_p.h | 20 | ||||
-rw-r--r-- | src/corelib/kernel/qsystemerror.cpp | 4 |
6 files changed, 440 insertions, 52 deletions
diff --git a/src/corelib/kernel/qabstracteventdispatcher.cpp b/src/corelib/kernel/qabstracteventdispatcher.cpp index e79f87a..2949cd0 100644 --- a/src/corelib/kernel/qabstracteventdispatcher.cpp +++ b/src/corelib/kernel/qabstracteventdispatcher.cpp @@ -49,22 +49,51 @@ QT_BEGIN_NAMESPACE // we allow for 2^24 = 8^8 = 16777216 simultaneously running timers -enum { NumberOfBuckets = 8, FirstBucketSize = 8 }; - -static const int BucketSize[NumberOfBuckets] = - { 8, 64, 512, 4096, 32768, 262144, 2097152, 16777216 - 2396744 }; -static const int BucketOffset[NumberOfBuckets] = - { 0, 8, 72, 584, 4680, 37448, 299592, 2396744 }; - -static int FirstBucket[FirstBucketSize] = { 1, 2, 3, 4, 5, 6, 7, 8 }; -static QBasicAtomicPointer<int> timerIds[NumberOfBuckets] = +static const int TimerIdMask = 0x00ffffff; +static const int TimerSerialMask = ~TimerIdMask & ~0x80000000; +static const int TimerSerialCounter = TimerIdMask + 1; +static const int MaxTimerId = TimerIdMask; + +static int FirstBucket[] = { + 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, + 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32 +}; + +enum { + FirstBucketOffset = 0, + SecondBucketOffset = sizeof(FirstBucket) / sizeof(FirstBucket[0]), + ThirdBucketOffset = 0x100, + FourthBucketOffset = 0x1000, + FifthBucketOffset = 0x10000, + SixthBucketOffset = 0x100000 +}; + +enum { + FirstBucketSize = SecondBucketOffset, + SecondBucketSize = ThirdBucketOffset - SecondBucketOffset, + ThirdBucketSize = FourthBucketOffset - ThirdBucketOffset, + FourthBucketSize = FifthBucketOffset - FourthBucketOffset, + FifthBucketSize = SixthBucketOffset - FifthBucketOffset, + SixthBucketSize = MaxTimerId - SixthBucketOffset +}; + +static const int BucketSize[] = { + FirstBucketSize, SecondBucketSize, ThirdBucketSize, + FourthBucketSize, FifthBucketSize, SixthBucketSize +}; +enum { NumberOfBuckets = sizeof(BucketSize) / sizeof(BucketSize[0]) }; + +static const int BucketOffset[] = { + FirstBucketOffset, SecondBucketOffset, ThirdBucketOffset, + FourthBucketOffset, FifthBucketOffset, SixthBucketOffset +}; + +static QBasicAtomicPointer<int> timerIds[] = { Q_BASIC_ATOMIC_INITIALIZER(FirstBucket), Q_BASIC_ATOMIC_INITIALIZER(0), Q_BASIC_ATOMIC_INITIALIZER(0), Q_BASIC_ATOMIC_INITIALIZER(0), Q_BASIC_ATOMIC_INITIALIZER(0), - Q_BASIC_ATOMIC_INITIALIZER(0), - Q_BASIC_ATOMIC_INITIALIZER(0), Q_BASIC_ATOMIC_INITIALIZER(0) }; static void timerIdsDestructorFunction() @@ -77,18 +106,23 @@ Q_DESTRUCTOR_FUNCTION(timerIdsDestructorFunction) static QBasicAtomicInt nextFreeTimerId = Q_BASIC_ATOMIC_INITIALIZER(1); -static const int TimerIdMask = 0x00ffffff; -static const int TimerSerialMask = ~TimerIdMask & ~0x80000000; -static const int TimerSerialCounter = TimerIdMask + 1; - // avoid the ABA-problem by using 7 of the top 8 bits of the timerId as a serial number static inline int prepareNewValueWithSerialNumber(int oldId, int newId) { return (newId & TimerIdMask) | ((oldId + TimerSerialCounter) & TimerSerialMask); } +namespace { + template<bool> struct QStaticAssertType; + template<> struct QStaticAssertType<true> { enum { Value = 1 }; }; +} +#define q_static_assert(expr) (void)QStaticAssertType<expr>::Value + static inline int bucketOffset(int timerId) { + q_static_assert(sizeof BucketSize == sizeof BucketOffset); + q_static_assert(sizeof(timerIds) / sizeof(timerIds[0]) == NumberOfBuckets); + for (int i = 0; i < NumberOfBuckets; ++i) { if (timerId < BucketSize[i]) return i; @@ -187,7 +221,8 @@ void QAbstractEventDispatcherPrivate::releaseTimerId(int timerId) int at = bucketIndex(bucket, which); int *b = timerIds[bucket]; - Q_ASSERT(b[at] == -timerId); + Q_ASSERT_X(timerId == -b[at], "QAbstractEventDispatcher::releaseTimerId", + "Internal error: timer ID not found"); int freeId, newTimerId; do { diff --git a/src/corelib/kernel/qcore_symbian_p.cpp b/src/corelib/kernel/qcore_symbian_p.cpp index 801d63f..c717cb9 100644 --- a/src/corelib/kernel/qcore_symbian_p.cpp +++ b/src/corelib/kernel/qcore_symbian_p.cpp @@ -44,6 +44,7 @@ #include <e32uid.h> #include "qcore_symbian_p.h" #include <string> +#include <in_sock.h> QT_BEGIN_NAMESPACE @@ -203,6 +204,11 @@ private: RFs iFs; }; +uint qHash(const RSubSessionBase& key) +{ + return qHash(key.SubSessionHandle()); +} + Q_GLOBAL_STATIC(QS60RFsSession, qt_s60_RFsSession); Q_CORE_EXPORT RFs& qt_s60GetRFs() @@ -210,4 +216,102 @@ Q_CORE_EXPORT RFs& qt_s60GetRFs() return qt_s60_RFsSession()->GetRFs(); } +QSymbianSocketManager::QSymbianSocketManager() : + iNextSocket(0), iDefaultConnection(0) +{ + TSessionPref preferences; + // ### In future this could be changed to KAfInet6 when that is more common than IPv4 + preferences.iAddrFamily = KAfInet; + preferences.iProtocol = KProtocolInetIp; + //use global message pool, as we do not know how many sockets app will use + //TODO: is this the right choice? + qt_symbian_throwIfError(iSocketServ.Connect(preferences, -1)); + qt_symbian_throwIfError(iSocketServ.ShareAuto()); +} + +QSymbianSocketManager::~QSymbianSocketManager() +{ + iSocketServ.Close(); + if(!socketMap.isEmpty()) { + qWarning("leaked %d sockets on exit", socketMap.count()); + } +} + +RSocketServ& QSymbianSocketManager::getSocketServer() { + return iSocketServ; +} + +int QSymbianSocketManager::addSocket(const RSocket& socket) { + QHashableSocket sock(static_cast<const QHashableSocket &>(socket)); + QMutexLocker l(&iMutex); + Q_ASSERT(!socketMap.contains(sock)); + if(socketMap.contains(sock)) + return socketMap.value(sock); + // allocate socket number + int guard = 0; + while(reverseSocketMap.contains(iNextSocket)) { + iNextSocket++; + iNextSocket %= max_sockets; + guard++; + if(guard > max_sockets) + return -1; + } + int id = iNextSocket; + + socketMap[sock] = id; + reverseSocketMap[id] = sock; + return id + socket_offset; +} + +bool QSymbianSocketManager::removeSocket(const RSocket &socket) { + QHashableSocket sock(static_cast<const QHashableSocket &>(socket)); + QMutexLocker l(&iMutex); + if(!socketMap.contains(sock)) + return false; + int id = socketMap.value(sock); + socketMap.remove(sock); + reverseSocketMap.remove(id); + return true; +} + +int QSymbianSocketManager::lookupSocket(const RSocket& socket) const { + QHashableSocket sock(static_cast<const QHashableSocket &>(socket)); + QMutexLocker l(&iMutex); + if(!socketMap.contains(sock)) + return -1; + int id = socketMap.value(sock); + return id + socket_offset; +} + +bool QSymbianSocketManager::lookupSocket(int fd, RSocket& socket) const { + QMutexLocker l(&iMutex); + int id = fd - socket_offset; + if(!reverseSocketMap.contains(id)) + return false; + socket = reverseSocketMap.value(id); + return true; +} + +void QSymbianSocketManager::setDefaultConnection(RConnection* con) +{ + iDefaultConnection = con; +} + +RConnection* QSymbianSocketManager::defaultConnection() const +{ + return iDefaultConnection; +} + +Q_GLOBAL_STATIC(QSymbianSocketManager, qt_symbianSocketManager); + +QSymbianSocketManager& QSymbianSocketManager::instance() +{ + return *(qt_symbianSocketManager()); +} + +Q_CORE_EXPORT RSocketServ& qt_symbianGetSocketServer() +{ + return QSymbianSocketManager::instance().getSocketServer(); +} + QT_END_NAMESPACE diff --git a/src/corelib/kernel/qcore_symbian_p.h b/src/corelib/kernel/qcore_symbian_p.h index 5b48689..cbe84a8 100644 --- a/src/corelib/kernel/qcore_symbian_p.h +++ b/src/corelib/kernel/qcore_symbian_p.h @@ -55,10 +55,12 @@ #include <e32std.h> #include <QtCore/qglobal.h> +#include <QtCore/qmutex.h> #include <qstring.h> #include <qrect.h> #include <qhash.h> #include <f32file.h> +#include <es_sock.h> #define QT_LSTRING2(x) L##x #define QT_LSTRING(x) QT_LSTRING2(x) @@ -154,6 +156,7 @@ enum S60PluginFuncOrdinals Q_CORE_EXPORT TLibraryFunction qt_resolveS60PluginFunc(int ordinal); Q_CORE_EXPORT RFs& qt_s60GetRFs(); +Q_CORE_EXPORT RSocketServ& qt_symbianGetSocketServer(); // Defined in qlocale_symbian.cpp. Q_CORE_EXPORT QByteArray qt_symbianLocaleName(int code); @@ -174,6 +177,104 @@ struct QScopedPointerRCloser } }; +//Wrapper for RSocket so it can be used as a key in QHash or QMap +class QHashableSocket : public RSocket +{ +public: + bool operator==(const QHashableSocket &other) const + { + return SubSessionHandle() == other.SubSessionHandle() + && Session().Handle() == other.Session().Handle(); + } + bool operator<(const QHashableSocket &other) const + { + if (Session().Handle() == other.Session().Handle()) + return SubSessionHandle() < other.SubSessionHandle(); + return Session().Handle() < other.Session().Handle(); + } +}; + +uint qHash(const RSubSessionBase& key); + +/*! + \internal + This class exists in QtCore for the benefit of QSocketNotifier, which uses integer + file descriptors in its public API. + So we need a way to map between int and RSocket. + Additionally, it is used to host the global RSocketServ session +*/ +class Q_CORE_EXPORT QSymbianSocketManager +{ +public: + QSymbianSocketManager(); + ~QSymbianSocketManager(); + + /*! + \internal + \return handle to the socket server + */ + RSocketServ& getSocketServer(); + /*! + \internal + Adds a symbian socket to the global map + \param an open socket + \return pseudo file descriptor, -1 if out of resources + */ + int addSocket(const RSocket &sock); + /*! + \internal + Removes a symbian socket from the global map + \param an open socket + \return true if the socket was in the map + */ + bool removeSocket(const RSocket &sock); + /*! + \internal + Get pseudo file descriptor for a socket + \param an open socket + \return integer handle, or -1 if not in map + */ + int lookupSocket(const RSocket &sock) const; + /*! + \internal + Get socket for a pseudo file descriptor + \param an open socket fd + \param sock (out) socket handle + \return true on success or false if not in map + */ + bool lookupSocket(int fd, RSocket& sock) const; + + /*! + \internal + Set the default connection to use for new sockets + \param an open connection + */ + void setDefaultConnection(RConnection* con); + /*! + \internal + Get the default connection to use for new sockets + \return the connection, or null pointer if there is none set + */ + RConnection *defaultConnection() const; + + /*! + \internal + Gets a reference to the singleton socket manager + */ + static QSymbianSocketManager& instance(); +private: + int allocateSocket(); + + const static int max_sockets = 0x20000; //covers all TCP and UDP ports, probably run out of memory first + const static int socket_offset = 0x40000000; //hacky way of separating sockets from file descriptors + int iNextSocket; + QHash<QHashableSocket, int> socketMap; + QHash<int, RSocket> reverseSocketMap; + mutable QMutex iMutex; + RSocketServ iSocketServ; + RConnection *iDefaultConnection; +}; + QT_END_NAMESPACE QT_END_HEADER diff --git a/src/corelib/kernel/qeventdispatcher_symbian.cpp b/src/corelib/kernel/qeventdispatcher_symbian.cpp index 4c01bde..e0eeb08 100644 --- a/src/corelib/kernel/qeventdispatcher_symbian.cpp +++ b/src/corelib/kernel/qeventdispatcher_symbian.cpp @@ -135,7 +135,7 @@ private: * The QCompleteDeferredAOs class is a special object that runs after all others, which will * reactivate the objects that were previously not run. */ -inline QActiveObject::QActiveObject(TInt priority, QEventDispatcherSymbian *dispatcher) +QActiveObject::QActiveObject(TInt priority, QEventDispatcherSymbian *dispatcher) : CActive(priority), m_dispatcher(dispatcher), m_hasAlreadyRun(false), @@ -167,12 +167,25 @@ bool QActiveObject::maybeQueueForLater() } } +bool QActiveObject::maybeDeferSocketEvent() +{ + Q_ASSERT(!m_hasRunAgain); + Q_ASSERT(m_dispatcher); + if (!m_dispatcher->areSocketEventsBlocked()) { + return false; + } + m_hasRunAgain = true; + m_dispatcher->addDeferredSocketActiveObject(this); + return true; +} + void QActiveObject::reactivateAndComplete() { + TInt error = iStatus.Int(); iStatus = KRequestPending; SetActive(); TRequestStatus *status = &iStatus; - QEventDispatcherSymbian::RequestComplete(status, KErrNone); + QEventDispatcherSymbian::RequestComplete(status, error); m_hasRunAgain = false; m_hasAlreadyRun = false; @@ -181,6 +194,7 @@ void QActiveObject::reactivateAndComplete() QWakeUpActiveObject::QWakeUpActiveObject(QEventDispatcherSymbian *dispatcher) : QActiveObject(WAKE_UP_PRIORITY, dispatcher) { + m_hostThreadId = RThread().Id(); CActiveScheduler::Add(this); iStatus = KRequestPending; SetActive(); @@ -196,6 +210,15 @@ void QWakeUpActiveObject::DoCancel() if (iStatus.Int() == KRequestPending) { TRequestStatus *status = &iStatus; QEventDispatcherSymbian::RequestComplete(status, KErrNone); + } else if (IsActive() && m_hostThreadId != RThread().Id()) { + // This is being cancelled in the adopted monitor thread, which can happen if an adopted thread with + // an event loop has exited. The event loop creates an event dispatcher with this active object, which may be complete but not run on exit. + // We force a cancellation in this thread, because a) the object cannot be deleted while active and b) without a cancellation + // the thread semaphore will be one count down. + // It is possible for this problem to affect other active objects. They symptom would be that finished signals + // from adopted threads are not sent, or they arrive much later than they should. + TRequestStatus *status = &iStatus; + User::RequestComplete(status, KErrNone); } } @@ -211,8 +234,10 @@ void QWakeUpActiveObject::RunL() QTimerActiveObject::QTimerActiveObject(QEventDispatcherSymbian *dispatcher, SymbianTimerInfo *timerInfo) : QActiveObject((timerInfo->interval) ? TIMER_PRIORITY : NULLTIMER_PRIORITY , dispatcher), - m_timerInfo(timerInfo) + m_timerInfo(timerInfo), m_expectedTimeSinceLastEvent(0) { + // start the timeout timer to ensure initialisation + m_timeoutTimer.start(); } QTimerActiveObject::~QTimerActiveObject() @@ -256,10 +281,23 @@ void QTimerActiveObject::StartTimer() m_rTimer.After(iStatus, MAX_SYMBIAN_TIMEOUT_MS * 1000); m_timerInfo->msLeft -= MAX_SYMBIAN_TIMEOUT_MS; } else { - //HighRes gives the 1ms accuracy expected by Qt, the +1 is to ensure that - //"Timers will never time out earlier than the specified timeout value" - //condition is always met. - m_rTimer.HighRes(iStatus, (m_timerInfo->msLeft + 1) * 1000); + // this algorithm implements drift correction for repeating timers + // calculate how late we are for this event + int timeSinceLastEvent = m_timeoutTimer.restart(); + int overshoot = timeSinceLastEvent - m_expectedTimeSinceLastEvent; + if (overshoot > m_timerInfo->msLeft) { + // we skipped a whole timeout, restart from here + overshoot = 0; + } + // calculate when the next event should happen + int waitTime = m_timerInfo->msLeft - overshoot; + m_expectedTimeSinceLastEvent = waitTime; + // limit the actual ms wait time to avoid wild corrections + // this will cause the real event time to slowly drift back to the expected event time + // measurements show that Symbian timers always fire 1 or 2 ms late + const int limit = 4; + waitTime = qMax(m_timerInfo->msLeft - limit, waitTime); + m_rTimer.HighRes(iStatus, waitTime * 1000); m_timerInfo->msLeft = 0; } SetActive(); @@ -306,6 +344,8 @@ void QTimerActiveObject::Start() if (!m_rTimer.Handle()) { qt_symbian_throwIfError(m_rTimer.CreateLocal()); } + m_timeoutTimer.start(); + m_expectedTimeSinceLastEvent = 0; StartTimer(); } else { iStatus = KRequestPending; @@ -635,10 +675,28 @@ void QSocketActiveObject::DoCancel() void QSocketActiveObject::RunL() { + if (maybeDeferSocketEvent()) + return; if (maybeQueueForLater()) return; - QT_TRYCATCH_LEAVING(m_dispatcher->socketFired(this)); + QT_TRYCATCH_LEAVING(run()); +} + +void QSocketActiveObject::run() +{ + QEvent e(QEvent::SockAct); + m_inSocketEvent = true; + QCoreApplication::sendEvent(m_notifier, &e); + m_inSocketEvent = false; + + if (m_deleteLater) { + delete this; + } else { + iStatus = KRequestPending; + SetActive(); + m_dispatcher->reactivateSocketNotifier(m_notifier); + } } void QSocketActiveObject::deleteLater() @@ -849,6 +907,14 @@ bool QEventDispatcherSymbian::processEvents ( QEventLoop::ProcessEventsFlags fla CActiveScheduler::Current()->WaitForAnyRequest(); } else { if (thread.RequestCount() == 0) { +#ifdef QT_SYMBIAN_PRIORITY_DROP + if (idleDetectorThread()->hasRun()) { + m_lastIdleRequestTimer.start(); + idleDetectorThread()->kick(); + } else if (m_lastIdleRequestTimer.elapsed() > maxBusyTime) { + User::AfterHighRes(m_delay); + } +#endif break; } // This one should return without delay. @@ -934,27 +1000,6 @@ void QEventDispatcherSymbian::timerFired(int timerId) return; } -void QEventDispatcherSymbian::socketFired(QSocketActiveObject *socketAO) -{ - if (m_noSocketEvents) { - m_deferredSocketEvents.append(socketAO); - return; - } - - QEvent e(QEvent::SockAct); - socketAO->m_inSocketEvent = true; - QCoreApplication::sendEvent(socketAO->m_notifier, &e); - socketAO->m_inSocketEvent = false; - - if (socketAO->m_deleteLater) { - delete socketAO; - } else { - socketAO->iStatus = KRequestPending; - socketAO->SetActive(); - reactivateSocketNotifier(socketAO->m_notifier); - } -} - void QEventDispatcherSymbian::wakeUpWasCalled() { // The reactivation should happen in RunL, right before the call to this function. @@ -1015,6 +1060,12 @@ inline void QEventDispatcherSymbian::addDeferredActiveObject(QActiveObject *obje inline void QEventDispatcherSymbian::removeDeferredActiveObject(QActiveObject *object) { m_deferredActiveObjects.removeAll(object); + m_deferredSocketEvents.removeAll(object); +} + +inline void QEventDispatcherSymbian::addDeferredSocketActiveObject(QActiveObject *object) +{ + m_deferredSocketEvents.append(object); } void QEventDispatcherSymbian::queueDeferredActiveObjectsCompletion() @@ -1040,7 +1091,8 @@ bool QEventDispatcherSymbian::sendDeferredSocketEvents() bool sentAnyEvents = false; while (!m_deferredSocketEvents.isEmpty()) { sentAnyEvents = true; - socketFired(m_deferredSocketEvents.takeFirst()); + QActiveObject *object = m_deferredSocketEvents.takeFirst(); + object->reactivateAndComplete(); } return sentAnyEvents; @@ -1059,6 +1111,8 @@ bool QEventDispatcherSymbian::hasPendingEvents() void QEventDispatcherSymbian::registerSocketNotifier ( QSocketNotifier * notifier ) { + //note - this is only for "open C" file descriptors + //for native sockets, an active object in the symbian socket engine handles this QSocketActiveObject *socketAO = new QSocketActiveObject(this, notifier); Q_CHECK_PTR(socketAO); m_notifiers.insert(notifier, socketAO); @@ -1067,6 +1121,8 @@ void QEventDispatcherSymbian::registerSocketNotifier ( QSocketNotifier * notifie void QEventDispatcherSymbian::unregisterSocketNotifier ( QSocketNotifier * notifier ) { + //note - this is only for "open C" file descriptors + //for native sockets, an active object in the symbian socket engine handles this if (m_selectThread) m_selectThread->cancelSocketEvents(notifier); if (m_notifiers.contains(notifier)) { @@ -1169,6 +1225,86 @@ void CQtActiveScheduler::Error(TInt aError) const QT_CATCH (const std::bad_alloc&) {} // ignore alloc fails, nothing more can be done } +bool QActiveObject::wait(CActive* ao, int ms) +{ + if (!ao->IsActive()) + return true; //request already complete + bool timedout = false; + if (ms > 0) { + TRequestStatus tstat; + RTimer t; + if (KErrNone != t.CreateLocal()) + return false; + t.HighRes(tstat, ms*1000); + User::WaitForRequest(tstat, ao->iStatus); + if (tstat != KRequestPending) { + timedout = true; + } else { + t.Cancel(); + //balance thread semaphore + User::WaitForRequest(tstat); + } + t.Close(); + } else { + User::WaitForRequest(ao->iStatus); + } + if (timedout) + return false; + + //evil cast to allow calling of protected virtual + ((QActiveObject*)ao)->RunL(); + + //clear active & pending flags + ao->iStatus = TRequestStatus(); + + return true; +} + +bool QActiveObject::wait(QList<CActive*> aos, int ms) +{ + QVector<TRequestStatus*> stati; + stati.reserve(aos.count() + 1); + foreach (CActive* ao, aos) { + if (!ao->IsActive()) + return true; //request already complete + stati.append(&(ao->iStatus)); + } + bool timedout = false; + TRequestStatus tstat; + RTimer t; + if (ms > 0) { + if (KErrNone != t.CreateLocal()) + return false; + t.HighRes(tstat, ms*1000); + stati.append(&tstat); + } + User::WaitForNRequest(stati.data(), stati.count()); + if (ms > 0) { + if (tstat != KRequestPending) { + timedout = true; + } else { + t.Cancel(); + //balance thread semaphore + User::WaitForRequest(tstat); + } + t.Close(); + } + if (timedout) + return false; + + foreach (CActive* ao, aos) { + if (ao->iStatus != KRequestPending) { + //evil cast to allow calling of protected virtual + ((QActiveObject*)ao)->RunL(); + + //clear active & pending flags + ao->iStatus = TRequestStatus(); + break; //only call one + } + } + return true; +} + QT_END_NAMESPACE #include "moc_qeventdispatcher_symbian_p.cpp" diff --git a/src/corelib/kernel/qeventdispatcher_symbian_p.h b/src/corelib/kernel/qeventdispatcher_symbian_p.h index bdb6dce..6fdd4b2 100644 --- a/src/corelib/kernel/qeventdispatcher_symbian_p.h +++ b/src/corelib/kernel/qeventdispatcher_symbian_p.h @@ -77,16 +77,19 @@ QT_BEGIN_NAMESPACE class QEventDispatcherSymbian; class QTimerActiveObject; -class QActiveObject : public CActive +class Q_CORE_EXPORT QActiveObject : public CActive { public: QActiveObject(TInt priority, QEventDispatcherSymbian *dispatcher); ~QActiveObject(); bool maybeQueueForLater(); + bool maybeDeferSocketEvent(); void reactivateAndComplete(); + static bool wait(CActive* ao, int ms); + static bool wait(QList<CActive*> aos, int ms); protected: QEventDispatcherSymbian *m_dispatcher; @@ -107,6 +110,9 @@ public: protected: void DoCancel(); void RunL(); + +private: + TThreadId m_hostThreadId; }; struct SymbianTimerInfo : public QSharedData @@ -144,6 +150,8 @@ private: private: SymbianTimerInfo *m_timerInfo; + QElapsedTimer m_timeoutTimer; + int m_expectedTimeSinceLastEvent; RTimer m_rTimer; }; @@ -174,6 +182,7 @@ public: protected: void DoCancel(); void RunL(); + void run(); private: QSocketNotifier *m_notifier; @@ -242,7 +251,6 @@ public: void closingDown(); void timerFired(int timerId); - void socketFired(QSocketActiveObject *socketAO); void wakeUpWasCalled(); void reactivateSocketNotifier(QSocketNotifier *notifier); @@ -254,6 +262,9 @@ public: inline int iterationCount() const { return m_iterationCount; } + void addDeferredSocketActiveObject(QActiveObject *object); + inline bool areSocketEventsBlocked() const { return m_noSocketEvents; } + static void RequestComplete(TRequestStatus *&status, TInt reason); static void RequestComplete(RThread &threadHandle, TRequestStatus *&status, TInt reason); @@ -279,8 +290,9 @@ private: unsigned char m_iterationCount; bool m_insideTimerEvent; bool m_noSocketEvents; - QList<QSocketActiveObject *> m_deferredSocketEvents; - + //deferred until socket events are enabled + QList<QActiveObject *> m_deferredSocketEvents; + //deferred until idle QList<QActiveObject *> m_deferredActiveObjects; int m_delay; diff --git a/src/corelib/kernel/qsystemerror.cpp b/src/corelib/kernel/qsystemerror.cpp index 3381afa..18622c7 100644 --- a/src/corelib/kernel/qsystemerror.cpp +++ b/src/corelib/kernel/qsystemerror.cpp @@ -154,7 +154,7 @@ static QString symbianErrorString(int errorCode) case KErrInUse: return QLatin1String("in use"); case KErrNotReady: - return QLatin1String("not ready (e.g. FS dismounted, no memory card)"); + return QLatin1String("not ready (e.g. FS dismounted, network down)"); case KErrCorrupt: return QLatin1String("corrupt"); case KErrAccessDenied: @@ -190,7 +190,7 @@ static QString symbianErrorString(int errorCode) case KErrPermissionDenied: return QLatin1String("permission denied"); default: - return QString(QLatin1String("symbian error %d")).arg(errorCode); + return QString(QLatin1String("symbian error %1")).arg(errorCode); } } #endif |