Files
Elyz/kernel/docs/allocator.md
2026-07-06 00:25:49 +03:00

106 lines
3.1 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Аллокатор кучи
**Файл**: `src/mem/allocator.rs`
Slab-аллокатор со spinlock-синхронизацией и fallback bump-аллокацией для больших блоков.
---
## Примитив синхронизации: `Locked<A>`
Самодельный spinlock (альтернатива `spin::Mutex`).
```rust
pub struct Locked<A> {
inner: UnsafeCell<A>,
lock: AtomicBool,
}
```
- `new(inner)` — создаёт с unlocked состоянием
- `lock() -> LockedGuard<'_, A>` — CAS-цикл на `AtomicBool` (спин-ожидание)
### LockedGuard
- `Deref`/`DerefMut` — доступ к внутренним данным
- `Drop``store(false, Release)` — освобождение блокировки
`unsafe impl<A> Sync for Locked<A>` — разработчик гарантирует корректность.
---
## SlabAllocator
```rust
pub struct SlabAllocator {
list_heads: [Option<&'static mut ListNode>; 9], // slab free list
large_block_free: Option<&'static mut LargeBlockNode>, // free list для >2048
heap_start: usize,
heap_end: usize,
next_bump: usize,
}
```
### Slab классы
```rust
const BLOCK_SIZES: &[usize] = &[8, 16, 32, 64, 128, 256, 512, 1024, 2048];
```
9 классов — степени двойки от 8 до 2048.
### ListNode / LargeBlockNode
```rust
struct ListNode {
next: Option<&'static mut ListNode>,
}
struct LargeBlockNode {
size: usize,
next: Option<&'static mut LargeBlockNode>,
}
```
Односвязные списки свободных блоков.
### `init(&mut self, start, size)`
Устанавливает границы кучи: `heap_start = start`, `heap_end = start + size`, `next_bump = start`.
### `list_index(layout) -> Option<usize>`
Находит индекс наименьшего slab-класса, покрывающего `max(size, align)`.
Пример: layout size=20, align=8 → блок 20 > 16, следующий 32 → index 3 (32 байта).
### `fallback_alloc(&mut self, layout) -> *mut u8`
1. Проверяет `large_block_free` — если есть подходящий блок, отдаёт его
2. Иначе bump-аллокация: выравнивание, проверка `next_bump + size <= heap_end`, возврат `next_bump`
3. При OOM возвращает null
---
## Глобальный аллокатор
```rust
#[global_allocator]
pub static ALLOCATOR: Locked<SlabAllocator>;
```
### `GlobalAlloc::alloc(&self, layout) -> *mut u8`
1. Lock allocator
2. Если `layout.size()` влезает в slab класс:
- Находит `list_index`
- Если free list не пуст: pop голову, вернуть указатель
- Если пуст: `fallback_alloc(layout)` но с размером slab-блока (не `layout.size()`)
3. Для блоков > 2048: сразу `fallback_alloc(layout)`
### `GlobalAlloc::dealloc(&self, ptr, layout)`
1. Lock allocator
2. Для slab-sized: push обратно в slab free list как ListNode
3. Для больших: push в large_block_free как LargeBlockNode