This commit is contained in:
anlicheng 2026-05-08 10:28:44 +08:00
parent c63734960b
commit 37042fb3c1
2 changed files with 60 additions and 42 deletions

View File

@ -7,6 +7,7 @@ actor SDLPacketReaderService {
}
typealias EventHandler = @Sendable (Event) async -> Void
private typealias PacketReadResult = (packets: [Data], protocols: [NSNumber])?
private final class CancellationToken: @unchecked Sendable {
private let lock = NSLock()
@ -27,45 +28,6 @@ actor SDLPacketReaderService {
}
}
private final class PacketReadContinuation: @unchecked Sendable {
typealias Result = (packets: [Data], protocols: [NSNumber])?
private let lock = NSLock()
private var continuation: CheckedContinuation<Result, Never>?
private var finished: Bool = false
func set(_ continuation: CheckedContinuation<Result, Never>) {
lock.lock()
if finished {
lock.unlock()
continuation.resume(returning: nil)
return
}
self.continuation = continuation
lock.unlock()
}
func resume(returning result: Result) {
lock.lock()
guard !finished else {
lock.unlock()
return
}
finished = true
let continuation = self.continuation
self.continuation = nil
lock.unlock()
continuation?.resume(returning: result)
}
func cancel() {
resume(returning: nil)
}
}
private let provider: NEPacketTunnelProvider
private let onEvent: EventHandler
private var readTask: Task<Void, Never>?
@ -119,8 +81,8 @@ actor SDLPacketReaderService {
readTask?.cancel()
}
private static func readPackets(from provider: NEPacketTunnelProvider) async -> PacketReadContinuation.Result {
let readContinuation = PacketReadContinuation()
private static func readPackets(from provider: NEPacketTunnelProvider) async -> PacketReadResult {
let readContinuation = OnceContinuation<PacketReadResult, Never>()
return await withTaskCancellationHandler {
await withCheckedContinuation { continuation in
@ -130,7 +92,7 @@ actor SDLPacketReaderService {
}
}
} onCancel: {
readContinuation.cancel()
readContinuation.resume(returning: nil)
}
}
}

View File

@ -0,0 +1,56 @@
//
// OnceContinuation.swift
// Tun
//
// Created by Codex on 2026/5/7.
//
import Foundation
final class OnceContinuation<Value, Failure: Error>: @unchecked Sendable {
private let lock = NSLock()
private var continuation: CheckedContinuation<Value, Failure>?
private var result: Result<Value, Failure>?
func set(_ continuation: CheckedContinuation<Value, Failure>) {
lock.lock()
if let result {
lock.unlock()
continuation.resume(with: result)
return
}
let hasPendingContinuation = self.continuation != nil
if !hasPendingContinuation {
self.continuation = continuation
}
lock.unlock()
if hasPendingContinuation {
preconditionFailure("OnceContinuation can only store one pending continuation")
}
}
func resume(returning value: Value) {
resume(with: .success(value))
}
func resume(throwing error: Failure) {
resume(with: .failure(error))
}
func resume(with result: Result<Value, Failure>) {
lock.lock()
guard self.result == nil else {
lock.unlock()
return
}
self.result = result
let continuation = self.continuation
self.continuation = nil
lock.unlock()
continuation?.resume(with: result)
}
}