⎇ 4bcdc88c838739c9bdac50c6d6d9a906c1d2f729
renaser/kernel/src/async_system/reloj.rs
History
Who touched what
raw
feat(renaser): Fase 11 — el reloj del sistema como capacidad de host
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}