-
Notifications
You must be signed in to change notification settings - Fork 656
New issue
Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? # to your account
fix EventLoopFuture.and's serious threading issues #175
Conversation
10ba901
to
a626cdc
Compare
Motivation: EventLoopFuture.and had serious threading issues if the EventLoops weren't the same. Modifications: Fixed the threading issues and tested them properly. Result: Hopefully `and` and `andAll` now don't crash if you use them across EventLoops.
a626cdc
to
1a4929f
Compare
This fix feels wrong: the use of a
The simplest way to handle that is probably to Another option is to If we use the intermediate promise for a minute, I think our code can become this: public func and<U>(_ other: EventLoopFuture<U>, file: StaticString = #file, line: UInt = #line) -> EventLoopFuture<(T,U)> {
let promise = EventLoopPromise<(T,U)>(eventLoop: eventLoop, file: file, line: line)
var tvalue: T?
var uvalue: U?
let otherFuture: EventLoopFuture<U>
if other.eventLoop.inEventLoop {
otherFuture = other
} else {
let threadHoppingPromise: EventLoopPromise<U> = self.eventLoop.newPromise()
other.cascade(promise: threadHoppingPromise)
otherFuture = threadHoppingPromise.futureResult
}
_whenComplete { () -> CallbackList in
switch self.value! {
case .failure(let error):
return promise._setValue(value: .failure(error))
case .success(let t):
if let u = uvalue {
return promise._setValue(value: .success((t, u)))
} else {
tvalue = t
}
}
return CallbackList()
}
otherFuture._whenComplete { () -> CallbackList in
switch otherFuture.value! {
case .failure(let error):
return promise._setValue(value: .failure(error))
case .success(let u):
if let t = tvalue {
return promise._setValue(value: .success((t, u)))
} else {
uvalue = u
}
}
return CallbackList()
}
return promise.futureResult
} This is not actually a sufficient fix because, insanely, this uses the internal public func and<U>(_ other: EventLoopFuture<U>, file: StaticString = #file, line: UInt = #line) -> EventLoopFuture<(T,U)> {
let promise = EventLoopPromise<(T,U)>(eventLoop: self.eventLoop, file: file, line: line)
var tvalue: T?
var uvalue: U?
let otherFuture: EventLoopFuture<U>
if other.eventLoop.inEventLoop {
otherFuture = other
} else {
let threadHoppingPromise: EventLoopPromise<U> = self.eventLoop.newPromise()
other.cascade(promise: threadHoppingPromise)
otherFuture = threadHoppingPromise.futureResult
}
self.map { t in
if let u = uvalue {
promise.succeed(result: (t, u))
} else {
tvalue = t
}
}.cascadeFailure(promise: promise)
otherFuture.map { u in
if let t = tvalue {
promise.succeed(result: (t, u))
} else {
uvalue = u
}
}.cascadeFailure(promise: promise)
return promise.futureResult
} This now seems like code we could feasibly debug, doesn't it? Have I missed something here? |
As a side note, the "thread hopping promise" pattern is not unique to this method, it's present in the |
@Lukasa I totally agree with you, I just wanted to do the smallest working fix. Maybe that was misguided, I can change that if you prefer (you do :) ) |
I definitely prefer changing it. This method is pretty heinous, so now that we're in here messing about with it I think we should burn it back and fix it. I'm working on a PR for the event loop hopping promise real quick, because that's a small patch in its own right. |
I agree with @Lukasa here... let us fix completely once and move on ;) |
@Lukasa besides that, this
afaik isn't threading correct either as you read EDIT: not quite right, |
proposed alternative in #176 |
Closing in favour of #176. |
Motivation Currently we don't confirm that the decompression has completed successfully. This means that we can incorrectly spin forever attempting to decompress past the end of a message, and that we can fail to notice that a message is truncated. Neither of these is good. Modifications Propagate the message zlib gives us as to whether or not decompression is done, and keep track of it. Add some tests written by @vojtarylko to validate the behaviour. Result Correctly police the bounds of the messages. Resolves apple#175 and apple#176.
another 🙈
alternative in #176
Motivation:
EventLoopFuture.and had serious threading issues if the EventLoops
weren't the same.
Modifications:
Fixed the threading issues and tested them properly.
Result:
Hopefully
and
andandAll
now don't crash if you use them acrossEventLoops.