Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Adopt strict concurrency and Sendable in NIOConcurrencyHelpers #2832

Merged
merged 4 commits into from
Aug 8, 2024
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
8 changes: 7 additions & 1 deletion Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,11 @@ let swiftSystem: PackageDescription.Target.Dependency = .product(
condition: .when(platforms: [.macOS, .iOS, .tvOS, .watchOS, .linux, .android])
)

let strictConcurrencySettings: [SwiftSetting] = [
.enableUpcomingFeature("StrictConcurrency"),
.enableUpcomingFeature("InferSendableFromCaptures"),
]

// This doesn't work when cross-compiling: the privacy manifest will be included in the Bundle and
// Foundation will be linked. This is, however, strictly better than unconditionally adding the
// resource.
Expand Down Expand Up @@ -150,7 +155,8 @@ let package = Package(
name: "NIOConcurrencyHelpers",
dependencies: [
"CNIOAtomics"
]
],
swiftSettings: strictConcurrencySettings
),
.target(
name: "NIOHTTP1",
Expand Down
18 changes: 18 additions & 0 deletions Sources/NIOConcurrencyHelpers/NIOAtomic.swift
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,23 @@ import CNIOAtomics
/// **Do not add conformance to this protocol for arbitrary types**. Only a small range
/// of types have appropriate atomic operations supported by the CPU, and those types
/// already have conformances implemented.
#if compiler(>=6.0)
@preconcurrency
public protocol NIOAtomicPrimitive {
associatedtype AtomicWrapper
static var nio_atomic_create_with_existing_storage: @Sendable (UnsafeMutablePointer<AtomicWrapper>, Self) -> Void {
get
}
static var nio_atomic_compare_and_exchange: @Sendable (UnsafeMutablePointer<AtomicWrapper>, Self, Self) -> Bool {
get
}
static var nio_atomic_add: @Sendable (UnsafeMutablePointer<AtomicWrapper>, Self) -> Self { get }
static var nio_atomic_sub: @Sendable (UnsafeMutablePointer<AtomicWrapper>, Self) -> Self { get }
static var nio_atomic_exchange: @Sendable (UnsafeMutablePointer<AtomicWrapper>, Self) -> Self { get }
static var nio_atomic_load: @Sendable (UnsafeMutablePointer<AtomicWrapper>) -> Self { get }
static var nio_atomic_store: @Sendable (UnsafeMutablePointer<AtomicWrapper>, Self) -> Void { get }
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unfortunately, this change to duplicate the protocol definition was required because Swift 5.8, 5.9, and 5.10 do not support InferSendableFromCaptures.

}
#else
public protocol NIOAtomicPrimitive {
associatedtype AtomicWrapper
static var nio_atomic_create_with_existing_storage: (UnsafeMutablePointer<AtomicWrapper>, Self) -> Void { get }
Expand All @@ -29,6 +46,7 @@ public protocol NIOAtomicPrimitive {
static var nio_atomic_load: (UnsafeMutablePointer<AtomicWrapper>) -> Self { get }
static var nio_atomic_store: (UnsafeMutablePointer<AtomicWrapper>, Self) -> Void { get }
}
#endif

extension Bool: NIOAtomicPrimitive {
public typealias AtomicWrapper = catmc_nio_atomic__Bool
Expand Down
23 changes: 23 additions & 0 deletions Sources/NIOConcurrencyHelpers/atomics.swift
Original file line number Diff line number Diff line change
Expand Up @@ -165,6 +165,9 @@ public struct UnsafeEmbeddedAtomic<T: AtomicPrimitive> {
}
}

@available(*, deprecated)
extension UnsafeEmbeddedAtomic: @unchecked Sendable where T: Sendable {}

/// An encapsulation of an atomic primitive object.
///
/// Atomic objects support a wide range of atomic operations:
Expand Down Expand Up @@ -284,11 +287,27 @@ public final class Atomic<T: AtomicPrimitive> {
}
}

@available(*, deprecated)
extension Atomic: @unchecked Sendable where T: Sendable {}

/// The protocol that all types that can be made atomic must conform to.
///
/// **Do not add conformance to this protocol for arbitrary types**. Only a small range
/// of types have appropriate atomic operations supported by the CPU, and those types
/// already have conformances implemented.
#if compiler(>=6.0)
@preconcurrency
public protocol AtomicPrimitive {
static var atomic_create: @Sendable (Self) -> OpaquePointer { get }
static var atomic_destroy: @Sendable (OpaquePointer) -> Void { get }
static var atomic_compare_and_exchange: @Sendable (OpaquePointer, Self, Self) -> Bool { get }
static var atomic_add: @Sendable (OpaquePointer, Self) -> Self { get }
static var atomic_sub: @Sendable (OpaquePointer, Self) -> Self { get }
static var atomic_exchange: @Sendable (OpaquePointer, Self) -> Self { get }
static var atomic_load: @Sendable (OpaquePointer) -> Self { get }
static var atomic_store: @Sendable (OpaquePointer, Self) -> Void { get }
}
#else
public protocol AtomicPrimitive {
static var atomic_create: (Self) -> OpaquePointer { get }
static var atomic_destroy: (OpaquePointer) -> Void { get }
Expand All @@ -299,6 +318,7 @@ public protocol AtomicPrimitive {
static var atomic_load: (OpaquePointer) -> Self { get }
static var atomic_store: (OpaquePointer, Self) -> Void { get }
}
#endif

extension Bool: AtomicPrimitive {
public static let atomic_create = catmc_atomic__Bool_create
Expand Down Expand Up @@ -597,3 +617,6 @@ public final class AtomicBox<T: AnyObject> {
_ = self.exchange(with: value)
}
}

@available(*, deprecated)
extension AtomicBox: @unchecked Sendable where T: Sendable {}
Loading