diff options
author | Ralf Baechle <ralf@linux-mips.org> | 2000-02-04 07:40:19 +0000 |
---|---|---|
committer | Ralf Baechle <ralf@linux-mips.org> | 2000-02-04 07:40:19 +0000 |
commit | 33263fc5f9ac8e8cb2b22d06af3ce5ac1dd815e4 (patch) | |
tree | 2d1b86a40bef0958a68cf1a2eafbeb0667a70543 /include/asm-i386/semaphore.h | |
parent | 216f5f51aa02f8b113aa620ebc14a9631a217a00 (diff) |
Merge with Linux 2.3.32.
Diffstat (limited to 'include/asm-i386/semaphore.h')
-rw-r--r-- | include/asm-i386/semaphore.h | 191 |
1 files changed, 174 insertions, 17 deletions
diff --git a/include/asm-i386/semaphore.h b/include/asm-i386/semaphore.h index 7b0cddf96..3cdb0f6cd 100644 --- a/include/asm-i386/semaphore.h +++ b/include/asm-i386/semaphore.h @@ -30,7 +30,7 @@ #include <asm/system.h> #include <asm/atomic.h> -#include <linux/spinlock.h> +#include <asm/rwlock.h> #include <linux/wait.h> struct semaphore { @@ -111,10 +111,7 @@ extern inline void down(struct semaphore * sem) __asm__ __volatile__( "# atomic down operation\n\t" -#ifdef __SMP__ - "lock ; " -#endif - "decl (%0)\n\t" /* --sem->count */ + LOCK "decl (%0)\n\t" /* --sem->count */ "js 2f\n" "1:\n" ".section .text.lock,\"ax\"\n" @@ -136,10 +133,7 @@ extern inline int down_interruptible(struct semaphore * sem) __asm__ __volatile__( "# atomic interruptible down operation\n\t" -#ifdef __SMP__ - "lock ; " -#endif - "decl (%1)\n\t" /* --sem->count */ + LOCK "decl (%1)\n\t" /* --sem->count */ "js 2f\n\t" "xorl %0,%0\n" "1:\n" @@ -163,10 +157,7 @@ extern inline int down_trylock(struct semaphore * sem) __asm__ __volatile__( "# atomic interruptible down operation\n\t" -#ifdef __SMP__ - "lock ; " -#endif - "decl (%1)\n\t" /* --sem->count */ + LOCK "decl (%1)\n\t" /* --sem->count */ "js 2f\n\t" "xorl %0,%0\n" "1:\n" @@ -193,10 +184,7 @@ extern inline void up(struct semaphore * sem) #endif __asm__ __volatile__( "# atomic up operation\n\t" -#ifdef __SMP__ - "lock ; " -#endif - "incl (%0)\n\t" /* ++sem->count */ + LOCK "incl (%0)\n\t" /* ++sem->count */ "jle 2f\n" "1:\n" ".section .text.lock,\"ax\"\n" @@ -208,4 +196,173 @@ extern inline void up(struct semaphore * sem) :"memory"); } +/* rw mutexes (should that be mutices? =) -- throw rw + * spinlocks and semaphores together, and this is what we + * end up with... + * + * The lock is initialized to BIAS. This way, a writer + * subtracts BIAS ands gets 0 for the case of an uncontended + * lock. Readers decrement by 1 and see a positive value + * when uncontended, negative if there are writers waiting + * (in which case it goes to sleep). + * + * The value 0x01000000 supports up to 128 processors and + * lots of processes. BIAS must be chosen such that subl'ing + * BIAS once per CPU will result in the long remaining + * negative. + * + * In terms of fairness, this should result in the lock + * flopping back and forth between readers and writers + * under heavy use. + * + * -ben + */ +struct rw_semaphore { + atomic_t count; + volatile unsigned char write_bias_granted; + volatile unsigned char read_bias_granted; + volatile unsigned char pad1; + volatile unsigned char pad2; + wait_queue_head_t wait; + wait_queue_head_t write_bias_wait; +#if WAITQUEUE_DEBUG + long __magic; + atomic_t readers; + atomic_t writers; +#endif +}; + +#if WAITQUEUE_DEBUG +#define __RWSEM_DEBUG_INIT , ATOMIC_INIT(0), ATOMIC_INIT(0) +#else +#define __RWSEM_DEBUG_INIT /* */ +#endif + +#define __RWSEM_INITIALIZER(name) \ +{ ATOMIC_INIT(RW_LOCK_BIAS), 0, 0, 0, 0, __WAIT_QUEUE_HEAD_INITIALIZER((name).wait), \ + __WAIT_QUEUE_HEAD_INITIALIZER((name).write_bias_wait) \ + __SEM_DEBUG_INIT(name) __RWSEM_DEBUG_INIT } + +extern inline void init_rwsem(struct rw_semaphore *sem) +{ + atomic_set(&sem->count, RW_LOCK_BIAS); + sem->read_bias_granted = 0; + sem->write_bias_granted = 0; + init_waitqueue_head(&sem->wait); + init_waitqueue_head(&sem->write_bias_wait); +#if WAITQUEUE_DEBUG + sem->__magic = (long)&sem->__magic; + atomic_set(&sem->readers, 0); + atomic_set(&sem->writers, 0); +#endif +} + +/* we use FASTCALL convention for the helpers */ +extern struct rw_semaphore *FASTCALL(down_read_failed(struct rw_semaphore *sem)); +extern struct rw_semaphore *FASTCALL(down_write_failed(struct rw_semaphore *sem)); +extern struct rw_semaphore *FASTCALL(rwsem_wake(struct rw_semaphore *sem)); + +extern inline void down_read(struct rw_semaphore *sem) +{ +#if WAITQUEUE_DEBUG + if (sem->__magic != (long)&sem->__magic) + BUG(); +#endif + __build_read_lock(sem, "__down_read_failed"); +#if WAITQUEUE_DEBUG + if (sem->write_bias_granted) + BUG(); + if (atomic_read(&sem->writers)) + BUG(); + atomic_inc(&sem->readers); +#endif +} + +extern inline void down_write(struct rw_semaphore *sem) +{ +#if WAITQUEUE_DEBUG + if (sem->__magic != (long)&sem->__magic) + BUG(); +#endif + __build_write_lock(sem, "__down_write_failed"); +#if WAITQUEUE_DEBUG + if (atomic_read(&sem->writers)) + BUG(); + if (atomic_read(&sem->readers)) + BUG(); + if (sem->read_bias_granted) + BUG(); + if (sem->write_bias_granted) + BUG(); + atomic_inc(&sem->writers); +#endif +} + +/* When a reader does a release, the only significant + * case is when there was a writer waiting, and we've + * bumped the count to 0: we must wake the writer up. + */ +extern inline void __up_read(struct rw_semaphore *sem) +{ + __asm__ __volatile__( + "# up_read\n\t" + LOCK "incl (%%eax)\n\t" + "jz 2f\n" /* only do the wake if result == 0 (ie, a writer) */ + "1:\n\t" + ".section .text.lock,\"ax\"\n" + "2:\tcall __rwsem_wake\n\t" + "jmp 1b\n" + ".previous" + ::"a" (sem) + :"memory" + ); +} + +/* releasing the writer is easy -- just release it and + * wake up any sleepers. + */ +extern inline void __up_write(struct rw_semaphore *sem) +{ + __asm__ __volatile__( + "# up_write\n\t" + LOCK "addl $" RW_LOCK_BIAS_STR ",(%%eax)\n" + "jc 2f\n" /* only do the wake if the result was -'ve to 0/+'ve */ + "1:\n\t" + ".section .text.lock,\"ax\"\n" + "2:\tcall __rwsem_wake\n\t" + "jmp 1b\n" + ".previous" + ::"a" (sem) + :"memory" + ); +} + +extern inline void up_read(struct rw_semaphore *sem) +{ +#if WAITQUEUE_DEBUG + if (sem->write_bias_granted) + BUG(); + if (atomic_read(&sem->writers)) + BUG(); + atomic_dec(&sem->readers); +#endif + __up_read(sem); +} + +extern inline void up_write(struct rw_semaphore *sem) +{ +#if WAITQUEUE_DEBUG + if (sem->read_bias_granted) + BUG(); + if (sem->write_bias_granted) + BUG(); + if (atomic_read(&sem->readers)) + BUG(); + if (atomic_read(&sem->writers) != 1) + BUG(); + atomic_dec(&sem->writers); +#endif + __up_write(sem); +} + #endif |