[PATCH] unify x86/x86-64 semaphore code
Benjamin LaHaise [Sat, 3 Sep 2005 22:56:52 +0000 (15:56 -0700)]
This patch moves the common code in x86 and x86-64's semaphore.c into a
single file in lib/semaphore-sleepers.c.  The arch specific asm stubs are
left in the arch tree (in semaphore.c for i386 and in the asm for x86-64).
There should be no changes in code/functionality with this patch.

Signed-off-by: Benjamin LaHaise <benjamin.c.lahaise@intel.com>
Cc: Andi Kleen <ak@muc.de>
Signed-off-by: Jeff Dike <jdike@addtoit.com>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>

arch/i386/Kconfig
arch/i386/kernel/semaphore.c
arch/um/Kconfig_i386
arch/um/Kconfig_x86_64
arch/um/sys-x86_64/Makefile
arch/x86_64/Kconfig
arch/x86_64/kernel/Makefile
lib/Makefile
lib/semaphore-sleepers.c [moved from arch/x86_64/kernel/semaphore.c with 94% similarity]

index dcb0ad0..3b3b017 100644 (file)
@@ -14,6 +14,10 @@ config X86
          486, 586, Pentiums, and various instruction-set-compatible chips by
          AMD, Cyrix, and others.
 
+config SEMAPHORE_SLEEPERS
+       bool
+       default y
+
 config MMU
        bool
        default y
index 469f496..7455ab6 100644 (file)
  * rw semaphores implemented November 1999 by Benjamin LaHaise <bcrl@kvack.org>
  */
 #include <linux/config.h>
-#include <linux/sched.h>
-#include <linux/err.h>
-#include <linux/init.h>
 #include <asm/semaphore.h>
 
 /*
- * Semaphores are implemented using a two-way counter:
- * The "count" variable is decremented for each process
- * that tries to acquire the semaphore, while the "sleeping"
- * variable is a count of such acquires.
- *
- * Notably, the inline "up()" and "down()" functions can
- * efficiently test if they need to do any extra work (up
- * needs to do something only if count was negative before
- * the increment operation.
- *
- * "sleeping" and the contention routine ordering is protected
- * by the spinlock in the semaphore's waitqueue head.
- *
- * Note that these functions are only called when there is
- * contention on the lock, and as such all this is the
- * "non-critical" part of the whole semaphore business. The
- * critical part is the inline stuff in <asm/semaphore.h>
- * where we want to avoid any extra jumps and calls.
- */
-
-/*
- * Logic:
- *  - only on a boundary condition do we need to care. When we go
- *    from a negative count to a non-negative, we wake people up.
- *  - when we go from a non-negative count to a negative do we
- *    (a) synchronize with the "sleeper" count and (b) make sure
- *    that we're on the wakeup list before we synchronize so that
- *    we cannot lose wakeup events.
- */
-
-static fastcall void __attribute_used__  __up(struct semaphore *sem)
-{
-       wake_up(&sem->wait);
-}
-
-static fastcall void __attribute_used__ __sched __down(struct semaphore * sem)
-{
-       struct task_struct *tsk = current;
-       DECLARE_WAITQUEUE(wait, tsk);
-       unsigned long flags;
-
-       tsk->state = TASK_UNINTERRUPTIBLE;
-       spin_lock_irqsave(&sem->wait.lock, flags);
-       add_wait_queue_exclusive_locked(&sem->wait, &wait);
-
-       sem->sleepers++;
-       for (;;) {
-               int sleepers = sem->sleepers;
-
-               /*
-                * Add "everybody else" into it. They aren't
-                * playing, because we own the spinlock in
-                * the wait_queue_head.
-                */
-               if (!atomic_add_negative(sleepers - 1, &sem->count)) {
-                       sem->sleepers = 0;
-                       break;
-               }
-               sem->sleepers = 1;      /* us - see -1 above */
-               spin_unlock_irqrestore(&sem->wait.lock, flags);
-
-               schedule();
-
-               spin_lock_irqsave(&sem->wait.lock, flags);
-               tsk->state = TASK_UNINTERRUPTIBLE;
-       }
-       remove_wait_queue_locked(&sem->wait, &wait);
-       wake_up_locked(&sem->wait);
-       spin_unlock_irqrestore(&sem->wait.lock, flags);
-       tsk->state = TASK_RUNNING;
-}
-
-static fastcall int __attribute_used__ __sched __down_interruptible(struct semaphore * sem)
-{
-       int retval = 0;
-       struct task_struct *tsk = current;
-       DECLARE_WAITQUEUE(wait, tsk);
-       unsigned long flags;
-
-       tsk->state = TASK_INTERRUPTIBLE;
-       spin_lock_irqsave(&sem->wait.lock, flags);
-       add_wait_queue_exclusive_locked(&sem->wait, &wait);
-
-       sem->sleepers++;
-       for (;;) {
-               int sleepers = sem->sleepers;
-
-               /*
-                * With signals pending, this turns into
-                * the trylock failure case - we won't be
-                * sleeping, and we* can't get the lock as
-                * it has contention. Just correct the count
-                * and exit.
-                */
-               if (signal_pending(current)) {
-                       retval = -EINTR;
-                       sem->sleepers = 0;
-                       atomic_add(sleepers, &sem->count);
-                       break;
-               }
-
-               /*
-                * Add "everybody else" into it. They aren't
-                * playing, because we own the spinlock in
-                * wait_queue_head. The "-1" is because we're
-                * still hoping to get the semaphore.
-                */
-               if (!atomic_add_negative(sleepers - 1, &sem->count)) {
-                       sem->sleepers = 0;
-                       break;
-               }
-               sem->sleepers = 1;      /* us - see -1 above */
-               spin_unlock_irqrestore(&sem->wait.lock, flags);
-
-               schedule();
-
-               spin_lock_irqsave(&sem->wait.lock, flags);
-               tsk->state = TASK_INTERRUPTIBLE;
-       }
-       remove_wait_queue_locked(&sem->wait, &wait);
-       wake_up_locked(&sem->wait);
-       spin_unlock_irqrestore(&sem->wait.lock, flags);
-
-       tsk->state = TASK_RUNNING;
-       return retval;
-}
-
-/*
- * Trylock failed - make sure we correct for
- * having decremented the count.
- *
- * We could have done the trylock with a
- * single "cmpxchg" without failure cases,
- * but then it wouldn't work on a 386.
- */
-static fastcall int __attribute_used__ __down_trylock(struct semaphore * sem)
-{
-       int sleepers;
-       unsigned long flags;
-
-       spin_lock_irqsave(&sem->wait.lock, flags);
-       sleepers = sem->sleepers + 1;
-       sem->sleepers = 0;
-
-       /*
-        * Add "everybody else" and us into it. They aren't
-        * playing, because we own the spinlock in the
-        * wait_queue_head.
-        */
-       if (!atomic_add_negative(sleepers, &sem->count)) {
-               wake_up_locked(&sem->wait);
-       }
-
-       spin_unlock_irqrestore(&sem->wait.lock, flags);
-       return 1;
-}
-
-
-/*
  * The semaphore operations have a special calling sequence that
  * allow us to do a simpler in-line version of them. These routines
  * need to convert that sequence back into the C sequence when
index 27c18a8..8ad156a 100644 (file)
@@ -6,6 +6,10 @@ config 64BIT
        bool
        default n
 
+config SEMAPHORE_SLEEPERS
+       bool
+       default y
+
 config TOP_ADDR
        hex
        default 0xc0000000 if !HOST_2G_2G
index 735a047..6e5357c 100644 (file)
@@ -6,6 +6,10 @@ config 64BIT
        bool
        default y
 
+config SEMAPHORE_SLEEPERS
+       bool
+       default y
+
 config TOP_ADDR
        hex
        default 0x80000000
index 7488206..736d3ed 100644 (file)
@@ -6,7 +6,7 @@
 
 #XXX: why into lib-y?
 lib-y = bitops.o bugs.o csum-partial.o delay.o fault.o mem.o memcpy.o \
-       ptrace.o ptrace_user.o semaphore.o sigcontext.o signal.o stub.o \
+       ptrace.o ptrace_user.o sigcontext.o signal.o stub.o \
        stub_segv.o syscalls.o syscall_table.o sysrq.o thunk.o
 
 obj-y := ksyms.o
@@ -15,7 +15,7 @@ obj-$(CONFIG_MODULES) += module.o um_module.o
 USER_OBJS := ptrace_user.o sigcontext.o
 
 SYMLINKS = bitops.c csum-copy.S csum-partial.c csum-wrappers.c memcpy.S \
-       semaphore.c thunk.S module.c
+       thunk.S module.c
 
 include arch/um/scripts/Makefile.rules
 
@@ -24,7 +24,6 @@ csum-copy.S-dir = lib
 csum-partial.c-dir = lib
 csum-wrappers.c-dir = lib
 memcpy.S-dir = lib
-semaphore.c-dir = kernel
 thunk.S-dir = lib
 module.c-dir = kernel
 
index 660a03a..75e52c5 100644 (file)
@@ -24,6 +24,10 @@ config X86
        bool
        default y
 
+config SEMAPHORE_SLEEPERS
+       bool
+       default y
+
 config MMU
        bool
        default y
index 48f9e2c..427501a 100644 (file)
@@ -4,7 +4,7 @@
 
 extra-y        := head.o head64.o init_task.o vmlinux.lds
 EXTRA_AFLAGS   := -traditional
-obj-y  := process.o semaphore.o signal.o entry.o traps.o irq.o \
+obj-y  := process.o signal.o entry.o traps.o irq.o \
                ptrace.o time.o ioport.o ldt.o setup.o i8259.o sys_x86_64.o \
                x8664_ksyms.o i387.o syscall.o vsyscall.o \
                setup64.o bootflag.o e820.o reboot.o quirks.o
index 52f8338..3e2bd0d 100644 (file)
@@ -18,6 +18,7 @@ endif
 
 lib-$(CONFIG_RWSEM_GENERIC_SPINLOCK) += rwsem-spinlock.o
 lib-$(CONFIG_RWSEM_XCHGADD_ALGORITHM) += rwsem.o
+lib-$(CONFIG_SEMAPHORE_SLEEPERS) += semaphore-sleepers.o
 lib-$(CONFIG_GENERIC_FIND_NEXT_BIT) += find_next_bit.o
 obj-$(CONFIG_LOCK_KERNEL) += kernel_lock.o
 obj-$(CONFIG_DEBUG_PREEMPT) += smp_processor_id.o
similarity index 94%
rename from arch/x86_64/kernel/semaphore.c
rename to lib/semaphore-sleepers.c
index 48f7c18..4d5f188 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * x86_64 semaphore implementation.
+ * i386 and x86-64 semaphore implementation.
  *
  * (C) Copyright 1999 Linus Torvalds
  *
@@ -14,9 +14,8 @@
  */
 #include <linux/config.h>
 #include <linux/sched.h>
+#include <linux/err.h>
 #include <linux/init.h>
-#include <asm/errno.h>
-
 #include <asm/semaphore.h>
 
 /*
  *    we cannot lose wakeup events.
  */
 
-void __up(struct semaphore *sem)
+fastcall void __up(struct semaphore *sem)
 {
        wake_up(&sem->wait);
 }
 
-void __sched __down(struct semaphore * sem)
+fastcall void __sched __down(struct semaphore * sem)
 {
        struct task_struct *tsk = current;
        DECLARE_WAITQUEUE(wait, tsk);
@@ -92,7 +91,7 @@ void __sched __down(struct semaphore * sem)
        tsk->state = TASK_RUNNING;
 }
 
-int __sched __down_interruptible(struct semaphore * sem)
+fastcall int __sched __down_interruptible(struct semaphore * sem)
 {
        int retval = 0;
        struct task_struct *tsk = current;
@@ -155,7 +154,7 @@ int __sched __down_interruptible(struct semaphore * sem)
  * single "cmpxchg" without failure cases,
  * but then it wouldn't work on a 386.
  */
-int __down_trylock(struct semaphore * sem)
+fastcall int __down_trylock(struct semaphore * sem)
 {
        int sleepers;
        unsigned long flags;
@@ -176,5 +175,3 @@ int __down_trylock(struct semaphore * sem)
        spin_unlock_irqrestore(&sem->wait.lock, flags);
        return 1;
 }
-
-