Bug 1643149 [Wayland] Fix MozContainer deadlock, r=jhorak
authorMartin Stransky <stransky@redhat.com>
Thu, 04 Jun 2020 13:50:46 +0000
changeset 533896 827d6e47acfcd064aacd45c393ca2d5ff9242e18
parent 533895 3e654bf7a1e6d7a4fc4a3a0d4232cdc1f05f3cb2
child 533897 447cbc28fda3f04d5b322cee1a07f2c4e41bb88e
push id37480
push userncsoregi@mozilla.com
push dateThu, 04 Jun 2020 22:00:12 +0000
treeherdermozilla-central@e33aea19d0c5 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjhorak
bugs1643149
milestone79.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1643149 [Wayland] Fix MozContainer deadlock, r=jhorak Differential Revision: https://phabricator.services.mozilla.com/D78278
widget/gtk/MozContainerWayland.cpp
widget/gtk/MozContainerWayland.h
widget/gtk/WakeLockListener.cpp
widget/gtk/WaylandVsyncSource.cpp
widget/gtk/WindowSurfaceWayland.cpp
--- a/widget/gtk/MozContainerWayland.cpp
+++ b/widget/gtk/MozContainerWayland.cpp
@@ -440,20 +440,24 @@ struct wl_surface* moz_container_wayland
   struct wl_surface* surface =
       moz_container_wayland_get_surface_locked(container, waylandDisplay);
   if (surface == nullptr) {
     container->wl_container.container_lock->Unlock();
   }
   return surface;
 }
 
-void moz_container_wayland_surface_unlock(MozContainer* container) {
+void moz_container_wayland_surface_unlock(MozContainer* container,
+                                          struct wl_surface** surface) {
   LOGWAYLAND(("%s [%p] surface %p\n", __FUNCTION__, (void*)container,
               (void*)container->wl_container.surface));
-  container->wl_container.container_lock->Unlock();
+  if (*surface) {
+    container->wl_container.container_lock->Unlock();
+    *surface = nullptr;
+  }
 }
 
 struct wl_egl_window* moz_container_wayland_get_egl_window(
     MozContainer* container, int scale) {
   GdkDisplay* display = gtk_widget_get_display(GTK_WIDGET(container));
   nsWaylandDisplay* waylandDisplay = WaylandDisplayGet(display);
   MozContainerWayland* wl_container = &container->wl_container;
 
--- a/widget/gtk/MozContainerWayland.h
+++ b/widget/gtk/MozContainerWayland.h
@@ -54,17 +54,18 @@ struct _MozContainer;
 struct _MozContainerClass;
 typedef struct _MozContainer MozContainer;
 typedef struct _MozContainerClass MozContainerClass;
 
 void moz_container_wayland_class_init(MozContainerClass* klass);
 void moz_container_wayland_init(MozContainerWayland* container);
 
 struct wl_surface* moz_container_wayland_surface_lock(MozContainer* container);
-void moz_container_wayland_surface_unlock(MozContainer* container);
+void moz_container_wayland_surface_unlock(MozContainer* container,
+                                          struct wl_surface** surface);
 
 struct wl_egl_window* moz_container_wayland_get_egl_window(
     MozContainer* container, int scale);
 
 gboolean moz_container_wayland_has_egl_window(MozContainer* container);
 gboolean moz_container_wayland_surface_needs_clear(MozContainer* container);
 void moz_container_wayland_move_resize(MozContainer* container, int dx, int dy,
                                        int width, int height);
--- a/widget/gtk/WakeLockListener.cpp
+++ b/widget/gtk/WakeLockListener.cpp
@@ -250,20 +250,20 @@ bool WakeLockTopic::InhibitWaylandIdle()
   if (!focusedWindow) {
     return false;
   }
 
   UninhibitWaylandIdle();
 
   MozContainer* container = focusedWindow->GetMozContainer();
   wl_surface* waylandSurface = moz_container_wayland_surface_lock(container);
-  if (!waylandSurface) {
+  if (waylandSurface) {
     mWaylandInhibitor = zwp_idle_inhibit_manager_v1_create_inhibitor(
         waylandDisplay->GetIdleInhibitManager(), waylandSurface);
-    moz_container_wayland_surface_unlock(container);
+    moz_container_wayland_surface_unlock(container, &waylandSurface);
   }
   return true;
 }
 
 bool WakeLockTopic::UninhibitWaylandIdle() {
   if (mWaylandInhibitor == nullptr) return false;
 
   zwp_idle_inhibitor_v1_destroy(mWaylandInhibitor);
--- a/widget/gtk/WaylandVsyncSource.cpp
+++ b/widget/gtk/WaylandVsyncSource.cpp
@@ -131,17 +131,17 @@ void WaylandVsyncSource::WaylandDisplay:
     mCallbackContext = new WaylandFrameCallbackContext(this);
   }
 
   struct wl_callback* callback = wl_surface_frame(surface);
   wl_callback_add_listener(callback, &WaylandVsyncSourceCallbackListener,
                            mCallbackContext);
   wl_surface_commit(surface);
   wl_display_flush(mDisplay);
-  moz_container_wayland_surface_unlock(mContainer);
+  moz_container_wayland_surface_unlock(mContainer, &surface);
 }
 
 void WaylandVsyncSource::WaylandDisplay::FrameCallback() {
   {
     MutexAutoLock lock(mEnabledLock);
 
     if (!mVsyncEnabled || !mMonitorEnabled) {
       // We are unwanted by either our creator or our consumer, so we just stop
--- a/widget/gtk/WindowSurfaceWayland.cpp
+++ b/widget/gtk/WindowSurfaceWayland.cpp
@@ -1074,18 +1074,19 @@ void WindowSurfaceWayland::CommitWayland
           NewRunnableFunction("WaylandBackBufferCommit",
                               &WaylandBufferDelayCommitHandler,
                               mDelayedCommitHandle),
           EVENT_LOOP_DELAY);
     }
     return;
   }
 
-  auto unlockContainer =
-      MakeScopeExit([&] { moz_container_wayland_surface_unlock(container); });
+  auto unlockContainer = MakeScopeExit([&] {
+    moz_container_wayland_surface_unlock(container, &waylandSurface);
+  });
 
   wl_proxy_set_queue((struct wl_proxy*)waylandSurface,
                      mWaylandDisplay->GetEventQueue());
 
   // We have an active frame callback request so handle it.
   if (mFrameCallback) {
     if (waylandSurface == mLastCommittedSurface) {
       LOGWAYLAND(("    [%p] wait for frame callback.\n", (void*)this));
@@ -1120,16 +1121,19 @@ void WindowSurfaceWayland::CommitWayland
 
   mFrameCallback = wl_surface_frame(waylandSurface);
   wl_callback_add_listener(mFrameCallback, &frame_listener, this);
 
   mWaylandBuffer->Attach(waylandSurface);
   mLastCommittedSurface = waylandSurface;
   mLastCommitTime = g_get_monotonic_time() / 1000;
 
+  // Unlock surface now as SyncBegin()
+  moz_container_wayland_surface_unlock(container, &waylandSurface);
+
   // Ask wl_display to start events synchronization. We're going to wait
   // until all events are processed before next WindowSurfaceWayland::Lock()
   // as we hope for free wl_buffer there.
   mWaylandDisplay->SyncBegin();
 
   // There's no pending commit, all changes are sent to compositor.
   mBufferPendingCommit = false;
 }