use crate::prelude::*;
use crate::proc::Pid;
use std::cell::Cell;
use std::rc::Rc;
pub type InternalJobId = u64;
pub struct WaitHandle {
pub pid: Pid,
pub internal_job_id: InternalJobId,
pub base_name: WString,
status: Cell<Option<i32>>,
}
impl WaitHandle {
pub fn is_completed(&self) -> bool {
self.status.get().is_some()
}
pub fn set_status_and_complete(&self, status: i32) {
assert!(!self.is_completed(), "wait handle already completed");
self.status.set(Some(status));
}
pub fn status(&self) -> Option<i32> {
self.status.get()
}
}
impl WaitHandle {
pub fn new(pid: Pid, internal_job_id: InternalJobId, base_name: WString) -> WaitHandleRef {
Rc::new(WaitHandle {
pid,
internal_job_id,
base_name,
status: Default::default(),
})
}
}
pub type WaitHandleRef = Rc<WaitHandle>;
const WAIT_HANDLE_STORE_DEFAULT_LIMIT: usize = 1024;
pub struct WaitHandleStore {
cache: lru::LruCache<Pid, WaitHandleRef>,
}
impl Default for WaitHandleStore {
fn default() -> Self {
Self::new_with_capacity(WAIT_HANDLE_STORE_DEFAULT_LIMIT)
}
}
impl WaitHandleStore {
pub fn new_with_capacity(capacity: usize) -> Self {
let capacity = std::num::NonZeroUsize::new(capacity).unwrap();
WaitHandleStore {
cache: lru::LruCache::new(capacity),
}
}
pub fn add(&mut self, wh: WaitHandleRef) {
self.cache.put(wh.pid, wh);
}
pub fn get_by_pid(&self, pid: Pid) -> Option<WaitHandleRef> {
self.cache.peek(&pid).cloned()
}
pub fn remove(&mut self, wh: &WaitHandleRef) {
if let Some(key) = self.cache.peek(&wh.pid) {
if Rc::ptr_eq(key, wh) {
self.cache.pop(&wh.pid);
}
}
}
pub fn remove_by_pid(&mut self, pid: Pid) {
self.cache.pop(&pid);
}
pub fn iter(&self) -> impl Iterator<Item = &WaitHandleRef> {
self.cache.iter().map(|(_, wh)| wh)
}
pub fn get_list(&self) -> Vec<WaitHandleRef> {
self.cache.iter().map(|(_, wh)| wh.clone()).collect()
}
pub fn size(&self) -> usize {
self.cache.len()
}
}
#[cfg(test)]
mod tests {
use super::{WaitHandle, WaitHandleStore};
use crate::prelude::*;
use crate::proc::Pid;
#[test]
fn test_wait_handles() {
let limit: usize = 4;
let mut whs = WaitHandleStore::new_with_capacity(limit);
assert_eq!(whs.size(), 0);
fn p(pid: i32) -> Pid {
Pid::new(pid)
}
assert!(whs.get_by_pid(p(5)).is_none());
whs.add(WaitHandle::new(p(5), 0, L!("first").to_owned()));
whs.add(WaitHandle::new(p(5), 0, L!("second").to_owned()));
assert_eq!(whs.size(), 1);
assert_eq!(whs.get_by_pid(p(5)).unwrap().base_name, "second");
whs.remove_by_pid(p(123));
assert_eq!(whs.size(), 1);
whs.remove_by_pid(p(5));
assert_eq!(whs.size(), 0);
whs.add(WaitHandle::new(p(1), 0, L!("1").to_owned()));
whs.add(WaitHandle::new(p(2), 0, L!("2").to_owned()));
whs.add(WaitHandle::new(p(3), 0, L!("3").to_owned()));
whs.add(WaitHandle::new(p(4), 0, L!("4").to_owned()));
whs.add(WaitHandle::new(p(5), 0, L!("5").to_owned()));
assert_eq!(whs.size(), 4);
let entries = whs.get_list();
let mut iter = entries.iter();
assert_eq!(iter.next().unwrap().base_name, "5");
assert_eq!(iter.next().unwrap().base_name, "4");
assert_eq!(iter.next().unwrap().base_name, "3");
assert_eq!(iter.next().unwrap().base_name, "2");
assert!(iter.next().is_none());
}
}