Support preconditionInEventLoop. (#11)

Motivation:

In SwiftNIO 1.11 we shipped improved interfaces for Channels to support
asserting being in the event loop. This is necessary because Dispatch
provides no non-precondition way to 100% guarantee that you are on a
specific queue, which is a requirement for accurate behaviour of
inEventLoop.

Modifications:

- Added an implementation of preconditionInEventLoop.
- Changed all assertions to use new interface.
- Required NIO 1.11.

Result:

Accurate assertions
This commit is contained in:
Cory Benfield 2018-11-06 17:44:41 +00:00 committed by GitHub
parent 9e8685be61
commit a9cece8a6d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 19 additions and 9 deletions

View File

@ -23,7 +23,7 @@ let package = Package(
.executable(name: "NIOTSHTTPServer", targets: ["NIOTSHTTPServer"]),
],
dependencies: [
.package(url: "https://github.com/apple/swift-nio.git", from: "1.8.0"),
.package(url: "https://github.com/apple/swift-nio.git", from: "1.11.0"),
],
targets: [
.target(name: "NIOTransportServices",

View File

@ -276,7 +276,7 @@ extension NIOTSConnectionChannel: Channel {
}
private func setOption0<T: ChannelOption>(option: T, value: T.OptionType) throws {
assert(eventLoop.inEventLoop)
self.eventLoop.assertInEventLoop()
guard !self.closed else {
throw ChannelError.ioOnClosedChannel
@ -320,7 +320,7 @@ extension NIOTSConnectionChannel: Channel {
}
func getOption0<T: ChannelOption>(option: T) throws -> T.OptionType {
assert(eventLoop.inEventLoop)
self.eventLoop.assertInEventLoop()
guard !self.closed else {
throw ChannelError.ioOnClosedChannel

View File

@ -71,6 +71,12 @@ internal class NIOTSEventLoop: QoSEventLoop {
return self.state == .active
}
/// Returns whether the currently executing code is on the event loop.
///
/// Due to limitations in Dispatch's API, this check is pessimistic: there are circumstances where a perfect
/// implementation *could* return `true`, but this version will be unable to prove that and will return `false`.
/// If you need to write an assertion about being in the event loop that must be correct, use SwiftNIO 1.11 or
/// later and call `preconditionInEventLoop` and `assertInEventLoop`.
public var inEventLoop: Bool {
return DispatchQueue.getSpecific(key: self.inQueueKey) == self.loopID
}
@ -127,6 +133,10 @@ internal class NIOTSEventLoop: QoSEventLoop {
queue.async { callback(error) }
}
}
func preconditionInEventLoop(file: StaticString, line: UInt) {
dispatchPrecondition(condition: .onQueue(self.loop))
}
}
extension NIOTSEventLoop {

View File

@ -276,16 +276,16 @@ private class AcceptHandler: ChannelInboundHandler {
@inline(__always)
func setupChildChannel() -> EventLoopFuture<Void> {
return self.childChannelOptions.applyAll(channel: newChannel).then { () -> EventLoopFuture<Void> in
assert(childLoop.inEventLoop)
childLoop.assertInEventLoop()
return childInitializer(newChannel)
}
}
@inline(__always)
func fireThroughPipeline(_ future: EventLoopFuture<Void>) {
assert(ctxEventLoop.inEventLoop)
ctxEventLoop.assertInEventLoop()
future.then { (_) -> EventLoopFuture<Void> in
assert(ctxEventLoop.inEventLoop)
ctxEventLoop.assertInEventLoop()
guard ctx.channel.isActive else {
return newChannel.close().thenThrowing {
throw ChannelError.ioOnClosedChannel
@ -294,7 +294,7 @@ private class AcceptHandler: ChannelInboundHandler {
ctx.fireChannelRead(self.wrapInboundOut(newChannel))
return ctx.eventLoop.newSucceededFuture(result: ())
}.whenFailure { error in
assert(ctx.eventLoop.inEventLoop)
ctx.eventLoop.assertInEventLoop()
_ = newChannel.close()
ctx.fireErrorCaught(error)
}

View File

@ -139,7 +139,7 @@ extension NIOTSListenerChannel: Channel {
}
private func setOption0<T: ChannelOption>(option: T, value: T.OptionType) throws {
assert(eventLoop.inEventLoop)
self.eventLoop.assertInEventLoop()
guard !self.closed else {
throw ChannelError.ioOnClosedChannel
@ -178,7 +178,7 @@ extension NIOTSListenerChannel: Channel {
}
func getOption0<T: ChannelOption>(option: T) throws -> T.OptionType {
assert(eventLoop.inEventLoop)
self.eventLoop.assertInEventLoop()
guard !self.closed else {
throw ChannelError.ioOnClosedChannel