Skip to content

Commit d334990

Browse files
committed
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.
1 parent ae71a91 commit d334990

File tree

3 files changed

+49
-29
lines changed

3 files changed

+49
-29
lines changed

src/swift/Data.swift

Lines changed: 28 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,6 @@ public struct DispatchData : RandomAccessCollection {
1919

2020
public static let empty: DispatchData = DispatchData(data: _swift_dispatch_data_empty())
2121

22-
#if false /* FIXME: dragging in _TMBO (Objective-C) */
2322
public enum Deallocator {
2423
/// Use `free`
2524
case free
@@ -28,7 +27,13 @@ public struct DispatchData : RandomAccessCollection {
2827
case unmap
2928

3029
/// A custom deallocator
31-
case custom(DispatchQueue?, @convention(block) () -> Void)
30+
// FIXME: Want @convention(block) here to minimize the overhead of
31+
// doing the conversion (once per custom enum instance instead
32+
// of once per call to DispatchData.init using the enum instance).
33+
// However, adding the annotation here results in Data.o containing
34+
// a reference to _TMBO (opaque metadata for Builtin.UnknownObject)
35+
// which is only made available on platforms with Objective-C.
36+
case custom(DispatchQueue?, () -> Void)
3237

3338
private var _deallocator: (DispatchQueue?, @convention(block) () -> Void) {
3439
switch self {
@@ -38,51 +43,50 @@ public struct DispatchData : RandomAccessCollection {
3843
}
3944
}
4045
}
41-
#endif
42-
internal var __wrapped: dispatch_data_t
46+
47+
internal var __wrapped: __DispatchData
4348

4449
/// Initialize a `Data` with copied memory content.
4550
///
4651
/// - parameter bytes: A pointer to the memory. It will be copied.
4752
/// - parameter count: The number of bytes to copy.
4853
public init(bytes buffer: UnsafeBufferPointer<UInt8>) {
49-
__wrapped = dispatch_data_create(
50-
buffer.baseAddress!, buffer.count, nil, _dispatch_data_destructor_default())
54+
let d = dispatch_data_create(buffer.baseAddress!, buffer.count, nil, _dispatch_data_destructor_default())
55+
self.init(data: d)
5156
}
52-
#if false /* FIXME: dragging in _TMBO (Objective-C) */
57+
5358
/// Initialize a `Data` without copying the bytes.
5459
///
55-
/// - parameter bytes: A pointer to the bytes.
56-
/// - parameter count: The size of the bytes.
60+
/// - parameter bytes: A buffer pointer containing the data.
5761
/// - parameter deallocator: Specifies the mechanism to free the indicated buffer.
5862
public init(bytesNoCopy bytes: UnsafeBufferPointer<UInt8>, deallocator: Deallocator = .free) {
5963
let (q, b) = deallocator._deallocator
60-
61-
__wrapped = dispatch_data_create(bytes.baseAddress!, bytes.count, q?.__wrapped, b)
64+
let d = dispatch_data_create(bytes.baseAddress!, bytes.count, q?.__wrapped, b)
65+
self.init(data: d)
6266
}
63-
#endif
67+
6468
internal init(data: dispatch_data_t) {
65-
__wrapped = data
69+
__wrapped = __DispatchData(data: data)
6670
}
6771

6872
public var count: Int {
69-
return CDispatch.dispatch_data_get_size(__wrapped)
73+
return CDispatch.dispatch_data_get_size(__wrapped.__wrapped)
7074
}
7175

7276
public func withUnsafeBytes<Result, ContentType>(
7377
body: @noescape (UnsafePointer<ContentType>) throws -> Result) rethrows -> Result
7478
{
7579
var ptr: UnsafePointer<Void>? = nil
7680
var size = 0;
77-
let data = CDispatch.dispatch_data_create_map(__wrapped, &ptr, &size)
81+
let data = CDispatch.dispatch_data_create_map(__wrapped.__wrapped, &ptr, &size)
7882
defer { _fixLifetime(data) }
7983
return try body(UnsafePointer<ContentType>(ptr!))
8084
}
8185

8286
public func enumerateBytes(
8387
block: @noescape (buffer: UnsafeBufferPointer<UInt8>, byteIndex: Int, stop: inout Bool) -> Void)
8488
{
85-
_swift_dispatch_data_apply(__wrapped) { (data: dispatch_data_t, offset: Int, ptr: UnsafePointer<Void>, size: Int) in
89+
_swift_dispatch_data_apply(__wrapped.__wrapped) { (data: dispatch_data_t, offset: Int, ptr: UnsafePointer<Void>, size: Int) in
8690
let bp = UnsafeBufferPointer(start: UnsafePointer<UInt8>(ptr), count: size)
8791
var stop = false
8892
block(buffer: bp, byteIndex: offset, stop: &stop)
@@ -103,8 +107,8 @@ public struct DispatchData : RandomAccessCollection {
103107
///
104108
/// - parameter data: The data to append to this data.
105109
public mutating func append(_ other: DispatchData) {
106-
let data = CDispatch.dispatch_data_create_concat(__wrapped, other.__wrapped)
107-
__wrapped = data
110+
let data = CDispatch.dispatch_data_create_concat(__wrapped.__wrapped, other.__wrapped.__wrapped)
111+
__wrapped = __DispatchData(data: data)
108112
}
109113

110114
/// Append a buffer of bytes to the data.
@@ -116,7 +120,7 @@ public struct DispatchData : RandomAccessCollection {
116120

117121
private func _copyBytesHelper(to pointer: UnsafeMutablePointer<UInt8>, from range: CountableRange<Index>) {
118122
var copiedCount = 0
119-
_ = CDispatch.dispatch_data_apply(__wrapped) { (data: dispatch_data_t, offset: Int, ptr: UnsafePointer<Void>, size: Int) in
123+
_ = CDispatch.dispatch_data_apply(__wrapped.__wrapped) { (data: dispatch_data_t, offset: Int, ptr: UnsafePointer<Void>, size: Int) in
120124
let limit = Swift.min((range.endIndex - range.startIndex) - copiedCount, size)
121125
memcpy(pointer + copiedCount, ptr, limit)
122126
copiedCount += limit
@@ -177,7 +181,7 @@ public struct DispatchData : RandomAccessCollection {
177181
/// Sets or returns the byte at the specified index.
178182
public subscript(index: Index) -> UInt8 {
179183
var offset = 0
180-
let subdata = CDispatch.dispatch_data_copy_region(__wrapped, index, &offset)
184+
let subdata = CDispatch.dispatch_data_copy_region(__wrapped.__wrapped, index, &offset)
181185

182186
var ptr: UnsafePointer<Void>? = nil
183187
var size = 0
@@ -197,13 +201,13 @@ public struct DispatchData : RandomAccessCollection {
197201
/// - parameter range: The range to copy.
198202
public func subdata(in range: CountableRange<Index>) -> DispatchData {
199203
let subrange = CDispatch.dispatch_data_create_subrange(
200-
__wrapped, range.startIndex, range.endIndex - range.startIndex)
204+
__wrapped.__wrapped, range.startIndex, range.endIndex - range.startIndex)
201205
return DispatchData(data: subrange)
202206
}
203207

204208
public func region(location: Int) -> (data: DispatchData, offset: Int) {
205209
var offset: Int = 0
206-
let data = CDispatch.dispatch_data_copy_region(__wrapped, location, &offset)
210+
let data = CDispatch.dispatch_data_copy_region(__wrapped.__wrapped, location, &offset)
207211
return (DispatchData(data: data), offset)
208212
}
209213

@@ -237,7 +241,7 @@ public struct DispatchDataIterator : IteratorProtocol, Sequence {
237241
public init(_data: DispatchData) {
238242
var ptr: UnsafePointer<Void>?
239243
self._count = 0
240-
self._data = CDispatch.dispatch_data_create_map(_data.__wrapped, &ptr, &self._count)
244+
self._data = __DispatchData(data: CDispatch.dispatch_data_create_map(_data.__wrapped.__wrapped, &ptr, &self._count))
241245
self._ptr = UnsafePointer(ptr)
242246
self._position = _data.startIndex
243247

@@ -254,7 +258,7 @@ public struct DispatchDataIterator : IteratorProtocol, Sequence {
254258
return element
255259
}
256260

257-
internal let _data: dispatch_data_t
261+
internal let _data: __DispatchData
258262
internal var _ptr: UnsafePointer<UInt8>!
259263
internal var _count: Int
260264
internal var _position: DispatchData.Index

src/swift/IO.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ public extension DispatchIO {
4141
}
4242

4343
public class func write(fromFileDescriptor: Int32, data: DispatchData, runningHandlerOn queue: DispatchQueue, handler: (data: DispatchData?, error: Int32) -> Void) {
44-
dispatch_write(fromFileDescriptor, data.__wrapped, queue.__wrapped) { (data: dispatch_data_t?, error: Int32) in
44+
dispatch_write(fromFileDescriptor, data.__wrapped.__wrapped, queue.__wrapped) { (data: dispatch_data_t?, error: Int32) in
4545
handler(data: data.flatMap { DispatchData(data: $0) }, error: error)
4646
}
4747
}
@@ -82,7 +82,7 @@ public extension DispatchIO {
8282
}
8383

8484
public func write(offset: off_t, data: DispatchData, queue: DispatchQueue, ioHandler: (done: Bool, data: DispatchData?, error: Int32) -> Void) {
85-
dispatch_io_write(self.__wrapped, offset, data.__wrapped, queue.__wrapped) { (done: Bool, data: dispatch_data_t?, error: Int32) in
85+
dispatch_io_write(self.__wrapped, offset, data.__wrapped.__wrapped, queue.__wrapped) { (done: Bool, data: dispatch_data_t?, error: Int32) in
8686
ioHandler(done: done, data: data.flatMap { DispatchData(data: $0) }, error: error)
8787
}
8888
}

src/swift/Wrapper.swift

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -186,6 +186,22 @@ extension DispatchSource : DispatchSourceProcess,
186186
}
187187
#endif
188188

189+
internal class __DispatchData : DispatchObject {
190+
internal let __wrapped:dispatch_data_t
191+
192+
final internal override func wrapped() -> dispatch_object_t {
193+
return unsafeBitCast(__wrapped, to: dispatch_object_t.self)
194+
}
195+
196+
internal init(data:dispatch_data_t) {
197+
__wrapped = data
198+
}
199+
200+
deinit {
201+
_swift_dispatch_release(wrapped())
202+
}
203+
}
204+
189205
public typealias DispatchSourceHandler = @convention(block) () -> Void
190206

191207
public protocol DispatchSourceType {
@@ -307,9 +323,9 @@ internal enum _OSQoSClass : UInt32 {
307323
case 0x21: self = .QOS_CLASS_USER_INTERACTIVE
308324
case 0x19: self = .QOS_CLASS_USER_INITIATED
309325
case 0x15: self = .QOS_CLASS_DEFAULT
310-
case 0x11: self = QOS_CLASS_UTILITY
311-
case 0x09: self = QOS_CLASS_BACKGROUND
312-
case 0x00: self = QOS_CLASS_UNSPECIFIED
326+
case 0x11: self = .QOS_CLASS_UTILITY
327+
case 0x09: self = .QOS_CLASS_BACKGROUND
328+
case 0x00: self = .QOS_CLASS_UNSPECIFIED
313329
default: return nil
314330
}
315331
}

0 commit comments

Comments
 (0)