aboutsummaryrefslogtreecommitdiff
path: root/objectivec/GPBMessage.m
diff options
context:
space:
mode:
authorThomas Van Lenten <thomasvl@google.com>2017-03-29 10:46:04 -0400
committerThomas Van Lenten <thomasvl@google.com>2017-03-29 13:03:33 -0400
commit130c166697cc7df082197a10936dd9554c3e4083 (patch)
treea8e22004c8673f935825a40606a4091e9293175a /objectivec/GPBMessage.m
parentba3fa41ba86cd87f1947b9e66e450b9dc39e85a6 (diff)
downloadprotobuf-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/GPBMessage.m')
-rw-r--r--objectivec/GPBMessage.m19
1 files changed, 19 insertions, 0 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];