Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

sync-channels panicking #2406

Closed
ineiti opened this issue Dec 28, 2020 · 5 comments
Closed

sync-channels panicking #2406

ineiti opened this issue Dec 28, 2020 · 5 comments
Labels

Comments

@ineiti
Copy link

ineiti commented Dec 28, 2020

Describe the Bug

I'm trying to use std::sync::mpsc to synchronize between the js-world and the wasm-world. Unfortunately I always get the following panicks:

sync_channel_bg.js:215 panicked at 'condvar wait not supported', library/std/src/sys/wasm/../unsupported/condvar.rs:21:9
[...]
sync_channel_bg.js:215 panicked at 'cannot recursively acquire mutex', library/std/src/sys/wasm/../unsupported/mutex.rs:22:9
[...]

Steps to Reproduce

I created an example code at https://github.com/ineiti/sync-channel that shows the error. It is mostly the following code:

#[wasm_bindgen]
pub fn greet() -> Result<(), JsValue> {
    utils::set_panic_hook();
    
    let (s1, r1) = mpsc::sync_channel::<&str>(1);

    let settimeout_callback = Closure::wrap(Box::new(move || {
        log_1(&JsValue::from_str("settimeout_callback"));
        match s1.send("done") {
            Ok(_) => log_1(&JsValue::from_str("OK")),
            Err(e) => log_2(&JsValue::from_str("Error: "),
            &JsValue::from_str(e.to_string().as_str())),
        }
        log_1(&JsValue::from_str("settimeout_callback done"));
    }) as Box<dyn Fn()>);
    window().unwrap().set_timeout_with_callback_and_timeout_and_arguments_0(
        settimeout_callback.as_ref().unchecked_ref(), 1000)?;
    settimeout_callback.forget();
    match r1.recv(){
        Ok(s) => log_2(&JsValue::from_str("Got: "), &JsValue::from_str(s)),
        Err(e) => log_2(&JsValue::from_str("Error: "), &JsValue::from_str(e.to_string().as_str())),
    };

    Ok(())
}

I'm quite new to rust/wasm, so I probably copy/pasted the wrong examples together. But I tried different versions of this, and it always failed with the sync-channel failures.

Expected Behavior

The code should wait on the r1.recv() until the setTimeout sends the data through.

Actual Behavior

sync_channel_bg.js:215 panicked at 'condvar wait not supported', library/std/src/sys/wasm/../unsupported/condvar.rs:21:9
[...]
sync_channel_bg.js:215 panicked at 'cannot recursively acquire mutex', library/std/src/sys/wasm/../unsupported/mutex.rs:22:9
[...]
@ineiti ineiti added the bug label Dec 28, 2020
@chinedufn
Copy link
Contributor

chinedufn commented Dec 28, 2020

Hey

What you're seeing is expected. Condvar.wait() is not supported in Rust's stdlib when targeting wasm https://github.com/rust-lang/rust/blob/master/library/std/src/sys/unsupported/condvar.rs#L23

I think that that is blocked by rust-lang/rust#77839

In the meantime you can consider using threads https://rustwasm.github.io/docs/wasm-bindgen/examples/raytrace.html , if they work for your use case.

Cheers

@ineiti
Copy link
Author

ineiti commented Dec 28, 2020

I was afraid it would be expected, but still wanted to make sure there was not a simple trick to overcome it...

Thanks for the link to threads - there are some many warnings in that example that I don't want to go into this minefield.

Is there another channel library that could work? futures throws the same error.

@chinedufn
Copy link
Contributor

chinedufn commented Dec 28, 2020

Unfortunately none of my Rust work in the browser uses JS so I don't have any thoughts based on experience.

If all you're trying to do is do nothing until JS gives you a value you could try:

  1. Run your Rust in a rAF loop
  2. In the closure you send to JS push to an Arc<Mutex<Vec<T>>>
  3. Have your Rust side check this vector every frame until it has what you want.

Another alternative is https://rustwasm.github.io/docs/wasm-bindgen/reference/js-promises-and-rust-futures.html

Really depends on what you're trying to do.


Note that I haven't used either of the above approaches so YMMV

@ineiti
Copy link
Author

ineiti commented Dec 28, 2020

Thanks a lot for the pointers. I ended up polling the channel using Receiver<>.try_iter().next() and then call out to a setTimeout so JS has the time to actually fill in my channel. I hope I find a nicer method...

Shall I close this issue, or leave it open in the hope that this gets fixed sometimes?

@chinedufn
Copy link
Contributor

chinedufn commented Dec 29, 2020

Nice!

This is less of a wasm-bindgen issue and more of an issue of synchronization primitives in the wasm world at large are still a work in progress - so I'd say you can close this issue.

Good luck with your work

@ineiti ineiti closed this as completed Dec 29, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

2 participants