tawasuyu

tawasuyu/brahman

Rust 575TOML 218Markdown 68JSON 198402 Definitions

⎇ 4bcdc88c838739c9bdac50c6d6d9a906c1d2f729 renaser/kernel/src/async_system/reloj.rs Rust · 108 lines · 4.4 KB History Who touched what raw

feat(renaser): Fase 11 — el reloj del sistema como capacidad de host 4bcdc88c8 · sergio ·

1// =============================================================================
2//  renaser :: async_system/reloj.rs — Fase 5 :: el compas de los fotogramas
3// -----------------------------------------------------------------------------
4//  El temporizador (PIT, IRQ0) ya no solo despierta al ejecutor de su `hlt`:
5//  ahora marca el COMPAS del userspace. Cada pulso a 100 Hz es un fotograma —
6//  una oportunidad de cesion cooperativa. `EsperaFrame` convierte ese pulso de
7//  hardware en un `Future`: una tarea WASM hace su trabajo de un fotograma y
8//  `.await`-ea el siguiente, cediendo la CPU a sus vecinas mientras tanto.
9// =============================================================================
10
11use alloc::vec::Vec;
12use core::future::Future;
13use core::pin::Pin;
14use core::sync::atomic::{AtomicU64, Ordering};
15use core::task::{Context, Poll, Waker};
16
17use spin::{Mutex, Once};
18use x86_64::instructions::interrupts;
19
20/// Pulsos del temporizador acumulados desde el arranque. Lo incrementa la IRQ0;
21/// lo consulta `EsperaFrame`. Atomico: la IRQ y el hilo principal lo comparten.
22static CONTADOR_PULSOS: AtomicU64 = AtomicU64::new(0);
23
24/// Censo de wakers en espera del proximo fotograma. Vive en el heap —de ahi el
25/// `Once`—; tras su `Mutex`, lo disputan el lado tarea y el manejador de IRQ0.
26static EN_ESPERA: Once<Mutex<Vec<Waker>>> = Once::new();
27
28/// Funda el censo de wakers del reloj. Requiere el heap ya activo; debe
29/// invocarse una sola vez, antes de habilitar las interrupciones.
30pub fn init() {
31    EN_ESPERA.call_once(|| Mutex::new(Vec::new()));
32}
33
34/// Punto de entrada DESDE el manejador de IRQ0. Avanza el contador de pulsos y
35/// despierta a cuantas tareas aguardaban el fotograma. Deliberadamente breve y
36/// libre de panicos: corre en contexto de interrupcion.
37pub fn pulso() {
38    // `Release`: el avance del contador se publica ANTES de que los wakers
39    // reinyecten sus tareas; el `poll` que sigue lo leera con `Acquire` y vera,
40    // garantizado, el valor nuevo.
41    CONTADOR_PULSOS.fetch_add(1, Ordering::Release);
42    if let Some(censo) = EN_ESPERA.get() {
43        // En contexto de IRQ las interrupciones ya estan acalladas; tomar aqui
44        // el cerrojo no puede interbloquear, pues el lado tarea siempre lo toma
45        // con las interrupciones desactivadas (ver `inscribir`).
46        for waker in censo.lock().drain(..) {
47            waker.wake();
48        }
49    }
50}
51
52/// Numero de pulsos del temporizador desde el arranque.
53fn pulsos() -> u64 {
54    CONTADOR_PULSOS.load(Ordering::Acquire)
55}
56
57/// Milisegundos transcurridos desde el arranque (Fase 11). El temporizador late
58/// a 100 Hz —un pulso cada 10 ms—; esta es la lectura del reloj MONOTONO que el
59/// host ofrece al userspace como `sys_tiempo_mono`. Jamas retrocede.
60pub fn milisegundos() -> u64 {
61    pulsos().saturating_mul(10)
62}
63
64/// Inscribe un waker en el censo de espera del proximo fotograma.
65fn inscribir(waker: Waker) {
66    if let Some(censo) = EN_ESPERA.get() {
67        // El cerrojo lo disputa el manejador de IRQ0: tomarlo con las
68        // interrupciones acalladas hace IMPOSIBLE el interbloqueo.
69        interrupts::without_interrupts(|| censo.lock().push(waker));
70    }
71}
72
73/// Un `Future` que se resuelve en el proximo pulso del temporizador. Es la
74/// unidad de cesion cooperativa del userspace: una tarea WASM hace su trabajo
75/// de un fotograma y `.await`-ea un `EsperaFrame` para ceder hasta el siguiente.
76pub struct EsperaFrame {
77    /// Pulso a partir del cual la espera se da por cumplida.
78    objetivo: u64,
79}
80
81impl EsperaFrame {
82    /// Crea una espera que se resolvera en el siguiente pulso del temporizador.
83    pub fn nueva() -> EsperaFrame {
84        EsperaFrame {
85            objetivo: pulsos() + 1,
86        }
87    }
88}
89
90impl Future for EsperaFrame {
91    type Output = ();
92
93    fn poll(self: Pin<&mut Self>, contexto: &mut Context<'_>) -> Poll<()> {
94        // Lectura optimista: si el fotograma ya llego, no hay nada que esperar.
95        if pulsos() >= self.objetivo {
96            return Poll::Ready(());
97        }
98        // Aun no: inscribir el waker y RE-VERIFICAR. Si un pulso se colo entre
99        // la lectura de arriba y la inscripcion, este segundo chequeo lo atrapa;
100        // sin el, el despertar se perderia hasta el pulso siguiente.
101        inscribir(contexto.waker().clone());
102        if pulsos() >= self.objetivo {
103            Poll::Ready(())
104        } else {
105            Poll::Pending
106        }
107    }
108}