Skip to content

Commit c55a9f5

Browse files
committed
rust: add UniqueRef.
This allows a ref-counted object to be allocated but initialised later. It is useful, for example, to allocate in one context (e.g., sleepable context) and initialise in a different context (e.g., atomic context). It can also be used to get mutable references to the inner object after it has been allocated, but before it can be shared (in which case it becomes pinned and there is no safe path to the mutable inner object). It is the last remaining feature before we can remove all usages of `Arc<T>` from Binder. Signed-off-by: Wedson Almeida Filho <[email protected]>
1 parent 9027821 commit c55a9f5

File tree

2 files changed

+159
-18
lines changed

2 files changed

+159
-18
lines changed

rust/kernel/sync/arc.rs

Lines changed: 158 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -25,8 +25,8 @@ use core::{
2525
cell::UnsafeCell,
2626
convert::{AsRef, TryFrom},
2727
marker::{PhantomData, Unsize},
28-
mem::ManuallyDrop,
29-
ops::Deref,
28+
mem::{ManuallyDrop, MaybeUninit},
29+
ops::{Deref, DerefMut},
3030
pin::Pin,
3131
ptr::{self, NonNull},
3232
};
@@ -75,17 +75,10 @@ unsafe impl<T: ?Sized + Sync + Send> Sync for Ref<T> {}
7575
impl<T> Ref<T> {
7676
/// Constructs a new reference counted instance of `T`.
7777
pub fn try_new(contents: T) -> Result<Self> {
78-
Self::try_new_and_init(contents, |_| {})
79-
}
80-
81-
/// Constructs a new reference counted instance of `T` and calls the initialisation function.
82-
///
83-
/// This is useful because it provides a mutable reference to `T` at its final location.
84-
pub fn try_new_and_init<U: FnOnce(Pin<&mut T>)>(contents: T, init: U) -> Result<Self> {
8578
let layout = Layout::new::<RefInner<T>>();
8679
// SAFETY: The layout size is guaranteed to be non-zero because `RefInner` contains the
8780
// reference count.
88-
let mut inner = NonNull::new(unsafe { alloc(layout) })
81+
let inner = NonNull::new(unsafe { alloc(layout) })
8982
.ok_or(Error::ENOMEM)?
9083
.cast::<RefInner<T>>();
9184

@@ -98,18 +91,18 @@ impl<T> Ref<T> {
9891
// SAFETY: `inner` is writable and properly aligned.
9992
unsafe { inner.as_ptr().write(value) };
10093

101-
// SAFETY: By the invariant, `RefInner` is pinned and `T` is also pinned.
102-
let pinned = unsafe { Pin::new_unchecked(&mut inner.as_mut().data) };
103-
104-
// INVARIANT: The only places where `&mut T` is available are here, which is explicitly
105-
// pinned, and in `drop`. Both are compatible with the pin requirements.
106-
init(pinned);
107-
10894
// SAFETY: We just created `inner` with a reference count of 1, which is owned by the new
10995
// `Ref` object.
11096
Ok(unsafe { Self::from_inner(inner) })
11197
}
11298

99+
/// Constructs a new reference counted instance of `T` and calls the initialisation function.
100+
///
101+
/// This is useful because it provides a mutable reference to `T` at its final location.
102+
pub fn try_new_and_init<U: FnOnce(Pin<&mut T>)>(contents: T, init: U) -> Result<Self> {
103+
Ok(UniqueRef::try_new(contents)?.pin_init_and_share(init))
104+
}
105+
113106
/// Deconstructs a [`Ref`] object into a `usize`.
114107
///
115108
/// It can be reconstructed once via [`Ref::from_usize`].
@@ -306,6 +299,12 @@ impl<T> TryFrom<Vec<T>> for Ref<[T]> {
306299
}
307300
}
308301

302+
impl<T: ?Sized> From<UniqueRef<T>> for Ref<T> {
303+
fn from(item: UniqueRef<T>) -> Self {
304+
item.inner
305+
}
306+
}
307+
309308
/// A borrowed [`Ref`] with manually-managed lifetime.
310309
///
311310
/// # Invariants
@@ -337,3 +336,145 @@ impl<T: ?Sized> Deref for RefBorrow<T> {
337336
self.inner_ref.deref()
338337
}
339338
}
339+
340+
/// A refcounted object that is known to have a refcount of 1.
341+
///
342+
/// It is mutable and can be converted to a [`Ref`] so that it can be shared.
343+
///
344+
/// # Invariants
345+
///
346+
/// `inner` always has a reference count of 1.
347+
///
348+
/// # Examples
349+
///
350+
/// In the following example, we make changes to the inner object before turning it into a
351+
/// `Ref<Test>` object (after which point, it cannot be mutated directly). Note that `x.into()`
352+
/// cannot fail.
353+
///
354+
/// ```
355+
/// # use kernel::prelude::*;
356+
/// use kernel::sync::{Ref, UniqueRef};
357+
///
358+
/// struct Example {
359+
/// a: u32,
360+
/// b: u32,
361+
/// }
362+
///
363+
/// fn test() -> Result<Ref<Example>> {
364+
/// let mut x = UniqueRef::try_new(Example { a: 10, b: 20 })?;
365+
/// x.a += 1;
366+
/// x.b += 1;
367+
/// Ok(x.into())
368+
/// }
369+
/// ```
370+
///
371+
/// In the following example we first allocate memory for a ref-counted `Example` but we don't
372+
/// initialise it on allocation. We do initialise it later with a call to [`UniqueRef::write`],
373+
/// followed by a conversion to `Ref<Example>`. This is particularly useful when allocation happens
374+
/// in one context (e.g., sleepable) and initialisation in another (e.g., atomic):
375+
///
376+
/// ```
377+
/// # use kernel::prelude::*;
378+
/// use kernel::sync::{Ref, UniqueRef};
379+
///
380+
/// struct Example {
381+
/// a: u32,
382+
/// b: u32,
383+
/// }
384+
///
385+
/// fn test2() -> Result<Ref<Example>> {
386+
/// let x = UniqueRef::try_new_uninit()?;
387+
/// Ok(x.write(Example { a: 10, b: 20 }).into())
388+
/// }
389+
/// ```
390+
///
391+
/// In the last example below, the caller gets a pinned instance of `Example` while converting to
392+
/// `Ref<Example>`; this is useful in scenarios where one needs a pinned reference during
393+
/// initialisation, for example, when initialising fields that are wrapped in locks.
394+
///
395+
/// ```
396+
/// # use kernel::prelude::*;
397+
/// use kernel::sync::{Ref, UniqueRef};
398+
///
399+
/// struct Example {
400+
/// a: u32,
401+
/// b: u32,
402+
/// }
403+
///
404+
/// fn test2() -> Result<Ref<Example>> {
405+
/// let mut x = UniqueRef::try_new(Example { a: 10, b: 20 })?;
406+
/// // We can modify `pinned` because it is `Unpin`.
407+
/// Ok(x.pin_init_and_share(|mut pinned| pinned.a += 1))
408+
/// }
409+
/// ```
410+
pub struct UniqueRef<T: ?Sized> {
411+
inner: Ref<T>,
412+
}
413+
414+
impl<T> UniqueRef<T> {
415+
/// Tries to allocate a new [`UniqueRef`] instance.
416+
pub fn try_new(value: T) -> Result<Self> {
417+
Ok(Self {
418+
// INVARIANT: The newly-created object has a ref-count of 1.
419+
inner: Ref::try_new(value)?,
420+
})
421+
}
422+
423+
/// Tries to allocate a new [`UniqueRef`] instance whose contents are not initialised yet.
424+
pub fn try_new_uninit() -> Result<UniqueRef<MaybeUninit<T>>> {
425+
Ok(UniqueRef::<MaybeUninit<T>> {
426+
// INVARIANT: The newly-created object has a ref-count of 1.
427+
inner: Ref::try_new(MaybeUninit::uninit())?,
428+
})
429+
}
430+
}
431+
432+
impl<T: ?Sized> UniqueRef<T> {
433+
/// Converts a [`UniqueRef<T>`] into a [`Ref<T>`].
434+
///
435+
/// It allows callers to get a `Pin<&mut T>` that they can use to initialise the inner object
436+
/// just before it becomes shareable.
437+
pub fn pin_init_and_share<U: FnOnce(Pin<&mut T>)>(mut self, init: U) -> Ref<T> {
438+
let inner = self.deref_mut();
439+
440+
// SAFETY: By the `Ref` invariant, `RefInner` is pinned and `T` is also pinned.
441+
let pinned = unsafe { Pin::new_unchecked(inner) };
442+
443+
// INVARIANT: The only places where `&mut T` is available are here (where it is explicitly
444+
// pinned, i.e. implementations of `init` will see a Pin<&mut T>), and in `Ref::drop`. Both
445+
// are compatible with the pin requirements of the invariants of `Ref`.
446+
init(pinned);
447+
448+
self.into()
449+
}
450+
}
451+
452+
impl<T> UniqueRef<MaybeUninit<T>> {
453+
/// Converts a `UniqueRef<MaybeUninit<T>>` into a `UniqueRef<T>` by writing a value into it.
454+
pub fn write(mut self, value: T) -> UniqueRef<T> {
455+
self.deref_mut().write(value);
456+
let inner = ManuallyDrop::new(self).inner.ptr;
457+
UniqueRef {
458+
// SAFETY: The new `Ref` is taking over `ptr` from `self.inner` (which won't be
459+
// dropped). The types are compatible because `MaybeUninit<T>` is compatible with `T`.
460+
inner: unsafe { Ref::from_inner(inner.cast()) },
461+
}
462+
}
463+
}
464+
465+
impl<T: ?Sized> Deref for UniqueRef<T> {
466+
type Target = T;
467+
468+
fn deref(&self) -> &Self::Target {
469+
self.inner.deref()
470+
}
471+
}
472+
473+
impl<T: ?Sized> DerefMut for UniqueRef<T> {
474+
fn deref_mut(&mut self) -> &mut Self::Target {
475+
// SAFETY: By the `Ref` type invariant, there is necessarily a reference to the object, so
476+
// it is safe to dereference it. Additionally, we know there is only one reference when
477+
// it's inside a `UniqueRef`, so it is safe to get a mutable reference.
478+
unsafe { &mut self.inner.ptr.as_mut().data }
479+
}
480+
}

rust/kernel/sync/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ mod locked_by;
3131
mod mutex;
3232
mod spinlock;
3333

34-
pub use arc::{Ref, RefBorrow};
34+
pub use arc::{Ref, RefBorrow, UniqueRef};
3535
pub use condvar::CondVar;
3636
pub use guard::{Guard, Lock};
3737
pub use locked_by::LockedBy;

0 commit comments

Comments
 (0)