summaryrefslogtreecommitdiff
path: root/linux-core/drm_bo_lock2.c
diff options
context:
space:
mode:
Diffstat (limited to 'linux-core/drm_bo_lock2.c')
-rw-r--r--linux-core/drm_bo_lock2.c99
1 files changed, 99 insertions, 0 deletions
diff --git a/linux-core/drm_bo_lock2.c b/linux-core/drm_bo_lock2.c
new file mode 100644
index 00000000..73e58bc0
--- /dev/null
+++ b/linux-core/drm_bo_lock2.c
@@ -0,0 +1,99 @@
+#include "drmP.h"
+
+void drm_bo_init_lock(struct drm_bo_lock *lock)
+{
+ DRM_INIT_WAITQUEUE(&lock->queue);
+ atomic_set(&lock->write_lock_pending, 0);
+ atomic_set(&lock->readers, 0);
+
+}
+
+void drm_bo_read_unlock(struct drm_bo_lock *lock)
+{
+ if (unlikely(atomic_add_negative(-1, &lock->readers) == 0))
+ BUG();
+ if (atomic_read(&lock->readers) == 0)
+ wake_up_interruptible(&lock->queue);
+}
+
+int drm_bo_read_lock(struct drm_bo_lock *lock)
+{
+ while( unlikely(atomic_read(&lock->write_lock_pending) != 0)) {
+ int ret;
+ ret = wait_event_interruptible
+ (lock->queue,
+ atomic_read(&lock->write_lock_pending) == 0);
+ if (ret)
+ return -EAGAIN;
+ }
+
+ while( unlikely (!atomic_add_unless(&lock->readers, 1, -1))) {
+ int ret;
+ ret = wait_event_interruptible
+ (lock->queue,
+ atomic_add_unless(&lock->readers, 1, -1));
+ if (ret)
+ return -EAGAIN;
+ }
+ return 0;
+}
+
+static int __drm_bo_write_unlock(struct drm_bo_lock *lock)
+{
+ if (unlikely(atomic_cmpxchg(&lock->readers, -1, 0) != -1))
+ return -EINVAL;
+ if (unlikely(atomic_cmpxchg(&lock->write_lock_pending, 1, 0) != 1))
+ return -EINVAL;
+ wake_up_interruptible(&lock->queue);
+ return 0;
+}
+
+static void drm_bo_write_lock_remove(struct drm_file *file_priv,
+ struct drm_user_object *item)
+{
+ struct drm_bo_lock *lock =
+ container_of(item, struct drm_bo_lock, base);
+ int ret;
+
+ ret = __drm_bo_write_unlock(lock);
+ BUG_ON(ret);
+}
+
+int drm_bo_write_lock(struct drm_bo_lock *lock, struct drm_file *file_priv)
+{
+ int ret = 0;
+ struct drm_device *dev;
+
+ if (unlikely(atomic_cmpxchg(&lock->write_lock_pending, 0, 1) != 0))
+ return -EINVAL;
+
+ while(unlikely(atomic_cmpxchg(&lock->readers, 0, -1) != 0)) {
+ ret = wait_event_interruptible
+ (lock->queue,
+ atomic_cmpxchg(&lock->readers, 0, -1) == 0);
+
+ if (ret) {
+ atomic_set(&lock->write_lock_pending, 0);
+ wake_up_interruptible(&lock->queue);
+ return -EAGAIN;
+ }
+ }
+
+ dev = file_priv->head->dev;
+ mutex_lock(&dev->struct_mutex);
+ ret = drm_add_user_object(file_priv, &lock->base, 0);
+ lock->base.remove = &drm_bo_write_lock_remove;
+ lock->base.type = drm_lock_type;
+ if (ret)
+ (void) __drm_bo_write_unlock(lock);
+ mutex_unlock(&dev->struct_mutex);
+
+ return ret;
+}
+
+
+int drm_bo_write_unlock(struct drm_bo_lock *lock, struct drm_file *file_priv)
+{
+ return drm_user_object_unref(file_priv, lock->base.hash.key,
+ drm_lock_type);
+}