containerization-framework 0.2.0

Rust bindings for Apple's Containerization framework: Linux containers in lightweight VMs, in-process and without a daemon.
//===----------------------------------------------------------------------===//
// The VMs this process owns, and the processes running in them.
//
// A `LinuxContainer` dies with the process that created it, so `run` owns its
// session with no daemon: `boot` registers it here, later `exec`s find it, and
// process exit stops it.
//
// Processes are held because a resize must reach the `LinuxProcess` owning the
// guest pty, and the SIGWINCH arrives on a different call than the exec.
//===----------------------------------------------------------------------===//

import Containerization
import ContainerizationOCI
import Synchronization

struct Booted {
    /// Held because dropping it drops the network interface.
    let manager: ContainerManager
    let container: LinuxContainer
    /// The image's process configuration, chiefly its user.
    ///
    /// `ContainerManager.create` seeds the first process from this, but
    /// `LinuxContainer.exec` starts from a bare config running as root, so each
    /// attach seeds itself from this copy.
    let imageConfig: ImageConfig?
}

/// Accessed concurrently: bridged calls arrive on one Rust thread per attached
/// terminal.
final class Sessions: Sendable {
    static let shared = Sessions()

    private let booted = Mutex<[String: Booted]>([:])
    /// Keyed by exec id, which the bridge makes unique per attach.
    private let processes = Mutex<[String: LinuxProcess]>([:])

    func insert(_ name: String, _ session: Booted) {
        booted.withLock { $0[name] = session }
    }

    func get(_ name: String) -> Booted? {
        booted.withLock { $0[name] }
    }

    func insert(process: LinuxProcess, id: String) {
        processes.withLock { $0[id] = process }
    }

    func process(_ id: String) -> LinuxProcess? {
        processes.withLock { $0[id] }
    }

    func remove(process id: String) {
        _ = processes.withLock { $0.removeValue(forKey: id) }
    }
}