Root/kernel/spinlock.c

1/*
2 * Copyright (2004) Linus Torvalds
3 *
4 * Author: Zwane Mwaikambo <zwane@fsmlabs.com>
5 *
6 * Copyright (2004, 2005) Ingo Molnar
7 *
8 * This file contains the spinlock/rwlock implementations for the
9 * SMP and the DEBUG_SPINLOCK cases. (UP-nondebug inlines them)
10 *
11 * Note that some architectures have special knowledge about the
12 * stack frames of these functions in their profile_pc. If you
13 * change anything significant here that could change the stack
14 * frame contact the architecture maintainers.
15 */
16
17#include <linux/linkage.h>
18#include <linux/preempt.h>
19#include <linux/spinlock.h>
20#include <linux/interrupt.h>
21#include <linux/debug_locks.h>
22#include <linux/module.h>
23
24#ifndef _spin_trylock
25int __lockfunc _spin_trylock(spinlock_t *lock)
26{
27    return __spin_trylock(lock);
28}
29EXPORT_SYMBOL(_spin_trylock);
30#endif
31
32#ifndef _read_trylock
33int __lockfunc _read_trylock(rwlock_t *lock)
34{
35    return __read_trylock(lock);
36}
37EXPORT_SYMBOL(_read_trylock);
38#endif
39
40#ifndef _write_trylock
41int __lockfunc _write_trylock(rwlock_t *lock)
42{
43    return __write_trylock(lock);
44}
45EXPORT_SYMBOL(_write_trylock);
46#endif
47
48/*
49 * If lockdep is enabled then we use the non-preemption spin-ops
50 * even on CONFIG_PREEMPT, because lockdep assumes that interrupts are
51 * not re-enabled during lock-acquire (which the preempt-spin-ops do):
52 */
53#if !defined(CONFIG_GENERIC_LOCKBREAK) || defined(CONFIG_DEBUG_LOCK_ALLOC)
54
55#ifndef _read_lock
56void __lockfunc _read_lock(rwlock_t *lock)
57{
58    __read_lock(lock);
59}
60EXPORT_SYMBOL(_read_lock);
61#endif
62
63#ifndef _spin_lock_irqsave
64unsigned long __lockfunc _spin_lock_irqsave(spinlock_t *lock)
65{
66    return __spin_lock_irqsave(lock);
67}
68EXPORT_SYMBOL(_spin_lock_irqsave);
69#endif
70
71#ifndef _spin_lock_irq
72void __lockfunc _spin_lock_irq(spinlock_t *lock)
73{
74    __spin_lock_irq(lock);
75}
76EXPORT_SYMBOL(_spin_lock_irq);
77#endif
78
79#ifndef _spin_lock_bh
80void __lockfunc _spin_lock_bh(spinlock_t *lock)
81{
82    __spin_lock_bh(lock);
83}
84EXPORT_SYMBOL(_spin_lock_bh);
85#endif
86
87#ifndef _read_lock_irqsave
88unsigned long __lockfunc _read_lock_irqsave(rwlock_t *lock)
89{
90    return __read_lock_irqsave(lock);
91}
92EXPORT_SYMBOL(_read_lock_irqsave);
93#endif
94
95#ifndef _read_lock_irq
96void __lockfunc _read_lock_irq(rwlock_t *lock)
97{
98    __read_lock_irq(lock);
99}
100EXPORT_SYMBOL(_read_lock_irq);
101#endif
102
103#ifndef _read_lock_bh
104void __lockfunc _read_lock_bh(rwlock_t *lock)
105{
106    __read_lock_bh(lock);
107}
108EXPORT_SYMBOL(_read_lock_bh);
109#endif
110
111#ifndef _write_lock_irqsave
112unsigned long __lockfunc _write_lock_irqsave(rwlock_t *lock)
113{
114    return __write_lock_irqsave(lock);
115}
116EXPORT_SYMBOL(_write_lock_irqsave);
117#endif
118
119#ifndef _write_lock_irq
120void __lockfunc _write_lock_irq(rwlock_t *lock)
121{
122    __write_lock_irq(lock);
123}
124EXPORT_SYMBOL(_write_lock_irq);
125#endif
126
127#ifndef _write_lock_bh
128void __lockfunc _write_lock_bh(rwlock_t *lock)
129{
130    __write_lock_bh(lock);
131}
132EXPORT_SYMBOL(_write_lock_bh);
133#endif
134
135#ifndef _spin_lock
136void __lockfunc _spin_lock(spinlock_t *lock)
137{
138    __spin_lock(lock);
139}
140EXPORT_SYMBOL(_spin_lock);
141#endif
142
143#ifndef _write_lock
144void __lockfunc _write_lock(rwlock_t *lock)
145{
146    __write_lock(lock);
147}
148EXPORT_SYMBOL(_write_lock);
149#endif
150
151#else /* CONFIG_PREEMPT: */
152
153/*
154 * This could be a long-held lock. We both prepare to spin for a long
155 * time (making _this_ CPU preemptable if possible), and we also signal
156 * towards that other CPU that it should break the lock ASAP.
157 *
158 * (We do this in a function because inlining it would be excessive.)
159 */
160
161#define BUILD_LOCK_OPS(op, locktype) \
162void __lockfunc _##op##_lock(locktype##_t *lock) \
163{ \
164    for (;;) { \
165        preempt_disable(); \
166        if (likely(_raw_##op##_trylock(lock))) \
167            break; \
168        preempt_enable(); \
169                                    \
170        if (!(lock)->break_lock) \
171            (lock)->break_lock = 1; \
172        while (!op##_can_lock(lock) && (lock)->break_lock) \
173            _raw_##op##_relax(&lock->raw_lock); \
174    } \
175    (lock)->break_lock = 0; \
176} \
177                                    \
178EXPORT_SYMBOL(_##op##_lock); \
179                                    \
180unsigned long __lockfunc _##op##_lock_irqsave(locktype##_t *lock) \
181{ \
182    unsigned long flags; \
183                                    \
184    for (;;) { \
185        preempt_disable(); \
186        local_irq_save(flags); \
187        if (likely(_raw_##op##_trylock(lock))) \
188            break; \
189        local_irq_restore(flags); \
190        preempt_enable(); \
191                                    \
192        if (!(lock)->break_lock) \
193            (lock)->break_lock = 1; \
194        while (!op##_can_lock(lock) && (lock)->break_lock) \
195            _raw_##op##_relax(&lock->raw_lock); \
196    } \
197    (lock)->break_lock = 0; \
198    return flags; \
199} \
200                                    \
201EXPORT_SYMBOL(_##op##_lock_irqsave); \
202                                    \
203void __lockfunc _##op##_lock_irq(locktype##_t *lock) \
204{ \
205    _##op##_lock_irqsave(lock); \
206} \
207                                    \
208EXPORT_SYMBOL(_##op##_lock_irq); \
209                                    \
210void __lockfunc _##op##_lock_bh(locktype##_t *lock) \
211{ \
212    unsigned long flags; \
213                                    \
214    /* */ \
215    /* Careful: we must exclude softirqs too, hence the */ \
216    /* irq-disabling. We use the generic preemption-aware */ \
217    /* function: */ \
218    /**/ \
219    flags = _##op##_lock_irqsave(lock); \
220    local_bh_disable(); \
221    local_irq_restore(flags); \
222} \
223                                    \
224EXPORT_SYMBOL(_##op##_lock_bh)
225
226/*
227 * Build preemption-friendly versions of the following
228 * lock-spinning functions:
229 *
230 * _[spin|read|write]_lock()
231 * _[spin|read|write]_lock_irq()
232 * _[spin|read|write]_lock_irqsave()
233 * _[spin|read|write]_lock_bh()
234 */
235BUILD_LOCK_OPS(spin, spinlock);
236BUILD_LOCK_OPS(read, rwlock);
237BUILD_LOCK_OPS(write, rwlock);
238
239#endif /* CONFIG_PREEMPT */
240
241#ifdef CONFIG_DEBUG_LOCK_ALLOC
242
243void __lockfunc _spin_lock_nested(spinlock_t *lock, int subclass)
244{
245    preempt_disable();
246    spin_acquire(&lock->dep_map, subclass, 0, _RET_IP_);
247    LOCK_CONTENDED(lock, _raw_spin_trylock, _raw_spin_lock);
248}
249EXPORT_SYMBOL(_spin_lock_nested);
250
251unsigned long __lockfunc _spin_lock_irqsave_nested(spinlock_t *lock, int subclass)
252{
253    unsigned long flags;
254
255    local_irq_save(flags);
256    preempt_disable();
257    spin_acquire(&lock->dep_map, subclass, 0, _RET_IP_);
258    LOCK_CONTENDED_FLAGS(lock, _raw_spin_trylock, _raw_spin_lock,
259                _raw_spin_lock_flags, &flags);
260    return flags;
261}
262EXPORT_SYMBOL(_spin_lock_irqsave_nested);
263
264void __lockfunc _spin_lock_nest_lock(spinlock_t *lock,
265                     struct lockdep_map *nest_lock)
266{
267    preempt_disable();
268    spin_acquire_nest(&lock->dep_map, 0, 0, nest_lock, _RET_IP_);
269    LOCK_CONTENDED(lock, _raw_spin_trylock, _raw_spin_lock);
270}
271EXPORT_SYMBOL(_spin_lock_nest_lock);
272
273#endif
274
275#ifndef _spin_unlock
276void __lockfunc _spin_unlock(spinlock_t *lock)
277{
278    __spin_unlock(lock);
279}
280EXPORT_SYMBOL(_spin_unlock);
281#endif
282
283#ifndef _write_unlock
284void __lockfunc _write_unlock(rwlock_t *lock)
285{
286    __write_unlock(lock);
287}
288EXPORT_SYMBOL(_write_unlock);
289#endif
290
291#ifndef _read_unlock
292void __lockfunc _read_unlock(rwlock_t *lock)
293{
294    __read_unlock(lock);
295}
296EXPORT_SYMBOL(_read_unlock);
297#endif
298
299#ifndef _spin_unlock_irqrestore
300void __lockfunc _spin_unlock_irqrestore(spinlock_t *lock, unsigned long flags)
301{
302    __spin_unlock_irqrestore(lock, flags);
303}
304EXPORT_SYMBOL(_spin_unlock_irqrestore);
305#endif
306
307#ifndef _spin_unlock_irq
308void __lockfunc _spin_unlock_irq(spinlock_t *lock)
309{
310    __spin_unlock_irq(lock);
311}
312EXPORT_SYMBOL(_spin_unlock_irq);
313#endif
314
315#ifndef _spin_unlock_bh
316void __lockfunc _spin_unlock_bh(spinlock_t *lock)
317{
318    __spin_unlock_bh(lock);
319}
320EXPORT_SYMBOL(_spin_unlock_bh);
321#endif
322
323#ifndef _read_unlock_irqrestore
324void __lockfunc _read_unlock_irqrestore(rwlock_t *lock, unsigned long flags)
325{
326    __read_unlock_irqrestore(lock, flags);
327}
328EXPORT_SYMBOL(_read_unlock_irqrestore);
329#endif
330
331#ifndef _read_unlock_irq
332void __lockfunc _read_unlock_irq(rwlock_t *lock)
333{
334    __read_unlock_irq(lock);
335}
336EXPORT_SYMBOL(_read_unlock_irq);
337#endif
338
339#ifndef _read_unlock_bh
340void __lockfunc _read_unlock_bh(rwlock_t *lock)
341{
342    __read_unlock_bh(lock);
343}
344EXPORT_SYMBOL(_read_unlock_bh);
345#endif
346
347#ifndef _write_unlock_irqrestore
348void __lockfunc _write_unlock_irqrestore(rwlock_t *lock, unsigned long flags)
349{
350    __write_unlock_irqrestore(lock, flags);
351}
352EXPORT_SYMBOL(_write_unlock_irqrestore);
353#endif
354
355#ifndef _write_unlock_irq
356void __lockfunc _write_unlock_irq(rwlock_t *lock)
357{
358    __write_unlock_irq(lock);
359}
360EXPORT_SYMBOL(_write_unlock_irq);
361#endif
362
363#ifndef _write_unlock_bh
364void __lockfunc _write_unlock_bh(rwlock_t *lock)
365{
366    __write_unlock_bh(lock);
367}
368EXPORT_SYMBOL(_write_unlock_bh);
369#endif
370
371#ifndef _spin_trylock_bh
372int __lockfunc _spin_trylock_bh(spinlock_t *lock)
373{
374    return __spin_trylock_bh(lock);
375}
376EXPORT_SYMBOL(_spin_trylock_bh);
377#endif
378
379notrace int in_lock_functions(unsigned long addr)
380{
381    /* Linker adds these: start and end of __lockfunc functions */
382    extern char __lock_text_start[], __lock_text_end[];
383
384    return addr >= (unsigned long)__lock_text_start
385    && addr < (unsigned long)__lock_text_end;
386}
387EXPORT_SYMBOL(in_lock_functions);
388

Archive Download this file



interactive