Skip to content
Merged
Show file tree
Hide file tree
Changes from 3 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
3 changes: 1 addition & 2 deletions Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -261,8 +261,7 @@ let package = Package(
.target(
name: "TerminalProgress",
dependencies: [
.product(name: "ContainerizationOS", package: "containerization"),
.product(name: "SendableProperty", package: "containerization"),
.product(name: "ContainerizationOS", package: "containerization")
]
),
.testTarget(
Expand Down
29 changes: 16 additions & 13 deletions Sources/Services/ContainerNetworkService/ReservedVmnetNetwork.swift
Original file line number Diff line number Diff line change
Expand Up @@ -21,22 +21,18 @@ import ContainerizationExtras
import Dispatch
import Foundation
import Logging
import SendableProperty
import Synchronization
import SystemConfiguration
import XPC
import vmnet

/// Creates a vmnet network with reservation APIs.
@available(macOS 26, *)
public final class ReservedVmnetNetwork: Network {
@SendablePropertyUnchecked
private var _state: NetworkState
private let _state: Mutex<NetworkState>
private let log: Logger

@SendableProperty
private var network: vmnet_network_ref?
@SendableProperty
private var interface: interface_ref?
private let network = Mutex<vmnet_network_ref?>(nil)
private let networkLock = NSLock()

/// Configure a bridge network that allows external system access using
Expand All @@ -51,23 +47,25 @@ public final class ReservedVmnetNetwork: Network {

log.info("creating vmnet network")
self.log = log
_state = .created(configuration)
_state = Mutex(.created(configuration))
log.info("created vmnet network")
}

public var state: NetworkState {
get async { _state }
get async { _state.withLock { $0 } }
}

public nonisolated func withAdditionalData(_ handler: (XPCMessage?) throws -> Void) throws {
try networkLock.withLock {
let network = self.network.withLock { $0 }
try handler(network.map { try Self.serialize_network_ref(ref: $0) })
}
}

public func start() async throws {
guard case .created(let configuration) = _state else {
throw ContainerizationError(.invalidArgument, message: "cannot start network that is in \(_state.state) state")
let state = _state.withLock { $0 }
guard case .created(let configuration) = state else {
throw ContainerizationError(.invalidArgument, message: "cannot start network that is in \(state.state) state")
}

try startNetwork(configuration: configuration, log: log)
Expand Down Expand Up @@ -125,7 +123,11 @@ public final class ReservedVmnetNetwork: Network {
guard let network = vmnet_network_create(vmnetConfiguration, &status), status == .VMNET_SUCCESS else {
throw ContainerizationError(.unsupported, message: "failed to create vmnet network with status \(status)")
}
self.network = network

let newNetwork = { network } // A workaround for "'inout sending' parameter '$0' cannot be task-isolated at end of function".
self.network.withLock {
$0 = newNetwork()
}

// retrieve the subnet since the caller may not have provided one
var subnetAddr = in_addr()
Expand All @@ -137,7 +139,8 @@ public final class ReservedVmnetNetwork: Network {
let upper = IPv4Address(fromValue: lower.value + ~maskValue)
let runningSubnet = try CIDRAddress(lower: lower, upper: upper)
let runningGateway = IPv4Address(fromValue: runningSubnet.lower.value + 1)
self._state = .running(configuration, NetworkStatus(address: runningSubnet.description, gateway: runningGateway.description))
let newState = NetworkState.running(configuration, NetworkStatus(address: runningSubnet.description, gateway: runningGateway.description))
self._state.withLock { $0 = newState }
log.info(
"started vmnet network",
metadata: [
Expand Down
6 changes: 4 additions & 2 deletions Sources/TerminalProgress/ProgressBar+Terminal.swift
Original file line number Diff line number Diff line change
Expand Up @@ -66,8 +66,10 @@ extension ProgressBar {
var text = text

// Clears previously printed characters if the new string is shorter.
text += String(repeating: " ", count: max(printedWidth - text.count, 0))
printedWidth = text.count
printedWidth.withLock {
text += String(repeating: " ", count: max($0 - text.count, 0))
$0 = text.count
}
state.withLock {
$0.output = text
}
Expand Down
4 changes: 1 addition & 3 deletions Sources/TerminalProgress/ProgressBar.swift
Original file line number Diff line number Diff line change
Expand Up @@ -15,15 +15,13 @@
//===----------------------------------------------------------------------===//

import Foundation
import SendableProperty
import Synchronization

/// A progress bar that updates itself as tasks are completed.
public final class ProgressBar: Sendable {
let config: ProgressConfig
let state: Mutex<State>
@SendableProperty
var printedWidth = 0
let printedWidth = Mutex(0)
let term: FileHandle?
let termQueue = DispatchQueue(label: "com.apple.container.ProgressBar")
private let standardError = StandardError()
Expand Down