diff --git a/Package.resolved b/Package.resolved index 524d2802..58c65149 100644 --- a/Package.resolved +++ b/Package.resolved @@ -1,5 +1,5 @@ { - "originHash" : "de8e92cc53d3475bc48033bb3a62c1be5fff6cfaa8277de1d89f19524d834833", + "originHash" : "ac3ef791bf32cf99904bb681e6465fd729983add7f517f1c9342249121799bef", "pins" : [ { "identity" : "async-http-client", @@ -208,15 +208,6 @@ "version" : "2.8.0" } }, - { - "identity" : "swift-syntax", - "kind" : "remoteSourceControl", - "location" : "https://github.com/swiftlang/swift-syntax.git", - "state" : { - "revision" : "0dff260d3d1bb99c382d8dfcd6bb093e5e9cbd36", - "version" : "602.0.0-prerelease-2025-05-29" - } - }, { "identity" : "swift-system", "kind" : "remoteSourceControl", diff --git a/Package.swift b/Package.swift index 0651bcaf..56159eb7 100644 --- a/Package.swift +++ b/Package.swift @@ -33,7 +33,6 @@ let package = Package( .library(name: "ContainerizationOS", targets: ["ContainerizationOS"]), .library(name: "ContainerizationExtras", targets: ["ContainerizationExtras"]), .library(name: "ContainerizationArchive", targets: ["ContainerizationArchive"]), - .library(name: "SendableProperty", targets: ["SendableProperty"]), .executable(name: "cctl", targets: ["cctl"]), ], dependencies: [ @@ -46,7 +45,6 @@ let package = Package( .package(url: "https://github.com/apple/swift-nio.git", from: "2.80.0"), .package(url: "https://github.com/swift-server/async-http-client.git", from: "1.20.1"), .package(url: "https://github.com/apple/swift-system.git", from: "1.4.0"), - .package(url: "https://github.com/swiftlang/swift-syntax.git", "602.0.0-latest"..<"603.0.0"), .package(url: "https://github.com/swiftlang/swift-docc-plugin", from: "1.1.0"), ], targets: [ @@ -64,7 +62,6 @@ let package = Package( "ContainerizationOS", "ContainerizationIO", "ContainerizationExtras", - "SendableProperty", .target(name: "ContainerizationEXT4", condition: .when(platforms: [.macOS])), ], exclude: [ @@ -204,7 +201,6 @@ let package = Package( .product(name: "Logging", package: "swift-log"), "CShim", "ContainerizationError", - "SendableProperty", ], exclude: [ "../ContainerizationOS/README.md" @@ -244,25 +240,5 @@ let package = Package( .target( name: "CShim" ), - // Library that exposes a macro as part of its API, which is used in client programs. - .target(name: "SendableProperty", dependencies: ["SendablePropertyMacros"]), - // Macro implementation that performs the source transformation of a macro. - .macro( - name: "SendablePropertyMacros", - dependencies: [ - .product(name: "SwiftSyntaxMacros", package: "swift-syntax"), - .product(name: "SwiftCompilerPlugin", package: "swift-syntax"), - ] - ), - // A test target used to develop the macro implementation. - .testTarget( - name: "SendablePropertyMacrosTests", - dependencies: [ - "SendablePropertyMacros", - .product(name: "SwiftSyntaxMacrosTestSupport", package: "swift-syntax"), - ] - ), - // A test target for the macro implementation. - .testTarget(name: "SendablePropertyTests", dependencies: ["SendableProperty"]), ] ) diff --git a/Sources/ContainerizationExtras/IndexedAddressAllocator.swift b/Sources/ContainerizationExtras/IndexedAddressAllocator.swift index 6478fbb5..6ab672c5 100644 --- a/Sources/ContainerizationExtras/IndexedAddressAllocator.swift +++ b/Sources/ContainerizationExtras/IndexedAddressAllocator.swift @@ -44,7 +44,7 @@ package final class IndexedAddressAllocator + private let state: Mutex /// Create an allocator with specified size and index mappings. package init( @@ -57,11 +57,11 @@ package final class IndexedAddressAllocator AddressType { - try self.stateGuard.withLock { state in + try self.state.withLock { state in guard state.enabled else { throw AllocatorError.allocatorDisabled } @@ -81,7 +81,7 @@ package final class IndexedAddressAllocator Bool { - self.stateGuard.withLock { state in + self.state.withLock { state in guard state.allocationCount == 0 else { return false } diff --git a/Sources/ContainerizationExtras/RotatingAddressAllocator.swift b/Sources/ContainerizationExtras/RotatingAddressAllocator.swift index 7399fa45..597605a4 100644 --- a/Sources/ContainerizationExtras/RotatingAddressAllocator.swift +++ b/Sources/ContainerizationExtras/RotatingAddressAllocator.swift @@ -39,7 +39,7 @@ package final class RotatingAddressAllocator: AddressAllocator { } } - private let stateGuard: Mutex + private let state: Mutex /// Create an allocator with specified size and index mappings. package init( @@ -52,11 +52,11 @@ package final class RotatingAddressAllocator: AddressAllocator { addressToIndex: addressToIndex, indexToAddress: indexToAddress ) - self.stateGuard = Mutex(state) + self.state = Mutex(state) } public func allocate() throws -> AddressType { - try self.stateGuard.withLock { state in + try self.state.withLock { state in guard state.enabled else { throw AllocatorError.allocatorDisabled } @@ -77,7 +77,7 @@ package final class RotatingAddressAllocator: AddressAllocator { } package func reserve(_ address: AddressType) throws { - try self.stateGuard.withLock { state in + try self.state.withLock { state in guard state.enabled else { throw AllocatorError.allocatorDisabled } @@ -97,7 +97,7 @@ package final class RotatingAddressAllocator: AddressAllocator { } package func release(_ address: AddressType) throws { - try self.stateGuard.withLock { state in + try self.state.withLock { state in guard let index = (state.addressToIndex(address)) else { throw AllocatorError.invalidAddress(address.description) } @@ -113,7 +113,7 @@ package final class RotatingAddressAllocator: AddressAllocator { } package func disableAllocator() -> Bool { - self.stateGuard.withLock { state in + self.state.withLock { state in guard state.allocationCount == 0 else { return false } diff --git a/Sources/SendableProperty/SendableProperty.swift b/Sources/SendableProperty/SendableProperty.swift deleted file mode 100644 index bf8d60e5..00000000 --- a/Sources/SendableProperty/SendableProperty.swift +++ /dev/null @@ -1,20 +0,0 @@ -//===----------------------------------------------------------------------===// -// Copyright © 2025 Apple Inc. and the Containerization project authors. All rights reserved. -// -// 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. -//===----------------------------------------------------------------------===// - -// A declaration of the `@SendableProperty` macro. -@attached(peer, names: arbitrary) -@attached(accessor) -public macro SendableProperty() = #externalMacro(module: "SendablePropertyMacros", type: "SendablePropertyMacro") diff --git a/Sources/SendableProperty/SendablePropertyUnchecked.swift b/Sources/SendableProperty/SendablePropertyUnchecked.swift deleted file mode 100644 index 8c859b92..00000000 --- a/Sources/SendableProperty/SendablePropertyUnchecked.swift +++ /dev/null @@ -1,20 +0,0 @@ -//===----------------------------------------------------------------------===// -// Copyright © 2025 Apple Inc. and the Containerization project authors. All rights reserved. -// -// 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. -//===----------------------------------------------------------------------===// - -// A declaration of the `@SendablePropertyUnchecked` macro. -@attached(peer, names: arbitrary) -@attached(accessor) -public macro SendablePropertyUnchecked() = #externalMacro(module: "SendablePropertyMacros", type: "SendablePropertyMacroUnchecked") diff --git a/Sources/SendableProperty/Synchronized.swift b/Sources/SendableProperty/Synchronized.swift deleted file mode 100644 index bbe5c42f..00000000 --- a/Sources/SendableProperty/Synchronized.swift +++ /dev/null @@ -1,41 +0,0 @@ -//===----------------------------------------------------------------------===// -// Copyright © 2025 Apple Inc. and the Containerization project authors. All rights reserved. -// -// 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. -//===----------------------------------------------------------------------===// - -// `Synchronization` will be automatically imported with `SendableProperty`. -@_exported import Synchronization - -/// A synchronization primitive that protects shared mutable state via mutual exclusion. -public final class Synchronized: Sendable { - private let lock: Mutex - - private struct State: @unchecked Sendable { - var value: T - } - - /// Creates a new instance. - /// - Parameter value: The initial value. - public init(_ value: T) { - self.lock = Mutex(State(value: value)) - } - - /// Calls the given closure after acquiring the lock and returns its value. - /// - Parameter body: The body of code to execute while the lock is held. - public func withLock(_ body: (inout T) throws -> R) rethrows -> R { - try lock.withLock { state in - try body(&state.value) - } - } -} diff --git a/Sources/SendablePropertyMacros/SendablePropertyError.swift b/Sources/SendablePropertyMacros/SendablePropertyError.swift deleted file mode 100644 index 41ca6e2d..00000000 --- a/Sources/SendablePropertyMacros/SendablePropertyError.swift +++ /dev/null @@ -1,30 +0,0 @@ -//===----------------------------------------------------------------------===// -// Copyright © 2025 Apple Inc. and the Containerization project authors. All rights reserved. -// -// 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. -//===----------------------------------------------------------------------===// - -/// Errors that can be thrown by `@SendableProperty`. -enum SendablePropertyError: CustomStringConvertible, Error { - case unexpectedError - case onlyApplicableToVar - case notApplicableToType - - var description: String { - switch self { - case .unexpectedError: return "The macro encountered an unexpected error" - case .onlyApplicableToVar: return "The macro can only be applied to a variable" - case .notApplicableToType: return "The macro can't be applied to a variable of this type" - } - } -} diff --git a/Sources/SendablePropertyMacros/SendablePropertyMacro.swift b/Sources/SendablePropertyMacros/SendablePropertyMacro.swift deleted file mode 100644 index 2a2667a2..00000000 --- a/Sources/SendablePropertyMacros/SendablePropertyMacro.swift +++ /dev/null @@ -1,81 +0,0 @@ -//===----------------------------------------------------------------------===// -// Copyright © 2025 Apple Inc. and the Containerization project authors. All rights reserved. -// -// 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. -//===----------------------------------------------------------------------===// - -import Foundation -import SwiftCompilerPlugin -import SwiftParser -import SwiftSyntax -import SwiftSyntaxBuilder -import SwiftSyntaxMacros - -/// A macro that allows to make a property of a supported type thread-safe keeping the `Sendable` conformance of the type. -public struct SendablePropertyMacro: PeerMacro { - private static let allowedTypes: Set = [ - "Int", "UInt", "Int16", "UInt16", "Int32", "UInt32", "Int64", "UInt64", "Float", "Double", "Bool", "UnsafeRawPointer", "UnsafeMutableRawPointer", "UnsafePointer", - "UnsafeMutablePointer", - ] - - private static func checkPropertyType(in declaration: some DeclSyntaxProtocol) throws { - guard let varDecl = declaration.as(VariableDeclSyntax.self), - let binding = varDecl.bindings.first, - let typeAnnotation = binding.typeAnnotation, - let id = typeAnnotation.type.as(IdentifierTypeSyntax.self) - else { - // Nothing to check. - return - } - - var typeName = id.name.text - // Allow optionals of the allowed types. - if typeName.prefix(9) == "Optional<" && typeName.suffix(1) == ">" { - typeName = String(typeName.dropFirst(9).dropLast(1)) - } - // Allow generics of the allowed types. - if typeName.contains("<") { - typeName = String(typeName.prefix { $0 != "<" }) - } - - guard allowedTypes.contains(typeName) else { - throw SendablePropertyError.notApplicableToType - } - } - - /// The macro expansion that introduces a `Sendable`-conforming "peer" declaration for a thread-safe storage for the value of the given declaration of a variable. - /// - Parameters: - /// - node: The given attribute node. - /// - declaration: The given declaration. - /// - context: The macro expansion context. - public static func expansion( - of node: SwiftSyntax.AttributeSyntax, providingPeersOf declaration: some SwiftSyntax.DeclSyntaxProtocol, in context: some SwiftSyntaxMacros.MacroExpansionContext - ) throws -> [SwiftSyntax.DeclSyntax] { - try checkPropertyType(in: declaration) - return try SendablePropertyMacroUnchecked.expansion(of: node, providingPeersOf: declaration, in: context) - } -} - -extension SendablePropertyMacro: AccessorMacro { - /// The macro expansion that adds `Sendable`-conforming accessors to the given declaration of a variable. - /// - Parameters: - /// - node: The given attribute node. - /// - declaration: The given declaration. - /// - context: The macro expansion context. - public static func expansion( - of node: SwiftSyntax.AttributeSyntax, providingAccessorsOf declaration: some SwiftSyntax.DeclSyntaxProtocol, in context: some SwiftSyntaxMacros.MacroExpansionContext - ) throws -> [SwiftSyntax.AccessorDeclSyntax] { - try checkPropertyType(in: declaration) - return try SendablePropertyMacroUnchecked.expansion(of: node, providingAccessorsOf: declaration, in: context) - } -} diff --git a/Sources/SendablePropertyMacros/SendablePropertyMacroUnchecked.swift b/Sources/SendablePropertyMacros/SendablePropertyMacroUnchecked.swift deleted file mode 100644 index 0330575a..00000000 --- a/Sources/SendablePropertyMacros/SendablePropertyMacroUnchecked.swift +++ /dev/null @@ -1,104 +0,0 @@ -//===----------------------------------------------------------------------===// -// Copyright © 2025 Apple Inc. and the Containerization project authors. All rights reserved. -// -// 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. -//===----------------------------------------------------------------------===// - -import Foundation -import SwiftCompilerPlugin -import SwiftParser -import SwiftSyntax -import SwiftSyntaxBuilder -import SwiftSyntaxMacros - -/// A macro that allows to make a property of a custom type thread-safe keeping the `Sendable` conformance of the type. This macro can be used with classes and enums. Avoid using it with structs, arrays, and dictionaries. -public struct SendablePropertyMacroUnchecked: PeerMacro { - private static func peerPropertyName(for propertyName: String) -> String { - "_" + propertyName - } - - /// The macro expansion that introduces a `Sendable`-conforming "peer" declaration for a thread-safe storage for the value of the given declaration of a variable. - /// - Parameters: - /// - node: The given attribute node. - /// - declaration: The given declaration. - /// - context: The macro expansion context. - public static func expansion( - of node: SwiftSyntax.AttributeSyntax, providingPeersOf declaration: some SwiftSyntax.DeclSyntaxProtocol, in context: some SwiftSyntaxMacros.MacroExpansionContext - ) throws -> [SwiftSyntax.DeclSyntax] { - guard let varDecl = declaration.as(VariableDeclSyntax.self), - let binding = varDecl.bindings.first, - let pattern = binding.pattern.as(IdentifierPatternSyntax.self) - else { - throw SendablePropertyError.onlyApplicableToVar - } - - let propertyName = pattern.identifier.text - let hasInitializer = binding.initializer != nil - let initializerValue = binding.initializer?.value.description ?? "nil" - - var genericTypeAnnotation = "" - if let typeAnnotation = binding.typeAnnotation { - let typeName = typeAnnotation.type.description.trimmingCharacters(in: CharacterSet.whitespacesAndNewlines) - genericTypeAnnotation = "<\(typeName)\(hasInitializer ? "" : "?")>" - } - - let accessLevel = varDecl.modifiers.first(where: { ["open", "public", "internal", "fileprivate", "private"].contains($0.name.text) })?.name.text ?? "internal" - - // Create a peer property - let peerPropertyName = self.peerPropertyName(for: propertyName) - let peerProperty: DeclSyntax = - """ - \(raw: accessLevel) let \(raw: peerPropertyName) = Synchronized\(raw: genericTypeAnnotation)(\(raw: initializerValue)) - """ - return [peerProperty] - } -} - -extension SendablePropertyMacroUnchecked: AccessorMacro { - /// The macro expansion that adds `Sendable`-conforming accessors to the given declaration of a variable. - /// - Parameters: - /// - node: The given attribute node. - /// - declaration: The given declaration. - /// - context: The macro expansion context. - public static func expansion( - of node: SwiftSyntax.AttributeSyntax, providingAccessorsOf declaration: some SwiftSyntax.DeclSyntaxProtocol, in context: some SwiftSyntaxMacros.MacroExpansionContext - ) throws -> [SwiftSyntax.AccessorDeclSyntax] { - guard let varDecl = declaration.as(VariableDeclSyntax.self), - let binding = varDecl.bindings.first, - let pattern = binding.pattern.as(IdentifierPatternSyntax.self) - else { - throw SendablePropertyError.onlyApplicableToVar - } - - let propertyName = pattern.identifier.text - let hasInitializer = binding.initializer != nil - - // Replace the property with an accessor - let peerPropertyName = Self.peerPropertyName(for: propertyName) - - let accessorGetter: AccessorDeclSyntax = - """ - get { - \(raw: peerPropertyName).withLock { $0\(raw: hasInitializer ? "" : "!") } - } - """ - let accessorSetter: AccessorDeclSyntax = - """ - set { - \(raw: peerPropertyName).withLock { $0 = newValue } - } - """ - - return [accessorGetter, accessorSetter] - } -} diff --git a/Sources/SendablePropertyMacros/SendablePropertyPlugin.swift b/Sources/SendablePropertyMacros/SendablePropertyPlugin.swift deleted file mode 100644 index bbf069c8..00000000 --- a/Sources/SendablePropertyMacros/SendablePropertyPlugin.swift +++ /dev/null @@ -1,27 +0,0 @@ -//===----------------------------------------------------------------------===// -// Copyright © 2025 Apple Inc. and the Containerization project authors. All rights reserved. -// -// 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. -//===----------------------------------------------------------------------===// - -import SwiftCompilerPlugin -import SwiftSyntaxMacros - -/// A plugin that registers the `SendablePropertyMacroUnchecked` and `SendablePropertyMacro`. -@main -struct SendablePropertyPlugin: CompilerPlugin { - let providingMacros: [Macro.Type] = [ - SendablePropertyMacroUnchecked.self, - SendablePropertyMacro.self, - ] -} diff --git a/Tests/SendablePropertyMacrosTests/SendablePropertyMacrosTests.swift b/Tests/SendablePropertyMacrosTests/SendablePropertyMacrosTests.swift deleted file mode 100644 index 7e629e74..00000000 --- a/Tests/SendablePropertyMacrosTests/SendablePropertyMacrosTests.swift +++ /dev/null @@ -1,138 +0,0 @@ -//===----------------------------------------------------------------------===// -// Copyright © 2025 Apple Inc. and the Containerization project authors. All rights reserved. -// -// 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. -//===----------------------------------------------------------------------===// - -import Foundation -import SwiftSyntax -import SwiftSyntaxBuilder -import SwiftSyntaxMacros -import SwiftSyntaxMacrosTestSupport -import XCTest - -// Macro implementations build for the host, so the corresponding module is not available when cross-compiling. Cross-compiled tests may still make use of the macro itself in end-to-end tests. -#if canImport(SendablePropertyMacros) -import SendablePropertyMacros - -let testMacros: [String: Macro.Type] = [ - "SendableProperty": SendablePropertyMacro.self -] -#endif - -final class SendablePropertyMacrosTests: XCTestCase { - func testMacroExpansionWithTypeAnnotation() throws { - #if canImport(SendablePropertyMacros) - assertMacroExpansion( - """ - final class TestMacro: Sendable { - @SendableProperty - var value: Int - } - """, - expandedSource: - """ - final class TestMacro: Sendable { - var value: Int { - get { - _value.withLock { - $0! - } - } - set { - _value.withLock { - $0 = newValue - } - } - } - - internal let _value = Synchronized(nil) - } - """, - macros: testMacros - ) - #else - throw XCTSkip("macros are only supported when running tests for the host platform") - #endif - } - - func testMacroExpansionWithInitialValue() throws { - #if canImport(SendablePropertyMacros) - assertMacroExpansion( - """ - final class TestMacro: Sendable { - @SendableProperty - var value = 0 - } - """, - expandedSource: - """ - final class TestMacro: Sendable { - var value { - get { - _value.withLock { - $0 - } - } - set { - _value.withLock { - $0 = newValue - } - } - } - - internal let _value = Synchronized(0) - } - """, - macros: testMacros - ) - #else - throw XCTSkip("macros are only supported when running tests for the host platform") - #endif - } - - func testMacroExpansionWithTypeAnnotationAndInitialValue() throws { - #if canImport(SendablePropertyMacros) - assertMacroExpansion( - """ - final class TestMacro: Sendable { - @SendableProperty - var value: Int = 0 - } - """, - expandedSource: - """ - final class TestMacro: Sendable { - var value: Int { - get { - _value.withLock { - $0 - } - } - set { - _value.withLock { - $0 = newValue - } - } - } - - internal let _value = Synchronized(0) - } - """, - macros: testMacros - ) - #else - throw XCTSkip("macros are only supported when running tests for the host platform") - #endif - } -} diff --git a/Tests/SendablePropertyTests/SendablePropertyTests.swift b/Tests/SendablePropertyTests/SendablePropertyTests.swift deleted file mode 100644 index b36df490..00000000 --- a/Tests/SendablePropertyTests/SendablePropertyTests.swift +++ /dev/null @@ -1,145 +0,0 @@ -//===----------------------------------------------------------------------===// -// Copyright © 2025 Apple Inc. and the Containerization project authors. All rights reserved. -// -// 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. -//===----------------------------------------------------------------------===// - -import Foundation -import SendableProperty -import XCTest - -final class SendablePropertyTests: XCTestCase { - func testMacroWithTypeAnnotation() throws { - final class TestMacro: Sendable { - @SendableProperty - var value: Int - } - - let testMacro = TestMacro() - testMacro.value = 42 - XCTAssertTrue(testMacro.value == 42) - } - - func testMacroWithInitialValue() throws { - final class TestMacro: Sendable { - @SendableProperty - var value = 0 - } - - let testMacro = TestMacro() - XCTAssertTrue(type(of: testMacro.value) == Int.self) - XCTAssertTrue(testMacro.value == 0) - testMacro.value = 42 - XCTAssertTrue(testMacro.value == 42) - } - - func testMacroWithTypeAnnotationAndInitialValue() throws { - final class TestMacro: Sendable { - @SendableProperty - var value: Int = 0 - } - - let testMacro = TestMacro() - testMacro.value = 42 - XCTAssertTrue(testMacro.value == 42) - } - - func testMacroInConcurrentThreads() throws { - final class TestMacro: Sendable { - @SendableProperty - var value = "" - } - - let testMacro = TestMacro() - let loremIpsum = - "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum." - - let numberOfIterations = 100_000 - let queue = DispatchQueue(label: "com.apple.sendable-property-tests", attributes: .concurrent) - let dispatchGroup = DispatchGroup() - for i in 0.. - @SendableProperty - var unsafeMutablePointer: UnsafeMutablePointer - - @SendableProperty - var intOpt: Int? - @SendableProperty - var uintOpt: UInt? - @SendableProperty - var int16Opt: Int16? - @SendableProperty - var uint16Opt: UInt16? - @SendableProperty - var int32Opt: Int32? - @SendableProperty - var uint32Opt: UInt32? - @SendableProperty - var int64Opt: Int64? - @SendableProperty - var uint64Opt: UInt64? - @SendableProperty - var floaOptt: Float? - @SendableProperty - var doubleOpt: Double? - @SendableProperty - var boolOpt: Bool? - @SendableProperty - var unsafeRawPoinerOpt: UnsafeRawPointer? - @SendableProperty - var unsafeMutableRawPointerOpt: UnsafeMutableRawPointer? - @SendableProperty - var unsafePoinerOpt: UnsafePointer? - @SendableProperty - var unsafeMutablePointerOpt: UnsafeMutablePointer? - } - } -} diff --git a/vminitd/Sources/vminitd/ManagedProcess.swift b/vminitd/Sources/vminitd/ManagedProcess.swift index ebe4327b..4cfff235 100644 --- a/vminitd/Sources/vminitd/ManagedProcess.swift +++ b/vminitd/Sources/vminitd/ManagedProcess.swift @@ -28,7 +28,7 @@ final class ManagedProcess: Sendable { private let log: Logger private let process: Command - private let lock: Mutex + private let state: Mutex private let syncfd: Pipe private let owningPid: Int32? @@ -44,7 +44,7 @@ final class ManagedProcess: Sendable { } var pid: Int32 { - self.lock.withLock { + self.state.withLock { $0.pid } } @@ -121,13 +121,13 @@ final class ManagedProcess: Sendable { try io.start(process: &process) self.process = process - self.lock = Mutex(State(io: io)) + self.state = Mutex(State(io: io)) } } extension ManagedProcess { func start() throws -> Int32 { - try self.lock.withLock { + try self.state.withLock { log.info( "starting managed process", metadata: [ @@ -164,7 +164,7 @@ extension ManagedProcess { } func setExit(_ status: Int32) { - self.lock.withLock { + self.state.withLock { self.log.info( "managed process exit", metadata: [ @@ -185,7 +185,7 @@ extension ManagedProcess { /// Wait on the process to exit func wait() async -> Int32 { await withCheckedContinuation { cont in - self.lock.withLock { + self.state.withLock { if let status = $0.exitStatus { cont.resume(returning: status) return @@ -196,7 +196,7 @@ extension ManagedProcess { } func kill(_ signal: Int32) throws { - try self.lock.withLock { + try self.state.withLock { guard $0.exitStatus == nil else { return } @@ -209,7 +209,7 @@ extension ManagedProcess { } func resize(size: Terminal.Size) throws { - try self.lock.withLock { + try self.state.withLock { guard $0.exitStatus == nil else { return } @@ -218,7 +218,7 @@ extension ManagedProcess { } func closeStdin() throws { - try self.lock.withLock { + try self.state.withLock { try $0.io.closeStdin() } } diff --git a/vminitd/Sources/vminitd/Server+GRPC.swift b/vminitd/Sources/vminitd/Server+GRPC.swift index 84de22ff..b9b71f10 100644 --- a/vminitd/Sources/vminitd/Server+GRPC.swift +++ b/vminitd/Sources/vminitd/Server+GRPC.swift @@ -173,7 +173,7 @@ extension Initd: Com_Apple_Containerization_Sandbox_V3_SandboxContextAsyncProvid log: log ) - try proxy.start() + try await proxy.start() try await state.add(proxy: proxy) } catch { log.error( @@ -202,7 +202,7 @@ extension Initd: Com_Apple_Containerization_Sandbox_V3_SandboxContextAsyncProvid do { let proxy = try await state.remove(proxy: request.id) - try proxy.close() + try await proxy.close() } catch { log.error( "stopVsockProxy", diff --git a/vminitd/Sources/vminitd/VsockProxy.swift b/vminitd/Sources/vminitd/VsockProxy.swift index 70ea308c..f3ef319b 100644 --- a/vminitd/Sources/vminitd/VsockProxy.swift +++ b/vminitd/Sources/vminitd/VsockProxy.swift @@ -18,9 +18,8 @@ import ContainerizationIO import ContainerizationOS import Foundation import Logging -import SendableProperty -final class VsockProxy: Sendable { +actor VsockProxy { enum Action { case listen case dial @@ -54,9 +53,8 @@ final class VsockProxy: Sendable { private let udsPerms: UInt32? private let log: Logger? - @SendableProperty private var listener: Socket? - private let task = Mutex?>(nil) + private var task: Task<(), Never>? } extension VsockProxy { @@ -70,11 +68,14 @@ extension VsockProxy { if fm.fileExists(atPath: self.path.path) { try FileManager.default.removeItem(at: self.path) } - let task = task.withLock { $0 } task?.cancel() + self.listener = nil } func start() throws { + guard listener == nil else { + return + } switch self.action { case .dial: try dialHost() @@ -140,7 +141,7 @@ extension VsockProxy { self.log?.error("failed to accept connection: \(error)") } } - self.task.withLock { $0 = task } + self.task = task } private func handleConn(