From 29e6528b73bf82c386f2d6560859dd75edfbd898 Mon Sep 17 00:00:00 2001 From: David Nadoba Date: Fri, 27 Oct 2023 11:28:00 +0100 Subject: [PATCH] Add explicit `Sendable` unavailability and add missing `Sendable` conformances Found with `-require-explicit-sendable` compiler flag. We may want to enable this flag in CI but it currently warns also for internal types that are @usableFromInline but we could mark them explicitly as well if we wanted. --- .../AsyncChannel/AsyncChannelInboundStream.swift | 2 +- .../AsyncChannelOutboundWriter.swift | 3 +++ .../NIOAsyncSequenceProducer.swift | 2 +- .../NIOCore/AsyncSequences/NIOAsyncWriter.swift | 5 ++++- .../NIOThrowingAsyncSequenceProducer.swift | 2 +- Sources/NIOCore/BSDSocketAPI.swift | 2 +- Sources/NIOCore/Channel.swift | 2 +- Sources/NIOCore/ChannelOption.swift | 4 ++-- Sources/NIOCore/FileHandle.swift | 3 +++ Sources/NIOCore/GlobalSingletons.swift | 2 +- Sources/NIOCore/IO.swift | 2 +- Sources/NIOCore/IPProtocol.swift | 2 +- Sources/NIOCore/Interfaces.swift | 2 +- Sources/NIOCore/UniversalBootstrapSupport.swift | 8 ++++++++ Sources/NIOCore/Utilities.swift | 2 +- Sources/NIOEmbedded/AsyncTestingChannel.swift | 3 ++- Sources/NIOEmbedded/Embedded.swift | 8 ++++++++ Sources/NIOPosix/BSDSocketAPICommon.swift | 2 +- Sources/NIOPosix/Bootstrap.swift | 16 ++++++++-------- Sources/NIOPosix/NIOThreadPool.swift | 2 +- Sources/NIOPosix/NonBlockingFileIO.swift | 2 +- Sources/_NIODataStructures/_TinyArray.swift | 2 ++ 22 files changed, 53 insertions(+), 25 deletions(-) diff --git a/Sources/NIOCore/AsyncChannel/AsyncChannelInboundStream.swift b/Sources/NIOCore/AsyncChannel/AsyncChannelInboundStream.swift index fb713929f6..9f16c33d3e 100644 --- a/Sources/NIOCore/AsyncChannel/AsyncChannelInboundStream.swift +++ b/Sources/NIOCore/AsyncChannel/AsyncChannelInboundStream.swift @@ -21,7 +21,7 @@ public struct NIOAsyncChannelInboundStream: Sendable { typealias Producer = NIOThrowingAsyncSequenceProducer /// A source used for driving a ``NIOAsyncChannelInboundStream`` during tests. - public struct TestSource { + public struct TestSource: Sendable{ @usableFromInline internal let continuation: AsyncThrowingStream.Continuation diff --git a/Sources/NIOCore/AsyncChannel/AsyncChannelOutboundWriter.swift b/Sources/NIOCore/AsyncChannel/AsyncChannelOutboundWriter.swift index 50e4d2ad4d..0f2e8e7c2a 100644 --- a/Sources/NIOCore/AsyncChannel/AsyncChannelOutboundWriter.swift +++ b/Sources/NIOCore/AsyncChannel/AsyncChannelOutboundWriter.swift @@ -162,3 +162,6 @@ public struct NIOAsyncChannelOutboundWriter: Sendable { @available(macOS 10.15, iOS 13, tvOS 13, watchOS 6, *) extension NIOAsyncChannelOutboundWriter.TestSink: Sendable {} + +@available(*, unavailable) +extension NIOAsyncChannelOutboundWriter.TestSink.AsyncIterator: Sendable { } diff --git a/Sources/NIOCore/AsyncSequences/NIOAsyncSequenceProducer.swift b/Sources/NIOCore/AsyncSequences/NIOAsyncSequenceProducer.swift index ba39820021..d651ba6fbc 100644 --- a/Sources/NIOCore/AsyncSequences/NIOAsyncSequenceProducer.swift +++ b/Sources/NIOCore/AsyncSequences/NIOAsyncSequenceProducer.swift @@ -251,7 +251,7 @@ extension NIOAsyncSequenceProducer { } /// The result of a call to ``NIOAsyncSequenceProducer/Source/yield(_:)``. - public enum YieldResult: Hashable { + public enum YieldResult: Hashable, Sendable { /// Indicates that the caller should produce more elements for now. The delegate's ``NIOAsyncSequenceProducerDelegate/produceMore()`` /// will **NOT** get called, since the demand was already signalled through this ``NIOAsyncSequenceProducer/Source/YieldResult``. case produceMore diff --git a/Sources/NIOCore/AsyncSequences/NIOAsyncWriter.swift b/Sources/NIOCore/AsyncSequences/NIOAsyncWriter.swift index a2e6fdae67..86b6b04118 100644 --- a/Sources/NIOCore/AsyncSequences/NIOAsyncWriter.swift +++ b/Sources/NIOCore/AsyncSequences/NIOAsyncWriter.swift @@ -147,7 +147,7 @@ public struct NIOAsyncWriter< /// This struct contains two properties: /// 1. The ``sink`` which should be retained by the consumer and is used to set the writability. /// 2. The ``writer`` which is the actual ``NIOAsyncWriter`` and should be passed to the producer. - public struct NewWriter { + public struct NewWriter: @unchecked Sendable { /// The ``sink`` which **MUST** be retained by the consumer and is used to set the writability. public let sink: Sink /// The ``writer`` which is the actual ``NIOAsyncWriter`` and should be passed to the producer. @@ -376,6 +376,9 @@ extension NIOAsyncWriter { } } +@available(*, unavailable) +extension NIOAsyncWriter.Sink: Sendable { } + @available(macOS 10.15, iOS 13, tvOS 13, watchOS 6, *) extension NIOAsyncWriter { /// This is the underlying storage of the writer. The goal of this is to synchronize the access to all state. diff --git a/Sources/NIOCore/AsyncSequences/NIOThrowingAsyncSequenceProducer.swift b/Sources/NIOCore/AsyncSequences/NIOThrowingAsyncSequenceProducer.swift index 3b5e2776ad..d63571a6e6 100644 --- a/Sources/NIOCore/AsyncSequences/NIOThrowingAsyncSequenceProducer.swift +++ b/Sources/NIOCore/AsyncSequences/NIOThrowingAsyncSequenceProducer.swift @@ -264,7 +264,7 @@ extension NIOThrowingAsyncSequenceProducer { } /// The result of a call to ``NIOThrowingAsyncSequenceProducer/Source/yield(_:)``. - public enum YieldResult: Hashable { + public enum YieldResult: Hashable, Sendable { /// Indicates that the caller should produce more elements. case produceMore /// Indicates that the caller should stop producing elements. diff --git a/Sources/NIOCore/BSDSocketAPI.swift b/Sources/NIOCore/BSDSocketAPI.swift index c370644eca..6a4a2d7d24 100644 --- a/Sources/NIOCore/BSDSocketAPI.swift +++ b/Sources/NIOCore/BSDSocketAPI.swift @@ -93,7 +93,7 @@ let SO_TIMESTAMP = CNIOLinux_SO_TIMESTAMP let SO_RCVTIMEO = CNIOLinux_SO_RCVTIMEO #endif -public enum NIOBSDSocket { +public enum NIOBSDSocket: Sendable{ #if os(Windows) public typealias Handle = SOCKET #else diff --git a/Sources/NIOCore/Channel.swift b/Sources/NIOCore/Channel.swift index d61e3b7dcf..3e10d9412c 100644 --- a/Sources/NIOCore/Channel.swift +++ b/Sources/NIOCore/Channel.swift @@ -378,7 +378,7 @@ extension ChannelError: Equatable { } /// The removal of a `ChannelHandler` using `ChannelPipeline.removeHandler` has been attempted more than once. public struct NIOAttemptedToRemoveHandlerMultipleTimesError: Error {} -public enum DatagramChannelError { +public enum DatagramChannelError: Sendable { public struct WriteOnUnconnectedSocketWithoutAddress: Error { public init() {} } diff --git a/Sources/NIOCore/ChannelOption.swift b/Sources/NIOCore/ChannelOption.swift index 5f1f2f6adc..5468d4deed 100644 --- a/Sources/NIOCore/ChannelOption.swift +++ b/Sources/NIOCore/ChannelOption.swift @@ -64,7 +64,7 @@ public typealias ConnectTimeoutOption = ChannelOptions.Types.ConnectTimeoutOptio public typealias AllowRemoteHalfClosureOption = ChannelOptions.Types.AllowRemoteHalfClosureOption extension ChannelOptions { - public enum Types { + public enum Types: Sendable { /// `SocketOption` allows users to specify configuration settings that are directly applied to the underlying socket file descriptor. /// @@ -291,7 +291,7 @@ extension ChannelOptions { } /// Provides `ChannelOption`s to be used with a `Channel`, `Bootstrap` or `ServerBootstrap`. -public struct ChannelOptions { +public struct ChannelOptions: Sendable { #if !os(Windows) public static let socket = { (level: SocketOptionLevel, name: SocketOptionName) -> Types.SocketOption in .init(level: NIOBSDSocket.OptionLevel(rawValue: CInt(level)), name: NIOBSDSocket.Option(rawValue: CInt(name))) diff --git a/Sources/NIOCore/FileHandle.swift b/Sources/NIOCore/FileHandle.swift index b9de95175a..d6f627e214 100644 --- a/Sources/NIOCore/FileHandle.swift +++ b/Sources/NIOCore/FileHandle.swift @@ -97,6 +97,9 @@ public final class NIOFileHandle: FileDescriptor { } } +@available(*, unavailable) +extension NIOFileHandle: Sendable { } + extension NIOFileHandle { /// `Mode` represents file access modes. public struct Mode: OptionSet, Sendable { diff --git a/Sources/NIOCore/GlobalSingletons.swift b/Sources/NIOCore/GlobalSingletons.swift index 79e752a74e..6c8d9ce3a4 100644 --- a/Sources/NIOCore/GlobalSingletons.swift +++ b/Sources/NIOCore/GlobalSingletons.swift @@ -33,7 +33,7 @@ import Musl /// `NIOSingletons.singletonsEnabledSuggestion = false`. All singleton-creating facilities should check /// this setting and if `false` restrain from creating any global singleton resources. Please note that disabling the /// global singletons will lead to a crash if _any_ code attempts to use any of the singletons. -public enum NIOSingletons { +public enum NIOSingletons: Sendable { } extension NIOSingletons { diff --git a/Sources/NIOCore/IO.swift b/Sources/NIOCore/IO.swift index 4377154317..1e67ae5163 100644 --- a/Sources/NIOCore/IO.swift +++ b/Sources/NIOCore/IO.swift @@ -39,7 +39,7 @@ import Darwin /// An `Error` for an IO operation. public struct IOError: Swift.Error { @available(*, deprecated, message: "NIO no longer uses FailureDescription.") - public enum FailureDescription { + public enum FailureDescription : Sendable{ case function(StaticString) case reason(String) } diff --git a/Sources/NIOCore/IPProtocol.swift b/Sources/NIOCore/IPProtocol.swift index 27e11de783..1452fb2b4a 100644 --- a/Sources/NIOCore/IPProtocol.swift +++ b/Sources/NIOCore/IPProtocol.swift @@ -16,7 +16,7 @@ /// called "Protocol" to identify the next level protocol. This is an 8 /// bit field. In Internet Protocol version 6 (IPv6) [RFC8200], this field /// is called the "Next Header" field. -public struct NIOIPProtocol: RawRepresentable, Hashable { +public struct NIOIPProtocol: RawRepresentable, Hashable, Sendable { public typealias RawValue = UInt8 public var rawValue: RawValue diff --git a/Sources/NIOCore/Interfaces.swift b/Sources/NIOCore/Interfaces.swift index 1c656db020..98ae22508b 100644 --- a/Sources/NIOCore/Interfaces.swift +++ b/Sources/NIOCore/Interfaces.swift @@ -64,7 +64,7 @@ private extension ifaddrs { /// A representation of a single network interface on a system. @available(*, deprecated, renamed: "NIONetworkDevice") -public final class NIONetworkInterface { +public final class NIONetworkInterface: Sendable{ // This is a class because in almost all cases this will carry // four structs that are backed by classes, and so will incur 4 // refcount operations each time it is copied. diff --git a/Sources/NIOCore/UniversalBootstrapSupport.swift b/Sources/NIOCore/UniversalBootstrapSupport.swift index b89594a201..c89c7d1fcf 100644 --- a/Sources/NIOCore/UniversalBootstrapSupport.swift +++ b/Sources/NIOCore/UniversalBootstrapSupport.swift @@ -248,6 +248,10 @@ public struct NIOClientTCPBootstrap { } } +@available(*, unavailable) +extension NIOClientTCPBootstrap: Sendable { } + + public protocol NIOClientTLSProvider { associatedtype Bootstrap @@ -261,3 +265,7 @@ public struct NIOInsecureNoTLS: NIOCli fatalError("NIOInsecureNoTLS cannot enable TLS.") } } + +@available(*, unavailable) +extension NIOInsecureNoTLS: Sendable { } + diff --git a/Sources/NIOCore/Utilities.swift b/Sources/NIOCore/Utilities.swift index f00ae18ecc..db17fdcaf9 100644 --- a/Sources/NIOCore/Utilities.swift +++ b/Sources/NIOCore/Utilities.swift @@ -60,7 +60,7 @@ final class Box { extension Box: Sendable where T: Sendable {} -public enum System { +public enum System: Sendable { /// A utility function that returns an estimate of the number of *logical* cores /// on the system available for use. /// diff --git a/Sources/NIOEmbedded/AsyncTestingChannel.swift b/Sources/NIOEmbedded/AsyncTestingChannel.swift index 3324db25d7..ba14d5eb2e 100644 --- a/Sources/NIOEmbedded/AsyncTestingChannel.swift +++ b/Sources/NIOEmbedded/AsyncTestingChannel.swift @@ -611,7 +611,7 @@ public final class NIOAsyncTestingChannel: Channel { } } - public struct SynchronousOptions: NIOSynchronousChannelOptions { + public struct SynchronousOptions: NIOSynchronousChannelOptions, Sendable { @usableFromInline internal let channel: NIOAsyncTestingChannel @@ -637,6 +637,7 @@ public final class NIOAsyncTestingChannel: Channel { } } + // MARK: Unchecked sendable // // Both of these types are unchecked Sendable because strictly, they aren't. This is diff --git a/Sources/NIOEmbedded/Embedded.swift b/Sources/NIOEmbedded/Embedded.swift index 4a8ce0d218..e7b44aaef5 100644 --- a/Sources/NIOEmbedded/Embedded.swift +++ b/Sources/NIOEmbedded/Embedded.swift @@ -857,6 +857,14 @@ public final class EmbeddedChannel: Channel { } } +// Stores NIOAny which isn't Sendable +@available(*, unavailable) +extension EmbeddedChannel.LeftOverState: Sendable { } + +// Stores NIOAny which isn't Sendable +@available(*, unavailable) +extension EmbeddedChannel.BufferState: Sendable { } + extension EmbeddedChannel { public struct SynchronousOptions: NIOSynchronousChannelOptions { @usableFromInline diff --git a/Sources/NIOPosix/BSDSocketAPICommon.swift b/Sources/NIOPosix/BSDSocketAPICommon.swift index 539136cc26..f274eadbdd 100644 --- a/Sources/NIOPosix/BSDSocketAPICommon.swift +++ b/Sources/NIOPosix/BSDSocketAPICommon.swift @@ -142,7 +142,7 @@ extension NIOBSDSocket { /// They aren't necessarily protocols in their own right: for example, ``mptcp`` /// is not. They act to modify the socket type instead: thus, ``mptcp`` acts /// to modify `SOCK_STREAM` to ask for ``mptcp`` support. - public struct ProtocolSubtype: RawRepresentable, Hashable { + public struct ProtocolSubtype: RawRepresentable, Hashable, Sendable { public typealias RawValue = CInt /// The underlying value of the protocol subtype. diff --git a/Sources/NIOPosix/Bootstrap.swift b/Sources/NIOPosix/Bootstrap.swift index bf70b9863e..ccd86c63cd 100644 --- a/Sources/NIOPosix/Bootstrap.swift +++ b/Sources/NIOPosix/Bootstrap.swift @@ -2269,8 +2269,8 @@ extension NIOPipeBootstrap { let channelOptions = self._channelOptions let channel: PipeChannel - let inputFileHandle: NIOFileHandle? - let outputFileHandle: NIOFileHandle? + let inputFileHandle: NIOLoopBound + let outputFileHandle: NIOLoopBound do { if let input = input { try self.validateFileDescriptorIsNotAFile(input) @@ -2279,12 +2279,12 @@ extension NIOPipeBootstrap { try self.validateFileDescriptorIsNotAFile(output) } - inputFileHandle = input.flatMap { NIOFileHandle(descriptor: $0) } - outputFileHandle = output.flatMap { NIOFileHandle(descriptor: $0) } + inputFileHandle = NIOLoopBound(input.flatMap { NIOFileHandle(descriptor: $0) }, eventLoop: eventLoop) + outputFileHandle = NIOLoopBound(output.flatMap { NIOFileHandle(descriptor: $0) }, eventLoop: eventLoop) channel = try PipeChannel( eventLoop: eventLoop as! SelectableEventLoop, - inputPipe: inputFileHandle, - outputPipe: outputFileHandle + inputPipe: inputFileHandle.value, + outputPipe: outputFileHandle.value ) } catch { return eventLoop.makeFailedFuture(error) @@ -2302,10 +2302,10 @@ extension NIOPipeBootstrap { channel.registerAlreadyConfigured0(promise: promise) return promise.futureResult.map { result } }.flatMap { result -> EventLoopFuture in - if inputFileHandle == nil { + if inputFileHandle.value == nil { return channel.close(mode: .input).map { result } } - if outputFileHandle == nil { + if outputFileHandle.value == nil { return channel.close(mode: .output).map { result } } return channel.selectableEventLoop.makeSucceededFuture(result) diff --git a/Sources/NIOPosix/NIOThreadPool.swift b/Sources/NIOPosix/NIOThreadPool.swift index 6d29801894..1e8d79681f 100644 --- a/Sources/NIOPosix/NIOThreadPool.swift +++ b/Sources/NIOPosix/NIOThreadPool.swift @@ -17,7 +17,7 @@ import NIOCore import NIOConcurrencyHelpers /// Errors that may be thrown when executing work on a `NIOThreadPool` -public enum NIOThreadPoolError { +public enum NIOThreadPoolError: Sendable{ /// The `NIOThreadPool` was not active. public struct ThreadPoolInactive: Error { diff --git a/Sources/NIOPosix/NonBlockingFileIO.swift b/Sources/NIOPosix/NonBlockingFileIO.swift index 2e07175bc3..559236d89d 100644 --- a/Sources/NIOPosix/NonBlockingFileIO.swift +++ b/Sources/NIOPosix/NonBlockingFileIO.swift @@ -697,7 +697,7 @@ public struct NonBlockingFileIO: Sendable { #if !os(Windows) /// A `NIODirectoryEntry` represents a single directory entry. -public struct NIODirectoryEntry: Hashable { +public struct NIODirectoryEntry: Hashable, Sendable { // File number of entry public var ino: UInt64 // File type diff --git a/Sources/_NIODataStructures/_TinyArray.swift b/Sources/_NIODataStructures/_TinyArray.swift index bc1c154b6a..b7d2606077 100644 --- a/Sources/_NIODataStructures/_TinyArray.swift +++ b/Sources/_NIODataStructures/_TinyArray.swift @@ -99,6 +99,8 @@ extension _TinyArray: RandomAccessCollection { } } +extension _TinyArray.Iterator: Sendable where Element: Sendable {} + extension _TinyArray { @inlinable public init(_ elements: some Sequence) {