@@ -78,6 +78,20 @@ @interface GPBMessage () {
78
78
GPBMessage *autocreator_;
79
79
GPBFieldDescriptor *autocreatorField_;
80
80
GPBExtensionDescriptor *autocreatorExtension_;
81
+
82
+ // A lock to provide mutual exclusion from internal data that can be modified
83
+ // by *read* operations such as getters (autocreation of message fields and
84
+ // message extensions, not setting of values). Used to guarantee thread safety
85
+ // for concurrent reads on the message.
86
+ // NOTE: OSSpinLock may seem like a good fit here but Apple engineers have
87
+ // pointed out that they are vulnerable to live locking on iOS in cases of
88
+ // priority inversion:
89
+ // http://mjtsai.com/blog/2015/12/16/osspinlock-is-unsafe/
90
+ // https://lists.swift.org/pipermail/swift-dev/Week-of-Mon-20151214/000372.html
91
+ // Use of readOnlySemaphore_ must be prefaced by a call to
92
+ // GPBPrepareReadOnlySemaphore to ensure it has been created. This allows
93
+ // readOnlySemaphore_ to be only created when actually needed.
94
+ _Atomic (dispatch_semaphore_t ) readOnlySemaphore_;
81
95
}
82
96
@end
83
97
@@ -3272,4 +3286,32 @@ id GPBGetMessageMapField(GPBMessage *self, GPBFieldDescriptor *field) {
3272
3286
return GetOrCreateMapIvarWithField (self, field, syntax);
3273
3287
}
3274
3288
3289
+ id GPBGetObjectIvarWithField (GPBMessage *self, GPBFieldDescriptor *field) {
3290
+ NSCAssert (!GPBFieldIsMapOrArray(field), @"Shouldn't get here");
3291
+ if (GPBGetHasIvarField (self, field)) {
3292
+ uint8_t *storage = (uint8_t *)self->messageStorage_ ;
3293
+ id *typePtr = (id *)&storage[field->description_->offset];
3294
+ return *typePtr;
3295
+ }
3296
+ // Not set...
3297
+
3298
+ // Non messages (string/data), get their default.
3299
+ if (!GPBFieldDataTypeIsMessage (field)) {
3300
+ return field.defaultValue .valueMessage ;
3301
+ }
3302
+
3303
+ GPBPrepareReadOnlySemaphore (self);
3304
+ dispatch_semaphore_wait (self->readOnlySemaphore_ , DISPATCH_TIME_FOREVER);
3305
+ GPBMessage *result = GPBGetObjectIvarWithFieldNoAutocreate (self, field);
3306
+ if (!result) {
3307
+ // For non repeated messages, create the object, set it and return it.
3308
+ // This object will not initially be visible via GPBGetHasIvar, so
3309
+ // we save its creator so it can become visible if it's mutated later.
3310
+ result = GPBCreateMessageWithAutocreator (field.msgClass , self, field);
3311
+ GPBSetAutocreatedRetainedObjectIvarWithField (self, field, result);
3312
+ }
3313
+ dispatch_semaphore_signal (self->readOnlySemaphore_ );
3314
+ return result;
3315
+ }
3316
+
3275
3317
#pragma clang diagnostic pop
0 commit comments