From 2b75385032300b4a756489dd261e3404c2b22b4d Mon Sep 17 00:00:00 2001
From: Matthew Wilcox <matthew@wil.cx>
Date: Sun, 27 Jan 2008 19:23:02 -0500
Subject: [PATCH] avr32: Implement down_killable

Signed-off-by: Matthew Wilcox <matthew@wil.cx>
---
 arch/avr32/kernel/semaphore.c |   54 +++++++++++++++++++++++++++++++++++++++++
 include/asm-avr32/semaphore.h |   11 ++++++++
 2 files changed, 65 insertions(+), 0 deletions(-)

diff --git a/arch/avr32/kernel/semaphore.c b/arch/avr32/kernel/semaphore.c
index 1e2705a..2c0681c 100644
--- a/arch/avr32/kernel/semaphore.c
+++ b/arch/avr32/kernel/semaphore.c
@@ -146,3 +146,57 @@ int __sched __down_interruptible(struct semaphore *sem)
 	return retval;
 }
 EXPORT_SYMBOL(__down_interruptible);
+
+int __sched __down_killable(struct semaphore *sem)
+{
+	int retval = 0;
+	struct task_struct *tsk = current;
+        DECLARE_WAITQUEUE(wait, tsk);
+        unsigned long flags;
+
+        tsk->state = TASK_KILLABLE;
+        spin_lock_irqsave(&sem->wait.lock, flags);
+        add_wait_queue_exclusive_locked(&sem->wait, &wait);
+
+        sem->sleepers++;
+        for (;;) {
+                int sleepers = sem->sleepers;
+
+		/*
+		 * With fatal signals pending, this turns into the trylock
+		 * failure case - we won't be sleeping, and we can't
+		 * get the lock as it has contention. Just correct the
+		 * count and exit.
+		 */
+		if (fatal_signal_pending(current)) {
+			retval = -EINTR;
+			sem->sleepers = 0;
+			atomic_add(sleepers, &sem->count);
+			break;
+		}
+
+                /*
+                 * Add "everybody else" into it. They aren't
+                 * playing, because we own the spinlock in
+                 * the wait_queue_head.
+                 */
+                if (atomic_add_return(sleepers - 1, &sem->count) >= 0) {
+                        sem->sleepers = 0;
+                        break;
+                }
+                sem->sleepers = 1;      /* us - see -1 above */
+                spin_unlock_irqrestore(&sem->wait.lock, flags);
+
+                schedule();
+
+                spin_lock_irqsave(&sem->wait.lock, flags);
+                tsk->state = TASK_KILLABLE;
+        }
+        remove_wait_queue_locked(&sem->wait, &wait);
+        wake_up_locked(&sem->wait);
+        spin_unlock_irqrestore(&sem->wait.lock, flags);
+
+        tsk->state = TASK_RUNNING;
+	return retval;
+}
+EXPORT_SYMBOL(__down_killable);
diff --git a/include/asm-avr32/semaphore.h b/include/asm-avr32/semaphore.h
index feaf1d4..6cb7f1e 100644
--- a/include/asm-avr32/semaphore.h
+++ b/include/asm-avr32/semaphore.h
@@ -56,6 +56,7 @@ static inline void init_MUTEX_LOCKED (struct semaphore *sem)
 
 void __down(struct semaphore * sem);
 int  __down_interruptible(struct semaphore * sem);
+int  __down_killable(struct semaphore * sem);
 void __up(struct semaphore * sem);
 
 /*
@@ -84,6 +85,16 @@ static inline int down_interruptible(struct semaphore * sem)
 	return ret;
 }
 
+static inline int down_killable(struct semaphore * sem)
+{
+	int ret = 0;
+
+	might_sleep();
+	if (unlikely(atomic_dec_return (&sem->count) < 0))
+		ret = __down_killable (sem);
+	return ret;
+}
+
 /*
  * Non-blockingly attempt to down() a semaphore.
  * Returns zero if we acquired it
-- 
1.5.3.8


