You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
#[test]fnwait_spurious_poll(){use tokio_test::{assert_pending, assert_ready_ok, task};let cell = Arc::new(WaitCell::new());letmut task = task::spawn({let cell = cell.clone();asyncmove{ cell.wait().await}});assert_pending!(task.poll(),"first poll should be pending");assert_pending!(task.poll(),"second poll should be pending");
cell.wake();assert_ready_ok!(task.poll(),"should have been woken");}
The second poll should return Poll::Pending, because the WaitCell has not yet been woken. However:
running 1 test
thread 'sync::wait_cell::tests::spurious_poll' panicked at 'ready; value = Ok(()); second poll should be pending', maitake/src/sync/wait_cell.rs:432:9
stack backtrace:
0: rust_begin_unwind
at /rustc/7820b62d20bc548096d4632a3487987308cb4b5d/library/std/src/panicking.rs:579:5
1: core::panicking::panic_fmt
at /rustc/7820b62d20bc548096d4632a3487987308cb4b5d/library/core/src/panicking.rs:64:14
2: maitake::sync::wait_cell::tests::spurious_poll
3: maitake::sync::wait_cell::tests::spurious_poll::{{closure}}
at ./src/sync/wait_cell.rs:422:24
4: core::ops::function::FnOnce::call_once
at /rustc/7820b62d20bc548096d4632a3487987308cb4b5d/library/core/src/ops/function.rs:250:5
5: core::ops::function::FnOnce::call_once
at /rustc/7820b62d20bc548096d4632a3487987308cb4b5d/library/core/src/ops/function.rs:250:5
note: Some details are omitted, run with `RUST_BACKTRACE=full` for a verbose backtrace.
test sync::wait_cell::tests::spurious_poll ... FAILED
failures:
failures:
sync::wait_cell::tests::spurious_poll
This branch changes the `Wait` future for `maitake::sync::WaitCell` to
handle spurious polls correctly. Currently, a `wait_cell::Wait` future
assumes that if it's ever polled a second time, that means its waker was
woken. However, there might be other reasons that a stack of futures
containing a `Wait` is polled again, and the `Wait` future will
incorrectly complete immediately in that case.
This branch fixes this by replacing the `bool` field in `Wait` that's
set on first poll with an "event count" stored in the remaining
`WaitCell` state bits. Now, when a `Wait` is created, it loads the
current event count, and calls to `wake()` and `close()` increment the
event count. The `Wait` future then checks if the event count has gone
up when it's polled, rather than just checking if it's ever been polled
before. This allows the `Wait` future to determine if it is being polled
because the `WaitCell` woke it up, or if it's being polled because some
other future decided to poll it. This *also* has the side benefit of
fixing racy scenarios where the `WaitCell` is woken between when the
`Wait` future is created and when it's polled for the first time.
Fixes#449
This branch changes the `Wait` future for `maitake::sync::WaitCell` to
handle spurious polls correctly. Currently, a `wait_cell::Wait` future
assumes that if it's ever polled a second time, that means its waker was
woken. However, there might be other reasons that a stack of futures
containing a `Wait` is polled again, and the `Wait` future will
incorrectly complete immediately in that case.
This branch fixes this by replacing the `bool` field in `Wait` that's
set on first poll with an additional bit stored in the `WaitCell`'s
state field. This is set when the cell is actually woken, and only
unset by the `Wait` future when it's polled. If the `WOKEN` bit was
set, the `Wait` future completes, and if it was unset, the future
re-registers itself. This way, the `Wait` future only completes if it
was *woken by the waitcell*, rather than on *any* poll if the task was
woken by something else.
Fixes#449
This test fails:
The second poll should return
Poll::Pending
, because theWaitCell
has not yet been woken. However:Shoutout to @jamesmunns for catching this oen!
The text was updated successfully, but these errors were encountered: