Browse Source

wasmtime: add EngineWeak which has ::upgrade, created by Engine::weak (#7797)

* wasmtime: add EngineWeak which has ::upgrade, created by Engine::weak

Engine is, internally, just an Arc<EngineInner>, so this is trivial to implement -
EngineWeak is a Weak<EngineInner>.

This behavior is desirable because `Engine::increment_epoch` typically
happens in a worker thread, which in turn requires additional machinery
to discard the `Engine` once it is no longer needed. If instead the
worker thread holds an `EngineWeak`, it can stop ticking when all
consumers of the `Engine` have dropped it. This has been documented as a
suggestion in `increment_epoch`.

For an example of additional machinery which is simplified by this change, see 25edee0700/lib/src/execute.rs (L108-L116))

Co-authored-by: John Van Enk <vanenkj@gmail.com>

* add a test

---------

Co-authored-by: John Van Enk <vanenkj@gmail.com>
pull/7799/head
Pat Hickey 10 months ago
committed by GitHub
parent
commit
c736c712e5
No known key found for this signature in database GPG Key ID: B5690EEEBB952194
  1. 39
      crates/wasmtime/src/engine.rs

39
crates/wasmtime/src/engine.rs

@ -180,6 +180,11 @@ impl Engine {
/// for an introduction to epoch-based interruption and pointers /// for an introduction to epoch-based interruption and pointers
/// to the other relevant methods. /// to the other relevant methods.
/// ///
/// When performing `increment_epoch` in a separate thread, consider using
/// [`Engine::weak`] to hold an [`EngineWeak`] and performing
/// [`EngineWeak::upgrade`] on each tick, so that the epoch ticking thread
/// does not keep an [`Engine`] alive longer than any of its consumers.
///
/// ## Signal Safety /// ## Signal Safety
/// ///
/// This method is signal-safe: it does not make any syscalls, and /// This method is signal-safe: it does not make any syscalls, and
@ -654,6 +659,13 @@ impl Engine {
pub fn detect_precompiled_file(&self, path: impl AsRef<Path>) -> Result<Option<Precompiled>> { pub fn detect_precompiled_file(&self, path: impl AsRef<Path>) -> Result<Option<Precompiled>> {
serialization::detect_precompiled_file(path) serialization::detect_precompiled_file(path)
} }
/// Take a weak reference to this engine.
pub fn weak(&self) -> EngineWeak {
EngineWeak {
inner: Arc::downgrade(&self.inner),
}
}
} }
impl Default for Engine { impl Default for Engine {
@ -671,6 +683,20 @@ pub enum Precompiled {
Component, Component,
} }
/// A weak reference to an [`Engine`].
#[derive(Clone)]
pub struct EngineWeak {
inner: std::sync::Weak<EngineInner>,
}
impl EngineWeak {
/// Upgrade this weak reference into an [`Engine`]. Returns `None` if
/// strong references (the [`Engine`] type itself) no longer exist.
pub fn upgrade(&self) -> Option<Engine> {
std::sync::Weak::upgrade(&self.inner).map(|inner| Engine { inner })
}
}
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use std::{ use std::{
@ -787,4 +813,17 @@ mod tests {
Ok(()) Ok(())
} }
#[test]
fn engine_weak_upgrades() {
let engine = Engine::default();
let weak = engine.weak();
weak.upgrade()
.expect("engine is still alive, so weak reference can upgrade");
drop(engine);
assert!(
weak.upgrade().is_none(),
"engine was dropped, so weak reference cannot upgrade"
);
}
} }

Loading…
Cancel
Save