Skip to content

Commit 17513eb

Browse files
author
Johnathan Van Why
committed
Make Allowed require Copy and remove all the Drop-related complexity.
Originally, I build Allowed so it can work with non-Copy types, which allows Drop types. The semantics of storing non-Copy and non-Drop types in shared memory, however, are somewhat nonobvious. Based on code review feedback, and being particularly cautious because Allowed uses `unsafe`, I decided to add a Copy constraint to Allowed.
1 parent c6e59f2 commit 17513eb

File tree

4 files changed

+38
-137
lines changed

4 files changed

+38
-137
lines changed

core/platform/src/allows/allowed.rs

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,13 @@
11
/// An individual value that has been shared with the kernel using the `allow`
22
/// system call.
3-
// Design note: Allowed's implementation does not directly use the 'b lifetime.
4-
// Platform uses 'b to prevent the Allowed from accessing the buffer after the
5-
// buffer becomes invalid.
6-
pub struct Allowed<'b, T: 'b> {
3+
// Allowed's implementation does not directly use the 'b lifetime. Platform uses
4+
// 'b to prevent the Allowed from accessing the buffer after the buffer becomes
5+
// invalid.
6+
// Allowed requires T to be Copy due to concerns about the semantics of
7+
// non-copyable types in shared memory as well as concerns about unexpected
8+
// behavior with Drop types. See the following PR discussion for more
9+
// information: https://github.com/tock/libtock-rs/pull/222
10+
pub struct Allowed<'b, T: Copy + 'b> {
711
// Safety properties:
812
// 1. `buffer` remains valid and usable for the lifetime of this Allowed
913
// instance.
@@ -37,7 +41,7 @@ pub struct Allowed<'b, T: 'b> {
3741
// need to be able to deconflict races between the kernel (which will never
3842
// interrupt an instruction's execution) and this process. Therefore volatile
3943
// accesses are sufficient to deconflict races.
40-
impl<'b, T: 'b> Allowed<'b, T> {
44+
impl<'b, T: Copy + 'b> Allowed<'b, T> {
4145
// Allowed can only be constructed by the Platform. It is constructed after
4246
// the `allow` system call, and as such must accept a raw pointer rather
4347
// than a reference. The caller must make sure the following are true:
@@ -52,33 +56,29 @@ impl<'b, T: 'b> Allowed<'b, T> {
5256
}
5357
}
5458

55-
// Sets the value in the buffer. Note that unlike `core::cell::Cell::set`,
56-
// `Allowed::set` will not drop the existing value. To drop the existing
57-
// value, use `replace` and drop the return value.
59+
// Sets the value in the buffer.
5860
pub fn set(&self, value: T) {
5961
unsafe {
6062
core::ptr::write_volatile(self.buffer.as_ptr(), value);
6163
}
6264
}
6365
}
6466

65-
impl<'b, T: crate::AllowReadable + 'b> Allowed<'b, T> {
67+
impl<'b, T: crate::AllowReadable + Copy + 'b> Allowed<'b, T> {
6668
pub fn replace(&self, value: T) -> T {
6769
let current = unsafe { core::ptr::read_volatile(self.buffer.as_ptr()) };
6870
unsafe {
6971
core::ptr::write_volatile(self.buffer.as_ptr(), value);
7072
}
7173
current
7274
}
73-
}
7475

75-
impl<'b, T: crate::AllowReadable + Copy + 'b> Allowed<'b, T> {
7676
pub fn get(&self) -> T {
7777
unsafe { core::ptr::read_volatile(self.buffer.as_ptr()) }
7878
}
7979
}
8080

81-
impl<'b, T: crate::AllowReadable + Default + 'b> Allowed<'b, T> {
81+
impl<'b, T: crate::AllowReadable + Copy + Default + 'b> Allowed<'b, T> {
8282
pub fn take(&self) -> T {
8383
self.replace(T::default())
8484
}
Lines changed: 26 additions & 86 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
use crate::allows::test_util::DropCheck;
21
use crate::Allowed;
32
use core::marker::PhantomData;
43
use core::ptr::NonNull;
@@ -32,15 +31,15 @@ use core::ptr::NonNull;
3231
// interacting with a real Tock kernel.
3332
//
3433
// [1] https://plv.mpi-sws.org/rustbelt/stacked-borrows/paper.pdf
35-
struct KernelPtr<'b, T: 'b> {
34+
struct KernelPtr<'b, T: Copy + 'b> {
3635
ptr: NonNull<T>,
3736

3837
// We need to consume the 'b lifetime. This is very similar to Allowed's
3938
// implementation.
4039
_phantom: PhantomData<&'b mut T>,
4140
}
4241

43-
impl<'b, T: 'b> KernelPtr<'b, T> {
42+
impl<'b, T: Copy + 'b> KernelPtr<'b, T> {
4443
// The constructor for KernelPtr; simulates allow(). Returns both the
4544
// Allowed instance the Platform would return and a KernelPtr the test can
4645
// use to simulate a kernel.
@@ -59,126 +58,67 @@ impl<'b, T: 'b> KernelPtr<'b, T> {
5958
(allowed, kernel_ptr)
6059
}
6160

62-
// Replaces the value in the buffer with a new one. Does not drop the
63-
// existing value.
61+
// Replaces the value in the buffer with a new one.
6462
pub fn set(&self, value: T) {
6563
unsafe {
6664
core::ptr::write(self.ptr.as_ptr(), value);
6765
}
6866
}
69-
}
7067

71-
impl<'b, T: Copy + 'b> KernelPtr<'b, T> {
7268
// Copies the contained value out of the buffer.
7369
pub fn get(&self) -> T {
7470
unsafe { core::ptr::read(self.ptr.as_ptr()) }
7571
}
7672
}
7773

78-
impl<'b, 'f: 'b> KernelPtr<'b, DropCheck<'f>> {
79-
// Retrieves the value of the contained DropCheck.
80-
pub fn value(&self) -> usize {
81-
let drop_check = unsafe { core::ptr::read(self.ptr.as_ptr()) };
82-
let value = drop_check.value;
83-
core::mem::forget(drop_check);
84-
value
85-
}
86-
}
87-
8874
#[test]
8975
fn set() {
90-
let dropped1 = core::cell::Cell::new(false);
91-
let dropped2 = core::cell::Cell::new(false);
92-
let dropped3 = core::cell::Cell::new(false);
93-
let mut buffer = DropCheck {
94-
flag: Some(&dropped1),
95-
value: 1,
96-
};
76+
let mut buffer = 1;
9777
let (allowed, kernel_ptr) = KernelPtr::allow(&mut buffer);
98-
assert_eq!(kernel_ptr.value(), 1);
99-
assert_eq!(dropped1.get(), false);
78+
assert_eq!(kernel_ptr.get(), 1);
10079

101-
// Simulate the kernel replacing the value in buffer. We don't drop the
102-
// existing value.
103-
kernel_ptr.set(DropCheck {
104-
flag: Some(&dropped2),
105-
value: 2,
106-
});
107-
allowed.set(DropCheck {
108-
flag: Some(&dropped3),
109-
value: 3,
110-
});
111-
assert_eq!(kernel_ptr.value(), 3);
112-
assert_eq!(dropped1.get(), false);
113-
assert_eq!(dropped2.get(), false);
114-
assert_eq!(dropped3.get(), false);
80+
// Simulate the kernel replacing the value in buffer.
81+
kernel_ptr.set(2);
82+
allowed.set(3);
83+
assert_eq!(kernel_ptr.get(), 3);
11584
}
11685

11786
#[test]
11887
fn replace() {
119-
let dropped1 = core::cell::Cell::new(false);
120-
let dropped2 = core::cell::Cell::new(false);
121-
let dropped3 = core::cell::Cell::new(false);
122-
let mut buffer = DropCheck {
123-
flag: Some(&dropped1),
124-
value: 1,
125-
};
88+
let mut buffer = 1;
12689
let (allowed, kernel_ptr) = KernelPtr::allow(&mut buffer);
127-
assert_eq!(kernel_ptr.value(), 1);
128-
assert_eq!(dropped1.get(), false);
90+
assert_eq!(kernel_ptr.get(), 1);
12991

130-
// Simulate the kernel replacing the value in buffer. We don't drop the
131-
// existing value.
132-
kernel_ptr.set(DropCheck {
133-
flag: Some(&dropped2),
134-
value: 2,
135-
});
136-
let returned = allowed.replace(DropCheck {
137-
flag: Some(&dropped3),
138-
value: 3,
139-
});
140-
assert_eq!(returned.value, 2);
141-
assert_eq!(kernel_ptr.value(), 3);
142-
assert_eq!(dropped1.get(), false);
143-
assert_eq!(dropped2.get(), false);
144-
assert_eq!(dropped3.get(), false);
92+
// Simulate the kernel replacing the value in buffer.
93+
kernel_ptr.set(2);
94+
let returned = allowed.replace(3);
95+
assert_eq!(returned, 2);
96+
assert_eq!(kernel_ptr.get(), 3);
14597
}
14698

14799
#[test]
148100
fn get() {
149-
// We can't use DropCheck because Drop and Copy cannot both be implemented
150-
// on a single type.
151101
let mut buffer = 1;
152102
let (allowed, kernel_ptr) = KernelPtr::allow(&mut buffer);
153103
assert_eq!(kernel_ptr.get(), 1);
104+
105+
assert_eq!(allowed.get(), 1);
106+
assert_eq!(kernel_ptr.get(), 1);
107+
154108
kernel_ptr.set(2);
155109
assert_eq!(allowed.get(), 2);
156110
assert_eq!(kernel_ptr.get(), 2);
157111
}
158112

159113
#[test]
160114
fn take() {
161-
let dropped1 = core::cell::Cell::new(false);
162-
let dropped2 = core::cell::Cell::new(false);
163-
let dropped3 = core::cell::Cell::new(false);
164-
let mut buffer = DropCheck {
165-
flag: Some(&dropped1),
166-
value: 1,
167-
};
115+
let mut buffer = 1;
168116
let (allowed, kernel_ptr) = KernelPtr::allow(&mut buffer);
169-
assert_eq!(kernel_ptr.value(), 1);
170-
assert_eq!(dropped1.get(), false);
117+
assert_eq!(kernel_ptr.get(), 1);
171118

172-
// Simulate the kernel replacing the value in buffer. We don't drop the
173-
// existing value.
174-
kernel_ptr.set(DropCheck {
175-
flag: Some(&dropped2),
176-
value: 2,
177-
});
119+
// Simulate the kernel replacing the value in buffer.
120+
kernel_ptr.set(2);
178121
let returned = allowed.take();
179-
assert_eq!(returned.value, 2);
180-
assert_eq!(kernel_ptr.value(), 0);
181-
assert_eq!(dropped1.get(), false);
182-
assert_eq!(dropped2.get(), false);
183-
assert_eq!(dropped3.get(), false);
122+
assert_eq!(returned, 2);
123+
assert_eq!(kernel_ptr.get(), 0);
184124
}

core/platform/src/allows/mod.rs

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,5 +6,3 @@ pub use allowed::Allowed;
66

77
#[cfg(test)]
88
mod allowed_tests;
9-
#[cfg(test)]
10-
mod test_util;

core/platform/src/allows/test_util.rs

Lines changed: 0 additions & 37 deletions
This file was deleted.

0 commit comments

Comments
 (0)