From c8d01b6151f77b62494d1d0147e3f3ab268d2bab Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Hru=C5=A1ka?= Date: Sat, 31 Oct 2020 17:55:23 +0100 Subject: [PATCH] coroutine fixes, first example --- crsn/src/runtime/run_thread.rs | 16 +++++++++--- crsn/src/runtime/run_thread/state.rs | 5 +++- examples/coroutines1.csn | 38 ++++++++++++++++++++++++++++ 3 files changed, 55 insertions(+), 4 deletions(-) create mode 100644 examples/coroutines1.csn diff --git a/crsn/src/runtime/run_thread.rs b/crsn/src/runtime/run_thread.rs index 9c6d3d7..fb58990 100644 --- a/crsn/src/runtime/run_thread.rs +++ b/crsn/src/runtime/run_thread.rs @@ -91,6 +91,7 @@ impl RunThread { loop_helper.loop_start(); } trace!("Step {}; Status = {}", advance, self.state.cr.frame.status); + let orig_pc = self.state.cr.frame.pc; self.state.cr.frame.pc.advance(advance); if let Some(dl) = self.state.cr_deadline { @@ -100,14 +101,17 @@ impl RunThread { match sched { SchedSignal::Normal => {} SchedSignal::Yield(None) => { + trace!("yield"); self.state.cr.cr_state = CoroutineState::Ready; want_switch = true; } SchedSignal::Yield(Some(value)) => { + trace!("yield {}", value); self.state.cr.cr_state = CoroutineState::YieldedValue(value); want_switch = true; } SchedSignal::Sleep(time) => { + trace!("sleep {:?}", time); self.state.cr.cr_state = CoroutineState::Sleep { due: Instant::now() + time }; want_switch = true; } @@ -117,27 +121,33 @@ impl RunThread { // TODO prioritize a thread that is waiting for this return value } SchedSignal::Join(handle) => { + trace!("Join cr {:#}", handle); let mut found = false; 'find: for (n, th) in self.state.parked.iter_mut().enumerate() { if th.handle == handle { if let CoroutineState::Finished(_) = &th.cr_state { let mut crs = mem::replace(&mut th.cr_state, CoroutineState::Ready); self.state.parked.remove(n); // delete it + found = true; if let CoroutineState::Finished(vals) = crs { self.state.cr.frame.set_retvals(&vals); - found = true; break 'find; } else { unreachable!(); } + } else { + self.state.cr.frame.pc = orig_pc; // Retry + self.state.cr.cr_state = CoroutineState::Ready; + want_switch = true; + found = true; } } } if !found { self.state.set_flag(Flag::Invalid, true); - warn!("Join with invalid thread handle!"); + warn!("Join with invalid thread handle {:#}!", handle); self.state.cr.frame.set_retvals(&[]); } } @@ -214,7 +224,7 @@ impl RunThread { let n_alive = self.state.parked.iter() .filter(|p| p.cr_state.is_alive()).count(); - if n_alive <= 1 { + if n_alive == 0 { trace!("Stop task switching, no parked threads are alive"); self.state.cr_deadline = None; } diff --git a/crsn/src/runtime/run_thread/state.rs b/crsn/src/runtime/run_thread/state.rs index fc4f055..5b3ffc2 100644 --- a/crsn/src/runtime/run_thread/state.rs +++ b/crsn/src/runtime/run_thread/state.rs @@ -82,7 +82,10 @@ impl RunState { /// Add a coroutine, marked as Ready, to run next pub fn add_coroutine(&mut self, frame : StackFrame) -> Value { let handle = self.thread_info.unique_handle(); - self.parked.push_back(CoroutineContext { + trace!("Spawn cr {:#}", handle); + + // front - so it runs ASAP + self.parked.push_front(CoroutineContext { handle, frame, call_stack: vec![], diff --git a/examples/coroutines1.csn b/examples/coroutines1.csn new file mode 100644 index 0000000..e550114 --- /dev/null +++ b/examples/coroutines1.csn @@ -0,0 +1,38 @@ +( + (lds @cout "main\n") + (msleep 500) + (lds @cout "main\n") + (msleep 500) + + (lds @cout "Spawnign bg\n") + + (spawn r15 bg 10) + + (msleep 500) + (lds @cout "FG\n") + (msleep 500) + (lds @cout "FG\n") + (msleep 500) + (lds @cout "FG\n") + + (msleep 1000) + + (lds @cout "Wait for BG\n") + (join @r15) + (lds @cout "Joined\n") + (msleep 500) + (lds @cout "main\n") + (msleep 500) + (lds @cout "main\n") + (msleep 500) + + (proc bg times + (ld r0 times) + (:x) + (msleep 500) + (lds @cout "***BG\n") + (dec r0 (nz? (j :x))) + (lds @cout "***BG done.\n") + (ret) + ) +)