From 16fd42f605cbc3d43e3a5a8cefb68fad422e9333 Mon Sep 17 00:00:00 2001 From: Nabil Hachicha Date: Mon, 14 Mar 2016 16:25:23 -0700 Subject: [PATCH 1/6] update docu (install procedure) --- README.md | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 6776d5a5..599fab64 100644 --- a/README.md +++ b/README.md @@ -22,7 +22,11 @@ platforms when integrated into a binding. cmake . ``` -3. Build: +3. Download pegtl dependency + ``` + git submodule update --init + ``` +4. Build: ``` make From 27c9669fbc87b12da1d321de25b82dc5d358ae18 Mon Sep 17 00:00:00 2001 From: Nabil Hachicha Date: Mon, 14 Mar 2016 16:39:44 -0700 Subject: [PATCH 2/6] moving pegtl dependency as step 1 in install doc --- README.md | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index 599fab64..8187e806 100644 --- a/README.md +++ b/README.md @@ -11,21 +11,22 @@ Cross-platform code used accross bindings. Binding developers can choose to use The object store's build system currently only suports building for OS X. The object store itself can build for all Apple platforms when integrated into a binding. -1. Install CMake. You can download an installer for OS X from the [CMake download page](https://cmake.org/download/), or install via [Homebrew](http://brew.sh): +1. Download PEGTL dependency + ``` + git submodule update --init + ``` + +2. Install CMake. You can download an installer for OS X from the [CMake download page](https://cmake.org/download/), or install via [Homebrew](http://brew.sh): ``` brew install cmake ``` -2. Generate build files: +3. Generate build files: ``` cmake . ``` -3. Download pegtl dependency - ``` - git submodule update --init - ``` 4. Build: ``` From f19bab76bd3dd9602d9f1e2e9fa8b96c60d9d57a Mon Sep 17 00:00:00 2001 From: Mark Rowe Date: Tue, 1 Mar 2016 21:26:02 -0800 Subject: [PATCH 3/6] Build both dynamic and static libraries. The dynamic library makes it easy to verify that there are no linker errors when building the object store, while the static library is easier for a binding to consume. This also tweaks how the library targets are defined to ensure that other CMake projects that pull in the libraries automatically get the right include paths and link to the appropriate libraries. --- .gitignore | 3 ++- CMakeLists.txt | 2 +- src/CMakeLists.txt | 19 +++++++++++++++++-- 3 files changed, 20 insertions(+), 4 deletions(-) diff --git a/.gitignore b/.gitignore index 59c6c914..3ea88b23 100644 --- a/.gitignore +++ b/.gitignore @@ -9,5 +9,6 @@ cmake_install.cmake rules.ninja # Build products -src/librealm-object-store.* +src/librealm-object-store.dylib +src/librealm-object-store-static.a tests/tests diff --git a/CMakeLists.txt b/CMakeLists.txt index 286e6ff0..e476b64c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -13,7 +13,7 @@ include(RealmCore) set(REALM_CORE_VERSION "0.100.1" CACHE STRING "") use_realm_core(${REALM_CORE_VERSION}) -include_directories(${REALM_CORE_INCLUDE_DIR} src external/pegtl) +set(PEGTL_INCLUDE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/external/pegtl) add_subdirectory(src) add_subdirectory(tests) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 8f849049..3574147e 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -55,5 +55,20 @@ else() impl/generic/external_commit_helper.hpp) endif() -add_library(realm-object-store SHARED ${SOURCES} ${HEADERS}) -target_link_libraries(realm-object-store realm ${CF_LIBRARY}) +set(INCLUDE_DIRS ${REALM_CORE_INCLUDE_DIR} ${PEGTL_INCLUDE_DIR} ${CMAKE_CURRENT_SOURCE_DIR}) + +# An object library to group together the compilation of the source files. +add_library(realm-object-store-objects OBJECT ${SOURCES} ${HEADERS}) +add_dependencies(realm-object-store-objects realm) +set_target_properties(realm-object-store-objects PROPERTIES POSITION_INDEPENDENT_CODE 1) +target_include_directories(realm-object-store-objects PUBLIC ${INCLUDE_DIRS}) + +# A static library, aggregating the prebuilt object files. +add_library(realm-object-store-static STATIC $) +target_include_directories(realm-object-store-static PUBLIC ${INCLUDE_DIRS}) +target_link_libraries(realm-object-store-static PUBLIC realm ${CF_LIBRARY}) + +# A dynamic library, linking together the prebuilt object files. +add_library(realm-object-store SHARED $) +target_include_directories(realm-object-store PUBLIC ${INCLUDE_DIRS}) +target_link_libraries(realm-object-store PRIVATE realm ${CF_LIBRARY}) From 91c87e4de6452c93b0794d03fc4f5bb21141170d Mon Sep 17 00:00:00 2001 From: Yavor Georgiev Date: Tue, 31 May 2016 17:15:32 +0200 Subject: [PATCH 4/6] Implement commit helper and realm notifier for Android (#69) * Implement commit helper and realm notifier for Android * Remove non-existent include * Shut down the current instance when move-assigning * Only use Android logging when on Android * Cleanup realm_ptr when it hasn't been sent over the pipe * Assed that WeakRealmNotifier is closed on the thread it was created on * Typo * Fix syntax error * changes after code review * Use the proper preprocessor definition for Android * Pass the correct address to write(2) * Explicitly handle looper events * changes after code review * Do not return after handling ALOOPER_EVENT_HANGUP * Handle HANGUP after INPUT --- src/impl/android/external_commit_helper.cpp | 204 ++++++++++++++++++++ src/impl/android/external_commit_helper.hpp | 76 ++++++++ src/impl/android/weak_realm_notifier.cpp | 142 ++++++++++++++ src/impl/android/weak_realm_notifier.hpp | 58 ++++++ src/impl/external_commit_helper.hpp | 2 + src/impl/weak_realm_notifier.hpp | 2 + src/impl/weak_realm_notifier_base.hpp | 4 +- 7 files changed, 487 insertions(+), 1 deletion(-) create mode 100644 src/impl/android/external_commit_helper.cpp create mode 100644 src/impl/android/external_commit_helper.hpp create mode 100644 src/impl/android/weak_realm_notifier.cpp create mode 100644 src/impl/android/weak_realm_notifier.hpp diff --git a/src/impl/android/external_commit_helper.cpp b/src/impl/android/external_commit_helper.cpp new file mode 100644 index 00000000..6298b478 --- /dev/null +++ b/src/impl/android/external_commit_helper.cpp @@ -0,0 +1,204 @@ +//////////////////////////////////////////////////////////////////////////// +// +// Copyright 2016 Realm Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +//////////////////////////////////////////////////////////////////////////// + +#include "impl/external_commit_helper.hpp" +#include "impl/realm_coordinator.hpp" + + +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef __ANDROID__ +#include +#define ANDROID_LOG __android_log_print +#else +#define ANDROID_LOG(...) +#endif + +#include +#include + +using namespace realm; +using namespace realm::_impl; + +#define LOGE(fmt...) do { \ + fprintf(stderr, fmt); \ + ANDROID_LOG(ANDROID_LOG_ERROR, "REALM", fmt); \ +} while (0) + +namespace { +// Write a byte to a pipe to notify anyone waiting for data on the pipe +void notify_fd(int fd) +{ + while (true) { + char c = 0; + ssize_t ret = write(fd, &c, 1); + if (ret == 1) { + break; + } + + // If the pipe's buffer is full, we need to read some of the old data in + // it to make space. We don't just read in the code waiting for + // notifications so that we can notify multiple waiters with a single + // write. + assert(ret == -1 && errno == EAGAIN); + char buff[1024]; + read(fd, buff, sizeof buff); + } +} +} // anonymous namespace + +void ExternalCommitHelper::FdHolder::close() +{ + if (m_fd != -1) { + ::close(m_fd); + } + m_fd = -1; +} + +ExternalCommitHelper::ExternalCommitHelper(RealmCoordinator& parent) +: m_parent(parent) +{ + m_epfd = epoll_create(1); + if (m_epfd == -1) { + throw std::system_error(errno, std::system_category()); + } + + auto path = parent.get_path() + ".note"; + + // Create and open the named pipe + int ret = mkfifo(path.c_str(), 0600); + if (ret == -1) { + int err = errno; + if (err == ENOTSUP) { + // Filesystem doesn't support named pipes, so try putting it in tmp instead + // Hash collisions are okay here because they just result in doing + // extra work, as opposed to correctness problems + std::ostringstream ss; + + std::string tmp_dir(getenv("TMPDIR")); + ss << tmp_dir; + if (tmp_dir.back() != '/') + ss << '/'; + ss << "realm_" << std::hash()(path) << ".note"; + path = ss.str(); + ret = mkfifo(path.c_str(), 0600); + err = errno; + } + // the fifo already existing isn't an error + if (ret == -1 && err != EEXIST) { + throw std::system_error(err, std::system_category()); + } + } + + m_notify_fd = open(path.c_str(), O_RDWR); + if (m_notify_fd == -1) { + throw std::system_error(errno, std::system_category()); + } + + // Make writing to the pipe return -1 when the pipe's buffer is full + // rather than blocking until there's space available + ret = fcntl(m_notify_fd, F_SETFL, O_NONBLOCK); + if (ret == -1) { + throw std::system_error(errno, std::system_category()); + } + + // Create the anonymous pipe + int pipe_fd[2]; + ret = pipe(pipe_fd); + if (ret == -1) { + throw std::system_error(errno, std::system_category()); + } + + m_shutdown_read_fd = pipe_fd[0]; + m_shutdown_write_fd = pipe_fd[1]; + + m_thread = std::thread([=] { + try { + listen(); + } + catch (std::exception const& e) { + LOGE("uncaught exception in notifier thread: %s: %s\n", typeid(e).name(), e.what()); + throw; + } + catch (...) { + LOGE("uncaught exception in notifier thread\n"); + throw; + } + }); +} + +ExternalCommitHelper::~ExternalCommitHelper() +{ + notify_fd(m_shutdown_write_fd); + m_thread.join(); // Wait for the thread to exit +} + +void ExternalCommitHelper::listen() +{ + pthread_setname_np(pthread_self(), "Realm notification listener"); + + int ret; + + struct epoll_event event[2]; + + event[0].events = EPOLLIN | EPOLLET; + event[0].data.fd = m_notify_fd; + ret = epoll_ctl(m_epfd, EPOLL_CTL_ADD, m_notify_fd, &event[0]); + assert(ret == 0); + + event[1].events = EPOLLIN; + event[1].data.fd = m_shutdown_read_fd; + ret = epoll_ctl(m_epfd, EPOLL_CTL_ADD, m_shutdown_read_fd, &event[1]); + assert(ret == 0); + + while (true) { + struct epoll_event ev; + ret = epoll_wait(m_epfd, &ev, 1, -1); + + if (ret == -1 && errno == EINTR) { + // Interrupted system call, try again. + continue; + } + + assert(ret >= 0); + if (ret == 0) { + // Spurious wakeup; just wait again + continue; + } + + if (ev.data.u32 == (uint32_t)m_shutdown_read_fd) { + return; + } + assert(ev.data.u32 == (uint32_t)m_notify_fd); + + m_parent.on_change(); + } +} + + +void ExternalCommitHelper::notify_others() +{ + notify_fd(m_notify_fd); +} diff --git a/src/impl/android/external_commit_helper.hpp b/src/impl/android/external_commit_helper.hpp new file mode 100644 index 00000000..8e78c65f --- /dev/null +++ b/src/impl/android/external_commit_helper.hpp @@ -0,0 +1,76 @@ +//////////////////////////////////////////////////////////////////////////// +// +// Copyright 2016 Realm Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +//////////////////////////////////////////////////////////////////////////// + +#include + +namespace realm { + +namespace _impl { +class RealmCoordinator; + +class ExternalCommitHelper { +public: + ExternalCommitHelper(RealmCoordinator& parent); + ~ExternalCommitHelper(); + + void notify_others(); + +private: + // A RAII holder for a file descriptor which automatically closes the wrapped + // fd when it's deallocated + class FdHolder { + public: + FdHolder() = default; + ~FdHolder() { close(); } + operator int() const { return m_fd; } + + FdHolder& operator=(int new_fd) { + close(); + m_fd = new_fd; + return *this; + } + + private: + int m_fd = -1; + void close(); + + FdHolder& operator=(FdHolder const&) = delete; + FdHolder(FdHolder const&) = delete; + }; + + void listen(); + + RealmCoordinator& m_parent; + + // The listener thread + std::thread m_thread; + + // Read-write file descriptor for the named pipe which is waited on for + // changes and written to when a commit is made + FdHolder m_notify_fd; + // File descriptor for epoll + FdHolder m_epfd; + // The two ends of an anonymous pipe used to notify the kqueue() thread that + // it should be shut down. + FdHolder m_shutdown_read_fd; + FdHolder m_shutdown_write_fd; +}; + +} // namespace _impl +} // namespace realm + diff --git a/src/impl/android/weak_realm_notifier.cpp b/src/impl/android/weak_realm_notifier.cpp new file mode 100644 index 00000000..e49537b5 --- /dev/null +++ b/src/impl/android/weak_realm_notifier.cpp @@ -0,0 +1,142 @@ +//////////////////////////////////////////////////////////////////////////// +// +// Copyright 2016 Realm Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +//////////////////////////////////////////////////////////////////////////// + +#include "impl/weak_realm_notifier.hpp" +#include "shared_realm.hpp" + +#include +#include +#include +#include + +#define LOGE(fmt...) do { \ + fprintf(stderr, fmt); \ + __android_log_print(ANDROID_LOG_ERROR, "REALM", fmt); \ +} while (0) + +namespace realm { +namespace _impl { + +WeakRealmNotifier::WeakRealmNotifier(const std::shared_ptr& realm, bool cache) +: WeakRealmNotifierBase(realm, cache) +, m_thread_has_looper(false) +{ + ALooper* looper = ALooper_forThread(); + if (!looper) { + return; + } + + int message_pipe[2]; + if (pipe2(message_pipe, O_CLOEXEC | O_NONBLOCK)) { + LOGE("could not create WeakRealmNotifier ALooper message pipe: %s", strerror(errno)); + return; + } + + if (ALooper_addFd(looper, message_pipe[0], 3 /* LOOPER_ID_USER */, ALOOPER_EVENT_INPUT | ALOOPER_EVENT_HANGUP, &looper_callback, nullptr) != 1) { + LOGE("Error adding WeakRealmNotifier callback to looper."); + ::close(message_pipe[0]); + ::close(message_pipe[1]); + + return; + } + + m_message_pipe.read = message_pipe[0]; + m_message_pipe.write = message_pipe[1]; + m_thread_has_looper = true; +} + +WeakRealmNotifier::WeakRealmNotifier(WeakRealmNotifier&& rgt) +: WeakRealmNotifierBase(std::move(rgt)) +, m_message_pipe(std::move(rgt.m_message_pipe)) +{ + bool flag = true; + m_thread_has_looper = rgt.m_thread_has_looper.compare_exchange_strong(flag, false); +} + +WeakRealmNotifier& WeakRealmNotifier::operator=(WeakRealmNotifier&& rgt) +{ + close(); + + WeakRealmNotifierBase::operator=(std::move(rgt)); + m_message_pipe = std::move(rgt.m_message_pipe); + + bool flag = true; + m_thread_has_looper = rgt.m_thread_has_looper.compare_exchange_strong(flag, false); + + return *this; +} + +void WeakRealmNotifier::close() +{ + bool flag = true; + if (m_thread_has_looper.compare_exchange_strong(flag, false)) { + // closing one end of the pipe here will trigger ALOOPER_EVENT_HANGUP in the callback + // which will do the rest of the cleanup + ::close(m_message_pipe.write); + } +} + +void WeakRealmNotifier::notify() +{ + if (m_thread_has_looper && !expired()) { + + // we need to pass the weak Realm pointer to the other thread. + // to do so we allocate a weak pointer on the heap and send its address over a pipe. + // the other end of the pipe is read by the realm thread. when it's done with the pointer, it deletes it. + auto realm_ptr = new std::weak_ptr(realm()); + if (write(m_message_pipe.write, &realm_ptr, sizeof(realm_ptr)) != sizeof(realm_ptr)) { + delete realm_ptr; + LOGE("Buffer overrun when writing to WeakRealmNotifier's ALooper message pipe."); + } + } +} + +int WeakRealmNotifier::looper_callback(int fd, int events, void* data) +{ + if ((events & ALOOPER_EVENT_INPUT) != 0) { + // this is a pointer to a heap-allocated weak Realm pointer created by the notifiying thread. + // the actual address to the pointer is communicated over a pipe. + // we have to delete it so as to not leak, using the same memory allocation facilities it was allocated with. + std::weak_ptr* realm_ptr = nullptr; + while (read(fd, &realm_ptr, sizeof(realm_ptr)) == sizeof(realm_ptr)) { + if (auto realm = realm_ptr->lock()) { + if (!realm->is_closed()) { + realm->notify(); + } + } + + delete realm_ptr; + } + } + + if ((events & ALOOPER_EVENT_HANGUP) != 0) { + // this callback is always invoked on the looper thread so it's fine to get the looper like this + ALooper_removeFd(ALooper_forThread(), fd); + ::close(fd); + } + + if ((events & ALOOPER_EVENT_ERROR) != 0) { + LOGE("Unexpected error on WeakRealmNotifier's ALooper message pipe."); + } + + // return 1 to continue receiving events + return 1; +} + +} +} diff --git a/src/impl/android/weak_realm_notifier.hpp b/src/impl/android/weak_realm_notifier.hpp new file mode 100644 index 00000000..ebb30da6 --- /dev/null +++ b/src/impl/android/weak_realm_notifier.hpp @@ -0,0 +1,58 @@ +//////////////////////////////////////////////////////////////////////////// +// +// Copyright 2016 Realm Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +//////////////////////////////////////////////////////////////////////////// + +#include "impl/weak_realm_notifier_base.hpp" + +#include + +namespace realm { +class Realm; + +namespace _impl { + +class WeakRealmNotifier : public WeakRealmNotifierBase { +public: + WeakRealmNotifier(const std::shared_ptr& realm, bool cache); + ~WeakRealmNotifier() { close(); } + + WeakRealmNotifier(WeakRealmNotifier&&); + WeakRealmNotifier& operator=(WeakRealmNotifier&&); + + WeakRealmNotifier(const WeakRealmNotifier&) = delete; + WeakRealmNotifier& operator=(const WeakRealmNotifier&) = delete; + + // Asyncronously call notify() on the Realm on the appropriate thread + void notify(); + +private: + void close(); + + static int looper_callback(int fd, int events, void* data); + + std::atomic m_thread_has_looper; + + // pipe file descriptor pair we use to signal ALooper + struct { + int read = -1; + int write = -1; + } m_message_pipe; +}; + +} // namespace _impl +} // namespace realm + diff --git a/src/impl/external_commit_helper.hpp b/src/impl/external_commit_helper.hpp index c467a4b9..0abbd56c 100644 --- a/src/impl/external_commit_helper.hpp +++ b/src/impl/external_commit_helper.hpp @@ -23,6 +23,8 @@ #if REALM_PLATFORM_APPLE #include "impl/apple/external_commit_helper.hpp" +#elif REALM_ANDROID +#include "impl/android/external_commit_helper.hpp" #else #include "impl/generic/external_commit_helper.hpp" #endif diff --git a/src/impl/weak_realm_notifier.hpp b/src/impl/weak_realm_notifier.hpp index b0e4f595..ecbe7a71 100644 --- a/src/impl/weak_realm_notifier.hpp +++ b/src/impl/weak_realm_notifier.hpp @@ -23,6 +23,8 @@ #if REALM_PLATFORM_APPLE #include "impl/apple/weak_realm_notifier.hpp" +#elif REALM_ANDROID +#include "impl/android/weak_realm_notifier.hpp" #else #include "impl/generic/weak_realm_notifier.hpp" #endif diff --git a/src/impl/weak_realm_notifier_base.hpp b/src/impl/weak_realm_notifier_base.hpp index a8c41bab..b72636fa 100644 --- a/src/impl/weak_realm_notifier_base.hpp +++ b/src/impl/weak_realm_notifier_base.hpp @@ -40,7 +40,7 @@ public: std::shared_ptr realm() const { return m_realm.lock(); } // Does this WeakRealmNotifierBase store a Realm instance that should be used on the current thread? - bool is_cached_for_current_thread() const { return m_cache && m_thread_id == std::this_thread::get_id(); } + bool is_cached_for_current_thread() const { return m_cache && is_for_current_thread(); } // Has the Realm instance been destroyed? bool expired() const { return m_realm.expired(); } @@ -48,6 +48,8 @@ public: // Is this a WeakRealmNotifierBase for the given Realm instance? bool is_for_realm(Realm* realm) const { return realm == m_realm_key; } + bool is_for_current_thread() const { return m_thread_id == std::this_thread::get_id(); } + private: std::weak_ptr m_realm; std::thread::id m_thread_id = std::this_thread::get_id(); From 7bb8a043592ecce6ac57d869e71e32f5aeac3c25 Mon Sep 17 00:00:00 2001 From: Scott Kyle Date: Tue, 31 May 2016 11:05:12 -0700 Subject: [PATCH 5/6] Fix for object store build issues on Android --- src/impl/android/external_commit_helper.cpp | 5 +---- src/impl/android/weak_realm_notifier.cpp | 1 + src/shared_realm.hpp | 2 ++ 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/impl/android/external_commit_helper.cpp b/src/impl/android/external_commit_helper.cpp index 6298b478..24129342 100644 --- a/src/impl/android/external_commit_helper.cpp +++ b/src/impl/android/external_commit_helper.cpp @@ -19,8 +19,8 @@ #include "impl/external_commit_helper.hpp" #include "impl/realm_coordinator.hpp" - #include +#include #include #include #include @@ -36,9 +36,6 @@ #define ANDROID_LOG(...) #endif -#include -#include - using namespace realm; using namespace realm::_impl; diff --git a/src/impl/android/weak_realm_notifier.cpp b/src/impl/android/weak_realm_notifier.cpp index e49537b5..9722751c 100644 --- a/src/impl/android/weak_realm_notifier.cpp +++ b/src/impl/android/weak_realm_notifier.cpp @@ -19,6 +19,7 @@ #include "impl/weak_realm_notifier.hpp" #include "shared_realm.hpp" +#include #include #include #include diff --git a/src/shared_realm.hpp b/src/shared_realm.hpp index 90ff1665..e7c3c0f2 100644 --- a/src/shared_realm.hpp +++ b/src/shared_realm.hpp @@ -132,6 +132,8 @@ namespace realm { // Realm after closing it will produce undefined behavior. void close(); + bool is_closed() { return m_shared_group == nullptr; } + ~Realm(); void init(std::shared_ptr<_impl::RealmCoordinator> coordinator); From 385fe97861843339db8d2ad2b627088a3934b5ce Mon Sep 17 00:00:00 2001 From: Scott Kyle Date: Tue, 31 May 2016 11:27:39 -0700 Subject: [PATCH 6/6] Make Realm::is_closed() work on read-only instances --- src/shared_realm.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/shared_realm.hpp b/src/shared_realm.hpp index e7c3c0f2..8b70d3b1 100644 --- a/src/shared_realm.hpp +++ b/src/shared_realm.hpp @@ -132,7 +132,7 @@ namespace realm { // Realm after closing it will produce undefined behavior. void close(); - bool is_closed() { return m_shared_group == nullptr; } + bool is_closed() { return !m_read_only_group && !m_shared_group; } ~Realm();