mirror of
https://github.com/apple/swift-nio.git
synced 2026-05-20 20:30:36 +00:00
expose_bytebuffer_allocator
2949
Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
661bfc5aea |
ByteBuffer custom allocator support
Motivation * Other libraries often have byte buffer storage with similar concepts as NIO's `ByteBuffer`, linear storage with reader and writer indices - it would be nice to have efficient conversion to and from these objects. * Efficienct conversion would likely mean taking ownership of the byte storage allocated by the other object and exposing `ByteBuffer`s internals so that they may be owned by another object, there is no API for this currently. Modifications * Added new methods behind `CustomByteBufferAllocator` SPI. * Added public `ByteBuffer` initializer for adopting externally-allocated memory * Made `ByteBufferAllocator` initializer public with custom `malloc`/`realloc`/`free`/`memcpy` hooks * Updated `realloc` signature to pass old capacity alongside new capacity to allow implementations to copy over bytes * Added `withVeryUnsafeMutableBytesWithStorageManagement` for mutable storage access * Updated all existing tests using internal allocator API to use the new API * Added tests for custom allocator functionality Result * Custom allocators can manage `ByteBuffer` memory with full size information * External systems can transfer memory ownership to `ByteBuffer` * System allocator maintains zero overhead due to inlining of the wrapper * API (SPI) is extensible for future allocation system integrations |
||
|
|
abe12cf13b |
Apple platforms CI issues (#3519)
Apple platform simulator CI failures ### Motivation * Several tests failed when testing against simulators for Apple platforms (iOS, tvOS, watchOS, visionOS) ### Modifications * Added `@available(macOS 13, iOS 16, tvOS 16, watchOS 9, *)` to each `@Test` method in `NIOThreadPoolTest`, `EventLoopFutureTest`, and `NIOTransportAccessibleChannelCoreTests` to match the availability of the APIs they use (`timeLimit` and `withUnsafeTransportIfAvailable`). * Removed `.timeLimit(.minutes(1))` from the `@Suite` declarations on `NIOThreadPoolTest` and `EventLoopFutureTest` - the `@Suite` macro cannot be used with `@available`, so `timeLimit` cannot be used. * Skip `testHomeDirectoryFromPasswd` on simulator targets via `#if targetEnvironment(simulator)` / `XCTSkip`, since simulators retu> success but nil information when invoking `getpwuid_r`. ### Result * Apple simulator platform builds and test runs no longer fail due to these issues. Some infrastructure issues remain to be resolved separately. |
||
|
|
8d19278bde |
Wait for the docker daemon on Windows (#3520)
Sometimes the docker daemon on Windows runners isn't ready immediately. This adds a step to wait for it to become ready. |
||
|
|
8f6f8361ff |
benchmark diff missing new threshold files (#3516)
### Motivation * When threshold files don't exist yet, `thresholds update` creates new untracked files. `git diff HEAD` only shows changes to tracked files, so newly created threshold files were silently omitted from the diff. ### Modifications * Run `git add --intent-to-add .` before `git diff HEAD` so that untracked files are registered in the index and appear in the diff output without staging their contents. ### Result * The diff output now includes newly created threshold files. |
||
|
|
83b0fcd82d |
Benchmark diffs not being output on threshold regression (#3515)
### Motivation * `check_benchmark_thresholds.sh` was updated to check for exit code 2 from `swift package benchmark thresholds check` to distinguish threshold regression from build errors. * It seems SwiftPM's `CommandPlugin` infrastructure always exits with code 1 when `performCommand` throws, regardless of the error's raw value. So the exit code is never 2, causing all regressions to fall through to the `else` branch and be misreported as build errors, with no diff output. ### Modifications * Remove the `rc == 2` check and instead attempt `thresholds update` for any non-zero `rc` from `thresholds check`. * Use the result of `thresholds update` to distinguish regression (success) from build error (failure). * Remove `--exit-code` from `git diff` to prevent `set -uo pipefail` from aborting the script before output is fully flushed. ### Result * Benchmark threshold regressions correctly output the `=== BEGIN DIFF ===` section again. * Actual build errors are still correctly detected and reported. |
||
|
|
535c2f8260 |
switch from main to 0.0.7 for swiftlang workflows (#3514)
Motivation * `@main` references to `swiftlang/github-workflows` are deprecated. Modifications * Replace `@main` with `@0.0.7` in all workflow files. Result * Workflow files reference a pinned version of `swiftlang/github-workflows`. |
||
|
|
e932d3c4d8 |
Workaround test crashing when compiled in release mode on Swift 6.2 (#3511)
### Motivation:
Our post-merge, pre-release pipelines run tests for our supported Swift
versions in both debug and release mode. The recent PR to add
`withUnsafeTransportIfAvailable` added some tests for various valid and
invalid usages of the API. One of the invalid usages was causing the
tests to crash, when compiled in release mode, in the Swift runtime:
```
% docker run --rm -it -v $PWD:/pwd -w /pwd swift:6.2 swift test --filter testUnderlyingSocketAccessForSocketBasedChannel
[1/1] Planning build
Building for debugging...
[1/1] Write swift-version-24593BA9C3E375BF.txt
Build complete! (2.38s)
Test Suite 'Selected tests' started at 2026-02-18 13:28:18.905
Test Suite 'Selected tests' passed at 2026-02-18 13:28:18.905
Executed 0 tests, with 0 failures (0 unexpected) in 0.0 (0.0) seconds
◇ Test run started.
↳ Testing Library Version: 6.2.3 (48a471ab313e858)
↳ Target Platform: aarch64-unknown-linux-gnu
◇ Suite NIOTransportAccessibleChannelCoreTests started.
◇ Test testUnderlyingSocketAccessForSocketBasedChannel() started.
✔ Test testUnderlyingSocketAccessForSocketBasedChannel() passed after 0.005 seconds.
✔ Suite NIOTransportAccessibleChannelCoreTests passed after 0.005 seconds.
✔ Test run with 1 test in 1 suite passed after 0.005 seconds.
```
```
% docker run --rm -it -v $PWD:/pwd -w /pwd swift:6.2 swift test -c release --filter testUnderlyingSocketAccessForSocketBasedChannel
[1/1] Planning build
Building for production...
[1/1] Write swift-version-24593BA9C3E375BF.txt
Build complete! (2.12s)
Test Suite 'Selected tests' started at 2026-02-18 13:27:12.102
Test Suite 'Selected tests' passed at 2026-02-18 13:27:12.103
Executed 0 tests, with 0 failures (0 unexpected) in 0.0 (0.0) seconds
◇ Test run started.
↳ Testing Library Version: 6.2.3 (48a471ab313e858)
↳ Target Platform: aarch64-unknown-linux-gnu
◇ Suite NIOTransportAccessibleChannelCoreTests started.
◇ Test testUnderlyingSocketAccessForSocketBasedChannel() started.
*** Signal 11: Backtracing from 0xffff8854b1ec... done ***
*** Program crashed: Bad pointer dereference at 0x0000000000000000 ***
Platform: arm64 Linux (Ubuntu 24.04.4 LTS)
Thread 0 "NIO-ELT-1-#1" crashed:
0 0x0000ffff8854b1ec tryCast(swift::OpaqueValue*, swift::TargetMetadata<swift::InProcess> const*, swift::OpaqueValue*, swift::TargetMetadata<swift::InProcess> const*, swift::TargetMetadata<swift::InProcess> const*&, swift::TargetMetadata<swift::InProcess> const*&, bool, bool, bool) + 52 in libswiftCore.so
1 [ra] 0x0000ffff8854b148 swift_dynamicCast + 79 in libswiftCore.so
2 [ra] [system] 0x0000aaaab8668588 specialized ChannelPipeline.SynchronousOperations.withUnsafeTransportIfAvailable<A, B>(of:_:) + 135 in swift-nioPackageTests.xctest at //<compiler-generated>
3 [ra] 0x0000aaaab8668148 closure #1 in NIOTransportAccessibleChannelCoreTests.testUnderlyingSocketAccessForSocketBasedChannel() + 3103 in swift-nioPackageTests.xctest at /tmp/swift-generated-sources/@__swiftmacro_13NIOPosixTests0049NIOTransportAccessibleChannelCoreTestsswift_IhHJqfMX55_16_33_309B77F97E02F918EDFF07092681CD49Ll6expectfMf8_.swift:1:40
4 [ra] [thunk] 0x0000aaaab866be1c partial apply for closure #1 in NIOTransportAccessibleChannelCoreTests.testUnderlyingSocketAccessForSocketBasedChannel() + 15 in swift-nioPackageTests.xctest at //<compiler-generated>
5 [ra] 0x0000aaaab7f410ec closure #1 in EventLoop.submit<A>(_:) + 95 in swift-nioPackageTests.xctest at /pwd/Sources/NIOCore/EventLoop.swift:1030:69
6 [ra] [inlined] 0x0000aaaab841d468 closure #1 in SelectableEventLoop.run(_:) in swift-nioPackageTests.xctest at /pwd/Sources/NIOPosix/SelectableEventLoop.swift:618:17
7 [ra] [inlined] 0x0000aaaab841d468 specialized withAutoReleasePool<A>(_:) in swift-nioPackageTests.xctest at /pwd/Sources/NIOPosix/SelectableEventLoop.swift:49:16
8 [ra] [inlined] 0x0000aaaab841d468 SelectableEventLoop.run(_:) in swift-nioPackageTests.xctest at /pwd/Sources/NIOPosix/SelectableEventLoop.swift:615:9
9 [ra] 0x0000aaaab841d468 SelectableEventLoop.runOneLoopTick(selfIdentifier:) + 535 in swift-nioPackageTests.xctest at /pwd/Sources/NIOPosix/SelectableEventLoop.swift:809:22
10 [ra] 0x0000aaaab8423e5c SelectableEventLoop.run() + 331 in swift-nioPackageTests.xctest at /pwd/Sources/NIOPosix/SelectableEventLoop.swift:923:38
11 [ra] [inlined] 0x0000aaaab83de614 static MultiThreadedEventLoopGroup.runTheLoop(thread:uniqueID:parentGroup:canEventLoopBeShutdownIndividually:selectorFactory:initializer:metricsDelegate:_:) in swift-nioPackageTests.xctest at /pwd/Sources/NIOPosix/MultiThreadedEventLoopGroup.swift:117:22
12 [ra] 0x0000aaaab83de614 closure #1 in static MultiThreadedEventLoopGroup.setupThreadAndEventLoop(name:uniqueID:parentGroup:selectorFactory:initializer:metricsDelegate:) + 1255 in swift-nioPackageTests.xctest at /pwd/Sources/NIOPosix/MultiThreadedEventLoopGroup.swift:139:41
13 [ra] [thunk] 0x0000aaaab83e1eec partial apply for closure #1 in static MultiThreadedEventLoopGroup.setupThreadAndEventLoop(name:uniqueID:parentGroup:selectorFactory:initializer:metricsDelegate:) + 39 in swift-nioPackageTests.xctest at //<compiler-generated>
14 [ra] [thunk] 0x0000aaaab843f534 thunk for @escaping @callee_guaranteed (@guaranteed NIOThread) -> () + 23 in swift-nioPackageTests.xctest at //<compiler-generated>
15 [ra] 0x0000aaaab84409dc closure #1 in closure #1 in static ThreadOpsPosix.run(handle:args:) + 319 in swift-nioPackageTests.xctest at /pwd/Sources/NIOPosix/ThreadPosix.swift:186:21
16 [ra] 0x0000ffff86af595c <unknown> in libc.so.6
...
Registers:
x0 0x0000ffff62fddfe0 48 60 00 58 ff ff 00 00 e0 e0 fd 62 ff ff 00 00 H`·Xÿÿ··ààýbÿÿ··
x1 0x0000000000000000 0
x2 0x0000ffff62fddff0 40 b4 01 5c ff ff 00 00 20 83 d1 b8 aa aa 00 00 @´·\ÿÿ·· ·Ñ¸ªª··
x3 0x0000ffff58002038 03 03 00 00 00 00 00 00 01 00 00 00 01 00 00 00 ················
x4 0x0000ffff62fddfa8 00 00 00 00 00 00 00 00 00 e0 fd 62 ff ff 00 00 ·········àýbÿÿ··
x5 0x0000ffff62fddfa0 38 20 00 58 ff ff 00 00 00 00 00 00 00 00 00 00 8 ·Xÿÿ··········
x6 0x0000000000000001 1
x7 0x0000000000000000 0
x8 0x0000000000000000 0
x9 0x0000ffff886cf4e8 98 73 54 88 ff ff 00 00 08 be 5b 88 ff ff 00 00 ·sT·ÿÿ···¾[·ÿÿ··
x10 0x000000000000ffff 65535
x11 0x0000000000000000 0
x12 0x0000000000000000 0
x13 0x0000000000000001 1
x14 0x0000aaaab8e3ff2c 05 00 00 00 d4 2e a7 ff 00 00 03 00 51 00 00 00 ····Ô.§ÿ····Q···
x15 0x0000000000000009 9
x16 0x0000aaaab8d70520 f8 b0 54 88 ff ff 00 00 b4 45 55 88 ff ff 00 00 ø°T·ÿÿ··´EU·ÿÿ··
x17 0x0000ffff8854b0f8 ff 43 01 d1 fd 7b 02 a9 f6 57 03 a9 f4 4f 04 a9 ÿC·Ñý{·©öW·©ôO·©
x18 0x0000000000000000 0
x19 0x0000ffff58002038 03 03 00 00 00 00 00 00 01 00 00 00 01 00 00 00 ················
x20 0x0000ffff62fddff0 40 b4 01 5c ff ff 00 00 20 83 d1 b8 aa aa 00 00 @´·\ÿÿ·· ·Ñ¸ªª··
x21 0x0000000000000006 6
x22 0x0000000000000000 0
x23 0x0000aaaab86688b0 09 00 40 f9 09 01 00 f9 c0 03 5f d6 ff c3 00 d1 ··@ù···ùÀ·_Öÿ÷Ñ
x24 0x0000ffff5c01b440 f0 9d d9 b8 aa aa 00 00 03 00 00 00 08 00 00 00 ð·Ù¸ªª··········
x25 0x0000aaaab8d18320 0c 9c e2 b8 aa aa 00 00 ec 3c 3a b8 aa aa 00 00 ··â¸ªª··ì<:¸ªª··
x26 0x0000ffff62fde170 6e 69 6c 00 00 00 00 00 00 00 00 00 00 00 00 e3 nil············ã
x27 0x0000ffff62fde0e0 2d 00 00 00 00 00 00 d0 a0 3b de b8 aa aa 00 80 -······Ð ;Þ¸ªª··
x28 0x0000ffff886c6c28 02 02 00 00 00 00 00 00 30 b0 6f 88 ff ff 00 00 ········0°o·ÿÿ··
fp 0x0000ffff62fddf30 b0 df fd 62 ff ff 00 00 48 b1 54 88 ff ff 00 00 °ßýbÿÿ··H±T·ÿÿ··
lr 0x0000ffff8854b148 1f 08 00 71 c0 00 00 54 1f 04 00 71 c1 00 00 54 ···qÀ··T···qÁ··T
sp 0x0000ffff62fddf00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ················
pc 0x0000ffff8854b1ec 68 01 40 f9 69 00 40 f9 1f fd 1f f1 f3 83 88 1a h·@ùi·@ù·ý·ñó···
Images (20 omitted):
0x0000aaaab7d20000–0x0000aaaab8cd6d00 a17d4d145f2d2621f7b9d43c2b2d2a754b69002b swift-nioPackageTests.xctest /pwd/.build/aarch64-unknown-linux-gnu/release/swift-nioPackageTests.xctest
0x0000ffff86a70000–0x0000ffff86c09ec1 d5ef86dde36cbd3289566cf5098226035d76f2e1 libc.so.6 /usr/lib/aarch64-linux-gnu/libc.so.6
0x0000ffff88160000–0x0000ffff8869e0c8 f62b9374639c58d0b60814a6fbec69d2b596cfc7 libswiftCore.so /usr/lib/swift/linux/libswiftCore.so
Backtrace took 0.62s
error: Exited with unexpected signal code 11
```
The test is fine for both debug and release mode on Swift 6.0, 6.1, and
6.3-nightly.
### Modifications:
Since this is a valid construction and the crash is a Swift bug, and
since it only manifests on a specific Swift version, and since it's only
triggered when mis-using the API, we can just not perform this part of
the test on Swift 6.2. The API is fully functional when used correctly.
### Result:
Running NIO tests, compiled in release mode, no longer crashes on Swift
6.2.3.
### Local testings:
With this branch:
```
% docker run --rm -it -v $PWD:/pwd -w /pwd swift:6.2 swift test -c release --filter testUnderlyingSocketAccessForSocketBasedChannel
[1/1] Planning build
Building for production...
[8/8] Linking swift-nioPackageTests.xctest
Build complete! (38.46s)
Test Suite 'Selected tests' started at 2026-02-18 14:23:12.902
Test Suite 'Selected tests' passed at 2026-02-18 14:23:12.902
Executed 0 tests, with 0 failures (0 unexpected) in 0.0 (0.0) seconds
◇ Test run started.
↳ Testing Library Version: 6.2.3 (48a471ab313e858)
↳ Target Platform: aarch64-unknown-linux-gnu
◇ Suite NIOTransportAccessibleChannelCoreTests started.
◇ Test testUnderlyingSocketAccessForSocketBasedChannel() started.
✔ Test testUnderlyingSocketAccessForSocketBasedChannel() passed after 0.002 seconds.
✔ Suite NIOTransportAccessibleChannelCoreTests passed after 0.003 seconds.
✔ Test run with 1 test in 1 suite passed after 0.003 seconds.
```
2.95.0
|
||
|
|
be8fdc13c0 |
Allow to copy files and symlinks while overwriting the destination (#3508)
Adds capability to NIOFS to copy regular files and symlink, allowing to overwrite the destination. ### Motivation: Per https://github.com/apple/swift-nio/issues/3403 and https://github.com/apple/swift-nio/pull/3470 we want to add `replaceExisting: bool` to `FileSystem.copyItem`. ### Modifications: 1. Adds `replaceExisting: bool` parameter to `FileSystemProtocol.copyItem`. 2. Adds `replaceExisting: bool` parameter to `FileSystem.copyItem` and implementation for regular files and symbolic links. 3. Adds tests. --------- Co-authored-by: George Barnett <gbarnett@apple.com> |
||
|
|
b0e024792a |
Add opt-in API for channels to expose their underlying transport (#3509)
## Motivation NIO channels abstract over an underlying transport mechanisms (sockets, pipes, etc.), which users typically need not interact with. However, there are scenarios where users need direct access to the underlying transport for low-level operations that work outside NIOs abstraction. One example is performing out out-of-band operations on the underlying file descriptor for a socket-based channel. This PR adds a structured way to access the underlying transport of a channel, for channels that choose to implement it. ## Modifications - Add a new `public protocol NIOTransportAccessibleChannelCore<Transport>` which provides a scoped `withUnsafeTransport(_:)`, used for channel implementations to opt-in. - Add conformance to `NIOTransportAccessibleChannel<NIOBSDSocket.Handle>` for `BaseSocketChannel`, to make this API available for all socket-based channels, including channels returned from the socket-based bootstrap public APIs. - Add public API `ChannelPipeline.SynchronousOperations.withUnsafeTransportIfAvailable(_:)` Note that not all channels need to or should their transport, which is why this was added as an additional protocol that refines `ChannelCore`, vs. extending `Channel` or `ChannelCore` with a default implementation. The protocol uses a primary associated type allowing channels to provide typed access to the transport. E.g. this could be used in NIO Transport Services to expose the underlying `NWConnection`, if desired. The method itself is spelled with "unsafe", uses scoped access, and has clear documentation that users must not violated any of NIOs assumptions about the state of the underlying transport. It's very much not intended for every day use. It being on `ChannelCore` should defer users of the low-level API, since `Channel._channelCore` is marked as for NIO internal use, and the public `withUnsafeTransportIfAvailable(_:)` will take care of the runtime checks for channels that have opted into this API. ## Result - New opt-in API for channel implementations to expose their underlying transport - All socket-based channels from NIOPosix now expose the underlying socket file descriptor - New API `ChannelPipeline.SynchronousOperations.withUnsafeTransportIfAvailable(_:)` for users --------- Co-authored-by: Agam Dua <agam_dua@apple.com> |
||
|
|
2fdda6c78e |
Fix benchmark succeeding – even though Benchmark build failed (#3502)
### Motivation: Currently if there is an error in the Benchmark targets, that prevents the Benchmark to build correctly, we still get a CI success. ### Modifications: - Check for the threshold changed error ### Result: - More reliable CI |
||
|
|
c329d1e173 |
Fix C++ interop CI script to work with changes in SwiftPM (#3510)
### Motivation: SwiftPM behaviour has changed in recent Swift nightlies. In most recent released version of Swift, SwiftPM will use the parent directory name for the source and test target directory too, even when it contains a period: ``` % docker run -it swift:6.2 bash -c 'mkdir -p /tmp/foo.bar && cd /tmp/foo.bar && swift package init' Creating library package: foo.bar Creating Package.swift Creating .gitignore Creating Sources Creating Sources/foo.bar/foo_bar.swift Creating Tests/ Creating Tests/foo.barTests/ Creating Tests/foo.barTests/foo_barTests.swift ``` Note in the above how it replaces the `.` with a `_` in the source files, but the directories retain the `.`. In the recent nightly-main, SwiftPM has also started replacing `.` with `_` in the target directory names: ``` % docker run -it swiftlang/swift:nightly-main bash -c 'cat /etc/motd && mkdir -p /tmp/foo.bar && cd /tmp/foo.bar && swift package init' ################################################################ # # # Swift Nightly Docker Image # # Tag: swift-DEVELOPMENT-SNAPSHOT-2026-02-06-a # # # ################################################################ Creating library package: foo.bar Creating Package.swift Creating .gitignore Creating Sources Creating Sources/foo_bar/foo_bar.swift Creating Tests/ Creating Tests/foo_barTests/ Creating Tests/foo_barTests/foo_barTests.swift ``` Probably this https://github.com/swiftlang/swift-package-manager/pull/9252. This breaks our CI automation, only on nightly-main, because we run `swift package init` in a directory created by `mktemp -d`, which, by default, follows the pattern `tmp.XXXXXXX`. ### Modifications: Create temporary directory for Swift package using explicit pattern containing no periods. ### Result: C++ interop CI should now work again on nightly-main Swift, and continue to work on all supported Swift versions. |
||
|
|
d948192838 |
Don't send (in)active when channel closes directly (#3497)
### Motivation Issue #2773 reports a problem where channels can receive `channelInactive` before `channelActive`. This breaks expectations and should not happen. Instead of sending them in the wrong order, this PR suppresses both of them in those cases. ### Modifications * Add a test to reproduce the problematic behavior. * Update the state machine to split the active state into two. This decouples succeeding the promise from sending the signal. Transiting to closing only sends `channelInactive` when originating from the state that sent `channelActive`. ### Result Address #2773. Edit: Updated modifications to reflect latests commit. |
||
|
|
9b92dcd5c2 |
Replace ConditionLock with wake-one signalling NIOThreadPoolWorkAvailable (#3507)
**TL;DR** This change leads to a ~90% reduction in observed system CPU time for some use cases by waking a single thread, instead of all idle threads. # Changes Inlining the commit messages here. ## Add NIOThreadPool submit throughput benchmarks ### Motivation `NIOThreadPool` had no benchmarks measuring submit overhead. This makes it difficult to evaluate the cost of signalling changes or to catch latency regressions. ### Modifications Add thread pool submit benchmarks, covering use cases with 4-thread and 16-thread pools. ### Result `NIOThreadPool` submit throughput and context-switch overhead are now tracked by benchmarks. ### Benchmark Results <details> ``` NIOThreadPool.serial_wakeup(16 threads) ╒══════════════════════════╤═══════════╤═══════════╤═══════════╤═══════════╤═══════════╤═══════════╤═══════════╤═══════════╕ │ Metric │ p0 │ p25 │ p50 │ p75 │ p90 │ p99 │ p100 │ Samples │ ╞══════════════════════════╪═══════════╪═══════════╪═══════════╪═══════════╪═══════════╪═══════════╪═══════════╪═══════════╡ │ Context switches (K) │ 77 │ 78 │ 79 │ 80 │ 80 │ 92 │ 92 │ 30 │ ├──────────────────────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┤ │ Syscalls (total) (K) * │ 106 │ 107 │ 108 │ 109 │ 110 │ 116 │ 116 │ 30 │ ├──────────────────────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┤ │ Time (system CPU) (ms) * │ 1649 │ 1752 │ 1768 │ 1795 │ 1826 │ 1929 │ 1929 │ 30 │ ├──────────────────────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┤ │ Time (total CPU) (ms) * │ 1701 │ 1805 │ 1821 │ 1849 │ 1879 │ 1987 │ 1987 │ 30 │ ├──────────────────────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┤ │ Time (user CPU) (ms) * │ 51 │ 52 │ 52 │ 53 │ 53 │ 57 │ 57 │ 30 │ ├──────────────────────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┤ │ Time (wall clock) (ms) * │ 167 │ 177 │ 178 │ 181 │ 183 │ 200 │ 200 │ 30 │ ╘══════════════════════════╧═══════════╧═══════════╧═══════════╧═══════════╧═══════════╧═══════════╧═══════════╧═══════════╛ NIOThreadPool.serial_wakeup(4 threads) ╒══════════════════════════╤═══════════╤═══════════╤═══════════╤═══════════╤═══════════╤═══════════╤═══════════╤═══════════╕ │ Metric │ p0 │ p25 │ p50 │ p75 │ p90 │ p99 │ p100 │ Samples │ ╞══════════════════════════╪═══════════╪═══════════╪═══════════╪═══════════╪═══════════╪═══════════╪═══════════╪═══════════╡ │ Context switches (K) │ 44 │ 44 │ 44 │ 45 │ 45 │ 45 │ 45 │ 30 │ ├──────────────────────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┤ │ Syscalls (total) (K) * │ 65 │ 65 │ 65 │ 66 │ 66 │ 67 │ 67 │ 30 │ ├──────────────────────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┤ │ Time (system CPU) (ms) * │ 159 │ 162 │ 163 │ 165 │ 166 │ 169 │ 169 │ 30 │ ├──────────────────────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┤ │ Time (total CPU) (ms) * │ 178 │ 182 │ 183 │ 185 │ 186 │ 190 │ 190 │ 30 │ ├──────────────────────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┤ │ Time (user CPU) (ms) * │ 19 │ 19 │ 20 │ 20 │ 20 │ 21 │ 21 │ 30 │ ├──────────────────────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┤ │ Time (wall clock) (ms) * │ 76 │ 79 │ 79 │ 80 │ 80 │ 82 │ 82 │ 30 │ ╘══════════════════════════╧═══════════╧═══════════╧═══════════╧═══════════╧═══════════╧═══════════╧═══════════╧═══════════╛ ``` </details> ## Replace `ConditionLock` with wake-one signalling `NIOThreadPoolWorkAvailable` ### Motivation `NIOThreadPool` used `ConditionLock` which calls `pthread_cond_broadcast` on every state change, waking all threads when only one work item is enqueued. This causes a thundering-herd problem. ### Modifications Add `NIOThreadPoolWorkAvailable` in NIOConcurrencyHelpers that uses `pthread_cond_signal` (wake-one) for work submission and `pthread_cond_broadcast` only for shutdown. Replace `ConditionLock<_WorkState>` and the `_WorkState` enum in `NIOThreadPool` with this new primitive. ### Result Submitting a work item wakes exactly **one** thread instead of all threads. ### Benchmark Results <details> ``` NIOThreadPool.serial_wakeup(16 threads) ╒══════════════════════════╤═══════════╤═══════════╤═══════════╤═══════════╤═══════════╤═══════════╤═══════════╤═══════════╕ │ Metric │ p0 │ p25 │ p50 │ p75 │ p90 │ p99 │ p100 │ Samples │ ╞══════════════════════════╪═══════════╪═══════════╪═══════════╪═══════════╪═══════════╪═══════════╪═══════════╪═══════════╡ │ Context switches (K) │ 20 │ 20 │ 20 │ 20 │ 20 │ 20 │ 20 │ 30 │ ├──────────────────────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┤ │ Syscalls (total) (K) * │ 40 │ 40 │ 40 │ 40 │ 40 │ 40 │ 40 │ 30 │ ├──────────────────────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┤ │ Time (system CPU) (ms) * │ 47 │ 49 │ 49 │ 50 │ 50 │ 55 │ 55 │ 30 │ ├──────────────────────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┤ │ Time (total CPU) (ms) * │ 57 │ 58 │ 59 │ 60 │ 61 │ 67 │ 67 │ 30 │ ├──────────────────────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┤ │ Time (user CPU) (ms) * │ 10 │ 10 │ 10 │ 10 │ 10 │ 12 │ 12 │ 30 │ ├──────────────────────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┤ │ Time (wall clock) (ms) * │ 54 │ 55 │ 56 │ 56 │ 57 │ 65 │ 65 │ 30 │ ╘══════════════════════════╧═══════════╧═══════════╧═══════════╧═══════════╧═══════════╧═══════════╧═══════════╧═══════════╛ NIOThreadPool.serial_wakeup(4 threads) ╒══════════════════════════╤═══════════╤═══════════╤═══════════╤═══════════╤═══════════╤═══════════╤═══════════╤═══════════╕ │ Metric │ p0 │ p25 │ p50 │ p75 │ p90 │ p99 │ p100 │ Samples │ ╞══════════════════════════╪═══════════╪═══════════╪═══════════╪═══════════╪═══════════╪═══════════╪═══════════╪═══════════╡ │ Context switches (K) │ 20 │ 20 │ 20 │ 20 │ 20 │ 20 │ 20 │ 30 │ ├──────────────────────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┤ │ Syscalls (total) (K) * │ 40 │ 40 │ 40 │ 40 │ 40 │ 40 │ 40 │ 30 │ ├──────────────────────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┤ │ Time (system CPU) (ms) * │ 45 │ 46 │ 46 │ 47 │ 57 │ 75 │ 75 │ 30 │ ├──────────────────────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┤ │ Time (total CPU) (ms) * │ 54 │ 55 │ 56 │ 57 │ 68 │ 87 │ 87 │ 30 │ ├──────────────────────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┤ │ Time (user CPU) (μs) * │ 9055 │ 9372 │ 9478 │ 9765 │ 10887 │ 12585 │ 12585 │ 30 │ ├──────────────────────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┤ │ Time (wall clock) (ms) * │ 52 │ 53 │ 53 │ 54 │ 64 │ 124 │ 124 │ 30 │ ╘══════════════════════════╧═══════════╧═══════════╧═══════════╧═══════════╧═══════════╧═══════════╧═══════════╧═══════════╛ ``` </details>2.94.1 |
||
|
|
db01d87942 |
Add symlinkat, renameatx_np, and unlinkat system call wrappers (#3505)
Adds three new system call wrappers for the `symlinkat`, `renameatx_np`, and `unlinkat` system calls. ### Motivation: Related to https://github.com/apple/swift-nio/issues/3403 and https://github.com/apple/swift-nio/pull/3470. This PR adds syscall wrappers needed to atomically overwrite existing files or symlinks at the destination during copy operations. On Linux, atomic overwrites require a "copy to temp file, then rename" strategy. We use the `*at` family of syscalls (which operate relative to directory file descriptors) to avoid TOCTOU race conditions. ### Modifications: 1. Adds three system call wrappers for the `symlinkat`, `renameatx_np`, and `unlinkat` system calls. 2. Adds related tests 3. Updates the `FileSystemError` for `symlink` and `unlink` to take in the system call name to allow for the `*at` names to be passed. |
||
|
|
edad6d8a9b |
Clarify state and relationship of NIOFileSystem and _NIOFileSystem in API docs (#3504)
### Motivation: `NIOFileSystem` currently exposes the same API as `_NIOFileSystem`, which is not API stable. `NIOFileSystem` was created in error, and its lack of underscore incorrectly implies API stability. Users who are currently importing `NIOFileSystem` should ideally move to `_NIOFileSystem`. However this isn't made clear in the docs: 1. The README talks about the non-underscored `NIOFileSystem`. 2. There are no hosted API docs `NIOFileSystem`. 3. The hosted API docs for `NIO` point to the docs for `NIOFileSystem` -- results in 404. ### Modifications: - Update the README to refer to `_NIOFileSystem`. - Update the hosted API docs for `NIO` to point to docs for `_NIOFileSystem`. - Add hosted API docs for `NIOFileSystem` with a statement explaining the situation and pointing people to the docs for `_NIOFileSystem`. ### Result: Clearer documentation on the state and relationship of the `NIOFileSystem` and `_NIOFileSystem` modules. |
||
|
|
90ed88baab |
test: Port NIOThreadPoolTest to Swift Testing. (#3490)
Ports NIOThreadPoolTest in NIOPosix from XCTest to Swift Testing. ### Motivation: Tests should use the latest Swift Testing framework when possible. ### Modifications: - Ported `NIOThreadPoolTest` from XCTest to Swift Testing - Updated test implementation from Dispatch to Swift Concurrency as needed to support test functionality ### Result: All tests continue to pass, NIOThreadPoolTest now has more modern Swift Testing syntax. |
||
|
|
e0476c6072 |
test: Port EventLoopFutureTest to Swift Testing. (#3491)
Port `EventLoopFutureTest` to Swift Testing. Includes some adjustments to ensure tests are ran from the event loop, among other minor changes ### Motivation: Tests should use the latest Swift Testing framework when possible. ### Modifications: - Ported `EventLoopFutureTest ` from XCTest to Swift Testing - Consolidated instantiations of `EmbeddedEventLoop()` into a private function called `makeEventLoop` to allow for easier injection of a different loop from a single location. - Migrated some `.wait` usages to `.get` to allow tests to run async. ### Result: All tests continue to pass, EventLoopFutureTest now has more modern Swift Testing syntax. |
||
|
|
6a6f7d7c33 |
Centralize UnsafeTransfer in NIOCore (#3492)
We have a number of copies of `UnsafeTransfer` and two copies of `UnsafeMutableTransferBox` in our code base. Before introducing more of those, lets centralize to just one using a `package` access modifier. |
||
|
|
c90e69406b | Fix Xcode 26.2 CI copy and paste error (#3499) | ||
|
|
d1aaf4371a |
Add support for Xcode 26.2 (#3498)
Adds the required new inputs to the macOS tests and benchmark reusable workflows |
||
|
|
5e72fc1029 |
Move nightly-next CI to 6.3 (#3496)
This PR moves the nightly-next CI to use the 6.3 images. Since those checks should be non required on any user of this package and the name of the check doesn't change with moving images this should be a non-breaking change.2.94.0 |
||
|
|
37ffc4b8d5 |
Add API to enable throwing in EmbeddedChannel.getOption and .setOption if channel is closed (#3495)
### Motivation: Channels based on `BaseSocketChannel` throw in both `getOption` and `setOption` if the channel has been closed, since the `setsockopt` will fail. However, the current behavior of `EmbeddedChannel` is options remain writable and readable on closed channels. There are situations where we'd like to be able to model the runtime behaviour of the real channel in tests, e.g. to test this fix: https://github.com/apple/swift-nio-extras/pull/304. ### Modifications: - Add API to enable throwing in `EmbeddedChannel.getOption` and `.setOption` if channel is closed. - Add a test for this new behavior. ### Result: - New API to enable throwing in `EmbeddedChannel.getOption` and `.setOption` if channel is closed. - No observable change for existing users of `EmbeddedChannel`. |
||
|
|
b2a14468d9 |
Bump actions/checkout from 6.0.1 to 6.0.2 (#3493)
Bumps [actions/checkout](https://github.com/actions/checkout) from 6.0.1 to 6.0.2. <details> <summary>Release notes</summary> <p><em>Sourced from <a href="https://github.com/actions/checkout/releases">actions/checkout's releases</a>.</em></p> <blockquote> <h2>v6.0.2</h2> <h2>What's Changed</h2> <ul> <li>Add orchestration_id to git user-agent when ACTIONS_ORCHESTRATION_ID is set by <a href="https://github.com/TingluoHuang"><code>@TingluoHuang</code></a> in <a href="https://redirect.github.com/actions/checkout/pull/2355">actions/checkout#2355</a></li> <li>Fix tag handling: preserve annotations and explicit fetch-tags by <a href="https://github.com/ericsciple"><code>@ericsciple</code></a> in <a href="https://redirect.github.com/actions/checkout/pull/2356">actions/checkout#2356</a></li> </ul> <p><strong>Full Changelog</strong>: <a href="https://github.com/actions/checkout/compare/v6.0.1...v6.0.2">https://github.com/actions/checkout/compare/v6.0.1...v6.0.2</a></p> </blockquote> </details> <details> <summary>Changelog</summary> <p><em>Sourced from <a href="https://github.com/actions/checkout/blob/main/CHANGELOG.md">actions/checkout's changelog</a>.</em></p> <blockquote> <h1>Changelog</h1> <h2>v6.0.2</h2> <ul> <li>Fix tag handling: preserve annotations and explicit fetch-tags by <a href="https://github.com/ericsciple"><code>@ericsciple</code></a> in <a href="https://redirect.github.com/actions/checkout/pull/2356">actions/checkout#2356</a></li> </ul> <h2>v6.0.1</h2> <ul> <li>Add worktree support for persist-credentials includeIf by <a href="https://github.com/ericsciple"><code>@ericsciple</code></a> in <a href="https://redirect.github.com/actions/checkout/pull/2327">actions/checkout#2327</a></li> </ul> <h2>v6.0.0</h2> <ul> <li>Persist creds to a separate file by <a href="https://github.com/ericsciple"><code>@ericsciple</code></a> in <a href="https://redirect.github.com/actions/checkout/pull/2286">actions/checkout#2286</a></li> <li>Update README to include Node.js 24 support details and requirements by <a href="https://github.com/salmanmkc"><code>@salmanmkc</code></a> in <a href="https://redirect.github.com/actions/checkout/pull/2248">actions/checkout#2248</a></li> </ul> <h2>v5.0.1</h2> <ul> <li>Port v6 cleanup to v5 by <a href="https://github.com/ericsciple"><code>@ericsciple</code></a> in <a href="https://redirect.github.com/actions/checkout/pull/2301">actions/checkout#2301</a></li> </ul> <h2>v5.0.0</h2> <ul> <li>Update actions checkout to use node 24 by <a href="https://github.com/salmanmkc"><code>@salmanmkc</code></a> in <a href="https://redirect.github.com/actions/checkout/pull/2226">actions/checkout#2226</a></li> </ul> <h2>v4.3.1</h2> <ul> <li>Port v6 cleanup to v4 by <a href="https://github.com/ericsciple"><code>@ericsciple</code></a> in <a href="https://redirect.github.com/actions/checkout/pull/2305">actions/checkout#2305</a></li> </ul> <h2>v4.3.0</h2> <ul> <li>docs: update README.md by <a href="https://github.com/motss"><code>@motss</code></a> in <a href="https://redirect.github.com/actions/checkout/pull/1971">actions/checkout#1971</a></li> <li>Add internal repos for checking out multiple repositories by <a href="https://github.com/mouismail"><code>@mouismail</code></a> in <a href="https://redirect.github.com/actions/checkout/pull/1977">actions/checkout#1977</a></li> <li>Documentation update - add recommended permissions to Readme by <a href="https://github.com/benwells"><code>@benwells</code></a> in <a href="https://redirect.github.com/actions/checkout/pull/2043">actions/checkout#2043</a></li> <li>Adjust positioning of user email note and permissions heading by <a href="https://github.com/joshmgross"><code>@joshmgross</code></a> in <a href="https://redirect.github.com/actions/checkout/pull/2044">actions/checkout#2044</a></li> <li>Update README.md by <a href="https://github.com/nebuk89"><code>@nebuk89</code></a> in <a href="https://redirect.github.com/actions/checkout/pull/2194">actions/checkout#2194</a></li> <li>Update CODEOWNERS for actions by <a href="https://github.com/TingluoHuang"><code>@TingluoHuang</code></a> in <a href="https://redirect.github.com/actions/checkout/pull/2224">actions/checkout#2224</a></li> <li>Update package dependencies by <a href="https://github.com/salmanmkc"><code>@salmanmkc</code></a> in <a href="https://redirect.github.com/actions/checkout/pull/2236">actions/checkout#2236</a></li> </ul> <h2>v4.2.2</h2> <ul> <li><code>url-helper.ts</code> now leverages well-known environment variables by <a href="https://github.com/jww3"><code>@jww3</code></a> in <a href="https://redirect.github.com/actions/checkout/pull/1941">actions/checkout#1941</a></li> <li>Expand unit test coverage for <code>isGhes</code> by <a href="https://github.com/jww3"><code>@jww3</code></a> in <a href="https://redirect.github.com/actions/checkout/pull/1946">actions/checkout#1946</a></li> </ul> <h2>v4.2.1</h2> <ul> <li>Check out other refs/* by commit if provided, fall back to ref by <a href="https://github.com/orhantoy"><code>@orhantoy</code></a> in <a href="https://redirect.github.com/actions/checkout/pull/1924">actions/checkout#1924</a></li> </ul> <h2>v4.2.0</h2> <ul> <li>Add Ref and Commit outputs by <a href="https://github.com/lucacome"><code>@lucacome</code></a> in <a href="https://redirect.github.com/actions/checkout/pull/1180">actions/checkout#1180</a></li> <li>Dependency updates by <a href="https://github.com/dependabot"><code>@dependabot</code></a>- <a href="https://redirect.github.com/actions/checkout/pull/1777">actions/checkout#1777</a>, <a href="https://redirect.github.com/actions/checkout/pull/1872">actions/checkout#1872</a></li> </ul> <h2>v4.1.7</h2> <ul> <li>Bump the minor-npm-dependencies group across 1 directory with 4 updates by <a href="https://github.com/dependabot"><code>@dependabot</code></a> in <a href="https://redirect.github.com/actions/checkout/pull/1739">actions/checkout#1739</a></li> <li>Bump actions/checkout from 3 to 4 by <a href="https://github.com/dependabot"><code>@dependabot</code></a> in <a href="https://redirect.github.com/actions/checkout/pull/1697">actions/checkout#1697</a></li> <li>Check out other refs/* by commit by <a href="https://github.com/orhantoy"><code>@orhantoy</code></a> in <a href="https://redirect.github.com/actions/checkout/pull/1774">actions/checkout#1774</a></li> <li>Pin actions/checkout's own workflows to a known, good, stable version. by <a href="https://github.com/jww3"><code>@jww3</code></a> in <a href="https://redirect.github.com/actions/checkout/pull/1776">actions/checkout#1776</a></li> </ul> <h2>v4.1.6</h2> <ul> <li>Check platform to set archive extension appropriately by <a href="https://github.com/cory-miller"><code>@cory-miller</code></a> in <a href="https://redirect.github.com/actions/checkout/pull/1732">actions/checkout#1732</a></li> </ul> <!-- raw HTML omitted --> </blockquote> <p>... (truncated)</p> </details> <details> <summary>Commits</summary> <ul> <li><a href="https://github.com/actions/checkout/commit/de0fac2e4500dabe0009e67214ff5f5447ce83dd"><code>de0fac2</code></a> Fix tag handling: preserve annotations and explicit fetch-tags (<a href="https://redirect.github.com/actions/checkout/issues/2356">#2356</a>)</li> <li><a href="https://github.com/actions/checkout/commit/064fe7f3312418007dea2b49a19844a9ee378f49"><code>064fe7f</code></a> Add orchestration_id to git user-agent when ACTIONS_ORCHESTRATION_ID is set (...</li> <li>See full diff in <a href="https://github.com/actions/checkout/compare/8e8c483db84b4bee98b60c0593521ed34d9990e8...de0fac2e4500dabe0009e67214ff5f5447ce83dd">compare view</a></li> </ul> </details> <br /> [](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores) Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`. [//]: # (dependabot-automerge-start) [//]: # (dependabot-automerge-end) --- <details> <summary>Dependabot commands and options</summary> <br /> You can trigger Dependabot actions by commenting on this PR: - `@dependabot rebase` will rebase this PR - `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it - `@dependabot merge` will merge this PR after your CI passes on it - `@dependabot squash and merge` will squash and merge this PR after your CI passes on it - `@dependabot cancel merge` will cancel a previously requested merge and block automerging - `@dependabot reopen` will reopen this PR if it is closed - `@dependabot close` will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually - `@dependabot show <dependency name> ignore conditions` will show all of the ignore conditions of the specified dependency - `@dependabot ignore this major version` will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this minor version` will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this dependency` will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself) </details> Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> |
||
|
|
5bf0267df4 |
build: Elide NIOPosix for WASI platforms only (#3485)
### Motivation:
Packages that consume NIOPosix should be able to compile to WASI
platforms without special configurations. This change elides the
NIOPosix source from WASI platforms to simplify configuration.
Without this change:
```swift
dependencies: [
// Without this PR, downstream packages must maintain exhaustive platform list to exclude `.wasi`:
.product(
name: "NIOPosix",
package: "swift-nio",
condition: .when(platforms: [
.macOS,
.macCatalyst,
.iOS,
.tvOS,
.watchOS,
.visionOS,
.driverKit,
.linux,
.windows,
.android,
.openbsd,
// .wasi // <-- Need to exclude this, because there is no exclusion list api for SPM conditionals
])
),
]
```
With this change:
```swift
dependencies: [
// Without this PR, downstream packages can consume NIOPosix simply:
.product(name: "NIOPosix", package: "swift-nio"),
]
```
### Modifications:
- Add compiler directives (`#if !os(WASI)`) to all source files in
NIOPosix
### Result:
Downstream packages can compile to wasm without manually excluding the
NIOPosix dependency.
### Testing performed
- Verified `swift build --swift-sdk wasm32-unknown-wasip1 --target
NIOPosix` compiles, which demonstrates proper elision of source files in
NIOPosix that aren't wasm-ready.
- Confirmed GitHub [checks
pass](https://github.com/PassiveLogic/swift-nio/actions/runs/21151341738).
|
||
|
|
3f80264185 |
build: Elide NIOEmbedded for WASI platforms only (#3484)
### Motivation:
Packages that consume NIOEmbedded should be able to compile to WASI
platforms without special configurations. This change elides the
NIOEmbedded source from WASI platforms to simplify configuration.
Without this change:
```swift
dependencies: [
// Without this PR, downstream packages must maintain exhaustive platform list to exclude `.wasi`:
.product(
name: "NIOEmbedded",
package: "swift-nio",
condition: .when(platforms: [
.macOS,
.macCatalyst,
.iOS,
.tvOS,
.watchOS,
.visionOS,
.driverKit,
.linux,
.windows,
.android,
.openbsd,
// .wasi // <-- Need to exclude this, because there is no exclusion list api for SPM conditionals
])
),
]
```
With this change:
```swift
dependencies: [
// Without this PR, downstream packages can consume NIOEmbedded simply:
.product(name: "NIOEmbedded", package: "swift-nio"),
]
```
### Modifications:
- Fix compiler directive using in AsyncTestingChannel.swift to include
an extension
### Result:
Packages can compile to wasm without manually excluding the NIOEmbedded
dependency.
### Testing performed
- Verified `swift build --swift-sdk wasm32-unknown-wasip1 --target
NIOEmbedded` compiles, which demonstrates proper elision of source files
in NIOEmbedded that aren't wasm-ready.
- Confirmed GitHub [checks
pass](https://github.com/PassiveLogic/swift-nio/actions/runs/21151287289).
|
||
|
|
c337170d91 |
chore: Elide mutex variable from Lock class when it is unused (#3483)
### Motivation: In reviewing a copy of this file in swift-log, @czechboy0 [noticed](https://github.com/apple/swift-log/pull/398#discussion_r2685605800) that the `mutex` variable is essentially unused and unnecessarily allocated for certain conditions. It is possible the compiler elided usage. But given the unconditional variable reference in the `deinit`, the compiler may not be able to. This change ensures the `mutex` property is completely elided except in the conditions where it is used. ### Modifications: - Adjusted compiler directive pattern to completely elide the `mutex` property for conditions where it would be unused. - Adjusted `deinit` to avoid referencing `mutex` unless it is compiled into the `Lock` class ### Result: The `mutex` property is no longer allocated or even compiled into the `Lock` class for unsupported configurations. All unit tests and checks pass. ### Research: The `deinit` used to have a blanket call to `mutex.deallocate()`. This has been moved into the platform-specific checks within the `deinit`. This allows complete elision of the `mutex` property altogether. The `_runtime(_multithreaded)` condition [appears to be rooted to this implementation](https://github.com/swiftlang/swift/blob/ffc51b914602765c5d680241796dbd3c3711fa6b/lib/Basic/LangOptions.cpp#L490). Diving deeper, all [operating systems in this list](https://github.com/swiftlang/swift/blob/ffc51b914602765c5d680241796dbd3c3711fa6b/lib/Basic/LangOptions.cpp#L554) except for UnknownOS and WASI result in `_runtime(_multithreaded)` returning true. That means that `OpenBSD` (and many other operating systems besides windows) were almost certainly using the `#elseif (compiler(<6.1) && !os(WASI)) || (compiler(>=6.1) && _runtime(_multithreaded))` condition in the `deinit`. In conclusion, moving `mutex.deallocate()` up into the conditional clauses inside `deinit` should be identical to the previous implementation for all operating systems except `llvm::Triple::UnknownOS`. And `llvm::Triple::UnknownOS` is likely not to have every compiled anyways due to the [check on line 32](https://github.com/apple/swift-nio/blob/main/Sources/NIOConcurrencyHelpers/lock.swift#L32). So in summary, it is expected that this clean up will compile identical to the previous implementation for all platforms except WASI platforms that don't have pthread support. For non-pthread WASI platforms, the unused `mutex` is properly elided from compilation altogether. ### Testing Done: - Confirmed that unit tests pass locally using Xcode - Verified [PR checks pass](https://github.com/PassiveLogic/swift-nio/actions/runs/21149729751) |
||
|
|
c534a13dcb |
Update macOS runners to Tahoe (#3489)
Sequoia runners are no longer available and we need to switch to Tahoe. ### Motivation: Sequoia runners are no longer available and jobs requesting them hang. ### Modifications: Request Tahoe runners. ### Result: Jobs no longer hang, macOS tests and benchmarks are running on Tahoe. |
||
|
|
233f61bc2c |
Initialize the mutexattr before use. (#3482)
As observed by @kkebo, this was missing from the implementation. ### Motivation: Correct pthread API usage. ### Modifications: Initialize the pthread_mutexattr_t with pthread_mutexattr_init before passed to pthread_mutex_init. ### Result: Even though this lock API appears to be deprecated, we'll correct the usage anyway. The non-deprecated NIOLock class doesn't have this problem.2.93.0 |
||
|
|
6ce9173261 |
fix: Ensure pthread_mutexattr_t is properly cleaned up with pthread_mutexattr_destroy in Lock (#3480)
### Motivation: In reviewing a copy of this file in swift-log, @czechboy0 noticed that the call to `pthread_mutexattr_destroy` is missing. Since pthread_mutexattr_t is like allocated on the stack rather than heap on most platforms, this is likely not a memory leak. But for correctness the missing destroy call should be added. This change is the start of a resolution [requested](https://github.com/apple/swift-log/pull/398#discussion_r2689459360) in a corresponding Lock rollout in swift-log ### Modifications: - Added missing call to `pthread_mutexattr_destroy` - Duplicated test for `NIOLock` to also test `Lock`, as a sanity test. ### Result: The new sanity test passes. If there are other ways this change can be realistically verified as safe and proper, please feel free to provide feedback in the PR. |
||
|
|
192616d47e |
Disable Xcode-beta builds until one is installed (#3446)
Xcode-latest currently points to the 26.1 release so it gives us a false sense of version coverage, and should be ignored. ### Motivation: We do not need to build twice with the same environment. ### Modifications: Set default value for Xcode latest beta enabled to `false` ### Result: One fewer job generated for the macOS build matrix. Co-authored-by: Rick Newton-Rogers <rnro@apple.com> |
||
|
|
61053a00bb |
NIOTypedHTTPClientUpgradeHandler will write Upgrade request on handlerAdded if active (#3473)
`NIOTypedHTTPClientUpgradeHandler.handlerAdded` will write upgrade request if the channel is already active ### Motivation: This has been added to make it easier to implement a websocket client that supports proxies. If the upgrade handler is added after the proxy connect has been processed previously nothing would happen. ### Modifications: - Added new function `NIOTypedHTTPClientUpgradeHandler.writeUpgradeRequest()` function. Call this from `channelActive` and also from `handlerAdded` if the channel is already active. - Added test `testUpgradeHappensAfterHandlerAdded` ### Result: NIOTypedHTTPClientUpgradeHandler now also works if it is added to a channel after the channel is active --------- Co-authored-by: Cory Benfield <lukasa@apple.com> |
||
|
|
6b33489e64 |
Updates to present docs on _NIOFileSystem (#3477)
This re-enables documentation lost during refactoring work, under the target _NIOFileSystem resolves #3474 ### Motivation: During the refactoring of NIOFileSystem and recent Swift updates, the mechanism to "shadow" symbols using `@_exported import` has stopped working for documentation and imports for symbols, which means that _NIOFileSystem is the target that needs to host the documentation for this (for now) ### Modifications: Moves DocC catalog into _NIOFileSystem target, and updates disambiguation hashes on overloaded symbols in order to verify no warnings are presented while generating documentation. Updates .spi.yml to present _NIOFileSystem instead of NIOFileSystem ### Result: Previous documentation should be available again, although at a slightly different URI structure within Swift Package Index. Co-authored-by: Cory Benfield <lukasa@apple.com> |
||
|
|
d779d6d104 |
Revert "Address potential template injection issues" (#3478)
Reverts apple/swift-nio#3466 - it broke CI in downstream projects. |
||
|
|
5ada77dafa |
Address potential template injection issues (#3466)
Instead of evaluating inputs directly in the run step, save them to an environment variable and evaluate that. ### Motivation: Evaluating workflow inputs directly can lead to injection attacks, such as those described at https://docs.zizmor.sh/audits/#template-injection ### Modifications: Evaluate workflow inputs as environment variables so that they do not inadvertently execute arbitrary shell injections. ### Result: The workflows should be more secure against malicious inputs. |
||
|
|
608e511d7a |
Add homeDirectory accessor to FileSystem (#3471)
Add homeDirectory accessor to FileSystem ### Motivation: Addresses #3381 by adding a `homeDirectory` property to FileSystem, equivalent to `FileManager.default.homeDirectoryForCurrentUser`. ### Modifications: - Added `homeDirectory` property to `FileSystemProtocol` and implemented in `FileSystem` - Implementation checks `HOME` environment variable first, falls back to `USERPROFILE` on Windows, or uses `getpwuid_r(3)` on POSIX systems - Added system call wrappers (`system_getuid`, `libc_getpwuid_r`) with proper platform guards - Added `FileSystemError.getpwuid_r()` error helper ### Result: Users can now access the home directory via `FileSystem.homeDirectory`, returning a `FilePath` asynchronously. Follows the same pattern as `currentWorkingDirectory` and `temporaryDirectory`. Co-authored-by: Cory Benfield <lukasa@apple.com> |
||
|
|
4a9a971110 |
docs: String(buffer:) needs to mention that it will always succeed (#3476)
### Motivation: The documentation for String(buffer:) initializer does not clearly indicate that this operation will always succeed, which may leave developers uncertain about error handling requirements. fixes: https://github.com/apple/swift-nio/issues/3449 ### Modifications: Updated the documentation for String(buffer:) to explicitly mention that the initialization will always succeed. ### Result: Developers will have clearer understanding that String(buffer:) is a safe operation that does not require error handling. Signed-off-by: Karan <karanlokchandani@protonmail.com>2.92.2 |
||
|
|
5dc3b4ba4a |
Cancel pending in/outbound consumers in EmbeddedChannelCore upon channel close (#3464)
### Motivation:
Currently, pending consumer closures remain in the
`{in}{out}boundBufferConsumer` queues of `EmbeddedChannelCore` even
after the channel closes. It is also possible to enqueue consumers
*after* the channel closes. In these cases, the consumer closures will
never be invoked and this can lead to unfavourable behaviour, as
observed in `NIOAsyncTestingChannel`'s `waitFor{In}{Out}boundWrite`
methods (the only places these queues are currently used).
`NIOAsyncTestingChannel`'s `waitFor{In}{Out}boundWrite` methods complete
a continuation *inside* the consumer closure. In the cases described
above, the continuation never completes and therefore
`waitFor{In}{Out}boundWrite` never returns.
### Modifications:
- Updated the element type in `EmbeddedChannelCore`'s
`{in}{out}boundBufferConsumer` from `(NIOAny) -> Void` to
`(Result<NIOAny, Error>) -> Void`.
- This is so that the `.failure` case can be used to notify the consumer
closure that the channel has closed.
- Changed the visibility of the `{in}{out}boundBufferConsumer`
properties from `internal` to `private` in order to prevent the queues
from being accessed and being appended to without the call site
considering whether the channel has been closed.
- Added new `internal` methods named
`enqueue{In}{Out}boundBufferConsumer(_:)` which take the consumer
closure as an argument and only append to the corresponding queue if the
channel isn't closed.
- If the channel is closed, the consumer closure is invoked immediately
with `.failure(ChannelError.ioOnClosedChannel)`.
- Updated `EmbeddedChannelCore`'s `close0` method to return a
`.failure(ChannelError.ioOnClosedChannel)` result to each closure in
`{in}{out}boundBufferConsumer` and empty both buffers.
- Updated `NIOAsyncTestingChannel`'s `waitFor{In}{Out}boundWrite` to
throw an error in the continuation upon receiving a `.failure` result.
- Added associated test cases.
### Result:
`EmbeddedChannelCore`'s `{in}{out}boundBufferConsumer` queues can be
used more safely: all pending closures will be invoked upon channel
close. As a result, `NIOAsyncTestingChannel`'s
`waitFor{In}{Out}boundWrite` no longer indefinitely blocks when the
channel closes.
|
||
|
|
e3d5c560e0 |
Fix coreCount on Linux when using cgroup v2 with CFS throttling disabled (#3462)
Fix coreCount on Linux when using cgroup v2 with CFS throttling disabled ### Motivation: When using `swift-nio` on Linux with cgroup v2 enabled, but with CFS throttling disabled, it falls back to attempting to read the cpuset file at the cgroup v1 path. This does not exist, which in turns falls back to returning `_SC_NPROCESSORS_ONLN`, which will return the total number of cores available (ignoring cgroup assignments). This has unexpected effects, including the default behaviour of starting the `MultiThreadedEventLoopGroup.singleton` with significantly more event loops than cores available to the workload. ### Modifications: - Adds `SystemCalls.statfs`, and associated constants, to determine the cgroup version. - Adds `Linux.cgroupVersion()` API to expose cgroup version. - Adds `Linux.cgroupV2MountPoint` variable to determine the cgroup v2 mount point. - Adds `Linux.cpuSetPathV1` & `Linux.cpuSetPathV2` (and `Linux.cpuSetPath` convenience) variables to determine the correct cpu set path. - Alters `System.coreCount` to use the appropriate logic from above to ensure that `cpuset.cpus` is parsed from the correct location. ### Result: `Linux.coreCount` should correctly parse and return the core count on Linux cgroup v2 enabled systems (when CFS throttling is disabled), while maintaining correctness for other configurations. --------- Co-authored-by: Johannes Weiss <johannesweiss@apple.com> Co-authored-by: Cory Benfield <lukasa@apple.com>2.92.1 |
||
|
|
92a262f376 |
ci: only run self-hosted ci on apple runners (#3468)
Limit Darwin Job execution to apple org. ### Motivation: When the repo is forked, the forks do not have access to the self-hosted CI, so it should not block actions in the forked environment. ### Modifications: Conditionalize Darwin job execution. ### Result: macOS CI will not queue on forks. |
||
|
|
1268babbc1 |
Allowlist 6.3 to be allowable for Swift Concurrency takeover (#3467)
Make 6.3 fast |
||
|
|
b0895c094d |
Update integration test allocation thresholds for nightly-main (#3465)
### Motivation: From https://github.com/apple/swift-nio/actions/runs/20197120190/job/57982705638 onwards, the Integration Test benchmark runs have been failing for `Linux (nightly-main)` due to allocations for seven tests falling below the defined thresholds. ### Modifications: Updated thresholds for the tests where the number of allocations were out-of-threshold (seven in total). ### Result: The Integration Test run for `Linux (nightly-main)` no longer fails. |
||
|
|
a1605a3303 |
Use explicit class name in all Self.[un]wrap{In}{Out}bound{In}{Out} calls (#3463)
### Motivation:
Swift does not currently generic specialize static methods on final
classes that have no parent classes when the method is implemented in a
protocol. This means that calling such methods through `Self` will not
involve a generic specialization, whereas using the explicit type name
will.
This pattern manifests in the `[un]wrap{In}{Out}bound{In}{Out}` static
methods defined in the
[`ChannelInboundHandler`](https://github.com/apple/swift-nio/blob/27146d484478b1bb0f150e848758f3a34ed9cbd0/Sources/NIOCore/TypeAssistedChannelHandler.swift#L60)
and
[`ChannelOutboundHandler`](https://github.com/apple/swift-nio/blob/27146d484478b1bb0f150e848758f3a34ed9cbd0/Sources/NIOCore/TypeAssistedChannelHandler.swift#L95)
protocols and their use from all channel handler classes. As such, we
should replace the `Self` part in all
`Self.[un]wrap{In}{Out}bound{In}{Out}` calls with the explicit class
name.
### Modifications:
Replaced all `Self.[un]wrap{In}{Out}bound{In}{Out}` calls to use the
explicit class name.
### Result:
Eliminates unnecessary overhead.
2.92.0
|
||
|
|
27146d4844 |
Extract macOS benchmarks into a separate reusable workflow (#3461)
Extract macOS benchmarks into a separate reusable workflow to completely remove them if they are not meant to be used. ### Motivation: macOS Benchmarks is an opt-in workflow. If no macOS versions selected to run benchmarks on, there is now a skipped matrix jobs, creating unnecessary visual and cognitive noise during workflow results analysis: <img width="391" height="369" alt="Screenshot 2025-12-10 at 14 22 50" src="https://github.com/user-attachments/assets/959ff2a1-3872-4bff-97ac-1dca6d2d4ea5" /> ### Modifications: macOS benchmarks workflow is extracted into a separate reusable workflow. ### Result: - If a repo is not running macOS benchmarks, there is no extra skipped jobs. - When willing to run macOS benchmarks, `macos_benchmarks.yml` workflow should be used. - This is a breaking change in the reusable workflows interface, so all the repos (just the `swift-log`?) need to adopt the new reusable workflow. Test runs: - old workflow run with [unused macOS benchmarks skipped and visible](https://github.com/apple/swift-nio/actions/runs/20102000384/job/57675171794) - new workflow run with [no macOS benchmarks visible](https://github.com/apple/swift-nio/actions/runs/20102837431) because they are not used - new workflow run with actually [executed and visible macOS benchmarks](https://github.com/apple/swift-nio/actions/runs/20103726421) |
||
|
|
03ec49f001 |
update actions/checkout and introduce dependabot (#3459)
Update the actions/checkout action to the latest release (v6.0.1) ### Motivation: https://github.com/actions/checkout?tab=readme-ov-file#whats-new > * Improved credential security: persist-credentials now stores credentials in a separate file under $RUNNER_TEMP instead of directly in .git/config > * No workflow changes required — git fetch, git push, etc. continue to work automatically > * Running authenticated git commands from a [Docker container action](https://docs.github.com/actions/sharing-automations/creating-actions/creating-a-docker-container-action) requires Actions Runner [v2.329.0](https://github.com/actions/runner/releases/tag/v2.329.0) or later > * Updated to the node24 runtime This requires a minimum Actions Runner version of [v2.327.1](https://github.com/actions/runner/releases/tag/v2.327.1) to run. ### Modifications: Updated the dependency version and added dependabot to take care of future upgrades. ### Result: Our workflows will be more secure! |
||
|
|
888f4affd6 |
Add ByteBuffer.readableBytesUInt8Span (#3458)
Add ByteBuffer.readableBytesUInt8Span ### Motivation: Provide access to readableBytes as a Span<UInt8> ### Modifications: Added computed property `ByteBuffer.readableBytesUInt8Span`. I also attempted to add `ByteBuffer.mutableReadableBytesUInt8Span` but due to an apparently faulty exclusivity issue I couldn't get this to work. See https://github.com/swiftlang/swift/issues/81218. ### Result: You can access the readable bytes of a ByteBuffer as a Span<UInt8> |
||
|
|
663ddc80f2 |
Dont hold lock over continuation in TokenBucket (#3455)
Motivation: The various 'withMumbleContinuation' APIs are supposed to be invoked synchronously with the caller. This assumption allows a lock to be acquired before the call and released from the body of the 'withMumbleContinuation' after e.g. storing the continuation. However this isn't the case and the job may be re-enqueued on the executor meaning that this is pattern is vulnerable to deadlocks. Modifications: - Drop and reacquire the lock in TokenBucket. - Switch to NIOLockedValueBox Result: Lower chance of deadlock2.91.0 |
||
|
|
2bc6627d74 |
Add some benchmarks for UDP and UDP metadata (#3457)
Motivation: I'm unhappy with AddressedEnvelope.Metadata, and I plan to change it. Before I change it, I want some way to get a clear picture of whether my changes make things better or worse. Modifications: Added a bunch of benchmarks Result: Some data will be available. --------- Co-authored-by: George Barnett <gbarnett@apple.com> |
||
|
|
b60d141920 |
Document when channel.remoteAddress field can be nil (#3456)
Added extra documentation to `channel.remoteAddress` field to capture a scenario where this field might be `nil` ### Motivation: It is somewhat common for users to have code like `channel.remoteAddress!` in their implementation, as it is a reasonable assumption to think a socket connection will have an associated remote address. However, in at least one known situation this might not be the case. When that happens, user's code might crash due to the force unwrap of the optional field. ### Modifications: Introduced more documentation to make it clear that users should be prepared to handle the `nil` scenario. ### Result: Less frequent mishandling of `channel.remoteAddress`. |
||
|
|
2bc71a6aff |
Partial OpenBSD support. (#3394)
### Motivation: Additional partial platform support. ### Modifications: * Create a new CNIOBSD module for OpenBSD, for general cleanliness, and make use of it throughout. Some of the changes are borrowed directly from CNIOLinux; some may technically be unnecessary; I am erring somewhat on expediency to functionality. * Since `malloc_size` is unavailable on OpenBSD, and some of the helpers make use of ManagedBufferPointer which makes use of it, mark some of this as unavailable as well. * Usual pthread optional typing changes, since pthread types are pointers on this platform. * Add conditionals to exclude other functionality not available here, like IP_RECVPKTINFO or IP_PKTINFO. * d_ino is a backwards-compatibility macro valued token for dirent, so instead, just expand with a conditional. * Use kqueue on OpenBSD. This necessitates adding some conditionals for type and feature compatibility. * The vsock API is unavailable on OpenBSD. ### Result: Tested the NIOTCPEchoClient and NIOTCPEchoServer appears to work and that swift-nio-ssh (hopefully wlog) builds with a local repository with these changes. Because NIOFS/_NIOFileSystem depend on some non-portable components, such as extended attributes, sendfile, non-portable linkat flags, and renameat2, this is only just partial OpenBSD support, which means that `swift build` on the full swift-nio project won't build cleanly, but at least the portable parts can be used to build servers and clients. This commit will mark the linked bug as fixed; I will open a new bug for file system support. Fixes #3383. --------- Co-authored-by: Rick Newton-Rogers <rnro@apple.com> |
||
|
|
cda536de37 |
Dont hold lock over continuation in NIOThrowingAsyncSequenceProducer (#3454)
Motivation: The various 'withMumbleContinuation' APIs are supposed to be invoked synchronously with the caller. This assumption allows a lock to be acquired before the call and released from the body of the 'withMumbleContinuation' after e.g. storing the continuation. However this isn't the case and the job may be re-enqueued on the executor meaning that this is pattern is vulnerable to deadlocks. Modifications: - Drop and reacquire the lock in the NIOThrowingAsyncSequenceProducer. - Merge 'next()' and 'next(for:)' methods in the state machine into a single func; this reduces the amount of duplicated logic across the two functions. Result: Lower chance of deadlock |