1 //===----------------------------------------------------------------------===//
3 // This source file is part of the Swift.org open source project
5 // Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors
6 // Licensed under Apache License v2.0 with Runtime Library Exception
8 // See http://swift.org/LICENSE.txt for license information
9 // See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
11 //===----------------------------------------------------------------------===//
17 public final class DispatchSpecificKey<T> {
21 internal class _DispatchSpecificValue<T> {
23 internal init(value: T) { self.value = value }
26 public extension DispatchQueue {
27 public struct Attributes : OptionSet {
28 public let rawValue: UInt64
29 public init(rawValue: UInt64) { self.rawValue = rawValue }
31 public static let concurrent = Attributes(rawValue: 1<<1)
33 @available(OSX 10.12, iOS 10.0, tvOS 10.0, watchOS 3.0, *)
34 public static let initiallyInactive = Attributes(rawValue: 1<<2)
36 fileprivate func _attr() -> dispatch_queue_attr_t? {
37 var attr: dispatch_queue_attr_t? = nil
39 if self.contains(.concurrent) {
40 attr = _swift_dispatch_queue_concurrent()
42 if #available(OSX 10.12, iOS 10.0, tvOS 10.0, watchOS 3.0, *) {
43 if self.contains(.initiallyInactive) {
44 attr = CDispatch.dispatch_queue_attr_make_initially_inactive(attr)
51 public enum GlobalQueuePriority {
52 @available(OSX, deprecated: 10.10, message: "Use qos attributes instead")
53 @available(*, deprecated: 8.0, message: "Use qos attributes instead")
56 @available(OSX, deprecated: 10.10, message: "Use qos attributes instead")
57 @available(*, deprecated: 8.0, message: "Use qos attributes instead")
60 @available(OSX, deprecated: 10.10, message: "Use qos attributes instead")
61 @available(*, deprecated: 8.0, message: "Use qos attributes instead")
64 @available(OSX, deprecated: 10.10, message: "Use qos attributes instead")
65 @available(*, deprecated: 8.0, message: "Use qos attributes instead")
68 internal var _translatedValue: Int {
70 case .high: return 2 // DISPATCH_QUEUE_PRIORITY_HIGH
71 case .default: return 0 // DISPATCH_QUEUE_PRIORITY_DEFAULT
72 case .low: return -2 // DISPATCH_QUEUE_PRIORITY_LOW
73 case .background: return Int(Int16.min) // DISPATCH_QUEUE_PRIORITY_BACKGROUND
78 public enum AutoreleaseFrequency {
81 @available(OSX 10.12, iOS 10.0, tvOS 10.0, watchOS 3.0, *)
84 @available(OSX 10.12, iOS 10.0, tvOS 10.0, watchOS 3.0, *)
87 internal func _attr(attr: dispatch_queue_attr_t?) -> dispatch_queue_attr_t? {
88 if #available(OSX 10.12, iOS 10.0, tvOS 10.0, watchOS 3.0, *) {
91 // DISPATCH_AUTORELEASE_FREQUENCY_INHERIT
92 return CDispatch.dispatch_queue_attr_make_with_autorelease_frequency(attr, dispatch_autorelease_frequency_t(0))
94 // DISPATCH_AUTORELEASE_FREQUENCY_WORK_ITEM
95 return CDispatch.dispatch_queue_attr_make_with_autorelease_frequency(attr, dispatch_autorelease_frequency_t(1))
97 // DISPATCH_AUTORELEASE_FREQUENCY_NEVER
98 return CDispatch.dispatch_queue_attr_make_with_autorelease_frequency(attr, dispatch_autorelease_frequency_t(2))
106 public class func concurrentPerform(iterations: Int, execute work: (Int) -> Void) {
107 _swift_dispatch_apply_current(iterations, work)
110 public class var main: DispatchQueue {
111 return DispatchQueue(queue: _swift_dispatch_get_main_queue())
114 @available(OSX, deprecated: 10.10, message: "")
115 @available(*, deprecated: 8.0, message: "")
116 public class func global(priority: GlobalQueuePriority) -> DispatchQueue {
117 return DispatchQueue(queue: CDispatch.dispatch_get_global_queue(priority._translatedValue, 0))
120 @available(OSX 10.10, iOS 8.0, *)
121 public class func global(qos: DispatchQoS.QoSClass = .default) -> DispatchQueue {
122 return DispatchQueue(queue: CDispatch.dispatch_get_global_queue(Int(qos.rawValue.rawValue), 0))
125 public class func getSpecific<T>(key: DispatchSpecificKey<T>) -> T? {
126 let k = Unmanaged.passUnretained(key).toOpaque()
127 if let p = CDispatch.dispatch_get_specific(k) {
128 let v = Unmanaged<_DispatchSpecificValue<T>>
130 .takeUnretainedValue()
136 public convenience init(
138 qos: DispatchQoS = .unspecified,
139 attributes: Attributes = [],
140 autoreleaseFrequency: AutoreleaseFrequency = .inherit,
141 target: DispatchQueue? = nil)
143 var attr = attributes._attr()
144 if autoreleaseFrequency != .inherit {
145 attr = autoreleaseFrequency._attr(attr: attr)
147 if #available(OSX 10.10, iOS 8.0, *), qos != .unspecified {
148 attr = CDispatch.dispatch_queue_attr_make_with_qos_class(attr, qos.qosClass.rawValue.rawValue, Int32(qos.relativePriority))
151 if #available(OSX 10.12, iOS 10.0, tvOS 10.0, watchOS 3.0, *) {
152 self.init(__label: label, attr: attr, queue: target)
154 self.init(__label: label, attr: attr)
155 if let tq = target { self.setTarget(queue: tq) }
159 public var label: String {
160 return String(validatingUTF8: dispatch_queue_get_label(self.__wrapped))!
163 @available(OSX 10.10, iOS 8.0, *)
164 public func sync(execute workItem: DispatchWorkItem) {
165 CDispatch.dispatch_sync(self.__wrapped, workItem._block)
168 @available(OSX 10.10, iOS 8.0, *)
169 public func async(execute workItem: DispatchWorkItem) {
170 CDispatch.dispatch_async(self.__wrapped, workItem._block)
173 @available(OSX 10.10, iOS 8.0, *)
174 public func async(group: DispatchGroup, execute workItem: DispatchWorkItem) {
175 CDispatch.dispatch_group_async(group.__wrapped, self.__wrapped, workItem._block)
179 group: DispatchGroup? = nil,
180 qos: DispatchQoS = .unspecified,
181 flags: DispatchWorkItemFlags = [],
182 execute work: @escaping @convention(block) () -> Void)
184 if group == nil && qos == .unspecified {
185 // Fast-path route for the most common API usage
187 CDispatch.dispatch_async(self.__wrapped, work)
189 } else if flags == .barrier {
190 CDispatch.dispatch_barrier_async(self.__wrapped, work)
195 var block: @convention(block) () -> Void = work
196 if #available(OSX 10.10, iOS 8.0, *), (qos != .unspecified || !flags.isEmpty) {
197 let workItem = DispatchWorkItem(qos: qos, flags: flags, block: work)
198 block = workItem._block
202 CDispatch.dispatch_group_async(g.__wrapped, self.__wrapped, block)
204 CDispatch.dispatch_async(self.__wrapped, block)
208 private func _syncBarrier(block: () -> ()) {
209 CDispatch.dispatch_barrier_sync(self.__wrapped, block)
212 private func _syncHelper<T>(
213 fn: (() -> ()) -> (),
214 execute work: () throws -> T,
215 rescue: ((Swift.Error) throws -> (T))) rethrows -> T
218 var error: Swift.Error?
219 withoutActuallyEscaping(work) { _work in
235 @available(OSX 10.10, iOS 8.0, *)
236 private func _syncHelper<T>(
237 fn: (DispatchWorkItem) -> (),
238 flags: DispatchWorkItemFlags,
239 execute work: () throws -> T,
240 rescue: @escaping ((Swift.Error) throws -> (T))) rethrows -> T
243 var error: Swift.Error?
244 let workItem = DispatchWorkItem(flags: flags, noescapeBlock: {
259 public func sync<T>(execute work: () throws -> T) rethrows -> T {
260 return try self._syncHelper(fn: sync, execute: work, rescue: { throw $0 })
263 public func sync<T>(flags: DispatchWorkItemFlags, execute work: () throws -> T) rethrows -> T {
264 if flags == .barrier {
265 return try self._syncHelper(fn: _syncBarrier, execute: work, rescue: { throw $0 })
266 } else if #available(OSX 10.10, iOS 8.0, *), !flags.isEmpty {
267 return try self._syncHelper(fn: sync, flags: flags, execute: work, rescue: { throw $0 })
269 return try self._syncHelper(fn: sync, execute: work, rescue: { throw $0 })
273 public func asyncAfter(
274 deadline: DispatchTime,
275 qos: DispatchQoS = .unspecified,
276 flags: DispatchWorkItemFlags = [],
277 execute work: @escaping @convention(block) () -> Void)
279 if #available(OSX 10.10, iOS 8.0, *), qos != .unspecified || !flags.isEmpty {
280 let item = DispatchWorkItem(qos: qos, flags: flags, block: work)
281 CDispatch.dispatch_after(deadline.rawValue, self.__wrapped, item._block)
283 CDispatch.dispatch_after(deadline.rawValue, self.__wrapped, work)
287 public func asyncAfter(
288 wallDeadline: DispatchWallTime,
289 qos: DispatchQoS = .unspecified,
290 flags: DispatchWorkItemFlags = [],
291 execute work: @escaping @convention(block) () -> Void)
293 if #available(OSX 10.10, iOS 8.0, *), qos != .unspecified || !flags.isEmpty {
294 let item = DispatchWorkItem(qos: qos, flags: flags, block: work)
295 CDispatch.dispatch_after(wallDeadline.rawValue, self.__wrapped, item._block)
297 CDispatch.dispatch_after(wallDeadline.rawValue, self.__wrapped, work)
301 @available(OSX 10.10, iOS 8.0, *)
302 public func asyncAfter(deadline: DispatchTime, execute: DispatchWorkItem) {
303 CDispatch.dispatch_after(deadline.rawValue, self.__wrapped, execute._block)
306 @available(OSX 10.10, iOS 8.0, *)
307 public func asyncAfter(wallDeadline: DispatchWallTime, execute: DispatchWorkItem) {
308 CDispatch.dispatch_after(wallDeadline.rawValue, self.__wrapped, execute._block)
311 @available(OSX 10.10, iOS 8.0, *)
312 public var qos: DispatchQoS {
313 var relPri: Int32 = 0
314 let cls = DispatchQoS.QoSClass(rawValue: _OSQoSClass(qosClass: dispatch_queue_get_qos_class(self.__wrapped, &relPri))!)!
315 return DispatchQoS(qosClass: cls, relativePriority: Int(relPri))
318 public func getSpecific<T>(key: DispatchSpecificKey<T>) -> T? {
319 let k = Unmanaged.passUnretained(key).toOpaque()
320 if let p = dispatch_queue_get_specific(self.__wrapped, k) {
321 let v = Unmanaged<_DispatchSpecificValue<T>>
323 .takeUnretainedValue()
329 public func setSpecific<T>(key: DispatchSpecificKey<T>, value: T?) {
330 let k = Unmanaged.passUnretained(key).toOpaque()
331 let v = value.flatMap { _DispatchSpecificValue(value: $0) }
332 let p = v.flatMap { Unmanaged.passRetained($0).toOpaque() }
333 dispatch_queue_set_specific(self.__wrapped, k, p, _destructDispatchSpecificValue)
337 @_silgen_name("_dispatch_install_thread_detach_callback")
338 private static func _dispatch_install_thread_detach_callback(_ cb: @escaping @convention(c) () -> Void)
340 public static func setThreadDetachCallback(_ cb: @escaping @convention(c) () -> Void) {
341 _dispatch_install_thread_detach_callback(cb)
346 private func _destructDispatchSpecificValue(ptr: UnsafeMutableRawPointer?) {
348 Unmanaged<AnyObject>.fromOpaque(p).release()
352 @_silgen_name("_swift_dispatch_queue_concurrent")
353 internal func _swift_dispatch_queue_concurrent() -> dispatch_queue_attr_t
355 @_silgen_name("_swift_dispatch_get_main_queue")
356 internal func _swift_dispatch_get_main_queue() -> dispatch_queue_t
358 @_silgen_name("_swift_dispatch_apply_current")
359 internal func _swift_dispatch_apply_current(_ iterations: Int, _ block: @convention(block) (Int) -> Void)