(a request) emscripten port + threads

Hi, I see that currently SDL2 only builds without threads when building for emscripten/wasm.

Considering threads weren’t in the wasm MVP and support for the thread extension usually requires special deployment setups in browsers for security reasons, and because modules built without threads can’t be linked with modules built with threads, this is probably the right move for default build options.

But skimming through configure.ac I see that the option to enable threads isn’t even there. Emscripten implements pthreads so adding support for threads should be as trivial as adding the same pthreads check for the Emscripten build as exists for Linux/BSD/etc builds, except for only when it’s explicitly requested, plus adding -pthread to both the compiler and linker options.

On a related note emscripten also has atomics now, and the SDK provides functions for them, which should only be enabled along with pthreads because until recently the extension proposal prohibited atomics when not building with threads support (and really why would you use atomics if you can’t make threads?)

More on enabling pthreads with emcc: https://emscripten.org/docs/porting/pthreads.html
(s -PROXY_TO_PTHREAD might be a good idea too, but I’m not sure if libraries need this, or just the main application)

I’m really not familiar with autotools or shell scripting and can’t even seem to get autoconf to work on my Windows machine or I’d just write up the patch myself, but having an option to enable threads when building the Emscripten port seems like a reasonable request that should be easy to fulfill.

Threads (and atomics) are currently enabled, so long as you link SDL2 using the -s USE_SDL=2 switch rather than compiling from source. If you have a suitable browser (most desktop browsers now work, except IE and Safari) you can click on this link to run my BBC BASIC app, which is multithreaded and couldn’t work otherwise.

Nor me! Fortunately it’s all been done for us and it ‘just works’. :grinning:

Okay, thanks! I was just looking at what was in the repo. (looks like your app doesn’t work with Chrome on Android though, got an exception but don’t know how to pull up the JS console. Will try it on a PC next time I’m coding)

Chrome on Android doesn’t enable WASM threads by default, but you can enable them manually. Enter chrome://flags#enable-webassembly-threads and select Enabled.

Cool, thanks. But now your app is saying it couldn’t allocate memory. Is this another flag I gotta tweak or does your app allocate just a lot of memory (my phone is a moto G6, I usually have at least 1GB of RAM available)?
(EDIT: Just tested on chrome on my workstation, no memory allocation error, uses <100mb from the looks of things, and seems to work fine.)

It runs OK here in Chrome on Android; have you tried force-closing Chrome and opening it again? The very fact that WASM threads are still considered ‘experimental’ on Android probably means one should not be surprised if there are glitches.

You should have no problems on a desktop, I’ve tested it with Brave, Chrome, Edge, Firefox, Opera and Vivaldi browsers. It runs slightly faster and smoother on Firefox than the rest (which are all based on Chrome).

(This is my understanding, having just messed with this over the weekend.)

Chrome has SharedArrayBuffers enabled by default; Firefox has them behind an option for now.

To add to the frustration, they’re about to change this to require magic headers for CORS or whatever to be set or SharedArrayBuffers won’t be available.

And: you can’t have a single build support threads and not-threads, so you need to make a decision in JavaScript and then load the correct .wasm.

In short: WebAssembly threading is still a mess in current times.

But this mostly works out of the box with SDL already, when it works.

No, that’s not correct: (desktop) Firefox has support for threads enabled by default. You only need to try my app on off-the-shelf Firefox to demonstrate that (and as I mentioned it actually works better on Firefox than the rest).

Chrome on Android and Firefox require COOP and COEP headers now, other browsers are likely to introduce that security requirement at some point. It’s not a major inconvenience so long as you have control over the host.

I was pleasantly surprised by how straightforward it all was, basically it ‘just worked’ for me. Apart from the changes to the main loop always required for Emscripten / WebAssembly (even single-threaded), and enabling the necessary COOP and COEP headers, porting my multithreaded app to WASM was much easier than I feared.

The one unexpected surprise was that SDL2’s events mechanism is not thread-safe. I’d never noticed any problems on native platforms, but in WASM I had to protect all calls to SDL_PushEvent(), SDL_PeepEvents() etc. with a mutex. That ended up being messy in the case of some ‘internal’ SDL events which I could only protect using SDL_SetEventFilter(). If consideration could be given to making events thread-safe in a future version that would make life easier.

Everything icculus is saying matches what I had read when I was looking into the practicality of making a patch myself.

IIRC Firefox should also require a HTTPS connection with a valid certificate if not on localhost

Some WASI runtimes lack the pthreads as well.

The state of threads in emscripten do indeed seem burdensome. Keeping threads out of the default build is probably wise.

Also what I’ve read seems to indicate that one can pass -s PROXY_TO_PTHREAD when linking to avoid refactoring the main loop. Not sure if this would impact SDL rendering though (both updates to the canvas element for the software rasterizer and webgl calls probably need to be proxied back to the browser thread)

True, but increasingly HTTPS is required anyway (it would be great if SDL2_net could support it on a cross-platform basis).

I’ve tried it, but it completely breaks my app (possibly because I make direct calls to WebGL); it’s not a panacea.