From 37042fb3c196f02b36cd110fad8a581dfc627f49 Mon Sep 17 00:00:00 2001 From: anlicheng <244108715@qq.com> Date: Fri, 8 May 2026 10:28:44 +0800 Subject: [PATCH] fix --- .../Context/SDLPacketReaderService.swift | 46 ++------------- Tun/Punchnet/OnceContinuation.swift | 56 +++++++++++++++++++ 2 files changed, 60 insertions(+), 42 deletions(-) create mode 100644 Tun/Punchnet/OnceContinuation.swift diff --git a/Tun/Punchnet/Context/SDLPacketReaderService.swift b/Tun/Punchnet/Context/SDLPacketReaderService.swift index 50a4b9c..e09c215 100644 --- a/Tun/Punchnet/Context/SDLPacketReaderService.swift +++ b/Tun/Punchnet/Context/SDLPacketReaderService.swift @@ -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? - private var finished: Bool = false - - func set(_ continuation: CheckedContinuation) { - 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? @@ -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() return await withTaskCancellationHandler { await withCheckedContinuation { continuation in @@ -130,7 +92,7 @@ actor SDLPacketReaderService { } } } onCancel: { - readContinuation.cancel() + readContinuation.resume(returning: nil) } } } diff --git a/Tun/Punchnet/OnceContinuation.swift b/Tun/Punchnet/OnceContinuation.swift new file mode 100644 index 0000000..51d42b3 --- /dev/null +++ b/Tun/Punchnet/OnceContinuation.swift @@ -0,0 +1,56 @@ +// +// OnceContinuation.swift +// Tun +// +// Created by Codex on 2026/5/7. +// + +import Foundation + +final class OnceContinuation: @unchecked Sendable { + private let lock = NSLock() + private var continuation: CheckedContinuation? + private var result: Result? + + func set(_ continuation: CheckedContinuation) { + 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) { + 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) + } +}