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

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

diff --git a/arch/frv/kernel/semaphore.c b/arch/frv/kernel/semaphore.c
index 7ee3a14..80150e5 100644
--- a/arch/frv/kernel/semaphore.c
+++ b/arch/frv/kernel/semaphore.c
@@ -124,6 +124,57 @@ int __down_interruptible(struct semaphore *sem, unsigned long flags)
 
 EXPORT_SYMBOL(__down_interruptible);
 
+int __down_killable(struct semaphore *sem, unsigned long flags)
+{
+	struct task_struct *tsk = current;
+	struct sem_waiter waiter;
+	int ret;
+
+	semtrace(sem,"Entering __down_killable");
+
+	/* set up my own style of waitqueue */
+	waiter.task = tsk;
+	get_task_struct(tsk);
+
+	list_add_tail(&waiter.list, &sem->wait_list);
+
+	/* we don't need to touch the semaphore struct anymore */
+	set_task_state(tsk, TASK_KILLABLE);
+
+	spin_unlock_irqrestore(&sem->wait_lock, flags);
+
+	/* wait to be given the semaphore */
+	ret = 0;
+	for (;;) {
+		if (list_empty(&waiter.list))
+			break;
+		if (unlikely(fatal_signal_pending(current)))
+			goto interrupted;
+		schedule();
+		set_task_state(tsk, TASK_KILLABLE);
+	}
+
+ out:
+	tsk->state = TASK_RUNNING;
+	semtrace(sem, "Leaving __down_killable");
+	return ret;
+
+ interrupted:
+	spin_lock_irqsave(&sem->wait_lock, flags);
+
+	if (!list_empty(&waiter.list)) {
+		list_del(&waiter.list);
+		ret = -EINTR;
+	}
+
+	spin_unlock_irqrestore(&sem->wait_lock, flags);
+	if (ret == -EINTR)
+		put_task_struct(current);
+	goto out;
+}
+
+EXPORT_SYMBOL(__down_killable);
+
 /*
  * release a single token back to a semaphore
  * - entered with lock held and interrupts disabled
diff --git a/include/asm-frv/semaphore.h b/include/asm-frv/semaphore.h
index d7aaa19..559814b 100644
--- a/include/asm-frv/semaphore.h
+++ b/include/asm-frv/semaphore.h
@@ -67,6 +67,7 @@ static inline void init_MUTEX_LOCKED (struct semaphore *sem)
 
 extern void __down(struct semaphore *sem, unsigned long flags);
 extern int  __down_interruptible(struct semaphore *sem, unsigned long flags);
+extern int  __down_killable(struct semaphore *sem, unsigned long flags);
 extern void __up(struct semaphore *sem);
 
 static inline void down(struct semaphore *sem)
@@ -107,6 +108,26 @@ static inline int down_interruptible(struct semaphore *sem)
 	return ret;
 }
 
+static inline int down_killable(struct semaphore *sem)
+{
+	unsigned long flags;
+	int ret = 0;
+
+#ifdef CONFIG_DEBUG_SEMAPHORE
+	CHECK_MAGIC(sem->__magic);
+#endif
+
+	spin_lock_irqsave(&sem->wait_lock, flags);
+	if (likely(sem->counter > 0)) {
+		sem->counter--;
+		spin_unlock_irqrestore(&sem->wait_lock, flags);
+	}
+	else {
+		ret = __down_killable(sem, flags);
+	}
+	return ret;
+}
+
 /*
  * non-blockingly attempt to down() a semaphore.
  * - returns zero if we acquired it
-- 
1.5.3.8


