-
Notifications
You must be signed in to change notification settings - Fork 635
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Better documentation for how to create an Executor #754
Comments
cc @aturon, perhaps excellent fodder for the book you're writing? |
For Futures that don't make progress, deadlocks (and probably panics) should be allowed, but I'm not sure if it should actually be undefined behavior. But I'm not an expert on Futures, so that's for you guys to decide. |
IMO:
should not be true as this could wreak havoc on things like Tokio, timers, etc... |
@carllerche But it's already true: there are various Executors which behavior that way, e.g. Everything I described is behaviors that Executors already have, I am not suggesting new behaviors. Whether the behaviors should be changed is a different issue, this issue is just about documenting the current behaviors (obviously if the behavior is changed then the docs should be changed to match). |
@Pauan Perhaps I misunderstood what you meant, my interpretation of the original statement is not how
|
I'd like to make a subtle distinction here: Futures aren't supposed to call
If a Future calls |
@carllerche You're right, I just tested Requiring
That sounds very odd to me: the whole purpose of
That's a good point, I'll change it.
But it will cause a deadlock on some single-threaded implementations of Executor (such as I have edited the original post to incorporate the changes. |
Running in a javascript VM would be a very different case due to fundamental limitations. However, in Rust, libs are being designed assuming that If an executor implements |
@carllerche I see, you just meant that |
I'm going to go ahead and close this out in light of the re-written docs for 0.2, as well as the (eventual) book, which will talk about this in depth. |
When creating a new Executor from scratch, there's a lot of subtle behavior which currently isn't documented.
This can create edge cases where one Executor behaves differently from another Executor, and Futures might start to rely upon the behavior of a particular Executor.
I believe these behaviors should be documented:
If a Future calls
task.notify()
multiple times within a certain time frame, it's allowed for the Executor to only callpoll
once (rather than once pertask.notify()
)Of course an Executor must call
poll
aftertask.notify()
, but it is allowed to combine multiple calls totask.notify()
together. As an example:With the above code, the Executor is allowed to call
poll
only once, even thoughtask.notify()
was called twice.Under certain pathological situations, it is allowed for the Executor to deadlock.
For example, a Future that calls
task.notify()
inside ofpoll
can sometimes trigger an infinite loop:In the above example, it is allowed for the Executor to deadlock, go into a 100% CPU infinite loop, etc.
In non-pathological situations, it is allowed for a Future to call
task.notify()
inside ofpoll
, and in that situation the Executor must not deadlock.Futures aren't supposed to call
task.notify()
if they cannot make any progress.This is related to the above point. If a Future calls
task.notify()
when nothing will change, then there is the possibility of a deadlock, so they shouldn't do that.This isn't a contract for Executors, it's a contract for Futures, but it affects the way that Executors are allowed to be implemented.
In particular, if a Future calls
task.notify()
without making any progress, then the behavior of the Executor is undefined and it can do anything it wants, including deadlock.Executors are allowed to synchronously call thepoll
method immediately whentask.notify()
is called. In other words, it isn't guaranteed thattask.notify()
is always asynchronous.This affects any situation where a Future callstask.notify()
and then proceeds to do something afterwards. The Future has to deal with the possibility that when it callstask.notify()
it might immediately have consequences.A contrived example is sharing aRefCell
between two Futures. If Future A mutably borrows theRefCell
, and then it callstask.notify()
which triggers Future B, and thepoll
implementation of Future B also mutably borrows theRefCell
, then it might trigger a panic.This behavior is allowed because the Executor is allowed to call thepoll
method immediately whentask.notify()
is called, so Futures need to plan for that.When calling
task.notify()
, it must not callpoll
immediately. In other words,task.notify()
must always be delayed, it yields to the event loop.The text was updated successfully, but these errors were encountered: