Yours (after pinning was added) worked when there is no competition for the lock, as on a typical poll_read
you would:
- successfully lock the lock (without receiving
Poll::Pending
even once)
- successfully read.
However, if there was competition, as soon as you don't instantly get a lock, you would bail, and drop the MutexLockFuture
, (representing your place in line to lock the Mutex) without making use of its waking capability.
let mut stack = match self.stack.lock().boxed().as_mut().poll(cx) {
Poll::Pending => return Poll::Pending,
Poll::Ready(stack) => stack,
};
// the lockfuture has been `Drop`ped at this point, which de-registers your interest in the availability of the Mutex
is basically equivalent to
let mut stack = match self.stack.try_lock() {
None => return Poll::Pending,
Some(stack) => stack,
};
(+ additional thrashing of registering then deregistering the waking rather than it never existing in the first place)
It's said that anyone implementing a poll
of some kind is responsible for having wakers registered if returning Poll::Pending
, lest they block forever.
Further to this, if this deadlock could be avoided somehow, and that's what the many lines of "acquired lock" show, in the cases of:
- underlying
read
call filled your buffer
- you successfully
read
some amount, but not everything you wanted
- the underlying
AsyncRead
was not ready (returned Pending
)
you will undesirably drop the successfully acquired lock guard, which means:
- you will have to acquire it again next time you
poll_read
- someone else might grab it in the meantime, and read some data from the middle of what you were expecting, so you end up with garbage.
However, with a reader adapter that locks once and stays locked until it's dropped, you might be able to produce reasonable behavior.