Skip to content

Commit

Permalink
kernel: add Ref::{with, clone}
Browse files Browse the repository at this point in the history
  • Loading branch information
Qix- committed Aug 9, 2024
1 parent a151f62 commit 27aded7
Show file tree
Hide file tree
Showing 2 changed files with 118 additions and 7 deletions.
60 changes: 54 additions & 6 deletions oro-kernel/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ pub(crate) mod port;
pub(crate) mod registry;
pub(crate) mod ring;

use core::{mem::MaybeUninit, str::FromStr};
use core::mem::MaybeUninit;
use oro_arch::Target;
use oro_common::{
arch::Arch,
Expand Down Expand Up @@ -248,12 +248,60 @@ pub unsafe fn boot(core_config: &CoreConfig) -> ! {
wait_for_all_cores!();

// XXX DEBUG
let module = module::ModuleInstance {
id: 0,
module_id: id::Id::from_str("M-1234ABCD5678EFGH9012IJKL3").unwrap(),
#[allow(clippy::cast_possible_truncation)]
let _: () = {
use self::{id::Id, module::ModuleInstance, registry::Ref};

let mut data = [0u8; 16];
data[15] = core_config.core_id as u8;

let module_ref = Ref::from(ModuleInstance {
id: core_config.core_id as u32,
module_id: Id::new(data),
})
.expect("failed to allocate");

module_ref.with(|module| {
let mut buf = [0; 27];
let strid = module.module_id.to_str(&mut buf);
dbg!(
"DEBUG",
"core {:02?} allocated {}",
core_config.core_id,
strid
);
});

#[allow(clippy::items_after_statements, clippy::missing_docs_in_private_items)]
static mut SHARED_REF: Option<(u64, Ref<ModuleInstance>)> = None;

if core_config.core_id == 2 {
SHARED_REF = Some((core_config.core_id, module_ref));
}

wait_for_all_cores!();

let shared_ref = unsafe { SHARED_REF.clone() };
if let Some((from_core_id, modref)) = shared_ref {
modref.with(|module| {
let mut buf = [0; 27];
let strid = module.module_id.to_str(&mut buf);
dbg!(
"DEBUG",
"core {:02?} got core {:02?}'s ref {}",
core_config.core_id,
from_core_id,
strid
);
});
} else {
dbg_err!(
"DEBUG",
"core {:02?} failed to get shared ref (None)",
core_config.core_id
);
}
};
let _ref_module: self::registry::Ref<module::ModuleInstance> =
self::registry::Ref::from(module).expect("failed to allocate");

Target::halt()
}
Expand Down
65 changes: 64 additions & 1 deletion oro-kernel/src/registry.rs
Original file line number Diff line number Diff line change
Expand Up @@ -383,6 +383,12 @@ struct ArenaEntry<T: Sized> {
/// For that reason, this trait is `unsafe` and only accessible within the
/// root module.
///
/// There must be a 1-to-1 relationship between the implementation of this
/// trait on any type `T` and a registry for that type `T`.
///
/// Registries MUST be static and MUST refer to shared registry segments
/// as prescribed by the architecture-specific address space layouts.
///
/// **DO NOT USE THIS TRAIT ANYWHERE ELSE IN THE KERNEL CODE.**
pub(super) unsafe trait RegistryTarget: Sized {
/// The type of allocator to use.
Expand Down Expand Up @@ -417,7 +423,6 @@ pub(super) unsafe trait RegistryTarget: Sized {
}

/// A reference to an object in a registry.
#[derive(Clone, Copy)]
pub struct Ref<T: RegistryTarget + Sized + 'static> {
/// The index of the object in the registry.
index: u32,
Expand Down Expand Up @@ -455,6 +460,64 @@ impl<T: RegistryTarget + Sized + 'static> Ref<T> {
registry: <T as RegistryTarget>::REGISTRY_PTR,
})
}

/// Operates on the underlying object.
///
/// Locks the object and passes it to the closure.
/// The closure is executed in a critical section.
///
/// # Safety
/// The closure MUST NOT panic, and MUST NOT
/// recursively call `Ref::with()` on the same object,
/// and must take care that any other functions called
/// from within the closure also do not recursively
/// call `Ref::with()` on the same object.
///
/// Calling `Ref::with()` on another object is fine.
pub unsafe fn with<F, R>(&self, f: F) -> R
where
F: FnOnce(&mut T) -> R,
{
// SAFETY(qix-): Barring a bug, we have a valid pointer to the registry.
let registry = unsafe { &*self.registry };
let entry = unsafe {
// SAFETY(qix-): We know that the index is valid, and that the
// SAFETY(qix-): registry is valid, so this is safe. Further,
// SAFETY(qix-): we know that the entry is initialized, so it
// SAFETY(qix-): is safe to call `assume_init_ref()`.
(*registry.base.add(self.index as usize)).assume_init_ref()
};

debug_assert!(entry.ref_count.load(Ordering::Acquire) > 0);

// SAFETY(qix-): We can guarantee that if we have a ref, the
// SAFETY(qix-): entry is valid.
let mut locked = entry.value.assume_init_ref().lock::<Target>();

f(&mut *locked)
}
}

impl<T: RegistryTarget + Sized + 'static> Clone for Ref<T> {
fn clone(&self) -> Self {
// SAFETY(qix-): Barring a bug, we have a valid pointer to the registry.
let registry = unsafe { &*self.registry };
let entry = unsafe {
// SAFETY(qix-): We know that the index is valid, and that the
// SAFETY(qix-): registry is valid, so this is safe. Further,
// SAFETY(qix-): we know that the entry is initialized, so it
// SAFETY(qix-): is safe to call `assume_init_ref()`.
(*registry.base.add(self.index as usize)).assume_init_ref()
};

let last_refcount = entry.ref_count.fetch_add(1, Ordering::AcqRel);
debug_assert!(last_refcount > 0);

Self {
index: self.index,
registry: self.registry,
}
}
}

// SAFETY(qix-): We ensure that `Ref` satisfies both of these
Expand Down

0 comments on commit 27aded7

Please sign in to comment.