lib.rs 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117
  1. extern crate proc_macro;
  2. use proc_macro::TokenStream;
  3. use quote::{format_ident, quote};
  4. use syn::{parse_macro_input, ItemStatic};
  5. mod arch;
  6. #[proc_macro_attribute]
  7. pub fn define_percpu(attrs: TokenStream, item: TokenStream) -> TokenStream {
  8. if !attrs.is_empty() {
  9. panic!("`define_percpu` attribute does not take any arguments");
  10. }
  11. let item = parse_macro_input!(item as ItemStatic);
  12. let vis = &item.vis;
  13. let ident = &item.ident;
  14. let ty = &item.ty;
  15. let expr = &item.expr;
  16. let is_bool = quote!(#ty).to_string().as_str() == "bool";
  17. let is_integer =
  18. ["u8", "u16", "u32", "u64", "usize"].contains(&quote!(#ty).to_string().as_str());
  19. let is_atomic_like = is_bool || is_integer || quote!(#ty).to_string().contains("NonNull");
  20. let inner_ident = format_ident!("_percpu_inner_{}", ident);
  21. let access_ident = format_ident!("_access_{}", ident);
  22. let integer_methods = if is_integer {
  23. quote! {
  24. pub fn add(&self, value: #ty) {
  25. *unsafe { self.as_mut() } += value;
  26. }
  27. pub fn sub(&self, value: #ty) {
  28. *unsafe { self.as_mut() } -= value;
  29. }
  30. }
  31. } else {
  32. quote! {}
  33. };
  34. let preempt_disable = if !is_atomic_like {
  35. quote! { crate::sync::preempt::disable(); }
  36. } else {
  37. quote! {}
  38. };
  39. let preempt_enable = if !is_atomic_like {
  40. quote! { crate::sync::preempt::enable(); }
  41. } else {
  42. quote! {}
  43. };
  44. let as_ptr = arch::get_percpu_pointer(&inner_ident, &ty);
  45. quote! {
  46. #[link_section = ".percpu"]
  47. #[allow(non_upper_case_globals)]
  48. static mut #inner_ident: #ty = #expr;
  49. #[allow(non_camel_case_types)]
  50. #vis struct #access_ident;
  51. #vis static #ident: #access_ident = #access_ident;
  52. impl #access_ident {
  53. /// # Safety
  54. /// This function is unsafe because it allows for mutable aliasing of the percpu
  55. /// variable.
  56. /// Make sure that preempt is disabled when calling this function.
  57. pub unsafe fn as_ptr(&self) -> *mut #ty {
  58. #as_ptr
  59. }
  60. pub fn get(&self) -> #ty {
  61. #preempt_disable
  62. let value = unsafe { self.as_ptr().read() };
  63. #preempt_enable
  64. value
  65. }
  66. pub fn set(&self, value: #ty) {
  67. #preempt_disable
  68. unsafe { self.as_ptr().write(value) }
  69. #preempt_enable
  70. }
  71. pub fn swap(&self, mut value: #ty) -> #ty {
  72. #preempt_disable
  73. unsafe { self.as_ptr().swap(&mut value) }
  74. #preempt_enable
  75. value
  76. }
  77. /// # Safety
  78. /// This function is unsafe because it allows for immutable aliasing of the percpu
  79. /// variable.
  80. /// Make sure that preempt is disabled when calling this function.
  81. pub unsafe fn as_ref(&self) -> & #ty {
  82. // SAFETY: This is safe because `as_ptr()` is guaranteed to be valid.
  83. self.as_ptr().as_ref().unwrap()
  84. }
  85. /// # Safety
  86. /// This function is unsafe because it allows for mutable aliasing of the percpu
  87. /// variable.
  88. /// Make sure that preempt is disabled when calling this function.
  89. pub unsafe fn as_mut(&self) -> &mut #ty {
  90. // SAFETY: This is safe because `as_ptr()` is guaranteed to be valid.
  91. self.as_ptr().as_mut().unwrap()
  92. }
  93. #integer_methods
  94. }
  95. }
  96. .into()
  97. }