gioser

tawasuyu/brahman

Rust 226TOML 67JSON 14HTML 12860 Sutichaykuna

⎇ e2272c0ed3c87ef53fd5ea5c9e6fd52d4790dcb8 renaser/kernel/src/async_system/executor.rs Rust · 103 siq'ikuna · 4.1 KB Ñawpa willay Pi imata llamkarqan ch'uya

feat: integra renaser (kernel SASOS bare-metal) al monorepo e2272c0ed · sergio ·

1// =============================================================================
2//  renaser :: async_system/executor.rs — Fase 3 :: el reactor cooperativo
3// -----------------------------------------------------------------------------
4//  El ejecutor es el corazon reactivo de renaser. Mantiene el censo de tareas
5//  vivas y una cola de las que estan listas para avanzar. Cuando no queda nada
6//  por hacer, no malgasta la CPU en un bucle ocupado: la duerme con `hlt`
7//  hasta que el proximo impulso de hardware la despierte.
8// =============================================================================
9
10use alloc::collections::{BTreeMap, VecDeque};
11use alloc::sync::Arc;
12use core::future::Future;
13use core::task::{Context, Poll, Waker};
14
15use spin::Mutex;
16use x86_64::instructions::interrupts;
17
18use super::task::{Task, TaskId};
19use super::waker::{self, ColaListas};
20
21/// El ejecutor cooperativo de renaser.
22pub struct Executor {
23    /// Censo de todas las tareas vivas, indexadas por su identidad.
24    tareas: BTreeMap<TaskId, Task>,
25    /// Cola de tareas listas para su proximo avance.
26    cola_listas: ColaListas,
27    /// Cache de wakers: uno por tarea, reutilizado entre avances.
28    cache_wakers: BTreeMap<TaskId, Waker>,
29}
30
31impl Executor {
32    /// Crea un ejecutor vacio. Requiere que el heap ya este fundado.
33    pub fn nuevo() -> Executor {
34        Executor {
35            tareas: BTreeMap::new(),
36            cola_listas: Arc::new(Mutex::new(VecDeque::new())),
37            cache_wakers: BTreeMap::new(),
38        }
39    }
40
41    /// Da de alta una tarea nueva y la marca como lista para su primer avance.
42    pub fn spawn(&mut self, futuro: impl Future<Output = ()> + Send + 'static) {
43        let tarea = Task::nueva(futuro);
44        let id = tarea.id;
45        if self.tareas.insert(id, tarea).is_some() {
46            panic!("renaser :: TaskId duplicado — lo imposible ha ocurrido");
47        }
48        interrupts::without_interrupts(|| self.cola_listas.lock().push_back(id));
49    }
50
51    /// Avanza, hasta agotarla, la cola de tareas listas.
52    fn avanzar_listas(&mut self) {
53        loop {
54            // Sacar el siguiente id con las interrupciones acalladas: la cola
55            // es compartida con los wakers que se disparan desde las IRQ.
56            let siguiente = interrupts::without_interrupts(|| self.cola_listas.lock().pop_front());
57            let id = match siguiente {
58                Some(id) => id,
59                None => return,
60            };
61            let tarea = match self.tareas.get_mut(&id) {
62                Some(t) => t,
63                None => continue, // la tarea concluyo en una vuelta previa
64            };
65            // Un waker por tarea, reutilizado: reinyecta esta tarea en la cola.
66            let cola = self.cola_listas.clone();
67            let despertador = self
68                .cache_wakers
69                .entry(id)
70                .or_insert_with(|| waker::crear(id, cola));
71            let mut contexto = Context::from_waker(despertador);
72            if let Poll::Ready(()) = tarea.poll(&mut contexto) {
73                // La tarea termino: se retira del censo y se libera su waker.
74                self.tareas.remove(&id);
75                self.cache_wakers.remove(&id);
76            }
77        }
78    }
79
80    /// Si no queda trabajo, duerme la CPU hasta la proxima interrupcion. El
81    /// chequeo y el `hlt` se hacen con las interrupciones acalladas para que
82    /// ningun despertar se pierda en la rendija entre uno y otro.
83    fn dormir_si_inactivo(&self) {
84        interrupts::disable();
85        let hay_trabajo = !self.cola_listas.lock().is_empty();
86        if hay_trabajo {
87            // Llego trabajo justo ahora: reactivar y seguir sin dormir.
88            interrupts::enable();
89        } else {
90            // `sti; hlt` atomico: habilita y duerme sin condicion de carrera.
91            interrupts::enable_and_hlt();
92        }
93    }
94
95    /// Cede el hilo principal al reactor. No retorna jamas: desde aqui, renaser
96    /// vive del latir de sus interrupciones.
97    pub fn run(&mut self) -> ! {
98        loop {
99            self.avanzar_listas();
100            self.dormir_si_inactivo();
101        }
102    }
103}