chore: import upstream snapshot with attribution
This commit is contained in:
@@ -0,0 +1,152 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Copyright © 2025-2026 Apple Inc. and the Containerization project authors.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// https://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#if os(macOS)
|
||||
import Foundation
|
||||
import Logging
|
||||
import Virtualization
|
||||
import ContainerizationError
|
||||
|
||||
extension VZVirtualMachine {
|
||||
nonisolated func connect(queue: DispatchQueue, port: UInt32) async throws -> VZVirtioSocketConnection {
|
||||
try await withCheckedThrowingContinuation { cont in
|
||||
queue.sync {
|
||||
guard let vsock = self.socketDevices[0] as? VZVirtioSocketDevice else {
|
||||
let error = ContainerizationError(.invalidArgument, message: "no vsock device")
|
||||
cont.resume(throwing: error)
|
||||
return
|
||||
}
|
||||
vsock.connect(toPort: port) { result in
|
||||
switch result {
|
||||
case .success(let conn):
|
||||
// `conn` isn't used concurrently.
|
||||
nonisolated(unsafe) let conn = conn
|
||||
cont.resume(returning: conn)
|
||||
case .failure(let error):
|
||||
cont.resume(throwing: error)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func listen(queue: DispatchQueue, port: UInt32, listener: VZVirtioSocketListener) throws {
|
||||
try queue.sync {
|
||||
guard let vsock = self.socketDevices[0] as? VZVirtioSocketDevice else {
|
||||
throw ContainerizationError(.invalidArgument, message: "no vsock device")
|
||||
}
|
||||
vsock.setSocketListener(listener, forPort: port)
|
||||
}
|
||||
}
|
||||
|
||||
func removeListener(queue: DispatchQueue, port: UInt32) throws {
|
||||
try queue.sync {
|
||||
guard let vsock = self.socketDevices[0] as? VZVirtioSocketDevice else {
|
||||
throw ContainerizationError(
|
||||
.invalidArgument,
|
||||
message: "no vsock device to remove"
|
||||
)
|
||||
}
|
||||
vsock.removeSocketListener(forPort: port)
|
||||
}
|
||||
}
|
||||
|
||||
func start(queue: DispatchQueue) async throws {
|
||||
try await withCheckedThrowingContinuation { (cont: CheckedContinuation<Void, Error>) in
|
||||
queue.sync {
|
||||
self.start { result in
|
||||
if case .failure(let error) = result {
|
||||
cont.resume(throwing: error)
|
||||
return
|
||||
}
|
||||
cont.resume()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func stop(queue: DispatchQueue) async throws {
|
||||
try await withCheckedThrowingContinuation { (cont: CheckedContinuation<Void, Error>) in
|
||||
queue.sync {
|
||||
self.stop { error in
|
||||
if let error {
|
||||
cont.resume(throwing: error)
|
||||
return
|
||||
}
|
||||
cont.resume()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func pause(queue: DispatchQueue) async throws {
|
||||
try await withCheckedThrowingContinuation { (cont: CheckedContinuation<Void, Error>) in
|
||||
queue.sync {
|
||||
self.pause { result in
|
||||
if case .failure(let error) = result {
|
||||
cont.resume(throwing: error)
|
||||
return
|
||||
}
|
||||
cont.resume()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func resume(queue: DispatchQueue) async throws {
|
||||
try await withCheckedThrowingContinuation { (cont: CheckedContinuation<Void, Error>) in
|
||||
queue.sync {
|
||||
self.resume { result in
|
||||
if case .failure(let error) = result {
|
||||
cont.resume(throwing: error)
|
||||
return
|
||||
}
|
||||
cont.resume()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
extension VZVirtualMachine {
|
||||
func waitForAgent(queue: DispatchQueue) async throws -> FileHandle {
|
||||
let agentConnectionRetryCount: Int = 200
|
||||
let agentConnectionSleepDuration: Duration = .milliseconds(20)
|
||||
|
||||
for _ in 0...agentConnectionRetryCount {
|
||||
do {
|
||||
return try await self.connect(queue: queue, port: Vminitd.port).dupHandle()
|
||||
} catch {
|
||||
try await Task.sleep(for: agentConnectionSleepDuration)
|
||||
continue
|
||||
}
|
||||
}
|
||||
throw ContainerizationError(.timeout, message: "failed to get a connection to agent socket")
|
||||
}
|
||||
}
|
||||
|
||||
extension VZVirtioSocketConnection {
|
||||
func dupHandle() throws -> FileHandle {
|
||||
let fd = dup(self.fileDescriptor)
|
||||
if fd == -1 {
|
||||
throw POSIXError.fromErrno()
|
||||
}
|
||||
self.close()
|
||||
return FileHandle(fileDescriptor: fd, closeOnDealloc: false)
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
Reference in New Issue
Block a user