Re: down_killable implementations for every architecture

2008-02-05 Thread Matthew Wilcox
On Tue, Jan 29, 2008 at 05:23:52AM +0100, Andi Kleen wrote:
> On Tuesday 29 January 2008 00:19, Matthew Wilcox wrote:
> > As part of the TASK_KILLABLE changes, we're going to need
> > down_killable().  Unfortunately, semaphores are implemented for every
> > architecture, which we should probably fix at some point.
> 
> It would be best to just change it now before doing further changes. Right now
> we have the bizarre situation that semaphores are more optimized
> with fast path inline assembly code than the far more critical spinlocks.
> But that clearly doesn't make much sense. So the best approach would
> be likely to just pick some generic C implementation from some architecture
> and use it everywhere.

We don't really have an appropriate one.  So I've invented my own.

 104 files changed, 338 insertions(+), 7335 deletions(-)

(and 228k).  That seems inappropriate to post.

Here's the whole patch (includes deletions from every architecture):
http://www.parisc-linux.org/~willy/generic-semaphore.diff

Here's the interesting/useful bit.  I've only tested it briefly on my
laptop -- it could be full of holes, but I've tried very hard to think
of all the interesting edge/race conditions with multiple
sleepers/wakers.

Please review.  I won't be around to respond to comments for another
four days.

diff --git a/include/linux/semaphore.h b/include/linux/semaphore.h
new file mode 100644
index 000..8e563bc
--- /dev/null
+++ b/include/linux/semaphore.h
@@ -0,0 +1,81 @@
+/*
+ * Copyright (c) 2008 Intel Corporation
+ * Author: Matthew Wilcox <[EMAIL PROTECTED]>
+ *
+ * Distributed under the terms of the GNU GPL, version 2
+ *
+ * Counting semaphores allow up to  tasks to acquire the semaphore
+ * simultaneously.
+ */
+#ifndef __LINUX_SEMAPHORE_H
+#define __LINUX_SEMAPHORE_H
+
+#include 
+#include 
+
+/*
+ * The spinlock controls access to the other members of the semaphore.
+ * 'count' is decremented by every task which calls down*() and incremented
+ * by every call to up().  Thus, if it is positive, it indicates how many
+ * more tasks may acquire the lock.  If it is negative, it indicates how
+ * many tasks are waiting for the lock.  Tasks waiting for the lock are
+ * kept on the wait_list.
+ */
+struct semaphore {
+   spinlock_t  lock;
+   int count;
+   struct list_headwait_list;
+};
+
+#define __SEMAPHORE_INITIALIZER(name, n)   \
+{  \
+   .lock   = __SPIN_LOCK_UNLOCKED((name).lock),\
+   .count  = n,\
+   .wait_list  = LIST_HEAD_INIT((name).wait_list), \
+}
+
+#define __DECLARE_SEMAPHORE_GENERIC(name, count) \
+   struct semaphore name = __SEMAPHORE_INITIALIZER(name, count)
+
+#define DECLARE_MUTEX(name)__DECLARE_SEMAPHORE_GENERIC(name, 1)
+ 
+static inline void sema_init(struct semaphore *sem, int val)
+{
+   *sem = (struct semaphore) __SEMAPHORE_INITIALIZER(*sem, val);
+}
+
+#define init_MUTEX(sem)sema_init(sem, 1)
+#define init_MUTEX_LOCKED(sem) sema_init(sem, 0)
+
+/*
+ * Attempt to acquire the semaphore.  If another task is already holding the
+ * semaphore, sleep until the semaphore is released.
+ */
+extern void fastcall down(struct semaphore *sem);
+
+/*
+ * As down(), except the sleep may be interrupted by a signal.  If it is,
+ * this function will return -EINTR.
+ */
+extern int __must_check fastcall down_interruptible(struct semaphore *sem);
+
+/*
+ * As down_interruptible(), except the sleep may only be interrupted by
+ * signals which are fatal to this process.
+ */
+extern int __must_check fastcall down_killable(struct semaphore *sem);
+
+/*
+ * As down, except this function will not sleep.  It will return 0 if it
+ * acquired the semaphore and 1 if the semaphore was contended.  This
+ * function may be called from any context, including interrupt and softirq.
+ */
+extern int __must_check fastcall down_trylock(struct semaphore *sem);
+
+/*
+ * Release the semaphore.  Unlike mutexes, up() may be called from any
+ * context and even by tasks which have never called down().
+ */
+extern void fastcall up(struct semaphore *sem);
+
+#endif /* __LINUX_SEMAPHORE_H */
diff --git a/kernel/semaphore.c b/kernel/semaphore.c
new file mode 100644
index 000..94f65a1
--- /dev/null
+++ b/kernel/semaphore.c
@@ -0,0 +1,208 @@
+/*
+ * Copyright (c) 2008 Intel Corporation
+ * Author: Matthew Wilcox <[EMAIL PROTECTED]>
+ *
+ * Distributed under the terms of the GNU GPL, version 2
+ */
+
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+
+/*
+ * Some notes on the implementation:
+ *
+ * down_trylock() and up() can be called from interrupt context.
+ * So we have to disable interrupts when taking the lock.
+ *
+ * The ->count variable, if positive, defines how many more tasks can
+ * acquire the semaphore.  If negative, 

Re: down_killable implementations for every architecture

2008-02-05 Thread Matthew Wilcox
On Tue, Jan 29, 2008 at 05:23:52AM +0100, Andi Kleen wrote:
 On Tuesday 29 January 2008 00:19, Matthew Wilcox wrote:
  As part of the TASK_KILLABLE changes, we're going to need
  down_killable().  Unfortunately, semaphores are implemented for every
  architecture, which we should probably fix at some point.
 
 It would be best to just change it now before doing further changes. Right now
 we have the bizarre situation that semaphores are more optimized
 with fast path inline assembly code than the far more critical spinlocks.
 But that clearly doesn't make much sense. So the best approach would
 be likely to just pick some generic C implementation from some architecture
 and use it everywhere.

We don't really have an appropriate one.  So I've invented my own.

 104 files changed, 338 insertions(+), 7335 deletions(-)

(and 228k).  That seems inappropriate to post.

Here's the whole patch (includes deletions from every architecture):
http://www.parisc-linux.org/~willy/generic-semaphore.diff

Here's the interesting/useful bit.  I've only tested it briefly on my
laptop -- it could be full of holes, but I've tried very hard to think
of all the interesting edge/race conditions with multiple
sleepers/wakers.

Please review.  I won't be around to respond to comments for another
four days.

diff --git a/include/linux/semaphore.h b/include/linux/semaphore.h
new file mode 100644
index 000..8e563bc
--- /dev/null
+++ b/include/linux/semaphore.h
@@ -0,0 +1,81 @@
+/*
+ * Copyright (c) 2008 Intel Corporation
+ * Author: Matthew Wilcox [EMAIL PROTECTED]
+ *
+ * Distributed under the terms of the GNU GPL, version 2
+ *
+ * Counting semaphores allow up to n tasks to acquire the semaphore
+ * simultaneously.
+ */
+#ifndef __LINUX_SEMAPHORE_H
+#define __LINUX_SEMAPHORE_H
+
+#include linux/list.h
+#include linux/spinlock.h
+
+/*
+ * The spinlock controls access to the other members of the semaphore.
+ * 'count' is decremented by every task which calls down*() and incremented
+ * by every call to up().  Thus, if it is positive, it indicates how many
+ * more tasks may acquire the lock.  If it is negative, it indicates how
+ * many tasks are waiting for the lock.  Tasks waiting for the lock are
+ * kept on the wait_list.
+ */
+struct semaphore {
+   spinlock_t  lock;
+   int count;
+   struct list_headwait_list;
+};
+
+#define __SEMAPHORE_INITIALIZER(name, n)   \
+{  \
+   .lock   = __SPIN_LOCK_UNLOCKED((name).lock),\
+   .count  = n,\
+   .wait_list  = LIST_HEAD_INIT((name).wait_list), \
+}
+
+#define __DECLARE_SEMAPHORE_GENERIC(name, count) \
+   struct semaphore name = __SEMAPHORE_INITIALIZER(name, count)
+
+#define DECLARE_MUTEX(name)__DECLARE_SEMAPHORE_GENERIC(name, 1)
+ 
+static inline void sema_init(struct semaphore *sem, int val)
+{
+   *sem = (struct semaphore) __SEMAPHORE_INITIALIZER(*sem, val);
+}
+
+#define init_MUTEX(sem)sema_init(sem, 1)
+#define init_MUTEX_LOCKED(sem) sema_init(sem, 0)
+
+/*
+ * Attempt to acquire the semaphore.  If another task is already holding the
+ * semaphore, sleep until the semaphore is released.
+ */
+extern void fastcall down(struct semaphore *sem);
+
+/*
+ * As down(), except the sleep may be interrupted by a signal.  If it is,
+ * this function will return -EINTR.
+ */
+extern int __must_check fastcall down_interruptible(struct semaphore *sem);
+
+/*
+ * As down_interruptible(), except the sleep may only be interrupted by
+ * signals which are fatal to this process.
+ */
+extern int __must_check fastcall down_killable(struct semaphore *sem);
+
+/*
+ * As down, except this function will not sleep.  It will return 0 if it
+ * acquired the semaphore and 1 if the semaphore was contended.  This
+ * function may be called from any context, including interrupt and softirq.
+ */
+extern int __must_check fastcall down_trylock(struct semaphore *sem);
+
+/*
+ * Release the semaphore.  Unlike mutexes, up() may be called from any
+ * context and even by tasks which have never called down().
+ */
+extern void fastcall up(struct semaphore *sem);
+
+#endif /* __LINUX_SEMAPHORE_H */
diff --git a/kernel/semaphore.c b/kernel/semaphore.c
new file mode 100644
index 000..94f65a1
--- /dev/null
+++ b/kernel/semaphore.c
@@ -0,0 +1,208 @@
+/*
+ * Copyright (c) 2008 Intel Corporation
+ * Author: Matthew Wilcox [EMAIL PROTECTED]
+ *
+ * Distributed under the terms of the GNU GPL, version 2
+ */
+
+#include linux/compiler.h
+#include linux/kernel.h
+#include linux/module.h
+#include linux/sched.h
+#include linux/semaphore.h
+#include linux/spinlock.h
+
+/*
+ * Some notes on the implementation:
+ *
+ * down_trylock() and up() can be called from interrupt context.
+ * So we have to disable interrupts when taking the lock.
+ *
+ * The 

Re: down_killable implementations for every architecture

2008-01-28 Thread Andi Kleen
On Tuesday 29 January 2008 00:19, Matthew Wilcox wrote:
> As part of the TASK_KILLABLE changes, we're going to need
> down_killable().  Unfortunately, semaphores are implemented for every
> architecture, which we should probably fix at some point.

It would be best to just change it now before doing further changes. Right now
we have the bizarre situation that semaphores are more optimized
with fast path inline assembly code than the far more critical spinlocks.
But that clearly doesn't make much sense. So the best approach would
be likely to just pick some generic C implementation from some architecture
and use it everywhere.

-Andi
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to [EMAIL PROTECTED]
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


down_killable implementations for every architecture

2008-01-28 Thread Matthew Wilcox

As part of the TASK_KILLABLE changes, we're going to need
down_killable().  Unfortunately, semaphores are implemented for every
architecture, which we should probably fix at some point.

On the plane ride down here, I did the necessary changes for each
architecture:

http://parisc-linux.org/~willy/down-killable/

I may have made mistakes.  Things to check:

 - The *_killable* functions should be exported for use by modules.
 - The down_killable implementation needs to check fatal_signal_pending,
   not signal_pending.
 - The task state needs to be set to TASK_KILLABLE, not
   TASK_INTERRUPTIBLE

It should only take a couple of minutes to verify your architecture.

-- 
Intel are signing my paycheques ... these opinions are still mine
"Bill, look, we understand that you're interested in selling us this
operating system, but compare it to ours.  We can't possibly take such
a retrograde step."
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to [EMAIL PROTECTED]
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


down_killable implementations for every architecture

2008-01-28 Thread Matthew Wilcox

As part of the TASK_KILLABLE changes, we're going to need
down_killable().  Unfortunately, semaphores are implemented for every
architecture, which we should probably fix at some point.

On the plane ride down here, I did the necessary changes for each
architecture:

http://parisc-linux.org/~willy/down-killable/

I may have made mistakes.  Things to check:

 - The *_killable* functions should be exported for use by modules.
 - The down_killable implementation needs to check fatal_signal_pending,
   not signal_pending.
 - The task state needs to be set to TASK_KILLABLE, not
   TASK_INTERRUPTIBLE

It should only take a couple of minutes to verify your architecture.

-- 
Intel are signing my paycheques ... these opinions are still mine
Bill, look, we understand that you're interested in selling us this
operating system, but compare it to ours.  We can't possibly take such
a retrograde step.
--
To unsubscribe from this list: send the line unsubscribe linux-kernel in
the body of a message to [EMAIL PROTECTED]
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


Re: down_killable implementations for every architecture

2008-01-28 Thread Andi Kleen
On Tuesday 29 January 2008 00:19, Matthew Wilcox wrote:
 As part of the TASK_KILLABLE changes, we're going to need
 down_killable().  Unfortunately, semaphores are implemented for every
 architecture, which we should probably fix at some point.

It would be best to just change it now before doing further changes. Right now
we have the bizarre situation that semaphores are more optimized
with fast path inline assembly code than the far more critical spinlocks.
But that clearly doesn't make much sense. So the best approach would
be likely to just pick some generic C implementation from some architecture
and use it everywhere.

-Andi
--
To unsubscribe from this list: send the line unsubscribe linux-kernel in
the body of a message to [EMAIL PROTECTED]
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/