Skip to content

Commit

Permalink
Make assumeIsolated work with SerialExecutors that are backed by Ev…
Browse files Browse the repository at this point in the history
…entLoops (#2865)

Allow usage of `assumeIsolated` in SerialExecutors that are backed by
EventLoops.

### Motivation:

We want to support all new Swift 6 features in SerialExecutors.

### Modifications:

- Implement `isSameExclusiveExecutionContext`
- Implement `checkIsolated`

### Result:

We can use `assumeIsolated` in actors that use an `EventLoop` as their
`SerialExecutor`.
  • Loading branch information
fabianfett authored Sep 3, 2024
1 parent 196928d commit 9746cf8
Show file tree
Hide file tree
Showing 2 changed files with 39 additions and 1 deletion.
14 changes: 13 additions & 1 deletion Sources/NIOCore/EventLoop+SerialExecutor.swift
Original file line number Diff line number Diff line change
Expand Up @@ -36,13 +36,25 @@ extension NIOSerialEventLoopExecutor {

@inlinable
public func asUnownedSerialExecutor() -> UnownedSerialExecutor {
UnownedSerialExecutor(ordinary: self)
UnownedSerialExecutor(complexEquality: self)
}

@inlinable
public var executor: any SerialExecutor {
self
}

@available(macOS 14.0, iOS 17.0, watchOS 10.0, tvOS 17.0, *)
@inlinable
public func isSameExclusiveExecutionContext(other: Self) -> Bool {
other === self
}

@available(macOS 15.0, iOS 18.0, watchOS 11.0, tvOS 18.0, *)
@inlinable
public func checkIsolated() {
self.preconditionInEventLoop()
}
}

/// A type that wraps a NIO ``EventLoop`` into a `SerialExecutor`
Expand Down
26 changes: 26 additions & 0 deletions Tests/NIOPosixTests/SerialExecutorTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@ import XCTest
actor EventLoopBoundActor {
nonisolated let unownedExecutor: UnownedSerialExecutor

var counter: Int = 0

init(loop: EventLoop) {
self.unownedExecutor = loop.executor.asUnownedSerialExecutor()
}
Expand All @@ -34,6 +36,14 @@ actor EventLoopBoundActor {
loop.assertNotInEventLoop()
XCTAssertFalse(loop.inEventLoop)
}

#if compiler(>=6.0)
nonisolated func assumeInLoop() -> Int {
self.assumeIsolated { actor in
actor.counter
}
}
#endif
}
#endif

Expand Down Expand Up @@ -69,4 +79,20 @@ final class SerialExecutorTests: XCTestCase {

try await self._testBasicExecutorFitsOnEventLoop(loop1: loop1, loop2: loop2)
}

func testAssumeIsolation() async throws {
#if compiler(<6.0)
throw XCTSkip("Custom executors are only supported in 5.9")
#else

let group = MultiThreadedEventLoopGroup(numberOfThreads: 1)
let el = group.next()

let testActor = EventLoopBoundActor(loop: el)
let result = try await el.submit {
testActor.assumeInLoop()
}.get()
XCTAssertEqual(result, 0)
#endif
}
}

0 comments on commit 9746cf8

Please sign in to comment.