Skip to content

Commit f8e2adb

Browse files
committed
allow::Ref-based Allow API design.
1 parent c0956d7 commit f8e2adb

File tree

3 files changed

+91
-0
lines changed

3 files changed

+91
-0
lines changed

allow_pin/README.md

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,3 +38,17 @@ The current API implementations are:
3838
Currently, `dynamic_type` seems more expensive than the other options, while
3939
`no_dynamic` and `full_dynamic` have similar code sizes to each other (for the
4040
large complex example).
41+
42+
## Where can buffers come from?
43+
44+
1. static raw buffers: no requirement to unallow, no local storage for share info.
45+
2. Pinned local buffers: unallow required, multiple options for tracking share info.
46+
3. Pinned static buffers: requires interior mutability or `unsafe`, no unshare
47+
required.
48+
4. Box: This is the only one that transfers ownership. Probably too different
49+
for a single API? Would not require guaranteed unallow -- instead recreate
50+
Box on unallow. APIs would need to return the allow handle to the caller,
51+
very different API.
52+
53+
Prefers no dynamic tracking: static buffers.
54+
Prefers dynamic tracking: Local buffers.

allow_pin/src/allow_ref.rs

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
//! A design based around the `allow::Ref` type, which is a type that can point
2+
//! to both 'static and stack-based buffers. `allow::Ref` itself is type (and
3+
//! lifetime)-erased to avoid monomorphization bloat in APIs. However, it is
4+
//! limited to only RO Allows or only RW Allows (because only allow::Ref<Ro> can
5+
//! be created from a `&'static [u8]`).
6+
7+
pub type ErrorCode = u32;
8+
9+
pub mod allow {
10+
use core::ptr::null_mut;
11+
use crate::*;
12+
13+
/// A reference to something that can be shared with the kernel via the
14+
/// Read-Only Allow system call (and if P is Rw, read-write Allow).
15+
pub struct Ref<P: Permissions, T: Allowable> {
16+
// The lifetime is erased to 'static here. There is no correct lifetime to
17+
// write when an AllowRef is embedded inside a Buffer.
18+
buffer: P::BufRef<'static, T>,
19+
// APIs need to be able to retrieve mutable references to the buffer
20+
// (for RW Allow), which requires that they have an exclusive reference
21+
// to the Ref. However, giving an &mut reference to the Ref would allow
22+
// the buffer to replace the Ref and forget it, which would prevent the
23+
// unallow from occurring before the buffer is dropped. To prevent that,
24+
// we pin the Ref as well.
25+
_pinned: PhantomPinned,
26+
share_info: Option<ShareInfo>,
27+
}
28+
29+
impl<P: Permissions, T: Allowable> Ref<P, T> {
30+
fn unshare_if_shared(self: Pin<&mut Self>) {
31+
let this = unsafe { Pin::into_inner_unchecked(self) };
32+
let Some(ref info) = this.share_info else { return };
33+
unsafe {
34+
dynamic_allow(info.driver_num, info.buffer_num, null_mut(), 0, info.allow_type);
35+
}
36+
this.share_info = None;
37+
}
38+
}
39+
40+
struct ShareInfo {
41+
allow_type: DynamicType,
42+
driver_num: u32,
43+
buffer_num: u32,
44+
}
45+
46+
/// Trait representing an allowable type.
47+
pub trait Allowable: FromBytes + IntoBytes + 'static {}
48+
impl<T: FromBytes + IntoBytes + ?Sized + 'static> Allowable for T {}
49+
50+
/// A type that represents whether a `Ref` has write access to a buffer.
51+
pub trait Permissions: sealed::Sealed {
52+
type BufRef<'b, T: Allowable>;
53+
// Only exists within the context of this design exploration; would not
54+
// exist in libtock-rs (because Permissions replaces StaticType
55+
// entirely).
56+
type Static: StaticType;
57+
}
58+
59+
// Permissions implementations.
60+
pub enum Ro {}
61+
impl sealed::Sealed for Ro {}
62+
impl Permissions for Ro {
63+
type BufRef<'b, T: Allowable> = &'b T;
64+
type Static = StaticRo;
65+
}
66+
pub enum Rw {}
67+
impl sealed::Sealed for Rw {}
68+
impl Permissions for Rw {
69+
type BufRef<'b, T: Allowable> = &'b mut T;
70+
type Static = StaticRw;
71+
}
72+
73+
mod sealed {
74+
pub trait Sealed {}
75+
}
76+
}

allow_pin/src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ use core::pin::Pin;
66
use core::ptr::null_mut;
77
use zerocopy::{FromBytes, IntoBytes};
88

9+
pub mod allow_ref;
910
pub mod dynamic_type;
1011
pub mod full_dynamic;
1112
pub mod no_dynamic;

0 commit comments

Comments
 (0)