Files
Elyz/kernel/docs/events/introduction.md
2026-07-07 16:40:41 +03:00

129 lines
5.0 KiB
Markdown
Raw Permalink 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.
# Очередь отзыва RevocationQueue: `events.rs`
## Концептуальная модель
**RevocationQueue** — это глобальная lock-free кольцевая очередь,
которая соединяет capability-систему (CNode) с виртуальной памятью (VMM).
### Назначение
Когда capability отзывается, VMM должна аннулировать все VMA,
связанные с этим capability. Но:
- CNode.revoke() не может напрямую обратиться к VMM (разные подсистемы,
разное время жизни блокировок).
- VMM может быть в обработке page fault'а.
- Отзыв может быть каскадным и рекурсивным.
Решение: **асинхронная очередь**.
```
CNode.revoke(token_1)
└──→ push(token_1) ───→ MMU_REVOCATION_QUEUE ──→ pop() ──→ VMM
CNode.revoke(token_2) │
│ │
└──→ push(token_2) ─────────────────────────────────────────┤
Page Fault handler │
│ │
└──→ process_pending_revocations() ←────────────────────────┘
```
## RevocationQueue — детали
```rust
pub struct RevocationQueue {
buffer: [AtomicU64; QUEUE_SIZE], // 1024 entry
_pad0: [u8; 64], // padding: кэш-линия
head: AtomicUsize, // читатель (VMM)
_pad1: [u8; 64], // padding: кэш-линия
tail: AtomicUsize, // писатели (CNode revoke)
}
```
Тот же паттерн, что и в `PMActorQueue`: разделение head и tail
по разным кэш-линиям предотвращает false sharing.
### push(token_sig)
```rust
pub fn push(&self, token_sig: u64) -> Result<(), &'static str> {
let mut tail = self.tail.load(Ordering::Relaxed);
loop {
let head = self.head.load(Ordering::Acquire);
if tail.wrapping_sub(head) >= QUEUE_SIZE {
return Err("Revocation queue overflow");
}
match self.tail.compare_exchange_weak(tail, tail+1, AcqRel, Relaxed) {
Ok(_) => {
self.buffer[tail & QUEUE_MASK].store(token_sig, Release);
return Ok(());
}
Err(actual) => tail = actual,
}
}
}
```
### pop()
```rust
pub fn pop(&self) -> Option<u64> {
let head = self.head.load(Ordering::Relaxed);
let tail = self.tail.load(Ordering::Acquire);
if head == tail { return None; }
let token = self.buffer[head & QUEUE_MASK].load(Ordering::Acquire);
self.head.store(head.wrapping_add(1), Ordering::Release);
Some(token)
}
```
## Глобальный экземпляр
```rust
pub static MMU_REVOCATION_QUEUE: RevocationQueue = RevocationQueue::new();
```
## VMM: обработка отзывов
```rust
// В interrupts.rs: rust_page_fault_handler()
let mut vmm_guard = KERNEL_SPACE.lock();
if let Some(space) = vmm_guard.as_mut() {
space.process_pending_revocations(); // ← дренирует очередь
match space.handle_fault(fault_addr, write) { ... }
}
```
```rust
// В vmm.rs: AddressSpace
pub fn process_pending_revocations(&mut self) {
let mut needs_flush = false;
while let Some(token) = MMU_REVOCATION_QUEUE.pop() {
self.do_revoke_by_token(token);
needs_flush = true;
}
if needs_flush {
tlb_flush_asid(self.asid);
}
}
```
## Почему именно так?
1. **Lock-free**: отзыв capability не блокируется VMM.
2. **Batch processing**: VMM обрабатывает сразу все накопленные отзывы
при следующем page fault, экономя TLB flush'ы.
3. **Deadlock prevention**: process_pending_revocations вызывается
**до** handle_fault, избегая циклических зависимостей между
блокировками capability и VMM.
4. **Простота**: кольцевой буфер с CAS — проверенная временем структура.
## Ограничения
- Размер: 1024 entry. Если очередь переполняется — **паника**.
Это проектный выбор: переполнение означает, что VMM не успевает
обрабатывать отзывы быстрее, чем CNode генерирует новые.
- Однопоточный pop (только page fault handler дренирует очередь).