Tags: apple/swift-nio
Tags
NIOSendableBox: allow off-loop initialisation iff Value is Sendable (#… …2753) ### Motivation: `NIOLoopBound` and `NIOLoopBoundBox` are important tools for making mutable types `Sendable`. The power of `NIOLoopBoundBox` is that it allows correct mutation, whilst remaining `Sendable` without locks and without having to use `@unchecked` if the mutable class makes sure to have all accesses (reading & writing) run on one particular `EventLoop`. This is safe as `EventLoop`s guarantee sequentially consistent memory order across executions of different work items/events. Typically `EventLoop`s achieve this by just being thread-bound. These types are well used already but there's a small and common pattern which is safe but unsupported as of yet: Initialise a `NIOLoopBoundBox` with a `Sendable` value _off_ the loop. All further accesses (reads & writes) however happen _on_ the loop. That's safe because of Swift's Definitive Initialisation (DI) but `NIOLoopBoundBox` didn't support this pattern (apart from `makeEmptyBox` which always initialises with `nil`). ### Modifications: - Allow `Sendable` values to be provided whilst creating the type off loop. ### Result: - Even more types can be safely & correctly made `Sendable` without using `@unchecked.
Add a fallback path if renameat2 fails (#2733) Motivation: 'renameat2' can fail with EINVAL if the RENAME_NOREPLACE flag isn't supported. However, not all kernel versions support this flag which can result in an error when creating a file 'transactionally'. Using 'renameat2' only happens on Linux as a fallback when O_TMPFILE isn't available. Modifications: - On Linux, fallback to a combination of 'stat' and 'rename' if 'renameat2' fails with EINVAL. - Add a couple of tests Result: Files can still be created exclusively
Retain a ref to NIOAsyncWriter until channel active (#2703) Motivation: NIOAsyncChannel requires users to explicitly close it, this is typically done by calling `executeThenClose`. If a `NIOAsyncChannel` isn't closed then its outbound writer will hit a precondition failure on `deinit`. Not calling `executeThenClose` is a programmer error. However there are some sharp edges: if NIO never returns the `NIOAsyncChannel` to the caller (e.g. if a connect attempt fails) then nothing will finish the writer and precondition will fail in the deinit. Working around this from a user perspective is non-obvious and requires keep tracking of all `NIOAsyncChannel`s created from a connect attempt and closing the unused ones. We still want to maintain the precondition when users don't close the channel, one way of achieving this is by defining a point in time at which NIO hands responsibility of the channel to the user. Modifications: - Retain the writer in the outbound writer handler until channel active - On successful connect attempts, the channel becomes active and the connected channel is returned to the caller. - On failed attempts channel active isn't called so the writer is retained until the handler is removed from the pipeline at which point it is finished. Result: Failed connect attempts don't result in precondition failures when using NIOAsyncChannel.
Fix memory allocations counters on macOS. (#2673) Motivation: Allocation counters are broken on macOS as described [here](#2672). This PR fixes it. Modifications: `AtomicCounter` library is made `.dynamic`. This deduplicates the two (static) copies that used to exist. One embedded in the main binary, and the other in `HookedFunctions` dylib. This deplication fixes the issue, because there is just one copy of the counters in the process address space. Result: All the tests counting allocations and related statistics work on macOS.
use feature-specific guard for @retroactive (#2581) Motivation: We should use the more granular guard for uses of @retroactive rather than coarse swift versions to guard against corner-cases Modifications: Switch `#if compiler(>=5.11)` for `#if hasFeature(RetroactiveAttribute)` Result: No change in most cases, more protected against corner-cases.
Fix exclusive access violation in `NIOAsyncChannelOutboundWriterHandl… …er` (#2580) # Motivation We were setting `self.sink = nil` in the `NIOAsyncChannelOutboundWriterHandler` twice in the same call stack which is an exclusivity violation. This happens because the first `self.sink = nil` triggers the `didTerminate` delegate call which again triggered `self.sink = nil`. # Modification This PR changes the code to only call `self.sink?.finish()` and only sets the `sink` to `nil` in the `didTerminate` implementation. This follows what we do for the inbound handler implementation. I also added a test that triggers this exclusivity violation. # Result No more exclusivity violations in our code.
Fix thread-safety issues in TCPThroughputBenchmark (#2537) Motivation: Several thread-safety issues were missed in code review. This patch fixes them. Modifications: - Removed the use of an unstructured Task, replaced with eventLoop.execute to ServerHandler's EventLoop. - Stopped ClientHandler reaching into the benchmark object without any synchronization, used promises and event loop hops instead. Result: Thread safety is back
PreviousNext