Changeset 64e9cf4 in mainline for kernel/generic/src/synch/spinlock.c
- Timestamp:
- 2023-02-02T22:23:23Z (2 years ago)
- Branches:
- master, ticket/834-toolchain-update, topic/msim-upgrade, topic/simplify-dev-export
- Children:
- 8addb24a
- Parents:
- f114d40 (diff), b076dfb (diff)
Note: this is a merge changeset, the changes displayed below correspond to the merge itself.
Use the(diff)
links above to see all the changes relative to each parent. - File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
kernel/generic/src/synch/spinlock.c
rf114d40 r64e9cf4 1 1 /* 2 2 * Copyright (c) 2001-2004 Jakub Jermar 3 * Copyright (c) 2023 Jiří Zárevúcky 3 4 * All rights reserved. 4 5 * … … 36 37 */ 37 38 39 #include <arch/asm.h> 38 40 #include <synch/spinlock.h> 39 41 #include <atomic.h> … … 47 49 #include <cpu.h> 48 50 49 #ifdef CONFIG_SMP 51 #ifndef ARCH_SPIN_HINT 52 #define ARCH_SPIN_HINT() ((void)0) 53 #endif 50 54 51 55 /** Initialize spinlock … … 56 60 void spinlock_initialize(spinlock_t *lock, const char *name) 57 61 { 62 #ifdef CONFIG_SMP 58 63 atomic_flag_clear_explicit(&lock->flag, memory_order_relaxed); 59 64 #ifdef CONFIG_DEBUG_SPINLOCK 60 65 lock->name = name; 61 66 #endif 67 #endif 62 68 } 63 69 64 #ifdef CONFIG_DEBUG_SPINLOCK65 66 70 /** Lock spinlock 67 *68 * Lock spinlock.69 * This version has limitted ability to report70 * possible occurence of deadlock.71 71 * 72 72 * @param lock Pointer to spinlock_t structure. 73 73 * 74 74 */ 75 void spinlock_lock _debug(spinlock_t *lock)75 void spinlock_lock(spinlock_t *lock) 76 76 { 77 preemption_disable(); 78 79 #ifdef CONFIG_SMP 80 bool deadlock_reported = false; 77 81 size_t i = 0; 78 bool deadlock_reported = false;79 82 80 preemption_disable();81 83 while (atomic_flag_test_and_set_explicit(&lock->flag, memory_order_acquire)) { 84 ARCH_SPIN_HINT(); 85 86 #ifdef CONFIG_DEBUG_SPINLOCK 82 87 /* 83 88 * We need to be careful about particular locks … … 111 116 deadlock_reported = true; 112 117 } 118 #endif 113 119 } 120 121 /* Avoid compiler warning with debug disabled. */ 122 (void) i; 114 123 115 124 if (deadlock_reported) 116 125 printf("cpu%u: not deadlocked\n", CPU->id); 126 127 #endif 117 128 } 118 129 119 130 /** Unlock spinlock 120 131 * 121 * Unlock spinlock.122 *123 132 * @param sl Pointer to spinlock_t structure. 124 133 */ 125 void spinlock_unlock _debug(spinlock_t *lock)134 void spinlock_unlock(spinlock_t *lock) 126 135 { 136 #ifdef CONFIG_SMP 137 #ifdef CONFIG_DEBUG_SPINLOCK 127 138 ASSERT_SPINLOCK(spinlock_locked(lock), lock); 139 #endif 128 140 129 141 atomic_flag_clear_explicit(&lock->flag, memory_order_release); 142 #endif 143 130 144 preemption_enable(); 131 145 } 132 146 133 #endif 134 135 /** Lock spinlock conditionally 136 * 147 /** 137 148 * Lock spinlock conditionally. If the spinlock is not available 138 149 * at the moment, signal failure. … … 140 151 * @param lock Pointer to spinlock_t structure. 141 152 * 142 * @return Zero on failure, non-zero otherwise.153 * @return true on success. 143 154 * 144 155 */ … … 146 157 { 147 158 preemption_disable(); 159 160 #ifdef CONFIG_SMP 148 161 bool ret = !atomic_flag_test_and_set_explicit(&lock->flag, memory_order_acquire); 149 162 … … 152 165 153 166 return ret; 167 #else 168 return true; 169 #endif 154 170 } 155 171 … … 161 177 bool spinlock_locked(spinlock_t *lock) 162 178 { 179 #ifdef CONFIG_SMP 163 180 // NOTE: Atomic flag doesn't support simple atomic read (by design), 164 181 // so instead we test_and_set and then clear if necessary. … … 170 187 atomic_flag_clear_explicit(&lock->flag, memory_order_relaxed); 171 188 return ret; 172 } 173 189 #else 190 return true; 174 191 #endif 175 176 /** Initialize interrupts-disabled spinlock177 *178 * @param lock IRQ spinlock to be initialized.179 * @param name IRQ spinlock name.180 *181 */182 void irq_spinlock_initialize(irq_spinlock_t *lock, const char *name)183 {184 spinlock_initialize(&(lock->lock), name);185 lock->guard = false;186 lock->ipl = 0;187 }188 189 /** Lock interrupts-disabled spinlock190 *191 * Lock a spinlock which requires disabled interrupts.192 *193 * @param lock IRQ spinlock to be locked.194 * @param irq_dis If true, disables interrupts before locking the spinlock.195 * If false, interrupts are expected to be already disabled.196 *197 */198 void irq_spinlock_lock(irq_spinlock_t *lock, bool irq_dis)199 {200 if (irq_dis) {201 ipl_t ipl = interrupts_disable();202 spinlock_lock(&(lock->lock));203 204 lock->guard = true;205 lock->ipl = ipl;206 } else {207 ASSERT_IRQ_SPINLOCK(interrupts_disabled(), lock);208 209 spinlock_lock(&(lock->lock));210 ASSERT_IRQ_SPINLOCK(!lock->guard, lock);211 }212 }213 214 /** Unlock interrupts-disabled spinlock215 *216 * Unlock a spinlock which requires disabled interrupts.217 *218 * @param lock IRQ spinlock to be unlocked.219 * @param irq_res If true, interrupts are restored to previously220 * saved interrupt level.221 *222 */223 void irq_spinlock_unlock(irq_spinlock_t *lock, bool irq_res)224 {225 ASSERT_IRQ_SPINLOCK(interrupts_disabled(), lock);226 227 if (irq_res) {228 ASSERT_IRQ_SPINLOCK(lock->guard, lock);229 230 lock->guard = false;231 ipl_t ipl = lock->ipl;232 233 spinlock_unlock(&(lock->lock));234 interrupts_restore(ipl);235 } else {236 ASSERT_IRQ_SPINLOCK(!lock->guard, lock);237 spinlock_unlock(&(lock->lock));238 }239 }240 241 /** Lock interrupts-disabled spinlock242 *243 * Lock an interrupts-disabled spinlock conditionally. If the244 * spinlock is not available at the moment, signal failure.245 * Interrupts are expected to be already disabled.246 *247 * @param lock IRQ spinlock to be locked conditionally.248 *249 * @return Zero on failure, non-zero otherwise.250 *251 */252 bool irq_spinlock_trylock(irq_spinlock_t *lock)253 {254 ASSERT_IRQ_SPINLOCK(interrupts_disabled(), lock);255 bool ret = spinlock_trylock(&(lock->lock));256 257 ASSERT_IRQ_SPINLOCK((!ret) || (!lock->guard), lock);258 return ret;259 }260 261 /** Pass lock from one interrupts-disabled spinlock to another262 *263 * Pass lock from one IRQ spinlock to another IRQ spinlock264 * without enabling interrupts during the process.265 *266 * The first IRQ spinlock is supposed to be locked.267 *268 * @param unlock IRQ spinlock to be unlocked.269 * @param lock IRQ spinlock to be locked.270 *271 */272 void irq_spinlock_pass(irq_spinlock_t *unlock, irq_spinlock_t *lock)273 {274 ASSERT_IRQ_SPINLOCK(interrupts_disabled(), unlock);275 276 /* Pass guard from unlock to lock */277 bool guard = unlock->guard;278 ipl_t ipl = unlock->ipl;279 unlock->guard = false;280 281 spinlock_unlock(&(unlock->lock));282 spinlock_lock(&(lock->lock));283 284 ASSERT_IRQ_SPINLOCK(!lock->guard, lock);285 286 if (guard) {287 lock->guard = true;288 lock->ipl = ipl;289 }290 }291 292 /** Hand-over-hand locking of interrupts-disabled spinlocks293 *294 * Implement hand-over-hand locking between two interrupts-disabled295 * spinlocks without enabling interrupts during the process.296 *297 * The first IRQ spinlock is supposed to be locked.298 *299 * @param unlock IRQ spinlock to be unlocked.300 * @param lock IRQ spinlock to be locked.301 *302 */303 void irq_spinlock_exchange(irq_spinlock_t *unlock, irq_spinlock_t *lock)304 {305 ASSERT_IRQ_SPINLOCK(interrupts_disabled(), unlock);306 307 spinlock_lock(&(lock->lock));308 ASSERT_IRQ_SPINLOCK(!lock->guard, lock);309 310 /* Pass guard from unlock to lock */311 if (unlock->guard) {312 lock->guard = true;313 lock->ipl = unlock->ipl;314 unlock->guard = false;315 }316 317 spinlock_unlock(&(unlock->lock));318 }319 320 /** Find out whether the IRQ spinlock is currently locked.321 *322 * @param lock IRQ spinlock.323 * @return True if the IRQ spinlock is locked, false otherwise.324 */325 bool irq_spinlock_locked(irq_spinlock_t *ilock)326 {327 return spinlock_locked(&ilock->lock);328 192 } 329 193
Note:
See TracChangeset
for help on using the changeset viewer.