summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRob Clark <robclark@freedesktop.org>2014-01-12 08:27:36 -0500
committerRob Clark <robclark@freedesktop.org>2014-01-12 09:00:51 -0500
commit8279c8fb498785ea2700c6cc4a3456d7e1134665 (patch)
tree3c18768a0b69bf294fd0bc3db5d59d3dbacdbc07
parentde0970203091618834e4753c14d5169770797800 (diff)
downloadlibdrm-8279c8fb498785ea2700c6cc4a3456d7e1134665.tar.gz
libdrm-8279c8fb498785ea2700c6cc4a3456d7e1134665.tar.bz2
libdrm-8279c8fb498785ea2700c6cc4a3456d7e1134665.zip
freedreno: add fd_device_new_dup()
There seem to be some cases (I've noticed this switching resolution in some games, for example) where the fd can get closed() before the device and all it's bo's are destroyed. Which, if the drm device is opened again and bo's are allocated with the same handles, results that when the first pipe_screen/pipe_context is destroyed causes the first dev to close handles for bo's allocated by the second device. The easy solution to that is to add a mode where the fd_device creates it's own private fd (a dup()). Signed-off-by: Rob Clark <robclark@freedesktop.org>
-rw-r--r--freedreno/freedreno_device.c12
-rw-r--r--freedreno/freedreno_drmif.h1
-rw-r--r--freedreno/freedreno_priv.h2
3 files changed, 15 insertions, 0 deletions
diff --git a/freedreno/freedreno_device.c b/freedreno/freedreno_device.c
index 6486983d..23e086bb 100644
--- a/freedreno/freedreno_device.c
+++ b/freedreno/freedreno_device.c
@@ -135,6 +135,16 @@ struct fd_device * fd_device_new(int fd)
return dev;
}
+/* like fd_device_new() but creates it's own private dup() of the fd
+ * which is close()d when the device is finalized.
+ */
+struct fd_device * fd_device_new_dup(int fd)
+{
+ struct fd_device *dev = fd_device_new(dup(fd));
+ dev->closefd = 1;
+ return dev;
+}
+
struct fd_device * fd_device_ref(struct fd_device *dev)
{
atomic_inc(&dev->refcnt);
@@ -147,6 +157,8 @@ static void fd_device_del_impl(struct fd_device *dev)
drmHashDestroy(dev->handle_table);
drmHashDestroy(dev->name_table);
drmHashDelete(dev_table, dev->fd);
+ if (dev->closefd)
+ close(dev->fd);
dev->funcs->destroy(dev);
}
diff --git a/freedreno/freedreno_drmif.h b/freedreno/freedreno_drmif.h
index 6a40ab8f..f3a01aff 100644
--- a/freedreno/freedreno_drmif.h
+++ b/freedreno/freedreno_drmif.h
@@ -72,6 +72,7 @@ enum fd_param_id {
*/
struct fd_device * fd_device_new(int fd);
+struct fd_device * fd_device_new_dup(int fd);
struct fd_device * fd_device_ref(struct fd_device *dev);
void fd_device_del(struct fd_device *dev);
diff --git a/freedreno/freedreno_priv.h b/freedreno/freedreno_priv.h
index 061d807e..d5cf9f97 100644
--- a/freedreno/freedreno_priv.h
+++ b/freedreno/freedreno_priv.h
@@ -84,6 +84,8 @@ struct fd_device {
struct fd_bo_bucket cache_bucket[14 * 4];
int num_buckets;
time_t time;
+
+ int closefd; /* call close(fd) upon destruction */
};
void fd_cleanup_bo_cache(struct fd_device *dev, time_t time);