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

2.8 KiB
Raw Blame History

Очередь отзыва (RevocationQueue)

Файл: src/events.rs

Lock-free MPSC (Multi-Producer Single-Consumer) очередь для уведомления VMM об отзыве capability.


RevocationQueue

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().


Глобальный экземпляр

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.