···67676868/*6969 * Read-write spinlocks, allowing multiple readers but only one writer.7070- * Linux rwlocks are unfair to writers; they can be starved for an indefinite7171- * time by readers. With care, they can also be taken in interrupt context.7070+ * Unfair locking as Writers could be starved indefinitely by Reader(s)7271 *7373- * In the PA-RISC implementation, we have a spinlock and a counter.7474- * Readers use the lock to serialise their access to the counter (which7575- * records how many readers currently hold the lock).7676- * Writers hold the spinlock, preventing any readers or other writers from7777- * grabbing the rwlock.7272+ * The spinlock itself is contained in @counter and access to it is7373+ * serialized with @lock_mutex.7874 */79758080-/* Note that we have to ensure interrupts are disabled in case we're8181- * interrupted by some other code that wants to grab the same read lock */8282-static __inline__ void arch_read_lock(arch_rwlock_t *rw)7676+/* 1 - lock taken successfully */7777+static inline int arch_read_trylock(arch_rwlock_t *rw)8378{7979+ int ret = 0;8480 unsigned long flags;8585- local_irq_save(flags);8686- arch_spin_lock_flags(&rw->lock, flags);8787- rw->counter++;8888- arch_spin_unlock(&rw->lock);8989- local_irq_restore(flags);9090-}91819292-/* Note that we have to ensure interrupts are disabled in case we're9393- * interrupted by some other code that wants to grab the same read lock */9494-static __inline__ void arch_read_unlock(arch_rwlock_t *rw)9595-{9696- unsigned long flags;9782 local_irq_save(flags);9898- arch_spin_lock_flags(&rw->lock, flags);9999- rw->counter--;100100- arch_spin_unlock(&rw->lock);101101- local_irq_restore(flags);102102-}8383+ arch_spin_lock(&(rw->lock_mutex));10384104104-/* Note that we have to ensure interrupts are disabled in case we're105105- * interrupted by some other code that wants to grab the same read lock */106106-static __inline__ int arch_read_trylock(arch_rwlock_t *rw)107107-{108108- unsigned long flags;109109- retry:110110- local_irq_save(flags);111111- if (arch_spin_trylock(&rw->lock)) {112112- rw->counter++;113113- arch_spin_unlock(&rw->lock);114114- local_irq_restore(flags);115115- return 1;8585+ /*8686+ * zero means writer holds the lock exclusively, deny Reader.8787+ * Otherwise grant lock to first/subseq reader8888+ */8989+ if (rw->counter > 0) {9090+ rw->counter--;9191+ ret = 1;11692 }117939494+ arch_spin_unlock(&(rw->lock_mutex));11895 local_irq_restore(flags);119119- /* If write-locked, we fail to acquire the lock */120120- if (rw->counter < 0)121121- return 0;12296123123- /* Wait until we have a realistic chance at the lock */124124- while (arch_spin_is_locked(&rw->lock) && rw->counter >= 0)9797+ return ret;9898+}9999+100100+/* 1 - lock taken successfully */101101+static inline int arch_write_trylock(arch_rwlock_t *rw)102102+{103103+ int ret = 0;104104+ unsigned long flags;105105+106106+ local_irq_save(flags);107107+ arch_spin_lock(&(rw->lock_mutex));108108+109109+ /*110110+ * If reader(s) hold lock (lock < __ARCH_RW_LOCK_UNLOCKED__),111111+ * deny writer. Otherwise if unlocked grant to writer112112+ * Hence the claim that Linux rwlocks are unfair to writers.113113+ * (can be starved for an indefinite time by readers).114114+ */115115+ if (rw->counter == __ARCH_RW_LOCK_UNLOCKED__) {116116+ rw->counter = 0;117117+ ret = 1;118118+ }119119+ arch_spin_unlock(&(rw->lock_mutex));120120+ local_irq_restore(flags);121121+122122+ return ret;123123+}124124+125125+static inline void arch_read_lock(arch_rwlock_t *rw)126126+{127127+ while (!arch_read_trylock(rw))125128 cpu_relax();126126-127127- goto retry;128129}129130130130-/* Note that we have to ensure interrupts are disabled in case we're131131- * interrupted by some other code that wants to read_trylock() this lock */132132-static __inline__ void arch_write_lock(arch_rwlock_t *rw)131131+static inline void arch_write_lock(arch_rwlock_t *rw)132132+{133133+ while (!arch_write_trylock(rw))134134+ cpu_relax();135135+}136136+137137+static inline void arch_read_unlock(arch_rwlock_t *rw)133138{134139 unsigned long flags;135135-retry:140140+136141 local_irq_save(flags);137137- arch_spin_lock_flags(&rw->lock, flags);138138-139139- if (rw->counter != 0) {140140- arch_spin_unlock(&rw->lock);141141- local_irq_restore(flags);142142-143143- while (rw->counter != 0)144144- cpu_relax();145145-146146- goto retry;147147- }148148-149149- rw->counter = -1; /* mark as write-locked */150150- mb();142142+ arch_spin_lock(&(rw->lock_mutex));143143+ rw->counter++;144144+ arch_spin_unlock(&(rw->lock_mutex));151145 local_irq_restore(flags);152146}153147154154-static __inline__ void arch_write_unlock(arch_rwlock_t *rw)155155-{156156- rw->counter = 0;157157- arch_spin_unlock(&rw->lock);158158-}159159-160160-/* Note that we have to ensure interrupts are disabled in case we're161161- * interrupted by some other code that wants to read_trylock() this lock */162162-static __inline__ int arch_write_trylock(arch_rwlock_t *rw)148148+static inline void arch_write_unlock(arch_rwlock_t *rw)163149{164150 unsigned long flags;165165- int result = 0;166151167152 local_irq_save(flags);168168- if (arch_spin_trylock(&rw->lock)) {169169- if (rw->counter == 0) {170170- rw->counter = -1;171171- result = 1;172172- } else {173173- /* Read-locked. Oh well. */174174- arch_spin_unlock(&rw->lock);175175- }176176- }153153+ arch_spin_lock(&(rw->lock_mutex));154154+ rw->counter = __ARCH_RW_LOCK_UNLOCKED__;155155+ arch_spin_unlock(&(rw->lock_mutex));177156 local_irq_restore(flags);178178-179179- return result;180157}181158182159#endif /* __ASM_SPINLOCK_H */
+11-3
arch/parisc/include/asm/spinlock_types.h
···1212#endif1313} arch_spinlock_t;14141515+1616+/* counter:1717+ * Unlocked : 0x0100_00001818+ * Read lock(s) : 0x00FF_FFFF to 0x01 (Multiple Readers decrement it)1919+ * Write lock : 0x0, but only if prior value is "unlocked" 0x0100_00002020+ */1521typedef struct {1616- arch_spinlock_t lock;1717- volatile int counter;2222+ arch_spinlock_t lock_mutex;2323+ volatile unsigned int counter;1824} arch_rwlock_t;19252020-#define __ARCH_RW_LOCK_UNLOCKED { __ARCH_SPIN_LOCK_UNLOCKED, 0 }2626+#define __ARCH_RW_LOCK_UNLOCKED__ 0x010000002727+#define __ARCH_RW_LOCK_UNLOCKED { .lock_mutex = __ARCH_SPIN_LOCK_UNLOCKED, \2828+ .counter = __ARCH_RW_LOCK_UNLOCKED__ }21292230#endif