From d334990f7a91254ce23d8bda3498db9f385928a6 Mon Sep 17 00:00:00 2001 From: David Grove Date: Fri, 15 Jul 2016 16:46:42 -0400 Subject: [PATCH] deallocation support for DispatchData on Linux Deallocation / reference counting support for DispatchData in the wrapping overlay consisting of two main pieces. First, since DispatchData is a struct and dispatch_data_t is a COpaquePointer, we need an intermediate class __DispatchData on which to perform the reference counting operations to enable the backing _dispatch_data_t to be deallocated when they are no longer reachable. I overlooked the mapping of _dispatch_data_t to OS_dispatch_data in Dispatch.apinotes in my initial pull request for the wrapping overlay and as a result all the dispatch_data_t instances were not being reference counted. Second, enable the DispatchData.Deallocator portion of the API. After some experimentation, found a way to have the desired API without getting a reference to _TMBO in the generated code. Left a FIXME because the current approach is sub-optimal in where it converts from Swift blocks to @convention(block) blocks. --- src/swift/Data.swift | 52 ++++++++++++++++++++++------------------- src/swift/IO.swift | 4 ++-- src/swift/Wrapper.swift | 22 ++++++++++++++--- 3 files changed, 49 insertions(+), 29 deletions(-) diff --git a/src/swift/Data.swift b/src/swift/Data.swift index ebec5e5a4..9d68ad3ad 100644 --- a/src/swift/Data.swift +++ b/src/swift/Data.swift @@ -19,7 +19,6 @@ public struct DispatchData : RandomAccessCollection { public static let empty: DispatchData = DispatchData(data: _swift_dispatch_data_empty()) -#if false /* FIXME: dragging in _TMBO (Objective-C) */ public enum Deallocator { /// Use `free` case free @@ -28,7 +27,13 @@ public struct DispatchData : RandomAccessCollection { case unmap /// A custom deallocator - case custom(DispatchQueue?, @convention(block) () -> Void) + // FIXME: Want @convention(block) here to minimize the overhead of + // doing the conversion (once per custom enum instance instead + // of once per call to DispatchData.init using the enum instance). + // However, adding the annotation here results in Data.o containing + // a reference to _TMBO (opaque metadata for Builtin.UnknownObject) + // which is only made available on platforms with Objective-C. + case custom(DispatchQueue?, () -> Void) private var _deallocator: (DispatchQueue?, @convention(block) () -> Void) { switch self { @@ -38,35 +43,34 @@ public struct DispatchData : RandomAccessCollection { } } } -#endif - internal var __wrapped: dispatch_data_t + + internal var __wrapped: __DispatchData /// Initialize a `Data` with copied memory content. /// /// - parameter bytes: A pointer to the memory. It will be copied. /// - parameter count: The number of bytes to copy. public init(bytes buffer: UnsafeBufferPointer) { - __wrapped = dispatch_data_create( - buffer.baseAddress!, buffer.count, nil, _dispatch_data_destructor_default()) + let d = dispatch_data_create(buffer.baseAddress!, buffer.count, nil, _dispatch_data_destructor_default()) + self.init(data: d) } -#if false /* FIXME: dragging in _TMBO (Objective-C) */ + /// Initialize a `Data` without copying the bytes. /// - /// - parameter bytes: A pointer to the bytes. - /// - parameter count: The size of the bytes. + /// - parameter bytes: A buffer pointer containing the data. /// - parameter deallocator: Specifies the mechanism to free the indicated buffer. public init(bytesNoCopy bytes: UnsafeBufferPointer, deallocator: Deallocator = .free) { let (q, b) = deallocator._deallocator - - __wrapped = dispatch_data_create(bytes.baseAddress!, bytes.count, q?.__wrapped, b) + let d = dispatch_data_create(bytes.baseAddress!, bytes.count, q?.__wrapped, b) + self.init(data: d) } -#endif + internal init(data: dispatch_data_t) { - __wrapped = data + __wrapped = __DispatchData(data: data) } public var count: Int { - return CDispatch.dispatch_data_get_size(__wrapped) + return CDispatch.dispatch_data_get_size(__wrapped.__wrapped) } public func withUnsafeBytes( @@ -74,7 +78,7 @@ public struct DispatchData : RandomAccessCollection { { var ptr: UnsafePointer? = nil var size = 0; - let data = CDispatch.dispatch_data_create_map(__wrapped, &ptr, &size) + let data = CDispatch.dispatch_data_create_map(__wrapped.__wrapped, &ptr, &size) defer { _fixLifetime(data) } return try body(UnsafePointer(ptr!)) } @@ -82,7 +86,7 @@ public struct DispatchData : RandomAccessCollection { public func enumerateBytes( block: @noescape (buffer: UnsafeBufferPointer, byteIndex: Int, stop: inout Bool) -> Void) { - _swift_dispatch_data_apply(__wrapped) { (data: dispatch_data_t, offset: Int, ptr: UnsafePointer, size: Int) in + _swift_dispatch_data_apply(__wrapped.__wrapped) { (data: dispatch_data_t, offset: Int, ptr: UnsafePointer, size: Int) in let bp = UnsafeBufferPointer(start: UnsafePointer(ptr), count: size) var stop = false block(buffer: bp, byteIndex: offset, stop: &stop) @@ -103,8 +107,8 @@ public struct DispatchData : RandomAccessCollection { /// /// - parameter data: The data to append to this data. public mutating func append(_ other: DispatchData) { - let data = CDispatch.dispatch_data_create_concat(__wrapped, other.__wrapped) - __wrapped = data + let data = CDispatch.dispatch_data_create_concat(__wrapped.__wrapped, other.__wrapped.__wrapped) + __wrapped = __DispatchData(data: data) } /// Append a buffer of bytes to the data. @@ -116,7 +120,7 @@ public struct DispatchData : RandomAccessCollection { private func _copyBytesHelper(to pointer: UnsafeMutablePointer, from range: CountableRange) { var copiedCount = 0 - _ = CDispatch.dispatch_data_apply(__wrapped) { (data: dispatch_data_t, offset: Int, ptr: UnsafePointer, size: Int) in + _ = CDispatch.dispatch_data_apply(__wrapped.__wrapped) { (data: dispatch_data_t, offset: Int, ptr: UnsafePointer, size: Int) in let limit = Swift.min((range.endIndex - range.startIndex) - copiedCount, size) memcpy(pointer + copiedCount, ptr, limit) copiedCount += limit @@ -177,7 +181,7 @@ public struct DispatchData : RandomAccessCollection { /// Sets or returns the byte at the specified index. public subscript(index: Index) -> UInt8 { var offset = 0 - let subdata = CDispatch.dispatch_data_copy_region(__wrapped, index, &offset) + let subdata = CDispatch.dispatch_data_copy_region(__wrapped.__wrapped, index, &offset) var ptr: UnsafePointer? = nil var size = 0 @@ -197,13 +201,13 @@ public struct DispatchData : RandomAccessCollection { /// - parameter range: The range to copy. public func subdata(in range: CountableRange) -> DispatchData { let subrange = CDispatch.dispatch_data_create_subrange( - __wrapped, range.startIndex, range.endIndex - range.startIndex) + __wrapped.__wrapped, range.startIndex, range.endIndex - range.startIndex) return DispatchData(data: subrange) } public func region(location: Int) -> (data: DispatchData, offset: Int) { var offset: Int = 0 - let data = CDispatch.dispatch_data_copy_region(__wrapped, location, &offset) + let data = CDispatch.dispatch_data_copy_region(__wrapped.__wrapped, location, &offset) return (DispatchData(data: data), offset) } @@ -237,7 +241,7 @@ public struct DispatchDataIterator : IteratorProtocol, Sequence { public init(_data: DispatchData) { var ptr: UnsafePointer? self._count = 0 - self._data = CDispatch.dispatch_data_create_map(_data.__wrapped, &ptr, &self._count) + self._data = __DispatchData(data: CDispatch.dispatch_data_create_map(_data.__wrapped.__wrapped, &ptr, &self._count)) self._ptr = UnsafePointer(ptr) self._position = _data.startIndex @@ -254,7 +258,7 @@ public struct DispatchDataIterator : IteratorProtocol, Sequence { return element } - internal let _data: dispatch_data_t + internal let _data: __DispatchData internal var _ptr: UnsafePointer! internal var _count: Int internal var _position: DispatchData.Index diff --git a/src/swift/IO.swift b/src/swift/IO.swift index 6e6b6692e..1b8d7b006 100644 --- a/src/swift/IO.swift +++ b/src/swift/IO.swift @@ -41,7 +41,7 @@ public extension DispatchIO { } public class func write(fromFileDescriptor: Int32, data: DispatchData, runningHandlerOn queue: DispatchQueue, handler: (data: DispatchData?, error: Int32) -> Void) { - dispatch_write(fromFileDescriptor, data.__wrapped, queue.__wrapped) { (data: dispatch_data_t?, error: Int32) in + dispatch_write(fromFileDescriptor, data.__wrapped.__wrapped, queue.__wrapped) { (data: dispatch_data_t?, error: Int32) in handler(data: data.flatMap { DispatchData(data: $0) }, error: error) } } @@ -82,7 +82,7 @@ public extension DispatchIO { } public func write(offset: off_t, data: DispatchData, queue: DispatchQueue, ioHandler: (done: Bool, data: DispatchData?, error: Int32) -> Void) { - dispatch_io_write(self.__wrapped, offset, data.__wrapped, queue.__wrapped) { (done: Bool, data: dispatch_data_t?, error: Int32) in + dispatch_io_write(self.__wrapped, offset, data.__wrapped.__wrapped, queue.__wrapped) { (done: Bool, data: dispatch_data_t?, error: Int32) in ioHandler(done: done, data: data.flatMap { DispatchData(data: $0) }, error: error) } } diff --git a/src/swift/Wrapper.swift b/src/swift/Wrapper.swift index ef7bf30d9..39c3cda35 100644 --- a/src/swift/Wrapper.swift +++ b/src/swift/Wrapper.swift @@ -186,6 +186,22 @@ extension DispatchSource : DispatchSourceProcess, } #endif +internal class __DispatchData : DispatchObject { + internal let __wrapped:dispatch_data_t + + final internal override func wrapped() -> dispatch_object_t { + return unsafeBitCast(__wrapped, to: dispatch_object_t.self) + } + + internal init(data:dispatch_data_t) { + __wrapped = data + } + + deinit { + _swift_dispatch_release(wrapped()) + } +} + public typealias DispatchSourceHandler = @convention(block) () -> Void public protocol DispatchSourceType { @@ -307,9 +323,9 @@ internal enum _OSQoSClass : UInt32 { case 0x21: self = .QOS_CLASS_USER_INTERACTIVE case 0x19: self = .QOS_CLASS_USER_INITIATED case 0x15: self = .QOS_CLASS_DEFAULT - case 0x11: self = QOS_CLASS_UTILITY - case 0x09: self = QOS_CLASS_BACKGROUND - case 0x00: self = QOS_CLASS_UNSPECIFIED + case 0x11: self = .QOS_CLASS_UTILITY + case 0x09: self = .QOS_CLASS_BACKGROUND + case 0x00: self = .QOS_CLASS_UNSPECIFIED default: return nil } }