Stream: git-wasmtime

Topic: wasmtime / PR #13341 c-api: add wasmtime_call_future_poll...


view this post on Zulip Wasmtime GitHub notifications bot (May 12 2026 at 20:04):

pgrayy opened PR #13341 from pgrayy:upstream/poll-with-notify to bytecodealliance:main:

Closes #12991.

This PR adds two features to the C API for embedders integrating wasmtime with foreign async event loops (e.g. Python's asyncio):

wasmtime_call_future_poll_with_notify — like wasmtime_call_future_poll, but accepts a socket fd. A SocketWaker writes a byte to the socket when the future can make progress, allowing the host to sleep on the socket instead of busy-polling.

Config::async_allow_sync — permits synchronous calls on stores that have async host functions linked. Intended for embedders that manage sync/async dispatch themselves and know certain exports will never suspend.

These are the wasmtime-side changes needed for wasmtime-py async support. A corresponding wasmtime-py PR is in development.

Testing

view this post on Zulip Wasmtime GitHub notifications bot (May 12 2026 at 20:07):

pgrayy edited PR #13341:

Closes #12991.

This PR adds two features to the C API for embedders integrating wasmtime with foreign async event loops (e.g. Python's asyncio):

wasmtime_call_future_poll_with_notify — like wasmtime_call_future_poll, but accepts a socket fd. A SocketWaker writes a byte to the socket when the future can make progress, allowing the host to sleep on the socket instead of busy-polling.

Config::async_allow_sync — permits synchronous calls on stores that have async host functions linked. Intended for embedders that manage sync/async dispatch themselves and know certain exports will never suspend.

These are the wasmtime-side changes needed for wasmtime-py async support. A corresponding wasmtime-py PR is in development.

Motivation

We are building Python bindings (wasmtime-py) that call WASM component functions using asyncio. The component uses wasi:http backed by wasmtime's internal Tokio runtime. Today, wasmtime_call_future_poll uses Waker::noop(), so the only way to know when to re-poll is busy-polling with asyncio.sleep(0). This wastes CPU and adds latency.

With poll_with_notify, Python creates a socket pair, passes the write fd to wasmtime, and awaits readability on the read end via loop.sock_recv(). When Tokio completes background I/O and wakes the future, the SocketWaker writes a byte, waking Python's event loop. Zero CPU while waiting, sub-millisecond wakeup latency.

The same embedder also needs to call pure-compute exports (e.g. greet, add) synchronously for simplicity, while using call_async for I/O-bound exports. Since linking WASI async bindings sets async_required on the store, sync calls are rejected by default. Config::async_allow_sync opts the embedder into managing this themselves.

Design decisions

Testing

view this post on Zulip Wasmtime GitHub notifications bot (May 12 2026 at 20:09):

pgrayy edited PR #13341:

Closes #12991.

This PR adds two features to the C API for embedders integrating wasmtime with foreign async event loops (e.g. Python's asyncio):

wasmtime_call_future_poll_with_notify — like wasmtime_call_future_poll, but accepts a socket fd. A SocketWaker writes a byte to the socket when the future can make progress, allowing the host to sleep on the socket instead of busy-polling.

Config::async_allow_sync — permits synchronous calls on stores that have async host functions linked. Intended for embedders that manage sync/async dispatch themselves and know certain exports will never suspend.

These are the wasmtime-side changes needed for wasmtime-py async support. A corresponding wasmtime-py PR is in development.

Motivation

We are building Python bindings (wasmtime-py) that call WASM component functions using asyncio. The component uses wasi:http backed by wasmtime's internal Tokio runtime. Today, wasmtime_call_future_poll uses Waker::noop(), so the only way to know when to re-poll is busy-polling with asyncio.sleep(0). This wastes CPU and adds latency.

With poll_with_notify, Python creates a socket pair, passes the write fd to wasmtime, and awaits readability on the read end via loop.sock_recv(). When Tokio completes background I/O and wakes the future, the SocketWaker writes a byte, waking Python's event loop.

The same embedder also needs to call pure-compute exports (e.g. greet, add) synchronously for simplicity, while using call_async for I/O-bound exports. Since linking WASI async bindings sets async_required on the store, sync calls are rejected by default. Config::async_allow_sync opts the embedder into managing this themselves.

Design decisions

Testing

view this post on Zulip Wasmtime GitHub notifications bot (May 12 2026 at 20:10):

pgrayy edited PR #13341:

Closes #12991.

This PR adds two features to the C API for embedders integrating wasmtime with foreign async event loops (e.g. Python's asyncio):

wasmtime_call_future_poll_with_notify — like wasmtime_call_future_poll, but accepts a socket fd. A SocketWaker writes a byte to the socket when the future can make progress, allowing the host to sleep on the socket instead of busy-polling.

Config::async_allow_sync — permits synchronous calls on stores that have async host functions linked. Intended for embedders that manage sync/async dispatch themselves and know certain exports will never suspend.

These are the wasmtime-side changes needed for wasmtime-py async support. A corresponding wasmtime-py PR is in development.

Motivation

We are building Python bindings (wasmtime-py) that call WASM component functions using asyncio. The component uses wasi:http backed by wasmtime's internal Tokio runtime. Today, wasmtime_call_future_poll uses Waker::noop(), so the only way to know when to re-poll is busy-polling with asyncio.sleep(0). This wastes CPU and adds latency.

With poll_with_notify, Python creates a socket pair, passes the write fd to wasmtime, and awaits readability on the read end via loop.sock_recv(). When Tokio completes background I/O and wakes the future, the SocketWaker writes a byte, waking Python's event loop.

For convenience, the same embedder also wants to call non-suspending exports synchronously (avoiding the overhead of setting up a socket pair and poll loop for functions that will complete immediately). Since linking WASI async bindings sets async_required on the store, sync calls are rejected by default. Config::async_allow_sync lets the embedder opt into managing sync/async dispatch themselves.

Design decisions

Testing

view this post on Zulip Wasmtime GitHub notifications bot (May 12 2026 at 20:11):

pgrayy edited PR #13341:

Closes #12991.

This PR adds two features to the C API for embedders integrating wasmtime with foreign async event loops (e.g. Python's asyncio):

wasmtime_call_future_poll_with_notify — like wasmtime_call_future_poll, but accepts a socket fd. A SocketWaker writes a byte to the socket when the future can make progress, allowing the host to sleep on the socket instead of busy-polling.

Config::async_allow_sync — permits synchronous calls on stores that have async host functions linked. Intended for embedders that manage sync/async dispatch themselves and know certain exports will never suspend.

These are the wasmtime-side changes needed for wasmtime-py async support. A corresponding wasmtime-py PR is in development.

Motivation

We are building Python bindings (wasmtime-py) that call WASM component functions using asyncio. The component uses wasi:http backed by wasmtime's internal Tokio runtime. Today, wasmtime_call_future_poll uses Waker::noop(), so the only way to know when to re-poll is busy-polling with asyncio.sleep(0). This wastes CPU and adds latency.

With poll_with_notify, Python creates a socket pair, passes the write fd to wasmtime, and awaits readability on the read end via loop.sock_recv(). When Tokio completes background I/O and wakes the future, the SocketWaker writes a byte, waking Python's event loop.

For convenience, the same embedder also wants to call non-suspending exports synchronously (avoiding the overhead of setting up a socket pair and poll loop for functions that will complete immediately). Since linking WASI async bindings sets async_required on the store, sync calls are rejected by default. Config::async_allow_sync lets the embedder opt into managing sync/async dispatch themselves.

Design decisions

Testing

view this post on Zulip Wasmtime GitHub notifications bot (May 12 2026 at 20:12):

pgrayy edited PR #13341:

Closes #12991.

This PR adds two features to the C API for embedders integrating wasmtime with foreign async event loops (e.g. Python's asyncio):

wasmtime_call_future_poll_with_notify — like wasmtime_call_future_poll, but accepts a socket fd. A SocketWaker writes a byte to the socket when the future can make progress, allowing the host to sleep on the socket instead of busy-polling.

Config::async_allow_sync — permits synchronous calls on stores that have async host functions linked. Intended for embedders that manage sync/async dispatch themselves and know certain exports will never suspend.

These are the wasmtime-side changes needed for wasmtime-py async support. A corresponding wasmtime-py PR is in development.

Motivation

We are building Python bindings (wasmtime-py) that call WASM component functions using asyncio. The component uses wasi:http backed by wasmtime's internal Tokio runtime. Today, wasmtime_call_future_poll uses Waker::noop(), so the only way to know when to re-poll is busy-polling with asyncio.sleep(0). This wastes CPU and adds latency.

With poll_with_notify, Python creates a socket pair, passes the write fd to wasmtime, and awaits readability on the read end via loop.sock_recv(). When Tokio completes background I/O and wakes the future, the SocketWaker writes a byte, waking Python's event loop.

For convenience, the same embedder also wants to call non-suspending exports synchronously (avoiding the overhead of setting up a socket pair and poll loop for functions that will complete immediately). Since linking WASI async bindings sets async_required on the store, sync calls are rejected by default. Config::async_allow_sync lets the embedder opt into managing sync/async dispatch themselves.

Design decisions

Testing

view this post on Zulip Wasmtime GitHub notifications bot (May 12 2026 at 20:14):

pgrayy updated PR #13341.

view this post on Zulip Wasmtime GitHub notifications bot (May 12 2026 at 20:57):

pgrayy updated PR #13341.

view this post on Zulip Wasmtime GitHub notifications bot (May 12 2026 at 21:00):

pgrayy updated PR #13341.

view this post on Zulip Wasmtime GitHub notifications bot (May 12 2026 at 21:08):

:cross_mark: pgrayy closed without merge PR #13341.


Last updated: Jun 01 2026 at 09:49 UTC