Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 7 additions & 4 deletions Sources/SWBServiceCore/ServiceHostConnection.swift
Original file line number Diff line number Diff line change
Expand Up @@ -148,10 +148,13 @@ final class ServiceHostConnection: @unchecked Sendable {
#endif

// Read data.
let result = read(self.inputFD.rawValue, tmp.baseAddress, numericCast(tmpBufferSize))
if result < 0 {
if errno == EINTR { continue }
error = ServiceHostIOError(message: "read from client failed", cause: SWBUtil.POSIXError(errno, context: "read"))
let result: Int
do {
let buf = try await DispatchFD(fileDescriptor: self.inputFD).readChunk(upToLength: tmpBufferSize)
result = buf.count
buf.copyBytes(to: tmp)
} catch let readError {
error = ServiceHostIOError(message: "read from client failed", cause: readError)
break
}
if result == 0 {
Expand Down
20 changes: 19 additions & 1 deletion Sources/SWBUtil/Dispatch+Async.swift
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
// This file contains helpers used to bridge GCD and Swift Concurrency.
// In the long term, these ideally all go away.

private import Foundation
import Foundation

/// Runs an async function and synchronously waits for the response.
/// - warning: This function is extremely dangerous because it blocks the calling thread and may lead to deadlock, and should only be used as a temporary transitional aid.
Expand Down Expand Up @@ -41,6 +41,24 @@ public func runAsyncAndBlock<T: Sendable, E>(_ block: @Sendable @escaping () asy
return try result.value!.get()
}

extension DispatchFD {
public func readChunk(upToLength maxLength: Int) async throws -> SWBDispatchData {
return try await withCheckedThrowingContinuation { continuation in
SWBDispatchIO.read(
fromFileDescriptor: self,
maxLength: maxLength,
runningHandlerOn: .global()
) { data, error in
if error != 0 {
continuation.resume(throwing: POSIXError(error))
return
}
continuation.resume(returning: data)
}
}
}
}

extension AsyncThrowingStream where Element == UInt8, Failure == any Error {
/// Returns an async stream which reads bytes from the specified file descriptor. Unlike `FileHandle.bytes`, it does not block the caller.
@available(macOS, deprecated: 15.0, message: "Use the AsyncSequence-returning overload.")
Expand Down
15 changes: 14 additions & 1 deletion Sources/SWBUtil/SWBDispatch.swift
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@

private import Dispatch
public import SWBLibc
import Foundation
public import Foundation

#if canImport(System)
public import System
Expand Down Expand Up @@ -123,6 +123,12 @@ extension SWBDispatchData: RandomAccessCollection {
}
}

extension SWBDispatchData: DataProtocol {
public var regions: DispatchData.Regions {
dispatchData.regions
}
}

/// Thin wrapper for `DispatchSemaphore` to isolate it from the rest of the codebase and help migration away from it.
internal final class SWBDispatchSemaphore: Sendable {
private let semaphore: DispatchSemaphore
Expand Down Expand Up @@ -183,6 +189,13 @@ public final class SWBDispatchIO: Sendable {
io = DispatchIO(type: .stream, fileDescriptor: numericCast(fileDescriptor), queue: queue.queue, cleanupHandler: cleanupHandler)
}

public static func read(fromFileDescriptor fileDescriptor: DispatchFD, maxLength: Int, runningHandlerOn queue: SWBQueue, handler: @escaping (SWBDispatchData, Int32) -> Void) {
// Most of the dispatch APIs take a parameter called "fileDescriptor". On Windows (except makeReadSource and makeWriteSource) it is actually a HANDLE, so convert it accordingly.
DispatchIO.read(fromFileDescriptor: numericCast(fileDescriptor.rawValue), maxLength: maxLength, runningHandlerOn: queue.queue) { data, error in
handler(SWBDispatchData(data), error)
}
}

public static func stream(fileDescriptor: DispatchFD, queue: SWBQueue, cleanupHandler: @escaping (Int32) -> Void) -> SWBDispatchIO {
// Most of the dispatch APIs take a parameter called "fileDescriptor". On Windows (except makeReadSource and makeWriteSource) it is actually a HANDLE, so convert it accordingly.
SWBDispatchIO(fileDescriptor: numericCast(fileDescriptor.rawValue), queue: queue, cleanupHandler: cleanupHandler)
Expand Down