{
saveSessionState();
- /* Why partially duplicate CoreNetwork destructor? When each CoreNetwork quits in the
- * destructor, disconnections are processed in sequence for each object. For many IRC servers
- * on a slow network, this could significantly delay core shutdown [msecs wait * network count].
- *
- * Here, CoreSession first calls disconnect on all networks, letting them all start
- * disconnecting before beginning to sequentially wait for each network. Ideally, after the
- * first network is disconnected, the other networks will have already closed. Worst-case may
- * still wait [msecs wait time * num. of networks], but the risk should be much lower.
- *
- * CoreNetwork should still do cleanup in its own destructor in case a network is deleted
- * outside of deleting the whole CoreSession.
- *
- * If this proves to be problematic in the future, there's an alternative Qt signal-based system
- * implemented in another pull request that guarentees a maximum amount of time to disconnect,
- * but at the cost of more complex code.
- *
- * See https://github.com/quassel/quassel/pull/203
- */
-
- foreach(CoreNetwork *net, _networks.values()) {
- // Request each network properly disconnect, but don't count as user-requested disconnect
- if (net->socketConnected()) {
- // Only try if the socket's fully connected (not initializing or disconnecting).
- // Force an immediate disconnect, jumping the command queue. Ensures the proper QUIT is
- // shown even if other messages are queued.
- net->disconnectFromIrc(false, QString(), false, true);
+ // Request disconnect from all connected networks in parallel, and wait until every network
+ // has emitted the disconnected() signal before deleting the session itself
+ for (CoreNetwork *net : _networks.values()) {
+ if (net->socketState() != QAbstractSocket::UnconnectedState) {
+ _networksPendingDisconnect.insert(net->networkId());
+ connect(net, SIGNAL(disconnected(NetworkId)), this, SLOT(onNetworkDisconnected(NetworkId)));
+ net->shutdown();
}
}
- // Process the putCmd events that trigger the quit. Without this, shutting down the core
- // results in abrubtly closing the socket rather than sending the QUIT as expected.
- QCoreApplication::processEvents();
-
- foreach(CoreNetwork *net, _networks.values()) {
- // Wait briefly for each network to disconnect. Sometimes it takes a little while to send.
- if (!net->forceDisconnect()) {
- qWarning() << "Timed out quitting network" << net->networkName() <<
- "(user ID " << net->userId() << ")";
- }
- // Delete the network now that it's closed
- delete net;
+ if (_networksPendingDisconnect.isEmpty()) {
+ // Nothing to do, suicide so the core can shut down
+ deleteLater();
}
+}
- _networks.clear();
- // Suicide
- deleteLater();
+void CoreSession::onNetworkDisconnected(NetworkId networkId)
+{
+ _networksPendingDisconnect.remove(networkId);
+ if (_networksPendingDisconnect.isEmpty()) {
+ // We're done, suicide so the core can shut down
+ deleteLater();
+ }
}