All of lore.kernel.org
 help / color / mirror / Atom feed
From: Paolo Bonzini <pbonzini@redhat.com>
To: Lyude Paul <lyude@redhat.com>,
	linux-kernel@vger.kernel.org, rust-for-linux@vger.kernel.org,
	Benno Lossin <lossin@kernel.org>
Cc: "Peter Zijlstra" <peterz@infradead.org>,
	"Ingo Molnar" <mingo@redhat.com>, "Will Deacon" <will@kernel.org>,
	"Boqun Feng" <boqun.feng@gmail.com>,
	"Waiman Long" <longman@redhat.com>,
	"Miguel Ojeda" <ojeda@kernel.org>,
	"Alex Gaynor" <alex.gaynor@gmail.com>,
	"Gary Guo" <gary@garyguo.net>,
	"Björn Roy Baron" <bjorn3_gh@protonmail.com>,
	"Andreas Hindborg" <a.hindborg@kernel.org>,
	"Alice Ryhl" <aliceryhl@google.com>,
	"Trevor Gross" <tmgross@umich.edu>,
	"Danilo Krummrich" <dakr@kernel.org>
Subject: Re: [PATCH v4] rust: lock: Export Guard::do_unlocked()
Date: Thu, 30 Oct 2025 11:43:30 +0100	[thread overview]
Message-ID: <c1ff48ea-53ca-40ea-9541-85abd1a528d0@redhat.com> (raw)
In-Reply-To: <20251029183538.226257-1-lyude@redhat.com>

On 10/29/25 19:35, Lyude Paul wrote:
> +    /// // Since we hold work.lock, which work will also try to acquire in WorkItem::run. Dropping
> +    /// // the lock temporarily while we wait for completion works around this.
> +    /// g.do_unlocked(|| work.done.wait_for_completion());
> +    ///
> +    /// assert_eq!(*g, 42);
> +    /// ```
> +    pub fn do_unlocked<U>(&mut self, cb: impl FnOnce() -> U) -> U {
>           // SAFETY: The caller owns the lock, so it is safe to unlock it.
>           unsafe { B::unlock(self.lock.state.get(), &self.state) };

Getting self as &mut is incorrect.  That's because owning a lock guard 
implicitly tells you that no other thread can observe the intermediate 
states of the object.  (The same is even more obviously true for a 
RefCell's mutable borrow, i.e. core::cell::RefMut)

Let's say you have a lock-protected data structure with an invariant 
that is preserved at the end of every critical section.  Let's say also 
that you have a function

     fn do_something() {
         let g = self.inner.lock();
         g.mess_up_the_invariant();          // (1)
         self.do_something_else(&mut g);     // uses do_unlocked()
         g.fix_the_invariant();              // (2)
     }

Because the function holds a guard between the calls (1) and (2), it 
expects that other thread cannot observe the temporary state.  The fact 
that do_unlocked() takes a &mut doesn't help, because the common case 
for RAII objects is that they're passed around mutably.

Instead, do_unlocked should take the guard and return another one:

     fn do_something() {
         let mut g = self.inner.lock();
         g.mess_up_the_invariant();          // (1)
         g = self.do_something_else(g);      // uses do_unlocked()
         g.fix_the_invariant();              // (2)
     }

This version of the interface makes it clear that (1) and (2) are in a 
separate critical section.  Unfortunately it makes the signature uglier 
for do_unlocked() itself:

     #[must_use]
     pub fn do_unlocked<U>(self, cb: impl FnOnce() -> U) -> (Self, U)

Paolo


  reply	other threads:[~2025-10-30 10:43 UTC|newest]

Thread overview: 7+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2025-10-29 18:35 [PATCH v4] rust: lock: Export Guard::do_unlocked() Lyude Paul
2025-10-30 10:43 ` Paolo Bonzini [this message]
2025-10-30 17:41   ` Lyude Paul
2025-10-31  9:31     ` Alice Ryhl
2025-10-31  9:38       ` Paolo Bonzini
2025-10-31 10:24         ` Alice Ryhl
2025-11-05 20:41           ` Lyude Paul

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=c1ff48ea-53ca-40ea-9541-85abd1a528d0@redhat.com \
    --to=pbonzini@redhat.com \
    --cc=a.hindborg@kernel.org \
    --cc=alex.gaynor@gmail.com \
    --cc=aliceryhl@google.com \
    --cc=bjorn3_gh@protonmail.com \
    --cc=boqun.feng@gmail.com \
    --cc=dakr@kernel.org \
    --cc=gary@garyguo.net \
    --cc=linux-kernel@vger.kernel.org \
    --cc=longman@redhat.com \
    --cc=lossin@kernel.org \
    --cc=lyude@redhat.com \
    --cc=mingo@redhat.com \
    --cc=ojeda@kernel.org \
    --cc=peterz@infradead.org \
    --cc=rust-for-linux@vger.kernel.org \
    --cc=tmgross@umich.edu \
    --cc=will@kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.