add sleep, which was unexpectedly titchy!
This commit is contained in:
parent
90505f89fe
commit
8923581eed
|
@ -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
|
||||
}
|
||||
|
|
20
sandbox.ld
20
sandbox.ld
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
13
src/vm.rs
13
src/vm.rs
|
@ -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}"),
|
||||
}
|
||||
}
|
||||
|
|
174
src/world.rs
174
src/world.rs
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue
Block a user