| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256 |
- extern crate proc_macro;
- mod loongarch64;
- mod riscv64;
- mod x86_64;
- use proc_macro2::TokenStream;
- use quote::{format_ident, quote};
- use syn::{parse2, Ident, ItemStatic, Type};
- fn define_percpu_impl(
- attrs: TokenStream,
- item: TokenStream,
- get_percpu_pointer: fn(&Ident, &Type) -> TokenStream,
- ) -> TokenStream {
- if !attrs.is_empty() {
- panic!("`define_percpu` attribute does not take any arguments");
- }
- let item = parse2::<ItemStatic>(item).unwrap();
- let vis = &item.vis;
- let ident = &item.ident;
- let ty = &item.ty;
- let expr = &item.expr;
- let is_bool = quote!(#ty).to_string().as_str() == "bool";
- let is_integer =
- ["u8", "u16", "u32", "u64", "usize"].contains("e!(#ty).to_string().as_str());
- let is_atomic_like = is_bool || is_integer || quote!(#ty).to_string().contains("NonNull");
- let inner_ident = format_ident!("_percpu_inner_{}", ident);
- let access_ident = format_ident!("_access_{}", ident);
- let integer_methods = if is_integer {
- quote! {
- pub fn add(&self, value: #ty) {
- *unsafe { self.as_mut() } += value;
- }
- pub fn sub(&self, value: #ty) {
- *unsafe { self.as_mut() } -= value;
- }
- }
- } else {
- quote! {}
- };
- let preempt_disable = if !is_atomic_like {
- quote! { eonix_preempt::disable(); }
- } else {
- quote! {}
- };
- let preempt_enable = if !is_atomic_like {
- quote! { eonix_preempt::enable(); }
- } else {
- quote! {}
- };
- let as_ptr = get_percpu_pointer(&inner_ident, &ty);
- quote! {
- #[link_section = ".percpu"]
- #[allow(non_upper_case_globals)]
- static mut #inner_ident: #ty = #expr;
- #[allow(non_camel_case_types)]
- #vis struct #access_ident;
- #vis static #ident: #access_ident = #access_ident;
- impl #access_ident {
- /// # Safety
- /// This function is unsafe because it allows for mutable aliasing of the percpu
- /// variable.
- /// Make sure that preempt is disabled when calling this function.
- pub unsafe fn as_ptr(&self) -> *mut #ty {
- #as_ptr
- }
- pub fn get(&self) -> #ty {
- #preempt_disable
- let value = unsafe { self.as_ptr().read() };
- #preempt_enable
- value
- }
- pub fn set(&self, value: #ty) {
- #preempt_disable
- unsafe { self.as_ptr().write(value) }
- #preempt_enable
- }
- pub fn swap(&self, mut value: #ty) -> #ty {
- #preempt_disable
- unsafe { self.as_ptr().swap(&mut value) }
- #preempt_enable
- value
- }
- /// # Safety
- /// This function is unsafe because it allows for immutable aliasing of the percpu
- /// variable.
- /// Make sure that preempt is disabled when calling this function.
- pub unsafe fn as_ref(&self) -> & #ty {
- // SAFETY: This is safe because `as_ptr()` is guaranteed to be valid.
- self.as_ptr().as_ref().unwrap()
- }
- /// # Safety
- /// This function is unsafe because it allows for mutable aliasing of the percpu
- /// variable.
- /// Make sure that preempt is disabled when calling this function.
- pub unsafe fn as_mut(&self) -> &mut #ty {
- // SAFETY: This is safe because `as_ptr()` is guaranteed to be valid.
- self.as_ptr().as_mut().unwrap()
- }
- #integer_methods
- }
- }
- .into()
- }
- fn define_percpu_shared_impl(
- attrs: TokenStream,
- item: TokenStream,
- get_percpu_pointer: fn(&Ident, &Type) -> TokenStream,
- get_percpu_offset: fn(&Ident) -> TokenStream,
- ) -> TokenStream {
- if !attrs.is_empty() {
- panic!("`define_percpu_shared` attribute does not take any arguments");
- }
- let item = parse2::<ItemStatic>(item).unwrap();
- let vis = &item.vis;
- let ident = &item.ident;
- let ty = &item.ty;
- let expr = &item.expr;
- let inner_ident = format_ident!("_percpu_shared_inner_{}", ident);
- let access_ident = format_ident!("_access_shared_{}", ident);
- let as_ptr = get_percpu_pointer(&inner_ident, &ty);
- let get_offset = get_percpu_offset(&inner_ident);
- quote! {
- #[link_section = ".percpu"]
- #[allow(non_upper_case_globals)]
- static #inner_ident: #ty = #expr;
- #[allow(non_camel_case_types)]
- #vis struct #access_ident;
- #vis static #ident: #access_ident = #access_ident;
- impl #access_ident {
- fn as_ptr(&self) -> *const #ty {
- unsafe { ( #as_ptr ) }
- }
- pub fn get_ref(&self) -> & #ty {
- // SAFETY: This is safe because `as_ptr()` is guaranteed to be valid.
- unsafe { self.as_ptr().as_ref().unwrap() }
- }
- pub fn get_for_cpu(&self, cpuid: usize) -> Option<& #ty > {
- let offset = #get_offset;
- let base = ::eonix_percpu::PercpuArea::get_for(cpuid);
- base.map(|base| unsafe { base.byte_add(offset).cast().as_ref() })
- }
- }
- impl ::core::ops::Deref for #access_ident {
- type Target = #ty;
- fn deref(&self) -> &Self::Target {
- self.get_ref()
- }
- }
- impl<T> ::core::convert::AsRef<T> for #access_ident
- where
- <Self as ::core::ops::Deref>::Target: ::core::convert::AsRef<T>,
- {
- fn as_ref(&self) -> &T {
- use ::core::ops::Deref;
- self.deref().as_ref()
- }
- }
- }
- }
- #[proc_macro_attribute]
- pub fn define_percpu_x86_64(
- attrs: proc_macro::TokenStream,
- item: proc_macro::TokenStream,
- ) -> proc_macro::TokenStream {
- define_percpu_impl(attrs.into(), item.into(), x86_64::get_percpu_pointer).into()
- }
- #[proc_macro_attribute]
- pub fn define_percpu_shared_x86_64(
- attrs: proc_macro::TokenStream,
- item: proc_macro::TokenStream,
- ) -> proc_macro::TokenStream {
- define_percpu_shared_impl(
- attrs.into(),
- item.into(),
- x86_64::get_percpu_pointer,
- x86_64::get_percpu_offset,
- )
- .into()
- }
- #[proc_macro_attribute]
- pub fn define_percpu_riscv64(
- attrs: proc_macro::TokenStream,
- item: proc_macro::TokenStream,
- ) -> proc_macro::TokenStream {
- define_percpu_impl(attrs.into(), item.into(), riscv64::get_percpu_pointer).into()
- }
- #[proc_macro_attribute]
- pub fn define_percpu_shared_riscv64(
- attrs: proc_macro::TokenStream,
- item: proc_macro::TokenStream,
- ) -> proc_macro::TokenStream {
- define_percpu_shared_impl(
- attrs.into(),
- item.into(),
- riscv64::get_percpu_pointer,
- riscv64::get_percpu_offset,
- )
- .into()
- }
- #[proc_macro_attribute]
- pub fn define_percpu_loongarch64(
- attrs: proc_macro::TokenStream,
- item: proc_macro::TokenStream,
- ) -> proc_macro::TokenStream {
- define_percpu_impl(attrs.into(), item.into(), loongarch64::get_percpu_pointer).into()
- }
- #[proc_macro_attribute]
- pub fn define_percpu_shared_loongarch64(
- attrs: proc_macro::TokenStream,
- item: proc_macro::TokenStream,
- ) -> proc_macro::TokenStream {
- define_percpu_shared_impl(
- attrs.into(),
- item.into(),
- loongarch64::get_percpu_pointer,
- loongarch64::get_percpu_offset,
- )
- .into()
- }
|