spinlock.c 9.0 KB
Newer Older
L
Linus Torvalds 已提交
1 2 3 4 5
/*
 * Copyright (2004) Linus Torvalds
 *
 * Author: Zwane Mwaikambo <zwane@fsmlabs.com>
 *
I
Ingo Molnar 已提交
6 7 8 9
 * Copyright (2004, 2005) Ingo Molnar
 *
 * This file contains the spinlock/rwlock implementations for the
 * SMP and the DEBUG_SPINLOCK cases. (UP-nondebug inlines them)
10 11 12 13 14
 *
 * Note that some architectures have special knowledge about the
 * stack frames of these functions in their profile_pc. If you
 * change anything significant here that could change the stack
 * frame contact the architecture maintainers.
L
Linus Torvalds 已提交
15 16 17 18 19 20
 */

#include <linux/linkage.h>
#include <linux/preempt.h>
#include <linux/spinlock.h>
#include <linux/interrupt.h>
21
#include <linux/debug_locks.h>
L
Linus Torvalds 已提交
22 23
#include <linux/module.h>

24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55
/*
 * If lockdep is enabled then we use the non-preemption spin-ops
 * even on CONFIG_PREEMPT, because lockdep assumes that interrupts are
 * not re-enabled during lock-acquire (which the preempt-spin-ops do):
 */
#if !defined(CONFIG_GENERIC_LOCKBREAK) || defined(CONFIG_DEBUG_LOCK_ALLOC)
/*
 * The __lock_function inlines are taken from
 * include/linux/spinlock_api_smp.h
 */
#else
/*
 * We build the __lock_function inlines here. They are too large for
 * inlining all over the place, but here is only one user per function
 * which embedds them into the calling _lock_function below.
 *
 * This could be a long-held lock. We both prepare to spin for a long
 * time (making _this_ CPU preemptable if possible), and we also signal
 * towards that other CPU that it should break the lock ASAP.
 */
#define BUILD_LOCK_OPS(op, locktype)					\
void __lockfunc __##op##_lock(locktype##_t *lock)			\
{									\
	for (;;) {							\
		preempt_disable();					\
		if (likely(_raw_##op##_trylock(lock)))			\
			break;						\
		preempt_enable();					\
									\
		if (!(lock)->break_lock)				\
			(lock)->break_lock = 1;				\
		while (!op##_can_lock(lock) && (lock)->break_lock)	\
56
			arch_##op##_relax(&lock->raw_lock);		\
57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75
	}								\
	(lock)->break_lock = 0;						\
}									\
									\
unsigned long __lockfunc __##op##_lock_irqsave(locktype##_t *lock)	\
{									\
	unsigned long flags;						\
									\
	for (;;) {							\
		preempt_disable();					\
		local_irq_save(flags);					\
		if (likely(_raw_##op##_trylock(lock)))			\
			break;						\
		local_irq_restore(flags);				\
		preempt_enable();					\
									\
		if (!(lock)->break_lock)				\
			(lock)->break_lock = 1;				\
		while (!op##_can_lock(lock) && (lock)->break_lock)	\
76
			arch_##op##_relax(&lock->raw_lock);		\
77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115
	}								\
	(lock)->break_lock = 0;						\
	return flags;							\
}									\
									\
void __lockfunc __##op##_lock_irq(locktype##_t *lock)			\
{									\
	_##op##_lock_irqsave(lock);					\
}									\
									\
void __lockfunc __##op##_lock_bh(locktype##_t *lock)			\
{									\
	unsigned long flags;						\
									\
	/*							*/	\
	/* Careful: we must exclude softirqs too, hence the	*/	\
	/* irq-disabling. We use the generic preemption-aware	*/	\
	/* function:						*/	\
	/**/								\
	flags = _##op##_lock_irqsave(lock);				\
	local_bh_disable();						\
	local_irq_restore(flags);					\
}									\

/*
 * Build preemption-friendly versions of the following
 * lock-spinning functions:
 *
 *         __[spin|read|write]_lock()
 *         __[spin|read|write]_lock_irq()
 *         __[spin|read|write]_lock_irqsave()
 *         __[spin|read|write]_lock_bh()
 */
BUILD_LOCK_OPS(spin, spinlock);
BUILD_LOCK_OPS(read, rwlock);
BUILD_LOCK_OPS(write, rwlock);

#endif

116
#ifndef CONFIG_INLINE_SPIN_TRYLOCK
L
Linus Torvalds 已提交
117 118
int __lockfunc _spin_trylock(spinlock_t *lock)
{
119
	return __spin_trylock(lock);
L
Linus Torvalds 已提交
120 121
}
EXPORT_SYMBOL(_spin_trylock);
122
#endif
L
Linus Torvalds 已提交
123

124 125
#ifndef CONFIG_INLINE_SPIN_TRYLOCK_BH
int __lockfunc _spin_trylock_bh(spinlock_t *lock)
L
Linus Torvalds 已提交
126
{
127
	return __spin_trylock_bh(lock);
L
Linus Torvalds 已提交
128
}
129
EXPORT_SYMBOL(_spin_trylock_bh);
130
#endif
L
Linus Torvalds 已提交
131

132 133
#ifndef CONFIG_INLINE_SPIN_LOCK
void __lockfunc _spin_lock(spinlock_t *lock)
L
Linus Torvalds 已提交
134
{
135
	__spin_lock(lock);
L
Linus Torvalds 已提交
136
}
137
EXPORT_SYMBOL(_spin_lock);
138
#endif
L
Linus Torvalds 已提交
139

140
#ifndef CONFIG_INLINE_SPIN_LOCK_IRQSAVE
L
Linus Torvalds 已提交
141 142
unsigned long __lockfunc _spin_lock_irqsave(spinlock_t *lock)
{
143
	return __spin_lock_irqsave(lock);
L
Linus Torvalds 已提交
144 145
}
EXPORT_SYMBOL(_spin_lock_irqsave);
146
#endif
L
Linus Torvalds 已提交
147

148
#ifndef CONFIG_INLINE_SPIN_LOCK_IRQ
L
Linus Torvalds 已提交
149 150
void __lockfunc _spin_lock_irq(spinlock_t *lock)
{
151
	__spin_lock_irq(lock);
L
Linus Torvalds 已提交
152 153
}
EXPORT_SYMBOL(_spin_lock_irq);
154
#endif
L
Linus Torvalds 已提交
155

156
#ifndef CONFIG_INLINE_SPIN_LOCK_BH
L
Linus Torvalds 已提交
157 158
void __lockfunc _spin_lock_bh(spinlock_t *lock)
{
159
	__spin_lock_bh(lock);
L
Linus Torvalds 已提交
160 161
}
EXPORT_SYMBOL(_spin_lock_bh);
162
#endif
L
Linus Torvalds 已提交
163

164 165
#ifndef CONFIG_INLINE_SPIN_UNLOCK
void __lockfunc _spin_unlock(spinlock_t *lock)
L
Linus Torvalds 已提交
166
{
167
	__spin_unlock(lock);
L
Linus Torvalds 已提交
168
}
169
EXPORT_SYMBOL(_spin_unlock);
170
#endif
L
Linus Torvalds 已提交
171

172 173
#ifndef CONFIG_INLINE_SPIN_UNLOCK_IRQRESTORE
void __lockfunc _spin_unlock_irqrestore(spinlock_t *lock, unsigned long flags)
L
Linus Torvalds 已提交
174
{
175
	__spin_unlock_irqrestore(lock, flags);
L
Linus Torvalds 已提交
176
}
177
EXPORT_SYMBOL(_spin_unlock_irqrestore);
178
#endif
L
Linus Torvalds 已提交
179

180 181
#ifndef CONFIG_INLINE_SPIN_UNLOCK_IRQ
void __lockfunc _spin_unlock_irq(spinlock_t *lock)
L
Linus Torvalds 已提交
182
{
183
	__spin_unlock_irq(lock);
L
Linus Torvalds 已提交
184
}
185
EXPORT_SYMBOL(_spin_unlock_irq);
186
#endif
L
Linus Torvalds 已提交
187

188 189
#ifndef CONFIG_INLINE_SPIN_UNLOCK_BH
void __lockfunc _spin_unlock_bh(spinlock_t *lock)
L
Linus Torvalds 已提交
190
{
191
	__spin_unlock_bh(lock);
L
Linus Torvalds 已提交
192
}
193
EXPORT_SYMBOL(_spin_unlock_bh);
194
#endif
L
Linus Torvalds 已提交
195

196 197
#ifndef CONFIG_INLINE_READ_TRYLOCK
int __lockfunc _read_trylock(rwlock_t *lock)
L
Linus Torvalds 已提交
198
{
199
	return __read_trylock(lock);
L
Linus Torvalds 已提交
200
}
201
EXPORT_SYMBOL(_read_trylock);
202
#endif
L
Linus Torvalds 已提交
203

204 205
#ifndef CONFIG_INLINE_READ_LOCK
void __lockfunc _read_lock(rwlock_t *lock)
L
Linus Torvalds 已提交
206
{
207
	__read_lock(lock);
L
Linus Torvalds 已提交
208
}
209
EXPORT_SYMBOL(_read_lock);
210
#endif
L
Linus Torvalds 已提交
211

212 213
#ifndef CONFIG_INLINE_READ_LOCK_IRQSAVE
unsigned long __lockfunc _read_lock_irqsave(rwlock_t *lock)
L
Linus Torvalds 已提交
214
{
215
	return __read_lock_irqsave(lock);
L
Linus Torvalds 已提交
216
}
217
EXPORT_SYMBOL(_read_lock_irqsave);
218
#endif
L
Linus Torvalds 已提交
219

220 221
#ifndef CONFIG_INLINE_READ_LOCK_IRQ
void __lockfunc _read_lock_irq(rwlock_t *lock)
L
Linus Torvalds 已提交
222
{
223
	__read_lock_irq(lock);
L
Linus Torvalds 已提交
224
}
225
EXPORT_SYMBOL(_read_lock_irq);
226
#endif
L
Linus Torvalds 已提交
227

228 229
#ifndef CONFIG_INLINE_READ_LOCK_BH
void __lockfunc _read_lock_bh(rwlock_t *lock)
L
Linus Torvalds 已提交
230
{
231
	__read_lock_bh(lock);
L
Linus Torvalds 已提交
232
}
233
EXPORT_SYMBOL(_read_lock_bh);
234
#endif
L
Linus Torvalds 已提交
235

236
#ifndef CONFIG_INLINE_READ_UNLOCK
L
Linus Torvalds 已提交
237 238
void __lockfunc _read_unlock(rwlock_t *lock)
{
239
	__read_unlock(lock);
L
Linus Torvalds 已提交
240 241
}
EXPORT_SYMBOL(_read_unlock);
242
#endif
L
Linus Torvalds 已提交
243

244
#ifndef CONFIG_INLINE_READ_UNLOCK_IRQRESTORE
L
Linus Torvalds 已提交
245 246
void __lockfunc _read_unlock_irqrestore(rwlock_t *lock, unsigned long flags)
{
247
	__read_unlock_irqrestore(lock, flags);
L
Linus Torvalds 已提交
248 249
}
EXPORT_SYMBOL(_read_unlock_irqrestore);
250
#endif
L
Linus Torvalds 已提交
251

252
#ifndef CONFIG_INLINE_READ_UNLOCK_IRQ
L
Linus Torvalds 已提交
253 254
void __lockfunc _read_unlock_irq(rwlock_t *lock)
{
255
	__read_unlock_irq(lock);
L
Linus Torvalds 已提交
256 257
}
EXPORT_SYMBOL(_read_unlock_irq);
258
#endif
L
Linus Torvalds 已提交
259

260
#ifndef CONFIG_INLINE_READ_UNLOCK_BH
L
Linus Torvalds 已提交
261 262
void __lockfunc _read_unlock_bh(rwlock_t *lock)
{
263
	__read_unlock_bh(lock);
L
Linus Torvalds 已提交
264 265
}
EXPORT_SYMBOL(_read_unlock_bh);
266
#endif
L
Linus Torvalds 已提交
267

268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315
#ifndef CONFIG_INLINE_WRITE_TRYLOCK
int __lockfunc _write_trylock(rwlock_t *lock)
{
	return __write_trylock(lock);
}
EXPORT_SYMBOL(_write_trylock);
#endif

#ifndef CONFIG_INLINE_WRITE_LOCK
void __lockfunc _write_lock(rwlock_t *lock)
{
	__write_lock(lock);
}
EXPORT_SYMBOL(_write_lock);
#endif

#ifndef CONFIG_INLINE_WRITE_LOCK_IRQSAVE
unsigned long __lockfunc _write_lock_irqsave(rwlock_t *lock)
{
	return __write_lock_irqsave(lock);
}
EXPORT_SYMBOL(_write_lock_irqsave);
#endif

#ifndef CONFIG_INLINE_WRITE_LOCK_IRQ
void __lockfunc _write_lock_irq(rwlock_t *lock)
{
	__write_lock_irq(lock);
}
EXPORT_SYMBOL(_write_lock_irq);
#endif

#ifndef CONFIG_INLINE_WRITE_LOCK_BH
void __lockfunc _write_lock_bh(rwlock_t *lock)
{
	__write_lock_bh(lock);
}
EXPORT_SYMBOL(_write_lock_bh);
#endif

#ifndef CONFIG_INLINE_WRITE_UNLOCK
void __lockfunc _write_unlock(rwlock_t *lock)
{
	__write_unlock(lock);
}
EXPORT_SYMBOL(_write_unlock);
#endif

316
#ifndef CONFIG_INLINE_WRITE_UNLOCK_IRQRESTORE
L
Linus Torvalds 已提交
317 318
void __lockfunc _write_unlock_irqrestore(rwlock_t *lock, unsigned long flags)
{
319
	__write_unlock_irqrestore(lock, flags);
L
Linus Torvalds 已提交
320 321
}
EXPORT_SYMBOL(_write_unlock_irqrestore);
322
#endif
L
Linus Torvalds 已提交
323

324
#ifndef CONFIG_INLINE_WRITE_UNLOCK_IRQ
L
Linus Torvalds 已提交
325 326
void __lockfunc _write_unlock_irq(rwlock_t *lock)
{
327
	__write_unlock_irq(lock);
L
Linus Torvalds 已提交
328 329
}
EXPORT_SYMBOL(_write_unlock_irq);
330
#endif
L
Linus Torvalds 已提交
331

332
#ifndef CONFIG_INLINE_WRITE_UNLOCK_BH
L
Linus Torvalds 已提交
333 334
void __lockfunc _write_unlock_bh(rwlock_t *lock)
{
335
	__write_unlock_bh(lock);
L
Linus Torvalds 已提交
336 337
}
EXPORT_SYMBOL(_write_unlock_bh);
338
#endif
L
Linus Torvalds 已提交
339

340 341 342
#ifdef CONFIG_DEBUG_LOCK_ALLOC

void __lockfunc _spin_lock_nested(spinlock_t *lock, int subclass)
L
Linus Torvalds 已提交
343
{
344 345 346
	preempt_disable();
	spin_acquire(&lock->dep_map, subclass, 0, _RET_IP_);
	LOCK_CONTENDED(lock, _raw_spin_trylock, _raw_spin_lock);
L
Linus Torvalds 已提交
347
}
348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372
EXPORT_SYMBOL(_spin_lock_nested);

unsigned long __lockfunc _spin_lock_irqsave_nested(spinlock_t *lock,
						   int subclass)
{
	unsigned long flags;

	local_irq_save(flags);
	preempt_disable();
	spin_acquire(&lock->dep_map, subclass, 0, _RET_IP_);
	LOCK_CONTENDED_FLAGS(lock, _raw_spin_trylock, _raw_spin_lock,
				_raw_spin_lock_flags, &flags);
	return flags;
}
EXPORT_SYMBOL(_spin_lock_irqsave_nested);

void __lockfunc _spin_lock_nest_lock(spinlock_t *lock,
				     struct lockdep_map *nest_lock)
{
	preempt_disable();
	spin_acquire_nest(&lock->dep_map, 0, 0, nest_lock, _RET_IP_);
	LOCK_CONTENDED(lock, _raw_spin_trylock, _raw_spin_lock);
}
EXPORT_SYMBOL(_spin_lock_nest_lock);

373
#endif
L
Linus Torvalds 已提交
374

375
notrace int in_lock_functions(unsigned long addr)
L
Linus Torvalds 已提交
376 377 378 379 380 381 382 383
{
	/* Linker adds these: start and end of __lockfunc functions */
	extern char __lock_text_start[], __lock_text_end[];

	return addr >= (unsigned long)__lock_text_start
	&& addr < (unsigned long)__lock_text_end;
}
EXPORT_SYMBOL(in_lock_functions);