Repository: rust
Issue: Clarify the behavior of std::task::Waker and Future::Poll
Labels: C-enhancement,T-libs-api,A-async-await,AsyncAwait-Triaged

I have been implemented a few sync mechanism including WaitGroup and MPMC/MPSC in async, althought currently my code seems to work fine. I have some confusion about the documented and feels that there's undefined behavior, especially when future is implemented as lockless and waited/wake_up between multiple thread concurrently.

In https://doc.rust-lang.org/std/future/trait.Future.html there's a saying.
`
Note that on multiple calls to poll, only the Waker from the Context passed to the most recent call should be scheduled to receive a wakeup.`

Before I have any introspect to the low level implemented, I'm assuming the following action should by done when implemented std::future::Future:

-  when poll(), the first thing is should have a test of the condition of readiness
-  register the waker,  either store the waker inside some object, or pass it to event driver reside in other thread.
-  check the condition of readiness again  
-  If poll() return Ready before  the waker atually fired, should do some cleanup of the waker registration resource. 
-  on Drop to the Future object (when use tokio::time::timeout with the future),  should do some cleanup of the waker registration resource

Later I found that when trying to be lockless,  during future::select!  will make the future poll() multiple times,  and register the waker to even driver every time harm the performance. And because I'm not sure  whether waker is the same when produced by the same future during multiple poll().  And when a future expect to seldom waked up (eg close channel receiver poll in combination with other busy channel receiver )  all the waker produced by the same future will take up considerble memory resource if my CustomWaker is not cleanup (cancel) ASAP. 

And then I discovered in all my usage cases the following assumption seems to be valid, which may help greatly to simply and speed up my code in parallel enviromment,  under controllable memory usage:

- A waker is valid from the time ctx.waker().clone() until it's woken up by outsider
-  During multiple poll(),  if the waker of previous call is not woken up, I can expect the future to wake up  on future calls poll() when waker.wake() on previous waker.
- If a call to poll() thinks it's condition is not meet, concurrent wake() will guarantee the future to wake in the future. 

I have a little investigation to tokio-0.2 runtime code:
https://github.com/tokio-rs/tokio/blob/master/tokio/src/runtime/task/raw.rs 
https://github.com/tokio-rs/tokio/blob/master/tokio/src/runtime/task/stack.rs
https://github.com/tokio-rs/tokio/blob/master/tokio/src/runtime/task/waker.rs

std::task::Waker just wraps std::task::RawWaker.  RawWaker.data points to "header" entry allocated on the heap.  when ctx.waker().clone(),  a ref_count of  "header". which means all waker return by ctx.waker().clone() points to the same waker. until all the waker is dropped or waked, the "header" exists.
The logic seems to support my assumption. modfication to my code base on these assumption runs better than before.

I think the document or RFC need to be more clarify, for better users' understanding and for more expectable behavior of different runtime implementations.