From de6a97ce42aca8cecb64fc5e151dd23a1c5a0447 Mon Sep 17 00:00:00 2001
From: Matthew Wilcox <matthew@wil.cx>
Date: Sun, 27 Jan 2008 19:54:46 -0500
Subject: [PATCH] mips: Implement down_killable

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

diff --git a/arch/mips/kernel/semaphore.c b/arch/mips/kernel/semaphore.c
index 1265358..6505de5 100644
--- a/arch/mips/kernel/semaphore.c
+++ b/arch/mips/kernel/semaphore.c
@@ -166,3 +166,35 @@ int __sched __down_interruptible(struct semaphore * sem)
 }
 
 EXPORT_SYMBOL(__down_interruptible);
+
+int __sched __down_killable(struct semaphore * sem)
+{
+	int retval = 0;
+	struct task_struct *tsk = current;
+	DECLARE_WAITQUEUE(wait, tsk);
+
+	__set_task_state(tsk, TASK_KILLABLE);
+	add_wait_queue_exclusive(&sem->wait, &wait);
+
+	while (__sem_update_count(sem, -1) <= 0) {
+		if (fatal_signal_pending(current)) {
+			/*
+			 * A signal is pending - give up trying.
+			 * Set sem->count to 0 if it is negative,
+			 * since we are no longer sleeping.
+			 */
+			__sem_update_count(sem, 0);
+			retval = -EINTR;
+			break;
+		}
+		schedule();
+		set_task_state(tsk, TASK_KILLABLE);
+	}
+	remove_wait_queue(&sem->wait, &wait);
+	__set_task_state(tsk, TASK_RUNNING);
+
+	wake_up(&sem->wait);
+	return retval;
+}
+
+EXPORT_SYMBOL(__down_killable);
diff --git a/include/asm-mips/semaphore.h b/include/asm-mips/semaphore.h
index fdf8042..a5ef708 100644
--- a/include/asm-mips/semaphore.h
+++ b/include/asm-mips/semaphore.h
@@ -68,6 +68,7 @@ static inline void init_MUTEX_LOCKED(struct semaphore *sem)
 
 extern void __down(struct semaphore * sem);
 extern int  __down_interruptible(struct semaphore * sem);
+extern int  __down_killable(struct semaphore * sem);
 extern void __up(struct semaphore * sem);
 
 static inline void down(struct semaphore * sem)
@@ -92,6 +93,17 @@ 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;
+}
+
 static inline int down_trylock(struct semaphore * sem)
 {
 	return atomic_dec_if_positive(&sem->count) < 0;
-- 
1.5.3.8


