aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorErik Gilling <konkers@android.com>2013-02-28 16:43:05 -0800
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2013-03-04 17:40:09 +0800
commitc0f61a4e6145728153d0b94152b4dd5b06899b3b (patch)
tree6e9d346a5ccc15a19469e3d82e2c21e5ebac7fe2
parent57b505bbe746dcc011152e79732bdaf96723c51a (diff)
staging: sync: Allow async waits to be canceled
In order to allow drivers to cleanly handled teardown we need to allow them to cancel pending async waits. To do this cleanly, we move allocation of sync_fence_waiter to the driver calling sync_async_wait(). Cc: Maarten Lankhorst <maarten.lankhorst@canonical.com> Cc: Erik Gilling <konkers@android.com> Cc: Daniel Vetter <daniel.vetter@ffwll.ch> Cc: Rob Clark <robclark@gmail.com> Cc: Sumit Semwal <sumit.semwal@linaro.org> Cc: dri-devel@lists.freedesktop.org Cc: Android Kernel Team <kernel-team@android.com> Signed-off-by: Erik Gilling <konkers@android.com> Signed-off-by: John Stultz <john.stultz@linaro.org> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
-rw-r--r--drivers/staging/android/sync.c46
-rw-r--r--drivers/staging/android/sync.h36
2 files changed, 60 insertions, 22 deletions
diff --git a/drivers/staging/android/sync.c b/drivers/staging/android/sync.c
index 9e35ea3e73d..54f84d926b9 100644
--- a/drivers/staging/android/sync.c
+++ b/drivers/staging/android/sync.c
@@ -421,33 +421,22 @@ static void sync_fence_signal_pt(struct sync_pt *pt)
container_of(pos, struct sync_fence_waiter,
waiter_list);
- waiter->callback(fence, waiter->callback_data);
list_del(pos);
- kfree(waiter);
+ waiter->callback(fence, waiter);
}
wake_up(&fence->wq);
}
}
int sync_fence_wait_async(struct sync_fence *fence,
- void (*callback)(struct sync_fence *, void *data),
- void *callback_data)
+ struct sync_fence_waiter *waiter)
{
- struct sync_fence_waiter *waiter;
unsigned long flags;
int err = 0;
- waiter = kzalloc(sizeof(struct sync_fence_waiter), GFP_KERNEL);
- if (waiter == NULL)
- return -ENOMEM;
-
- waiter->callback = callback;
- waiter->callback_data = callback_data;
-
spin_lock_irqsave(&fence->waiter_list_lock, flags);
if (fence->status) {
- kfree(waiter);
err = fence->status;
goto out;
}
@@ -459,6 +448,34 @@ out:
return err;
}
+int sync_fence_cancel_async(struct sync_fence *fence,
+ struct sync_fence_waiter *waiter)
+{
+ struct list_head *pos;
+ struct list_head *n;
+ unsigned long flags;
+ int ret = -ENOENT;
+
+ spin_lock_irqsave(&fence->waiter_list_lock, flags);
+ /*
+ * Make sure waiter is still in waiter_list because it is possible for
+ * the waiter to be removed from the list while the callback is still
+ * pending.
+ */
+ list_for_each_safe(pos, n, &fence->waiter_list_head) {
+ struct sync_fence_waiter *list_waiter =
+ container_of(pos, struct sync_fence_waiter,
+ waiter_list);
+ if (list_waiter == waiter) {
+ list_del(pos);
+ ret = 0;
+ break;
+ }
+ }
+ spin_unlock_irqrestore(&fence->waiter_list_lock, flags);
+ return ret;
+}
+
int sync_fence_wait(struct sync_fence *fence, long timeout)
{
int err;
@@ -739,8 +756,7 @@ static void sync_print_fence(struct seq_file *s, struct sync_fence *fence)
container_of(pos, struct sync_fence_waiter,
waiter_list);
- seq_printf(s, "waiter %pF %p\n", waiter->callback,
- waiter->callback_data);
+ seq_printf(s, "waiter %pF\n", waiter->callback);
}
spin_unlock_irqrestore(&fence->waiter_list_lock, flags);
}
diff --git a/drivers/staging/android/sync.h b/drivers/staging/android/sync.h
index 4f199387146..943f414b3f3 100644
--- a/drivers/staging/android/sync.h
+++ b/drivers/staging/android/sync.h
@@ -159,6 +159,10 @@ struct sync_fence {
struct list_head sync_fence_list;
};
+struct sync_fence_waiter;
+typedef void (*sync_callback_t)(struct sync_fence *fence,
+ struct sync_fence_waiter *waiter);
+
/**
* struct sync_fence_waiter - metadata for asynchronous waiter on a fence
* @waiter_list: membership in sync_fence.waiter_list_head
@@ -168,10 +172,15 @@ struct sync_fence {
struct sync_fence_waiter {
struct list_head waiter_list;
- void (*callback)(struct sync_fence *fence, void *data);
- void *callback_data;
+ sync_callback_t callback;
};
+static inline void sync_fence_waiter_init(struct sync_fence_waiter *waiter,
+ sync_callback_t callback)
+{
+ waiter->callback = callback;
+}
+
/*
* API for sync_timeline implementers
*/
@@ -284,16 +293,29 @@ void sync_fence_install(struct sync_fence *fence, int fd);
/**
* sync_fence_wait_async() - registers and async wait on the fence
* @fence: fence to wait on
- * @callback: callback
- * @callback_data data to pass to the callback
+ * @waiter: waiter callback struck
*
* Returns 1 if @fence has already signaled.
*
- * Registers a callback to be called when @fence signals or has an error
+ * Registers a callback to be called when @fence signals or has an error.
+ * @waiter should be initialized with sync_fence_waiter_init().
*/
int sync_fence_wait_async(struct sync_fence *fence,
- void (*callback)(struct sync_fence *, void *data),
- void *callback_data);
+ struct sync_fence_waiter *waiter);
+
+/**
+ * sync_fence_cancel_async() - cancels an async wait
+ * @fence: fence to wait on
+ * @waiter: waiter callback struck
+ *
+ * returns 0 if waiter was removed from fence's async waiter list.
+ * returns -ENOENT if waiter was not found on fence's async waiter list.
+ *
+ * Cancels a previously registered async wait. Will fail gracefully if
+ * @waiter was never registered or if @fence has already signaled @waiter.
+ */
+int sync_fence_cancel_async(struct sync_fence *fence,
+ struct sync_fence_waiter *waiter);
/**
* sync_fence_wait() - wait on fence