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 struct DispatchQueueAttributes : OptionSet {
18 public let rawValue: UInt64
19 public init(rawValue: UInt64) { self.rawValue = rawValue }
21 public static let serial = DispatchQueueAttributes(rawValue: 0<<0)
22 public static let concurrent = DispatchQueueAttributes(rawValue: 1<<1)
24 @available(OSX 10.12, iOS 10.0, tvOS 10.0, watchOS 3.0, *)
25 public static let initiallyInactive = DispatchQueueAttributes(rawValue: 1<<2)
27 @available(OSX 10.12, iOS 10.0, tvOS 10.0, watchOS 3.0, *)
28 public static let autoreleaseInherit = DispatchQueueAttributes(rawValue: 1<<3)
30 @available(OSX 10.12, iOS 10.0, tvOS 10.0, watchOS 3.0, *)
31 public static let autoreleaseWorkItem = DispatchQueueAttributes(rawValue: 1<<4)
33 @available(OSX 10.12, iOS 10.0, tvOS 10.0, watchOS 3.0, *)
34 public static let autoreleaseNever = DispatchQueueAttributes(rawValue: 1<<5)
36 @available(OSX 10.10, iOS 8.0, *)
37 public static let qosUserInteractive = DispatchQueueAttributes(rawValue: 1<<6)
39 @available(OSX 10.10, iOS 8.0, *)
40 public static let qosUserInitiated = DispatchQueueAttributes(rawValue: 1<<7)
42 @available(OSX 10.10, iOS 8.0, *)
43 public static let qosDefault = DispatchQueueAttributes(rawValue: 1<<8)
45 @available(OSX 10.10, iOS 8.0, *)
46 public static let qosUtility = DispatchQueueAttributes(rawValue: 1<<9)
48 @available(OSX 10.10, iOS 8.0, *)
49 public static let qosBackground = DispatchQueueAttributes(rawValue: 1<<10)
51 @available(*, deprecated, message: ".noQoS has no effect, it should not be used")
52 public static let noQoS = DispatchQueueAttributes(rawValue: 1<<11)
54 private var attr: dispatch_queue_attr_t? {
55 var attr: dispatch_queue_attr_t?
57 if self.contains(.concurrent) {
58 attr = _swift_dispatch_queue_concurrent()
60 if #available(OSX 10.12, iOS 10.0, tvOS 10.0, watchOS 3.0, *) {
61 if self.contains(.initiallyInactive) {
62 attr = CDispatch.dispatch_queue_attr_make_initially_inactive(attr)
64 if self.contains(.autoreleaseWorkItem) {
65 // DISPATCH_AUTORELEASE_FREQUENCY_WORK_ITEM
66 attr = CDispatch.dispatch_queue_attr_make_with_autorelease_frequency(attr, dispatch_autorelease_frequency_t(1))
67 } else if self.contains(.autoreleaseInherit) {
68 // DISPATCH_AUTORELEASE_FREQUENCY_INHERIT
69 attr = CDispatch.dispatch_queue_attr_make_with_autorelease_frequency(attr, dispatch_autorelease_frequency_t(0))
70 } else if self.contains(.autoreleaseNever) {
71 // DISPATCH_AUTORELEASE_FREQUENCY_NEVER
72 attr = CDispatch.dispatch_queue_attr_make_with_autorelease_frequency(attr, dispatch_autorelease_frequency_t(2))
75 if #available(OSX 10.10, iOS 8.0, *) {
76 if self.contains(.qosUserInteractive) {
77 attr = CDispatch.dispatch_queue_attr_make_with_qos_class(attr, _OSQoSClass.QOS_CLASS_USER_INTERACTIVE.rawValue, 0)
78 } else if self.contains(.qosUserInitiated) {
79 attr = CDispatch.dispatch_queue_attr_make_with_qos_class(attr, _OSQoSClass.QOS_CLASS_USER_INITIATED.rawValue, 0)
80 } else if self.contains(.qosDefault) {
81 attr = CDispatch.dispatch_queue_attr_make_with_qos_class(attr, _OSQoSClass.QOS_CLASS_DEFAULT.rawValue, 0)
82 } else if self.contains(.qosUtility) {
83 attr = CDispatch.dispatch_queue_attr_make_with_qos_class(attr, _OSQoSClass.QOS_CLASS_UTILITY.rawValue, 0)
84 } else if self.contains(.qosBackground) {
85 attr = CDispatch.dispatch_queue_attr_make_with_qos_class(attr, _OSQoSClass.QOS_CLASS_BACKGROUND.rawValue, 0)
93 public final class DispatchSpecificKey<T> {
97 internal class _DispatchSpecificValue<T> {
99 internal init(value: T) { self.value = value }
102 public extension DispatchQueue {
104 public struct GlobalAttributes : OptionSet {
105 public let rawValue: UInt64
106 public init(rawValue: UInt64) { self.rawValue = rawValue }
108 @available(OSX 10.10, iOS 8.0, *)
109 public static let qosUserInteractive = GlobalAttributes(rawValue: 1<<0)
111 @available(OSX 10.10, iOS 8.0, *)
112 public static let qosUserInitiated = GlobalAttributes(rawValue: 1<<1)
114 @available(OSX 10.10, iOS 8.0, *)
115 public static let qosDefault = GlobalAttributes(rawValue: 1<<2)
117 @available(OSX 10.10, iOS 8.0, *)
118 public static let qosUtility = GlobalAttributes(rawValue: 1<<3)
120 @available(OSX 10.10, iOS 8.0, *)
121 public static let qosBackground = GlobalAttributes(rawValue: 1<<4)
123 // Avoid using our own deprecated constants here by declaring
124 // non-deprecated constants and then basing the public ones on those.
125 internal static let _priorityHigh = GlobalAttributes(rawValue: 1<<5)
126 internal static let _priorityDefault = GlobalAttributes(rawValue: 1<<6)
127 internal static let _priorityLow = GlobalAttributes(rawValue: 1<<7)
128 internal static let _priorityBackground = GlobalAttributes(rawValue: 1<<8)
130 @available(OSX, deprecated: 10.10, message: "Use qos attributes instead")
131 @available(*, deprecated: 8.0, message: "Use qos attributes instead")
132 public static let priorityHigh = _priorityHigh
134 @available(OSX, deprecated: 10.10, message: "Use qos attributes instead")
135 @available(*, deprecated: 8.0, message: "Use qos attributes instead")
136 public static let priorityDefault = _priorityDefault
138 @available(OSX, deprecated: 10.10, message: "Use qos attributes instead")
139 @available(*, deprecated: 8.0, message: "Use qos attributes instead")
140 public static let priorityLow = _priorityLow
142 @available(OSX, deprecated: 10.10, message: "Use qos attributes instead")
143 @available(*, deprecated: 8.0, message: "Use qos attributes instead")
144 public static let priorityBackground = _priorityBackground
146 internal var _translatedValue: Int {
147 if #available(OSX 10.10, iOS 8.0, *) {
148 if self.contains(.qosUserInteractive) { return Int(_OSQoSClass.QOS_CLASS_USER_INTERACTIVE.rawValue) }
149 else if self.contains(.qosUserInitiated) { return Int(_OSQoSClass.QOS_CLASS_USER_INITIATED.rawValue) }
150 else if self.contains(.qosDefault) { return Int(_OSQoSClass.QOS_CLASS_DEFAULT.rawValue) }
151 else if self.contains(.qosUtility) { return Int(_OSQoSClass.QOS_CLASS_UTILITY.rawValue) }
152 else { return Int(_OSQoSClass.QOS_CLASS_BACKGROUND.rawValue) }
154 if self.contains(._priorityHigh) { return 2 } // DISPATCH_QUEUE_PRIORITY_HIGH
155 else if self.contains(._priorityDefault) { return 0 } // DISPATCH_QUEUE_PRIORITY_DEFAULT
156 else if self.contains(._priorityLow) { return -2 } // // DISPATCH_QUEUE_PRIORITY_LOW
157 else if self.contains(._priorityBackground) { return Int(Int16.min) } // // DISPATCH_QUEUE_PRIORITY_BACKGROUND
162 public class func concurrentPerform(iterations: Int, execute work: @noescape (Int) -> Void) {
163 _swift_dispatch_apply_current(iterations, work)
166 public class var main: DispatchQueue {
167 return DispatchQueue(queue: _swift_dispatch_get_main_queue())
170 public class func global(attributes: GlobalAttributes = []) -> DispatchQueue {
171 // SubOptimal? Should we be caching these global DispatchQueue objects?
172 return DispatchQueue(queue:dispatch_get_global_queue(attributes._translatedValue, 0))
175 public class func getSpecific<T>(key: DispatchSpecificKey<T>) -> T? {
176 let k = Unmanaged.passUnretained(key).toOpaque()
177 if let p = CDispatch.dispatch_get_specific(k) {
178 let v = Unmanaged<_DispatchSpecificValue<T>>
180 .takeUnretainedValue()
186 public convenience init(
188 attributes: DispatchQueueAttributes = .serial,
189 target: DispatchQueue? = nil)
191 if #available(OSX 10.12, iOS 10.0, tvOS 10.0, watchOS 3.0, *) {
192 self.init(__label: label, attr: attributes.attr, queue: target)
194 self.init(__label: label, attr: attributes.attr)
195 if let tq = target { self.setTarget(queue: tq) }
199 public var label: String {
200 return String(validatingUTF8: dispatch_queue_get_label(self.__wrapped))!
203 @available(OSX 10.10, iOS 8.0, *)
204 public func sync(execute workItem: DispatchWorkItem) {
205 dispatch_sync(self.__wrapped, workItem._block)
208 @available(OSX 10.10, iOS 8.0, *)
209 public func async(execute workItem: DispatchWorkItem) {
210 // _swift_dispatch_{group,}_async preserves the @convention(block)
211 // for work item blocks.
212 if let g = workItem._group {
213 dispatch_group_async(g.__wrapped, self.__wrapped, workItem._block)
215 dispatch_async(self.__wrapped, workItem._block)
219 public func async(group: DispatchGroup? = nil, qos: DispatchQoS = .unspecified, flags: DispatchWorkItemFlags = [], execute work: @convention(block) () -> Void) {
220 if group == nil && qos == .unspecified && flags.isEmpty {
221 // Fast-path route for the most common API usage
222 dispatch_async(self.__wrapped, work)
226 if #available(OSX 10.10, iOS 8.0, *), (qos != .unspecified || !flags.isEmpty) {
227 let workItem = DispatchWorkItem(qos: qos, flags: flags, block: work)
229 dispatch_group_async(g.__wrapped, self.__wrapped, workItem._block)
231 dispatch_async(self.__wrapped, workItem._block)
235 dispatch_group_async(g.__wrapped, self.__wrapped, work)
237 dispatch_async(self.__wrapped, work)
242 private func _syncBarrier(block: @noescape () -> ()) {
243 dispatch_barrier_sync(self.__wrapped, block)
246 private func _syncHelper<T>(
247 fn: (@noescape () -> ()) -> (),
248 execute work: @noescape () throws -> T,
249 rescue: ((Swift.Error) throws -> (T))) rethrows -> T
252 var error: Swift.Error?
267 @available(OSX 10.10, iOS 8.0, *)
268 private func _syncHelper<T>(
269 fn: (DispatchWorkItem) -> (),
270 flags: DispatchWorkItemFlags,
271 execute work: @noescape () throws -> T,
272 rescue: ((Swift.Error) throws -> (T))) rethrows -> T
275 var error: Swift.Error?
276 let workItem = DispatchWorkItem(flags: flags, noescapeBlock: {
291 public func sync<T>(execute work: @noescape () throws -> T) rethrows -> T {
292 return try self._syncHelper(fn: sync, execute: work, rescue: { throw $0 })
295 public func sync<T>(flags: DispatchWorkItemFlags, execute work: @noescape () throws -> T) rethrows -> T {
296 if flags == .barrier {
297 return try self._syncHelper(fn: _syncBarrier, execute: work, rescue: { throw $0 })
298 } else if #available(OSX 10.10, iOS 8.0, *), !flags.isEmpty {
299 return try self._syncHelper(fn: sync, flags: flags, execute: work, rescue: { throw $0 })
301 return try self._syncHelper(fn: sync, execute: work, rescue: { throw $0 })
305 public func after(when: DispatchTime, qos: DispatchQoS = .unspecified, flags: DispatchWorkItemFlags = [], execute work: @convention(block) () -> Void) {
306 if #available(OSX 10.10, iOS 8.0, *), qos != .unspecified || !flags.isEmpty {
307 let item = DispatchWorkItem(qos: qos, flags: flags, block: work)
308 dispatch_after(when.rawValue, self.__wrapped, item._block)
310 dispatch_after(when.rawValue, self.__wrapped, work)
314 @available(OSX 10.10, iOS 8.0, *)
315 public func after(when: DispatchTime, execute: DispatchWorkItem) {
316 dispatch_after(when.rawValue, self.__wrapped, execute._block)
319 public func after(walltime when: DispatchWallTime, qos: DispatchQoS = .unspecified, flags: DispatchWorkItemFlags = [], execute work: @convention(block) () -> Void) {
320 if #available(OSX 10.10, iOS 8.0, *), qos != .unspecified || !flags.isEmpty {
321 let item = DispatchWorkItem(qos: qos, flags: flags, block: work)
322 dispatch_after(when.rawValue, self.__wrapped, item._block)
324 dispatch_after(when.rawValue, self.__wrapped, work)
328 @available(OSX 10.10, iOS 8.0, *)
329 public func after(walltime when: DispatchWallTime, execute: DispatchWorkItem) {
330 dispatch_after(when.rawValue, self.__wrapped, execute._block)
333 @available(OSX 10.10, iOS 8.0, *)
334 public var qos: DispatchQoS {
335 var relPri: Int32 = 0
336 let cls = DispatchQoS.QoSClass(qosClass: _OSQoSClass(qosClass: dispatch_queue_get_qos_class(self.__wrapped, &relPri))!)!
337 return DispatchQoS(qosClass: cls, relativePriority: Int(relPri))
340 public func getSpecific<T>(key: DispatchSpecificKey<T>) -> T? {
341 let k = Unmanaged.passUnretained(key).toOpaque()
342 if let p = dispatch_queue_get_specific(self.__wrapped, k) {
343 let v = Unmanaged<_DispatchSpecificValue<T>>
345 .takeUnretainedValue()
351 public func setSpecific<T>(key: DispatchSpecificKey<T>, value: T) {
352 let v = _DispatchSpecificValue(value: value)
353 let k = Unmanaged.passUnretained(key).toOpaque()
354 let p = Unmanaged.passRetained(v).toOpaque()
355 dispatch_queue_set_specific(self.__wrapped, k, p, _destructDispatchSpecificValue)
359 extension DispatchQueue {
360 @available(*, deprecated, renamed: "DispatchQueue.sync(self:execute:)")
361 public func synchronously(execute work: @noescape () -> ()) {
365 @available(OSX, introduced: 10.10, deprecated: 10.12, renamed: "DispatchQueue.sync(self:execute:)")
366 @available(iOS, introduced: 8.0, deprecated: 10.0, renamed: "DispatchQueue.sync(self:execute:)")
367 @available(*, deprecated, renamed: "DispatchQueue.sync(self:execute:)")
368 public func synchronously(execute workItem: DispatchWorkItem) {
369 sync(execute: workItem)
372 @available(OSX, introduced: 10.10, deprecated: 10.12, renamed: "DispatchQueue.async(self:execute:)")
373 @available(iOS, introduced: 8.0, deprecated: 10.0, renamed: "DispatchQueue.async(self:execute:)")
374 @available(*, deprecated, renamed: "DispatchQueue.async(self:execute:)")
375 public func asynchronously(execute workItem: DispatchWorkItem) {
376 async(execute: workItem)
379 @available(*, deprecated, renamed: "DispatchQueue.async(self:group:qos:flags:execute:)")
380 public func asynchronously(group: DispatchGroup? = nil, qos: DispatchQoS = .unspecified, flags: DispatchWorkItemFlags = [], execute work: @convention(block) () -> Void) {
381 async(group: group, qos: qos, flags: flags, execute: work)
384 @available(*, deprecated, renamed: "DispatchQueue.sync(self:execute:)")
385 public func synchronously<T>(execute work: @noescape () throws -> T) rethrows -> T {
386 return try sync(execute: work)
389 @available(*, deprecated, renamed: "DispatchQueue.sync(self:flags:execute:)")
390 public func synchronously<T>(flags: DispatchWorkItemFlags, execute work: @noescape () throws -> T) rethrows -> T {
391 return try sync(flags: flags, execute: work)
394 @available(*, deprecated, renamed: "DispatchQueue.concurrentPerform(iterations:execute:)")
395 public func apply(applier iterations: Int, execute block: @noescape (Int) -> Void) {
396 DispatchQueue.concurrentPerform(iterations: iterations, execute: block)
399 @available(*, deprecated, renamed: "DispatchQueue.setTarget(self:queue:)")
400 public func setTargetQueue(queue: DispatchQueue) {
401 self.setTarget(queue: queue)
405 private func _destructDispatchSpecificValue(ptr: UnsafeMutablePointer<Void>?) {
407 Unmanaged<AnyObject>.fromOpaque(p).release()
411 @_silgen_name("_swift_dispatch_queue_concurrent")
412 internal func _swift_dispatch_queue_concurrent() -> dispatch_queue_attr_t
414 @_silgen_name("_swift_dispatch_get_main_queue")
415 internal func _swift_dispatch_get_main_queue() -> dispatch_queue_t
417 @_silgen_name("_swift_dispatch_apply_current_root_queue")
418 internal func _swift_dispatch_apply_current_root_queue() -> dispatch_queue_t
420 @_silgen_name("_swift_dispatch_apply_current")
421 internal func _swift_dispatch_apply_current(_ iterations: Int, _ block: @convention(block) @noescape (Int) -> Void)