mirror of
https://github.com/vcmi/vcmi.git
synced 2025-11-27 22:49:25 +02:00
Properly lock UI mutex on accessing GUI state from network thread
This commit is contained in:
@@ -88,8 +88,6 @@ template<typename T> class CApplyOnLobby : public CBaseForLobbyApply
|
|||||||
public:
|
public:
|
||||||
bool applyOnLobbyHandler(CServerHandler * handler, CPackForLobby & pack) const override
|
bool applyOnLobbyHandler(CServerHandler * handler, CPackForLobby & pack) const override
|
||||||
{
|
{
|
||||||
boost::mutex::scoped_lock interfaceLock(GH.interfaceMutex);
|
|
||||||
|
|
||||||
auto & ref = static_cast<T&>(pack);
|
auto & ref = static_cast<T&>(pack);
|
||||||
ApplyOnLobbyHandlerNetPackVisitor visitor(*handler);
|
ApplyOnLobbyHandlerNetPackVisitor visitor(*handler);
|
||||||
|
|
||||||
@@ -278,6 +276,9 @@ void CServerHandler::connectToServer(const std::string & addr, const ui16 port)
|
|||||||
|
|
||||||
void CServerHandler::onConnectionFailed(const std::string & errorMessage)
|
void CServerHandler::onConnectionFailed(const std::string & errorMessage)
|
||||||
{
|
{
|
||||||
|
assert(state == EClientState::CONNECTING);
|
||||||
|
boost::mutex::scoped_lock interfaceLock(GH.interfaceMutex);
|
||||||
|
|
||||||
if (isServerLocal())
|
if (isServerLocal())
|
||||||
{
|
{
|
||||||
// retry - local server might be still starting up
|
// retry - local server might be still starting up
|
||||||
@@ -294,6 +295,8 @@ void CServerHandler::onConnectionFailed(const std::string & errorMessage)
|
|||||||
|
|
||||||
void CServerHandler::onTimer()
|
void CServerHandler::onTimer()
|
||||||
{
|
{
|
||||||
|
boost::mutex::scoped_lock interfaceLock(GH.interfaceMutex);
|
||||||
|
|
||||||
if(state == EClientState::CONNECTION_CANCELLED)
|
if(state == EClientState::CONNECTION_CANCELLED)
|
||||||
{
|
{
|
||||||
logNetwork->info("Connection aborted by player!");
|
logNetwork->info("Connection aborted by player!");
|
||||||
@@ -306,6 +309,10 @@ void CServerHandler::onTimer()
|
|||||||
|
|
||||||
void CServerHandler::onConnectionEstablished(const NetworkConnectionPtr & netConnection)
|
void CServerHandler::onConnectionEstablished(const NetworkConnectionPtr & netConnection)
|
||||||
{
|
{
|
||||||
|
assert(state == EClientState::CONNECTING);
|
||||||
|
|
||||||
|
boost::mutex::scoped_lock interfaceLock(GH.interfaceMutex);
|
||||||
|
|
||||||
networkConnection = netConnection;
|
networkConnection = netConnection;
|
||||||
|
|
||||||
logNetwork->info("Connection established");
|
logNetwork->info("Connection established");
|
||||||
@@ -324,7 +331,6 @@ void CServerHandler::onConnectionEstablished(const NetworkConnectionPtr & netCon
|
|||||||
|
|
||||||
void CServerHandler::applyPackOnLobbyScreen(CPackForLobby & pack)
|
void CServerHandler::applyPackOnLobbyScreen(CPackForLobby & pack)
|
||||||
{
|
{
|
||||||
boost::mutex::scoped_lock interfaceLock(GH.interfaceMutex);
|
|
||||||
const CBaseForLobbyApply * apply = applier->getApplier(CTypeList::getInstance().getTypeID(&pack)); //find the applier
|
const CBaseForLobbyApply * apply = applier->getApplier(CTypeList::getInstance().getTypeID(&pack)); //find the applier
|
||||||
apply->applyOnLobbyScreen(dynamic_cast<CLobbyScreen *>(SEL), this, pack);
|
apply->applyOnLobbyScreen(dynamic_cast<CLobbyScreen *>(SEL), this, pack);
|
||||||
GH.windows().totalRedraw();
|
GH.windows().totalRedraw();
|
||||||
@@ -428,7 +434,7 @@ void CServerHandler::sendClientDisconnecting()
|
|||||||
logNetwork->info("Sent leaving signal to the server");
|
logNetwork->info("Sent leaving signal to the server");
|
||||||
}
|
}
|
||||||
sendLobbyPack(lcd);
|
sendLobbyPack(lcd);
|
||||||
c->getConnection()->close();
|
networkConnection.reset();
|
||||||
c.reset();
|
c.reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -861,6 +867,8 @@ public:
|
|||||||
|
|
||||||
void CServerHandler::onPacketReceived(const std::shared_ptr<INetworkConnection> &, const std::vector<std::byte> & message)
|
void CServerHandler::onPacketReceived(const std::shared_ptr<INetworkConnection> &, const std::vector<std::byte> & message)
|
||||||
{
|
{
|
||||||
|
boost::mutex::scoped_lock interfaceLock(GH.interfaceMutex);
|
||||||
|
|
||||||
if(state == EClientState::DISCONNECTING)
|
if(state == EClientState::DISCONNECTING)
|
||||||
{
|
{
|
||||||
assert(0); //Should not be possible - socket must be closed at this point
|
assert(0); //Should not be possible - socket must be closed at this point
|
||||||
@@ -874,33 +882,35 @@ void CServerHandler::onPacketReceived(const std::shared_ptr<INetworkConnection>
|
|||||||
|
|
||||||
void CServerHandler::onDisconnected(const std::shared_ptr<INetworkConnection> & connection, const std::string & errorMessage)
|
void CServerHandler::onDisconnected(const std::shared_ptr<INetworkConnection> & connection, const std::string & errorMessage)
|
||||||
{
|
{
|
||||||
networkConnection.reset();
|
|
||||||
|
|
||||||
if(state == EClientState::DISCONNECTING)
|
if(state == EClientState::DISCONNECTING)
|
||||||
{
|
{
|
||||||
logNetwork->info("Successfully closed connection to server, ending listening thread!");
|
assert(networkConnection == nullptr);
|
||||||
|
// Note: this branch can be reached on app shutdown, when main thread holds mutex till destruction
|
||||||
|
logNetwork->info("Successfully closed connection to server!");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
boost::mutex::scoped_lock interfaceLock(GH.interfaceMutex);
|
||||||
|
|
||||||
|
logNetwork->error("Lost connection to server! Connection has been closed");
|
||||||
|
networkConnection.reset();
|
||||||
|
|
||||||
|
if(client)
|
||||||
|
{
|
||||||
|
state = EClientState::DISCONNECTING;
|
||||||
|
|
||||||
|
GH.dispatchMainThread([]()
|
||||||
|
{
|
||||||
|
CSH->endGameplay();
|
||||||
|
GH.defActionsDef = 63;
|
||||||
|
CMM->menu->switchToTab("main");
|
||||||
|
});
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
logNetwork->error("Lost connection to server, ending listening thread! Connection has been closed");
|
LobbyClientDisconnected lcd;
|
||||||
|
lcd.clientId = c->connectionID;
|
||||||
if(client)
|
applyPackOnLobbyScreen(lcd);
|
||||||
{
|
|
||||||
state = EClientState::DISCONNECTING;
|
|
||||||
|
|
||||||
GH.dispatchMainThread([]()
|
|
||||||
{
|
|
||||||
CSH->endGameplay();
|
|
||||||
GH.defActionsDef = 63;
|
|
||||||
CMM->menu->switchToTab("main");
|
|
||||||
});
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
LobbyClientDisconnected lcd;
|
|
||||||
lcd.clientId = c->connectionID;
|
|
||||||
applyPackOnLobbyScreen(lcd);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -521,7 +521,6 @@ void CClient::handlePack(CPack * pack)
|
|||||||
CBaseForCLApply * apply = applier->getApplier(CTypeList::getInstance().getTypeID(pack)); //find the applier
|
CBaseForCLApply * apply = applier->getApplier(CTypeList::getInstance().getTypeID(pack)); //find the applier
|
||||||
if(apply)
|
if(apply)
|
||||||
{
|
{
|
||||||
boost::mutex::scoped_lock interfaceLock(GH.interfaceMutex);
|
|
||||||
apply->applyOnClBefore(this, pack);
|
apply->applyOnClBefore(this, pack);
|
||||||
logNetwork->trace("\tMade first apply on cl: %s", typeid(pack).name());
|
logNetwork->trace("\tMade first apply on cl: %s", typeid(pack).name());
|
||||||
gs->apply(pack);
|
gs->apply(pack);
|
||||||
|
|||||||
@@ -207,6 +207,8 @@ void GlobalLobbyClient::receiveJoinRoomSuccess(const JsonNode & json)
|
|||||||
|
|
||||||
void GlobalLobbyClient::onConnectionEstablished(const std::shared_ptr<INetworkConnection> & connection)
|
void GlobalLobbyClient::onConnectionEstablished(const std::shared_ptr<INetworkConnection> & connection)
|
||||||
{
|
{
|
||||||
|
boost::mutex::scoped_lock interfaceLock(GH.interfaceMutex);
|
||||||
|
|
||||||
networkConnection = connection;
|
networkConnection = connection;
|
||||||
|
|
||||||
JsonNode toSend;
|
JsonNode toSend;
|
||||||
@@ -238,6 +240,8 @@ void GlobalLobbyClient::sendClientLogin()
|
|||||||
|
|
||||||
void GlobalLobbyClient::onConnectionFailed(const std::string & errorMessage)
|
void GlobalLobbyClient::onConnectionFailed(const std::string & errorMessage)
|
||||||
{
|
{
|
||||||
|
boost::mutex::scoped_lock interfaceLock(GH.interfaceMutex);
|
||||||
|
|
||||||
auto loginWindowPtr = loginWindow.lock();
|
auto loginWindowPtr = loginWindow.lock();
|
||||||
|
|
||||||
if(!loginWindowPtr || !GH.windows().topWindow<GlobalLobbyLoginWindow>())
|
if(!loginWindowPtr || !GH.windows().topWindow<GlobalLobbyLoginWindow>())
|
||||||
@@ -249,6 +253,8 @@ void GlobalLobbyClient::onConnectionFailed(const std::string & errorMessage)
|
|||||||
|
|
||||||
void GlobalLobbyClient::onDisconnected(const std::shared_ptr<INetworkConnection> & connection, const std::string & errorMessage)
|
void GlobalLobbyClient::onDisconnected(const std::shared_ptr<INetworkConnection> & connection, const std::string & errorMessage)
|
||||||
{
|
{
|
||||||
|
boost::mutex::scoped_lock interfaceLock(GH.interfaceMutex);
|
||||||
|
|
||||||
assert(connection == networkConnection);
|
assert(connection == networkConnection);
|
||||||
networkConnection.reset();
|
networkConnection.reset();
|
||||||
|
|
||||||
|
|||||||
@@ -261,10 +261,11 @@ bool CVCMIServer::prepareToStartGame()
|
|||||||
Load::ProgressAccumulator progressTracking;
|
Load::ProgressAccumulator progressTracking;
|
||||||
Load::Progress current(1);
|
Load::Progress current(1);
|
||||||
progressTracking.include(current);
|
progressTracking.include(current);
|
||||||
auto currentProgress = std::numeric_limits<Load::Type>::max();
|
|
||||||
|
auto progressTrackingThread = boost::thread([this, &progressTracking]()
|
||||||
auto progressTrackingThread = boost::thread([this, &progressTracking, ¤tProgress]()
|
|
||||||
{
|
{
|
||||||
|
auto currentProgress = std::numeric_limits<Load::Type>::max();
|
||||||
|
|
||||||
while(!progressTracking.finished())
|
while(!progressTracking.finished())
|
||||||
{
|
{
|
||||||
if(progressTracking.get() != currentProgress)
|
if(progressTracking.get() != currentProgress)
|
||||||
|
|||||||
Reference in New Issue
Block a user