asio icon indicating copy to clipboard operation
asio copied to clipboard

ASIO support for WebAssembly? Any ETA?

Open ghost opened this issue 4 years ago • 5 comments

@DragonOsman commented on Sep 29, 2018, 12:41 PM UTC:

Hi everyone.

I want to ask if there're any plans for and/or ETA for ASIO supporting WebAssembly. I have a web server application I wrote using sync server and client examples from the Beast library that I wanted to try porting to WebAssembly, but I was told at the Beast GitHub that ASIO doesn't WebAssembly.

I'll show my source code here for reference, in case someone wants to see it (I have it all on Gist): C++: https://gist.github.com/DragonOsman/d00ea7ec3d49c128ad7789293f156a09 CSS: https://gist.github.com/DragonOsman/3f3ba56ffd58476c6defaea95b066dc2 HTML: https://gist.github.com/DragonOsman/506bd2bae1dfe4c03a4bbe2a6d830324 JavaScript: https://gist.github.com/DragonOsman/c6e8fb15343544e662f474c5a526d1c2

The C++ code also declares two environment variables that are needed on the front-end side. It sends them over as needed.

This issue was moved by chriskohlhoff from boostorg/asio#151.

ghost avatar Dec 30 '20 00:12 ghost

@DragonOsman commented on Nov 20, 2018, 2:18 PM UTC:

Update: there's an official Emscripten port of ASIO. May need to verify version and see if it's the latest version. If it's not, then I want to know how to roll out my own ASIO port locally (I might propose for it to be included in the official port as well if it's good enough).

ghost avatar Dec 30 '20 00:12 ghost

Is it able to use ASIO with WebAssembly?

UniverseHan avatar Jan 13 '21 22:01 UniverseHan

@chriskohlhoff Any updates?

sergio-eld avatar Apr 16 '21 21:04 sergio-eld

@chriskohlhoff does this support co_await etc.?

unicomp21 avatar May 27 '21 11:05 unicomp21

I managed to get boost ASIO (boost version 1.82 installed as a system package on Fedora 41) working with multi-threaded web assembly with many c++23 (and prior) features. I putting it here as a reference for others.

Example code:

// File: asio_test.cpp

#include <boost/asio.hpp>
#include <boost/asio/experimental/promise.hpp>
#include <boost/asio/experimental/use_promise.hpp>
#include <boost/asio/deferred.hpp>
#include <print>
#include <thread>

namespace net = boost::asio;
using udp = net::ip::udp;
using udp_socket = net::deferred_t::as_default_on_t<udp::socket>;
using steady_timer = net::deferred_t::as_default_on_t<net::steady_timer>;

struct Instrumentation {
  Instrumentation() noexcept = default;
  
  ~Instrumentation() noexcept {
    std::println("Destroyed instrumentation class successfully!");
  }
};

auto side_task() -> net::awaitable<void> {
  Instrumentation const val{};
  auto ex = co_await net::this_coro::executor;
  steady_timer timer{ex};
  for(std::size_t i = 0;; i++) {
    std::println("Side task counter value: {}", i);
    using namespace std::literals::chrono_literals;
    timer.expires_after(1s);
    co_await timer.async_wait();
  }
}

auto run_main() -> net::awaitable<void> {
  auto ex = co_await net::this_coro::executor;
  auto prm = net::co_spawn(ex, side_task(), net::experimental::use_promise);
  std::println("Sleeping run_main()");
  using namespace std::literals::chrono_literals;
  steady_timer timer{ex, 5s};
  co_await timer.async_wait();
  std::println("Woked up run_main()");
  prm.cancel();
  std::println("Cancelled promise");
  std::println("Waiting before finishing...");
  timer.expires_after(5s);
  co_await timer.async_wait();
  std::println("Finishing run_main()");
}

auto main() -> int {
  net::io_context ioc(2);
  net::co_spawn(ioc, run_main(), net::detached);
  ioc.run(); // Not running the two threads simultaneously as it seems to have some issues (due to poor support for exceptions)
  std::thread thrd{[&ioc]{
    ioc.run();
  }};
  thrd.join();
}

Emscripten compile command (works with em++ version 4.0.5).

em++ -s USE_PTHREADS=1 -s WASM=1 -sPTHREAD_POOL_SIZE=2 -sPTHREAD_POOL_SIZE_STRICT=2 -s USE_BOOST_HEADERS=1 -sEXCEPTION_CATCHING_ALLOWED=yes -std=c++23 asio_test.cpp -o asio_test.html

You can serve the asio_test.html (and implicitly asio_test.js, asio_test.wasm) file(s) through a http server with the http headers (without this browsers will likely throw an error):

Cross-Origin-Embedder-Policy: require-corp
Cross-Origin-Opener-Policy: same-origin

Accessing asio_test.html using Zen browser 1.11.1 worked as expected (for the most part).

The limitations (if any) of this approach aren't clear and documentation is sparse. Some pitfalls to watch out for the console created by emscripten doesn't flush immediately so look into the javascript console of the browser. Also, there is an error about unhandled exception due to cancellation in the console (doesn't seem to affect behavior) not sure why this occurs (doesn't happen for non-webassembly builds). I believe it is due to the webassembly runtime not properly handling unhandled_exception() method of the coroutine's promise_type (happens when we make it single threaded). Blocking main thread causes some weird issues as well (won't be an issue for real code I believe). I will look into these later, most of these seem to be due to poor support for exceptions in general.

arun5309 avatar Apr 09 '25 10:04 arun5309