From a849d50ce633e92a954c5d5c50ab727cb8faecb9 Mon Sep 17 00:00:00 2001 From: Cory Benfield Date: Mon, 3 Feb 2025 11:25:02 +0000 Subject: [PATCH 1/9] Opt NIO module into Strict Concurrency (#3097) Motivation: Honestly these little modules are pretty mechanical now. Modifications: Add the strict concurrency flags to a module with nothing in it. Result: Become even more automatic from way downtown. --- Package.swift | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Package.swift b/Package.swift index 74d00fc68a..a68614687d 100644 --- a/Package.swift +++ b/Package.swift @@ -129,7 +129,8 @@ let package = Package( "NIOCore", "NIOEmbedded", "NIOPosix", - ] + ], + swiftSettings: strictConcurrencySettings ), .target( name: "_NIOConcurrency", From 8bf3316c377612594d0d88dae2c4541f845c003a Mon Sep 17 00:00:00 2001 From: Cory Benfield Date: Mon, 3 Feb 2025 11:49:56 +0000 Subject: [PATCH 2/9] Clean up concurrency in NIOEchoClient (#3099) Motivation: We're getting to the examples now! This patch updates NIOEchoClient to be clean under strict concurrency. Modifications: Use the sync operations to add echo handler. Result: Another strict concurrency module. Co-authored-by: George Barnett --- Package.swift | 3 ++- Sources/NIOEchoClient/main.swift | 4 +++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/Package.swift b/Package.swift index a68614687d..931bc28161 100644 --- a/Package.swift +++ b/Package.swift @@ -301,7 +301,8 @@ let package = Package( "NIOCore", "NIOConcurrencyHelpers", ], - exclude: ["README.md"] + exclude: ["README.md"], + swiftSettings: strictConcurrencySettings ), .executableTarget( name: "NIOHTTP1Server", diff --git a/Sources/NIOEchoClient/main.swift b/Sources/NIOEchoClient/main.swift index d7de8eb35b..e92ebc02ff 100644 --- a/Sources/NIOEchoClient/main.swift +++ b/Sources/NIOEchoClient/main.swift @@ -58,7 +58,9 @@ let bootstrap = ClientBootstrap(group: group) // Enable SO_REUSEADDR. .channelOption(.socketOption(.so_reuseaddr), value: 1) .channelInitializer { channel in - channel.pipeline.addHandler(EchoHandler()) + channel.eventLoop.makeCompletedFuture { + try channel.pipeline.syncOperations.addHandler(EchoHandler()) + } } defer { try! group.syncShutdownGracefully() From d273f906fe4819e74e45dc086425fd48ae8c1097 Mon Sep 17 00:00:00 2001 From: Cory Benfield Date: Mon, 3 Feb 2025 12:56:02 +0000 Subject: [PATCH 3/9] Add strict concurrency to NIOUDPEchoServer (#3101) Motivation: Another strict concurrency change, another echo handler. Modifications: Move to sync operations. Result: Another step on strict concurrency. --- Package.swift | 3 ++- Sources/NIOUDPEchoServer/main.swift | 5 +++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/Package.swift b/Package.swift index 931bc28161..863c3f4016 100644 --- a/Package.swift +++ b/Package.swift @@ -375,7 +375,8 @@ let package = Package( "NIOPosix", "NIOCore", ], - exclude: ["README.md"] + exclude: ["README.md"], + swiftSettings: strictConcurrencySettings ), .executableTarget( name: "NIOUDPEchoClient", diff --git a/Sources/NIOUDPEchoServer/main.swift b/Sources/NIOUDPEchoServer/main.swift index a33de6780b..f8dd508577 100644 --- a/Sources/NIOUDPEchoServer/main.swift +++ b/Sources/NIOUDPEchoServer/main.swift @@ -47,8 +47,9 @@ var bootstrap = DatagramBootstrap(group: group) // Set the handlers that are applied to the bound channel .channelInitializer { channel in - // Ensure we don't read faster than we can write by adding the BackPressureHandler into the pipeline. - channel.pipeline.addHandler(EchoHandler()) + channel.eventLoop.makeCompletedFuture { + try channel.pipeline.syncOperations.addHandler(EchoHandler()) + } } defer { From aa360ab8e895d1f16160a5e7feca9b8d59224fd1 Mon Sep 17 00:00:00 2001 From: Cory Benfield Date: Mon, 3 Feb 2025 13:55:41 +0000 Subject: [PATCH 4/9] Lock in strict concurrency in NIOEchoServer (#3100) Motivation: Prior patches actually removed all the issues in NIOEchoServer, so let's bank the win. Modifications: Added strict concurrency checking to NIOEchoServer Result: More stricter. --- Package.swift | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Package.swift b/Package.swift index 863c3f4016..585fd34718 100644 --- a/Package.swift +++ b/Package.swift @@ -292,7 +292,8 @@ let package = Package( "NIOCore", "NIOConcurrencyHelpers", ], - exclude: ["README.md"] + exclude: ["README.md"], + swiftSettings: strictConcurrencySettings ), .executableTarget( name: "NIOEchoClient", From 9a181b3aae48f7297cb3636b2fce6d0e1cbf2c54 Mon Sep 17 00:00:00 2001 From: Cory Benfield Date: Mon, 3 Feb 2025 14:22:56 +0000 Subject: [PATCH 5/9] Update NIOUDPEchoClient for strict concurrency (#3102) Motivation: NIOUDPEchoClient should be strict concurrency clean. Modifications: Annotate one closure @Sendable to convince Swift it's ok. Result: Strict concurrency clean in NIOUDPEchoClient. --- Package.swift | 3 ++- Sources/NIOUDPEchoClient/main.swift | 6 ++++-- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/Package.swift b/Package.swift index 585fd34718..7c7378bf75 100644 --- a/Package.swift +++ b/Package.swift @@ -385,7 +385,8 @@ let package = Package( "NIOPosix", "NIOCore", ], - exclude: ["README.md"] + exclude: ["README.md"], + swiftSettings: strictConcurrencySettings ), .executableTarget( name: "NIOAsyncAwaitDemo", diff --git a/Sources/NIOUDPEchoClient/main.swift b/Sources/NIOUDPEchoClient/main.swift index 3a74de9d04..9d131b8899 100644 --- a/Sources/NIOUDPEchoClient/main.swift +++ b/Sources/NIOUDPEchoClient/main.swift @@ -115,7 +115,7 @@ default: connectTarget = .ip(host: defaultHost, sendPort: defaultServerPort, listeningPort: defaultListeningPort) } -let remoteAddress = { () -> SocketAddress in +let remoteAddress = { @Sendable () -> SocketAddress in switch connectTarget { case .ip(let host, let sendPort, _): return try SocketAddress.makeAddressResolvingHost(host, port: sendPort) @@ -129,7 +129,9 @@ let bootstrap = DatagramBootstrap(group: group) // Enable SO_REUSEADDR. .channelOption(.socketOption(.so_reuseaddr), value: 1) .channelInitializer { channel in - channel.pipeline.addHandler(EchoHandler(remoteAddressInitializer: remoteAddress)) + channel.eventLoop.makeCompletedFuture { + try channel.pipeline.syncOperations.addHandler(EchoHandler(remoteAddressInitializer: remoteAddress)) + } } defer { try! group.syncShutdownGracefully() From 0bc48ebbc574eca23c02af17886dc0e57a879876 Mon Sep 17 00:00:00 2001 From: Cory Benfield Date: Mon, 3 Feb 2025 15:20:45 +0000 Subject: [PATCH 6/9] Strict concurrency for TCP examples (#3103) Motivation: Two more examples with no changes required. Modifications: Lock in strict concurrency for NIOTCPEchoClient and NIOTCPEchoServer. Result: Even more stricter concurrencier. --- Package.swift | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/Package.swift b/Package.swift index 7c7378bf75..96f4a3a074 100644 --- a/Package.swift +++ b/Package.swift @@ -275,7 +275,8 @@ let package = Package( "NIOPosix", "NIOCore", ], - exclude: ["README.md"] + exclude: ["README.md"], + swiftSettings: strictConcurrencySettings ), .executableTarget( name: "NIOTCPEchoClient", @@ -283,7 +284,8 @@ let package = Package( "NIOPosix", "NIOCore", ], - exclude: ["README.md"] + exclude: ["README.md"], + swiftSettings: strictConcurrencySettings ), .executableTarget( name: "NIOEchoServer", From 8f19d80751978af1448ab2dde781a7b8c2d5e877 Mon Sep 17 00:00:00 2001 From: Cory Benfield Date: Mon, 3 Feb 2025 16:04:40 +0000 Subject: [PATCH 7/9] Strict concurrency for the chat examples (#3104) Motivation: Our next suite of examples for strict concurrency are the chat ones. These are very similar to the rest: either no violation at all, or just a need to use the sync operations on pipeline setup. Modifications: - Use sync operations - Lock in strict concurrency checking Result: We continue our march. Co-authored-by: Rick Newton-Rogers --- Package.swift | 9 ++++++--- Sources/NIOChatClient/main.swift | 18 +++++------------- Sources/NIOMulticastChat/main.swift | 4 ++-- 3 files changed, 13 insertions(+), 18 deletions(-) diff --git a/Package.swift b/Package.swift index 96f4a3a074..fdccf75965 100644 --- a/Package.swift +++ b/Package.swift @@ -334,7 +334,8 @@ let package = Package( "NIOCore", "NIOConcurrencyHelpers", ], - exclude: ["README.md"] + exclude: ["README.md"], + swiftSettings: strictConcurrencySettings ), .executableTarget( name: "NIOChatClient", @@ -343,7 +344,8 @@ let package = Package( "NIOCore", "NIOConcurrencyHelpers", ], - exclude: ["README.md"] + exclude: ["README.md"], + swiftSettings: strictConcurrencySettings ), .executableTarget( name: "NIOWebSocketServer", @@ -370,7 +372,8 @@ let package = Package( dependencies: [ "NIOPosix", "NIOCore", - ] + ], + swiftSettings: strictConcurrencySettings ), .executableTarget( name: "NIOUDPEchoServer", diff --git a/Sources/NIOChatClient/main.swift b/Sources/NIOChatClient/main.swift index c41250e39d..a350bf14bf 100644 --- a/Sources/NIOChatClient/main.swift +++ b/Sources/NIOChatClient/main.swift @@ -18,19 +18,9 @@ private final class ChatHandler: ChannelInboundHandler { public typealias InboundIn = ByteBuffer public typealias OutboundOut = ByteBuffer - private func printByte(_ byte: UInt8) { - #if os(Android) - print(Character(UnicodeScalar(byte)), terminator: "") - #else - fputc(Int32(byte), stdout) - #endif - } - public func channelRead(context: ChannelHandlerContext, data: NIOAny) { - var buffer = Self.unwrapInboundIn(data) - while let byte: UInt8 = buffer.readInteger() { - printByte(byte) - } + let buffer = Self.unwrapInboundIn(data) + print(String(buffer: buffer)) } public func errorCaught(context: ChannelHandlerContext, error: Error) { @@ -47,7 +37,9 @@ let bootstrap = ClientBootstrap(group: group) // Enable SO_REUSEADDR. .channelOption(.socketOption(.so_reuseaddr), value: 1) .channelInitializer { channel in - channel.pipeline.addHandler(ChatHandler()) + channel.eventLoop.makeCompletedFuture { + try channel.pipeline.syncOperations.addHandler(ChatHandler()) + } } defer { try! group.syncShutdownGracefully() diff --git a/Sources/NIOMulticastChat/main.swift b/Sources/NIOMulticastChat/main.swift index 7d3298ee7e..94316e5ecd 100644 --- a/Sources/NIOMulticastChat/main.swift +++ b/Sources/NIOMulticastChat/main.swift @@ -72,8 +72,8 @@ let group = MultiThreadedEventLoopGroup(numberOfThreads: 1) var datagramBootstrap = DatagramBootstrap(group: group) .channelOption(.socketOption(.so_reuseaddr), value: 1) .channelInitializer { channel in - channel.pipeline.addHandler(ChatMessageEncoder()).flatMap { - channel.pipeline.addHandler(ChatMessageDecoder()) + channel.eventLoop.makeCompletedFuture { + try channel.pipeline.syncOperations.addHandlers(ChatMessageEncoder(), ChatMessageDecoder()) } } From e2bfa2fc75665f716f48cb321554d4d06a3e9692 Mon Sep 17 00:00:00 2001 From: Cory Benfield Date: Mon, 3 Feb 2025 16:32:55 +0000 Subject: [PATCH 8/9] Strict concurrency enablement for some test targets (#3105) Motivation: A few more low-hanging-fruit test targets. Modifications: Enable strict concurrency for: - NIOFoundationCompatTests - NIOSingletonsTests Result: We're knocking down those targets, one by one. --- Package.swift | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/Package.swift b/Package.swift index fdccf75965..ea463d8ba9 100644 --- a/Package.swift +++ b/Package.swift @@ -521,7 +521,8 @@ let package = Package( dependencies: [ "NIOCore", "NIOFoundationCompat", - ] + ], + swiftSettings: strictConcurrencySettings ), .testTarget( name: "NIOTests", @@ -529,7 +530,8 @@ let package = Package( ), .testTarget( name: "NIOSingletonsTests", - dependencies: ["NIOCore", "NIOPosix"] + dependencies: ["NIOCore", "NIOPosix"], + swiftSettings: strictConcurrencySettings ), .testTarget( name: "NIOFileSystemTests", From 2f1c7800e41cd4866bb25aeec704a699540cf663 Mon Sep 17 00:00:00 2001 From: Cory Benfield Date: Mon, 3 Feb 2025 16:57:45 +0000 Subject: [PATCH 9/9] Strict concurrency for NIOTests (#3106) Motivation: NIOTests was already warning free, now we're just going to make sure of it. Modifications: Enable strict concurrency for NIOTests Result: Our relentless safety march continues. --- Package.swift | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Package.swift b/Package.swift index ea463d8ba9..a4c9ee7426 100644 --- a/Package.swift +++ b/Package.swift @@ -526,7 +526,8 @@ let package = Package( ), .testTarget( name: "NIOTests", - dependencies: ["NIO"] + dependencies: ["NIO"], + swiftSettings: strictConcurrencySettings ), .testTarget( name: "NIOSingletonsTests",