Skip to content
This repository has been archived by the owner on Sep 21, 2020. It is now read-only.

Commit

Permalink
Move immediate connection notification logic into Dispatcher.
Browse files Browse the repository at this point in the history
This prevents a race condition that could result in out of order
notifications.
  • Loading branch information
PeterJohnson committed Oct 1, 2017
1 parent e4a8bff commit e68a710
Show file tree
Hide file tree
Showing 6 changed files with 48 additions and 14 deletions.
6 changes: 3 additions & 3 deletions src/main/native/cpp/ConnectionNotifier.h
Original file line number Diff line number Diff line change
Expand Up @@ -57,9 +57,9 @@ class ConnectionNotifier

void Start();

unsigned int Add(
std::function<void(const ConnectionNotification& event)> callback);
unsigned int AddPolled(unsigned int poller_uid);
unsigned int Add(std::function<void(const ConnectionNotification& event)>
callback) override;
unsigned int AddPolled(unsigned int poller_uid) override;

void NotifyConnection(bool connected, const ConnectionInfo& conn_info,
unsigned int only_listener = UINT_MAX) override;
Expand Down
29 changes: 29 additions & 0 deletions src/main/native/cpp/Dispatcher.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -239,6 +239,35 @@ bool DispatcherBase::IsConnected() const {
return false;
}

unsigned int DispatcherBase::AddListener(
std::function<void(const ConnectionNotification& event)> callback,
bool immediate_notify) const {
std::lock_guard<std::mutex> lock(m_user_mutex);
unsigned int uid = m_notifier.Add(callback);
// perform immediate notifications
if (immediate_notify) {
for (auto& conn : m_connections) {
if (conn->state() != NetworkConnection::kActive) continue;
m_notifier.NotifyConnection(true, conn->info(), uid);
}
}
return uid;
}

unsigned int DispatcherBase::AddPolledListener(unsigned int poller_uid,
bool immediate_notify) const {
std::lock_guard<std::mutex> lock(m_user_mutex);
unsigned int uid = m_notifier.AddPolled(poller_uid);
// perform immediate notifications
if (immediate_notify) {
for (auto& conn : m_connections) {
if (conn->state() != NetworkConnection::kActive) continue;
m_notifier.NotifyConnection(true, conn->info(), uid);
}
}
return uid;
}

void DispatcherBase::SetConnector(Connector connector) {
std::lock_guard<std::mutex> lock(m_user_mutex);
m_client_connector = std::move(connector);
Expand Down
6 changes: 6 additions & 0 deletions src/main/native/cpp/Dispatcher.h
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,12 @@ class DispatcherBase : public IDispatcher {
std::vector<ConnectionInfo> GetConnections() const;
bool IsConnected() const;

unsigned int AddListener(
std::function<void(const ConnectionNotification& event)> callback,
bool immediate_notify) const;
unsigned int AddPolledListener(unsigned int poller_uid,
bool immediate_notify) const;

void SetConnector(Connector connector);
void SetConnectorOverride(Connector connector);
void ClearConnectorOverride();
Expand Down
3 changes: 3 additions & 0 deletions src/main/native/cpp/IConnectionNotifier.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,9 @@ class IConnectionNotifier {
IConnectionNotifier(const IConnectionNotifier&) = delete;
IConnectionNotifier& operator=(const IConnectionNotifier&) = delete;
virtual ~IConnectionNotifier() = default;
virtual unsigned int Add(
std::function<void(const ConnectionNotification& event)> callback) = 0;
virtual unsigned int AddPolled(unsigned int poller_uid) = 0;
virtual void NotifyConnection(bool connected, const ConnectionInfo& conn_info,
unsigned int only_listener = UINT_MAX) = 0;
};
Expand Down
13 changes: 2 additions & 11 deletions src/main/native/cpp/ntcore_cpp.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -388,11 +388,7 @@ NT_ConnectionListener AddConnectionListener(
auto ii = InstanceImpl::Get(i);
if (!ii) return 0;

unsigned int uid = ii->connection_notifier.Add(callback);
if (immediate_notify) {
for (auto& conn : ii->dispatcher.GetConnections())
ii->connection_notifier.NotifyConnection(true, conn, uid);
}
unsigned int uid = ii->dispatcher.AddListener(callback, immediate_notify);
return Handle(i, uid, Handle::kConnectionListener);
}

Expand Down Expand Up @@ -422,12 +418,7 @@ NT_ConnectionListener AddPolledConnectionListener(
auto ii = InstanceImpl::Get(i);
if (id < 0 || !ii) return 0;

unsigned int uid = ii->connection_notifier.AddPolled(id);
// perform immediate notifications
if (immediate_notify) {
for (auto& conn : ii->dispatcher.GetConnections())
ii->connection_notifier.NotifyConnection(true, conn, uid);
}
unsigned int uid = ii->dispatcher.AddPolledListener(id, immediate_notify);
return Handle(i, uid, Handle::kConnectionListener);
}

Expand Down
5 changes: 5 additions & 0 deletions src/test/native/cpp/MockConnectionNotifier.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,11 @@ namespace nt {

class MockConnectionNotifier : public IConnectionNotifier {
public:
MOCK_METHOD1(
Add,
unsigned int(
std::function<void(const ConnectionNotification& event)> callback));
MOCK_METHOD1(AddPolled, unsigned int(unsigned int poller_uid));
MOCK_METHOD3(NotifyConnection,
void(bool connected, const ConnectionInfo& conn_info,
unsigned int only_listener));
Expand Down

0 comments on commit e68a710

Please sign in to comment.