# How to stop a wasm function?

**URL:** <https://users.rust-lang.org/t/how-to-stop-a-wasm-function/58672>\
**Category:** help\
**Created:** [April 20, 2021, 3:38pm UTC](https://users.rust-lang.org/t/how-to-stop-a-wasm-function/58672 "2021-04-20T15:38:04Z")\
**Posts on this page:** 15\
**Page:** 1

<div class="post-metadata">

**Author:** ![mattpiz](https://sea1.discourse-cdn.com/flex019/user_avatar/users.rust-lang.org/mattpiz/32/8476_2.png) [@mattpiz](https://users.rust-lang.org/u/mattpiz)\
**Post date:** [April 20, 2021, 3:38pm UTC](https://users.rust-lang.org/t/how-to-stop-a-wasm-function/58672/1 "2021-04-20T15:38:05Z")

</div>

So the question I have is rather simple, but it has lead to me to some rabbit holes and I'm getting to darker places slowly but surely so I'm trying to get a fresh point of view from other rust users.

I have a command line tool, performing some iterative optimization algorithm that can take a bit of time (from few seconds to a minute or so). In the terminal, it's fairly easy to stop it via [Ctrl+C] if needed. But I have ported the algorithm to WebAssembly and I'm struggling to find a solution to stop the function from user input in the web app.

## What I've got so far

The wasm module is loaded in a web worker to prevent the main UI thread to freeze. I can communicate from wasm to the web app via imported JS functions, that's what enabled my implementation of `Log` to pass the program logs to the main thread as they occur. Below is a sreenshot of the logs while the algorithm is running and a "stop!" button that I'd like to be able to click to stop the algorithm.

 ![lowrr-logs](https://us1.discourse-cdn.com/flex019/uploads/rust_lang/original/3X/0/6/06a509b2eda9efbe288db249f52b934feb7adf24.png)

I thought I could also inject a function as a parameter in my algorithm, with something looking like:

```rust
fn algorithm(should_stop: &mut dyn FnMut() -> bool) {
    loop {
        if should_stop() { return; }
        ...
    }
}

```

And that `should_stop` function would be imported from JS and would check a global value `stop_order` in the worker that could be changed anytime by a user interaction in the main thread. But that's where the rabbit hole starts.

Since JS is monothreaded, I can't change that value until the algorithm finishes running, which defies its purpose. UNLESS `algorithm` and `should_stop` are actually `async`. In such case, every call to `should_stop` would give control back to the JS loop, which will execute the received worker message telling it to change that `stop_order` global value and the next call to `should_stop` would actually terminate the algorithm.

But I think doing that (if possible, [which seems it is](https://rustwasm.github.io/docs/wasm-bindgen/reference/js-promises-and-rust-futures.html)) means I bring the whole `async` ecosystem to my crate, just because I need it in the WebAssembly port. Currently I have a workspace with `<mycrate>-lib`, `<mycrate>-bin` (a CLI app) and `<mycrate>-wasm` to use in the web app. The `algorithm` function lives in `<mycrate>-lib` and I'd like to avoid bringing the whole async ecosystem to it.

So I thought I could just gate this behind a feature, but then again I'm hitting an unknown. The `algoritm` function is roughly 200 lines and can't really get much shorter. I would hate having to duplicate this function to have another one (with some `if should_stop() { .. }` sprinkled) under a `cfg_attr` because it means the two will eventually get out of sync (pun intended ^^). Is there a simple way to do that in Rust without duplicating the function? I'm afraid not because the other function also must have a different signature starting with `async fn ...` right? (I've actually never used async in Rust yet)

## Is there a simpler way?

I'm getting quite far from my original goal of just being able to stop that wasm function? Is there a simpler way?

PS: here is the app in question in case interested: [https://lowrr.pizenberg.fr](https://lowrr.pizenberg.fr).

---

<div class="post-metadata">

**Author:** ![bjorn3](https://sea1.discourse-cdn.com/flex019/user_avatar/users.rust-lang.org/bjorn3/32/5255_2.png) [@bjorn3](https://users.rust-lang.org/u/bjorn3)\
**Post date:** [April 20, 2021, 4:03pm UTC](https://users.rust-lang.org/t/how-to-stop-a-wasm-function/58672/2 "2021-04-20T16:03:19Z")

</div>

There are only two options you have. Either you periodically check if you should stop with the function or you use a web worker and use the `.terminate()` method to stop the web worker. For periodic checking you don't have to duplicate the function. You can also use `#[cfg(target_arch = "wasm32")] { if should_stop () { ... } }`. Note that `#[cfg]` isn't allowed directly on `if`, but it is allowed on blocks.

---

<div class="post-metadata">

**Author:** ![mattpiz](https://sea1.discourse-cdn.com/flex019/user_avatar/users.rust-lang.org/mattpiz/32/8476_2.png) [@mattpiz](https://users.rust-lang.org/u/mattpiz)\
**Post date:** [April 20, 2021, 4:20pm UTC](https://users.rust-lang.org/t/how-to-stop-a-wasm-function/58672/3 "2021-04-20T16:20:07Z")

</div>

> [@bjorn3](#):
>
> Note that `#[cfg]` isn't allowed directly on `if` , but it is allowed on blocks.

That's good to know!

> [@bjorn3](#):
>
> use a web worker and use the `.terminate()`

That won't be usefull since in our case it means we loose the images data loaded into the wasm memory and it's roughly equivalent to just reload the page. So I guess periodic check it is!

> [@bjorn3](#):
>
> you don't have to duplicate the function

How about the fact that one function is `fn algorithm()` while the other is `async fn algorithm(should_stop ...)`. There needs to be two different functions right? Or is it something that can be solved with macro somehow? I've 0 experience with macros.

---

<div class="post-metadata">

**Author:** ![bjorn3](https://sea1.discourse-cdn.com/flex019/user_avatar/users.rust-lang.org/bjorn3/32/5255_2.png) [@bjorn3](https://users.rust-lang.org/u/bjorn3)\
**Post date:** [April 20, 2021, 4:27pm UTC](https://users.rust-lang.org/t/how-to-stop-a-wasm-function/58672/4 "2021-04-20T16:27:57Z")

</div>

> [@mattpiz](#):
>
> How about the fact that one function is `fn algorithm()` while the other is `async fn algorithm(should_stop ...)` . There needs to be two different functions right? Or is it something that can be solved with macro somehow? I've 0 experience with macros.

I think you could use a macro like

```rust
macro_rules! my_algorithm {
    ($arg1:expr, $arg2:expr, $maybe_stop:block) => {
        // part of the algorithm
        $maybe_stop
        // some other part
    }
}

```

And then invoked like `my_algorithm!(the_first_arg, the_second_arg, {})` on native and like `my_algorithm!(the_first_arg, the_second_arg, { if { should_stop() { return; } })` on wasm.

---

<div class="post-metadata">

**Author:** ![mattpiz](https://sea1.discourse-cdn.com/flex019/user_avatar/users.rust-lang.org/mattpiz/32/8476_2.png) [@mattpiz](https://users.rust-lang.org/u/mattpiz)\
**Post date:** [April 20, 2021, 5:32pm UTC](https://users.rust-lang.org/t/how-to-stop-a-wasm-function/58672/5 "2021-04-20T17:32:47Z")

</div>

I'll try to validate first the wasm-bindgen async approach with duplicated code and once that ok I'll try the macro as you suggest and let you know how things go. Thanks!

---

<div class="post-metadata">

**Author:** ![mejrs](https://sea1.discourse-cdn.com/flex019/user_avatar/users.rust-lang.org/mejrs/32/26585_2.png) [@mejrs](https://users.rust-lang.org/u/mejrs)\
**Post date:** [April 21, 2021, 12:33pm UTC](https://users.rust-lang.org/t/how-to-stop-a-wasm-function/58672/6 "2021-04-21T12:33:41Z")

</div>

> I'd like to avoid bringing the whole async ecosystem to it.

Having written async webassembly, the only real pain is potentially having to do a global refactor to make everything async. If you expose only async rust functions to javascript you can simply await those on the javascript side. There is no need to choose an async executor.

> Since JS is monothreaded, I can't change that value until the algorithm finishes running

Try a [SharedArrayBuffer](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/SharedArrayBuffer) here. These can be shared between main and (multiple) webworkers.

People have written hacks (using SharedArrayBuffer) to write libraries enabling multithreaded wasm. Perhaps one of these is useful for you.

---

<div class="post-metadata">

**Author:** ![mattpiz](https://sea1.discourse-cdn.com/flex019/user_avatar/users.rust-lang.org/mattpiz/32/8476_2.png) [@mattpiz](https://users.rust-lang.org/u/mattpiz)\
**Post date:** [April 21, 2021, 1:08pm UTC](https://users.rust-lang.org/t/how-to-stop-a-wasm-function/58672/7 "2021-04-21T13:08:59Z")

</div>

> [@mejrs](#):
>
> Try a [SharedArrayBuffer](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/SharedArrayBuffer) here.

Yeah I'd totally have gone that way if I didn't want to support Safari 🙂

> [@mejrs](#):
>
> If you expose only async rust functions to javascript you can simply await those on the javascript side. There is no need to choose an async executor.

I'll try that! I haven't got the time yet but will try later today.

---

<div class="post-metadata">

**Author:** ![jonh](https://avatars.discourse-cdn.com/v4/letter/j/dec6dc/32.png) [@jonh](https://users.rust-lang.org/u/jonh)\
**Post date:** [April 21, 2021, 2:08pm UTC](https://users.rust-lang.org/t/how-to-stop-a-wasm-function/58672/8 "2021-04-21T14:08:38Z")

</div>

`setTimeout` is the classic way to yield to the event loop.

---

<div class="post-metadata">

**Author:** ![Michael-F-Bryan](https://sea1.discourse-cdn.com/flex019/user_avatar/users.rust-lang.org/michael-f-bryan/32/28749_2.png) [@Michael-F-Bryan](https://users.rust-lang.org/u/Michael-F-Bryan)\
**Post date:** [April 21, 2021, 7:35pm UTC](https://users.rust-lang.org/t/how-to-stop-a-wasm-function/58672/9 "2021-04-21T19:35:16Z")

</div>

If you don't want to pull async into your WebAssembly, one option is to turn the loop inside out.

So instead of this:

```rust
fn algorithm(should_stop: &mut dyn FnMut() -> bool) {
    loop {
        if should_stop() { return; }
        ...
    }
}

```

You would break `algorithm()` into small chunks and write something like this:

```rust
fn poll_algorithm(state: &mut AlgorithmState) {
  // do a little bit of computation
}

```

Then as part of your web worker you might use `setTiimeout()` to poll the algorithm and re-schedule it to be polled again asap.

```nohighlight
import { AlgorithmState, poll_algorithm } from "./wasm";

let keepGoing = true;
const state = new AlgorithmState();

const action = () => {
  if (keepGoing) {
    setTimeout(action, 0);
    poll_algorithm(state);
  }
};

setTimeout(action, 0);

```

If you squint a little you'll see this is effectively like writing your own `Future` by hand.

In the normal desktop version you'd then create a wrapper function that calls your `poll_algorithm()` function to completion.

---

<div class="post-metadata">

**Author:** ![mattpiz](https://sea1.discourse-cdn.com/flex019/user_avatar/users.rust-lang.org/mattpiz/32/8476_2.png) [@mattpiz](https://users.rust-lang.org/u/mattpiz)\
**Post date:** [April 21, 2021, 8:36pm UTC](https://users.rust-lang.org/t/how-to-stop-a-wasm-function/58672/10 "2021-04-21T20:36:08Z")

</div>

> [@Michael-F-Bryan](#):
>
> If you squint a little you'll see this is effectively like writing your own `Future` by hand

Thanks for the insight, it's interesting to see it that way. Unfortunately breaking the algorithm into small pieces really isn't practical because of it's complexity. But the good news is I've managed to do the async change 🙂 It was far from trivial though since I am not used to all the things you have to know when dealing with `async` functions and wasm bindgen such as [this](https://github.com/rustwasm/wasm-bindgen/issues/1858) or [that](https://github.com/rustwasm/wasm-bindgen/issues/2195).

The approach I took to make it work was to have a newtype wrapper for an `Rc<RefCell<...>>`. It looks like this:

```rust
// src/lib.rs

use wasm_bindgen::prelude::*;
// some other imports

#[wasm_bindgen(raw_module = "../worker.mjs")]
extern "C" {
    #[wasm_bindgen(js_name = "shouldStop")]
    async fn should_stop() -> JsValue; // bool
}

async fn should_stop_bool() -> bool {
    let js_bool = should_stop().await;
    js_bool.as_bool().unwrap()
}

// This wrapper trick is because we cannot have async functions referencing &self.
// https://github.com/rustwasm/wasm-bindgen/issues/1858
#[wasm_bindgen]
pub struct Handler(Rc<RefCell<InnerHandler>>);

#[wasm_bindgen]
impl Handler {
    pub fn init() -> Self {
        Handler(Rc::new(RefCell::new(InnerHandler::init())))
    }
    pub fn immutable_call(&self) -> Result<JsValue, JsValue> {
        self.0.borrow().immutable_call()
    }
    pub fn mutable_call(&mut self) -> Result<(), JsValue> {
        let inner = Rc::clone(&self.0);
        let result = (*inner).borrow_mut().mutable_call(); // split in two lines needed
        result
    }
    pub fn mutable_async_call(&mut self) -> js_sys::Promise {
        let inner = Rc::clone(&self.0);
        wasm_bindgen_futures::future_to_promise(async_rc(inner))
    }
}

// Intermediate function between the async method in InnerHandler
// and the exported method that returns a promise in Handler.
async fn async_rc(mutself: Rc<RefCell<InnerHandler>>) -> Result<JsValue, JsValue> {
    let mut inner = (*mutself).borrow_mut();
    let result = inner.mutable_async_call();
    result.await
}

// Struct that initially was Handler but is now wrapped in an Rc<RefCell<>>
// the Handler new type.
struct InnerHandler { ... }

impl InnerHandler {
    fn init() -> Self { ... } // unchanged
    fn immutable_call(&self) -> Result<JsValue, JsValue> { ... } // unchanged
    fn mutable_call(&mut self) -> Result<(), JsValue> { ... } // unchanged

    // The function turned async and calling should_stop() inside our algorithm
    async fn mutable_async_call(&mut self) -> Result<JsValue, JsValue> {
        ...
        let result = algorithm_async(..., should_stop_bool).await;
        ...
    }
}

```

With in the JS code the following bits:

```js
// worker.mjs

// Function regularly called in the algorithm to check if it should stop.
export async function shouldStop() {
  await sleep(0); // Force to give control back.
  return stopOrder; // Global variable in the worker being set via worker messages
}

// Small utility function.
function sleep(ms) {
  return new Promise((resolve) => setTimeout(resolve, ms));
}

```

For the time being, to check that it works (and it does!) I have duplicated `algorithm` and `algorithm_async` functions like so:

```rust
pub fn algorithm() -> ... { ... }
pub async fn algorithm_async<FB: Future<Output = bool>>(
    should_stop: fn() -> FB
) -> ... { ... }

```

Now the only thing left is to dedup those two functions with some macro magic 🙂

---

<div class="post-metadata">

**Author:** ![Michael-F-Bryan](https://sea1.discourse-cdn.com/flex019/user_avatar/users.rust-lang.org/michael-f-bryan/32/28749_2.png) [@Michael-F-Bryan](https://users.rust-lang.org/u/Michael-F-Bryan)\
**Post date:** [April 21, 2021, 8:52pm UTC](https://users.rust-lang.org/t/how-to-stop-a-wasm-function/58672/11 "2021-04-21T20:52:00Z")

</div>

> [@mattpiz](#):
>
> Unfortunately breaking the algorithm into small pieces really isn't practical because of it's complexity. But the good news is I've managed to do the async change

Awesome!

> [@mattpiz](#):
>
> Now the only thing left is to dedup those to functions with some macro magic

I'd try to avoid this if possible.

If the algorithm has any amount of size or complexity you'll take a massive hit in readability and maintainability because you've got the normal logic intermingled with "meta-logic" (i.e. abstracting over async-ness). You see C codebases make this mistake with `#if` all the time, typically to hack a particular feature in, and it makes the resulting code quite hard to follow.

Instead, what about using [`futures::executor::block_on()`](https://docs.rs/futures/0.3.14/futures/executor/fn.block_on.html) to create a synchronous function which wraps your async version and polls it to completion? If you pass `should_stop()` in using dependency injection and that is the only async function it calls (i.e. you aren't reading from a `TcpStream` which requires the `tokio` runtime) then you could probably get away with it.

```rust
pub async fn algorithm_async(should_stop: &dyn Fn() -> Future<Item=bool>) { ... }

pub fn algorithm() {
  let should_stop = || async { false };

  futures::executor::block_on(move || algorithm_async(&should_stop));
}

```

I'd also recommend reading [_What Color is your Function?_](https://journal.stuffwithstuff.com/2015/02/01/what-color-is-your-function/) which explains the incompatibilities between sync and async functions at a higher level.

---

<div class="post-metadata">

**Author:** ![mattpiz](https://sea1.discourse-cdn.com/flex019/user_avatar/users.rust-lang.org/mattpiz/32/8476_2.png) [@mattpiz](https://users.rust-lang.org/u/mattpiz)\
**Post date:** [April 21, 2021, 9:04pm UTC](https://users.rust-lang.org/t/how-to-stop-a-wasm-function/58672/12 "2021-04-21T21:04:41Z")

</div>

> [@Michael-F-Bryan](#):
>
> If you pass `should_stop()` in using dependency injection and that is the only async function it calls

That is indeed the case. I'll see how `block_on()` plays with my setup, thanks for that link!

> [@Michael-F-Bryan](#):
>
> I'd also recommend reading [_What Color is your Function?_](https://journal.stuffwithstuff.com/2015/02/01/what-color-is-your-function/) which explains the incompatibilities between sync and async functions at a higher level.

Looks like an interesting read! I like the blue-red analogy starting point. Will try to read it fully when I find time 🙂

---

<div class="post-metadata">

**Author:** ![mattpiz](https://sea1.discourse-cdn.com/flex019/user_avatar/users.rust-lang.org/mattpiz/32/8476_2.png) [@mattpiz](https://users.rust-lang.org/u/mattpiz)\
**Post date:** [April 22, 2021, 10:00am UTC](https://users.rust-lang.org/t/how-to-stop-a-wasm-function/58672/13 "2021-04-22T10:00:03Z")

</div>

Turns out the macro was very clean:

```rust
// Exact same content than previous algo_async
// except for the $(...)* expansion
// that enables calling the macro without should_stop for algo_sync
macro_rules! algo_macro {
    ($arg1: expr, $arg2: expr, $($should_stop: expr),*) => {{
        ...
        $(if $should_stop().await { return Err(...); })*
        ...
    }};
}

pub fn algo_sync(arg1: ..., arg2: ...) -> ... {
    algo_macro!(arg1, arg2,)
}

pub async fn algo_async(arg1: ..., arg2: ..., should_stop: ...) -> ... {
    algo_macro!(arg1, arg2, should_stop)
}

```

---

<div class="post-metadata">

**Author:** ![Michael-F-Bryan](https://sea1.discourse-cdn.com/flex019/user_avatar/users.rust-lang.org/michael-f-bryan/32/28749_2.png) [@Michael-F-Bryan](https://users.rust-lang.org/u/Michael-F-Bryan)\
**Post date:** [April 22, 2021, 4:22pm UTC](https://users.rust-lang.org/t/how-to-stop-a-wasm-function/58672/14 "2021-04-22T16:22:26Z")

</div>

> [@mattpiz](#):
>
> Turns out the macro was very clean

Oh nice!

I was honestly expecting it to be a mess. Especially if you are doing recursion or have multiple sub-functions which need to switch between sync or async.

---

<div class="post-metadata">

**Author:** ![system](https://sea1.discourse-cdn.com/flex019/user_avatar/users.rust-lang.org/system/32/51372_2.png) [@system](https://users.rust-lang.org/u/system)\
**Post date:** [July 21, 2021, 4:22pm UTC](https://users.rust-lang.org/t/how-to-stop-a-wasm-function/58672/15 "2021-07-21T16:22:28Z")

</div>

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.
