From f574adc1ad4166a7e57d4edb1e31fe72d6956ad6 Mon Sep 17 00:00:00 2001
From: Matthew Wilcox <matthew@wil.cx>
Date: Sun, 27 Jan 2008 19:43:47 -0500
Subject: [PATCH] m32r: Implement down_killable

Signed-off-by: Matthew Wilcox <matthew@wil.cx>
---
 arch/m32r/kernel/m32r_ksyms.c |    1 +
 arch/m32r/kernel/semaphore.c  |   55 +++++++++++++++++++++++++++++++++++++++++
 include/asm-m32r/semaphore.h  |   13 +++++++++
 3 files changed, 69 insertions(+), 0 deletions(-)

diff --git a/arch/m32r/kernel/m32r_ksyms.c b/arch/m32r/kernel/m32r_ksyms.c
index 41a4c95..7069679 100644
--- a/arch/m32r/kernel/m32r_ksyms.c
+++ b/arch/m32r/kernel/m32r_ksyms.c
@@ -24,6 +24,7 @@ EXPORT_SYMBOL(iounmap);
 EXPORT_SYMBOL(kernel_thread);
 EXPORT_SYMBOL(__down);
 EXPORT_SYMBOL(__down_interruptible);
+EXPORT_SYMBOL(__down_killable);
 EXPORT_SYMBOL(__up);
 EXPORT_SYMBOL(__down_trylock);
 
diff --git a/arch/m32r/kernel/semaphore.c b/arch/m32r/kernel/semaphore.c
index 940c2d3..58e6d8d 100644
--- a/arch/m32r/kernel/semaphore.c
+++ b/arch/m32r/kernel/semaphore.c
@@ -154,6 +154,61 @@ asmlinkage int __sched __down_interruptible(struct semaphore * sem)
 	return retval;
 }
 
+asmlinkage 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 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
+		 * wait_queue_head. The "-1" is because we're
+		 * still hoping to get the semaphore.
+		 */
+		if (!atomic_add_negative(sleepers - 1, &sem->count)) {
+			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;
+}
+
 /*
  * Trylock failed - make sure we correct for
  * having decremented the count.
diff --git a/include/asm-m32r/semaphore.h b/include/asm-m32r/semaphore.h
index b5bf95a..4fc5883 100644
--- a/include/asm-m32r/semaphore.h
+++ b/include/asm-m32r/semaphore.h
@@ -61,11 +61,13 @@ static inline void init_MUTEX_LOCKED (struct semaphore *sem)
 
 asmlinkage void __down_failed(void /* special register calling convention */);
 asmlinkage int  __down_failed_interruptible(void  /* params in registers */);
+asmlinkage int  __down_failed_killable(void  /* params in registers */);
 asmlinkage int  __down_failed_trylock(void  /* params in registers */);
 asmlinkage void __up_wakeup(void /* special register calling convention */);
 
 asmlinkage void __down(struct semaphore * sem);
 asmlinkage int  __down_interruptible(struct semaphore * sem);
+asmlinkage int  __down_killable(struct semaphore * sem);
 asmlinkage int  __down_trylock(struct semaphore * sem);
 asmlinkage void __up(struct semaphore * sem);
 
@@ -95,6 +97,17 @@ static inline int down_interruptible(struct semaphore * sem)
 	return result;
 }
 
+static inline int down_killable(struct semaphore * sem)
+{
+	int result = 0;
+
+	might_sleep();
+	if (unlikely(atomic_dec_return(&sem->count) < 0))
+		result = __down_killable(sem);
+
+	return result;
+}
+
 /*
  * Non-blockingly attempt to down() a semaphore.
  * Returns zero if we acquired it
-- 
1.5.3.8

