Stream: git-wasmtime

Topic: wasmtime / issue #12485 Code not interrupting


view this post on Zulip Wasmtime GitHub notifications bot (Feb 01 2026 at 18:21):

suprohub opened issue #12485:

Why i see only start and dont see code interrupt every 50 ms?

use std::time::Duration;

use anyhow::Result;
use wasmtime::*;

#[tokio::main]
async fn main() -> Result<()> {
    let mut config = Config::default();

    config.async_support(true);
    config.epoch_interruption(true);

    let engine = Engine::new(&config)?;

    let engine_clone = engine.clone();
    std::thread::spawn(move || {
        loop {
            std::thread::sleep(Duration::from_millis(50));
            engine_clone.increment_epoch();
        }
    });


    let wat = r#"
        (module
            (type (;0;) (func))
            (func (;0;) (type 0)
                loop  ;; label = @1
                loop
                i32.const 1
                drop
                br 1
                end
                br 0 (;@1;)
                end)
            (memory (;0;) 16)
            (global (;0;) (mut i32) (i32.const 1048576))
            (global (;1;) i32 (i32.const 1048576))
            (global (;2;) i32 (i32.const 1048576))
            (export "memory" (memory 0))
            (export "main" (func 0))
            (export "__data_end" (global 1))
            (export "__heap_base" (global 2))
        )
    "#;
    let module = Module::new(&engine, wat)?;

    // Create a `Linker` which will be later used to instantiate this module.
    // Host functionality is defined by name within the `Linker`.
    let mut linker = Linker::new(&engine);
    linker.func_wrap("host", "host_func", |caller: Caller<'_, StoreLimits>, param: i32| {
        println!("Got {} from WebAssembly", param);
    })?;

    // All wasm objects operate within the context of a "store". Each
    // `Store` has a type parameter to store host-specific data, which in
    // this case we're using `4` for.
    let mut store = Store::new(&engine, StoreLimits::default());
    store.limiter(|state| state);
    store.set_epoch_deadline(1);
    store.epoch_deadline_async_yield_and_update(1);
    let instance = linker.instantiate_async(&mut store, &module).await?;
    let hello = instance.get_typed_func::<(), ()>(&mut store, "main")?;

    // And finally we can call the wasm!
    let call_future = hello.call_async(&mut store, ());
    tokio::pin!(call_future);

    loop {
        println!("start");
        call_future.as_mut().await?;
        println!("epoch");
        tokio::time::sleep(Duration::from_millis(1000)).await;
    }
    Ok(())
}

view this post on Zulip Wasmtime GitHub notifications bot (Feb 02 2026 at 01:25):

cfallin commented on issue #12485:

call_future.as_mut().await?;

Awaiting the call future will block until the call is complete. An epoch yield configured with epoch_deadline_async_yield_and_update operates "below the abstraction level" of future completion: it causes the Future::poll invocation on the future to return Poll::Pending and mark itself immediately ready to re-execute (via the waker), giving the async event loop a chance to run something else.

That gets back to the intent of the epoch mechanism: it is to make arbitrarily-long-running Wasm code play well with an async executor loop.

There are two-and-a-half ways to actually see the yield:

view this post on Zulip Wasmtime GitHub notifications bot (Feb 02 2026 at 01:25):

cfallin closed issue #12485:

Why i see only start and dont see code interrupt every 50 ms?

use std::time::Duration;

use anyhow::Result;
use wasmtime::*;

#[tokio::main]
async fn main() -> Result<()> {
    let mut config = Config::default();

    config.async_support(true);
    config.epoch_interruption(true);

    let engine = Engine::new(&config)?;

    let engine_clone = engine.clone();
    std::thread::spawn(move || {
        loop {
            std::thread::sleep(Duration::from_millis(50));
            engine_clone.increment_epoch();
        }
    });


    let wat = r#"
        (module
            (type (;0;) (func))
            (func (;0;) (type 0)
                loop  ;; label = @1
                loop
                i32.const 1
                drop
                br 1
                end
                br 0 (;@1;)
                end)
            (memory (;0;) 16)
            (global (;0;) (mut i32) (i32.const 1048576))
            (global (;1;) i32 (i32.const 1048576))
            (global (;2;) i32 (i32.const 1048576))
            (export "memory" (memory 0))
            (export "main" (func 0))
            (export "__data_end" (global 1))
            (export "__heap_base" (global 2))
        )
    "#;
    let module = Module::new(&engine, wat)?;

    // Create a `Linker` which will be later used to instantiate this module.
    // Host functionality is defined by name within the `Linker`.
    let mut linker = Linker::new(&engine);
    linker.func_wrap("host", "host_func", |caller: Caller<'_, StoreLimits>, param: i32| {
        println!("Got {} from WebAssembly", param);
    })?;

    // All wasm objects operate within the context of a "store". Each
    // `Store` has a type parameter to store host-specific data, which in
    // this case we're using `4` for.
    let mut store = Store::new(&engine, StoreLimits::default());
    store.limiter(|state| state);
    store.set_epoch_deadline(1);
    store.epoch_deadline_async_yield_and_update(1);
    let instance = linker.instantiate_async(&mut store, &module).await?;
    let hello = instance.get_typed_func::<(), ()>(&mut store, "main")?;

    // And finally we can call the wasm!
    let call_future = hello.call_async(&mut store, ());
    tokio::pin!(call_future);

    loop {
        println!("start");
        call_future.as_mut().await?;
        println!("epoch");
        tokio::time::sleep(Duration::from_millis(1000)).await;
    }
    Ok(())
}

view this post on Zulip Wasmtime GitHub notifications bot (Feb 02 2026 at 01:25):

cfallin commented on issue #12485:

I'll close this issue since the API is working as designed, but feel free to ask followup questions here or in our Zulip.


Last updated: Feb 24 2026 at 04:36 UTC