add sleep, which was unexpectedly titchy!

This commit is contained in:
Scott Richmond 2025-06-27 14:27:42 -04:00
parent 90505f89fe
commit 8923581eed
5 changed files with 136 additions and 74 deletions

View File

@ -414,6 +414,7 @@ fn print! {
"Sends a text representation of Ludus values to the console."
(...args) -> {
let line = do args > map (string, _) > join (_, " ")
base :print! (args)
update! (console, append (_, line))
:ok
}

View File

@ -1,16 +1,20 @@
fn simple_reporter () -> {
fn reporter () -> {
print! (self (), msgs ())
}
fn hanger () -> hanger ()
fn printer () -> {
print!("LUDUS SAYS ==> hi")
sleep! (1)
printer ()
}
let foo = spawn! (hanger)
let bar = spawn! (simple_reporter)
let baz = spawn! (fn () -> panic! :oops)
send (foo, [:foo, :bar, :baz])
send (bar, (1, 2, 3))
let foo = spawn! (printer)
let bar = spawn! (reporter)
yield! ()
send (bar, [:foo, :bar, :baz])
& yield! ()
sleep! (5)
:done

View File

@ -3,7 +3,7 @@ use imbl::HashMap;
use wasm_bindgen::prelude::*;
const DEBUG_SCRIPT_COMPILE: bool = false;
const DEBUG_SCRIPT_RUN: bool = true;
const DEBUG_SCRIPT_RUN: bool = false;
const DEBUG_PRELUDE_COMPILE: bool = false;
const DEBUG_PRELUDE_RUN: bool = false;

View File

@ -292,14 +292,15 @@ impl Creature {
self.push(Value::Keyword("ok"));
}
"spawn" => {
println!("spawning new process!");
let f = args[1].clone();
let proc = Creature::spawn(f, self.zoo.clone(), self.debug);
let id = self.zoo.as_ref().borrow_mut().put(proc);
println!("spawning new process {id}!");
self.push(Value::Keyword(id));
}
"yield" => {
self.r#yield = true;
println!("yielding from {}", self.id);
self.push(Value::Keyword("ok"));
}
"alive" => {
@ -318,7 +319,15 @@ impl Creature {
self.mbx = VecDeque::new();
self.push(Value::Keyword("ok"));
}
"sleep" => {}
"sleep" => {
println!("sleeping {} for {}", self.id, args[1]);
let Value::Number(ms) = args[1] else {
unreachable!()
};
self.zoo.as_ref().borrow_mut().sleep(self.id, ms as usize);
self.r#yield = true;
self.push(Value::Keyword("ok"));
}
msg => panic!("Process does not understand message: {msg}"),
}
}

View File

@ -4,7 +4,9 @@ use crate::vm::{Creature, Panic};
use ran::ran_u8;
use std::cell::RefCell;
use std::collections::HashMap;
use std::mem::swap;
use std::rc::Rc;
use std::time::{Duration, Instant};
const ANIMALS: [&str; 24] = [
"tortoise",
@ -67,7 +69,9 @@ pub struct Zoo {
ids: HashMap<&'static str, usize>,
dead: Vec<&'static str>,
kill_list: Vec<&'static str>,
active: usize,
sleeping: HashMap<&'static str, (Instant, Duration)>,
active_idx: usize,
active_id: &'static str,
}
impl Zoo {
@ -78,7 +82,9 @@ impl Zoo {
ids: HashMap::new(),
kill_list: vec![],
dead: vec![],
active: 0,
sleeping: HashMap::new(),
active_idx: 0,
active_id: "",
}
}
@ -119,27 +125,63 @@ impl Zoo {
self.kill_list.push(id);
}
pub fn sleep(&mut self, id: &'static str, ms: usize) {
self.sleeping
.insert(id, (Instant::now(), Duration::from_millis(ms as u64)));
}
pub fn is_alive(&self, id: &'static str) -> bool {
if self.kill_list.contains(&id) {
return false;
}
let idx = self.ids.get(id);
match idx {
Some(idx) => match self.procs.get(*idx) {
Some(proc) => match proc {
Status::Empty => false,
Status::Borrowed => true,
Status::Nested(_) => true,
},
None => false,
},
None => false,
}
}
pub fn clean_up(&mut self) {
while let Some(id) = self.kill_list.pop() {
if let Some(idx) = self.ids.get(id) {
println!("buried process {id}");
self.procs[*idx] = Status::Empty;
self.empty.push(*idx);
self.ids.remove(id);
self.dead.push(id);
}
}
self.sleeping
.retain(|_, (instant, duration)| instant.elapsed() < *duration);
println!(
"currently sleeping processes: {}",
self.sleeping
.keys()
.map(|id| id.to_string())
.collect::<Vec<_>>()
.join(" | ")
);
}
pub fn catch(&mut self, id: &'static str) -> Creature {
if let Some(idx) = self.ids.get(id) {
let mut proc = Status::Borrowed;
std::mem::swap(&mut proc, &mut self.procs[*idx]);
swap(&mut proc, &mut self.procs[*idx]);
let Status::Nested(proc) = proc else {
unreachable!("tried to borrow an empty or already-borrowed process");
unreachable!("tried to borrow an empty or already-borrowed process {id}");
};
proc
} else {
unreachable!("tried to borrow a non-existent process");
unreachable!("tried to borrow a non-existent process {id}");
}
}
@ -147,46 +189,36 @@ impl Zoo {
let id = proc.id;
if let Some(idx) = self.ids.get(id) {
let mut proc = Status::Nested(proc);
std::mem::swap(&mut proc, &mut self.procs[*idx]);
} else {
unreachable!("tried to return a process the world doesn't know about");
swap(&mut proc, &mut self.procs[*idx]);
}
// Removed because, well, we shouldn't have creatures we don't know about
// And since zoo.next now cleans (and thus kills) before the world releases its active process
// We'll die if we execute this check
// else {
// unreachable!("tried to return a process the world doesn't know about");
// }
}
pub fn is_available(&self) -> bool {
match &self.procs[self.active_idx] {
Status::Empty => false,
Status::Borrowed => false,
Status::Nested(proc) => !self.sleeping.contains_key(proc.id),
}
}
pub fn next(&mut self, curr_id: &'static str) -> &'static str {
println!("getting next process from {curr_id}");
println!(
"current procs in zoo:\n{}",
self.procs
.iter()
.map(|proc| proc.to_string())
.collect::<Vec<_>>()
.join("//")
);
println!("ids: {:?}", self.ids);
let idx = self.ids.get(curr_id).unwrap();
println!("current idx: {idx}");
if *idx != self.active {
panic!(
"tried to get next creature after {curr_id} while {} is active",
self.active
pub fn next(&mut self) -> &'static str {
self.active_idx = (self.active_idx + 1) % self.procs.len();
while !self.is_available() {
self.clean_up();
self.active_idx = (self.active_idx + 1) % self.procs.len();
println!(
"testing process availability: {}",
self.procs[self.active_idx]
);
}
self.active = (self.active + 1) % self.procs.len();
println!("active idx is now: {}", self.active);
while self.procs[self.active] == Status::Empty {
let new_active_idx = (self.active + 1) % self.procs.len();
println!("new active idx: {new_active_idx}");
println!("new active process is: {}", self.procs[new_active_idx]);
self.active = (self.active + 1) % self.procs.len();
}
println!("found next proc: {}", &self.procs[self.active]);
match &self.procs[self.active] {
Status::Empty => unreachable!(),
Status::Borrowed => panic!(
"encountered unexpectedly borrowed process at idx {}",
self.active
),
match &self.procs[self.active_idx] {
Status::Empty | Status::Borrowed => unreachable!(),
Status::Nested(proc) => proc.id,
}
}
@ -231,26 +263,42 @@ impl World {
// proc.receive(msg);
// self.zoo.release(proc);
// }
//
fn next(&mut self) {
let id = self
.zoo
.as_ref()
.borrow_mut()
.next(self.active.as_ref().unwrap().id);
println!("next id is {id}");
let mut active = None;
std::mem::swap(&mut active, &mut self.active);
let mut holding_pen = self.zoo.as_ref().borrow_mut().catch(id);
let mut active = active.unwrap();
std::mem::swap(&mut active, &mut holding_pen);
println!("now in the holding pen: {}", holding_pen.id);
holding_pen.reset_reductions();
self.zoo.as_ref().borrow_mut().release(holding_pen);
let mut active = Some(active);
std::mem::swap(&mut active, &mut self.active);
swap(&mut active, &mut self.active);
let mut zoo = self.zoo.as_ref().borrow_mut();
zoo.release(active.unwrap());
// at the moment, active is None, process is released.
// zoo should NOT need an id--it has a representation of the current active process
// world has an active process for memory reasons
// not for state-keeping reasons
let new_active_id = zoo.next();
let mut new_active_proc = zoo.catch(new_active_id);
new_active_proc.reset_reductions();
let mut new_active_opt = Some(new_active_proc);
swap(&mut new_active_opt, &mut self.active);
}
// fn old_next(&mut self) {
// let id = self
// .zoo
// .as_ref()
// .borrow_mut()
// .next(self.active.as_ref().unwrap().id);
// println!("next id is {id}");
// let mut active = None;
// std::mem::swap(&mut active, &mut self.active);
// let mut holding_pen = self.zoo.as_ref().borrow_mut().catch(id);
// let mut active = active.unwrap();
// std::mem::swap(&mut active, &mut holding_pen);
// println!("now in the holding pen: {}", holding_pen.id);
// holding_pen.reset_reductions();
// self.zoo.as_ref().borrow_mut().release(holding_pen);
// let mut active = Some(active);
// std::mem::swap(&mut active, &mut self.active);
// }
// pub fn sleep(&mut self, id: &'static str) {
// // check if the id is the actually active process
// if self.active.id != id {
@ -299,16 +347,15 @@ impl World {
&self.active.as_ref().unwrap().result
}
pub fn clean_up(&mut self) {
self.zoo.as_ref().borrow_mut().clean_up()
}
pub fn run(&mut self) {
self.activate_main();
loop {
println!("entering world loop");
println!(
"entering world loop; active process is {}",
self.active_id()
);
self.active.as_mut().unwrap().interpret();
println!("interpreted loop");
println!("yielded from {}", self.active_id());
match self.active_result() {
None => (),
Some(_) => {
@ -316,12 +363,13 @@ impl World {
self.result = self.active_result().clone();
return;
}
println!("process died: {}", self.active_id());
self.kill_active();
}
}
println!("getting next process");
self.next();
self.clean_up();
// self.clean_up();
}
}