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<Uuid> = const { RwLock::new(Uuid::nil()) };
}
static RUNNING_PROCESSES: LazyLock<RwLock<HashMap<Uuid, Process>>> =
LazyLock::new(|| RwLock::new(HashMap::new()));
#[derive(Debug)]
pub struct Process {
id: Uuid,
thread: JoinHandle<()>,
channel: mpsc::Sender<Message>,
}
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(())
}
|