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

174 lines
5.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.
# Акторы физической памяти (PMActor) и маршрутизатор (PM Router)
---
## Формат сообщений
Вся коммуникация использует упаковку в `u64`:
```
[8b opcode | 16b channel_id | 20b arg1 | 20b arg2]
```
Константы: `OPCODE_SHIFT = 56`, `CHAN_SHIFT = 40`, `ARG1_SHIFT = 20`
Маски: `CHAN_MASK = 0x0000_FFFF`, `ARG_MASK = 0x000F_FFFF`
---
## PMActor
**Файл**: `src/mem/pm_manages.rs`
Распределённый актор физической памяти. Каждый актор владеет фиксрованным диапазоном и управляет им через BuddyAllocator.
### PMRequest
```rust
pub enum PMRequest {
Allocate { size_pages: usize, token_sig: u32, channel_id: u16 },
Free { local_frame_idx: usize, order: usize },
Carve { offset_pages: usize, size_pages: usize, channel_id: u16 },
None, // sentinel (не может быть отправлен)
}
```
Методы: `pack() -> u64`, `unpack(val: u64) -> Self`.
### PMResult
```rust
pub enum PMResult {
Allocated { cap: Capability, order: usize },
OutOfMemory { size_pages: usize },
Carved { cap: Capability },
Freed { pages_returned: usize },
}
```
### PMResponse
```rust
pub struct PMResponse {
pub channel_id: u16,
pub result: PMResult,
}
```
### PMActorQueue — Lock-free MPSC
Кольцевой буфер на 1024 слота (`AtomicU64`) с cache-line padding.
- `send(req)` — CAS loop на `tail` (multi-producer). Отклоняет None.
- `pop()` — single-consumer. `Acquire`/`Release` ordering.
### PMActor
```rust
pub struct PMActor {
actor_id: u64,
root_untyped: Capability,
managed_range: (PhysAddr, PhysAddr), // [start, end)
queue: PMActorQueue,
buddy: BuddyAllocator,
}
```
#### `new(actor_id, root_cap, start, size_bytes) -> Self`
Конструктор.
#### `submit_request(req) -> Result<(), &str>`
Thread-safe: пушит в `queue`.
#### `process_messages(&mut self) -> Vec<PMResponse>`
Дренирует очередь, обрабатывает каждый запрос через приватные методы.
**Только из контекста актора** (`&mut self` гарантирует single consumer).
#### Приватные обработчики
**`handle_allocate(size_pages, token_sig, channel_id) -> Option<PMResponse>`**
1. `buddy.alloc_pages(size_pages)``(local_idx, order)`
2. Строит сильную дочернюю Capability с уникальным `token_sig`
3. Возвращает `Allocated { cap, order }`
4. При неудаче: `OutOfMemory` (планируется ballooning)
**`handle_free(local_frame_idx, order) -> Option<PMResponse>`**
1. Валидация границ
2. `buddy.free(local_frame_idx, order)`
3. Возвращает None (маршрутизация не нужна)
**`handle_carve(offset_pages, size_pages, channel_id) -> Option<PMResponse>`**
1. Валидация диапазона
2. Возвращает `Carved { cap }`
3. Не взаимодействует с buddy
---
## PMRouter
**Файл**: `src/mem/pm_router.rs`
Глобальная ткань маршрутизации: 65536 lock-free каналов.
### Константы
- `CHANNEL_COUNT = 65536`
- Состояния: `STATE_FREE = 0`, `STATE_PENDING = 1`, `STATE_READY = 2`
### Channel — `#[repr(align(64))]`
```rust
struct Channel {
state: AtomicU8,
next_free: AtomicU16,
result: UnsafeCell<Option<PMResult>>,
}
```
### PMRouter
```rust
pub struct PMRouter {
channels: Box<[Channel]>, // 65536 каналов
free_head: AtomicU16, // голова free list (0 = sentinel)
}
```
### GlobalRouter
```rust
static ROUTER: GlobalRouter; // синглтон
```
### `init()`
1. Создаёт Vec из 65536 каналов, соединённых в linked list (каждый `next_free` указывает на следующий)
2. Преобразует в `Box<[Channel]>`
3. Сохраняет в `ROUTER.inner`, устанавливает `is_ready`
### `alloc_channel() -> Option<u16>`
CAS-цикл на `free_head`: извлекает голову списка, устанавливает `state = PENDING`.
### `route_responses(responses: Vec<PMResponse>)`
Для каждого PMResponse с ненулевым `channel_id`: сохраняет `result` в канале, устанавливает `state = READY`.
### `wait_for_response(id: u16) -> PMResult`
Spin-wait до `state == READY`. Забирает результат, пушит канал обратно в freelist, возвращает результат.
### `request_and_wait(actor, req_builder) -> PMResult`
Convenience: аллоцирует канал, строит запрос с channel_id, отправляет актору, ждёт ответ. (process_messages должен быть вызван внешне.)
### `dispatch(responses: Vec<PMResponse>)`
Точка входа для маршрутизации ответов через `PMActor::route_responses()` (вызов на глобальном роутере).