1
+ //! [ArceOS](https://github.com/rcore-os/arceos) global memory allocator.
2
+ //!
3
+ //! It provides [`GlobalAllocator`], which implements the trait
4
+ //! [`core::alloc::GlobalAlloc`]. A static global variable of type
5
+ //! [`GlobalAllocator`] is defined with the `#[global_allocator]` attribute, to
6
+ //! be registered as the standard library’s default allocator.
7
+
1
8
#![ no_std]
2
9
#![ feature( alloc_error_handler) ]
3
10
@@ -17,19 +24,34 @@ const MIN_HEAP_SIZE: usize = 0x8000; // 32 K
17
24
18
25
pub use page:: GlobalPage ;
19
26
27
+ /// The global allocator used by ArceOS.
28
+ ///
29
+ /// It combines a [`ByteAllocator`] and a [`PageAllocator`] into a simple
30
+ /// two-level allocator: firstly tries allocate from the byte allocator, if
31
+ /// there is no memory, asks the page allocator for more memory and adds it to
32
+ /// the byte allocator.
33
+ ///
34
+ /// Currently, [`SlabByteAllocator`] is used as the byte allocator, while
35
+ /// [`BitmapPageAllocator`] is used as the page allocator.
20
36
pub struct GlobalAllocator {
21
37
balloc : SpinNoIrq < SlabByteAllocator > ,
22
38
palloc : SpinNoIrq < BitmapPageAllocator < PAGE_SIZE > > ,
23
39
}
24
40
25
41
impl GlobalAllocator {
42
+ /// Creates an empty [`GlobalAllocator`].
26
43
pub const fn new ( ) -> Self {
27
44
Self {
28
45
balloc : SpinNoIrq :: new ( SlabByteAllocator :: new ( ) ) ,
29
46
palloc : SpinNoIrq :: new ( BitmapPageAllocator :: new ( ) ) ,
30
47
}
31
48
}
32
49
50
+ /// Initializes the allocator with the given region.
51
+ ///
52
+ /// It firstly adds the whole region to the page allocator, then allocates
53
+ /// a small region (32 KB) to initialize the byte allocator. Therefore,
54
+ /// the given region must be larger than 32 KB.
33
55
pub fn init ( & self , start_vaddr : usize , size : usize ) {
34
56
assert ! ( size > MIN_HEAP_SIZE ) ;
35
57
let init_heap_size = MIN_HEAP_SIZE ;
@@ -40,10 +62,22 @@ impl GlobalAllocator {
40
62
self . balloc . lock ( ) . init ( heap_ptr, init_heap_size) ;
41
63
}
42
64
65
+ /// Add the given region to the allocator.
66
+ ///
67
+ /// It will add the whole region to the byte allocator.
43
68
pub fn add_memory ( & self , start_vaddr : usize , size : usize ) -> AllocResult {
44
69
self . balloc . lock ( ) . add_memory ( start_vaddr, size)
45
70
}
46
71
72
+ /// Allocate arbitrary number of bytes. Returns the left bound of the
73
+ /// allocated region.
74
+ ///
75
+ /// It firstly tries to allocate from the byte allocator. If there is no
76
+ /// memory, it asks the page allocator for more memory and adds it to the
77
+ /// byte allocator.
78
+ ///
79
+ /// `align_pow2` must be a power of 2, and the returned region bound will be
80
+ /// aligned to it.
47
81
pub fn alloc ( & self , size : usize , align_pow2 : usize ) -> AllocResult < usize > {
48
82
// simple two-level allocator: if no heap memory, allocate from the page allocator.
49
83
let mut balloc = self . balloc . lock ( ) ;
@@ -64,30 +98,54 @@ impl GlobalAllocator {
64
98
}
65
99
}
66
100
101
+ /// Gives back the allocated region to the byte allocator.
102
+ ///
103
+ /// The region should be allocated by [`alloc`], and `align_pow2` should be
104
+ /// the same as the one used in [`alloc`]. Otherwise, the behavior is
105
+ /// undefined.
106
+ ///
107
+ /// [`alloc`]: GlobalAllocator::alloc
67
108
pub fn dealloc ( & self , pos : usize , size : usize , align_pow2 : usize ) {
68
109
self . balloc . lock ( ) . dealloc ( pos, size, align_pow2)
69
110
}
70
111
112
+ /// Allocates contiguous pages.
113
+ ///
114
+ /// It allocates `num_pages` pages from the page allocator.
115
+ ///
116
+ /// `align_pow2` must be a power of 2, and the returned region bound will be
117
+ /// aligned to it.
71
118
pub fn alloc_pages ( & self , num_pages : usize , align_pow2 : usize ) -> AllocResult < usize > {
72
119
self . palloc . lock ( ) . alloc_pages ( num_pages, align_pow2)
73
120
}
74
121
122
+ /// Gives back the allocated pages starts from `pos` to the page allocator.
123
+ ///
124
+ /// The pages should be allocated by [`alloc_pages`], and `align_pow2`
125
+ /// should be the same as the one used in [`alloc_pages`]. Otherwise, the
126
+ /// behavior is undefined.
127
+ ///
128
+ /// [`alloc_pages`]: GlobalAllocator::alloc_pages
75
129
pub fn dealloc_pages ( & self , pos : usize , num_pages : usize ) {
76
130
self . palloc . lock ( ) . dealloc_pages ( pos, num_pages)
77
131
}
78
132
133
+ /// Returns the number of allocated bytes in the byte allocator.
79
134
pub fn used_bytes ( & self ) -> usize {
80
135
self . balloc . lock ( ) . used_bytes ( )
81
136
}
82
137
138
+ /// Returns the number of available bytes in the byte allocator.
83
139
pub fn available_bytes ( & self ) -> usize {
84
140
self . balloc . lock ( ) . available_bytes ( )
85
141
}
86
142
143
+ /// Returns the number of allocated pages in the page allocator.
87
144
pub fn used_pages ( & self ) -> usize {
88
145
self . palloc . lock ( ) . used_pages ( )
89
146
}
90
147
148
+ /// Returns the number of available pages in the page allocator.
91
149
pub fn available_pages ( & self ) -> usize {
92
150
self . palloc . lock ( ) . available_pages ( )
93
151
}
@@ -120,10 +178,19 @@ fn handle_alloc_error(layout: Layout) -> ! {
120
178
) ;
121
179
}
122
180
181
+ /// Returns the reference to the global allocator.
123
182
pub fn global_allocator ( ) -> & ' static GlobalAllocator {
124
183
& GLOBAL_ALLOCATOR
125
184
}
126
185
186
+ /// Initializes the global allocator with the given memory region.
187
+ ///
188
+ /// Note that the memory region bounds are just numbers, and the allocator
189
+ /// does not actually access the region. Users should ensure that the region
190
+ /// is valid and not being used by others, so that the allocated memory is also
191
+ /// valid.
192
+ ///
193
+ /// This function should be called only once, and before any allocation.
127
194
pub fn global_init ( start_vaddr : usize , size : usize ) {
128
195
debug ! (
129
196
"initialize global allocator at: [{:#x}, {:#x})" ,
@@ -133,6 +200,12 @@ pub fn global_init(start_vaddr: usize, size: usize) {
133
200
GLOBAL_ALLOCATOR . init ( start_vaddr, size) ;
134
201
}
135
202
203
+ /// Add the given memory region to the global allocator.
204
+ ///
205
+ /// Users should ensure that the region is valid and not being used by others,
206
+ /// so that the allocated memory is also valid.
207
+ ///
208
+ /// It's similar to [`global_init`], but can be called multiple times.
136
209
pub fn global_add_memory ( start_vaddr : usize , size : usize ) -> AllocResult {
137
210
debug ! (
138
211
"add a memory region to global allocator: [{:#x}, {:#x})" ,
0 commit comments