source: mainline/kernel/generic/src/synch/spinlock.c@ bf2042f9

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since bf2042f9 was a35b458, checked in by Jiří Zárevúcky <zarevucky.jiri@…>, 7 years ago

style: Remove trailing whitespace on _all_ lines, including empty ones, for particular file types.

Command used: tools/srepl '\s\+$' '' -- *.c *.h *.py *.sh *.s *.S *.ag

Currently, whitespace on empty lines is very inconsistent.
There are two basic choices: Either remove the whitespace, or keep empty lines
indented to the level of surrounding code. The former is AFAICT more common,
and also much easier to do automatically.

Alternatively, we could write script for automatic indentation, and use that
instead. However, if such a script exists, it's possible to use the indented
style locally, by having the editor apply relevant conversions on load/save,
without affecting remote repository. IMO, it makes more sense to adopt
the simpler rule.

  • Property mode set to 100644
File size: 8.3 KB
Line 
1/*
2 * Copyright (c) 2001-2004 Jakub Jermar
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * - Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * - Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * - The name of the author may not be used to endorse or promote products
15 * derived from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29/** @addtogroup sync
30 * @{
31 */
32
33/**
34 * @file
35 * @brief Spinlocks.
36 */
37
38#include <synch/spinlock.h>
39#include <atomic.h>
40#include <arch/barrier.h>
41#include <arch.h>
42#include <preemption.h>
43#include <print.h>
44#include <debug.h>
45#include <symtab.h>
46#include <stacktrace.h>
47#include <cpu.h>
48
49#ifdef CONFIG_SMP
50
51/** Initialize spinlock
52 *
53 * @param sl Pointer to spinlock_t structure.
54 *
55 */
56void spinlock_initialize(spinlock_t *lock, const char *name)
57{
58 atomic_set(&lock->val, 0);
59#ifdef CONFIG_DEBUG_SPINLOCK
60 lock->name = name;
61#endif
62}
63
64#ifdef CONFIG_DEBUG_SPINLOCK
65
66/** Lock spinlock
67 *
68 * Lock spinlock.
69 * This version has limitted ability to report
70 * possible occurence of deadlock.
71 *
72 * @param lock Pointer to spinlock_t structure.
73 *
74 */
75void spinlock_lock_debug(spinlock_t *lock)
76{
77 size_t i = 0;
78 bool deadlock_reported = false;
79
80 preemption_disable();
81 while (test_and_set(&lock->val)) {
82 /*
83 * We need to be careful about particular locks
84 * which are directly used to report deadlocks
85 * via printf() (and recursively other functions).
86 * This conserns especially printf_lock and the
87 * framebuffer lock.
88 *
89 * Any lock whose name is prefixed by "*" will be
90 * ignored by this deadlock detection routine
91 * as this might cause an infinite recursion.
92 * We trust our code that there is no possible deadlock
93 * caused by these locks (except when an exception
94 * is triggered for instance by printf()).
95 *
96 * We encountered false positives caused by very
97 * slow framebuffer interaction (especially when
98 * run in a simulator) that caused problems with both
99 * printf_lock and the framebuffer lock.
100 */
101 if (lock->name[0] == '*')
102 continue;
103
104 if (i++ > DEADLOCK_THRESHOLD) {
105 printf("cpu%u: looping on spinlock %p:%s, "
106 "caller=%p (%s)\n", CPU->id, lock, lock->name,
107 (void *) CALLER, symtab_fmt_name_lookup(CALLER));
108 stack_trace();
109
110 i = 0;
111 deadlock_reported = true;
112 }
113 }
114
115 if (deadlock_reported)
116 printf("cpu%u: not deadlocked\n", CPU->id);
117
118 /*
119 * Prevent critical section code from bleeding out this way up.
120 */
121 CS_ENTER_BARRIER();
122}
123
124/** Unlock spinlock
125 *
126 * Unlock spinlock.
127 *
128 * @param sl Pointer to spinlock_t structure.
129 */
130void spinlock_unlock_debug(spinlock_t *lock)
131{
132 ASSERT_SPINLOCK(spinlock_locked(lock), lock);
133
134 /*
135 * Prevent critical section code from bleeding out this way down.
136 */
137 CS_LEAVE_BARRIER();
138
139 atomic_set(&lock->val, 0);
140 preemption_enable();
141}
142
143#endif
144
145/** Lock spinlock conditionally
146 *
147 * Lock spinlock conditionally. If the spinlock is not available
148 * at the moment, signal failure.
149 *
150 * @param lock Pointer to spinlock_t structure.
151 *
152 * @return Zero on failure, non-zero otherwise.
153 *
154 */
155bool spinlock_trylock(spinlock_t *lock)
156{
157 preemption_disable();
158 bool ret = !test_and_set(&lock->val);
159
160 /*
161 * Prevent critical section code from bleeding out this way up.
162 */
163 CS_ENTER_BARRIER();
164
165 if (!ret)
166 preemption_enable();
167
168 return ret;
169}
170
171/** Find out whether the spinlock is currently locked.
172 *
173 * @param lock Spinlock.
174 * @return True if the spinlock is locked, false otherwise.
175 */
176bool spinlock_locked(spinlock_t *lock)
177{
178 return atomic_get(&lock->val) != 0;
179}
180
181#endif
182
183/** Initialize interrupts-disabled spinlock
184 *
185 * @param lock IRQ spinlock to be initialized.
186 * @param name IRQ spinlock name.
187 *
188 */
189void irq_spinlock_initialize(irq_spinlock_t *lock, const char *name)
190{
191 spinlock_initialize(&(lock->lock), name);
192 lock->guard = false;
193 lock->ipl = 0;
194}
195
196/** Lock interrupts-disabled spinlock
197 *
198 * Lock a spinlock which requires disabled interrupts.
199 *
200 * @param lock IRQ spinlock to be locked.
201 * @param irq_dis If true, disables interrupts before locking the spinlock.
202 * If false, interrupts are expected to be already disabled.
203 *
204 */
205void irq_spinlock_lock(irq_spinlock_t *lock, bool irq_dis)
206{
207 if (irq_dis) {
208 ipl_t ipl = interrupts_disable();
209 spinlock_lock(&(lock->lock));
210
211 lock->guard = true;
212 lock->ipl = ipl;
213 } else {
214 ASSERT_IRQ_SPINLOCK(interrupts_disabled(), lock);
215
216 spinlock_lock(&(lock->lock));
217 ASSERT_IRQ_SPINLOCK(!lock->guard, lock);
218 }
219}
220
221/** Unlock interrupts-disabled spinlock
222 *
223 * Unlock a spinlock which requires disabled interrupts.
224 *
225 * @param lock IRQ spinlock to be unlocked.
226 * @param irq_res If true, interrupts are restored to previously
227 * saved interrupt level.
228 *
229 */
230void irq_spinlock_unlock(irq_spinlock_t *lock, bool irq_res)
231{
232 ASSERT_IRQ_SPINLOCK(interrupts_disabled(), lock);
233
234 if (irq_res) {
235 ASSERT_IRQ_SPINLOCK(lock->guard, lock);
236
237 lock->guard = false;
238 ipl_t ipl = lock->ipl;
239
240 spinlock_unlock(&(lock->lock));
241 interrupts_restore(ipl);
242 } else {
243 ASSERT_IRQ_SPINLOCK(!lock->guard, lock);
244 spinlock_unlock(&(lock->lock));
245 }
246}
247
248/** Lock interrupts-disabled spinlock
249 *
250 * Lock an interrupts-disabled spinlock conditionally. If the
251 * spinlock is not available at the moment, signal failure.
252 * Interrupts are expected to be already disabled.
253 *
254 * @param lock IRQ spinlock to be locked conditionally.
255 *
256 * @return Zero on failure, non-zero otherwise.
257 *
258 */
259bool irq_spinlock_trylock(irq_spinlock_t *lock)
260{
261 ASSERT_IRQ_SPINLOCK(interrupts_disabled(), lock);
262 bool ret = spinlock_trylock(&(lock->lock));
263
264 ASSERT_IRQ_SPINLOCK((!ret) || (!lock->guard), lock);
265 return ret;
266}
267
268/** Pass lock from one interrupts-disabled spinlock to another
269 *
270 * Pass lock from one IRQ spinlock to another IRQ spinlock
271 * without enabling interrupts during the process.
272 *
273 * The first IRQ spinlock is supposed to be locked.
274 *
275 * @param unlock IRQ spinlock to be unlocked.
276 * @param lock IRQ spinlock to be locked.
277 *
278 */
279void irq_spinlock_pass(irq_spinlock_t *unlock, irq_spinlock_t *lock)
280{
281 ASSERT_IRQ_SPINLOCK(interrupts_disabled(), unlock);
282
283 /* Pass guard from unlock to lock */
284 bool guard = unlock->guard;
285 ipl_t ipl = unlock->ipl;
286 unlock->guard = false;
287
288 spinlock_unlock(&(unlock->lock));
289 spinlock_lock(&(lock->lock));
290
291 ASSERT_IRQ_SPINLOCK(!lock->guard, lock);
292
293 if (guard) {
294 lock->guard = true;
295 lock->ipl = ipl;
296 }
297}
298
299/** Hand-over-hand locking of interrupts-disabled spinlocks
300 *
301 * Implement hand-over-hand locking between two interrupts-disabled
302 * spinlocks without enabling interrupts during the process.
303 *
304 * The first IRQ spinlock is supposed to be locked.
305 *
306 * @param unlock IRQ spinlock to be unlocked.
307 * @param lock IRQ spinlock to be locked.
308 *
309 */
310void irq_spinlock_exchange(irq_spinlock_t *unlock, irq_spinlock_t *lock)
311{
312 ASSERT_IRQ_SPINLOCK(interrupts_disabled(), unlock);
313
314 spinlock_lock(&(lock->lock));
315 ASSERT_IRQ_SPINLOCK(!lock->guard, lock);
316
317 /* Pass guard from unlock to lock */
318 if (unlock->guard) {
319 lock->guard = true;
320 lock->ipl = unlock->ipl;
321 unlock->guard = false;
322 }
323
324 spinlock_unlock(&(unlock->lock));
325}
326
327/** Find out whether the IRQ spinlock is currently locked.
328 *
329 * @param lock IRQ spinlock.
330 * @return True if the IRQ spinlock is locked, false otherwise.
331 */
332bool irq_spinlock_locked(irq_spinlock_t *ilock)
333{
334 return spinlock_locked(&ilock->lock);
335}
336
337/** @}
338 */
Note: See TracBrowser for help on using the repository browser.