use std::{collections::HashMap, sync::{atomic::{AtomicUsize, Ordering}, Mutex, RwLock}}; use tokio::process::Command; #[allow(dead_code)] #[derive(Debug, Clone)] struct Proc { msg: String, finished: bool } lazy_static::lazy_static!( static ref PROCESSES: Mutex>> = Mutex::new(RwLock::new(HashMap::new())); ); static PROC_INC: AtomicUsize = AtomicUsize::new(0); pub fn add_proc(mut cmd: Command, msg: String) -> anyhow::Result<()> { let mut proc = cmd.spawn()?; let id = PROC_INC.fetch_add(1, Ordering::AcqRel); tokio::spawn(async move { let id = id; proc.wait().await .expect("child process encountered an error"); PROCESSES.lock().unwrap().write().unwrap().get_mut(&id).unwrap().finished = true; }); PROCESSES.lock().unwrap().write().unwrap().insert(id, Proc { finished: false, msg, }); Ok(()) } pub fn is_proc_queue_full(max: usize) -> bool { let proc_cnt = PROCESSES.lock().unwrap().read().unwrap().len(); proc_cnt >= max } pub fn purge_done_procs() -> usize { let mut finish_count = 0; let procs = { PROCESSES.lock().unwrap().read().unwrap().clone() }; for (idx, proc) in procs { if proc.finished { { PROCESSES.lock().unwrap().write().unwrap().remove(&idx); } log::info!("{}", proc.msg); finish_count += 1; } } finish_count } /// Waits for processes to finish untill the proc count is lower or equal to `max` pub fn wait_for_procs_untill(max: usize) -> anyhow::Result { // NOTE: This looks really fucked because i dont want to deadlock the processes so i lock PROCESSES for as little as possible // NOTE: So its also kinda really slow let mut finish_count = 0; loop { if !is_proc_queue_full(max) { return Ok(finish_count); } finish_count += purge_done_procs(); } }