diff options
author | Thomas Van Lenten <thomasvl@google.com> | 2017-03-02 14:50:10 -0500 |
---|---|---|
committer | Thomas Van Lenten <thomasvl@google.com> | 2017-03-02 16:34:11 -0500 |
commit | 2d1c5e26cb291193ac4d1f4a5179d8f6e1906229 (patch) | |
tree | 1486c2e0c6ffa3e5121f00096b27b52450f5a395 /objectivec/GPBRootObject.m | |
parent | a7e3b0ab016312f7427426d2cb88b0ab77210b79 (diff) | |
download | protobuf-2d1c5e26cb291193ac4d1f4a5179d8f6e1906229.tar.gz protobuf-2d1c5e26cb291193ac4d1f4a5179d8f6e1906229.tar.bz2 protobuf-2d1c5e26cb291193ac4d1f4a5179d8f6e1906229.zip |
Handing threading race resolving methods.
- Don't prune the extension registry as that can lead to failures when two
threads are racing.
- If adding the method fails, check and see if it already is bound to decide
the return result. Deals with threading races binding the methods.
Diffstat (limited to 'objectivec/GPBRootObject.m')
-rw-r--r-- | objectivec/GPBRootObject.m | 21 |
1 files changed, 14 insertions, 7 deletions
diff --git a/objectivec/GPBRootObject.m b/objectivec/GPBRootObject.m index 4570716f..585d205a 100644 --- a/objectivec/GPBRootObject.m +++ b/objectivec/GPBRootObject.m @@ -184,11 +184,10 @@ static id ExtensionForName(id self, SEL _cmd) { dispatch_semaphore_wait(gExtensionSingletonDictionarySemaphore, DISPATCH_TIME_FOREVER); id extension = (id)CFDictionaryGetValue(gExtensionSingletonDictionary, key); - if (extension) { - // The method is getting wired in to the class, so no need to keep it in - // the dictionary. - CFDictionaryRemoveValue(gExtensionSingletonDictionary, key); - } + // We can't remove the key from the dictionary here (as an optimization), + // two threads could have gone into +resolveClassMethod: for the same method, + // and ended up here; there's no way to ensure both return YES without letting + // both try to wire in the method. dispatch_semaphore_signal(gExtensionSingletonDictionarySemaphore); return extension; } @@ -212,9 +211,17 @@ BOOL GPBResolveExtensionClassMethod(Class self, SEL sel) { #pragma unused(obj) return extension; }); - if (class_addMethod(metaClass, sel, imp, encoding)) { - return YES; + BOOL methodAdded = class_addMethod(metaClass, sel, imp, encoding); + // class_addMethod() is documented as also failing if the method was already + // added; so we check if the method is already there and return success so + // the method dispatch will still happen. Why would it already be added? + // Two threads could cause the same method to be bound at the same time, + // but only one will actually bind it; the other still needs to return true + // so things will dispatch. + if (!methodAdded) { + methodAdded = GPBClassHasSel(metaClass, sel); } + return methodAdded; } return NO; } |