86 lines
2.8 KiB
Markdown
86 lines
2.8 KiB
Markdown
# Очередь отзыва (RevocationQueue)
|
||
|
||
**Файл**: `src/events.rs`
|
||
|
||
Lock-free MPSC (Multi-Producer Single-Consumer) очередь для уведомления VMM об отзыве capability.
|
||
|
||
---
|
||
|
||
## RevocationQueue
|
||
|
||
```rust
|
||
pub struct RevocationQueue {
|
||
buffer: [AtomicU64; QUEUE_SIZE], // 1024 слота
|
||
_pad0: [u8; 64], // cache-line padding
|
||
head: AtomicUsize, // индекс потребителя (VMM)
|
||
_pad1: [u8; 64], // ещё padding
|
||
tail: AtomicUsize, // индекс производителя (CNode)
|
||
}
|
||
```
|
||
|
||
Cache-line padding (64 байта) предотвращает **false sharing** между head и tail на разных кэш-линиях.
|
||
|
||
### Константы
|
||
|
||
- `QUEUE_SIZE = 1024`
|
||
- `QUEUE_MASK = 1023`
|
||
|
||
### `new() -> Self`
|
||
|
||
Все слоты = 0, head = 0, tail = 0.
|
||
|
||
### `push(token_sig: u64) -> Result<(), &'static str>`
|
||
|
||
1. Читает `tail` (Relaxed)
|
||
2. CAS-цикл: пытается захватить следующий слот
|
||
3. Если буфер полон (`tail - head == QUEUE_SIZE`): ошибка
|
||
4. Записывает `token_sig` в `buffer[tail & QUEUE_MASK]` (Release ordering)
|
||
5. Обновляет `tail` (Release)
|
||
|
||
**Производители**: CNode::revoke() — при каждом отзыве пушит token_sig.
|
||
|
||
### `pop() -> Option<u64>`
|
||
|
||
1. Читает `tail` (Acquire) и `head` (Relaxed)
|
||
2. Если `head == tail`: буфер пуст, None
|
||
3. Читает `buffer[head & QUEUE_MASK]` (Acquire)
|
||
4. Обновляет `head` (Release)
|
||
5. Возвращает token
|
||
|
||
**Потребитель**: VMM — `AddressSpace::process_pending_revocations()`.
|
||
|
||
---
|
||
|
||
## Глобальный экземпляр
|
||
|
||
```rust
|
||
pub static MMU_REVOCATION_QUEUE: RevocationQueue = RevocationQueue::new();
|
||
```
|
||
|
||
---
|
||
|
||
## Полный цикл ревокации
|
||
|
||
```
|
||
CNode::revoke(slot_idx)
|
||
→ revoke_internal(slot_idx) // рекурсивное уничтожение потомков
|
||
→ slot = Empty
|
||
→ MMU_REVOCATION_QUEUE.push(token_sig)
|
||
|
||
... позже, при page fault ...
|
||
|
||
rust_page_fault_handler()
|
||
→ process_deferred_mmu_events()
|
||
→ KERNEL_SPACE.lock()
|
||
→ process_pending_revocations()
|
||
→ while let Some(token) = MMU_REVOCATION_QUEUE.pop()
|
||
→ revoke_by_token(token)
|
||
→ unmap matching VMAs (кроме PINNED)
|
||
→ TLB flush
|
||
|
||
→ KERNEL_SPACE.lock()
|
||
→ handle_fault(fault_addr, write) // обработка исходного fault
|
||
```
|
||
|
||
**Почему такая очерёдность?** Ревокации обрабатываются **до** захвата VMM для page fault, чтобы избежать deadlock'а: и revoke, и handle_fault хотят lock на `KERNEL_SPACE`.
|