24 11:50:51 2015 -0700 Avoid deadlocks in standalone object initialization diff --git a/Realm/RLMAccessor.mm b/Realm/RLMAccessor.mm index a9525fe..537caee 100644 --- a/Realm/RLMAccessor.mm +++ b/Realm/RLMAccessor.mm @@ -597,6 +597,12 @@ void RLMReplaceSharedSchemaMethod(Class accessorClass, RLMObjectSchema *schema) class_replaceMethod(metaClass, @selector(sharedSchema), imp, "@@:"); } +void RLMReplaceSharedSchemaMethodWithBlock(Class accessorClass, RLMObjectSchema *(^method)(Class)) { + Class metaClass = objc_getMetaClass(class_getName(accessorClass)); + IMP imp = imp_implementationWithBlock(method); + class_replaceMethod(metaClass, @selector(sharedSchema), imp, "@@:"); +} + static Class RLMCreateAccessorClass(Class objectClass, RLMObjectSchema *schema, NSString *accessorClassPrefix, diff --git a/Realm/RLMObjectBase.h b/Realm/RLMObjectBase.h index 8184c2c..925e8e5 100644 --- a/Realm/RLMObjectBase.h +++ b/Realm/RLMObjectBase.h @@ -33,7 +33,7 @@ RLM_ASSUME_NONNULL_BEGIN + (NSString *)className; -/// Returns whether the class is included in the default set of classes persisted in a Realm. +// Returns whether the class is included in the default set of classes persisted in a Realm. + (BOOL)shouldIncludeInDefaultSchema; @end diff --git a/Realm/RLMSchema.mm b/Realm/RLMSchema.mm index d4c5f8f..2d9f514 100644 --- a/Realm/RLMSchema.mm +++ b/Realm/RLMSchema.mm @@ -41,8 +41,8 @@ const uint64_t RLMNotVersioned = realm::ObjectStore::NotVersioned; @end static RLMSchema *s_sharedSchema; -static RLMSchema *s_partialSharedSchema; -static NSMutableDictionary *s_localNameToClass; +static RLMSchema *s_partialSharedSchema = [[RLMSchema alloc] init]; +static NSMutableDictionary *s_localNameToClass = [[NSMutableDictionary alloc] init]; @implementation RLMSchema @@ -85,23 +85,13 @@ static NSMutableDictionary *s_localNameToClass; } } -+ (void)initialize { - static bool initialized; - if (initialized) { - return; - } - initialized = true; - - s_localNameToClass = [NSMutableDictionary dictionary]; - s_partialSharedSchema = [[RLMSchema alloc] init]; -} - + (instancetype)partialSharedSchema { return s_partialSharedSchema; } + (void)registerClasses:(Class *)classes count:(NSUInteger)count { @synchronized(s_localNameToClass) { + auto threadID = pthread_mach_thread_np(pthread_self()); // first create class to name mapping so we can do array validation // when creating object schema for (NSUInteger i = 0; i < count; i++) { @@ -134,8 +124,17 @@ static NSMutableDictionary *s_localNameToClass; s_localNameToClass[className] = cls; RLMReplaceClassNameMethod(cls, className); - // override sharedSchema classs method to return nil to avoid topo-sort issues - RLMReplaceSharedSchemaMethod(cls, nil); + // override sharedSchema classs method to return nil to avoid topo-sort issues when on this thread + // (i.e. while during schema initialization), but wait on other threads until schema initialization is done, + // then return the just-initialized schema + RLMReplaceSharedSchemaMethodWithBlock(cls, ^RLMObjectSchema *(Class cls) { + if (threadID == pthread_mach_thread_np(pthread_self())) { + return nil; + } + @synchronized(s_localNameToClass) { + return [cls sharedSchema]; + } + }); }