RLMRealmUtil.mm 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147
  1. ////////////////////////////////////////////////////////////////////////////
  2. //
  3. // Copyright 2014 Realm Inc.
  4. //
  5. // Licensed under the Apache License, Version 2.0 (the "License");
  6. // you may not use this file except in compliance with the License.
  7. // You may obtain a copy of the License at
  8. //
  9. // http://www.apache.org/licenses/LICENSE-2.0
  10. //
  11. // Unless required by applicable law or agreed to in writing, software
  12. // distributed under the License is distributed on an "AS IS" BASIS,
  13. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14. // See the License for the specific language governing permissions and
  15. // limitations under the License.
  16. //
  17. ////////////////////////////////////////////////////////////////////////////
  18. #import "RLMRealmUtil.hpp"
  19. #import "RLMObjectSchema_Private.hpp"
  20. #import "RLMObservation.hpp"
  21. #import "RLMRealm_Private.hpp"
  22. #import "RLMUtil.hpp"
  23. #import <Realm/RLMConstants.h>
  24. #import <Realm/RLMSchema.h>
  25. #import "binding_context.hpp"
  26. #import <map>
  27. #import <mutex>
  28. #import <sys/event.h>
  29. #import <sys/stat.h>
  30. #import <sys/time.h>
  31. #import <unistd.h>
  32. // Global realm state
  33. static std::mutex& s_realmCacheMutex = *new std::mutex();
  34. static std::map<std::string, NSMapTable *>& s_realmsPerPath = *new std::map<std::string, NSMapTable *>();
  35. void RLMCacheRealm(std::string const& path, __unsafe_unretained RLMRealm *const realm) {
  36. std::lock_guard<std::mutex> lock(s_realmCacheMutex);
  37. NSMapTable *realms = s_realmsPerPath[path];
  38. if (!realms) {
  39. s_realmsPerPath[path] = realms = [NSMapTable mapTableWithKeyOptions:NSPointerFunctionsOpaquePersonality|NSPointerFunctionsOpaqueMemory
  40. valueOptions:NSPointerFunctionsWeakMemory];
  41. }
  42. [realms setObject:realm forKey:(__bridge id)pthread_self()];
  43. }
  44. RLMRealm *RLMGetAnyCachedRealmForPath(std::string const& path) {
  45. std::lock_guard<std::mutex> lock(s_realmCacheMutex);
  46. return [s_realmsPerPath[path] objectEnumerator].nextObject;
  47. }
  48. RLMRealm *RLMGetThreadLocalCachedRealmForPath(std::string const& path) {
  49. std::lock_guard<std::mutex> lock(s_realmCacheMutex);
  50. return [s_realmsPerPath[path] objectForKey:(__bridge id)pthread_self()];
  51. }
  52. void RLMClearRealmCache() {
  53. std::lock_guard<std::mutex> lock(s_realmCacheMutex);
  54. s_realmsPerPath.clear();
  55. }
  56. bool RLMIsInRunLoop() {
  57. // The main thread may not be in a run loop yet if we're called from
  58. // something like `applicationDidFinishLaunching:`, but it presumably will
  59. // be in the future
  60. if ([NSThread isMainThread]) {
  61. return true;
  62. }
  63. // Current mode indicates why the current callout from the runloop was made,
  64. // and is null if a runloop callout isn't currently being processed
  65. if (auto mode = CFRunLoopCopyCurrentMode(CFRunLoopGetCurrent())) {
  66. CFRelease(mode);
  67. return true;
  68. }
  69. return false;
  70. }
  71. namespace {
  72. class RLMNotificationHelper : public realm::BindingContext {
  73. public:
  74. RLMNotificationHelper(RLMRealm *realm) : _realm(realm) { }
  75. bool can_deliver_notifications() const noexcept override {
  76. return RLMIsInRunLoop();
  77. }
  78. void changes_available() override {
  79. @autoreleasepool {
  80. auto realm = _realm;
  81. if (realm && !realm.autorefresh) {
  82. [realm sendNotifications:RLMRealmRefreshRequiredNotification];
  83. }
  84. }
  85. }
  86. std::vector<ObserverState> get_observed_rows() override {
  87. @autoreleasepool {
  88. if (auto realm = _realm) {
  89. [realm detachAllEnumerators];
  90. return RLMGetObservedRows(realm->_info);
  91. }
  92. return {};
  93. }
  94. }
  95. void will_change(std::vector<ObserverState> const& observed, std::vector<void*> const& invalidated) override {
  96. @autoreleasepool {
  97. RLMWillChange(observed, invalidated);
  98. }
  99. }
  100. void did_change(std::vector<ObserverState> const& observed, std::vector<void*> const& invalidated, bool version_changed) override {
  101. try {
  102. @autoreleasepool {
  103. RLMDidChange(observed, invalidated);
  104. if (version_changed) {
  105. [_realm sendNotifications:RLMRealmDidChangeNotification];
  106. }
  107. }
  108. }
  109. catch (...) {
  110. // This can only be called during a write transaction if it was
  111. // called due to the transaction beginning, so cancel it to ensure
  112. // exceptions thrown here behave the same as exceptions thrown when
  113. // actually beginning the write
  114. if (_realm.inWriteTransaction) {
  115. [_realm cancelWriteTransaction];
  116. }
  117. throw;
  118. }
  119. }
  120. private:
  121. // This is owned by the realm, so it needs to not retain the realm
  122. __weak RLMRealm *const _realm;
  123. };
  124. } // anonymous namespace
  125. std::unique_ptr<realm::BindingContext> RLMCreateBindingContext(__unsafe_unretained RLMRealm *const realm) {
  126. return std::unique_ptr<realm::BindingContext>(new RLMNotificationHelper(realm));
  127. }