diff options
author | Thomas Van Lenten <thomasvl@google.com> | 2018-01-31 15:57:30 -0500 |
---|---|---|
committer | Thomas Van Lenten <thomasvl@google.com> | 2018-01-31 16:57:53 -0500 |
commit | cf016a42e645a0aea2ce0d1027e210157c49016c (patch) | |
tree | c0c230df3f080cf54602d1e2040248a06d01e525 /objectivec/GPBMessage.m | |
parent | d570d48648503e57f3abfcd9b9516583768fec48 (diff) | |
download | protobuf-cf016a42e645a0aea2ce0d1027e210157c49016c.tar.gz protobuf-cf016a42e645a0aea2ce0d1027e210157c49016c.tar.bz2 protobuf-cf016a42e645a0aea2ce0d1027e210157c49016c.zip |
Work around strange error with atomic and swift under Xcode 8.3.3.
Haven't been able to make a repo case, but this should "fix" the problem
by avoid it completely.
- Move readOnlySemaphore_ into the .m file so it isn't exposed in any
header.
- Move GPBGetObjectIvarWithField() also to go with the new limited
visibility on the readOnlySemaphore_.
Diffstat (limited to 'objectivec/GPBMessage.m')
-rw-r--r-- | objectivec/GPBMessage.m | 42 |
1 files changed, 42 insertions, 0 deletions
diff --git a/objectivec/GPBMessage.m b/objectivec/GPBMessage.m index 2e9fd7c6..db5d3b60 100644 --- a/objectivec/GPBMessage.m +++ b/objectivec/GPBMessage.m @@ -78,6 +78,20 @@ static NSString *const kGPBDataCoderKey = @"GPBData"; GPBMessage *autocreator_; GPBFieldDescriptor *autocreatorField_; GPBExtensionDescriptor *autocreatorExtension_; + + // A lock to provide mutual exclusion from internal data that can be modified + // by *read* operations such as getters (autocreation of message fields and + // message extensions, not setting of values). Used to guarantee thread safety + // for concurrent reads on the message. + // 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 + // 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. + _Atomic(dispatch_semaphore_t) readOnlySemaphore_; } @end @@ -3272,4 +3286,32 @@ id GPBGetMessageMapField(GPBMessage *self, GPBFieldDescriptor *field) { return GetOrCreateMapIvarWithField(self, field, syntax); } +id GPBGetObjectIvarWithField(GPBMessage *self, GPBFieldDescriptor *field) { + NSCAssert(!GPBFieldIsMapOrArray(field), @"Shouldn't get here"); + if (GPBGetHasIvarField(self, field)) { + uint8_t *storage = (uint8_t *)self->messageStorage_; + id *typePtr = (id *)&storage[field->description_->offset]; + return *typePtr; + } + // Not set... + + // Non messages (string/data), get their default. + if (!GPBFieldDataTypeIsMessage(field)) { + return field.defaultValue.valueMessage; + } + + GPBPrepareReadOnlySemaphore(self); + dispatch_semaphore_wait(self->readOnlySemaphore_, DISPATCH_TIME_FOREVER); + GPBMessage *result = GPBGetObjectIvarWithFieldNoAutocreate(self, field); + if (!result) { + // For non repeated messages, create the object, set it and return it. + // This object will not initially be visible via GPBGetHasIvar, so + // we save its creator so it can become visible if it's mutated later. + result = GPBCreateMessageWithAutocreator(field.msgClass, self, field); + GPBSetAutocreatedRetainedObjectIvarWithField(self, field, result); + } + dispatch_semaphore_signal(self->readOnlySemaphore_); + return result; +} + #pragma clang diagnostic pop |