Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[RFC] Simpler and more robust component interface #1618

Closed
wants to merge 9 commits into from
108 changes: 35 additions & 73 deletions boards/components/src/alarm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,104 +18,66 @@
// Author: Philip Levis <pal@cs.stanford.edu>
// Last modified: 12/21/2019

use core::mem::MaybeUninit;

use capsules::alarm::AlarmDriver;
use capsules::virtual_alarm::{MuxAlarm, VirtualMuxAlarm};
use kernel::capabilities;
use kernel::component::Component;
use kernel::create_capability;
use kernel::hil::time;
use kernel::static_init_half;

// Setup static space for the objects.
#[macro_export]
macro_rules! alarm_mux_component_helper {
macro_rules! alarm_mux_component_buf {
($A:ty) => {{
use capsules::virtual_alarm::MuxAlarm;
use core::mem::MaybeUninit;
static mut BUF: MaybeUninit<MuxAlarm<'static, $A>> = MaybeUninit::uninit();
&mut BUF
$crate::uninit_static_buf!(MuxAlarm<'static, $A>)
};};
}

// Setup static space for the objects.
#[macro_export]
macro_rules! alarm_component_helper {
macro_rules! alarm_component_buf {
($A:ty) => {{
use capsules::alarm::AlarmDriver;
use capsules::virtual_alarm::VirtualMuxAlarm;
use core::mem::MaybeUninit;
static mut BUF1: MaybeUninit<VirtualMuxAlarm<'static, $A>> = MaybeUninit::uninit();
static mut BUF2: MaybeUninit<AlarmDriver<'static, VirtualMuxAlarm<'static, $A>>> =
MaybeUninit::uninit();
(&mut BUF1, &mut BUF2)
(
$crate::uninit_static_buf!(VirtualMuxAlarm<'static, $A>),
$crate::uninit_static_buf!(AlarmDriver<'static, VirtualMuxAlarm<'static, $A>>),
)
};};
}

pub struct AlarmMuxComponent<A: 'static + time::Alarm<'static>> {
alarm: &'static A,
}

impl<A: 'static + time::Alarm<'static>> AlarmMuxComponent<A> {
pub fn new(alarm: &'static A) -> AlarmMuxComponent<A> {
AlarmMuxComponent { alarm }
}
}

impl<A: 'static + time::Alarm<'static>> Component for AlarmMuxComponent<A> {
type StaticInput = &'static mut MaybeUninit<MuxAlarm<'static, A>>;
type Output = &'static MuxAlarm<'static, A>;
pub mod alarm_mux_component {
use capsules::virtual_alarm::MuxAlarm;
use kernel::hil::time;
use kernel::UninitStaticBuf;

unsafe fn finalize(&mut self, static_buffer: Self::StaticInput) -> Self::Output {
let mux_alarm = static_init_half!(
static_buffer,
MuxAlarm<'static, A>,
MuxAlarm::new(self.alarm)
);
pub unsafe fn create<A: 'static + time::Alarm<'static>>(
alarm: &'static A,
static_buffer: UninitStaticBuf<MuxAlarm<'static, A>>,
) -> &'static MuxAlarm<'static, A> {
let mux_alarm = static_buffer.initialize(MuxAlarm::new(alarm));

time::Alarm::set_client(self.alarm, mux_alarm);
time::Alarm::set_client(alarm, mux_alarm);
mux_alarm
}
}

pub struct AlarmDriverComponent<A: 'static + time::Alarm<'static>> {
board_kernel: &'static kernel::Kernel,
alarm_mux: &'static MuxAlarm<'static, A>,
}
pub mod alarm_driver_component {
use capsules::alarm::AlarmDriver;
use capsules::virtual_alarm::{MuxAlarm, VirtualMuxAlarm};
use kernel::hil::time;
use kernel::UninitStaticBuf;
use kernel::{capabilities, create_capability};

impl<A: 'static + time::Alarm<'static>> AlarmDriverComponent<A> {
pub fn new(
pub unsafe fn create<A: 'static + time::Alarm<'static>>(
board_kernel: &'static kernel::Kernel,
mux: &'static MuxAlarm<'static, A>,
) -> AlarmDriverComponent<A> {
AlarmDriverComponent {
board_kernel: board_kernel,
alarm_mux: mux,
}
}
}

impl<A: 'static + time::Alarm<'static>> Component for AlarmDriverComponent<A> {
type StaticInput = (
&'static mut MaybeUninit<VirtualMuxAlarm<'static, A>>,
&'static mut MaybeUninit<AlarmDriver<'static, VirtualMuxAlarm<'static, A>>>,
);
type Output = &'static AlarmDriver<'static, VirtualMuxAlarm<'static, A>>;

unsafe fn finalize(&mut self, static_buffer: Self::StaticInput) -> Self::Output {
alarm_mux: &'static MuxAlarm<'static, A>,
static_buffer: (
UninitStaticBuf<VirtualMuxAlarm<'static, A>>,
UninitStaticBuf<AlarmDriver<'static, VirtualMuxAlarm<'static, A>>>,
),
) -> &'static AlarmDriver<'static, VirtualMuxAlarm<'static, A>> {
let grant_cap = create_capability!(capabilities::MemoryAllocationCapability);

let virtual_alarm1 = static_init_half!(
static_buffer.0,
VirtualMuxAlarm<'static, A>,
VirtualMuxAlarm::new(self.alarm_mux)
);
let alarm = static_init_half!(
static_buffer.1,
AlarmDriver<'static, VirtualMuxAlarm<'static, A>>,
AlarmDriver::new(virtual_alarm1, self.board_kernel.create_grant(&grant_cap))
);
let virtual_alarm1 = static_buffer.0.initialize(VirtualMuxAlarm::new(alarm_mux));
let alarm = static_buffer.1.initialize(AlarmDriver::new(
virtual_alarm1,
board_kernel.create_grant(&grant_cap),
));

time::Alarm::set_client(virtual_alarm1, alarm);
alarm
Expand Down
3 changes: 3 additions & 0 deletions boards/components/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,3 +19,6 @@ pub mod process_console;
pub mod rng;
pub mod si7021;
pub mod spi;

// Needed for the helper macros to resolve uninit_static_buf.
pub use kernel::uninit_static_buf;
13 changes: 8 additions & 5 deletions boards/imix/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ use kernel::hil::Controller;
use kernel::{create_capability, debug, debug_gpio, static_init};

use components;
use components::alarm::{AlarmDriverComponent, AlarmMuxComponent};
use components::alarm::{alarm_driver_component, alarm_mux_component};
use components::console::{ConsoleComponent, UartMuxComponent};
use components::crc::CrcComponent;
use components::debug_writer::DebugWriterComponent;
Expand Down Expand Up @@ -321,11 +321,14 @@ pub unsafe fn reset_handler() {

// # TIMER
let ast = &sam4l::ast::AST;
let mux_alarm = AlarmMuxComponent::new(ast)
.finalize(components::alarm_mux_component_helper!(sam4l::ast::Ast));
let mux_alarm =
alarm_mux_component::create(ast, components::alarm_mux_component_buf!(sam4l::ast::Ast));
ast.configure(mux_alarm);
let alarm = AlarmDriverComponent::new(board_kernel, mux_alarm)
.finalize(components::alarm_component_helper!(sam4l::ast::Ast));
let alarm = alarm_driver_component::create(
board_kernel,
mux_alarm,
components::alarm_component_buf!(sam4l::ast::Ast),
);

// # I2C and I2C Sensors
let mux_i2c = static_init!(MuxI2C<'static>, MuxI2C::new(&sam4l::i2c::I2C2));
Expand Down
69 changes: 60 additions & 9 deletions kernel/src/common/utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,15 +15,66 @@
/// destructor.
#[macro_export]
macro_rules! static_init {
($T:ty, $e:expr) => {
{
use core::mem::MaybeUninit;
// Statically allocate a read-write buffer for the value, write our
// initial value into it (without dropping the initial zeros) and
// return a reference to it.
static mut BUF: MaybeUninit<$T> = MaybeUninit::uninit();
$crate::static_init_half!(&mut BUF, $T, $e)
};
($T:ty, $e:expr) => {{
let mut buf = $crate::uninit_static_buf!($T);
buf.initialize($e)
}};
}

/// Same as `static_init!()` but without initializing the buffer's contents.
#[macro_export]
macro_rules! uninit_static_buf {
($T:ty) => {{
// Statically allocate a read-write buffer for the value, write our
// initial value into it (without dropping the initial zeros) and
// return a reference to it.
static mut BUF: $crate::common::utils::UninitBuf<$T> =
$crate::common::utils::UninitBuf::new();
$crate::UninitStaticBuf::new(&mut BUF)
}};
}

use core::mem::MaybeUninit;

/// A wrapper around a `MaybeUninit<T>` which is guaranteed to contain a
/// `MaybeUninit::uninit()` value.
#[repr(transparent)]
pub struct UninitBuf<T>(MaybeUninit<T>);

impl<T> UninitBuf<T> {
/// The only way to contruct an `UninitBuf` is via this function, which
/// initializes it to `MaybeUninit::uninit()`. This guarantees the
/// invariant that `UninitBuf` doesn't contain an initialized value.
pub const fn new() -> Self {
UninitBuf(MaybeUninit::uninit())
}
}

/// A wrapper around a static mutable reference to an `UninitBuf`. This wrapper
/// can be consumed by initializing it to some value, obtaining a static
/// mutable reference to the inner type `T`.
pub struct UninitStaticBuf<T: 'static> {
buf: &'static mut UninitBuf<T>,
}

impl<T> UninitStaticBuf<T> {
/// This function is not intended to be called publicly. It's only meant to
/// be called within `uninit_static_buf!` macro, but Rust's visibility
/// rules require it to be public, so that the macro's body can be
/// instantiated.
pub fn new(buf: &'static mut UninitBuf<T>) -> Self {
Self { buf }
}

/// This function consumes an uninitialized static buffer, initializing it
/// to some value and returning a static mutable reference to it. This
/// allows for runtime initialization of `static` values that don't have a
/// `const` constructor.
pub unsafe fn initialize(self, value: T) -> &'static mut T {
self.buf.0.as_mut_ptr().write(value);
// TODO: use MaybeUninit::get_mut() once that is stabilized (see
// https://github.com/rust-lang/rust/issues/63568).
&mut *self.buf.0.as_mut_ptr() as &'static mut T
}
}

Expand Down
1 change: 1 addition & 0 deletions kernel/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ mod sched;
mod tbfheader;

pub use crate::callback::{AppId, Callback};
pub use crate::common::utils::UninitStaticBuf;
pub use crate::driver::Driver;
pub use crate::grant::Grant;
pub use crate::mem::{AppPtr, AppSlice, Private, Shared};
Expand Down