From 4a6ac2a329f9895d83353ba68fb7907c3877ed39 Mon Sep 17 00:00:00 2001
From: Matthew Wilcox <matthew@wil.cx>
Date: Sun, 27 Jan 2008 19:30:58 -0500
Subject: [PATCH] cris: Implement down_killable

Signed-off-by: Matthew Wilcox <matthew@wil.cx>
---
 arch/cris/kernel/crisksyms.c        |    1 +
 arch/cris/kernel/semaphore.c        |   19 +++++++++++++++++++
 include/asm-cris/semaphore-helper.h |   18 ++++++++++++++++++
 include/asm-cris/semaphore.h        |   17 +++++++++++++++++
 4 files changed, 55 insertions(+), 0 deletions(-)

diff --git a/arch/cris/kernel/crisksyms.c b/arch/cris/kernel/crisksyms.c
index 62f0e75..31a8f5d 100644
--- a/arch/cris/kernel/crisksyms.c
+++ b/arch/cris/kernel/crisksyms.c
@@ -53,6 +53,7 @@ EXPORT_SYMBOL(iounmap);
 EXPORT_SYMBOL(__up);
 EXPORT_SYMBOL(__down);
 EXPORT_SYMBOL(__down_interruptible);
+EXPORT_SYMBOL(__down_killable);
 EXPORT_SYMBOL(__down_trylock);
 
 /* Userspace access functions */
diff --git a/arch/cris/kernel/semaphore.c b/arch/cris/kernel/semaphore.c
index b884263..1b7c543 100644
--- a/arch/cris/kernel/semaphore.c
+++ b/arch/cris/kernel/semaphore.c
@@ -124,6 +124,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/include/asm-cris/semaphore-helper.h b/include/asm-cris/semaphore-helper.h
index 27bfeca..7b1ba01 100644
--- a/include/asm-cris/semaphore-helper.h
+++ b/include/asm-cris/semaphore-helper.h
@@ -57,6 +57,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)
+{
+	int ret = 0;
+	unsigned long flags;
+
+	local_irq_save(flags);
+	if (read(&sem->waking) > 0) {
+		dec(&sem->waking);
+		ret = 1;
+	} else if (fatal_signal_pending(tsk)) {
+		inc(&sem->count);
+		ret = -EINTR;
+	}
+	local_irq_restore(flags);
+	return ret;
+}
+
 static inline int waking_non_zero_trylock(struct semaphore *sem)
 {
         int ret = 1;
diff --git a/include/asm-cris/semaphore.h b/include/asm-cris/semaphore.h
index 31a4ac4..d16384a 100644
--- a/include/asm-cris/semaphore.h
+++ b/include/asm-cris/semaphore.h
@@ -53,6 +53,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 int __down_trylock(struct semaphore * sem);
 extern void __up(struct semaphore * sem);
 
@@ -96,6 +97,22 @@ static inline int down_interruptible(struct semaphore * sem)
 	return(failed);
 }
 
+static inline int down_killable(struct semaphore * sem)
+{
+	unsigned long flags;
+	int failed;
+
+	might_sleep();
+
+	/* atomically decrement the semaphores count, and if its negative, we wait */
+	cris_atomic_save(sem, flags);
+	failed = --(sem->count.counter) < 0;
+	cris_atomic_restore(sem, flags);
+	if(failed)
+		failed = __down_killable(sem);
+	return(failed);
+}
+
 static inline int down_trylock(struct semaphore * sem)
 {
 	unsigned long flags;
-- 
1.5.3.8


