summaryrefslogtreecommitdiff
path: root/freedreno/freedreno_device.c
diff options
context:
space:
mode:
authorRob Clark <robclark@freedesktop.org>2013-05-15 13:18:02 -0400
committerRob Clark <robclark@freedesktop.org>2013-05-15 15:34:15 -0400
commit0b89e2730c41466e8d9c04c469679ba23d052ec9 (patch)
tree723d251c1394c596b8fbce9ce4c4ec9bfdd402d8 /freedreno/freedreno_device.c
parent63aeae123848d0bfbc0a35102cb9717cf496eab6 (diff)
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 <robclark@freedesktop.org>
Diffstat (limited to 'freedreno/freedreno_device.c')
-rw-r--r--freedreno/freedreno_device.c61
1 files changed, 59 insertions, 2 deletions
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 <robclark@freedesktop.org>
*/
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+
#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);
}
-