]> git.sesse.net Git - nageru/commitdiff
Fix a possible deadlock in CEF.
authorSteinar H. Gunderson <sgunderson@bigfoot.com>
Tue, 18 Jun 2019 20:47:08 +0000 (22:47 +0200)
committerSteinar H. Gunderson <sgunderson@bigfoot.com>
Tue, 18 Jun 2019 20:47:08 +0000 (22:47 +0200)
nageru/cef_capture.cpp
nageru/cef_capture.h
nageru/mixer.cpp

index 09c451fa2c7b6dff968f9b828e6c08f42a9d570b..952486158cdb67e19d604c6322af253d745b71ea 100644 (file)
@@ -97,8 +97,17 @@ void CEFCapture::resize(unsigned width, unsigned height)
        this->height = height;
 }
 
-void CEFCapture::request_new_frame()
+void CEFCapture::request_new_frame(bool ignore_if_locked)
 {
+       unique_lock<recursive_mutex> outer_lock(browser_mutex, defer_lock);
+       if (ignore_if_locked && !outer_lock.try_lock()) {
+               // If the caller is holding card_mutex, we need to abort here
+               // if we can't get browser_mutex, since otherwise, the UI thread
+               // might hold browser_mutex (blocking post_to_cef_ui_thread())
+               // and be waiting for card_mutex.
+               return;
+       }
+
        // By adding a delay, we make sure we don't get a new frame
        // delivered immediately (we probably already are on the UI thread),
        // where we couldn't really deal with it.
@@ -129,7 +138,7 @@ void CEFCapture::OnPaint(const void *buffer, int width, int height)
                // (CEF only sends OnPaint when there are actual changes,
                // so we need to do this explicitly, or we could be stuck on an
                // old frame forever if the image doesn't change.)
-               request_new_frame();
+               request_new_frame(/*ignore_if_locked=*/false);
                ++timecode;
        } else {
                assert(video_frame.size >= unsigned(width * height * 4));
index 2b4d1cb8441b45dca8bb618a5c4bacc48ef77c50..cc3c67c566517b85fbf0b961747ac371555f075e 100644 (file)
@@ -85,7 +85,7 @@ public:
        void set_max_fps(int max_fps);
        void execute_javascript_async(const std::string &js);
        void resize(unsigned width, unsigned height);
-       void request_new_frame();
+       void request_new_frame(bool ignore_if_locked);
 
        // Callbacks from NageruCEFClient.
        void OnPaint(const void *buffer, int width, int height);
index 91c82d4ca6378ffe20054429610ca0429f5070f0..c9f7ed78861b7bf3136c913038eff9c13a0254c5 100644 (file)
@@ -1270,7 +1270,7 @@ start:
                                // we dropped. (may_have_dropped_last_frame is set whenever we
                                // trim the queue completely away, and cleared when we actually
                                // get a new frame.)
-                               ((CEFCapture *)card->capture.get())->request_new_frame();
+                               ((CEFCapture *)card->capture.get())->request_new_frame(/*ignore_if_locked=*/true);
                        }
 #endif
                } else {