wasm-micro-runtime icon indicating copy to clipboard operation
wasm-micro-runtime copied to clipboard

Properly killing native apps from the host side

Open kr-t opened this issue 4 months ago • 5 comments

Context

I've been working on ocre-runtime, a project that runs WebAssembly (WASM) applications using wasm-micro-runtime. Ocre supports both Zephyr and Linux, and its core functionality involves creating, running, stopping, and restarting multiple WASM apps—including those designed to run indefinitely (e.g., blinky, echo-server).

The Issue

After introducing networking, we noticed that resources aren't being cleaned up properly—even though we're calling the recommended cleanup functions from the C/C++ Embed Guide.

What's Different

Unlike the guide, we spawn a separate thread for each WASM app. When we destroy an app, we terminate its thread and invoke the cleanup routines. However, this approach doesn't fully release resources. If the app exits cleanly on its own, everything works fine. But if we kill the thread externally, cleanup fails—even when calling the appropriate functions.

Repro Steps

I've created a minimal demo repo: kr-t/embedding-wasm-simple

  • /sample_app contains the .wasm binary
  • main.c in the root runs the app twice
  • Use build.sh to compile first the WASM app, then the C app for Linux

Expected output:

**********************************************
Server is starting...
Server listening on port 8000

**********************************************
Server is starting...
Server listening on port 8000
bind: Address in use

The second run fails because the socket wasn't released properly.

What We've Tried

  • Creating a separate execution environment from host to native with a custom "shutdown" function that calls close(socket) and exit(0) — same result as killing the thread externally
  • Using fork() instead of threads works on Linux, but similar function isn't available not on Zephyr. Still, it demonstrates the behavior we want

Question

Is there a way to terminate WASM applications from the host side while ensuring all resources are properly cleaned up—so that restarting the same app doesn't cause unexpected behavior?

If not, is there a recommended workaround? We'd prefer not to require app developers to avoid blocking calls or implement custom signal handling, if possible.

Thanks for your time! Let me know if you need more details or have ideas for a solution.

kr-t avatar Aug 19 '25 13:08 kr-t

wamr is not cancellation safe. use wasm_runtime_terminate to terminate the instance instead.

yamt avatar Aug 25 '25 03:08 yamt

Hi @yamt , I have tested the suggested solution both on Linux and Zephyr:

  • On Linux it works fine - after terminating the instance via API above, it seems to be cleaning up the garbage and the next time I try binding to the same port - it binds and works.
  • On Zephyr it seems that it doesn't work the same way - I see no difference, and my address is still in use after the termination.

Do you have any suggestion, maybe config parameter of what I shall be doing differently on Zephyr compared to Linux, in order to achieve the same result? Thanks in advance!

kr-t avatar Aug 25 '25 08:08 kr-t

the underlying api (os_wakeup_blocking_op etc) is not implemented for all platforms. zephyr doesn't seem to have it.

yamt avatar Aug 25 '25 08:08 yamt

Thanks, I've checked the code, I see it now. I believe I got all my answers; if you think this functionality might be useful and we shall keep this issue open for somebody to implement it correctly, we can keep it. Otherwise I'm fine closing it.

kr-t avatar Aug 26 '25 05:08 kr-t

the tricky part is that it needs to somehow cancel host functions like WASI. for unix-like platforms it's implemented using signals as signals can interrupt most of blocking system calls there. as i'm not familiar with zephyr, i don't know what OS functionality there can be used for this purpose.

yamt avatar Aug 26 '25 06:08 yamt