"Reentrancy" guarantees of std::task::Waker::wake

I am not sure how to correctly phrase the question, but can the wake method cause some task to be polled immediately (in the same stack frame)?

In other words, are executors obliged to clear the stack before starting to poll a future, or are they allowed to do this on some other future's stack?

I am looking at roughly the following code:

let ref_mut = shared_ref_cell.borrow_mut();
some_waker.wake();
drop(ref_mut)

and I am wondering if the call to wake can re-enter and cause a panic on recursively borrowing a RefCell.

1 Like

Is this code that ends up in a poll method of a Future? Because that method borrows the future mutsbly, hence reentreant calls are impossible.

(My intuition for executors is limited, please tell me if my question does not make sense.)

There's no guarantee that it can't, however a much more likely thing is that waking the waker can cause the future to be dropped, which can cause similar problems if the RefCell is accessed in the destructor.

@steffahn I assume the RefCell is shared with the future through e.g. an Rc.

2 Likes

It indeed ends up in the poll, so the current future can't get polled. But the state is shared between several futures (it's an Rc<RefCell<Thing>>) and an the executor can, in theory, poll different futures.

We had the same discussion in the Tokio developer group about waking futures while a mutex is locked. And the general consensus is that it's a bad idea to do so, and that you should unlock it first.

The reason that the future could be dropped when waking the waker is that the future may be implemented as an Arc, and the waker could also contain an Arc into this future. Thus when the wake call consumes the waker, the ref-count drops to zero and it is dropped.

1 Like