client: call func of tbm_surface after unlock mutex of queue_info 30/192130/5
authorChangyeon Lee <cyeon.lee@samsung.com>
Tue, 30 Oct 2018 10:43:20 +0000 (19:43 +0900)
committerChangyeon Lee <cyeon.lee@samsung.com>
Wed, 31 Oct 2018 02:49:17 +0000 (11:49 +0900)
if func of tbm_surfacef is called with lock mutex,
deadlock issue is caused when wayland-tbm function is called in
free callback of user_data.

Change-Id: I9cffccf0eb803aadd0ec61b559e20e85c6120344

src/wayland-tbm-client.c

index 115a995..6a34344 100644 (file)
@@ -846,6 +846,22 @@ wayland_tbm_client_get_bufmgr(struct wayland_tbm_client *tbm_client)
 }
 
 static void
+_wayland_tbm_client_queue_get_attach_bufs(struct wayland_tbm_surface_queue *queue_info,
+                                                               int unused, tbm_surface_h *surfaces, int *count)
+{
+       struct wayland_tbm_buffer *buffer, *tmp;
+
+       *count = 0;
+
+       wl_list_for_each_safe(buffer, tmp, &queue_info->attach_bufs, link) {
+               if (unused && buffer->allocated) continue;
+
+               surfaces[*count] = buffer->tbm_surface;
+               *count = *count + 1;
+       }
+}
+
+static void
 _wayland_tbm_client_queue_destroy_attach_bufs(struct wayland_tbm_surface_queue *queue_info)
 {
        struct wayland_tbm_buffer *buffer, *tmp;
@@ -866,7 +882,6 @@ _wayland_tbm_client_queue_destroy_attach_bufs(struct wayland_tbm_surface_queue *
                        }
                }
 
-               tbm_surface_internal_unref(buffer->tbm_surface);
                wl_list_remove(&buffer->link);
                free(buffer);
        }
@@ -899,7 +914,6 @@ _wayland_tbm_client_queue_destroy_unused_attach_bufs(struct wayland_tbm_surface_
                        }
                }
 
-               tbm_surface_internal_unref(buffer->tbm_surface);
                wl_list_remove(&buffer->link);
                free(buffer);
        }
@@ -1005,8 +1019,9 @@ __wayland_tbm_client_surface_alloc_cb(tbm_surface_queue_h surface_queue, void *d
 {
        struct wayland_tbm_surface_queue *queue_info =
                                (struct wayland_tbm_surface_queue *)data;
-       struct wayland_tbm_buffer *buffer;
        tbm_surface_h surface = NULL;
+       struct wayland_tbm_buffer *buffer;
+       int alloc = 0;
 
        pthread_mutex_lock(&queue_info->lock);
 
@@ -1016,38 +1031,36 @@ __wayland_tbm_client_surface_alloc_cb(tbm_surface_queue_h surface_queue, void *d
                                if (_wayland_tbm_client_is_valid_attach_bufs(queue_info, buffer)) {
                                        surface = buffer->tbm_surface;
                                        /* ref.. pair of __wayland_tbm_client_surface_free_cb */
-                                       tbm_surface_internal_ref(surface);
                                        buffer->allocated = 1;
-#ifdef DEBUG_TRACE
+
                                        WL_TBM_TRACE("   pid:%d wl_buffer:%p tbm_surface:%p ACTIVE", getpid(), buffer->wl_buffer, buffer->tbm_surface);
-#endif
+
                                } else {
-                                       surface = tbm_surface_internal_create_with_flags(queue_info->width,
-                                               queue_info->height,
-                                               queue_info->format,
-                                               queue_info->flag);
-#ifdef DEBUG_TRACE
-                                       WL_TBM_TRACE("   pid:%d tbm_surface:%p invalid attach_bufs fallback", getpid(), surface);
-#endif
+                                       alloc = 1;
                                }
 
                                break;
                        }
                }
        } else {
+               alloc = 1;
+       }
+
+       pthread_mutex_unlock(&queue_info->lock);
+
+       if (surface) {
+               /* ref.. pair of __wayland_tbm_client_surface_free_cb */
+               tbm_surface_internal_ref(surface);
+       } else if (!surface && alloc) {
                /* ref.. pair of __wayland_tbm_client_surface_free_cb */
                surface = tbm_surface_internal_create_with_flags(queue_info->width,
                                                        queue_info->height,
                                                        queue_info->format,
                                                        queue_info->flag);
 
-#ifdef DEBUG_TRACE
                WL_TBM_TRACE("   pid:%d tbm_surface:%p DEACTIVE", getpid(), surface);
-#endif
        }
 
-       pthread_mutex_unlock(&queue_info->lock);
-
        return surface;
 }
 
@@ -1061,6 +1074,7 @@ __wayland_tbm_client_surface_free_cb(tbm_surface_queue_h surface_queue, void *da
        struct wayland_tbm_surface_queue *queue_info =
                                (struct wayland_tbm_surface_queue *)data;
        struct wayland_tbm_buffer *buffer, *tmp;
+       int attached = 0;
 
        pthread_mutex_lock(&queue_info->lock);
 
@@ -1075,15 +1089,18 @@ __wayland_tbm_client_surface_free_cb(tbm_surface_queue_h surface_queue, void *da
                if (buffer->wl_buffer)
                        wl_tbm_queue_detach_buffer(queue_info->wl_tbm_queue, buffer->wl_buffer);
 
-               tbm_surface_internal_unref(buffer->tbm_surface);
+               attached = 1;
                wl_list_remove(&buffer->link);
                free(buffer);
        }
 
+       pthread_mutex_unlock(&queue_info->lock);
+
+       if (attached)
+               tbm_surface_internal_unref(surface);
+
        /* unref.. pair of __wayland_tbm_client_surface_alloc_cb */
        tbm_surface_internal_unref(surface);
-
-       pthread_mutex_unlock(&queue_info->lock);
 }
 
 static void
@@ -1175,10 +1192,14 @@ handle_tbm_queue_deactive(void *data,
 {
        struct wayland_tbm_surface_queue *queue_info =
                                (struct wayland_tbm_surface_queue *)data;
+       tbm_surface_queue_h tbm_queue = NULL;
+       tbm_surface_h *surfaces = NULL;
        int flush = 0;
        int need_flush = 0;
-       tbm_surface_queue_h tbm_queue = NULL;
        int queue_size = 0;
+       int count = 0;
+       int length = 0;
+       int i;
 
 #ifdef DEBUG_TRACE
        WL_TBM_TRACE("                  pid:%d", getpid());
@@ -1198,9 +1219,21 @@ handle_tbm_queue_deactive(void *data,
 
        if (queue_info->active_flush) {
                queue_info->active_flush = 0;
-               /* flush the attached surfaces */
-               _wayland_tbm_client_queue_destroy_unused_attach_bufs(queue_info, &flush);
-               need_flush = 1;
+
+               length = wl_list_length(&queue_info->attach_bufs);
+               if (length) {
+                       surfaces = (tbm_surface_h *)calloc(length, sizeof(tbm_surface_h));
+                       if (!surfaces) {
+                               WL_TBM_LOG_E("failed to alloc surfaces");
+                               pthread_mutex_unlock(&queue_info->lock);
+                               return;
+                       }
+
+                       _wayland_tbm_client_queue_get_attach_bufs(queue_info, 1, surfaces, &count);
+                       /* flush the attached surfaces */
+                       _wayland_tbm_client_queue_destroy_unused_attach_bufs(queue_info, &flush);
+                       need_flush = 1;
+               }
        }
 
        tbm_queue = queue_info->tbm_queue;
@@ -1208,6 +1241,13 @@ handle_tbm_queue_deactive(void *data,
 
        pthread_mutex_unlock(&queue_info->lock);
 
+       if (surfaces) {
+               for (i = 0; i < count; i++)
+                       tbm_surface_internal_unref(surfaces[i]);
+
+               free(surfaces);
+       }
+
        if (need_flush)
                tbm_surface_queue_set_size(tbm_queue, queue_size, flush);
 }
@@ -1321,14 +1361,29 @@ _handle_tbm_surface_queue_destroy_notify(tbm_surface_queue_h surface_queue,
 {
        struct wayland_tbm_surface_queue *queue_info =
                                (struct wayland_tbm_surface_queue *)data;
+       tbm_surface_h *surfaces = NULL;
+       int count = 0;
+       int length = 0;
+       int i;
 
 #ifdef DEBUG_TRACE
        WL_TBM_TRACE(" pid:%d", getpid());
 #endif
        pthread_mutex_lock(&queue_info->lock);
 
-       /* remove the attach_bufs int the queue_info */
-       _wayland_tbm_client_queue_destroy_attach_bufs(queue_info);
+       length = wl_list_length(&queue_info->attach_bufs);
+       if (length) {
+               surfaces = (tbm_surface_h *)calloc(length, sizeof(tbm_surface_h));
+               if (!surfaces) {
+                       WL_TBM_LOG_E("failed to alloc surfaces");
+                       pthread_mutex_unlock(&queue_info->lock);
+                       return;
+               }
+
+               _wayland_tbm_client_queue_get_attach_bufs(queue_info, 0, surfaces, &count);
+               /* remove the attach_bufs int the queue_info */
+               _wayland_tbm_client_queue_destroy_attach_bufs(queue_info);
+       }
 
        if (queue_info->wl_tbm_queue)
                wl_tbm_queue_destroy(queue_info->wl_tbm_queue);
@@ -1337,6 +1392,13 @@ _handle_tbm_surface_queue_destroy_notify(tbm_surface_queue_h surface_queue,
        pthread_mutex_unlock(&queue_info->lock);
        pthread_mutex_destroy(&queue_info->lock);
        free(queue_info);
+
+       if (surfaces) {
+               for (i = 0; i < count; i++)
+                       tbm_surface_internal_unref(surfaces[i]);
+
+               free(surfaces);
+       }
 }
 
 static void