Skip to content

Commit

Permalink
use pin_init
Browse files Browse the repository at this point in the history
  • Loading branch information
nbdd0121 committed Jun 11, 2021
1 parent 4201017 commit 549b8e3
Show file tree
Hide file tree
Showing 13 changed files with 138 additions and 156 deletions.
24 changes: 10 additions & 14 deletions drivers/android/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,9 @@ struct Manager {
uid: Option<bindings::kuid_t>,
}

#[pin_init]
pub(crate) struct Context {
#[pin]
manager: Mutex<Manager>,
}

Expand All @@ -25,23 +27,17 @@ unsafe impl Sync for Context {}

impl Context {
pub(crate) fn new() -> Result<Pin<Arc<Self>>> {
let mut ctx_ref = Arc::try_new(Self {
let ctx = Arc::try_pin_with(init_pin!(Self {
// SAFETY: Init is called below.
manager: unsafe {
Mutex::new(Manager {
manager: kernel::mutex_new!(
"Context::manager",
Manager {
node: None,
uid: None,
})
},
})?;
let ctx = Arc::get_mut(&mut ctx_ref).unwrap();

// SAFETY: `manager` is also pinned when `ctx` is.
let manager = unsafe { Pin::new_unchecked(&ctx.manager) };
kernel::mutex_init!(manager, "Context::manager");

// SAFETY: `ctx_ref` is pinned behind the `Arc` reference.
Ok(unsafe { Pin::new_unchecked(ctx_ref) })
}
),
}))?;
Ok(ctx)
}

pub(crate) fn set_manager_node(&self, node_ref: NodeRef) -> Result {
Expand Down
27 changes: 14 additions & 13 deletions drivers/android/node.rs
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ struct NodeDeathInner {
aborted: bool,
}

#[pin_init]
pub(crate) struct NodeDeath {
node: Arc<Node>,
process: Ref<Process>,
Expand All @@ -67,6 +68,7 @@ pub(crate) struct NodeDeath {
// TODO: Add the moment we're using this for two lists, which isn't safe because we want to
// remove from the list without knowing the list it's in. We need to separate this out.
death_links: Links<NodeDeath>,
#[pin]
inner: SpinLock<NodeDeathInner>,
}

Expand All @@ -76,28 +78,27 @@ impl NodeDeath {
/// # Safety
///
/// The caller must call `NodeDeath::init` before using the notification object.
pub(crate) unsafe fn new(node: Arc<Node>, process: Ref<Process>, cookie: usize) -> Self {
Self {
pub(crate) fn new(
node: Arc<Node>,
process: Ref<Process>,
cookie: usize,
) -> impl kernel::pin::Init<Self, kernel::Error> {
init_pin!(Self {
node,
process,
cookie,
work_links: Links::new(),
death_links: Links::new(),
inner: unsafe {
SpinLock::new(NodeDeathInner {
inner: kernel::spinlock_new!(
"NodeDeath::inner",
NodeDeathInner {
dead: false,
cleared: false,
notification_done: false,
aborted: false,
})
},
}
}

pub(crate) fn init(self: Pin<&Self>) {
// SAFETY: `inner` is pinned when `self` is.
let inner = unsafe { self.map_unchecked(|s| &s.inner) };
kernel::spinlock_init!(inner, "NodeDeath::inner");
}
),
})
}

/// Sets the cleared flag to `true`.
Expand Down
74 changes: 22 additions & 52 deletions drivers/android/process.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ use kernel::{
io_buffer::{IoBufferReader, IoBufferWriter},
linked_list::List,
pages::Pages,
pin::UniqueArc,
prelude::*,
sync::{Guard, Mutex, Ref, RefCount, RefCounted},
user_ptr::{UserSlicePtr, UserSlicePtrReader},
Expand Down Expand Up @@ -219,32 +220,6 @@ impl ProcessInner {
}
}

struct ArcReservation<T> {
mem: Arc<MaybeUninit<T>>,
}

impl<T> ArcReservation<T> {
fn new() -> Result<Self> {
Ok(Self {
mem: Arc::try_new(MaybeUninit::<T>::uninit())?,
})
}

fn commit(mut self, data: T) -> Arc<T> {
// SAFETY: Memory was allocated and properly aligned by using `MaybeUninit`.
unsafe {
Arc::get_mut(&mut self.mem)
.unwrap()
.as_mut_ptr()
.write(data);
}

// SAFETY: We have just initialised the memory block, and we know it's compatible with `T`
// because we used `MaybeUninit`.
unsafe { Arc::from_raw(Arc::into_raw(self.mem) as _) }
}
}

struct NodeRefInfo {
node_ref: NodeRef,
death: Option<Pin<Arc<NodeDeath>>>,
Expand Down Expand Up @@ -273,6 +248,7 @@ impl ProcessNodeRefs {
}
}

#[pin_init]
pub(crate) struct Process {
ctx: Arc<Context>,
ref_count: RefCount,
Expand All @@ -281,10 +257,12 @@ pub(crate) struct Process {
// holding the lock. We may want to split up the process state at some point to use a spin lock
// for the other fields; we can also get rid of allocations in BTreeMap once we replace it.
// TODO: Make this private again.
#[pin]
pub(crate) inner: Mutex<ProcessInner>,

// References are in a different mutex to avoid recursive acquisition when
// incrementing/decrementing a node in another process.
#[pin]
node_refs: Mutex<ProcessNodeRefs>,
}

Expand All @@ -293,23 +271,15 @@ unsafe impl Sync for Process {}

impl Process {
fn new(ctx: Arc<Context>) -> Result<Pin<Ref<Self>>> {
let mut proc_ref = Ref::try_new(Self {
let process = Ref::try_pin_with(init_pin!(Self {
ref_count: RefCount::new(),
ctx,
// SAFETY: `inner` is initialised in the call to `mutex_init` below.
inner: unsafe { Mutex::new(ProcessInner::new()) },
inner: kernel::mutex_new!("Process::inner", ProcessInner::new()),
// SAFETY: `node_refs` is initialised in the call to `mutex_init` below.
node_refs: unsafe { Mutex::new(ProcessNodeRefs::new()) },
})?;
let process = Ref::get_mut(&mut proc_ref).ok_or(Error::EINVAL)?;
// SAFETY: `inner` is pinned behind the `Arc` reference.
let pinned = unsafe { Pin::new_unchecked(&process.inner) };
kernel::mutex_init!(pinned, "Process::inner");
// SAFETY: `node_refs` is pinned behind the `Arc` reference.
let pinned = unsafe { Pin::new_unchecked(&process.node_refs) };
kernel::mutex_init!(pinned, "Process::node_refs");
// SAFETY: Pointer is pinned behind `Ref`.
Ok(unsafe { Pin::new_unchecked(proc_ref) })
node_refs: kernel::mutex_new!("Process::node_refs", ProcessNodeRefs::new()),
}))?;
Ok(process)
}

/// Attemps to fetch a work item from the process queue.
Expand Down Expand Up @@ -698,10 +668,12 @@ impl Process {
// TODO: Do we care about the context manager dying?

// Queue BR_ERROR if we can't allocate memory for the death notification.
let death = ArcReservation::new().map_err(|err| {
thread.push_return_work(BR_ERROR);
err
})?;
let death: Pin<_> = UniqueArc::try_new(MaybeUninit::uninit())
.map_err(|err| {
thread.push_return_work(BR_ERROR);
err
})?
.into();

let mut refs = self.node_refs.lock();
let info = refs.by_handle.get_mut(&handle).ok_or(Error::EINVAL)?;
Expand All @@ -711,15 +683,13 @@ impl Process {
return Ok(());
}

// SAFETY: `init` is called below.
let death = death.commit(unsafe {
NodeDeath::new(info.node_ref.node.clone(), Ref::new_from(self), cookie)
});
// SAFETY: `death` is pinned behind the `Arc` reference.
let death = unsafe { Pin::new_unchecked(death) };
// SAFETY: `death` is pinned behind the `Arc` reference.
death.as_ref().init();

// NOPANIC: This initialization always succeeds
let death = UniqueArc::init(
death,
NodeDeath::new(info.node_ref.node.clone(), Ref::new_from(self), cookie),
)
.unwrap();
let death = UniqueArc::shareable_pin(death);
info.death = Some(death.clone());

// Register the death notification.
Expand Down
21 changes: 8 additions & 13 deletions drivers/android/thread.rs
Original file line number Diff line number Diff line change
Expand Up @@ -224,10 +224,13 @@ impl InnerThread {
}
}

#[pin_init]
pub(crate) struct Thread {
pub(crate) id: i32,
pub(crate) process: Ref<Process>,
#[pin]
inner: SpinLock<InnerThread>,
#[pin]
work_condvar: CondVar,
links: Links<Thread>,
}
Expand All @@ -236,27 +239,19 @@ impl Thread {
pub(crate) fn new(id: i32, process: Ref<Process>) -> Result<Pin<Arc<Self>>> {
let return_work = Arc::try_new(ThreadError::new(InnerThread::set_return_work))?;
let reply_work = Arc::try_new(ThreadError::new(InnerThread::set_reply_work))?;
let mut arc = Arc::try_new(Self {
let arc = Arc::try_pin_with(init_pin!(Self {
id,
process,
// SAFETY: `inner` is initialised in the call to `spinlock_init` below.
inner: unsafe { SpinLock::new(InnerThread::new()) },
// SAFETY: `work_condvar` is initalised in the call to `condvar_init` below.
work_condvar: unsafe { CondVar::new() },
inner: kernel::spinlock_new!("Thread::inner", InnerThread::new()),
work_condvar: kernel::condvar_new!("Thread::work_condvar"),
links: Links::new(),
})?;
let thread = Arc::get_mut(&mut arc).unwrap();
// SAFETY: `inner` is pinned behind the `Arc` reference.
let inner = unsafe { Pin::new_unchecked(&thread.inner) };
kernel::spinlock_init!(inner, "Thread::inner");
let condvar = unsafe { Pin::new_unchecked(&thread.work_condvar) };
kernel::condvar_init!(condvar, "Thread::work_condvar");
}))?;
{
let mut inner = arc.inner.lock();
inner.set_reply_work(reply_work);
inner.set_return_work(return_work);
}
Ok(unsafe { Pin::new_unchecked(arc) })
Ok(arc)
}

pub(crate) fn set_current_transaction(&self, transaction: Arc<Transaction>) {
Expand Down
5 changes: 5 additions & 0 deletions rust/kernel/prelude.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,3 +24,8 @@ pub use super::static_assert;
pub use super::{KernelModule, Result};

pub use crate::traits::TryPin;

pub use super::{
init_stack,
pin::{init_pin, pin_init, Init, PtrInit as _, PtrTryPinWith as _},
};
11 changes: 10 additions & 1 deletion rust/kernel/sync/arc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,12 @@
//!
//! [`Arc`]: https://doc.rust-lang.org/std/sync/struct.Arc.html
use crate::Result;
use crate::{prelude::*, Result};
use alloc::boxed::Box;
use core::{
mem::ManuallyDrop,
ops::Deref,
pin::Pin,
ptr::NonNull,
sync::atomic::{fence, AtomicUsize, Ordering},
};
Expand Down Expand Up @@ -54,6 +55,14 @@ impl<T: RefCounted> Ref<T> {
let ptr = NonNull::from(Box::leak(boxed));
Ok(Ref { ptr })
}

pub fn try_pin_with(contents: impl crate::pin::Init<T, crate::Error>) -> Result<Pin<Self>> {
let pin_box = Box::try_pin_with(contents)?;
let boxed = unsafe { Pin::into_inner_unchecked(pin_box) };
boxed.get_count().count.store(1, Ordering::Relaxed);
let ptr = NonNull::from(Box::leak(boxed));
Ok(unsafe { Pin::new_unchecked(Ref { ptr }) })
}
}

impl<T: RefCounted + ?Sized> Ref<T> {
Expand Down
15 changes: 11 additions & 4 deletions rust/kernel/sync/condvar.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,18 @@ extern "C" {
fn rust_helper_init_wait(wq: *mut bindings::wait_queue_entry);
}

/// Safely initialises a [`CondVar`] with the given name, generating a new lock class.
/// Safely creates a [`CondVar`] with the given name, generating a new lock class.
#[macro_export]
macro_rules! condvar_init {
($condvar:expr, $name:literal) => {
$crate::init_with_lockdep!($condvar, $name)
macro_rules! condvar_new {
($name:literal) => {
kernel::pin::init_from_closure(|mut this| {
if false {
return Err(this.init_err($crate::Error::EINVAL));
}
let ok = this.init_with_value(unsafe { CondVar::new() });
$crate::init_with_lockdep!(ok.as_ref(), $name);
Ok(ok)
})
};
}

Expand Down
3 changes: 1 addition & 2 deletions rust/kernel/sync/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,7 @@
//! # use kernel::mutex_init;
//! # use kernel::sync::Mutex;
//! // SAFETY: `init` is called below.
//! let data = alloc::sync::Arc::pin(unsafe { Mutex::new(0) });
//! mutex_init!(data.as_ref(), "test::data");
//! let data = alloc::sync::Arc::try_pin_with(mutex_new!("test::data", 0));
//! *data.lock() = 10;
//! pr_info!("{}\n", *data.lock());
//! ```
Expand Down
16 changes: 12 additions & 4 deletions rust/kernel/sync/mutex.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,19 @@ use crate::bindings;
use crate::str::CStr;
use core::{cell::UnsafeCell, marker::PhantomPinned, pin::Pin};

/// Safely initialises a [`Mutex`] with the given name, generating a new lock class.
/// Safely creates a [`Mutex`] with the given name, generating a new lock class.
#[macro_export]
macro_rules! mutex_init {
($mutex:expr, $name:literal) => {
$crate::init_with_lockdep!($mutex, $name)
macro_rules! mutex_new {
($name:literal, $val:expr) => {
kernel::pin::init_from_closure(|mut this| {
if false {
return Err(this.init_err($crate::Error::EINVAL));
}
let val = $val;
let ok = this.init_with_value(unsafe { Mutex::new(val) });
$crate::init_with_lockdep!(ok.as_ref(), $name);
Ok(ok)
})
};
}

Expand Down
16 changes: 12 additions & 4 deletions rust/kernel/sync/spinlock.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,11 +22,19 @@ extern "C" {
fn rust_helper_spin_unlock(lock: *mut bindings::spinlock);
}

/// Safely initialises a [`SpinLock`] with the given name, generating a new lock class.
/// Safely creates a [`SpinLock`] with the given name, generating a new lock class.
#[macro_export]
macro_rules! spinlock_init {
($spinlock:expr, $name:literal) => {
$crate::init_with_lockdep!($spinlock, $name)
macro_rules! spinlock_new {
($name:literal, $val:expr) => {
kernel::pin::init_from_closure(|mut this| {
if false {
return Err(this.init_err($crate::Error::EINVAL));
}
let val = $val;
let ok = this.init_with_value(unsafe { SpinLock::new(val) });
$crate::init_with_lockdep!(ok.as_ref(), $name);
Ok(ok)
})
};
}

Expand Down
Loading

0 comments on commit 549b8e3

Please sign in to comment.