Skip to content

Commit

Permalink
#5422: Fix deadlock when saving an unsaved map on exiting the applica…
Browse files Browse the repository at this point in the history
…tion.

Caused by the EditStopwatch thread trying to use the MessageBus with the main thread blocking it.
  • Loading branch information
codereader committed Nov 18, 2020
1 parent 899573a commit bd5d60b
Showing 1 changed file with 28 additions and 22 deletions.
50 changes: 28 additions & 22 deletions radiantcore/messagebus/MessageBus.h
@@ -1,6 +1,6 @@
#pragma once

#include <mutex>
#include <map>
#include "imessagebus.h"
#include "itextstream.h"

Expand All @@ -11,13 +11,11 @@ class MessageBus :
public IMessageBus
{
private:
std::recursive_mutex _lock;

// Listener and its registration handle
typedef std::pair<std::size_t, Listener> ListenerPlusId;

// Maps message types to Listeners
std::multimap<std::size_t, ListenerPlusId> _listeners;
using Channel = std::map<std::size_t, Listener>;
// Maps message types to a set of listeners
std::map<std::size_t, Channel> _channels;

bool _processingMessage;
std::size_t _nextId;
Expand All @@ -29,23 +27,28 @@ class MessageBus :

std::size_t addListener(std::size_t messageType, const Listener& listener) override
{
std::lock_guard<std::recursive_mutex> guard(_lock);
auto channel = _channels.find(messageType);

if (channel == _channels.end())
{
channel = _channels.emplace(messageType, Channel()).first;
}

auto id = _nextId++;
_listeners.emplace(messageType, std::make_pair(id, listener));
auto subscriberId = _nextId++;
channel->second.emplace(subscriberId, listener);

return id;
return subscriberId;
}

void removeListener(std::size_t listenerId) override
{
std::lock_guard<std::recursive_mutex> guard(_lock);

for (auto it = _listeners.begin(); it != _listeners.end(); ++it)
for (auto& channel : _channels)
{
if (it->second.first == listenerId)
auto l = channel.second.find(listenerId);

if (l != channel.second.end())
{
_listeners.erase(it);
channel.second.erase(l);
return;
}
}
Expand All @@ -55,15 +58,18 @@ class MessageBus :

void sendMessage(IMessage& message) override
{
std::lock_guard<std::recursive_mutex> guard(_lock);
auto channel = _channels.find(message.getId());

// Get the message type ID
auto msgId = message.getId();
if (channel == _channels.end())
{
rWarning() << "MessageBus: No channel for message ID " << message.getId() << std::endl;
return;
}

for (auto it = _listeners.lower_bound(msgId);
it != _listeners.end() && it != _listeners.upper_bound(msgId); /* in-loop */)
for (auto it = channel->second.begin();
it != channel->second.end(); /* in-loop */)
{
(*it++).second.second(message);
(*it++).second(message);
}
}
};
Expand Down

0 comments on commit bd5d60b

Please sign in to comment.