emilk / egui

egui: an easy-to-use immediate mode GUI in Rust that runs on both web and native
https://www.egui.rs/
Apache License 2.0
20.75k stars 1.5k forks source link

Firefox panic with parking_lot (Parking not supported on this platform) #4405

Open zdimension opened 2 months ago

zdimension commented 2 months ago

Similar to #1401. This issue is a series in my attempt to use request_repaint from Web Workers (previous one was #4368).

Describe the bug

When called from a Web Worker, Context::request_repaint calls Context::viewport_id which calls RawRwLock::lock_shared_slow which uses ThreadParker which doesn't seem to be supported on Firefox.

image

To Reproduce

Call request_repaint from a Web Worker on Firefox.

Workarounds

I just end up not calling request_repaint from a Web Worker and instead call request_repaint_after in my main thread with some fixed time like 1/60 s.

Desktop (please complete the following information):

white-axe commented 2 months ago

You need to enable the nightly feature of parking_lot

zdimension commented 2 months ago

You need to enable the nightly feature of parking_lot

Thanks, this fixed it (though, was this documented anywhere in egui?), though since the stdsimd feature was renamed to stdarch_wasm_atomic_wait, the latest crates.io release of parking_lot doesn't work as is, I had to manually patch parking_lot_core to use the Git repo which contains the fix:

[patch.crates-io]
# TODO: update this when parking_lot_core > 0.9.9 is released
# https://github.com/Amanieu/parking_lot/pull/435#issuecomment-2072218790
parking_lot_core = { git = "https://github.com/Amanieu/parking_lot" }

And, then run cargo update to fetch it of course.

This patch will be necessary until the next release of parking_lot_core.

Keeping this open since @emilk kept my other issue open as a reminder to add to docs or add the feature in eframe. Feel free to close it if it's not relevant

zdimension commented 2 months ago

@white-axe pinging you since you seem to have a lot of knowledge in the arcane bits of parking_lot, I'm having another issue with egui and threads that I'm having trouble to pinpoint the origin of: (same issue, triggered from multiple points randomly each time I refresh)

image

image

Seems like it's trying to lock the context data to access it, but if it's already locked by someone else (a thread in the middle of calling request_repaint, maybe?) then it just crashes since Atomics.wait can't be used to block the main thread.

(should I open another issue for this?)

white-axe commented 2 months ago

It's happening because your application clones an egui::Context from the main thread and sends it to the worker thread, and then sometimes calls .request_repaint() on the egui::Context from the worker thread. An egui::Context is actually a std::sync::Arc<parking_lot::RwLock<ContextImpl>> and calling .request_repaint() or any other operation on the context locks it, so your application probably did any operation on the main thread that requires the context at the exact same time the worker thread was in the middle of calling .request_repaint().

One easy way around this is to not send the context to the worker thread at all, and instead use an asynchronous task running on the main thread to listen for repaint requests from the worker thread.

For example, using tokio::sync::mpsc:

let (tx, mut rx) = tokio::sync::mpsc::unbounded_channel();
wasm_bindgen_futures::spawn_local(async move {
    loop {
        let Some(message) = rx.recv().await else {
            break;
        };
        do_something_with_message(message);
        ctx.request_repaint();
    }
});

Now send the tx to the worker thread, and whenever the worker thread wants to repaint it can call tx.send(message).

zdimension commented 2 months ago

Ah, thanks, I hadn't thought of using a local future for that. I replaced pretty much all my cross-thread request_repaint calls with that for my WASM build (still use request_repaint on desktop since it works) and it works flawlessly.