use std::collections::HashMap; use std::sync::{LazyLock, RwLock, mpsc}; use std::thread::JoinHandle; use happylock::ThreadKey; use uuid::Uuid; use crate::pipe::{Message, MessageResponse}; thread_local! { static PROCESS_ID: RwLock = const { RwLock::new(Uuid::nil()) }; } static RUNNING_PROCESSES: LazyLock>> = LazyLock::new(|| RwLock::new(HashMap::new())); #[derive(Debug)] pub struct Process { id: Uuid, thread: JoinHandle<()>, channel: mpsc::Sender, } pub fn is_builtin(program_id: Uuid) -> bool { program_id.as_u64_pair().0 == 0 } pub fn process_id(key: &mut ThreadKey) -> Uuid { PROCESS_ID.with(|id| *id.read().unwrap()) } pub fn send_message(key: &mut ThreadKey, program_id: Uuid, message: Message) -> MessageResponse { start_program(key, program_id); let programs = RUNNING_PROCESSES.read().unwrap(); // TODO: this can crash if the program runs and exits immediately let program = programs.get(&program_id).unwrap(); let response = MessageResponse::from_message(&message); _ = program.channel.send(message); response } pub fn start_builtin_as(key: &mut ThreadKey, package_id: Uuid, as_program: Uuid) -> Option<()> { let mut processes = RUNNING_PROCESSES.write().unwrap(); if processes.contains_key(&as_program) { return Some(()); } let builtin_index = package_id.as_u64_pair().1 as usize; let func = crate::builtins::BUILTINS.get(builtin_index)?.as_ref()?; let (sender, receiver) = mpsc::channel(); let handle = std::thread::spawn(move || { let key = ThreadKey::get().expect("the thread just started"); PROCESS_ID.with(|id| { *id.write().unwrap() = as_program; }); func(key, receiver); }); let process = Process { id: as_program, thread: handle, channel: sender, }; processes.insert(as_program, process); Some(()) } pub fn start_builtin(key: &mut ThreadKey, package_id: Uuid) -> Option<()> { start_builtin_as(key, package_id, package_id) } pub fn start_program(key: &mut ThreadKey, package_id: Uuid) -> Option<()> { start_builtin(key, package_id)?; Some(()) }