e5347d4
changeset:   556172:143b4ca96ec9
e5347d4
tag:         tip
e5347d4
parent:      556169:61c35792ca70
e5347d4
user:        stransky <stransky@redhat.com>
e5347d4
date:        Mon Oct 26 12:15:49 2020 +0100
e5347d4
files:       widget/gtk/WindowSurfaceWayland.cpp widget/gtk/WindowSurfaceWayland.h
e5347d4
description:
e5347d4
Bug 1673313 [Wayland] Don't fail when Shm allocation fails, r?jhorak
e5347d4
e5347d4
- Make WaylandAllocateShmMemory() fallible.
e5347d4
- Implement WaylandReAllocateShmMemory() to re-allocate Shm pool.
e5347d4
- Remove WaylandShmPool::Resize() and use WaylandShmPool::Create() only.
e5347d4
- Implement and use WaylandShmPool::Release().
e5347d4
- Make WindowSurfaceWayland::CreateWaylandBuffer() as fallible.
e5347d4
e5347d4
Differential Revision: https://phabricator.services.mozilla.com/D94735
e5347d4
e5347d4
e5347d4
diff --git a/widget/gtk/WindowSurfaceWayland.cpp b/widget/gtk/WindowSurfaceWayland.cpp
e5347d4
--- a/widget/gtk/WindowSurfaceWayland.cpp
e5347d4
+++ b/widget/gtk/WindowSurfaceWayland.cpp
e5347d4
@@ -209,14 +209,23 @@ RefPtr<nsWaylandDisplay> WindowBackBuffe
e5347d4
 }
e5347d4
 
e5347d4
 static int WaylandAllocateShmMemory(int aSize) {
e5347d4
-  static int counter = 0;
e5347d4
-  nsPrintfCString shmName("/wayland.mozilla.ipc.%d", counter++);
e5347d4
-  int fd = shm_open(shmName.get(), O_CREAT | O_RDWR | O_EXCL, 0600);
e5347d4
-  if (fd >= 0) {
e5347d4
-    shm_unlink(shmName.get());
e5347d4
-  } else {
e5347d4
-    printf_stderr("Unable to SHM memory segment\n");
e5347d4
-    MOZ_CRASH();
e5347d4
+  int fd = -1;
e5347d4
+  do {
e5347d4
+    static int counter = 0;
e5347d4
+    nsPrintfCString shmName("/wayland.mozilla.ipc.%d", counter++);
e5347d4
+    fd = shm_open(shmName.get(), O_CREAT | O_RDWR | O_EXCL, 0600);
e5347d4
+    if (fd >= 0) {
e5347d4
+      // We don't want to use leaked file
e5347d4
+      if (shm_unlink(shmName.get()) != 0) {
e5347d4
+        NS_WARNING("shm_unlink failed");
e5347d4
+        return -1;
e5347d4
+      }
e5347d4
+    }
e5347d4
+  } while (fd < 0 && errno == EEXIST);
e5347d4
+
e5347d4
+  if (fd < 0) {
e5347d4
+    NS_WARNING(nsPrintfCString("shm_open failed: %s", strerror(errno)).get());
e5347d4
+    return -1;
e5347d4
   }
e5347d4
 
e5347d4
   int ret = 0;
e5347d4
@@ -225,59 +234,103 @@ static int WaylandAllocateShmMemory(int 
e5347d4
     ret = posix_fallocate(fd, 0, aSize);
e5347d4
   } while (ret == EINTR);
e5347d4
   if (ret != 0) {
e5347d4
+    NS_WARNING(
e5347d4
+        nsPrintfCString("posix_fallocate() fails to allocate shm memory: %s",
e5347d4
+                        strerror(ret))
e5347d4
+            .get());
e5347d4
     close(fd);
e5347d4
-    MOZ_CRASH("posix_fallocate() fails to allocate shm memory");
e5347d4
+    return -1;
e5347d4
   }
e5347d4
 #else
e5347d4
   do {
e5347d4
     ret = ftruncate(fd, aSize);
e5347d4
   } while (ret < 0 && errno == EINTR);
e5347d4
   if (ret < 0) {
e5347d4
+    NS_WARNING(nsPrintfCString("ftruncate() fails to allocate shm memory: %s",
e5347d4
+                               strerror(ret))
e5347d4
+                   .get());
e5347d4
     close(fd);
e5347d4
-    MOZ_CRASH("ftruncate() fails to allocate shm memory");
e5347d4
+    fd = -1;
e5347d4
   }
e5347d4
 #endif
e5347d4
 
e5347d4
   return fd;
e5347d4
 }
e5347d4
 
e5347d4
-WaylandShmPool::WaylandShmPool(RefPtr<nsWaylandDisplay> aWaylandDisplay,
e5347d4
-                               int aSize)
e5347d4
-    : mAllocatedSize(aSize) {
e5347d4
-  mShmPoolFd = WaylandAllocateShmMemory(mAllocatedSize);
e5347d4
-  mImageData = mmap(nullptr, mAllocatedSize, PROT_READ | PROT_WRITE, MAP_SHARED,
e5347d4
-                    mShmPoolFd, 0);
e5347d4
-  MOZ_RELEASE_ASSERT(mImageData != MAP_FAILED,
e5347d4
-                     "Unable to map drawing surface!");
e5347d4
+static bool WaylandReAllocateShmMemory(int aFd, int aSize) {
e5347d4
+  if (ftruncate(aFd, aSize) < 0) {
e5347d4
+    return false;
e5347d4
+  }
e5347d4
+#ifdef HAVE_POSIX_FALLOCATE
e5347d4
+  do {
e5347d4
+    errno = posix_fallocate(aFd, 0, aSize);
e5347d4
+  } while (errno == EINTR);
e5347d4
+  if (errno != 0) {
e5347d4
+    return false;
e5347d4
+  }
e5347d4
+#endif
e5347d4
+  return true;
e5347d4
+}
e5347d4
 
e5347d4
-  mShmPool =
e5347d4
-      wl_shm_create_pool(aWaylandDisplay->GetShm(), mShmPoolFd, mAllocatedSize);
e5347d4
+WaylandShmPool::WaylandShmPool()
e5347d4
+    : mShmPool(nullptr),
e5347d4
+      mShmPoolFd(-1),
e5347d4
+      mAllocatedSize(0),
e5347d4
+      mImageData(MAP_FAILED){};
e5347d4
 
e5347d4
-  // We set our queue to get mShmPool events at compositor thread.
e5347d4
-  wl_proxy_set_queue((struct wl_proxy*)mShmPool,
e5347d4
-                     aWaylandDisplay->GetEventQueue());
e5347d4
+void WaylandShmPool::Release() {
e5347d4
+  if (mImageData != MAP_FAILED) {
e5347d4
+    munmap(mImageData, mAllocatedSize);
e5347d4
+    mImageData = MAP_FAILED;
e5347d4
+  }
e5347d4
+  if (mShmPool) {
e5347d4
+    wl_shm_pool_destroy(mShmPool);
e5347d4
+    mShmPool = 0;
e5347d4
+  }
e5347d4
+  if (mShmPoolFd >= 0) {
e5347d4
+    close(mShmPoolFd);
e5347d4
+    mShmPoolFd = -1;
e5347d4
+  }
e5347d4
 }
e5347d4
 
e5347d4
-bool WaylandShmPool::Resize(int aSize) {
e5347d4
+bool WaylandShmPool::Create(RefPtr<nsWaylandDisplay> aWaylandDisplay,
e5347d4
+                            int aSize) {
e5347d4
   // We do size increase only
e5347d4
-  if (aSize <= mAllocatedSize) return true;
e5347d4
-
e5347d4
-  if (ftruncate(mShmPoolFd, aSize) < 0) return false;
e5347d4
+  if (aSize <= mAllocatedSize) {
e5347d4
+    return true;
e5347d4
+  }
e5347d4
 
e5347d4
-#ifdef HAVE_POSIX_FALLOCATE
e5347d4
-  do {
e5347d4
-    errno = posix_fallocate(mShmPoolFd, 0, aSize);
e5347d4
-  } while (errno == EINTR);
e5347d4
-  if (errno != 0) return false;
e5347d4
-#endif
e5347d4
+  if (mShmPoolFd < 0) {
e5347d4
+    mShmPoolFd = WaylandAllocateShmMemory(aSize);
e5347d4
+    if (mShmPoolFd < 0) {
e5347d4
+      return false;
e5347d4
+    }
e5347d4
+  } else {
e5347d4
+    if (!WaylandReAllocateShmMemory(mShmPoolFd, aSize)) {
e5347d4
+      Release();
e5347d4
+      return false;
e5347d4
+    }
e5347d4
+  }
e5347d4
 
e5347d4
-  wl_shm_pool_resize(mShmPool, aSize);
e5347d4
-
e5347d4
-  munmap(mImageData, mAllocatedSize);
e5347d4
-
e5347d4
+  if (mImageData != MAP_FAILED) {
e5347d4
+    munmap(mImageData, mAllocatedSize);
e5347d4
+  }
e5347d4
   mImageData =
e5347d4
       mmap(nullptr, aSize, PROT_READ | PROT_WRITE, MAP_SHARED, mShmPoolFd, 0);
e5347d4
-  if (mImageData == MAP_FAILED) return false;
e5347d4
+  if (mImageData == MAP_FAILED) {
e5347d4
+    NS_WARNING("Unable to map drawing surface!");
e5347d4
+    Release();
e5347d4
+    return false;
e5347d4
+  }
e5347d4
+
e5347d4
+  if (mShmPool) {
e5347d4
+    wl_shm_pool_resize(mShmPool, aSize);
e5347d4
+  } else {
e5347d4
+    mShmPool = wl_shm_create_pool(aWaylandDisplay->GetShm(), mShmPoolFd, aSize);
e5347d4
+    // We set our queue to get mShmPool events at compositor thread.
e5347d4
+    wl_proxy_set_queue((struct wl_proxy*)mShmPool,
e5347d4
+                       aWaylandDisplay->GetEventQueue());
e5347d4
+  }
e5347d4
 
e5347d4
   mAllocatedSize = aSize;
e5347d4
   return true;
e5347d4
@@ -289,11 +342,7 @@ void WaylandShmPool::SetImageDataFromPoo
e5347d4
   memcpy(mImageData, aSourcePool->GetImageData(), aImageDataSize);
e5347d4
 }
e5347d4
 
e5347d4
-WaylandShmPool::~WaylandShmPool() {
e5347d4
-  munmap(mImageData, mAllocatedSize);
e5347d4
-  wl_shm_pool_destroy(mShmPool);
e5347d4
-  close(mShmPoolFd);
e5347d4
-}
e5347d4
+WaylandShmPool::~WaylandShmPool() { Release(); }
e5347d4
 
e5347d4
 static void buffer_release(void* data, wl_buffer* buffer) {
e5347d4
   auto surface = reinterpret_cast<WindowBackBuffer*>(data);
e5347d4
@@ -302,14 +351,14 @@ static void buffer_release(void* data, w
e5347d4
 
e5347d4
 static const struct wl_buffer_listener buffer_listener = {buffer_release};
e5347d4
 
e5347d4
-void WindowBackBufferShm::Create(int aWidth, int aHeight) {
e5347d4
+bool WindowBackBufferShm::Create(int aWidth, int aHeight) {
e5347d4
   MOZ_ASSERT(!IsAttached(), "We can't create attached buffers.");
e5347d4
-  MOZ_ASSERT(!mWLBuffer, "there is wl_buffer already!");
e5347d4
 
e5347d4
-  int newBufferSize = aWidth * aHeight * BUFFER_BPP;
e5347d4
-  if (!mShmPool.Resize(newBufferSize)) {
e5347d4
-    mWLBuffer = nullptr;
e5347d4
-    return;
e5347d4
+  ReleaseShmSurface();
e5347d4
+
e5347d4
+  int size = aWidth * aHeight * BUFFER_BPP;
e5347d4
+  if (!mShmPool.Create(GetWaylandDisplay(), size)) {
e5347d4
+    return false;
e5347d4
   }
e5347d4
 
e5347d4
   mWLBuffer =
e5347d4
@@ -325,14 +374,16 @@ void WindowBackBufferShm::Create(int aWi
e5347d4
   LOGWAYLAND(("WindowBackBufferShm::Create [%p] wl_buffer %p ID %d\n",
e5347d4
               (void*)this, (void*)mWLBuffer,
e5347d4
               mWLBuffer ? wl_proxy_get_id((struct wl_proxy*)mWLBuffer) : -1));
e5347d4
+  return true;
e5347d4
 }
e5347d4
 
e5347d4
 void WindowBackBufferShm::ReleaseShmSurface() {
e5347d4
   LOGWAYLAND(("WindowBackBufferShm::Release [%p]\n", (void*)this));
e5347d4
-
e5347d4
-  wl_buffer_destroy(mWLBuffer);
e5347d4
+  if (mWLBuffer) {
e5347d4
+    wl_buffer_destroy(mWLBuffer);
e5347d4
+    mWLBuffer = nullptr;
e5347d4
+  }
e5347d4
   mWidth = mHeight = 0;
e5347d4
-  mWLBuffer = nullptr;
e5347d4
 }
e5347d4
 
e5347d4
 void WindowBackBufferShm::Clear() {
e5347d4
@@ -340,16 +391,13 @@ void WindowBackBufferShm::Clear() {
e5347d4
 }
e5347d4
 
e5347d4
 WindowBackBufferShm::WindowBackBufferShm(
e5347d4
-    WindowSurfaceWayland* aWindowSurfaceWayland, int aWidth, int aHeight)
e5347d4
+    WindowSurfaceWayland* aWindowSurfaceWayland)
e5347d4
     : WindowBackBuffer(aWindowSurfaceWayland),
e5347d4
-      mShmPool(aWindowSurfaceWayland->GetWaylandDisplay(),
e5347d4
-               aWidth * aHeight * BUFFER_BPP),
e5347d4
+      mShmPool(),
e5347d4
       mWLBuffer(nullptr),
e5347d4
-      mWidth(aWidth),
e5347d4
-      mHeight(aHeight),
e5347d4
-      mAttached(false) {
e5347d4
-  Create(aWidth, aHeight);
e5347d4
-}
e5347d4
+      mWidth(0),
e5347d4
+      mHeight(0),
e5347d4
+      mAttached(false) {}
e5347d4
 
e5347d4
 WindowBackBufferShm::~WindowBackBufferShm() { ReleaseShmSurface(); }
e5347d4
 
e5347d4
@@ -357,13 +405,9 @@ bool WindowBackBufferShm::Resize(int aWi
e5347d4
   if (aWidth == mWidth && aHeight == mHeight) {
e5347d4
     return true;
e5347d4
   }
e5347d4
-
e5347d4
   LOGWAYLAND(("WindowBackBufferShm::Resize [%p] %d %d\n", (void*)this, aWidth,
e5347d4
               aHeight));
e5347d4
-
e5347d4
-  ReleaseShmSurface();
e5347d4
   Create(aWidth, aHeight);
e5347d4
-
e5347d4
   return (mWLBuffer != nullptr);
e5347d4
 }
e5347d4
 
e5347d4
@@ -488,11 +532,13 @@ WindowBackBuffer* WindowSurfaceWayland::
e5347d4
     return nullptr;
e5347d4
   }
e5347d4
 
e5347d4
-  WindowBackBuffer* buffer = new WindowBackBufferShm(this, aWidth, aHeight);
e5347d4
-  if (buffer) {
e5347d4
-    mShmBackupBuffer[availableBuffer] = buffer;
e5347d4
+  WindowBackBuffer* buffer = new WindowBackBufferShm(this);
e5347d4
+  if (!buffer->Create(aWidth, aHeight)) {
e5347d4
+    delete buffer;
e5347d4
+    return nullptr;
e5347d4
   }
e5347d4
 
e5347d4
+  mShmBackupBuffer[availableBuffer] = buffer;
e5347d4
   return buffer;
e5347d4
 }
e5347d4
 
e5347d4
diff --git a/widget/gtk/WindowSurfaceWayland.h b/widget/gtk/WindowSurfaceWayland.h
e5347d4
--- a/widget/gtk/WindowSurfaceWayland.h
e5347d4
+++ b/widget/gtk/WindowSurfaceWayland.h
e5347d4
@@ -25,14 +25,14 @@ class WindowSurfaceWayland;
e5347d4
 // Allocates and owns shared memory for Wayland drawing surface
e5347d4
 class WaylandShmPool {
e5347d4
  public:
e5347d4
-  WaylandShmPool(RefPtr<nsWaylandDisplay> aDisplay, int aSize);
e5347d4
-  ~WaylandShmPool();
e5347d4
-
e5347d4
-  bool Resize(int aSize);
e5347d4
+  bool Create(RefPtr<nsWaylandDisplay> aWaylandDisplay, int aSize);
e5347d4
+  void Release();
e5347d4
   wl_shm_pool* GetShmPool() { return mShmPool; };
e5347d4
   void* GetImageData() { return mImageData; };
e5347d4
   void SetImageDataFromPool(class WaylandShmPool* aSourcePool,
e5347d4
                             int aImageDataSize);
e5347d4
+  WaylandShmPool();
e5347d4
+  ~WaylandShmPool();
e5347d4
 
e5347d4
  private:
e5347d4
   wl_shm_pool* mShmPool;
e5347d4
@@ -53,6 +53,7 @@ class WindowBackBuffer {
e5347d4
   virtual bool IsAttached() = 0;
e5347d4
 
e5347d4
   virtual void Clear() = 0;
e5347d4
+  virtual bool Create(int aWidth, int aHeight) = 0;
e5347d4
   virtual bool Resize(int aWidth, int aHeight) = 0;
e5347d4
 
e5347d4
   virtual int GetWidth() = 0;
e5347d4
@@ -87,8 +88,7 @@ class WindowBackBuffer {
e5347d4
 
e5347d4
 class WindowBackBufferShm : public WindowBackBuffer {
e5347d4
  public:
e5347d4
-  WindowBackBufferShm(WindowSurfaceWayland* aWindowSurfaceWayland, int aWidth,
e5347d4
-                      int aHeight);
e5347d4
+  WindowBackBufferShm(WindowSurfaceWayland* aWindowSurfaceWayland);
e5347d4
   ~WindowBackBufferShm();
e5347d4
 
e5347d4
   already_AddRefed<gfx::DrawTarget> Lock();
e5347d4
@@ -100,6 +100,7 @@ class WindowBackBufferShm : public Windo
e5347d4
   void SetAttached() { mAttached = true; };
e5347d4
 
e5347d4
   void Clear();
e5347d4
+  bool Create(int aWidth, int aHeight);
e5347d4
   bool Resize(int aWidth, int aHeight);
e5347d4
   bool SetImageDataFromBuffer(class WindowBackBuffer* aSourceBuffer);
e5347d4
 
e5347d4
@@ -109,7 +110,6 @@ class WindowBackBufferShm : public Windo
e5347d4
   wl_buffer* GetWlBuffer() { return mWLBuffer; };
e5347d4
 
e5347d4
  private:
e5347d4
-  void Create(int aWidth, int aHeight);
e5347d4
   void ReleaseShmSurface();
e5347d4
 
e5347d4
   // WaylandShmPool provides actual shared memory we draw into
e5347d4