5.1 KiB
Акторы физической памяти (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
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
pub enum PMResult {
Allocated { cap: Capability, order: usize },
OutOfMemory { size_pages: usize },
Carved { cap: Capability },
Freed { pages_returned: usize },
}
PMResponse
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/Releaseordering.
PMActor
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>
buddy.alloc_pages(size_pages)→(local_idx, order)- Строит сильную дочернюю Capability с уникальным
token_sig - Возвращает
Allocated { cap, order } - При неудаче:
OutOfMemory(планируется ballooning)
handle_free(local_frame_idx, order) -> Option<PMResponse>
- Валидация границ
buddy.free(local_frame_idx, order)- Возвращает None (маршрутизация не нужна)
handle_carve(offset_pages, size_pages, channel_id) -> Option<PMResponse>
- Валидация диапазона
- Возвращает
Carved { cap } - Не взаимодействует с 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))]
struct Channel {
state: AtomicU8,
next_free: AtomicU16,
result: UnsafeCell<Option<PMResult>>,
}
PMRouter
pub struct PMRouter {
channels: Box<[Channel]>, // 65536 каналов
free_head: AtomicU16, // голова free list (0 = sentinel)
}
GlobalRouter
static ROUTER: GlobalRouter; // синглтон
init()
- Создаёт Vec из 65536 каналов, соединённых в linked list (каждый
next_freeуказывает на следующий) - Преобразует в
Box<[Channel]> - Сохраняет в
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() (вызов на глобальном роутере).