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

Signed-off-by: Matthew Wilcox <matthew@wil.cx>
---
 arch/alpha/kernel/alpha_ksyms.c |    2 +
 arch/alpha/kernel/semaphore.c   |   57 +++++++++++++++++++++++++++++++++++++++
 include/asm-alpha/semaphore.h   |   16 +++++++++++
 3 files changed, 75 insertions(+), 0 deletions(-)

diff --git a/arch/alpha/kernel/alpha_ksyms.c b/arch/alpha/kernel/alpha_ksyms.c
index e9762a3..ed97e10 100644
--- a/arch/alpha/kernel/alpha_ksyms.c
+++ b/arch/alpha/kernel/alpha_ksyms.c
@@ -80,9 +80,11 @@ EXPORT_SYMBOL(__strnlen_user);
 /* Semaphore helper functions.  */
 EXPORT_SYMBOL(__down_failed);
 EXPORT_SYMBOL(__down_failed_interruptible);
+EXPORT_SYMBOL(__down_failed_killable);
 EXPORT_SYMBOL(__up_wakeup);
 EXPORT_SYMBOL(down);
 EXPORT_SYMBOL(down_interruptible);
+EXPORT_SYMBOL(down_killable);
 EXPORT_SYMBOL(down_trylock);
 EXPORT_SYMBOL(up);
 
diff --git a/arch/alpha/kernel/semaphore.c b/arch/alpha/kernel/semaphore.c
index 8d2982a..c27a469 100644
--- a/arch/alpha/kernel/semaphore.c
+++ b/arch/alpha/kernel/semaphore.c
@@ -145,6 +145,49 @@ __down_failed_interruptible(struct semaphore *sem)
 	return ret;
 }
 
+int __sched
+__down_failed_killable(struct semaphore *sem)
+{
+	struct task_struct *tsk = current;
+	DECLARE_WAITQUEUE(wait, tsk);
+	long ret = 0;
+
+#ifdef CONFIG_DEBUG_SEMAPHORE
+	printk("%s(%d): down failed(%p)\n",
+	       tsk->comm, task_pid_nr(tsk), sem);
+#endif
+
+	tsk->state = TASK_KILLABLE;
+	wmb();
+	add_wait_queue_exclusive(&sem->wait, &wait);
+
+	while (__sem_update_count(sem, -1) <= 0) {
+		if (fatal_signal_pending(current)) {
+			/*
+			 * A fatal 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);
+			ret = -EINTR;
+			break;
+		}
+		schedule();
+		set_task_state(tsk, TASK_KILLABLE);
+	}
+
+	remove_wait_queue(&sem->wait, &wait);
+	tsk->state = TASK_RUNNING;
+	wake_up(&sem->wait);
+
+#ifdef CONFIG_DEBUG_SEMAPHORE
+	printk("%s(%d): down %s(%p)\n",
+	       current->comm, task_pid_nr(current),
+	       (ret < 0 ? "interrupted" : "acquired"), sem);
+#endif
+	return ret;
+}
+
 void
 __up_wakeup(struct semaphore *sem)
 {
@@ -188,6 +231,20 @@ down_interruptible(struct semaphore *sem)
 	return __down_interruptible(sem);
 }
 
+int __sched
+down_killable(struct semaphore *sem)
+{
+#ifdef WAITQUEUE_DEBUG
+	CHECK_MAGIC(sem->__magic);
+#endif
+#ifdef CONFIG_DEBUG_SEMAPHORE
+	printk("%s(%d): down(%p) <count=%d> from %p\n",
+	       current->comm, task_pid_nr(current), sem,
+	       atomic_read(&sem->count), __builtin_return_address(0));
+#endif
+	return __down_killable(sem);
+}
+
 int
 down_trylock(struct semaphore *sem)
 {
diff --git a/include/asm-alpha/semaphore.h b/include/asm-alpha/semaphore.h
index f1e9278..2763df9 100644
--- a/include/asm-alpha/semaphore.h
+++ b/include/asm-alpha/semaphore.h
@@ -57,6 +57,8 @@ extern void down(struct semaphore *);
 extern void __down_failed(struct semaphore *);
 extern int  down_interruptible(struct semaphore *);
 extern int  __down_failed_interruptible(struct semaphore *);
+extern int  down_killable(struct semaphore *);
+extern int  __down_failed_killable(struct semaphore *);
 extern int  down_trylock(struct semaphore *);
 extern void up(struct semaphore *);
 extern void __up_wakeup(struct semaphore *);
@@ -86,6 +88,16 @@ static inline int __down_interruptible(struct semaphore *sem)
 	return 0;
 }
 
+static inline int __down_killable(struct semaphore *sem)
+{
+	long count;
+	might_sleep();
+	count = atomic_dec_return(&sem->count);
+	if (unlikely(count < 0))
+		return __down_failed_killable(sem);
+	return 0;
+}
+
 /*
  * down_trylock returns 0 on success, 1 if we failed to get the lock.
  */
@@ -136,6 +148,10 @@ extern inline int down_interruptible(struct semaphore *sem)
 {
 	return __down_interruptible(sem);
 }
+extern inline int down_killable(struct semaphore *sem)
+{
+	return __down_killable(sem);
+}
 extern inline int down_trylock(struct semaphore *sem)
 {
 	return __down_trylock(sem);
-- 
1.5.3.8


