From d47df3fb7a897d79cce287ccf9e7630cbcb4deec Mon Sep 17 00:00:00 2001
From: Matthew Wilcox <matthew@wil.cx>
Date: Sun, 27 Jan 2008 22:46:38 -0500
Subject: [PATCH] sh64: Implement down_killable

Signed-off-by: Matthew Wilcox <matthew@wil.cx>
---
 arch/sh64/kernel/semaphore.c        |   19 +++++++++++++++++++
 arch/sh64/kernel/sh_ksyms.c         |    2 ++
 include/asm-sh64/semaphore-helper.h |   18 ++++++++++++++++++
 include/asm-sh64/semaphore.h        |   11 +++++++++++
 4 files changed, 50 insertions(+), 0 deletions(-)

diff --git a/arch/sh64/kernel/semaphore.c b/arch/sh64/kernel/semaphore.c
index 72c1653..335c7b3 100644
--- a/arch/sh64/kernel/semaphore.c
+++ b/arch/sh64/kernel/semaphore.c
@@ -134,6 +134,25 @@ int __sched __down_interruptible(struct semaphore * sem)
 	return ret;
 }
 
+int __sched __down_killable(struct semaphore * sem)
+{
+	int ret = 0;
+	DOWN_VAR
+	DOWN_HEAD(TASK_KILLABLE)
+
+	ret = waking_non_zero_killable(sem, tsk);
+	if (ret)
+	{
+		if (ret == 1)
+			/* ret != 0 only if we get interrupted -arca */
+			ret = 0;
+		break;
+	}
+	schedule();
+	DOWN_TAIL(TASK_KILLABLE)
+	return ret;
+}
+
 int __down_trylock(struct semaphore * sem)
 {
 	return waking_non_zero_trylock(sem);
diff --git a/arch/sh64/kernel/sh_ksyms.c b/arch/sh64/kernel/sh_ksyms.c
index b1705ac..87e12ee 100644
--- a/arch/sh64/kernel/sh_ksyms.c
+++ b/arch/sh64/kernel/sh_ksyms.c
@@ -41,6 +41,8 @@ EXPORT_SYMBOL(screen_info);
 #endif
 
 EXPORT_SYMBOL(__down);
+EXPORT_SYMBOL(__down_interruptible);
+EXPORT_SYMBOL(__down_killable);
 EXPORT_SYMBOL(__down_trylock);
 EXPORT_SYMBOL(__up);
 EXPORT_SYMBOL(__put_user_asm_l);
diff --git a/include/asm-sh64/semaphore-helper.h b/include/asm-sh64/semaphore-helper.h
index fcfafe2..f34c03c 100644
--- a/include/asm-sh64/semaphore-helper.h
+++ b/include/asm-sh64/semaphore-helper.h
@@ -73,6 +73,24 @@ static __inline__ int waking_non_zero_interruptible(struct semaphore *sem,
 	return ret;
 }
 
+static __inline__ int waking_non_zero_killable(struct semaphore *sem,
+						struct task_struct *tsk)
+{
+	unsigned long flags;
+	int ret = 0;
+
+	spin_lock_irqsave(&semaphore_wake_lock, flags);
+	if (sem->sleepers > 0) {
+		sem->sleepers--;
+		ret = 1;
+	} else if (fatal_signal_pending(tsk)) {
+		atomic_inc(&sem->count);
+		ret = -EINTR;
+	}
+	spin_unlock_irqrestore(&semaphore_wake_lock, flags);
+	return ret;
+}
+
 /*
  * waking_non_zero_trylock:
  *	1	failed to lock
diff --git a/include/asm-sh64/semaphore.h b/include/asm-sh64/semaphore.h
index f027cc1..b87c0c6 100644
--- a/include/asm-sh64/semaphore.h
+++ b/include/asm-sh64/semaphore.h
@@ -71,12 +71,14 @@ static inline void init_MUTEX_LOCKED (struct semaphore *sem)
 #if 0
 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 */);
 #endif
 
 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);
 
@@ -97,6 +99,15 @@ static inline int down_interruptible(struct semaphore * sem)
 	return ret;
 }
 
+static inline int down_killable(struct semaphore * sem)
+{
+	int ret = 0;
+
+	if (atomic_dec_return(&sem->count) < 0)
+		ret = __down_killable(sem);
+	return ret;
+}
+
 static inline int down_trylock(struct semaphore * sem)
 {
 	int ret = 0;
-- 
1.5.3.8


