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