1pub use self::slab::StdFree;
2pub use self::zone::*;
3
4pub(self) use self::bucket::*;
5pub(self) use self::keg::*;
6pub(self) use self::slab::{FreeItem, Slab, SlabHdr};
7
8use crate::config::PAGE_SIZE;
9use crate::vm::Vm;
10use alloc::format;
11use alloc::string::String;
12use alloc::sync::Arc;
13use alloc::vec::Vec;
14use core::alloc::Layout;
15use core::num::NonZero;
16use core::sync::atomic::AtomicBool;
17use macros::bitflag;
18
19#[cfg_attr(target_arch = "aarch64", path = "aarch64.rs")]
20#[cfg_attr(target_arch = "x86_64", path = "x86_64.rs")]
21mod arch;
22mod bucket;
23mod keg;
24mod slab;
25mod zone;
26
27pub struct Uma {
29 vm: Arc<Vm>,
30 bucket_enable: Arc<AtomicBool>,
31 bucket_keys: Arc<Vec<usize>>, bucket_zones: Arc<Vec<UmaZone<StdFree>>>, }
34
35impl Uma {
36 const SMALLEST_UNIT: NonZero<usize> = NonZero::new(PAGE_SIZE.get() / 256).unwrap();
38
39 const MAX_WASTE: NonZero<usize> = NonZero::new(PAGE_SIZE.get() / 10).unwrap();
41 const BUCKET_MAX: usize = 128;
42 const BUCKET_SHIFT: usize = 4;
43
44 const BUCKET_SIZES: [usize; 4] = [16, 32, 64, 128];
46
47 pub fn new(vm: Arc<Vm>) -> Arc<Self> {
54 let bucket_enable = Arc::new(AtomicBool::new(true)); let mut bucket_keys = Vec::new();
56 let mut bucket_zones = Vec::with_capacity(Self::BUCKET_SIZES.len());
57 let mut ki = 0;
58
59 for (si, size) in Self::BUCKET_SIZES.into_iter().enumerate() {
61 let items = Layout::array::<*mut u8>(size).unwrap();
62 let layout = Layout::new::<BucketHdr>()
63 .extend(items)
64 .unwrap()
65 .0
66 .pad_to_align();
67
68 bucket_zones.push(UmaZone::new(
69 vm.clone(),
70 bucket_enable.clone(),
71 Arc::default(),
72 Arc::default(),
73 format!("{size} Bucket"),
74 None,
75 layout.size().try_into().unwrap(),
76 Some(layout.align() - 1),
77 None,
78 UmaFlags::Bucket | UmaFlags::Internal,
79 ));
80
81 while ki <= size {
82 bucket_keys.push(si);
83 ki += 1 << Self::BUCKET_SHIFT;
84 }
85 }
86
87 Arc::new(Self {
88 vm,
89 bucket_enable,
90 bucket_keys: Arc::new(bucket_keys),
91 bucket_zones: Arc::new(bucket_zones),
92 })
93 }
94
95 pub fn create_zone<T: FreeItem>(
102 &self,
103 name: impl Into<String>,
104 size: NonZero<usize>,
105 align: Option<usize>,
106 init: Option<fn()>,
107 flags: impl Into<UmaFlags>,
108 ) -> UmaZone<T> {
109 UmaZone::new(
112 self.vm.clone(),
113 self.bucket_enable.clone(),
114 self.bucket_keys.clone(),
115 self.bucket_zones.clone(),
116 name,
117 None,
118 size,
119 align,
120 init,
121 flags,
122 )
123 }
124}
125
126#[bitflag(u32)]
128pub enum UmaFlags {
129 ZInit = 0x2,
131 Offpage = 0x8,
133 Malloc = 0x10,
135 MtxClass = 0x40,
137 Vm = 0x80,
139 Hash = 0x100,
141 Secondary = 0x200,
143 MaxBucket = 0x800,
145 CacheSpread = 0x1000,
147 VToSlab = 0x2000,
149 Bucket = 0x2000000,
151 Internal = 0x20000000,
153 CacheOnly = 0x80000000,
155}
156
157#[bitflag(u32)]
159pub enum Alloc {
160 NoWait = 0x1,
162 Wait = 0x2,
164 Zero = 0x100,
166 NoVm = 0x200,
168}