Browse Source

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.
Thomas Van Lenten 9 years ago
parent
commit
bd41a39f69
3 changed files with 19 additions and 3 deletions
  1. 6 3
      objectivec/GPBMessage.m
  2. 12 0
      objectivec/GPBMessage_PackagePrivate.h
  3. 1 0
      objectivec/GPBUtilities.m

+ 6 - 3
objectivec/GPBMessage.m

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

+ 12 - 0
objectivec/GPBMessage_PackagePrivate.h

@@ -67,6 +67,10 @@ typedef struct GPBMessage_Storage *GPBMessage_StoragePtr;
   // priority inversion:
   // priority inversion:
   //   http://mjtsai.com/blog/2015/12/16/osspinlock-is-unsafe/
   //   http://mjtsai.com/blog/2015/12/16/osspinlock-is-unsafe/
   //   https://lists.swift.org/pipermail/swift-dev/Week-of-Mon-20151214/000372.html
   //   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_;
   dispatch_semaphore_t readOnlySemaphore_;
 }
 }
 
 
@@ -103,6 +107,14 @@ typedef struct GPBMessage_Storage *GPBMessage_StoragePtr;
 
 
 CF_EXTERN_C_BEGIN
 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
 // Returns a new instance that was automatically created by |autocreator| for
 // its field |field|.
 // its field |field|.
 GPBMessage *GPBCreateMessageWithAutocreator(Class msgClass,
 GPBMessage *GPBCreateMessageWithAutocreator(Class msgClass,

+ 1 - 0
objectivec/GPBUtilities.m

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