Configure the currently running `thread`. This will save off any state necessary for the previous thread, if applicable, and then it'll additionally update state for `thread` if needed too.
(&mut self, thread: impl Into<CurrentThread>)
| 1741 | /// applicable, and then it'll additionally update state for `thread` if |
| 1742 | /// needed too. |
| 1743 | fn set_thread(&mut self, thread: impl Into<CurrentThread>) -> Result<CurrentThread> { |
| 1744 | let thread = thread.into(); |
| 1745 | let state = self.concurrent_state_mut(); |
| 1746 | let old_thread = mem::replace(&mut state.current_thread, thread); |
| 1747 | |
| 1748 | // First thing to do after swapping threads is updating the context |
| 1749 | // slots for this thread within the store. This restores the behavior of |
| 1750 | // `context.{get,set}`. This involves taking the old state out of the |
| 1751 | // store, saving it in the thread that's being swapped from, and doing |
| 1752 | // the inverse for the new thread. When debug assertions are enabled |
| 1753 | // this also leaves behind sentinel values to try to uncover bugs where |
| 1754 | // this may be forgotten. |
| 1755 | if let Some(old_thread) = old_thread.guest() { |
| 1756 | let old_context = self.vm_store_context().component_context; |
| 1757 | self.concurrent_state_mut() |
| 1758 | .get_mut(old_thread.thread)? |
| 1759 | .context = old_context; |
| 1760 | } |
| 1761 | if cfg!(debug_assertions) { |
| 1762 | self.vm_store_context_mut().component_context = [u32::MAX; NUM_COMPONENT_CONTEXT_SLOTS]; |
| 1763 | } |
| 1764 | if let Some(thread) = thread.guest() { |
| 1765 | let thread = self.concurrent_state_mut().get_mut(thread.thread)?; |
| 1766 | let context = thread.context; |
| 1767 | if cfg!(debug_assertions) { |
| 1768 | thread.context = [u32::MAX; NUM_COMPONENT_CONTEXT_SLOTS]; |
| 1769 | } |
| 1770 | self.vm_store_context_mut().component_context = context; |
| 1771 | } |
| 1772 | |
| 1773 | // Each time we switch threads, we conservatively set `task_may_block` |
| 1774 | // to `false` for the component instance we're switching away from (if |
| 1775 | // any), meaning it will be `false` for any new thread created for that |
| 1776 | // instance unless explicitly set otherwise. |
| 1777 | // |
| 1778 | // Additionally if we're switching to a new thread, set its component |
| 1779 | // instance's `task_may_block` according to where it left off. |
| 1780 | let state = self.concurrent_state_mut(); |
| 1781 | if let Some(old_thread) = old_thread.guest() { |
| 1782 | let instance = state.get_mut(old_thread.task)?.instance.instance; |
| 1783 | self.component_instance_mut(instance) |
| 1784 | .set_task_may_block(false) |
| 1785 | } |
| 1786 | |
| 1787 | if thread.guest().is_some() { |
| 1788 | self.set_task_may_block()?; |
| 1789 | } |
| 1790 | |
| 1791 | Ok(old_thread) |
| 1792 | } |
| 1793 | |
| 1794 | /// Set the global variable representing whether the current task may block |
| 1795 | /// prior to entering Wasm code. |
no test coverage detected