123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147 |
- ////////////////////////////////////////////////////////////////////////////
- //
- // Copyright 2014 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.
- //
- ////////////////////////////////////////////////////////////////////////////
- #import "RLMRealmUtil.hpp"
- #import "RLMObjectSchema_Private.hpp"
- #import "RLMObservation.hpp"
- #import "RLMRealm_Private.hpp"
- #import "RLMUtil.hpp"
- #import <Realm/RLMConstants.h>
- #import <Realm/RLMSchema.h>
- #import "binding_context.hpp"
- #import <map>
- #import <mutex>
- #import <sys/event.h>
- #import <sys/stat.h>
- #import <sys/time.h>
- #import <unistd.h>
- // Global realm state
- static std::mutex& s_realmCacheMutex = *new std::mutex();
- static std::map<std::string, NSMapTable *>& s_realmsPerPath = *new std::map<std::string, NSMapTable *>();
- void RLMCacheRealm(std::string const& path, __unsafe_unretained RLMRealm *const realm) {
- std::lock_guard<std::mutex> lock(s_realmCacheMutex);
- NSMapTable *realms = s_realmsPerPath[path];
- if (!realms) {
- s_realmsPerPath[path] = realms = [NSMapTable mapTableWithKeyOptions:NSPointerFunctionsOpaquePersonality|NSPointerFunctionsOpaqueMemory
- valueOptions:NSPointerFunctionsWeakMemory];
- }
- [realms setObject:realm forKey:(__bridge id)pthread_self()];
- }
- RLMRealm *RLMGetAnyCachedRealmForPath(std::string const& path) {
- std::lock_guard<std::mutex> lock(s_realmCacheMutex);
- return [s_realmsPerPath[path] objectEnumerator].nextObject;
- }
- RLMRealm *RLMGetThreadLocalCachedRealmForPath(std::string const& path) {
- std::lock_guard<std::mutex> lock(s_realmCacheMutex);
- return [s_realmsPerPath[path] objectForKey:(__bridge id)pthread_self()];
- }
- void RLMClearRealmCache() {
- std::lock_guard<std::mutex> lock(s_realmCacheMutex);
- s_realmsPerPath.clear();
- }
- bool RLMIsInRunLoop() {
- // The main thread may not be in a run loop yet if we're called from
- // something like `applicationDidFinishLaunching:`, but it presumably will
- // be in the future
- if ([NSThread isMainThread]) {
- return true;
- }
- // Current mode indicates why the current callout from the runloop was made,
- // and is null if a runloop callout isn't currently being processed
- if (auto mode = CFRunLoopCopyCurrentMode(CFRunLoopGetCurrent())) {
- CFRelease(mode);
- return true;
- }
- return false;
- }
- namespace {
- class RLMNotificationHelper : public realm::BindingContext {
- public:
- RLMNotificationHelper(RLMRealm *realm) : _realm(realm) { }
- bool can_deliver_notifications() const noexcept override {
- return RLMIsInRunLoop();
- }
- void changes_available() override {
- @autoreleasepool {
- auto realm = _realm;
- if (realm && !realm.autorefresh) {
- [realm sendNotifications:RLMRealmRefreshRequiredNotification];
- }
- }
- }
- std::vector<ObserverState> get_observed_rows() override {
- @autoreleasepool {
- if (auto realm = _realm) {
- [realm detachAllEnumerators];
- return RLMGetObservedRows(realm->_info);
- }
- return {};
- }
- }
- void will_change(std::vector<ObserverState> const& observed, std::vector<void*> const& invalidated) override {
- @autoreleasepool {
- RLMWillChange(observed, invalidated);
- }
- }
- void did_change(std::vector<ObserverState> const& observed, std::vector<void*> const& invalidated, bool version_changed) override {
- try {
- @autoreleasepool {
- RLMDidChange(observed, invalidated);
- if (version_changed) {
- [_realm sendNotifications:RLMRealmDidChangeNotification];
- }
- }
- }
- catch (...) {
- // This can only be called during a write transaction if it was
- // called due to the transaction beginning, so cancel it to ensure
- // exceptions thrown here behave the same as exceptions thrown when
- // actually beginning the write
- if (_realm.inWriteTransaction) {
- [_realm cancelWriteTransaction];
- }
- throw;
- }
- }
- private:
- // This is owned by the realm, so it needs to not retain the realm
- __weak RLMRealm *const _realm;
- };
- } // anonymous namespace
- std::unique_ptr<realm::BindingContext> RLMCreateBindingContext(__unsafe_unretained RLMRealm *const realm) {
- return std::unique_ptr<realm::BindingContext>(new RLMNotificationHelper(realm));
- }
|