servo / servo

Servo, the embeddable, independent, memory-safe, modular, parallel web rendering engine
https://servo.org
Mozilla Public License 2.0
28.52k stars 3.04k forks source link

Webrender can end up blocked on the WebGL thread #22914

Open asajeffrey opened 5 years ago

asajeffrey commented 5 years ago

Servo depends on a blocks-on relation to avoid deadlocks caused by cycles in threads blcoking on each other, as documented at https://github.com/servo/servo/blob/cc8a9fa92823010d2134ee9daf997bcbc33de41b/components/constellation/constellation.rs#L70-L78

In particular, the compositor shouldn't end up blocking on canvas. This caused deadlock in trying to fix #22795, which (on macOS) means the VRDisplay has to render in the main thread, so the thread running the VR display has to block waiting on the main thread. Since presenting VR displays are run in the WebGL thread, this means adding canvas can block on compositor. This is fine as long as the compositor never blocks on canvas, but...

#0  pthread_cond_wait@@GLIBC_2.3.2 () at ../sysdeps/unix/sysv/linux/x86_64/pthread_cond_wait.S:185
#1  0x000055555ec218f3 in wait () at src/libstd/sys/unix/condvar.rs:70
#2  wait () at src/libstd/sys_common/condvar.rs:41
#3  wait<()> () at src/libstd/sync/condvar.rs:204
#4  park () at src/libstd/thread/mod.rs:908
#5  0x000055555ec2ceb2 in wait () at src/libstd/sync/mpsc/blocking.rs:71
#6  0x000055555b54a30e in <std::sync::mpsc::shared::Packet<T>>::recv (self=0x7fffef846370, deadline=...) at /rustc/da6ab956e1002517803ecd38b904504a1223274b/src/libstd/sync/mpsc/shared.rs:229
#7  0x000055555b6a9bec in <std::sync::mpsc::Receiver<T>>::recv (self=0x7fffef846288) at /rustc/da6ab956e1002517803ecd38b904504a1223274b/src/libstd/sync/mpsc/mod.rs:1209
#8  0x000055555b6c3c5c in <canvas_traits::webgl_channel::mpsc::WebGLReceiver<T>>::recv (self=0x7fffef846288) at /home/ajeffrey/github/asajeffrey/servo/components/canvas_traits/webgl_channel/mpsc.rs:48
#9  0x000055555b52aecf in <canvas_traits::webgl_channel::WebGLReceiver<T>>::recv (self=0x7fffef846280) at /home/ajeffrey/github/asajeffrey/servo/components/canvas_traits/webgl_channel/mod.rs:70
#10 0x000055555b4b8ea0 in <canvas::webgl_mode::inprocess::WebGLExternalImages as canvas::webgl_thread::WebGLExternalImageApi>::lock (self=0x7fffef846240, ctx_id=...) at components/canvas/webgl_mode/inprocess.rs:97
#11 0x000055555b56dca2 in <canvas::webgl_thread::WebGLExternalImageHandler<T> as webrender::renderer::ExternalImageHandler>::lock (self=0x7fffef846240, key=..., _channel_index=0, _rendering=webrender_api::display_item::ImageRendering::Auto) at components/canvas/webgl_thread.rs:759
#12 0x000055555bd6a935 in webrender::renderer::Renderer::update_deferred_resolves (self=0x7fffffffb998, deferred_resolves=&[webrender::prim_store::DeferredResolve](len: 1) = {...}) at /home/ajeffrey/.cargo/git/checkouts/webrender-c3596abe1cf4f320/2ff8da0/webrender/src/renderer.rs:3861
#13 0x000055555bd5ea40 in webrender::renderer::Renderer::prepare_gpu_cache (self=0x7fffffffb998, frame=0x7fffef831388) at /home/ajeffrey/.cargo/git/checkouts/webrender-c3596abe1cf4f320/2ff8da0/webrender/src/renderer.rs:2805
#14 0x000055555bd5da18 in webrender::renderer::Renderer::render_impl::{{closure}} () at /home/ajeffrey/.cargo/git/checkouts/webrender-c3596abe1cf4f320/2ff8da0/webrender/src/renderer.rs:2605
#15 0x000055555c02cea7 in webrender::profiler::TimeProfileCounter::profile (self=0x7fffffffa028, callback=...) at /home/ajeffrey/.cargo/git/checkouts/webrender-c3596abe1cf4f320/2ff8da0/webrender/src/profiler.rs:204
#16 0x000055555bd5c5ad in webrender::renderer::Renderer::render_impl (self=0x7fffffffb998, framebuffer_size=...) at /home/ajeffrey/.cargo/git/checkouts/webrender-c3596abe1cf4f320/2ff8da0/webrender/src/renderer.rs:2563
#17 0x000055555bd5c01b in webrender::renderer::Renderer::render (self=0x7fffffffb998, framebuffer_size=...) at /home/ajeffrey/.cargo/git/checkouts/webrender-c3596abe1cf4f320/2ff8da0/webrender/src/renderer.rs:2495
#18 0x00005555560bdaaa in <compositing::compositor::IOCompositor<Window>>::composite_specific_target::{{closure}} () at /home/ajeffrey/github/asajeffrey/servo/components/compositing/compositor.rs:1245
#19 0x0000555556040687 in profile_traits::time::profile (category=profile_traits::time::ProfilerCategory::Compositing, meta=..., profiler_chan=..., callback=...) at /home/ajeffrey/github/asajeffrey/servo/components/profile_traits/time.rs:142
#20 0x00005555560bbbb4 in <compositing::compositor::IOCompositor<Window>>::composite_specific_target (self=0x7fffffffb8d0, target=compositing::compositor::CompositeTarget::Window) at /home/ajeffrey/github/asajeffrey/servo/components/compositing/compositor.rs:1236
#21 0x00005555560c2501 in <compositing::compositor::IOCompositor<Window>>::composite (self=0x7fffffffb8d0) at /home/ajeffrey/github/asajeffrey/servo/components/compositing/compositor.rs:1165
#22 0x00005555560b45e5 in <compositing::compositor::IOCompositor<Window>>::perform_updates (self=0x7fffffffb8d0) at /home/ajeffrey/github/asajeffrey/servo/components/compositing/compositor.rs:1396
#23 0x00005555560e0330 in <servo::Servo<Window>>::handle_events (self=0x7fffffffb8d0, events=Vec<compositing::windowing::WindowEvent>(len: 3, cap: 4) = {...}) at /home/ajeffrey/github/asajeffrey/servo/components/servo/lib.rs:454
#24 0x000055555604031c in servo::main::{{closure}} () at ports/servo/non_android_main.rs:162
#25 0x0000555555ff9fae in servo::glutin_app::window::Window::run (self=0x7fffef83f010, servo_callback=...) at ports/servo/glutin_app/window.rs:356
#26 0x00005555560506f7 in servo::main () at ports/servo/non_android_main.rs:147

This stack shows that webrender locks each external image, which calls https://github.com/servo/servo/blob/cc8a9fa92823010d2134ee9daf997bcbc33de41b/components/canvas/webgl_mode/inprocess.rs#L91-L104

This blocks waiting on the WebGL thread, and so the compositor thread ends up blocking on the canvas thread. Oops.

asajeffrey commented 5 years ago

IRC chat with @jdm and @glennw: https://mozilla.logbot.info/servo/20190219#c15986149

asajeffrey commented 5 years ago

As a work-around, we can avoid blocking the WebGL thread on the main thread (which is probably better for throughput anyway). https://github.com/asajeffrey/servo/commit/497455a780c8ae51795eaf96eecf2100fb0496d9

asajeffrey commented 5 years ago

IRC monologue here: https://mozilla.logbot.info/servo/20190220#c15992836