summaryrefslogtreecommitdiff
path: root/src/processes.rs
blob: 7ac326f63c7cab59bd9d13f011da8aae66250be3 (plain)
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(())
}