diff --git a/Sources/NIOTransportServices/NIOTSEventLoop.swift b/Sources/NIOTransportServices/NIOTSEventLoop.swift index c316f84..c7f3c51 100644 --- a/Sources/NIOTransportServices/NIOTSEventLoop.swift +++ b/Sources/NIOTransportServices/NIOTSEventLoop.swift @@ -105,19 +105,19 @@ internal class NIOTSEventLoop: QoSEventLoop { return Scheduled(promise: p, cancellationTask: { } ) } - // Dispatch has no support for cancellation, so instead we synchronize over this nice variable. - var cancelled = false - - self.taskQueue.asyncAfter(deadline: DispatchTime(uptimeNanoseconds: DispatchTime.now().uptimeNanoseconds + UInt64(time.nanoseconds)), qos: qos) { - guard !cancelled else { return } + // Dispatch support for cancellation exists at the work-item level, so we explicitly create one here. + // We set the QoS on this work item and explicitly enforce it when the block runs. + let workItem = DispatchWorkItem(qos: qos, flags: .enforceQoS) { do { p.succeed(result: try task()) } catch { p.fail(error: error) } } + + self.taskQueue.asyncAfter(deadline: DispatchTime(uptimeNanoseconds: DispatchTime.now().uptimeNanoseconds + UInt64(time.nanoseconds)), execute: workItem) - return Scheduled(promise: p, cancellationTask: { self.taskQueue.async { cancelled = true } }) + return Scheduled(promise: p, cancellationTask: { workItem.cancel() }) } public func shutdownGracefully(queue: DispatchQueue, _ callback: @escaping (Error?) -> Void) { diff --git a/Sources/NIOTransportServices/StateManagedChannel.swift b/Sources/NIOTransportServices/StateManagedChannel.swift index 78532ed..401d391 100644 --- a/Sources/NIOTransportServices/StateManagedChannel.swift +++ b/Sources/NIOTransportServices/StateManagedChannel.swift @@ -46,12 +46,10 @@ internal enum ChannelState { } fileprivate mutating func beginActivating() throws { - switch self { - case .registered: - self = .activating - case .idle, .activating, .active, .inactive: + guard case .registered = self else { throw NIOTSErrors.InvalidChannelStateTransition() } + self = .activating } fileprivate mutating func becomeActive() throws { @@ -242,9 +240,7 @@ extension StateManagedChannel { return } - if let promise = promise { - promise.succeed(result: ()) - } + promise?.succeed(result: ()) self.pipeline.fireChannelActive() self.readIfNeeded0() }