# Акторы физической памяти (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` Дренирует очередь, обрабатывает каждый запрос через приватные методы. **Только из контекста актора** (`&mut self` гарантирует single consumer). #### Приватные обработчики **`handle_allocate(size_pages, token_sig, channel_id) -> Option`** 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`** 1. Валидация границ 2. `buddy.free(local_frame_idx, order)` 3. Возвращает None (маршрутизация не нужна) **`handle_carve(offset_pages, size_pages, channel_id) -> Option`** 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>, } ``` ### 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` CAS-цикл на `free_head`: извлекает голову списка, устанавливает `state = PENDING`. ### `route_responses(responses: Vec)` Для каждого 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)` Точка входа для маршрутизации ответов через `PMActor::route_responses()` (вызов на глобальном роутере).