summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorShane Kearns <shane.kearns@accenture.com>2011-04-07 14:10:31 (GMT)
committerShane Kearns <shane.kearns@accenture.com>2011-04-08 15:25:33 (GMT)
commit847df81a5680fe4d71196d0afe5e68e41ae49700 (patch)
tree6568afeb603433649d7e22f023535cb98cf2f887
parenta951fb79139498774d021759d0466b4b2ff50e68 (diff)
downloadQt-847df81a5680fe4d71196d0afe5e68e41ae49700.zip
Qt-847df81a5680fe4d71196d0afe5e68e41ae49700.tar.gz
Qt-847df81a5680fe4d71196d0afe5e68e41ae49700.tar.bz2
Implement support for sockets started before the event loop
If there is no event loop when a socket notification is enabled, then invoke the method via a queued connection so that it is run again when the event loop is started. This covers sockets created and having an asynchronous API called before calling QCoreApplication::exec(). Reviewed-by: Markus Goetz
-rw-r--r--src/network/socket/qsymbiansocketengine.cpp69
-rw-r--r--src/network/socket/qsymbiansocketengine_p.h2
-rw-r--r--tests/auto/qtcpsocket/tst_qtcpsocket.cpp45
3 files changed, 72 insertions, 44 deletions
diff --git a/src/network/socket/qsymbiansocketengine.cpp b/src/network/socket/qsymbiansocketengine.cpp
index 165316d..f1b2982 100644
--- a/src/network/socket/qsymbiansocketengine.cpp
+++ b/src/network/socket/qsymbiansocketengine.cpp
@@ -1433,6 +1433,26 @@ void QSymbianSocketEnginePrivate::setError(TInt symbianError)
hasSetSocketError = true;
}
+void QSymbianSocketEngine::startNotifications()
+{
+ Q_D(QSymbianSocketEngine);
+#ifdef QNATIVESOCKETENGINE_DEBUG
+ qDebug() << "QSymbianSocketEngine::startNotifications" << d->readNotificationsEnabled << d->writeNotificationsEnabled << d->exceptNotificationsEnabled;
+#endif
+ if (!d->asyncSelect && (d->readNotificationsEnabled || d->writeNotificationsEnabled || d->exceptNotificationsEnabled)) {
+ if (d->threadData->eventDispatcher) {
+ d->asyncSelect = q_check_ptr(new QAsyncSelect(
+ static_cast<QEventDispatcherSymbian*> (d->threadData->eventDispatcher), d->nativeSocket,
+ this));
+ } else {
+ // call again when event dispatcher has been created
+ QMetaObject::invokeMethod(this, "startNotifications", Qt::QueuedConnection);
+ }
+ }
+ if (d->asyncSelect)
+ d->asyncSelect->IssueRequest();
+}
+
bool QSymbianSocketEngine::isReadNotificationEnabled() const
{
Q_D(const QSymbianSocketEngine);
@@ -1448,13 +1468,7 @@ void QSymbianSocketEngine::setReadNotificationEnabled(bool enable)
qDebug() << "QSymbianSocketEngine::setReadNotificationEnabled" << enable << "socket" << d->socketDescriptor;
#endif
d->readNotificationsEnabled = enable;
- if (enable && d->threadData->eventDispatcher && !d->asyncSelect)
- d->asyncSelect = q_check_ptr(
- new QAsyncSelect(static_cast<QEventDispatcherSymbian*>(d->threadData->eventDispatcher),
- d->nativeSocket, this));
- // TODO: what do we do if event dispatcher doesn't exist yet?
- if (d->asyncSelect)
- d->asyncSelect->IssueRequest();
+ startNotifications();
}
bool QSymbianSocketEngine::isWriteNotificationEnabled() const
@@ -1472,13 +1486,7 @@ void QSymbianSocketEngine::setWriteNotificationEnabled(bool enable)
qDebug() << "QSymbianSocketEngine::setWriteNotificationEnabled" << enable << "socket" << d->socketDescriptor;
#endif
d->writeNotificationsEnabled = enable;
- if (enable && d->threadData->eventDispatcher && !d->asyncSelect)
- d->asyncSelect = q_check_ptr(
- new QAsyncSelect(static_cast<QEventDispatcherSymbian*>(d->threadData->eventDispatcher),
- d->nativeSocket, this));
- // TODO: what do we do if event dispatcher doesn't exist yet?
- if (d->asyncSelect)
- d->asyncSelect->IssueRequest();
+ startNotifications();
}
bool QSymbianSocketEngine::isExceptionNotificationEnabled() const
@@ -1489,7 +1497,6 @@ bool QSymbianSocketEngine::isExceptionNotificationEnabled() const
return false;
}
-// FIXME do we really need this for symbian?
void QSymbianSocketEngine::setExceptionNotificationEnabled(bool enable)
{
Q_D(QSymbianSocketEngine);
@@ -1498,12 +1505,7 @@ void QSymbianSocketEngine::setExceptionNotificationEnabled(bool enable)
qDebug() << "QSymbianSocketEngine::setExceptionNotificationEnabled" << enable << "socket" << d->socketDescriptor;
#endif
d->exceptNotificationsEnabled = enable;
- if (enable && d->threadData->eventDispatcher && !d->asyncSelect)
- d->asyncSelect = q_check_ptr(
- new QAsyncSelect(static_cast<QEventDispatcherSymbian*>(d->threadData->eventDispatcher),
- d->nativeSocket, this));
- if (d->asyncSelect)
- d->asyncSelect->IssueRequest();
+ startNotifications();
}
bool QSymbianSocketEngine::waitForRead(int msecs, bool *timedOut)
@@ -1588,38 +1590,21 @@ qint64 QSymbianSocketEngine::bytesToWrite() const
return 0;
}
-//TODO: is defining PostThreadChangeEvent as QEvent::User + 1 safe?
-//TODO: would QMetaObject::invokeMethod(obj, "postThreadChangeSlot", Qt::QueuedConnection) be better?
-//TODO: if QTBUG-16787 is implemented, use that instead
bool QSymbianSocketEngine::event(QEvent* ev)
{
Q_D(QSymbianSocketEngine);
+ if (ev->type() == QEvent::ThreadChange) {
#ifdef QNATIVESOCKETENGINE_DEBUG
- qDebug() << "QSymbianSocketEngine::event";
-#endif
- switch (ev->type()) {
- case QEvent::ThreadChange:
-#ifdef QNATIVESOCKETENGINE_DEBUG
- qDebug() << "ThreadChange" << d->readNotificationsEnabled << d->writeNotificationsEnabled << d->exceptNotificationsEnabled;
+ qDebug() << "QSymbianSocketEngine::event - ThreadChange" << d->readNotificationsEnabled << d->writeNotificationsEnabled << d->exceptNotificationsEnabled;
#endif
if (d->asyncSelect) {
delete d->asyncSelect;
d->asyncSelect = 0;
- QEvent *postThreadChangeEvent = new QEvent(PostThreadChangeEvent);
- QCoreApplication::postEvent(this, postThreadChangeEvent);
+ // recreate select in new thread (because it is queued, the method is called in the new thread context)
+ QMetaObject::invokeMethod(this, "startNotifications", Qt::QueuedConnection);
}
d->selectTimer.Close();
return true;
- case PostThreadChangeEvent:
-#ifdef QNATIVESOCKETENGINE_DEBUG
- qDebug() << "PostThreadChangeEvent" << d->readNotificationsEnabled << d->writeNotificationsEnabled << d->exceptNotificationsEnabled;
-#endif
- // recreate select in new thread
- d->asyncSelect = q_check_ptr(
- new QAsyncSelect(static_cast<QEventDispatcherSymbian*>(d->threadData->eventDispatcher),
- d->nativeSocket, this));
- d->asyncSelect->IssueRequest();
- return true;
}
return QAbstractSocketEngine::event(ev);
}
diff --git a/src/network/socket/qsymbiansocketengine_p.h b/src/network/socket/qsymbiansocketengine_p.h
index bbe1269..85ab54a 100644
--- a/src/network/socket/qsymbiansocketengine_p.h
+++ b/src/network/socket/qsymbiansocketengine_p.h
@@ -134,7 +134,7 @@ public:
bool event(QEvent* ev);
- static const QEvent::Type PostThreadChangeEvent = (QEvent::Type)(QEvent::User + 1);
+ Q_INVOKABLE void startNotifications();
public Q_SLOTS:
// TODO: Why do we do this? This is private Qt implementation stuff anyway, no need for it
diff --git a/tests/auto/qtcpsocket/tst_qtcpsocket.cpp b/tests/auto/qtcpsocket/tst_qtcpsocket.cpp
index 6852e29..623e02b 100644
--- a/tests/auto/qtcpsocket/tst_qtcpsocket.cpp
+++ b/tests/auto/qtcpsocket/tst_qtcpsocket.cpp
@@ -106,6 +106,7 @@ Q_DECLARE_METATYPE(QList<QNetworkProxy>)
//TESTED_FILES=
QT_FORWARD_DECLARE_CLASS(QTcpSocket)
+QT_FORWARD_DECLARE_CLASS(SocketPair)
class tst_QTcpSocket : public QObject
{
@@ -138,6 +139,7 @@ public slots:
void init();
void cleanup();
private slots:
+ void socketsConstructedBeforeEventLoop();
void constructing();
void setInvalidSocketDescriptor();
void setSocketDescriptor();
@@ -221,6 +223,8 @@ protected slots:
void abortiveClose_abortSlot();
void remoteCloseErrorSlot();
void proxyAuthenticationRequired(const QNetworkProxy &, QAuthenticator *auth);
+ void earlySocketBytesSent(qint64 bytes);
+ void earlySocketReadyRead();
private:
QByteArray expectedReplyIMAP();
@@ -243,6 +247,10 @@ private:
bool gotClosedSignal;
int numConnections;
static int loopLevel;
+
+ SocketPair *earlyConstructedSockets;
+ int earlyBytesWrittenCount;
+ int earlyReadyReadCount;
};
enum ProxyTests {
@@ -296,8 +304,16 @@ public:
tst_QTcpSocket::tst_QTcpSocket()
{
- Q_SET_DEFAULT_IAP
tmpSocket = 0;
+
+ //This code relates to the socketsConstructedBeforeEventLoop test case
+ earlyConstructedSockets = new SocketPair;
+ QVERIFY(earlyConstructedSockets->create());
+ earlyBytesWrittenCount = 0;
+ earlyReadyReadCount = 0;
+ connect(earlyConstructedSockets->endPoints[0], SIGNAL(readyRead()), this, SLOT(earlySocketReadyRead()));
+ connect(earlyConstructedSockets->endPoints[1], SIGNAL(bytesWritten(qint64)), this, SLOT(earlySocketBytesSent(qint64)));
+ earlyConstructedSockets->endPoints[1]->write("hello work");
}
tst_QTcpSocket::~tst_QTcpSocket()
@@ -399,6 +415,33 @@ void tst_QTcpSocket::proxyAuthenticationRequired(const QNetworkProxy &, QAuthent
//----------------------------------------------------------------------------------
+void tst_QTcpSocket::socketsConstructedBeforeEventLoop()
+{
+ QFETCH_GLOBAL(bool, setProxy);
+ QFETCH_GLOBAL(bool, ssl);
+ if (setProxy || ssl)
+ return;
+ //This test checks that sockets constructed before QCoreApplication::exec() still emit signals
+ //see construction code in the tst_QTcpSocket constructor
+ enterLoop(3);
+ QCOMPARE(earlyBytesWrittenCount, 1);
+ QCOMPARE(earlyReadyReadCount, 1);
+ earlyConstructedSockets->endPoints[0]->close();
+ earlyConstructedSockets->endPoints[1]->close();
+}
+
+void tst_QTcpSocket::earlySocketBytesSent(qint64 bytes)
+{
+ earlyBytesWrittenCount++;
+}
+
+void tst_QTcpSocket::earlySocketReadyRead()
+{
+ earlyReadyReadCount++;
+}
+
+//----------------------------------------------------------------------------------
+
void tst_QTcpSocket::constructing()
{
QTcpSocket *socket = newSocket();