ADD: added new version of protobuf
This commit is contained in:
@@ -31,7 +31,6 @@
|
||||
#import "GPBRootObject_PackagePrivate.h"
|
||||
|
||||
#import <objc/runtime.h>
|
||||
#import <os/lock.h>
|
||||
|
||||
#import <CoreFoundation/CoreFoundation.h>
|
||||
|
||||
@@ -74,19 +73,26 @@ static uint32_t jenkins_one_at_a_time_hash(const char *key) {
|
||||
// to worry about deallocation. All of the items are added to it at
|
||||
// startup, and so the keys don't need to be retained/released.
|
||||
// Keys are NULL terminated char *.
|
||||
static const void *GPBRootExtensionKeyRetain(__unused CFAllocatorRef allocator, const void *value) {
|
||||
static const void *GPBRootExtensionKeyRetain(CFAllocatorRef allocator,
|
||||
const void *value) {
|
||||
#pragma unused(allocator)
|
||||
return value;
|
||||
}
|
||||
|
||||
static void GPBRootExtensionKeyRelease(__unused CFAllocatorRef allocator,
|
||||
__unused const void *value) {}
|
||||
static void GPBRootExtensionKeyRelease(CFAllocatorRef allocator,
|
||||
const void *value) {
|
||||
#pragma unused(allocator)
|
||||
#pragma unused(value)
|
||||
}
|
||||
|
||||
static CFStringRef GPBRootExtensionCopyKeyDescription(const void *value) {
|
||||
const char *key = (const char *)value;
|
||||
return CFStringCreateWithCString(kCFAllocatorDefault, key, kCFStringEncodingUTF8);
|
||||
return CFStringCreateWithCString(kCFAllocatorDefault, key,
|
||||
kCFStringEncodingUTF8);
|
||||
}
|
||||
|
||||
static Boolean GPBRootExtensionKeyEqual(const void *value1, const void *value2) {
|
||||
static Boolean GPBRootExtensionKeyEqual(const void *value1,
|
||||
const void *value2) {
|
||||
const char *key1 = (const char *)value1;
|
||||
const char *key2 = (const char *)value2;
|
||||
return strcmp(key1, key2) == 0;
|
||||
@@ -97,34 +103,31 @@ static CFHashCode GPBRootExtensionKeyHash(const void *value) {
|
||||
return jenkins_one_at_a_time_hash(key);
|
||||
}
|
||||
|
||||
// Long ago, this was an OSSpinLock, but then it came to light that there were issues for that on
|
||||
// iOS:
|
||||
// NOTE: OSSpinLock may seem like a good fit here but Apple engineers have
|
||||
// pointed out that they are vulnerable to live locking on iOS in cases of
|
||||
// priority inversion:
|
||||
// http://mjtsai.com/blog/2015/12/16/osspinlock-is-unsafe/
|
||||
// https://lists.swift.org/pipermail/swift-dev/Week-of-Mon-20151214/000372.html
|
||||
// It was changed to a dispatch_semaphore_t, but that has potential for priority inversion issues.
|
||||
// The minOS versions are now high enough that os_unfair_lock can be used, and should provide
|
||||
// all the support we need. For more information in the concurrency/locking space see:
|
||||
// https://gist.github.com/tclementdev/6af616354912b0347cdf6db159c37057
|
||||
// https://developer.apple.com/library/archive/documentation/Performance/Conceptual/EnergyGuide-iOS/PrioritizeWorkWithQoS.html
|
||||
// https://developer.apple.com/videos/play/wwdc2017/706/
|
||||
static os_unfair_lock gExtensionSingletonDictionaryLock = OS_UNFAIR_LOCK_INIT;
|
||||
static dispatch_semaphore_t gExtensionSingletonDictionarySemaphore;
|
||||
static CFMutableDictionaryRef gExtensionSingletonDictionary = NULL;
|
||||
static GPBExtensionRegistry *gDefaultExtensionRegistry = NULL;
|
||||
|
||||
+ (void)initialize {
|
||||
// Ensure the global is started up.
|
||||
if (!gExtensionSingletonDictionary) {
|
||||
gExtensionSingletonDictionarySemaphore = dispatch_semaphore_create(1);
|
||||
CFDictionaryKeyCallBacks keyCallBacks = {
|
||||
// See description above for reason for using custom dictionary.
|
||||
0,
|
||||
GPBRootExtensionKeyRetain,
|
||||
GPBRootExtensionKeyRelease,
|
||||
GPBRootExtensionCopyKeyDescription,
|
||||
GPBRootExtensionKeyEqual,
|
||||
GPBRootExtensionKeyHash,
|
||||
// See description above for reason for using custom dictionary.
|
||||
0,
|
||||
GPBRootExtensionKeyRetain,
|
||||
GPBRootExtensionKeyRelease,
|
||||
GPBRootExtensionCopyKeyDescription,
|
||||
GPBRootExtensionKeyEqual,
|
||||
GPBRootExtensionKeyHash,
|
||||
};
|
||||
gExtensionSingletonDictionary = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, &keyCallBacks,
|
||||
&kCFTypeDictionaryValueCallBacks);
|
||||
gExtensionSingletonDictionary =
|
||||
CFDictionaryCreateMutable(kCFAllocatorDefault, 0, &keyCallBacks,
|
||||
&kCFTypeDictionaryValueCallBacks);
|
||||
gDefaultExtensionRegistry = [[GPBExtensionRegistry alloc] init];
|
||||
}
|
||||
|
||||
@@ -144,9 +147,10 @@ static GPBExtensionRegistry *gDefaultExtensionRegistry = NULL;
|
||||
|
||||
+ (void)globallyRegisterExtension:(GPBExtensionDescriptor *)field {
|
||||
const char *key = [field singletonNameC];
|
||||
os_unfair_lock_lock(&gExtensionSingletonDictionaryLock);
|
||||
dispatch_semaphore_wait(gExtensionSingletonDictionarySemaphore,
|
||||
DISPATCH_TIME_FOREVER);
|
||||
CFDictionarySetValue(gExtensionSingletonDictionary, key, field);
|
||||
os_unfair_lock_unlock(&gExtensionSingletonDictionaryLock);
|
||||
dispatch_semaphore_signal(gExtensionSingletonDictionarySemaphore);
|
||||
}
|
||||
|
||||
static id ExtensionForName(id self, SEL _cmd) {
|
||||
@@ -178,20 +182,21 @@ static id ExtensionForName(id self, SEL _cmd) {
|
||||
key[classNameLen + 1 + selNameLen] = '\0';
|
||||
|
||||
// NOTE: Even though this method is called from another C function,
|
||||
// gExtensionSingletonDictionaryLock and gExtensionSingletonDictionary
|
||||
// gExtensionSingletonDictionarySemaphore and gExtensionSingletonDictionary
|
||||
// will always be initialized. This is because this call flow is just to
|
||||
// lookup the Extension, meaning the code is calling an Extension class
|
||||
// message on a Message or Root class. This guarantees that the class was
|
||||
// initialized and Message classes ensure their Root was also initialized.
|
||||
NSAssert(gExtensionSingletonDictionary, @"Startup order broken!");
|
||||
|
||||
os_unfair_lock_lock(&gExtensionSingletonDictionaryLock);
|
||||
dispatch_semaphore_wait(gExtensionSingletonDictionarySemaphore,
|
||||
DISPATCH_TIME_FOREVER);
|
||||
id extension = (id)CFDictionaryGetValue(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.
|
||||
os_unfair_lock_unlock(&gExtensionSingletonDictionaryLock);
|
||||
dispatch_semaphore_signal(gExtensionSingletonDictionarySemaphore);
|
||||
return extension;
|
||||
}
|
||||
|
||||
@@ -207,9 +212,11 @@ BOOL GPBResolveExtensionClassMethod(Class self, SEL sel) {
|
||||
// file.
|
||||
id extension = ExtensionForName(self, sel);
|
||||
if (extension != nil) {
|
||||
const char *encoding = GPBMessageEncodingForSelector(@selector(getClassValue), NO);
|
||||
const char *encoding =
|
||||
GPBMessageEncodingForSelector(@selector(getClassValue), NO);
|
||||
Class metaClass = objc_getMetaClass(class_getName(self));
|
||||
IMP imp = imp_implementationWithBlock(^(__unused id obj) {
|
||||
IMP imp = imp_implementationWithBlock(^(id obj) {
|
||||
#pragma unused(obj)
|
||||
return extension;
|
||||
});
|
||||
BOOL methodAdded = class_addMethod(metaClass, sel, imp, encoding);
|
||||
@@ -227,6 +234,7 @@ BOOL GPBResolveExtensionClassMethod(Class self, SEL sel) {
|
||||
return NO;
|
||||
}
|
||||
|
||||
|
||||
+ (BOOL)resolveClassMethod:(SEL)sel {
|
||||
if (GPBResolveExtensionClassMethod(self, sel)) {
|
||||
return YES;
|
||||
|
||||
Reference in New Issue
Block a user