From 0b89e2730c41466e8d9c04c469679ba23d052ec9 Mon Sep 17 00:00:00 2001 From: Rob Clark Date: Wed, 15 May 2013 13:18:02 -0400 Subject: freedreno: add handle and name tracking Due to the evil userspace buffer tracking we have to do, and hacks for creating GEM buffer from fbdev/scanout, "evil-twin" fd_bo objects are problematic. So introduce hashtable tracking of bo's and dev's, to avoid getting duplicate fd_bo ptrs for the same underlying gem object, in particular when importing via flink name. Signed-off-by: Rob Clark --- freedreno/freedreno_device.c | 61 ++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 59 insertions(+), 2 deletions(-) (limited to 'freedreno/freedreno_device.c') diff --git a/freedreno/freedreno_device.c b/freedreno/freedreno_device.c index 0a9ef9f2..901d0667 100644 --- a/freedreno/freedreno_device.c +++ b/freedreno/freedreno_device.c @@ -26,20 +26,77 @@ * Rob Clark */ +#include +#include +#include + #include "freedreno_drmif.h" #include "freedreno_priv.h" -struct fd_device * fd_device_new(int fd) +static pthread_mutex_t table_lock = PTHREAD_MUTEX_INITIALIZER; +static void * dev_table; + +static struct fd_device * fd_device_new_impl(int fd) { struct fd_device *dev = calloc(1, sizeof(*dev)); if (!dev) return NULL; + atomic_set(&dev->refcnt, 1); dev->fd = fd; + dev->handle_table = drmHashCreate(); + dev->name_table = drmHashCreate(); + return dev; +} + +/* use inode for key into dev_table, rather than fd, to avoid getting + * confused by multiple-opens: + */ +static int devkey(int fd) +{ + struct stat s; + if (fstat(fd, &s)) { + ERROR_MSG("stat failed: %s", strerror(errno)); + return -1; + } + return s.st_ino; +} + +struct fd_device * fd_device_new(int fd) +{ + struct fd_device *dev = NULL; + int key = devkey(fd); + + pthread_mutex_lock(&table_lock); + + if (!dev_table) + dev_table = drmHashCreate(); + + if (drmHashLookup(dev_table, key, (void **)&dev)) { + dev = fd_device_new_impl(fd); + drmHashInsert(dev_table, key, dev); + } else { + dev = fd_device_ref(dev); + } + + pthread_mutex_unlock(&table_lock); + + return dev; +} + +struct fd_device * fd_device_ref(struct fd_device *dev) +{ + atomic_inc(&dev->refcnt); return dev; } void fd_device_del(struct fd_device *dev) { + if (!atomic_dec_and_test(&dev->refcnt)) + return; + pthread_mutex_lock(&table_lock); + drmHashDestroy(dev->handle_table); + drmHashDestroy(dev->name_table); + drmHashDelete(dev_table, devkey(dev->fd)); + pthread_mutex_unlock(&table_lock); free(dev); } - -- cgit v1.2.3