Skip to content

Commit

Permalink
Add a Subscribe API to libtock_platform.
Browse files Browse the repository at this point in the history
This API is based on the design at tock#341.
  • Loading branch information
jrvanwhy committed Nov 13, 2021
1 parent eab0f0e commit 654318a
Showing 4 changed files with 88 additions and 1 deletion.
2 changes: 2 additions & 0 deletions platform/src/lib.rs
Original file line number Diff line number Diff line change
@@ -8,6 +8,7 @@ mod error_code;
mod raw_syscalls;
mod register;
pub mod return_variant;
pub mod subscribe;
mod syscall_scope;
mod syscalls;
mod syscalls_impl;
@@ -21,6 +22,7 @@ pub use error_code::ErrorCode;
pub use raw_syscalls::RawSyscalls;
pub use register::Register;
pub use return_variant::ReturnVariant;
pub use subscribe::{Subscribe, Upcall};
pub use syscall_scope::syscall_scope;
pub use syscalls::Syscalls;
pub use termination::Termination;
61 changes: 61 additions & 0 deletions platform/src/subscribe.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
use crate::syscall_scope::ShareList;
use crate::Syscalls;

/// A `Subscribe` instance allows safe code to call Tock's Subscribe system
/// call, by guaranteeing the upcall will be cleaned up before 'scope ends. It
/// is generally used with the `syscall_scope` function, which offers a safe
/// interface for constructing `Subscribe` instances.
pub struct Subscribe<'scope, S: Syscalls, const DRIVER_NUM: u32, const SUBSCRIBE_NUM: u32> {
_syscalls: core::marker::PhantomData<S>,

// Make this struct invariant with respect to the 'scope lifetime.
//
// Covariance would be unsound, as that would allow code with a
// `Subscribe<'static, ...>` to register an upcall that lasts for a shorter
// lifetime, resulting in use-after-free if the upcall in invoked.
// Contravariance would be sound, but is not necessary and may be confusing.
//
// Additionally, we want to have at least one private member of this struct
// so that code outside this module cannot construct a `Subscribe` without
// calling `ShareList::new`.
_scope: core::marker::PhantomData<core::cell::Cell<&'scope ()>>,
}

impl<'scope, S: Syscalls, const DRIVER_NUM: u32, const SUBSCRIBE_NUM: u32> Drop
for Subscribe<'scope, S, DRIVER_NUM, SUBSCRIBE_NUM>
{
fn drop(&mut self) {
S::unsubscribe(DRIVER_NUM, SUBSCRIBE_NUM);
}
}

impl<'scope, S: Syscalls, const DRIVER_NUM: u32, const SUBSCRIBE_NUM: u32> ShareList<'scope>
for Subscribe<'scope, S, DRIVER_NUM, SUBSCRIBE_NUM>
{
unsafe fn new() -> Subscribe<'scope, S, DRIVER_NUM, SUBSCRIBE_NUM> {
Subscribe {
_syscalls: core::marker::PhantomData,
_scope: core::marker::PhantomData,
}
}
}

/// A Tock kernel upcall. Upcalls are registered using the Subscribe system
/// call, and are invoked during Yield calls.
///
/// Each `Upcall` supports one or more subscribe IDs, which are indicated by the
/// `SupportedIds` parameter. The types `AnySubscribeId` and `OneSubscribeId`
/// are provided to use as `SupportedIds` parameters in `Upcall`
/// implementations.
pub trait Upcall<SupportedIds> {
fn upcall(&self, arg0: u32, arg1: u32, arg2: u32);
}

trait AllowsId<const DRIVER_NUM: u32, const SUBSCRIBE_NUM: u32> {}

pub struct AnyId;
impl<const DRIVER_NUM: u32, const SUBSCRIBE_NUM: u32> AllowsId<DRIVER_NUM, SUBSCRIBE_NUM> for AnyId {}

pub struct OneId<const DRIVER_NUM: u32, const SUBSCRIBE_NUM: u32>;
impl<const DRIVER_NUM: u32, const SUBSCRIBE_NUM: u32> AllowsId<DRIVER_NUM, SUBSCRIBE_NUM>
for OneId<DRIVER_NUM, SUBSCRIBE_NUM> {}
8 changes: 7 additions & 1 deletion platform/src/syscalls.rs
Original file line number Diff line number Diff line change
@@ -17,7 +17,13 @@ pub trait Syscalls {
/// callback, then returns.
fn yield_wait();

// TODO: Add a subscribe interface.
// -------------------------------------------------------------------------
// Subscribe
// -------------------------------------------------------------------------

/// Unregisters the upcall with the given ID. If no upcall is registered
/// with the given ID, `unsubscribe` does nothing.
fn unsubscribe(driver_num: u32, subscribe_num: u32);

// -------------------------------------------------------------------------
// Command
18 changes: 18 additions & 0 deletions platform/src/syscalls_impl.rs
Original file line number Diff line number Diff line change
@@ -33,6 +33,24 @@ impl<S: RawSyscalls> Syscalls for S {
}
}

// -------------------------------------------------------------------------
// Subscribe
// -------------------------------------------------------------------------

fn unsubscribe(driver_num: u32, subscribe_num: u32) {
unsafe {
// syscall4's documentation indicates it can be used to call
// Subscribe. The upcall pointer passed is the null upcall, which
// cannot cause undefined behavior on its own.
Self::syscall4::<{ syscall_class::SUBSCRIBE }>([
driver_num.into(),
subscribe_num.into(),
0usize.into(),
0usize.into(),
]);
}
}

// -------------------------------------------------------------------------
// Command
// -------------------------------------------------------------------------

0 comments on commit 654318a

Please sign in to comment.