Only create the readonlySemaphore on demand.

This will lower the amount of dispatch_semaphores created per Message when the
full object tree isn't walked in a way that would require them to be created.
Uses a dispatch_once_t for one time init of the dispatch_semaphore.
pull/1339/head
Thomas Van Lenten 9 years ago
parent 5e933847cc
commit bd41a39f69
  1. 9
      objectivec/GPBMessage.m
  2. 12
      objectivec/GPBMessage_PackagePrivate.h
  3. 1
      objectivec/GPBUtilities.m

@ -556,6 +556,7 @@ static id GetArrayIvarWithField(GPBMessage *self, GPBFieldDescriptor *field) {
id array = GPBGetObjectIvarWithFieldNoAutocreate(self, field);
if (!array) {
// Check again after getting the lock.
GPBPrepareReadOnlySemaphore(self);
dispatch_semaphore_wait(self->readOnlySemaphore_, DISPATCH_TIME_FOREVER);
array = GPBGetObjectIvarWithFieldNoAutocreate(self, field);
if (!array) {
@ -586,6 +587,7 @@ static id GetMapIvarWithField(GPBMessage *self, GPBFieldDescriptor *field) {
id dict = GPBGetObjectIvarWithFieldNoAutocreate(self, field);
if (!dict) {
// Check again after getting the lock.
GPBPrepareReadOnlySemaphore(self);
dispatch_semaphore_wait(self->readOnlySemaphore_, DISPATCH_TIME_FOREVER);
dict = GPBGetObjectIvarWithFieldNoAutocreate(self, field);
if (!dict) {
@ -791,8 +793,6 @@ static GPBUnknownFieldSet *GetOrMakeUnknownFields(GPBMessage *self) {
if ((self = [super init])) {
messageStorage_ = (GPBMessage_StoragePtr)(
((uint8_t *)self) + class_getInstanceSize([self class]));
readOnlySemaphore_ = dispatch_semaphore_create(1);
}
return self;
@ -868,7 +868,9 @@ static GPBUnknownFieldSet *GetOrMakeUnknownFields(GPBMessage *self) {
- (void)dealloc {
[self internalClear:NO];
NSCAssert(!autocreator_, @"Autocreator was not cleared before dealloc.");
dispatch_release(readOnlySemaphore_);
if (readOnlySemaphore_) {
dispatch_release(readOnlySemaphore_);
}
[super dealloc];
}
@ -1706,6 +1708,7 @@ static GPBUnknownFieldSet *GetOrMakeUnknownFields(GPBMessage *self) {
}
// Check for an autocreated value.
GPBPrepareReadOnlySemaphore(self);
dispatch_semaphore_wait(readOnlySemaphore_, DISPATCH_TIME_FOREVER);
value = [autocreatedExtensionMap_ objectForKey:extension];
if (!value) {

@ -67,6 +67,10 @@ typedef struct GPBMessage_Storage *GPBMessage_StoragePtr;
// 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
// Use of readOnlySemaphore_ must be prefaced by a call to
// GPBPrepareReadOnlySemaphore to ensure it has been created. This allows
// readOnlySemaphore_ to be only created when actually needed.
dispatch_once_t readOnlySemaphoreCreationOnce_;
dispatch_semaphore_t readOnlySemaphore_;
}
@ -103,6 +107,14 @@ typedef struct GPBMessage_Storage *GPBMessage_StoragePtr;
CF_EXTERN_C_BEGIN
// Call this before using the readOnlySemaphore_. This ensures it is created only once.
NS_INLINE void GPBPrepareReadOnlySemaphore(GPBMessage *self) {
dispatch_once(&self->readOnlySemaphoreCreationOnce_, ^{
self->readOnlySemaphore_ = dispatch_semaphore_create(1);
});
}
// Returns a new instance that was automatically created by |autocreator| for
// its field |field|.
GPBMessage *GPBCreateMessageWithAutocreator(Class msgClass,

@ -412,6 +412,7 @@ id GPBGetObjectIvarWithField(GPBMessage *self, GPBFieldDescriptor *field) {
return field.defaultValue.valueMessage;
}
GPBPrepareReadOnlySemaphore(self);
dispatch_semaphore_wait(self->readOnlySemaphore_, DISPATCH_TIME_FOREVER);
GPBMessage *result = GPBGetObjectIvarWithFieldNoAutocreate(self, field);
if (!result) {

Loading…
Cancel
Save