Channel.getOption(...) should return EventLoopFuture and not block
Motivation: Channel.getOption(...) should return an EventLoopFuture to ensure we not end up with a deadlock. Modifications: Change getOption(...) to return EventLoopFuture. Result: No deadlocks and more consistent API.
This commit is contained in:
parent
adbcd7c4a8
commit
2180d03690
|
@ -66,7 +66,7 @@ public protocol Channel : class, ChannelOutboundInvoker {
|
|||
func setOption<T: ChannelOption>(option: T, value: T.OptionType) -> EventLoopFuture<Void>
|
||||
|
||||
/// Get the value of `option` for this `Channel`.
|
||||
func getOption<T: ChannelOption>(option: T) throws -> T.OptionType
|
||||
func getOption<T: ChannelOption>(option: T) -> EventLoopFuture<T.OptionType>
|
||||
|
||||
/// Returns if this `Channel` is currently writable.
|
||||
var isWritable: Bool { get }
|
||||
|
|
|
@ -103,8 +103,8 @@ internal final class DeadChannel: Channel {
|
|||
return EventLoopFuture(eventLoop: self.pipeline.eventLoop, error: ChannelError.ioOnClosedChannel, file: #file, line: #line)
|
||||
}
|
||||
|
||||
func getOption<T>(option: T) throws -> T.OptionType where T : ChannelOption {
|
||||
throw ChannelError.ioOnClosedChannel
|
||||
func getOption<T>(option: T) -> EventLoopFuture<T.OptionType> where T : ChannelOption {
|
||||
return eventLoop.newFailedFuture(error: ChannelError.ioOnClosedChannel)
|
||||
}
|
||||
|
||||
let isWritable = false
|
||||
|
|
|
@ -336,9 +336,9 @@ public class EmbeddedChannel : Channel {
|
|||
fatalError("no options supported")
|
||||
}
|
||||
|
||||
public func getOption<T>(option: T) throws -> T.OptionType where T : ChannelOption {
|
||||
public func getOption<T>(option: T) -> EventLoopFuture<T.OptionType> where T : ChannelOption {
|
||||
if option is AutoReadOption {
|
||||
return true as! T.OptionType
|
||||
return self.eventLoop.newSucceededFuture(result: true as! T.OptionType)
|
||||
}
|
||||
fatalError("option \(option) not supported")
|
||||
}
|
||||
|
|
|
@ -305,11 +305,15 @@ class BaseSocketChannel<T : BaseSocket> : SelectableChannel, ChannelCore {
|
|||
}
|
||||
}
|
||||
|
||||
public final func getOption<T: ChannelOption>(option: T) throws -> T.OptionType {
|
||||
public func getOption<T>(option: T) -> EventLoopFuture<T.OptionType> where T : ChannelOption {
|
||||
if eventLoop.inEventLoop {
|
||||
return try getOption0(option: option)
|
||||
do {
|
||||
return eventLoop.newSucceededFuture(result: try getOption0(option: option))
|
||||
} catch {
|
||||
return eventLoop.newFailedFuture(error: error)
|
||||
}
|
||||
} else {
|
||||
return try eventLoop.submit{ try self.getOption0(option: option) }.wait()
|
||||
return eventLoop.submit { try self.getOption0(option: option) }
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -575,7 +579,8 @@ class BaseSocketChannel<T : BaseSocket> : SelectableChannel, ChannelCore {
|
|||
// ChannelError.eof is not something we want to fire through the pipeline as it just means the remote
|
||||
// peer closed / shutdown the connection.
|
||||
if let channelErr = err as? ChannelError, channelErr == ChannelError.eof {
|
||||
if try! getOption(option: ChannelOptions.allowRemoteHalfClosure) {
|
||||
// Directly call getOption0 as we are already on the EventLoop and so not need to create an extra future.
|
||||
if try! getOption0(option: ChannelOptions.allowRemoteHalfClosure) {
|
||||
// If we want to allow half closure we will just mark the input side of the Channel
|
||||
// as closed.
|
||||
pipeline.fireChannelReadComplete0()
|
||||
|
|
Loading…
Reference in New Issue