util: remove LIST_ADDTAIL macro
[mesa.git] / src / gallium / winsys / svga / drm / vmw_fence.c
index edf205e6239c6764a5d2d3578f9940c706b1395e..593be9c797b1da7c11f0976c80f8d2254b7b2b94 100644 (file)
@@ -22,6 +22,8 @@
  * SOFTWARE.
  *
  **********************************************************/
+#include <libsync.h>
+
 #include "util/u_memory.h"
 #include "util/u_atomic.h"
 #include "util/list.h"
@@ -32,7 +34,7 @@
 #include "vmw_screen.h"
 #include "vmw_fence.h"
 
-struct vmw_fence_ops 
+struct vmw_fence_ops
 {
    /*
     * Immutable members.
@@ -58,6 +60,8 @@ struct vmw_fence
    uint32_t mask;
    int32_t signalled;
    uint32_t seqno;
+   int32_t fence_fd;
+   boolean imported; /* TRUE if imported from another process */
 };
 
 /**
@@ -175,15 +179,16 @@ vmw_fence(struct pipe_fence_handle *fence)
  * @fence_ops: The fence_ops manager to register with.
  * @handle: Handle identifying the kernel fence object.
  * @mask: Mask of flags that this fence object may signal.
+ * @fd: File descriptor to associate with the fence
  *
  * Returns NULL on failure.
  */
 struct pipe_fence_handle *
 vmw_fence_create(struct pb_fence_ops *fence_ops, uint32_t handle,
-                 uint32_t seqno, uint32_t mask)
+                 uint32_t seqno, uint32_t mask, int32_t fd)
 {
    struct vmw_fence *fence = CALLOC_STRUCT(vmw_fence);
-   struct vmw_fence_ops *ops = vmw_fence_ops(fence_ops);
+   struct vmw_fence_ops *ops = NULL;
 
    if (!fence)
       return NULL;
@@ -192,15 +197,28 @@ vmw_fence_create(struct pb_fence_ops *fence_ops, uint32_t handle,
    fence->handle = handle;
    fence->mask = mask;
    fence->seqno = seqno;
+   fence->fence_fd = fd;
    p_atomic_set(&fence->signalled, 0);
+
+   /*
+    * If the fence was not created by our device, then we won't
+    * manage it with our ops
+    */
+   if (!fence_ops) {
+      fence->imported = true;
+      return (struct pipe_fence_handle *) fence;
+   }
+
+   ops = vmw_fence_ops(fence_ops);
+
    mtx_lock(&ops->mutex);
 
    if (vmw_fence_seq_is_signaled(seqno, ops->last_signaled, seqno)) {
       p_atomic_set(&fence->signalled, 1);
-      LIST_INITHEAD(&fence->ops_list);
+      list_inithead(&fence->ops_list);
    } else {
       p_atomic_set(&fence->signalled, 0);
-      LIST_ADDTAIL(&fence->ops_list, &ops->not_signaled);
+      list_addtail(&fence->ops_list, &ops->not_signaled);
    }
 
    mtx_unlock(&ops->mutex);
@@ -209,6 +227,21 @@ vmw_fence_create(struct pb_fence_ops *fence_ops, uint32_t handle,
 }
 
 
+/**
+ * vmw_fence_destroy - Frees a vmw fence object.
+ *
+ * Also closes the file handle associated with the object, if any
+ */
+static
+void vmw_fence_destroy(struct vmw_fence *vfence)
+{
+   if (vfence->fence_fd != -1)
+      close(vfence->fence_fd);
+
+   FREE(vfence);
+}
+
+
 /**
  * vmw_fence_reference - Reference / unreference a vmw fence object.
  *
@@ -227,13 +260,15 @@ vmw_fence_reference(struct vmw_winsys_screen *vws,
       if (p_atomic_dec_zero(&vfence->refcount)) {
          struct vmw_fence_ops *ops = vmw_fence_ops(vws->fence_ops);
 
-        vmw_ioctl_fence_unref(vws, vfence->handle);
+         if (!vfence->imported) {
+            vmw_ioctl_fence_unref(vws, vfence->handle);
 
-         mtx_lock(&ops->mutex);
-         LIST_DELINIT(&vfence->ops_list);
-         mtx_unlock(&ops->mutex);
+            mtx_lock(&ops->mutex);
+            LIST_DELINIT(&vfence->ops_list);
+            mtx_unlock(&ops->mutex);
+         }
 
-        FREE(vfence);
+         vmw_fence_destroy(vfence);
       }
    }
 
@@ -300,6 +335,7 @@ vmw_fence_signalled(struct vmw_winsys_screen *vws,
  *
  * @vws: Pointer to the winsys screen.
  * @fence: Handle to the fence object.
+ * @timeout: How long to wait before timing out.
  * @flag: Fence flags to wait for. If the fence object can't signal
  * a flag, it is assumed to be already signaled.
  *
@@ -308,6 +344,7 @@ vmw_fence_signalled(struct vmw_winsys_screen *vws,
 int
 vmw_fence_finish(struct vmw_winsys_screen *vws,
                 struct pipe_fence_handle *fence,
+                uint64_t timeout,
                 unsigned flag)
 {
    struct vmw_fence *vfence;
@@ -319,6 +356,16 @@ vmw_fence_finish(struct vmw_winsys_screen *vws,
       return 0;
 
    vfence = vmw_fence(fence);
+
+   if (vfence->imported) {
+      ret = sync_wait(vfence->fence_fd, timeout / 1000000);
+
+      if (!ret)
+         p_atomic_set(&vfence->signalled, 1);
+
+      return !!ret;
+   }
+
    old = p_atomic_read(&vfence->signalled);
    vflags &= ~vfence->mask;
 
@@ -339,6 +386,23 @@ vmw_fence_finish(struct vmw_winsys_screen *vws,
    return ret;
 }
 
+/**
+ * vmw_fence_get_fd
+ *
+ * Returns the file descriptor associated with the fence
+ */
+int
+vmw_fence_get_fd(struct pipe_fence_handle *fence)
+{
+   struct vmw_fence *vfence;
+
+   if (!fence)
+      return -1;
+
+   vfence = vmw_fence(fence);
+   return vfence->fence_fd;
+}
+
 
 /**
  * vmw_fence_ops_fence_reference - wrapper for the pb_fence_ops api.
@@ -383,7 +447,7 @@ vmw_fence_ops_fence_finish(struct pb_fence_ops *ops,
 {
    struct vmw_winsys_screen *vws = vmw_fence_ops(ops)->vws;
 
-   return vmw_fence_finish(vws, fence, flag);
+   return vmw_fence_finish(vws, fence, PIPE_TIMEOUT_INFINITE, flag);
 }
 
 
@@ -422,7 +486,7 @@ vmw_fence_ops_create(struct vmw_winsys_screen *vws)
       return NULL;
 
    (void) mtx_init(&ops->mutex, mtx_plain);
-   LIST_INITHEAD(&ops->not_signaled);
+   list_inithead(&ops->not_signaled);
    ops->base.destroy = &vmw_fence_ops_destroy;
    ops->base.fence_reference = &vmw_fence_ops_fence_reference;
    ops->base.fence_signalled = &vmw_fence_ops_fence_signalled;