Skip to content

Commit 3c1aae4

Browse files
authored
Reduce unstructured task (#12)
* Reduce unstructured Task usage Motivation: Feedback from @FranzBusch Modification: Use lock instead of actor to control access to `ares_channel`. * Handle task cancellation
1 parent 5e70cd7 commit 3c1aae4

File tree

3 files changed

+39
-29
lines changed

3 files changed

+39
-29
lines changed

Sources/AsyncDNSResolver/c-ares/AresChannel.swift

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -13,22 +13,22 @@
1313
//===----------------------------------------------------------------------===//
1414

1515
import CAsyncDNSResolver
16+
import Foundation
1617

1718
// MARK: - ares_channel
1819

19-
actor AresChannel {
20+
class AresChannel {
2021
let pointer: UnsafeMutablePointer<ares_channel?>
22+
let lock = NSLock()
2123

2224
private var underlying: ares_channel? {
2325
self.pointer.pointee
2426
}
2527

2628
deinit {
27-
Task { [pointer] in
28-
ares_destroy(pointer.pointee)
29-
pointer.deallocate()
30-
ares_library_cleanup()
31-
}
29+
ares_destroy(pointer.pointee)
30+
pointer.deallocate()
31+
ares_library_cleanup()
3232
}
3333

3434
init(options: AresOptions) throws {
@@ -52,6 +52,9 @@ actor AresChannel {
5252
}
5353

5454
func withChannel(_ body: (ares_channel) -> Void) {
55+
self.lock.lock()
56+
defer { self.lock.unlock() }
57+
5558
guard let underlying = self.underlying else {
5659
fatalError("ares_channel not initialized")
5760
}

Sources/AsyncDNSResolver/c-ares/DNSResolver_c-ares.swift

Lines changed: 29 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -141,33 +141,40 @@ class Ares {
141141
name: String,
142142
replyParser: ReplyParser
143143
) async throws -> ReplyParser.Reply {
144-
try await withCheckedThrowingContinuation { continuation in
145-
let handler = QueryReplyHandler(parser: replyParser, continuation)
144+
try await withTaskCancellationHandler(
145+
operation: {
146+
try await withCheckedThrowingContinuation { continuation in
147+
let handler = QueryReplyHandler(parser: replyParser, continuation)
148+
149+
// Wrap `handler` into a pointer so we can pass it to callback. The pointer will be deallocated in there later.
150+
let handlerPointer = UnsafeMutableRawPointer.allocate(
151+
byteCount: MemoryLayout<QueryReplyHandler>.stride,
152+
alignment: MemoryLayout<QueryReplyHandler>.alignment
153+
)
154+
handlerPointer.initializeMemory(as: QueryReplyHandler.self, repeating: handler, count: 1)
146155

147-
// Wrap `handler` into a pointer so we can pass it to callback. The pointer will be deallocated in there later.
148-
let handlerPointer = UnsafeMutableRawPointer.allocate(
149-
byteCount: MemoryLayout<QueryReplyHandler>.stride,
150-
alignment: MemoryLayout<QueryReplyHandler>.alignment
151-
)
152-
handlerPointer.initializeMemory(as: QueryReplyHandler.self, repeating: handler, count: 1)
156+
let queryCallback: QueryCallback = { arg, status, _, buf, len in
157+
guard let handlerPointer = arg else {
158+
preconditionFailure("'arg' is nil. This is a bug.")
159+
}
153160

154-
let queryCallback: QueryCallback = { arg, status, _, buf, len in
155-
guard let handlerPointer = arg else {
156-
preconditionFailure("'arg' is nil. This is a bug.")
157-
}
161+
let handler = QueryReplyHandler(pointer: handlerPointer)
162+
defer { handlerPointer.deallocate() }
158163

159-
let handler = QueryReplyHandler(pointer: handlerPointer)
160-
defer { handlerPointer.deallocate() }
161-
162-
handler.handle(status: status, buffer: buf, length: len)
163-
}
164+
handler.handle(status: status, buffer: buf, length: len)
165+
}
164166

165-
Task {
166-
await self.channel.withChannel { channel in
167-
ares_query(channel, name, DNSClass.IN.rawValue, type.intValue, queryCallback, handlerPointer)
167+
self.channel.withChannel { channel in
168+
ares_query(channel, name, DNSClass.IN.rawValue, type.intValue, queryCallback, handlerPointer)
169+
}
170+
}
171+
},
172+
onCancel: {
173+
self.channel.withChannel { channel in
174+
ares_cancel(channel)
168175
}
169176
}
170-
}
177+
)
171178
}
172179

173180
/// See `arpa/nameser.h`.
@@ -199,7 +206,7 @@ extension Ares {
199206
func poll() async {
200207
var socks = [ares_socket_t](repeating: ares_socket_t(), count: Int(ARES_GETSOCK_MAXNUM))
201208

202-
await self.channel.withChannel { channel in
209+
self.channel.withChannel { channel in
203210
// Indicates what actions (i.e., read/write) to wait for on the different sockets
204211
let bitmask = UInt32(ares_getsock(channel, &socks, ARES_GETSOCK_MAXNUM))
205212

Tests/AsyncDNSResolverTests/c-ares/AresChannelTests.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ final class AresChannelTests: XCTestCase {
2828
guard let channel = try? AresChannel(options: options) else {
2929
return XCTFail("Channel not initialized")
3030
}
31-
guard let _ = await channel.pointer.pointee else {
31+
guard let _ = channel.pointer.pointee else {
3232
return XCTFail("Underlying ares_channel is nil")
3333
}
3434
}

0 commit comments

Comments
 (0)