OSDN Git Service

minigbm: Add userspace reference counting
authorGurchetan Singh <gurchetansingh@chromium.org>
Thu, 4 Aug 2016 00:14:55 +0000 (17:14 -0700)
committerchrome-bot <chrome-bot@chromium.org>
Thu, 18 Aug 2016 02:15:49 +0000 (19:15 -0700)
When a dmabuf is imported multiple times, further imports after the
first one are not refcounted, i.e. the first close() will lose the
dmabuf. To avoid this, user space needs to track the number of imports
and only close() the dmabuf once the last import is closed.

BUG=None
TEST=Ran graphics_Gbm on minnie.  Still passes.

Change-Id: Iba63556ccc94ac5d49be2f827ceead85e0e22c9c
Reviewed-on: https://chromium-review.googlesource.com/366041
Commit-Ready: Gurchetan Singh <gurchetansingh@chromium.org>
Tested-by: Gurchetan Singh <gurchetansingh@chromium.org>
Reviewed-by: Stéphane Marchesin <marcheu@chromium.org>
drv.c
drv_priv.h
helpers.c
helpers.h

diff --git a/drv.c b/drv.c
index 54d1d39..de5b87f 100644 (file)
--- a/drv.c
+++ b/drv.c
@@ -5,6 +5,7 @@
  */
 #include <assert.h>
 #include <fcntl.h>
+#include <pthread.h>
 #include <stdint.h>
 #include <stdio.h>
 #include <stdlib.h>
@@ -103,6 +104,17 @@ struct driver *drv_create(int fd)
                return NULL;
        }
 
+       if (pthread_mutex_init(&drv->table_lock, NULL)) {
+               free(drv);
+               return NULL;
+       }
+
+       drv->buffer_table = drmHashCreate();
+       if (!drv->buffer_table) {
+               free(drv);
+               return NULL;
+       }
+
        if (drv->backend->init) {
                ret = drv->backend->init(drv);
                if (ret) {
@@ -119,6 +131,9 @@ void drv_destroy(struct driver *drv)
        if (drv->backend->close)
                drv->backend->close(drv);
 
+       pthread_mutex_destroy(&drv->table_lock);
+       drmHashDestroy(drv->buffer_table);
+
        free(drv);
 }
 
@@ -182,6 +197,7 @@ struct bo *drv_bo_create(struct driver *drv, uint32_t width, uint32_t height,
                         drv_format_t format, uint64_t flags)
 {
        int ret;
+       size_t plane;
        struct bo *bo;
 
        bo = drv_bo_new(drv, width, height, format);
@@ -196,12 +212,35 @@ struct bo *drv_bo_create(struct driver *drv, uint32_t width, uint32_t height,
                return NULL;
        }
 
+       pthread_mutex_lock(&drv->table_lock);
+
+       for (plane = 0; plane < bo->num_planes; plane++)
+               drv_increment_reference_count(drv, bo, plane);
+
+       pthread_mutex_unlock(&drv->table_lock);
+
        return bo;
 }
 
 void drv_bo_destroy(struct bo *bo)
 {
-       bo->drv->backend->bo_destroy(bo);
+       size_t plane;
+       uintptr_t total = 0;
+       struct driver *drv = bo->drv;
+
+       pthread_mutex_lock(&drv->table_lock);
+
+       for (plane = 0; plane < bo->num_planes; plane++)
+               drv_decrement_reference_count(drv, bo, plane);
+
+       for (plane = 0; plane < bo->num_planes; plane++)
+               total += drv_get_reference_count(drv, bo, plane);
+
+       pthread_mutex_unlock(&drv->table_lock);
+
+       if (total == 0)
+               bo->drv->backend->bo_destroy(bo);
+
        free(bo);
 }
 
@@ -235,6 +274,10 @@ struct bo *drv_bo_import(struct driver *drv, struct drv_import_fd_data *data)
        bo->sizes[0] = data->height * data->stride;
        bo->handles[0].u32 = prime_handle.handle;
 
+       pthread_mutex_lock(&drv->table_lock);
+       drv_increment_reference_count(drv, bo, 0);
+       pthread_mutex_unlock(&drv->table_lock);
+
        return bo;
 }
 
index d49c9da..349d02e 100644 (file)
@@ -33,6 +33,8 @@ struct driver {
        int fd;
        struct backend *backend;
        void *priv;
+       void *buffer_table;
+       pthread_mutex_t table_lock;
 };
 
 struct backend
index 378b01f..ed7c0c8 100644 (file)
--- a/helpers.c
+++ b/helpers.c
@@ -224,3 +224,38 @@ int drv_gem_bo_destroy(struct bo *bo)
 
        return error;
 }
+
+uintptr_t drv_get_reference_count(struct driver *drv, struct bo *bo,
+                                 size_t plane)
+{
+       void *count;
+       uintptr_t num = 0;
+
+       if (!drmHashLookup(drv->buffer_table, bo->handles[plane].u32, &count))
+               num = (uintptr_t) (count);
+
+       return num;
+}
+
+void drv_increment_reference_count(struct driver *drv, struct bo *bo,
+                                  size_t plane)
+{
+       uintptr_t num = drv_get_reference_count(drv, bo, plane);
+
+       /* If a value isn't in the table, drmHashDelete is a no-op */
+       drmHashDelete(drv->buffer_table, bo->handles[plane].u32);
+       drmHashInsert(drv->buffer_table, bo->handles[plane].u32,
+                     (void *) (num + 1));
+}
+
+void drv_decrement_reference_count(struct driver *drv, struct bo *bo,
+                                  size_t plane)
+{
+       uintptr_t num = drv_get_reference_count(drv, bo, plane);
+
+       drmHashDelete(drv->buffer_table, bo->handles[plane].u32);
+
+       if (num > 0)
+               drmHashInsert(drv->buffer_table, bo->handles[plane].u32,
+                             (void *) (num - 1));
+}
index ecb49f3..de17f7f 100644 (file)
--- a/helpers.h
+++ b/helpers.h
@@ -16,5 +16,10 @@ int drv_dumb_bo_create(struct bo *bo, uint32_t width, uint32_t height,
                       uint32_t format, uint32_t flags);
 int drv_dumb_bo_destroy(struct bo *bo);
 int drv_gem_bo_destroy(struct bo *bo);
-
+uintptr_t drv_get_reference_count(struct driver *drv, struct bo *bo,
+                                 size_t plane);
+void drv_increment_reference_count(struct driver *drv, struct bo *bo,
+                                  size_t plane);
+void drv_decrement_reference_count(struct driver *drv, struct bo *bo,
+                                  size_t plane);
 #endif