From d6fe7b6165859e17f0308cd28ab0cd2e2e3db294 Mon Sep 17 00:00:00 2001
From: Paul Olav Tvete <paul.tvete@theqtcompany.com>
Date: Tue, 23 Feb 2016 13:28:10 +0100
Subject: [PATCH] Proper fix for buffer destruction

The previous fix (93ca929fb9caf347150) would always crash on client exit.
It tried use the same destroy_listener on several buffers. Due to the
way linked lists are implemented in Wayland, a listener can only
be listening to one signal at the time.

The correct way to do this is to create a new listener for each buffer.

Change-Id: Ie94dd8cd2d3dc7f93a0526c5c585a8feab3b7354
Reviewed-by: Pier Luigi Fiorini <pierluigi.fiorini@gmail.com>
Reviewed-by: Louai Al-Khanji <louai.al-khanji@theqtcompany.com>
---
 .../waylandeglclientbufferintegration.cpp       | 17 ++++++++++++-----
 1 file changed, 12 insertions(+), 5 deletions(-)

diff --git a/src/hardwareintegration/compositor/wayland-egl/waylandeglclientbufferintegration.cpp b/src/hardwareintegration/compositor/wayland-egl/waylandeglclientbufferintegration.cpp
index 63da3ea4..d573edfc 100644
--- a/src/hardwareintegration/compositor/wayland-egl/waylandeglclientbufferintegration.cpp
+++ b/src/hardwareintegration/compositor/wayland-egl/waylandeglclientbufferintegration.cpp
@@ -115,9 +115,6 @@ public:
         , gl_egl_image_target_texture_2d(0)
         , funcs(Q_NULLPTR)
     {
-        destroy_listener.d = this;
-        destroy_listener.listener.notify = destroy_listener_callback;
-        wl_list_init(&destroy_listener.listener.link);
     }
 
     static void destroy_listener_callback(wl_listener *listener, void *data) {
@@ -127,7 +124,10 @@ public:
         buffer_destroy_listener *destroy_listener = reinterpret_cast<buffer_destroy_listener *>(listener);
         WaylandEglClientBufferIntegrationPrivate *self = destroy_listener->d;
         struct ::wl_resource *buffer = static_cast<struct ::wl_resource *>(data);
+
         wl_list_remove(&listener->link);
+        delete listener;
+
         if (!self->buffers.contains(buffer))
             return;
 
@@ -143,11 +143,18 @@ public:
             self->funcs->destroy_stream(self->egl_display, state.egl_stream);
     }
 
+    void create_destroy_listener(struct ::wl_resource *buffer) {
+        buffer_destroy_listener *newListener = new buffer_destroy_listener;
+        newListener->d = this;
+        newListener->listener.notify = destroy_listener_callback;
+
+        wl_signal_add(&buffer->destroy_signal, &newListener->listener);
+    }
+
     EGLDisplay egl_display;
     bool valid;
     bool display_bound;
     QHash<struct ::wl_resource *, BufferState> buffers;
-    buffer_destroy_listener destroy_listener;
 
     PFNEGLBINDWAYLANDDISPLAYWL egl_bind_wayland_display;
     PFNEGLUNBINDWAYLANDDISPLAYWL egl_unbind_wayland_display;
@@ -257,7 +264,7 @@ void WaylandEglClientBufferIntegration::initializeBuffer(struct ::wl_resource *b
     if (!buffer || d->buffers.contains(buffer))
         return;
 
-    wl_signal_add(&buffer->destroy_signal, &d->destroy_listener.listener);
+    d->create_destroy_listener(buffer);
 }
 
 int WaylandEglClientBufferIntegration::textureTargetForBuffer(struct ::wl_resource *buffer) const
-- 
GitLab