chore: import upstream snapshot with attribution
This commit is contained in:
@@ -0,0 +1,130 @@
|
||||
import Foundation
|
||||
|
||||
/// Cost-usage scans read and parse the full local session corpus synchronously and can run for
|
||||
/// minutes on large archives. Executing that work inline on Swift's cooperative thread pool
|
||||
/// starves every other async task in the process — menus freeze while the main thread sits idle —
|
||||
/// and overlapping provider scans multiply both the pool pressure and the disk load. This
|
||||
/// executor pins all corpus scans to a single serial utility queue off the cooperative pool, so
|
||||
/// long scans cost one dedicated thread instead of the app's async runtime.
|
||||
public enum CostUsageScanExecutor {
|
||||
public static let queueLabel = "com.steipete.codexbar.cost-usage-scan"
|
||||
|
||||
private static let queue = DispatchQueue(label: queueLabel, qos: .utility)
|
||||
|
||||
private final class RunState<Value: Sendable>: @unchecked Sendable {
|
||||
private enum Phase {
|
||||
case initial
|
||||
case queued
|
||||
case running
|
||||
case completed
|
||||
}
|
||||
|
||||
private let lock = NSLock()
|
||||
private var phase: Phase = .initial
|
||||
private var cancellationRequested = false
|
||||
private var continuation: CheckedContinuation<Value, Error>?
|
||||
|
||||
func install(_ continuation: CheckedContinuation<Value, Error>) -> Bool {
|
||||
let shouldEnqueue: Bool
|
||||
let shouldResumeCancellation: Bool
|
||||
self.lock.lock()
|
||||
if self.cancellationRequested {
|
||||
self.phase = .completed
|
||||
shouldEnqueue = false
|
||||
shouldResumeCancellation = true
|
||||
} else {
|
||||
self.phase = .queued
|
||||
self.continuation = continuation
|
||||
shouldEnqueue = true
|
||||
shouldResumeCancellation = false
|
||||
}
|
||||
self.lock.unlock()
|
||||
|
||||
if shouldResumeCancellation {
|
||||
continuation.resume(throwing: CancellationError())
|
||||
}
|
||||
return shouldEnqueue
|
||||
}
|
||||
|
||||
func begin() -> Bool {
|
||||
self.lock.lock()
|
||||
defer { self.lock.unlock() }
|
||||
guard self.phase == .queued else { return false }
|
||||
self.phase = .running
|
||||
return true
|
||||
}
|
||||
|
||||
func cancel() {
|
||||
let continuation: CheckedContinuation<Value, Error>?
|
||||
self.lock.lock()
|
||||
self.cancellationRequested = true
|
||||
if self.phase == .queued {
|
||||
self.phase = .completed
|
||||
continuation = self.continuation
|
||||
self.continuation = nil
|
||||
} else {
|
||||
continuation = nil
|
||||
}
|
||||
self.lock.unlock()
|
||||
continuation?.resume(throwing: CancellationError())
|
||||
}
|
||||
|
||||
func checkCancellation() throws {
|
||||
self.lock.lock()
|
||||
let cancellationRequested = self.cancellationRequested
|
||||
self.lock.unlock()
|
||||
if cancellationRequested {
|
||||
throw CancellationError()
|
||||
}
|
||||
}
|
||||
|
||||
func complete(with result: Result<Value, Error>) {
|
||||
let continuation: CheckedContinuation<Value, Error>?
|
||||
let resolvedResult: Result<Value, Error>
|
||||
self.lock.lock()
|
||||
guard self.phase == .running else {
|
||||
self.lock.unlock()
|
||||
return
|
||||
}
|
||||
self.phase = .completed
|
||||
continuation = self.continuation
|
||||
self.continuation = nil
|
||||
resolvedResult = self.cancellationRequested ? .failure(CancellationError()) : result
|
||||
self.lock.unlock()
|
||||
continuation?.resume(with: resolvedResult)
|
||||
}
|
||||
}
|
||||
|
||||
/// Runs `work` on the serial scan queue and bridges Swift task cancellation into the
|
||||
/// scanner's cooperative `checkCancellation` callbacks. Work that is still queued when the
|
||||
/// awaiting task is cancelled resumes immediately with `CancellationError` instead of
|
||||
/// waiting behind an in-flight scan.
|
||||
public static func run<T: Sendable>(
|
||||
_ work: @escaping @Sendable (_ checkCancellation: @escaping @Sendable () throws -> Void) throws -> T)
|
||||
async throws -> T
|
||||
{
|
||||
try await self.run(on: self.queue, work)
|
||||
}
|
||||
|
||||
static func run<T: Sendable>(
|
||||
on queue: DispatchQueue,
|
||||
_ work: @escaping @Sendable (_ checkCancellation: @escaping @Sendable () throws -> Void) throws -> T)
|
||||
async throws -> T
|
||||
{
|
||||
let state = RunState<T>()
|
||||
let checkCancellation: @Sendable () throws -> Void = {
|
||||
try state.checkCancellation()
|
||||
}
|
||||
return try await withTaskCancellationHandler {
|
||||
try await withCheckedThrowingContinuation { continuation in
|
||||
guard state.install(continuation) else { return }
|
||||
queue.async {
|
||||
guard state.begin() else { return }
|
||||
state.complete(with: Result { try work(checkCancellation) })
|
||||
}
|
||||
}
|
||||
} onCancel: {
|
||||
state.cancel()
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user