From c3a9489b0250dabbbe0884553408fb52816be8e5 Mon Sep 17 00:00:00 2001 From: Thomas Goyne Date: Thu, 20 Aug 2015 12:27:23 -0700 Subject: [PATCH] Fix a potential deadlock when opening a realm --- src/impl/realm_coordinator.cpp | 21 +++++++++++++-------- src/impl/realm_coordinator.hpp | 3 ++- 2 files changed, 15 insertions(+), 9 deletions(-) diff --git a/src/impl/realm_coordinator.cpp b/src/impl/realm_coordinator.cpp index 82a6dff1..297a42d3 100644 --- a/src/impl/realm_coordinator.cpp +++ b/src/impl/realm_coordinator.cpp @@ -24,6 +24,11 @@ using namespace realm; using namespace realm::_impl; +struct realm::_impl::CachedRealm { + std::weak_ptr realm; + std::thread::id thread_id; +}; + static std::mutex s_coordinator_mutex; static std::map> s_coordinators_per_path; @@ -86,11 +91,11 @@ std::shared_ptr RealmCoordinator::get_realm(Realm::Config config) auto thread_id = std::this_thread::get_id(); if (config.cache) { - for (auto& weakRealm : m_cached_realms) { - // can be null if we jumped in between ref count hitting zero and - // unregister_realm() getting the lock - if (auto realm = weakRealm.lock()) { - if (realm->thread_id() == thread_id) { + for (auto& cachedRealm : m_cached_realms) { + if (cachedRealm.thread_id == thread_id) { + // can be null if we jumped in between ref count hitting zero and + // unregister_realm() getting the lock + if (auto realm = cachedRealm.realm.lock()) { return realm; } } @@ -103,7 +108,7 @@ std::shared_ptr RealmCoordinator::get_realm(Realm::Config config) m_notifier->add_realm(realm.get()); } if (config.cache) { - m_cached_realms.push_back(realm); + m_cached_realms.push_back({realm, thread_id}); } return realm; } @@ -135,7 +140,7 @@ void RealmCoordinator::unregister_realm(Realm* realm) m_notifier->remove_realm(realm); } for (size_t i = 0; i < m_cached_realms.size(); ++i) { - if (m_cached_realms[i].expired()) { + if (m_cached_realms[i].realm.expired()) { if (i + 1 < m_cached_realms.size()) { m_cached_realms[i] = std::move(m_cached_realms.back()); } @@ -159,7 +164,7 @@ void RealmCoordinator::clear_cache() } for (auto& cached_realm : coordinator->m_cached_realms) { - if (auto realm = cached_realm.lock()) { + if (auto realm = cached_realm.realm.lock()) { realms_to_close.push_back(realm); } } diff --git a/src/impl/realm_coordinator.hpp b/src/impl/realm_coordinator.hpp index f2adc69f..5813d93f 100644 --- a/src/impl/realm_coordinator.hpp +++ b/src/impl/realm_coordinator.hpp @@ -26,6 +26,7 @@ namespace realm { namespace _impl { class ExternalCommitHelper; +struct CachedRealm; // RealmCoordinator manages the weak cache of Realm instances and communication // between per-thread Realm instances for a given file @@ -66,7 +67,7 @@ private: Realm::Config m_config; std::mutex m_realm_mutex; - std::vector> m_cached_realms; + std::vector m_cached_realms; std::unique_ptr<_impl::ExternalCommitHelper> m_notifier; };