diff options
| author | Linus Torvalds <torvalds@linux-foundation.org> | 2011-03-15 21:28:30 -0400 |
|---|---|---|
| committer | Linus Torvalds <torvalds@linux-foundation.org> | 2011-03-15 21:28:30 -0400 |
| commit | 0586bed3e8563c2eb89bc7256e30ce633ae06cfb (patch) | |
| tree | 7a59610f45f7222f25b3212c53fa28636bb4427c /kernel/timer.c | |
| parent | b80cd62b7d4406bbe8c573fe4381dcc71a2850fd (diff) | |
| parent | dbebbfbb1605f0179e7c0d900d941cc9c45de569 (diff) | |
Merge branch 'core-locking-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/linux-2.6-tip
* 'core-locking-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/linux-2.6-tip:
rtmutex: tester: Remove the remaining BKL leftovers
lockdep/timers: Explain in detail the locking problems del_timer_sync() may cause
rtmutex: Simplify PI algorithm and make highest prio task get lock
rwsem: Remove redundant asmregparm annotation
rwsem: Move duplicate function prototypes to linux/rwsem.h
rwsem: Unify the duplicate rwsem_is_locked() inlines
rwsem: Move duplicate init macros and functions to linux/rwsem.h
rwsem: Move duplicate struct rwsem declaration to linux/rwsem.h
x86: Cleanup rwsem_count_t typedef
rwsem: Cleanup includes
locking: Remove deprecated lock initializers
cred: Replace deprecated spinlock initialization
kthread: Replace deprecated spinlock initialization
xtensa: Replace deprecated spinlock initialization
um: Replace deprecated spinlock initialization
sparc: Replace deprecated spinlock initialization
mips: Replace deprecated spinlock initialization
cris: Replace deprecated spinlock initialization
alpha: Replace deprecated spinlock initialization
rtmutex-tester: Remove BKL tests
Diffstat (limited to 'kernel/timer.c')
| -rw-r--r-- | kernel/timer.c | 23 |
1 files changed, 23 insertions, 0 deletions
diff --git a/kernel/timer.c b/kernel/timer.c index 33a67925d900..3503c17ac1d3 100644 --- a/kernel/timer.c +++ b/kernel/timer.c | |||
| @@ -970,6 +970,25 @@ EXPORT_SYMBOL(try_to_del_timer_sync); | |||
| 970 | * add_timer_on(). Upon exit the timer is not queued and the handler is | 970 | * add_timer_on(). Upon exit the timer is not queued and the handler is |
| 971 | * not running on any CPU. | 971 | * not running on any CPU. |
| 972 | * | 972 | * |
| 973 | * Note: You must not hold locks that are held in interrupt context | ||
| 974 | * while calling this function. Even if the lock has nothing to do | ||
| 975 | * with the timer in question. Here's why: | ||
| 976 | * | ||
| 977 | * CPU0 CPU1 | ||
| 978 | * ---- ---- | ||
| 979 | * <SOFTIRQ> | ||
| 980 | * call_timer_fn(); | ||
| 981 | * base->running_timer = mytimer; | ||
| 982 | * spin_lock_irq(somelock); | ||
| 983 | * <IRQ> | ||
| 984 | * spin_lock(somelock); | ||
| 985 | * del_timer_sync(mytimer); | ||
| 986 | * while (base->running_timer == mytimer); | ||
| 987 | * | ||
| 988 | * Now del_timer_sync() will never return and never release somelock. | ||
| 989 | * The interrupt on the other CPU is waiting to grab somelock but | ||
| 990 | * it has interrupted the softirq that CPU0 is waiting to finish. | ||
| 991 | * | ||
| 973 | * The function returns whether it has deactivated a pending timer or not. | 992 | * The function returns whether it has deactivated a pending timer or not. |
| 974 | */ | 993 | */ |
| 975 | int del_timer_sync(struct timer_list *timer) | 994 | int del_timer_sync(struct timer_list *timer) |
| @@ -977,6 +996,10 @@ int del_timer_sync(struct timer_list *timer) | |||
| 977 | #ifdef CONFIG_LOCKDEP | 996 | #ifdef CONFIG_LOCKDEP |
| 978 | unsigned long flags; | 997 | unsigned long flags; |
| 979 | 998 | ||
| 999 | /* | ||
| 1000 | * If lockdep gives a backtrace here, please reference | ||
| 1001 | * the synchronization rules above. | ||
| 1002 | */ | ||
| 980 | local_irq_save(flags); | 1003 | local_irq_save(flags); |
| 981 | lock_map_acquire(&timer->lockdep_map); | 1004 | lock_map_acquire(&timer->lockdep_map); |
| 982 | lock_map_release(&timer->lockdep_map); | 1005 | lock_map_release(&timer->lockdep_map); |
