summaryrefslogtreecommitdiffstats
path: root/include/asm-m68k/semaphore.h
diff options
context:
space:
mode:
authorRalf Baechle <ralf@linux-mips.org>1999-02-15 02:15:32 +0000
committerRalf Baechle <ralf@linux-mips.org>1999-02-15 02:15:32 +0000
commit86464aed71025541805e7b1515541aee89879e33 (patch)
treee01a457a4912a8553bc65524aa3125d51f29f810 /include/asm-m68k/semaphore.h
parent88f99939ecc6a95a79614574cb7d95ffccfc3466 (diff)
Merge with Linux 2.2.1.
Diffstat (limited to 'include/asm-m68k/semaphore.h')
-rw-r--r--include/asm-m68k/semaphore.h40
1 files changed, 34 insertions, 6 deletions
diff --git a/include/asm-m68k/semaphore.h b/include/asm-m68k/semaphore.h
index 50aabc1c8..9d05256df 100644
--- a/include/asm-m68k/semaphore.h
+++ b/include/asm-m68k/semaphore.h
@@ -3,6 +3,7 @@
#include <linux/config.h>
#include <linux/linkage.h>
+#include <asm/current.h>
#include <asm/system.h>
#include <asm/atomic.h>
@@ -16,18 +17,30 @@
struct semaphore {
atomic_t count;
+ unsigned long owner, owner_depth;
atomic_t waking;
struct wait_queue * wait;
};
-#define MUTEX ((struct semaphore) { ATOMIC_INIT(1), ATOMIC_INIT(0), NULL })
-#define MUTEX_LOCKED ((struct semaphore) { ATOMIC_INIT(0), ATOMIC_INIT(0), NULL })
+/*
+ * Because we want the non-contention case to be
+ * fast, we save the stack pointer into the "owner"
+ * field, and to get the true task pointer we have
+ * to do the bit masking. That moves the masking
+ * operation into the slow path.
+ */
+#define semaphore_owner(sem) \
+ ((struct task_struct *)((2*PAGE_MASK) & (sem)->owner))
+
+#define MUTEX ((struct semaphore) { ATOMIC_INIT(1), 0, 0, ATOMIC_INIT(0), NULL })
+#define MUTEX_LOCKED ((struct semaphore) { ATOMIC_INIT(0), 0, 1, ATOMIC_INIT(0), NULL })
asmlinkage void __down_failed(void /* special register calling convention */);
asmlinkage int __down_failed_interruptible(void /* params in registers */);
asmlinkage void __up_wakeup(void /* special register calling convention */);
extern void __down(struct semaphore * sem);
+extern int __down_interruptible(struct semaphore * sem);
extern void __up(struct semaphore * sem);
#define sema_init(sem, val) atomic_set(&((sem)->count), val)
@@ -37,7 +50,7 @@ static inline void wake_one_more(struct semaphore * sem)
atomic_inc(&sem->waking);
}
-static inline int waking_non_zero(struct semaphore *sem)
+static inline int waking_non_zero(struct semaphore *sem, struct task_struct *tsk)
{
#ifndef CONFIG_RMW_INSNS
unsigned long flags;
@@ -45,7 +58,9 @@ static inline int waking_non_zero(struct semaphore *sem)
save_flags(flags);
cli();
- if (atomic_read(&sem->waking) > 0) {
+ if (atomic_read(&sem->waking) > 0 || (owner_depth && semaphore_owner(sem) == tsk)) {
+ sem->owner = (unsigned long)tsk;
+ sem->owner_depth++;
atomic_dec(&sem->waking);
ret = 1;
}
@@ -55,7 +70,7 @@ static inline int waking_non_zero(struct semaphore *sem)
__asm__ __volatile__
("1: movel %2,%0\n"
- " jeq 3f\n"
+ " jeq 3f\n"
"2: movel %0,%1\n"
" subql #1,%1\n"
" casl %0,%1,%2\n"
@@ -64,6 +79,13 @@ static inline int waking_non_zero(struct semaphore *sem)
" jne 2b\n"
"3:"
: "=d" (ret), "=d" (tmp), "=m" (sem->waking));
+
+ ret |= ((sem->owner_depth != 0) && (semaphore_owner(sem) == tsk));
+ if (ret) {
+ sem->owner = (unsigned long)tsk;
+ sem->owner_depth++;
+ }
+
#endif
return ret;
}
@@ -79,7 +101,9 @@ extern inline void down(struct semaphore * sem)
__asm__ __volatile__(
"| atomic down operation\n\t"
"subql #1,%0@\n\t"
- "jmi 2f\n"
+ "jmi 2f\n\t"
+ "movel %%sp,4(%0)\n"
+ "movel #1,8(%0)\n\t"
"1:\n"
".section .text.lock,\"ax\"\n"
".even\n"
@@ -100,6 +124,9 @@ extern inline int down_interruptible(struct semaphore * sem)
"| atomic interruptible down operation\n\t"
"subql #1,%1@\n\t"
"jmi 2f\n\t"
+ "movel %%sp,4(%1)\n"
+ "moveql #1,%0\n"
+ "movel %0,8(%1)\n"
"clrl %0\n"
"1:\n"
".section .text.lock,\"ax\"\n"
@@ -124,6 +151,7 @@ extern inline void up(struct semaphore * sem)
register struct semaphore *sem1 __asm__ ("%a1") = sem;
__asm__ __volatile__(
"| atomic up operation\n\t"
+ "subql #1,8(%0)\n\t"
"addql #1,%0@\n\t"
"jle 2f\n"
"1:\n"