Skip to content

Commit

Permalink
added pinned_drop
Browse files Browse the repository at this point in the history
  • Loading branch information
y86-dev committed Oct 12, 2022
1 parent fef97c6 commit a355755
Show file tree
Hide file tree
Showing 4 changed files with 125 additions and 3 deletions.
8 changes: 5 additions & 3 deletions drivers/android/transaction.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ use kernel::{
io_buffer::IoBufferWriter,
linked_list::List,
linked_list::{GetLinks, Links},
macros::pinned_drop,
new_spinlock,
prelude::*,
sync::{Arc, SpinLock, UniqueArc},
Expand All @@ -27,7 +28,7 @@ struct TransactionInner {
file_list: List<Box<FileInfo>>,
}

#[pin_project]
#[pin_project(PinnedDrop)]
pub(crate) struct Transaction {
#[pin]
inner: SpinLock<TransactionInner>,
Expand Down Expand Up @@ -276,8 +277,9 @@ impl DeliverToRead for Transaction {
}
}

impl Drop for Transaction {
fn drop(&mut self) {
#[pinned_drop]
impl PinnedDrop for Transaction {
fn drop(self: Pin<&mut Self>) {
if self.free_allocation.load(Ordering::Relaxed) {
self.to.buffer_get(self.data_address);
}
Expand Down
12 changes: 12 additions & 0 deletions rust/kernel/init.rs
Original file line number Diff line number Diff line change
Expand Up @@ -641,6 +641,18 @@ where
}
}

/// Trait facilitating pinned destruction.
///
/// Use [`pinned_drop`] to implement this trait safely.
pub unsafe trait PinnedDrop {
/// # Safety
///
/// Only call this from `<Self as Drop>::drop`.
unsafe fn drop(self: Pin<&mut Self>);
#[doc(hidden)]
fn __ensure_no_unsafe_op_in_drop(self: Pin<&mut Self>);
}

/// Smart pointer that can initialize memory in-place.
pub trait InPlaceInit<T>: Sized {
/// Use the given initializer to in-place initialize a `T`.
Expand Down
7 changes: 7 additions & 0 deletions rust/macros/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ mod concat_idents;
mod helpers;
mod module;
mod pin_project;
mod pinned_drop;
mod vtable;

use proc_macro::TokenStream;
Expand Down Expand Up @@ -211,3 +212,9 @@ pub fn concat_idents(ts: TokenStream) -> TokenStream {
pub fn pin_project(inner: TokenStream, item: TokenStream) -> TokenStream {
pin_project::pin_project(inner, item)
}

/// TODO
#[proc_macro_attribute]
pub fn pinned_drop(args: TokenStream, input: TokenStream) -> TokenStream {
pinned_drop::pinned_drop(args, input)
}
101 changes: 101 additions & 0 deletions rust/macros/pinned_drop.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
// SPDX-License-Identifier: GPL-2.0

use proc_macro::{Delimiter, Group, Ident, Punct, Spacing, Span, TokenStream, TokenTree};

pub(crate) fn pinned_drop(_args: TokenStream, input: TokenStream) -> TokenStream {
let mut toks = input.into_iter().collect::<Vec<_>>();
assert!(!toks.is_empty());
// ensure that we have an impl item
assert!(matches!(&toks[0], TokenTree::Ident(i) if i.to_string() == "impl"));
// ensure that we are implementing `PinnedDrop`
let mut nesting: usize = 0;
let mut pinned_drop_idx = None;
for (i, tt) in toks.iter().enumerate() {
match tt {
TokenTree::Punct(p) if p.as_char() == '<' => {
nesting += 1;
}
TokenTree::Punct(p) if p.as_char() == '>' => {
nesting = nesting.checked_sub(1).unwrap();
}
_ => {}
}
if i >= 1 && nesting == 0 {
assert!(matches!(tt, TokenTree::Ident(i) if i.to_string() == "PinnedDrop"));
pinned_drop_idx = Some(i);
break;
}
}
let idx = pinned_drop_idx.unwrap();
//inserting `::kernel::init::` in reverse order
toks.insert(idx, TokenTree::Punct(Punct::new(':', Spacing::Alone)));
toks.insert(idx, TokenTree::Punct(Punct::new(':', Spacing::Joint)));
toks.insert(idx, TokenTree::Ident(Ident::new("init", Span::call_site())));
toks.insert(idx, TokenTree::Punct(Punct::new(':', Spacing::Alone)));
toks.insert(idx, TokenTree::Punct(Punct::new(':', Spacing::Joint)));
toks.insert(
idx,
TokenTree::Ident(Ident::new("kernel", Span::call_site())),
);
toks.insert(idx, TokenTree::Punct(Punct::new(':', Spacing::Alone)));
toks.insert(idx, TokenTree::Punct(Punct::new(':', Spacing::Joint)));
if let Some(TokenTree::Group(last)) = toks.pop() {
let mut inner = last.stream().into_iter().collect::<Vec<_>>();
if let Some(TokenTree::Group(inner_last)) = inner.pop() {
// make the impl unsafe
toks.insert(0, TokenTree::Ident(Ident::new("unsafe", Span::call_site())));
// make the first function unsafe
inner.insert(0, TokenTree::Ident(Ident::new("unsafe", Span::call_site())));
// re-add the body
inner.push(TokenTree::Group(inner_last.clone()));
add_ensure_no_unsafe_op_in_drop(&mut inner, inner_last);
toks.push(TokenTree::Group(Group::new(
Delimiter::Brace,
TokenStream::from_iter(inner),
)));
TokenStream::from_iter(toks)
} else {
toks.push(TokenTree::Group(last));
TokenStream::from_iter(toks)
}
} else {
TokenStream::from_iter(toks)
}
}

fn add_ensure_no_unsafe_op_in_drop(v: &mut Vec<TokenTree>, inner_last: Group) {
v.push(TokenTree::Ident(Ident::new("fn", Span::call_site())));
v.push(TokenTree::Ident(Ident::new(
"__ensure_no_unsafe_op_in_drop",
Span::call_site(),
)));
v.push(TokenTree::Group(Group::new(
Delimiter::Parenthesis,
TokenStream::from_iter(vec![
TokenTree::Ident(Ident::new("self", Span::call_site())),
TokenTree::Punct(Punct::new(':', Spacing::Alone)),
TokenTree::Punct(Punct::new(':', Spacing::Joint)),
TokenTree::Punct(Punct::new(':', Spacing::Alone)),
TokenTree::Ident(Ident::new("core", Span::call_site())),
TokenTree::Punct(Punct::new(':', Spacing::Joint)),
TokenTree::Punct(Punct::new(':', Spacing::Alone)),
TokenTree::Ident(Ident::new("pin", Span::call_site())),
TokenTree::Punct(Punct::new(':', Spacing::Joint)),
TokenTree::Punct(Punct::new(':', Spacing::Alone)),
TokenTree::Ident(Ident::new("Pin", Span::call_site())),
TokenTree::Punct(Punct::new('<', Spacing::Alone)),
TokenTree::Punct(Punct::new('&', Spacing::Alone)),
TokenTree::Ident(Ident::new("mut", Span::call_site())),
TokenTree::Ident(Ident::new("Self", Span::call_site())),
TokenTree::Punct(Punct::new('>', Spacing::Alone)),
]),
)));
v.push(TokenTree::Group(Group::new(
Delimiter::Brace,
TokenStream::from_iter(vec![
TokenTree::Ident(Ident::new("if", Span::call_site())),
TokenTree::Ident(Ident::new("false", Span::call_site())),
TokenTree::Group(inner_last),
]),
)));
}

0 comments on commit a355755

Please sign in to comment.