~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/arch/arc/include/asm/spinlock.h

Version: ~ [ linux-5.12-rc1 ] ~ [ linux-5.11.2 ] ~ [ linux-5.10.19 ] ~ [ linux-5.9.16 ] ~ [ linux-5.8.18 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.101 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.177 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.222 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.258 ] ~ [ linux-4.8.17 ] ~ [ linux-4.7.10 ] ~ [ linux-4.6.7 ] ~ [ linux-4.5.7 ] ~ [ linux-4.4.258 ] ~ [ linux-4.3.6 ] ~ [ linux-4.2.8 ] ~ [ linux-4.1.52 ] ~ [ linux-4.0.9 ] ~ [ linux-3.18.140 ] ~ [ linux-3.16.85 ] ~ [ linux-3.14.79 ] ~ [ linux-3.12.74 ] ~ [ linux-3.10.108 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.5 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  1 /*
  2  * Copyright (C) 2004, 2007-2010, 2011-2012 Synopsys, Inc. (www.synopsys.com)
  3  *
  4  * This program is free software; you can redistribute it and/or modify
  5  * it under the terms of the GNU General Public License version 2 as
  6  * published by the Free Software Foundation.
  7  */
  8 
  9 #ifndef __ASM_SPINLOCK_H
 10 #define __ASM_SPINLOCK_H
 11 
 12 #include <asm/spinlock_types.h>
 13 #include <asm/processor.h>
 14 #include <asm/barrier.h>
 15 
 16 #define arch_spin_is_locked(x)  ((x)->slock != __ARCH_SPIN_LOCK_UNLOCKED__)
 17 #define arch_spin_lock_flags(lock, flags)       arch_spin_lock(lock)
 18 #define arch_spin_unlock_wait(x) \
 19         do { while (arch_spin_is_locked(x)) cpu_relax(); } while (0)
 20 
 21 static inline void arch_spin_lock(arch_spinlock_t *lock)
 22 {
 23         unsigned int tmp = __ARCH_SPIN_LOCK_LOCKED__;
 24 
 25         /*
 26          * This smp_mb() is technically superfluous, we only need the one
 27          * after the lock for providing the ACQUIRE semantics.
 28          * However doing the "right" thing was regressing hackbench
 29          * so keeping this, pending further investigation
 30          */
 31         smp_mb();
 32 
 33         __asm__ __volatile__(
 34         "1:     ex  %0, [%1]            \n"
 35         "       breq  %0, %2, 1b        \n"
 36         : "+&r" (tmp)
 37         : "r"(&(lock->slock)), "ir"(__ARCH_SPIN_LOCK_LOCKED__)
 38         : "memory");
 39 
 40         /*
 41          * ACQUIRE barrier to ensure load/store after taking the lock
 42          * don't "bleed-up" out of the critical section (leak-in is allowed)
 43          * http://www.spinics.net/lists/kernel/msg2010409.html
 44          *
 45          * ARCv2 only has load-load, store-store and all-all barrier
 46          * thus need the full all-all barrier
 47          */
 48         smp_mb();
 49 }
 50 
 51 static inline int arch_spin_trylock(arch_spinlock_t *lock)
 52 {
 53         unsigned int tmp = __ARCH_SPIN_LOCK_LOCKED__;
 54 
 55         smp_mb();
 56 
 57         __asm__ __volatile__(
 58         "1:     ex  %0, [%1]            \n"
 59         : "+r" (tmp)
 60         : "r"(&(lock->slock))
 61         : "memory");
 62 
 63         smp_mb();
 64 
 65         return (tmp == __ARCH_SPIN_LOCK_UNLOCKED__);
 66 }
 67 
 68 static inline void arch_spin_unlock(arch_spinlock_t *lock)
 69 {
 70         unsigned int tmp = __ARCH_SPIN_LOCK_UNLOCKED__;
 71 
 72         /*
 73          * RELEASE barrier: given the instructions avail on ARCv2, full barrier
 74          * is the only option
 75          */
 76         smp_mb();
 77 
 78         __asm__ __volatile__(
 79         "       ex  %0, [%1]            \n"
 80         : "+r" (tmp)
 81         : "r"(&(lock->slock))
 82         : "memory");
 83 
 84         /*
 85          * superfluous, but keeping for now - see pairing version in
 86          * arch_spin_lock above
 87          */
 88         smp_mb();
 89 }
 90 
 91 /*
 92  * Read-write spinlocks, allowing multiple readers but only one writer.
 93  *
 94  * The spinlock itself is contained in @counter and access to it is
 95  * serialized with @lock_mutex.
 96  *
 97  * Unfair locking as Writers could be starved indefinitely by Reader(s)
 98  */
 99 
100 /* Would read_trylock() succeed? */
101 #define arch_read_can_lock(x)   ((x)->counter > 0)
102 
103 /* Would write_trylock() succeed? */
104 #define arch_write_can_lock(x)  ((x)->counter == __ARCH_RW_LOCK_UNLOCKED__)
105 
106 /* 1 - lock taken successfully */
107 static inline int arch_read_trylock(arch_rwlock_t *rw)
108 {
109         int ret = 0;
110 
111         arch_spin_lock(&(rw->lock_mutex));
112 
113         /*
114          * zero means writer holds the lock exclusively, deny Reader.
115          * Otherwise grant lock to first/subseq reader
116          */
117         if (rw->counter > 0) {
118                 rw->counter--;
119                 ret = 1;
120         }
121 
122         arch_spin_unlock(&(rw->lock_mutex));
123 
124         smp_mb();
125         return ret;
126 }
127 
128 /* 1 - lock taken successfully */
129 static inline int arch_write_trylock(arch_rwlock_t *rw)
130 {
131         int ret = 0;
132 
133         arch_spin_lock(&(rw->lock_mutex));
134 
135         /*
136          * If reader(s) hold lock (lock < __ARCH_RW_LOCK_UNLOCKED__),
137          * deny writer. Otherwise if unlocked grant to writer
138          * Hence the claim that Linux rwlocks are unfair to writers.
139          * (can be starved for an indefinite time by readers).
140          */
141         if (rw->counter == __ARCH_RW_LOCK_UNLOCKED__) {
142                 rw->counter = 0;
143                 ret = 1;
144         }
145         arch_spin_unlock(&(rw->lock_mutex));
146 
147         return ret;
148 }
149 
150 static inline void arch_read_lock(arch_rwlock_t *rw)
151 {
152         while (!arch_read_trylock(rw))
153                 cpu_relax();
154 }
155 
156 static inline void arch_write_lock(arch_rwlock_t *rw)
157 {
158         while (!arch_write_trylock(rw))
159                 cpu_relax();
160 }
161 
162 static inline void arch_read_unlock(arch_rwlock_t *rw)
163 {
164         arch_spin_lock(&(rw->lock_mutex));
165         rw->counter++;
166         arch_spin_unlock(&(rw->lock_mutex));
167 }
168 
169 static inline void arch_write_unlock(arch_rwlock_t *rw)
170 {
171         arch_spin_lock(&(rw->lock_mutex));
172         rw->counter = __ARCH_RW_LOCK_UNLOCKED__;
173         arch_spin_unlock(&(rw->lock_mutex));
174 }
175 
176 #define arch_read_lock_flags(lock, flags)       arch_read_lock(lock)
177 #define arch_write_lock_flags(lock, flags)      arch_write_lock(lock)
178 
179 #define arch_spin_relax(lock)   cpu_relax()
180 #define arch_read_relax(lock)   cpu_relax()
181 #define arch_write_relax(lock)  cpu_relax()
182 
183 #endif /* __ASM_SPINLOCK_H */
184 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | Wiki (Japanese) | Wiki (English) | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

osdn.jp