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+
18#![ no_std]
29#![ feature( alloc_error_handler) ]
310
@@ -17,19 +24,34 @@ const MIN_HEAP_SIZE: usize = 0x8000; // 32 K
1724
1825pub use page:: GlobalPage ;
1926
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.
2036pub struct GlobalAllocator {
2137 balloc : SpinNoIrq < SlabByteAllocator > ,
2238 palloc : SpinNoIrq < BitmapPageAllocator < PAGE_SIZE > > ,
2339}
2440
2541impl GlobalAllocator {
42+ /// Creates an empty [`GlobalAllocator`].
2643 pub const fn new ( ) -> Self {
2744 Self {
2845 balloc : SpinNoIrq :: new ( SlabByteAllocator :: new ( ) ) ,
2946 palloc : SpinNoIrq :: new ( BitmapPageAllocator :: new ( ) ) ,
3047 }
3148 }
3249
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.
3355 pub fn init ( & self , start_vaddr : usize , size : usize ) {
3456 assert ! ( size > MIN_HEAP_SIZE ) ;
3557 let init_heap_size = MIN_HEAP_SIZE ;
@@ -40,10 +62,22 @@ impl GlobalAllocator {
4062 self . balloc . lock ( ) . init ( heap_ptr, init_heap_size) ;
4163 }
4264
65+ /// Add the given region to the allocator.
66+ ///
67+ /// It will add the whole region to the byte allocator.
4368 pub fn add_memory ( & self , start_vaddr : usize , size : usize ) -> AllocResult {
4469 self . balloc . lock ( ) . add_memory ( start_vaddr, size)
4570 }
4671
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.
4781 pub fn alloc ( & self , size : usize , align_pow2 : usize ) -> AllocResult < usize > {
4882 // simple two-level allocator: if no heap memory, allocate from the page allocator.
4983 let mut balloc = self . balloc . lock ( ) ;
@@ -64,30 +98,54 @@ impl GlobalAllocator {
6498 }
6599 }
66100
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
67108 pub fn dealloc ( & self , pos : usize , size : usize , align_pow2 : usize ) {
68109 self . balloc . lock ( ) . dealloc ( pos, size, align_pow2)
69110 }
70111
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.
71118 pub fn alloc_pages ( & self , num_pages : usize , align_pow2 : usize ) -> AllocResult < usize > {
72119 self . palloc . lock ( ) . alloc_pages ( num_pages, align_pow2)
73120 }
74121
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
75129 pub fn dealloc_pages ( & self , pos : usize , num_pages : usize ) {
76130 self . palloc . lock ( ) . dealloc_pages ( pos, num_pages)
77131 }
78132
133+ /// Returns the number of allocated bytes in the byte allocator.
79134 pub fn used_bytes ( & self ) -> usize {
80135 self . balloc . lock ( ) . used_bytes ( )
81136 }
82137
138+ /// Returns the number of available bytes in the byte allocator.
83139 pub fn available_bytes ( & self ) -> usize {
84140 self . balloc . lock ( ) . available_bytes ( )
85141 }
86142
143+ /// Returns the number of allocated pages in the page allocator.
87144 pub fn used_pages ( & self ) -> usize {
88145 self . palloc . lock ( ) . used_pages ( )
89146 }
90147
148+ /// Returns the number of available pages in the page allocator.
91149 pub fn available_pages ( & self ) -> usize {
92150 self . palloc . lock ( ) . available_pages ( )
93151 }
@@ -120,10 +178,19 @@ fn handle_alloc_error(layout: Layout) -> ! {
120178 ) ;
121179}
122180
181+ /// Returns the reference to the global allocator.
123182pub fn global_allocator ( ) -> & ' static GlobalAllocator {
124183 & GLOBAL_ALLOCATOR
125184}
126185
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.
127194pub fn global_init ( start_vaddr : usize , size : usize ) {
128195 debug ! (
129196 "initialize global allocator at: [{:#x}, {:#x})" ,
@@ -133,6 +200,12 @@ pub fn global_init(start_vaddr: usize, size: usize) {
133200 GLOBAL_ALLOCATOR . init ( start_vaddr, size) ;
134201}
135202
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.
136209pub fn global_add_memory ( start_vaddr : usize , size : usize ) -> AllocResult {
137210 debug ! (
138211 "add a memory region to global allocator: [{:#x}, {:#x})" ,
0 commit comments