diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2023-04-30 11:20:22 -0700 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2023-04-30 11:20:22 -0700 |
commit | 310897659cf056016e2c772a028f9b8abc934928 (patch) | |
tree | ca5f122d871a4e54026884bcc98a6309e3fd4069 /rust/macros/pin_data.rs | |
parent | 825a0714d2b3883d4f8ff64f6933fb73ee3f1834 (diff) | |
parent | ea76e08f4d901a450619831a255e9e0a4c0ed162 (diff) | |
download | lwn-310897659cf056016e2c772a028f9b8abc934928.tar.gz lwn-310897659cf056016e2c772a028f9b8abc934928.zip |
Merge tag 'rust-6.4' of https://github.com/Rust-for-Linux/linux
Pull rust updates from Miguel Ojeda
"More additions to the Rust core. Importantly, this adds the pin-init
API, which will be used by other abstractions, such as the
synchronization ones added here too:
- pin-init API: a solution for the safe pinned initialization
problem.
This allows to reduce the need for 'unsafe' code in the kernel when
dealing with data structures that require a stable address. Commit
90e53c5e70a6 ("rust: add pin-init API core") contains a nice
introduction -- here is an example of how it looks like:
#[pin_data]
struct Example {
#[pin]
value: Mutex<u32>,
#[pin]
value_changed: CondVar,
}
impl Example {
fn new() -> impl PinInit<Self> {
pin_init!(Self {
value <- new_mutex!(0),
value_changed <- new_condvar!(),
})
}
}
// In a `Box`.
let b = Box::pin_init(Example::new())?;
// In the stack.
stack_pin_init!(let s = Example::new());
- 'sync' module:
New types 'LockClassKey' ('struct lock_class_key'), 'Lock',
'Guard', 'Mutex' ('struct mutex'), 'SpinLock' ('spinlock_t'),
'LockedBy' and 'CondVar' (uses 'wait_queue_head_t'), plus macros
such as 'static_lock_class!' and 'new_spinlock!'.
In particular, 'Lock' and 'Guard' are generic implementations that
contain code that is common to all locks. Then, different backends
(the new 'Backend' trait) are implemented and used to define types
like 'Mutex':
type Mutex<T> = Lock<T, MutexBackend>;
In addition, new methods 'assume_init()', 'init_with()' and
'pin_init_with()' for 'UniqueArc<MaybeUninit<T>>' and 'downcast()'
for 'Arc<dyn Any + Send + Sync>'; as well as 'Debug' and 'Display'
implementations for 'Arc' and 'UniqueArc'. Reduced stack usage of
'UniqueArc::try_new_uninit()', too.
- 'types' module:
New trait 'AlwaysRefCounted' and new type 'ARef' (an owned
reference to an always-reference-counted object, meant to be used
in wrappers for C types that have their own ref counting
functions).
Moreover, new associated functions 'raw_get()' and 'ffi_init()' for
'Opaque'.
- New 'task' module with a new type 'Task' ('struct task_struct'),
and a new macro 'current!' to safely get a reference to the current
one.
- New 'ioctl' module with new '_IOC*' const functions (equivalent to
the C macros).
- New 'uapi' crate, intended to be accessible by drivers directly.
- 'macros' crate: new 'quote!' macro (similar to the one provided in
userspace by the 'quote' crate); and the 'module!' macro now allows
specifying multiple module aliases.
- 'error' module:
New associated functions for the 'Error' type, such as
'from_errno()' and new functions such as 'to_result()'.
- 'alloc' crate:
More fallible 'Vec' methods: 'try_resize` and
'try_extend_from_slice' and the infrastructure (imported from the
Rust standard library) they need"
* tag 'rust-6.4' of https://github.com/Rust-for-Linux/linux: (44 commits)
rust: ioctl: Add ioctl number manipulation functions
rust: uapi: Add UAPI crate
rust: sync: introduce `CondVar`
rust: lock: add `Guard::do_unlocked`
rust: sync: introduce `LockedBy`
rust: introduce `current`
rust: add basic `Task`
rust: introduce `ARef`
rust: lock: introduce `SpinLock`
rust: lock: introduce `Mutex`
rust: sync: introduce `Lock` and `Guard`
rust: sync: introduce `LockClassKey`
MAINTAINERS: add Benno Lossin as Rust reviewer
rust: init: broaden the blanket impl of `Init`
rust: sync: add functions for initializing `UniqueArc<MaybeUninit<T>>`
rust: sync: reduce stack usage of `UniqueArc::try_new_uninit`
rust: types: add `Opaque::ffi_init`
rust: prelude: add `pin-init` API items to prelude
rust: init: add `Zeroable` trait and `init::zeroed` function
rust: init: add `stack_pin_init!` macro
...
Diffstat (limited to 'rust/macros/pin_data.rs')
-rw-r--r-- | rust/macros/pin_data.rs | 79 |
1 files changed, 79 insertions, 0 deletions
diff --git a/rust/macros/pin_data.rs b/rust/macros/pin_data.rs new file mode 100644 index 000000000000..954149d77181 --- /dev/null +++ b/rust/macros/pin_data.rs @@ -0,0 +1,79 @@ +// SPDX-License-Identifier: Apache-2.0 OR MIT + +use proc_macro::{Punct, Spacing, TokenStream, TokenTree}; + +pub(crate) fn pin_data(args: TokenStream, input: TokenStream) -> TokenStream { + // This proc-macro only does some pre-parsing and then delegates the actual parsing to + // `kernel::__pin_data!`. + // + // In here we only collect the generics, since parsing them in declarative macros is very + // elaborate. We also do not need to analyse their structure, we only need to collect them. + + // `impl_generics`, the declared generics with their bounds. + let mut impl_generics = vec![]; + // Only the names of the generics, without any bounds. + let mut ty_generics = vec![]; + // Tokens not related to the generics e.g. the `impl` token. + let mut rest = vec![]; + // The current level of `<`. + let mut nesting = 0; + let mut toks = input.into_iter(); + // If we are at the beginning of a generic parameter. + let mut at_start = true; + for tt in &mut toks { + match tt.clone() { + TokenTree::Punct(p) if p.as_char() == '<' => { + if nesting >= 1 { + impl_generics.push(tt); + } + nesting += 1; + } + TokenTree::Punct(p) if p.as_char() == '>' => { + if nesting == 0 { + break; + } else { + nesting -= 1; + if nesting >= 1 { + impl_generics.push(tt); + } + if nesting == 0 { + break; + } + } + } + tt => { + if nesting == 1 { + match &tt { + TokenTree::Ident(i) if i.to_string() == "const" => {} + TokenTree::Ident(_) if at_start => { + ty_generics.push(tt.clone()); + ty_generics.push(TokenTree::Punct(Punct::new(',', Spacing::Alone))); + at_start = false; + } + TokenTree::Punct(p) if p.as_char() == ',' => at_start = true, + TokenTree::Punct(p) if p.as_char() == '\'' && at_start => { + ty_generics.push(tt.clone()); + } + _ => {} + } + } + if nesting >= 1 { + impl_generics.push(tt); + } else if nesting == 0 { + rest.push(tt); + } + } + } + } + rest.extend(toks); + // This should be the body of the struct `{...}`. + let last = rest.pop(); + quote!(::kernel::__pin_data! { + parse_input: + @args(#args), + @sig(#(#rest)*), + @impl_generics(#(#impl_generics)*), + @ty_generics(#(#ty_generics)*), + @body(#last), + }) +} |