dispatch.cpp
1 /* 2 * Copyright (c) 2014 Apple Inc. All Rights Reserved. 3 * 4 * @APPLE_LICENSE_HEADER_START@ 5 * 6 * This file contains Original Code and/or Modifications of Original Code 7 * as defined in and that are subject to the Apple Public Source License 8 * Version 2.0 (the 'License'). You may not use this file except in 9 * compliance with the License. Please obtain a copy of the License at 10 * http://www.opensource.apple.com/apsl/ and read it before using this 11 * file. 12 * 13 * The Original Code and all software distributed under the License are 14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 18 * Please see the License for the specific language governing rights and 19 * limitations under the License. 20 * 21 * @APPLE_LICENSE_HEADER_END@ 22 */ 23 24 // 25 // dispatch - libdispatch wrapper 26 // 27 #include "dispatch.h" 28 #include <security_utilities/errors.h> 29 30 namespace Security { 31 namespace Dispatch { 32 33 ExceptionAwareEnqueuing::ExceptionAwareEnqueuing() 34 : mExceptionPending(false) 35 { } 36 37 void ExceptionAwareEnqueuing::enqueueWithDispatcher(void (^dispatcher)(dispatch_block_t), dispatch_block_t block) 38 { 39 if (mExceptionPending) 40 return; 41 42 dispatcher(^{ 43 if (mExceptionPending) 44 return; 45 try { 46 block(); 47 } catch (...) { 48 StLock<Mutex> _(mLock); 49 mExceptionPending = true; 50 mException = std::current_exception(); 51 } 52 }); 53 } 54 55 void ExceptionAwareEnqueuing::throwPendingException() 56 { 57 if (mExceptionPending) { 58 mExceptionPending = false; 59 std::rethrow_exception(mException); 60 } 61 } 62 63 64 65 Queue::Queue(const char *label, bool concurrent, dispatch_qos_class_t qos_class) 66 { 67 dispatch_queue_attr_t attr = concurrent ? DISPATCH_QUEUE_CONCURRENT : DISPATCH_QUEUE_SERIAL; 68 attr = dispatch_queue_attr_make_with_qos_class(attr, qos_class, 0); 69 mQueue = dispatch_queue_create(label, attr); 70 } 71 72 Queue::~Queue() 73 { 74 dispatch_barrier_sync(mQueue, ^{}); 75 dispatch_release(mQueue); 76 } 77 78 void Queue::enqueue(dispatch_block_t block) 79 { 80 enqueuing.enqueueWithDispatcher(^(dispatch_block_t block){ dispatch_async(mQueue, block); }, block); 81 } 82 83 void Queue::wait() 84 { 85 dispatch_barrier_sync(mQueue, ^{}); 86 enqueuing.throwPendingException(); 87 } 88 89 90 91 Group::Group() 92 { 93 mGroup = dispatch_group_create(); 94 } 95 96 Group::~Group() 97 { 98 dispatch_group_wait(mGroup, DISPATCH_TIME_FOREVER); 99 dispatch_release(mGroup); 100 } 101 102 void Group::enqueue(dispatch_queue_t queue, dispatch_block_t block) 103 { 104 enqueuing.enqueueWithDispatcher(^(dispatch_block_t block){ dispatch_group_async(mGroup, queue, block); }, block); 105 } 106 107 void Group::wait() 108 { 109 dispatch_group_wait(mGroup, DISPATCH_TIME_FOREVER); 110 enqueuing.throwPendingException(); 111 } 112 113 114 115 Semaphore::Semaphore(long count) { 116 mSemaphore = dispatch_semaphore_create(count); 117 } 118 119 Semaphore::Semaphore(Semaphore& semaphore) 120 : mSemaphore(semaphore.mSemaphore) 121 { 122 dispatch_retain(mSemaphore); 123 } 124 125 Semaphore::~Semaphore() { 126 dispatch_release(mSemaphore); 127 } 128 129 bool Semaphore::signal() { 130 return dispatch_semaphore_signal(mSemaphore) == 0; 131 } 132 133 bool Semaphore::wait(dispatch_time_t timeout) { 134 return dispatch_semaphore_wait(mSemaphore, timeout) == 0; 135 } 136 137 138 // Transfer ownership of held resource. 139 SemaphoreWait::SemaphoreWait(SemaphoreWait &originalWait) 140 : mSemaphore(originalWait.mSemaphore), mAcquired(originalWait.mAcquired) 141 { 142 originalWait.mAcquired = false; 143 } 144 145 SemaphoreWait::SemaphoreWait(Semaphore &semaphore, dispatch_time_t timeout) 146 : mSemaphore(semaphore) 147 { 148 mAcquired = mSemaphore.wait(timeout); 149 } 150 151 SemaphoreWait::~SemaphoreWait() 152 { 153 if (mAcquired) 154 mSemaphore.signal(); 155 } 156 157 158 } // end namespace Dispatch 159 } // end namespace Security