diff options
author | Thomas Van Lenten <thomasvl@google.com> | 2017-03-29 10:46:04 -0400 |
---|---|---|
committer | Thomas Van Lenten <thomasvl@google.com> | 2017-03-29 13:03:33 -0400 |
commit | 130c166697cc7df082197a10936dd9554c3e4083 (patch) | |
tree | a8e22004c8673f935825a40606a4091e9293175a /objectivec | |
parent | ba3fa41ba86cd87f1947b9e66e450b9dc39e85a6 (diff) | |
download | protobuf-130c166697cc7df082197a10936dd9554c3e4083.tar.gz protobuf-130c166697cc7df082197a10936dd9554c3e4083.tar.bz2 protobuf-130c166697cc7df082197a10936dd9554c3e4083.zip |
Remove the use of dispatch_once that is heap backed.
Apple recently updated the docs on dispatch_once to point out
that the storage for the dispatch_once_t must be static or global,
but not something that was ever used before as the implementation
doesn't use a memory barrier. So we drop the use and create the
semaphore when needed and use an atomic swap deal with any
threading races.
Diffstat (limited to 'objectivec')
-rw-r--r-- | objectivec/GPBMessage.m | 19 | ||||
-rw-r--r-- | objectivec/GPBMessage_PackagePrivate.h | 18 |
2 files changed, 20 insertions, 17 deletions
diff --git a/objectivec/GPBMessage.m b/objectivec/GPBMessage.m index 58a10fdb..78935b19 100644 --- a/objectivec/GPBMessage.m +++ b/objectivec/GPBMessage.m @@ -738,6 +738,25 @@ void GPBClearMessageAutocreator(GPBMessage *self) { self->autocreatorExtension_ = nil; } +// Call this before using the readOnlySemaphore_. This ensures it is created only once. +void GPBPrepareReadOnlySemaphore(GPBMessage *self) { +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdirect-ivar-access" +#pragma clang diagnostic ignored "-Wdeprecated-declarations" + + // Create the semaphore on demand (rather than init) as developers might not cause them + // to be needed, and the heap usage can add up. The atomic swap is used to avoid needing + // another lock around creating it. + if (self->readOnlySemaphore_ == nil) { + dispatch_semaphore_t worker = dispatch_semaphore_create(1); + if (!OSAtomicCompareAndSwapPtrBarrier(NULL, worker, (void * volatile *)&(self->readOnlySemaphore_))) { + dispatch_release(worker); + } + } + +#pragma clang diagnostic pop +} + static GPBUnknownFieldSet *GetOrMakeUnknownFields(GPBMessage *self) { if (!self->unknownFields_) { self->unknownFields_ = [[GPBUnknownFieldSet alloc] init]; diff --git a/objectivec/GPBMessage_PackagePrivate.h b/objectivec/GPBMessage_PackagePrivate.h index 9324cf8d..90834d40 100644 --- a/objectivec/GPBMessage_PackagePrivate.h +++ b/objectivec/GPBMessage_PackagePrivate.h @@ -70,7 +70,6 @@ typedef struct GPBMessage_Storage *GPBMessage_StoragePtr; // 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_; } @@ -105,22 +104,7 @@ CF_EXTERN_C_BEGIN // Call this before using the readOnlySemaphore_. This ensures it is created only once. -NS_INLINE void GPBPrepareReadOnlySemaphore(GPBMessage *self) { -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wdirect-ivar-access" - -// Starting on Xcode 8.3, the static analyzer complains that the dispatch_once_t -// variable passed to dispatch_once should not be allocated on the heap or -// stack. Given that the semaphore is also an instance variable of the message, -// both variables are cleared at the same time, so this is safe. -#if !defined(__clang_analyzer__) - dispatch_once(&self->readOnlySemaphoreCreationOnce_, ^{ - self->readOnlySemaphore_ = dispatch_semaphore_create(1); - }); -#endif // !defined(__clang_analyzer__) - -#pragma clang diagnostic pop -} +void GPBPrepareReadOnlySemaphore(GPBMessage *self); // Returns a new instance that was automatically created by |autocreator| for // its field |field|. |