1
0
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:
Ivan Savenko
2024-02-03 22:24:32 +02:00
parent 80fc2bb695
commit 1b6ac1052a
4 changed files with 46 additions and 30 deletions

View File

@@ -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,15 +882,18 @@ 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;
} }
else
{ boost::mutex::scoped_lock interfaceLock(GH.interfaceMutex);
logNetwork->error("Lost connection to server, ending listening thread! Connection has been closed");
logNetwork->error("Lost connection to server! Connection has been closed");
networkConnection.reset();
if(client) if(client)
{ {
@@ -901,7 +912,6 @@ void CServerHandler::onDisconnected(const std::shared_ptr<INetworkConnection> &
lcd.clientId = c->connectionID; lcd.clientId = c->connectionID;
applyPackOnLobbyScreen(lcd); applyPackOnLobbyScreen(lcd);
} }
}
} }
void CServerHandler::visitForLobby(CPackForLobby & lobbyPack) void CServerHandler::visitForLobby(CPackForLobby & lobbyPack)

View File

@@ -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);

View File

@@ -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();

View File

@@ -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 progressTrackingThread = boost::thread([this, &progressTracking]()
{
auto currentProgress = std::numeric_limits<Load::Type>::max(); auto currentProgress = std::numeric_limits<Load::Type>::max();
auto progressTrackingThread = boost::thread([this, &progressTracking, &currentProgress]()
{
while(!progressTracking.finished()) while(!progressTracking.finished())
{ {
if(progressTracking.get() != currentProgress) if(progressTracking.get() != currentProgress)