Skip to content

Commit 8f0be78

Browse files
committed
move kernel_mutex_rcu example
1 parent 92865de commit 8f0be78

File tree

3 files changed

+171
-172
lines changed

3 files changed

+171
-172
lines changed

examples/kernel_mutex_rcu.rs

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

examples/kernel_mutex_rcu/main.rs

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
#![feature(unsafe_pinned)]
2+
#![allow(dead_code)]
3+
4+
use field_projection::compat::{HasFields, p, start_proj};
5+
use std::pin::Pin;
6+
7+
mod rcu;
8+
use rcu::*;
9+
10+
struct BufferConfig {
11+
flush_sensitivity: u8,
12+
}
13+
14+
#[derive(HasFields)]
15+
#[fields(with_pinned)]
16+
struct Buffer {
17+
// We also require `Rcu` to be pinned, because `&mut Rcu` must not exist (otherwise one could
18+
// call mem::swap).
19+
#[pin]
20+
cfg: Rcu<Box<BufferConfig>>,
21+
buf: Vec<u8>,
22+
}
23+
24+
#[derive(HasFields)]
25+
#[fields(with_pinned)]
26+
struct MyDriver {
27+
// The `Mutex` in the kernel needs to be pinned.
28+
#[pin]
29+
buf: RcuMutex<Buffer>,
30+
}
31+
32+
impl MyDriver {
33+
fn flush_sensitivity<'a>(&'a self, rcu_guard: &'a RcuGuard) -> u8 {
34+
let buf: &'a RcuMutex<Buffer> = &self.buf;
35+
start_proj!(buf);
36+
// Here we use the special projections set up for `Mutex` with fields of type `Rcu<T>`.
37+
let cfg: &Rcu<Box<BufferConfig>> = p!(@buf->cfg);
38+
cfg.read(rcu_guard).flush_sensitivity
39+
}
40+
41+
fn buffer_config<'a>(&'a self, rcu_guard: &'a RcuGuard) -> &'a BufferConfig {
42+
let buf: &'a RcuMutex<Buffer> = &self.buf;
43+
start_proj!(move buf);
44+
let cfg: &Rcu<Box<BufferConfig>> = p!(@move buf->cfg);
45+
cfg.read(rcu_guard)
46+
}
47+
48+
fn set_buffer_config(&self, flush_sensitivity: u8) {
49+
// `RcuMutex` pins the value.
50+
let mut guard: Pin<RcuMutexGuard<'_, Buffer>> = self.buf.lock();
51+
let mut buf: Pin<&mut Buffer> = guard.as_mut();
52+
start_proj!(mut buf);
53+
// We can use pin-projections since we marked `cfg` as `#[pin]`
54+
let cfg: Pin<&mut Rcu<Box<BufferConfig>>> = p!(@mut buf->cfg);
55+
cfg.set(Box::new(BufferConfig { flush_sensitivity }));
56+
// ^^^ this returns an `Old<Box<BufferConfig>>` and runs `synchronize_rcu` on drop.
57+
}
58+
}
59+
60+
fn main() {}

examples/kernel_mutex_rcu/rcu.rs

Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,111 @@
1+
use std::{
2+
cell::UnsafeCell,
3+
ops::{Deref, DerefMut},
4+
pin::{Pin, UnsafePinned},
5+
};
6+
7+
use field_projection::{
8+
compat::{ProjectableExt, Safe},
9+
marker::UnalignedField,
10+
ops::{Project, Projectable, SafeProject},
11+
};
12+
13+
pub struct RcuGuard(());
14+
15+
impl Drop for RcuGuard {
16+
fn drop(&mut self) {
17+
/* bindings::rcu_read_unlock() */
18+
}
19+
}
20+
21+
pub fn read_lock() -> RcuGuard {
22+
/* bindings::rcu_read_lock() */
23+
RcuGuard(())
24+
}
25+
26+
pub struct Rcu<P> {
27+
inner: UnsafePinned<UnsafeCell<P>>,
28+
}
29+
30+
impl<P: Deref> Rcu<P> {
31+
pub fn read<'a>(&'a self, _guard: &'a RcuGuard) -> &'a P::Target {
32+
// FIX: this should actually use an atomic ptr read
33+
unsafe { &*UnsafeCell::raw_get(self.inner.get()) }
34+
}
35+
36+
// FIX: the return type should actually be `impl PinInit<Old<P>>`, since the value *must*
37+
// be dropped and is not allowed to be forgotten, so we use the pin guarantee.
38+
pub fn set(self: Pin<&mut Self>, new: P) -> Old<P> {
39+
let ptr = UnsafeCell::raw_get(self.inner.get());
40+
// FIX: need to use atomic write for this operation, so need some additional trait on P.
41+
let old = unsafe { ptr.read() };
42+
unsafe { ptr.write(new) };
43+
Old(old)
44+
}
45+
}
46+
47+
pub struct Old<P>(P);
48+
49+
impl<P> Drop for Old<P> {
50+
fn drop(&mut self) {
51+
/* bindings::synchronize_rcu() */
52+
}
53+
}
54+
55+
pub struct RcuMutex<T> {
56+
data: UnsafeCell<T>,
57+
}
58+
59+
pub struct RcuMutexGuard<'a, T> {
60+
mtx: &'a RcuMutex<T>,
61+
}
62+
63+
impl<T> Deref for RcuMutexGuard<'_, T> {
64+
type Target = T;
65+
fn deref(&self) -> &Self::Target {
66+
unsafe { &*self.mtx.data.get() }
67+
}
68+
}
69+
70+
impl<T> DerefMut for RcuMutexGuard<'_, T> {
71+
fn deref_mut(&mut self) -> &mut Self::Target {
72+
unsafe { &mut *self.mtx.data.get() }
73+
}
74+
}
75+
76+
impl<T> RcuMutex<T> {
77+
pub fn lock(&self) -> Pin<RcuMutexGuard<'_, T>> {
78+
let res = RcuMutexGuard { mtx: self };
79+
unsafe { Pin::new_unchecked(res) }
80+
}
81+
}
82+
83+
impl<T> Projectable for &RcuMutex<T> {
84+
type Inner = T;
85+
}
86+
87+
unsafe impl<T> SafeProject for &RcuMutex<T> {}
88+
89+
unsafe impl<T> ProjectableExt for &RcuMutex<T> {
90+
type Safety = Safe;
91+
}
92+
93+
unsafe impl<'a, T, U, F> Project<F> for &'a RcuMutex<T>
94+
where
95+
F: UnalignedField<Base = T, Type = Rcu<U>>,
96+
U: 'a,
97+
{
98+
type Output<'b>
99+
= &'b F::Type
100+
where
101+
Self: 'b;
102+
103+
unsafe fn project<'b>(this: *const Self) -> Self::Output<'b>
104+
where
105+
Self: 'b,
106+
{
107+
let ptr: *const RcuMutex<T> = unsafe { this.read() };
108+
let ptr = UnsafeCell::raw_get(unsafe { &raw const (*ptr).data });
109+
unsafe { &*ptr.byte_add(F::OFFSET).cast() }
110+
}
111+
}

0 commit comments

Comments
 (0)