Re: [PATCH 12/13] rust: sync: introduce `CondVar`

From: Peter Zijlstra
Date: Mon Apr 03 2023 - 05:00:30 EST


On Thu, Mar 30, 2023 at 11:56:33AM -0300, Wedson Almeida Filho wrote:
> On Thu, Mar 30, 2023 at 02:59:27PM +0200, Peter Zijlstra wrote:
> > On Thu, Mar 30, 2023 at 01:39:53AM -0300, Wedson Almeida Filho wrote:
> >
> > > + fn wait_internal<T: ?Sized, B: Backend>(&self, wait_state: u32, guard: &mut Guard<'_, T, B>) {
> > > + let wait = Opaque::<bindings::wait_queue_entry>::uninit();
> > > +
> > > + // SAFETY: `wait` points to valid memory.
> > > + unsafe { bindings::init_wait(wait.get()) };
> > > +
> > > + // SAFETY: Both `wait` and `wait_list` point to valid memory.
> > > + unsafe {
> > > + bindings::prepare_to_wait_exclusive(self.wait_list.get(), wait.get(), wait_state as _)
> > > + };
> >
> > I can't read this rust gunk, but where is the condition test gone?
> >
> > Also, where is the loop gone to?
>
> They're both at the caller. The usage of condition variables is something like:
>
> while guard.value != v {
> condvar.wait_uninterruptible(&mut guard);
> }
>
> (Note that this is not specific to the kernel or to Rust: this is how condvars
> work in general. You'll find this in any textbook on the topic.)
>
> In the implementation of wait_internal(), we add the local wait entry to the
> wait queue _before_ releasing the lock (i.e., before the test result can
> change), so we guarantee that we don't miss wake up attempts.

Ah, so you've not yet been exposed to the wonderful 'feature' where
pthread_cond_timedwait() gets called with .mutex=NULL and people expect
things to just work :/ (luckily not accepted by the majority of
implementations)

Or a little more devious, calling signal and not holding the same mutex.

But then yes, I suppose it should work. I just got alarm bells going off
because I see prepare_to_wait without an obvious loop around it.