spinlock.c 11.1 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 24 25 26
#include <linux/module.h>

int __lockfunc _spin_trylock(spinlock_t *lock)
{
	preempt_disable();
27 28
	if (_raw_spin_trylock(lock)) {
		spin_acquire(&lock->dep_map, 0, 1, _RET_IP_);
L
Linus Torvalds 已提交
29
		return 1;
30
	}
L
Linus Torvalds 已提交
31 32 33 34 35 36 37 38 39
	
	preempt_enable();
	return 0;
}
EXPORT_SYMBOL(_spin_trylock);

int __lockfunc _read_trylock(rwlock_t *lock)
{
	preempt_disable();
40 41
	if (_raw_read_trylock(lock)) {
		rwlock_acquire_read(&lock->dep_map, 0, 1, _RET_IP_);
L
Linus Torvalds 已提交
42
		return 1;
43
	}
L
Linus Torvalds 已提交
44 45 46 47 48 49 50 51 52

	preempt_enable();
	return 0;
}
EXPORT_SYMBOL(_read_trylock);

int __lockfunc _write_trylock(rwlock_t *lock)
{
	preempt_disable();
53 54
	if (_raw_write_trylock(lock)) {
		rwlock_acquire(&lock->dep_map, 0, 1, _RET_IP_);
L
Linus Torvalds 已提交
55
		return 1;
56
	}
L
Linus Torvalds 已提交
57 58 59 60 61 62

	preempt_enable();
	return 0;
}
EXPORT_SYMBOL(_write_trylock);

63 64 65 66 67
/*
 * 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):
 */
N
Nick Piggin 已提交
68
#if !defined(CONFIG_GENERIC_LOCKBREAK) || defined(CONFIG_DEBUG_LOCK_ALLOC)
L
Linus Torvalds 已提交
69 70 71 72

void __lockfunc _read_lock(rwlock_t *lock)
{
	preempt_disable();
73
	rwlock_acquire_read(&lock->dep_map, 0, 0, _RET_IP_);
74
	LOCK_CONTENDED(lock, _raw_read_trylock, _raw_read_lock);
L
Linus Torvalds 已提交
75 76 77 78 79 80 81 82 83
}
EXPORT_SYMBOL(_read_lock);

unsigned long __lockfunc _spin_lock_irqsave(spinlock_t *lock)
{
	unsigned long flags;

	local_irq_save(flags);
	preempt_disable();
84 85 86 87 88 89
	spin_acquire(&lock->dep_map, 0, 0, _RET_IP_);
	/*
	 * On lockdep we dont want the hand-coded irq-enable of
	 * _raw_spin_lock_flags() code, because lockdep assumes
	 * that interrupts are not re-enabled during lock-acquire:
	 */
90
#ifdef CONFIG_LOCKDEP
91
	LOCK_CONTENDED(lock, _raw_spin_trylock, _raw_spin_lock);
92
#else
I
Ingo Molnar 已提交
93
	_raw_spin_lock_flags(lock, &flags);
94
#endif
L
Linus Torvalds 已提交
95 96 97 98 99 100 101 102
	return flags;
}
EXPORT_SYMBOL(_spin_lock_irqsave);

void __lockfunc _spin_lock_irq(spinlock_t *lock)
{
	local_irq_disable();
	preempt_disable();
103
	spin_acquire(&lock->dep_map, 0, 0, _RET_IP_);
104
	LOCK_CONTENDED(lock, _raw_spin_trylock, _raw_spin_lock);
L
Linus Torvalds 已提交
105 106 107 108 109 110 111
}
EXPORT_SYMBOL(_spin_lock_irq);

void __lockfunc _spin_lock_bh(spinlock_t *lock)
{
	local_bh_disable();
	preempt_disable();
112
	spin_acquire(&lock->dep_map, 0, 0, _RET_IP_);
113
	LOCK_CONTENDED(lock, _raw_spin_trylock, _raw_spin_lock);
L
Linus Torvalds 已提交
114 115 116 117 118 119 120 121 122
}
EXPORT_SYMBOL(_spin_lock_bh);

unsigned long __lockfunc _read_lock_irqsave(rwlock_t *lock)
{
	unsigned long flags;

	local_irq_save(flags);
	preempt_disable();
123
	rwlock_acquire_read(&lock->dep_map, 0, 0, _RET_IP_);
124
	LOCK_CONTENDED(lock, _raw_read_trylock, _raw_read_lock);
L
Linus Torvalds 已提交
125 126 127 128 129 130 131 132
	return flags;
}
EXPORT_SYMBOL(_read_lock_irqsave);

void __lockfunc _read_lock_irq(rwlock_t *lock)
{
	local_irq_disable();
	preempt_disable();
133
	rwlock_acquire_read(&lock->dep_map, 0, 0, _RET_IP_);
134
	LOCK_CONTENDED(lock, _raw_read_trylock, _raw_read_lock);
L
Linus Torvalds 已提交
135 136 137 138 139 140 141
}
EXPORT_SYMBOL(_read_lock_irq);

void __lockfunc _read_lock_bh(rwlock_t *lock)
{
	local_bh_disable();
	preempt_disable();
142
	rwlock_acquire_read(&lock->dep_map, 0, 0, _RET_IP_);
143
	LOCK_CONTENDED(lock, _raw_read_trylock, _raw_read_lock);
L
Linus Torvalds 已提交
144 145 146 147 148 149 150 151 152
}
EXPORT_SYMBOL(_read_lock_bh);

unsigned long __lockfunc _write_lock_irqsave(rwlock_t *lock)
{
	unsigned long flags;

	local_irq_save(flags);
	preempt_disable();
153
	rwlock_acquire(&lock->dep_map, 0, 0, _RET_IP_);
154
	LOCK_CONTENDED(lock, _raw_write_trylock, _raw_write_lock);
L
Linus Torvalds 已提交
155 156 157 158 159 160 161 162
	return flags;
}
EXPORT_SYMBOL(_write_lock_irqsave);

void __lockfunc _write_lock_irq(rwlock_t *lock)
{
	local_irq_disable();
	preempt_disable();
163
	rwlock_acquire(&lock->dep_map, 0, 0, _RET_IP_);
164
	LOCK_CONTENDED(lock, _raw_write_trylock, _raw_write_lock);
L
Linus Torvalds 已提交
165 166 167 168 169 170 171
}
EXPORT_SYMBOL(_write_lock_irq);

void __lockfunc _write_lock_bh(rwlock_t *lock)
{
	local_bh_disable();
	preempt_disable();
172
	rwlock_acquire(&lock->dep_map, 0, 0, _RET_IP_);
173
	LOCK_CONTENDED(lock, _raw_write_trylock, _raw_write_lock);
L
Linus Torvalds 已提交
174 175 176 177 178 179
}
EXPORT_SYMBOL(_write_lock_bh);

void __lockfunc _spin_lock(spinlock_t *lock)
{
	preempt_disable();
180
	spin_acquire(&lock->dep_map, 0, 0, _RET_IP_);
181
	LOCK_CONTENDED(lock, _raw_spin_trylock, _raw_spin_lock);
L
Linus Torvalds 已提交
182 183 184 185 186 187 188
}

EXPORT_SYMBOL(_spin_lock);

void __lockfunc _write_lock(rwlock_t *lock)
{
	preempt_disable();
189
	rwlock_acquire(&lock->dep_map, 0, 0, _RET_IP_);
190
	LOCK_CONTENDED(lock, _raw_write_trylock, _raw_write_lock);
L
Linus Torvalds 已提交
191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208
}

EXPORT_SYMBOL(_write_lock);

#else /* CONFIG_PREEMPT: */

/*
 * 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.
 *
 * (We do this in a function because inlining it would be excessive.)
 */

#define BUILD_LOCK_OPS(op, locktype)					\
void __lockfunc _##op##_lock(locktype##_t *lock)			\
{									\
	for (;;) {							\
209
		preempt_disable();					\
L
Linus Torvalds 已提交
210 211 212
		if (likely(_raw_##op##_trylock(lock)))			\
			break;						\
		preempt_enable();					\
213
									\
L
Linus Torvalds 已提交
214 215 216
		if (!(lock)->break_lock)				\
			(lock)->break_lock = 1;				\
		while (!op##_can_lock(lock) && (lock)->break_lock)	\
217
			_raw_##op##_relax(&lock->raw_lock);		\
L
Linus Torvalds 已提交
218 219 220 221 222 223 224 225 226 227 228
	}								\
	(lock)->break_lock = 0;						\
}									\
									\
EXPORT_SYMBOL(_##op##_lock);						\
									\
unsigned long __lockfunc _##op##_lock_irqsave(locktype##_t *lock)	\
{									\
	unsigned long flags;						\
									\
	for (;;) {							\
229
		preempt_disable();					\
L
Linus Torvalds 已提交
230 231 232 233 234
		local_irq_save(flags);					\
		if (likely(_raw_##op##_trylock(lock)))			\
			break;						\
		local_irq_restore(flags);				\
		preempt_enable();					\
235
									\
L
Linus Torvalds 已提交
236 237 238
		if (!(lock)->break_lock)				\
			(lock)->break_lock = 1;				\
		while (!op##_can_lock(lock) && (lock)->break_lock)	\
239
			_raw_##op##_relax(&lock->raw_lock);		\
L
Linus Torvalds 已提交
240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284
	}								\
	(lock)->break_lock = 0;						\
	return flags;							\
}									\
									\
EXPORT_SYMBOL(_##op##_lock_irqsave);					\
									\
void __lockfunc _##op##_lock_irq(locktype##_t *lock)			\
{									\
	_##op##_lock_irqsave(lock);					\
}									\
									\
EXPORT_SYMBOL(_##op##_lock_irq);					\
									\
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);					\
}									\
									\
EXPORT_SYMBOL(_##op##_lock_bh)

/*
 * 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 /* CONFIG_PREEMPT */

285 286 287 288 289 290
#ifdef CONFIG_DEBUG_LOCK_ALLOC

void __lockfunc _spin_lock_nested(spinlock_t *lock, int subclass)
{
	preempt_disable();
	spin_acquire(&lock->dep_map, subclass, 0, _RET_IP_);
291
	LOCK_CONTENDED(lock, _raw_spin_trylock, _raw_spin_lock);
292 293 294
}

EXPORT_SYMBOL(_spin_lock_nested);
295 296 297 298 299 300 301 302 303 304 305 306
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_);
	/*
	 * On lockdep we dont want the hand-coded irq-enable of
	 * _raw_spin_lock_flags() code, because lockdep assumes
	 * that interrupts are not re-enabled during lock-acquire:
	 */
307
#ifdef CONFIG_LOCKDEP
308
	LOCK_CONTENDED(lock, _raw_spin_trylock, _raw_spin_lock);
309 310 311 312 313 314 315
#else
	_raw_spin_lock_flags(lock, &flags);
#endif
	return flags;
}

EXPORT_SYMBOL(_spin_lock_irqsave_nested);
316 317 318

#endif

L
Linus Torvalds 已提交
319 320
void __lockfunc _spin_unlock(spinlock_t *lock)
{
321
	spin_release(&lock->dep_map, 1, _RET_IP_);
L
Linus Torvalds 已提交
322 323 324 325 326 327 328
	_raw_spin_unlock(lock);
	preempt_enable();
}
EXPORT_SYMBOL(_spin_unlock);

void __lockfunc _write_unlock(rwlock_t *lock)
{
329
	rwlock_release(&lock->dep_map, 1, _RET_IP_);
L
Linus Torvalds 已提交
330 331 332 333 334 335 336
	_raw_write_unlock(lock);
	preempt_enable();
}
EXPORT_SYMBOL(_write_unlock);

void __lockfunc _read_unlock(rwlock_t *lock)
{
337
	rwlock_release(&lock->dep_map, 1, _RET_IP_);
L
Linus Torvalds 已提交
338 339 340 341 342 343 344
	_raw_read_unlock(lock);
	preempt_enable();
}
EXPORT_SYMBOL(_read_unlock);

void __lockfunc _spin_unlock_irqrestore(spinlock_t *lock, unsigned long flags)
{
345
	spin_release(&lock->dep_map, 1, _RET_IP_);
L
Linus Torvalds 已提交
346 347 348 349 350 351 352 353
	_raw_spin_unlock(lock);
	local_irq_restore(flags);
	preempt_enable();
}
EXPORT_SYMBOL(_spin_unlock_irqrestore);

void __lockfunc _spin_unlock_irq(spinlock_t *lock)
{
354
	spin_release(&lock->dep_map, 1, _RET_IP_);
L
Linus Torvalds 已提交
355 356 357 358 359 360 361 362
	_raw_spin_unlock(lock);
	local_irq_enable();
	preempt_enable();
}
EXPORT_SYMBOL(_spin_unlock_irq);

void __lockfunc _spin_unlock_bh(spinlock_t *lock)
{
363
	spin_release(&lock->dep_map, 1, _RET_IP_);
L
Linus Torvalds 已提交
364
	_raw_spin_unlock(lock);
365
	preempt_enable_no_resched();
366
	local_bh_enable_ip((unsigned long)__builtin_return_address(0));
L
Linus Torvalds 已提交
367 368 369 370 371
}
EXPORT_SYMBOL(_spin_unlock_bh);

void __lockfunc _read_unlock_irqrestore(rwlock_t *lock, unsigned long flags)
{
372
	rwlock_release(&lock->dep_map, 1, _RET_IP_);
L
Linus Torvalds 已提交
373 374 375 376 377 378 379 380
	_raw_read_unlock(lock);
	local_irq_restore(flags);
	preempt_enable();
}
EXPORT_SYMBOL(_read_unlock_irqrestore);

void __lockfunc _read_unlock_irq(rwlock_t *lock)
{
381
	rwlock_release(&lock->dep_map, 1, _RET_IP_);
L
Linus Torvalds 已提交
382 383 384 385 386 387 388 389
	_raw_read_unlock(lock);
	local_irq_enable();
	preempt_enable();
}
EXPORT_SYMBOL(_read_unlock_irq);

void __lockfunc _read_unlock_bh(rwlock_t *lock)
{
390
	rwlock_release(&lock->dep_map, 1, _RET_IP_);
L
Linus Torvalds 已提交
391
	_raw_read_unlock(lock);
392
	preempt_enable_no_resched();
393
	local_bh_enable_ip((unsigned long)__builtin_return_address(0));
L
Linus Torvalds 已提交
394 395 396 397 398
}
EXPORT_SYMBOL(_read_unlock_bh);

void __lockfunc _write_unlock_irqrestore(rwlock_t *lock, unsigned long flags)
{
399
	rwlock_release(&lock->dep_map, 1, _RET_IP_);
L
Linus Torvalds 已提交
400 401 402 403 404 405 406 407
	_raw_write_unlock(lock);
	local_irq_restore(flags);
	preempt_enable();
}
EXPORT_SYMBOL(_write_unlock_irqrestore);

void __lockfunc _write_unlock_irq(rwlock_t *lock)
{
408
	rwlock_release(&lock->dep_map, 1, _RET_IP_);
L
Linus Torvalds 已提交
409 410 411 412 413 414 415 416
	_raw_write_unlock(lock);
	local_irq_enable();
	preempt_enable();
}
EXPORT_SYMBOL(_write_unlock_irq);

void __lockfunc _write_unlock_bh(rwlock_t *lock)
{
417
	rwlock_release(&lock->dep_map, 1, _RET_IP_);
L
Linus Torvalds 已提交
418
	_raw_write_unlock(lock);
419
	preempt_enable_no_resched();
420
	local_bh_enable_ip((unsigned long)__builtin_return_address(0));
L
Linus Torvalds 已提交
421 422 423 424 425 426 427
}
EXPORT_SYMBOL(_write_unlock_bh);

int __lockfunc _spin_trylock_bh(spinlock_t *lock)
{
	local_bh_disable();
	preempt_disable();
428 429
	if (_raw_spin_trylock(lock)) {
		spin_acquire(&lock->dep_map, 0, 1, _RET_IP_);
L
Linus Torvalds 已提交
430
		return 1;
431
	}
L
Linus Torvalds 已提交
432

433
	preempt_enable_no_resched();
434
	local_bh_enable_ip((unsigned long)__builtin_return_address(0));
L
Linus Torvalds 已提交
435 436 437 438 439 440 441 442 443 444 445 446 447
	return 0;
}
EXPORT_SYMBOL(_spin_trylock_bh);

int in_lock_functions(unsigned long addr)
{
	/* 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);