From 4ea1f304060606e1a82aa3a3441fe1739840cd83 Mon Sep 17 00:00:00 2001 From: Cory Benfield Date: Thu, 8 Aug 2024 12:57:49 +0100 Subject: [PATCH] Adopt strict concurrency and Sendable in NIOConcurrencyHelpers (#2832) Motivation: This patch adds strict concurrency and Sendable support to NIOConcurrencyHelpers. This is a useful first step in adding full support across the ecosystem. Modifications: - Added some explicit Sendable conformances that were missing. - Fixed some declarations to make them Strict Sendable safe. Result: One step towards strict concurrency --- Package.swift | 8 ++++++- Sources/NIOConcurrencyHelpers/NIOAtomic.swift | 18 +++++++++++++++ Sources/NIOConcurrencyHelpers/atomics.swift | 23 +++++++++++++++++++ 3 files changed, 48 insertions(+), 1 deletion(-) diff --git a/Package.swift b/Package.swift index 89277a203b..af1ef62bee 100644 --- a/Package.swift +++ b/Package.swift @@ -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. @@ -150,7 +155,8 @@ let package = Package( name: "NIOConcurrencyHelpers", dependencies: [ "CNIOAtomics" - ] + ], + swiftSettings: strictConcurrencySettings ), .target( name: "NIOHTTP1", diff --git a/Sources/NIOConcurrencyHelpers/NIOAtomic.swift b/Sources/NIOConcurrencyHelpers/NIOAtomic.swift index c718b5105e..b67e6847d8 100644 --- a/Sources/NIOConcurrencyHelpers/NIOAtomic.swift +++ b/Sources/NIOConcurrencyHelpers/NIOAtomic.swift @@ -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, Self) -> Void { + get + } + static var nio_atomic_compare_and_exchange: @Sendable (UnsafeMutablePointer, Self, Self) -> Bool { + get + } + static var nio_atomic_add: @Sendable (UnsafeMutablePointer, Self) -> Self { get } + static var nio_atomic_sub: @Sendable (UnsafeMutablePointer, Self) -> Self { get } + static var nio_atomic_exchange: @Sendable (UnsafeMutablePointer, Self) -> Self { get } + static var nio_atomic_load: @Sendable (UnsafeMutablePointer) -> Self { get } + static var nio_atomic_store: @Sendable (UnsafeMutablePointer, Self) -> Void { get } +} +#else public protocol NIOAtomicPrimitive { associatedtype AtomicWrapper static var nio_atomic_create_with_existing_storage: (UnsafeMutablePointer, Self) -> Void { get } @@ -29,6 +46,7 @@ public protocol NIOAtomicPrimitive { static var nio_atomic_load: (UnsafeMutablePointer) -> Self { get } static var nio_atomic_store: (UnsafeMutablePointer, Self) -> Void { get } } +#endif extension Bool: NIOAtomicPrimitive { public typealias AtomicWrapper = catmc_nio_atomic__Bool diff --git a/Sources/NIOConcurrencyHelpers/atomics.swift b/Sources/NIOConcurrencyHelpers/atomics.swift index 65488b0162..afc8e25c8d 100644 --- a/Sources/NIOConcurrencyHelpers/atomics.swift +++ b/Sources/NIOConcurrencyHelpers/atomics.swift @@ -165,6 +165,9 @@ public struct UnsafeEmbeddedAtomic { } } +@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: @@ -284,11 +287,27 @@ public final class Atomic { } } +@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 } @@ -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 @@ -597,3 +617,6 @@ public final class AtomicBox { _ = self.exchange(with: value) } } + +@available(*, deprecated) +extension AtomicBox: @unchecked Sendable where T: Sendable {}