diff --git a/src/runtime2/branch.rs b/src/runtime2/branch.rs index f67f2e5570a5743c3680ae3af354a0bd59ce13d7..16931db7d8d272feb58fb48d8950889cb978c032 100644 --- a/src/runtime2/branch.rs +++ b/src/runtime2/branch.rs @@ -1,6 +1,9 @@ +use std::collections::HashMap; use std::ops::{Index, IndexMut}; use crate::protocol::ComponentState; +use crate::protocol::eval::ValueGroup; +use crate::runtime2::port::PortIdLocal; /// Generic branch ID. A component will always have one branch: the /// non-speculative branch. This branch has ID 0. Hence in a speculative context @@ -50,7 +53,9 @@ pub(crate) struct Branch { // Execution state pub code_state: ComponentState, pub sync_state: SpeculativeState, + pub awaiting_port: PortIdLocal, // only valid if in "awaiting message" queue. TODO: Maybe put in enum pub next_in_queue: BranchId, // used by `ExecTree`/`BranchQueue` + pub inbox: HashMap; // TODO: Remove, currently only valid in single-get/put mode } impl Branch { @@ -61,7 +66,9 @@ impl Branch { parent_id: BranchId::new_invalid(), code_state: component_state, sync_state: SpeculativeState::RunningNonSync, + awaiting_port: PortIdLocal::new_invalid(), next_in_queue: BranchId::new_invalid(), + inbox: HashMap::new(), } } @@ -79,9 +86,20 @@ impl Branch { parent_id: parent_branch.index, code_state: parent_branch.code_state.clone(), sync_state: SpeculativeState::RunningInSync, + awaiting_port: parent_branch.awaiting_port, next_in_queue: BranchId::new_invalid(), + inbox: parent_branch.inbox.clone(), } } + + /// Inserts a message into the branch for retrieval by a corresponding + /// `get(port)` call. + pub(crate) fn insert_message(&mut self, target_port: PortIdLocal, contents: ValueGroup) { + debug_assert!(target_port.is_valid()); + debug_assert!(self.awaiting_port == target_port); + self.awaiting_port = PortIdLocal::new_invalid(); + self.inbox.insert(target_port, contents); + } } /// Queue of branches. Just a little helper. @@ -157,6 +175,11 @@ impl ExecTree { return self.branches.len() != 1; } + /// Returns true if the particular queue is empty + pub fn queue_is_empty(&self, kind: QueueKind) -> bool { + return self.queues[kind.as_index()].is_empty(); + } + /// Pops a branch (ID) from a queue. pub fn pop_from_queue(&mut self, kind: QueueKind) -> Option { let queue = &mut self.queues[kind.as_index()]; @@ -187,15 +210,25 @@ impl ExecTree { } } - pub fn iter_queue(&self, kind: QueueKind) -> BranchIter { + /// Returns an iterator over all the elements in the queue of the given kind + pub fn iter_queue(&self, kind: QueueKind) -> BranchQueueIter { let queue = &self.queues[kind.as_index()]; let index = queue.first as usize; - return BranchIter{ + return BranchQueueIter { branches: self.branches.as_slice(), index, } } + /// Returns an iterator that starts with the provided branch, and then + /// continues to visit all of the branch's parents. + pub fn iter_parents(&self, branch_id: BranchId) -> BranchParentIter { + return BranchParentIter{ + branches: self.branches.as_slice(), + index: branch_id.index as usize, + } + } + // --- Preparing and finishing a speculative round /// Starts a synchronous round by cloning the non-sync branch and marking it @@ -210,16 +243,12 @@ impl ExecTree { /// Creates a new speculative branch based on the provided one. The index to /// retrieve this new branch will be returned. - pub fn fork_branch(&mut self, parent_branch_id: BranchId, initial_queue: Option) -> BranchId { + pub fn fork_branch(&mut self, parent_branch_id: BranchId) -> BranchId { debug_assert!(self.is_in_sync()); let parent_branch = &self[parent_branch_id]; let new_branch = Branch::new_sync(1, parent_branch); let new_branch_id = new_branch.id; - if let Some(kind) = initial_queue { - self.push_into_queue(kind, new_branch_id); - } - return new_branch_id; } @@ -263,12 +292,12 @@ impl IndexMut for ExecTree { } } -pub struct BranchIter<'a> { +pub struct BranchQueueIter<'a> { branches: &'a [Branch], index: usize, } -impl<'a> Iterator for BranchIter<'a> { +impl<'a> Iterator for BranchQueueIter<'a> { type Item = &'a Branch; fn next(&mut self) -> Option { @@ -281,4 +310,23 @@ impl<'a> Iterator for BranchIter<'a> { self.index = branch.next_in_queue.index as usize; return Some(branch); } +} + +pub struct BranchParentIter<'a> { + branches: &'a [Branch], + index: usize, +} + +impl<'a> Iterator for BranchParentIter<'a> { + type Item = &'a Branch; + + fn next(&mut self) -> Option { + if self.index == 0 { + return None; + } + + let branch = &self.branches[self.index]; + self.index = branch.parent_id.index as usize; + return Some(branch); + } } \ No newline at end of file