diff options
author | Johannes Berg <johannes@sipsolutions.net> | 2009-01-29 10:03:20 -0500 |
---|---|---|
committer | Ingo Molnar <mingo@elte.hu> | 2009-02-14 17:25:52 -0500 |
commit | 6f2b9b9a9d750a9175dc79c74bfed5add840983c (patch) | |
tree | 176fda4698f3ee6dfa4f35febe9fb959f584d353 /include/linux/timer.h | |
parent | 673f8205914a12e928c65afbcd78ae748f78df53 (diff) |
timer: implement lockdep deadlock detection
This modifies the timer code in a way to allow lockdep to detect
deadlocks resulting from a lock being taken in the timer function
as well as around the del_timer_sync() call.
Signed-off-by: Johannes Berg <johannes@sipsolutions.net>
Diffstat (limited to 'include/linux/timer.h')
-rw-r--r-- | include/linux/timer.h | 93 |
1 files changed, 84 insertions, 9 deletions
diff --git a/include/linux/timer.h b/include/linux/timer.h index daf9685b861c..51774eb87cc6 100644 --- a/include/linux/timer.h +++ b/include/linux/timer.h | |||
@@ -5,6 +5,7 @@ | |||
5 | #include <linux/ktime.h> | 5 | #include <linux/ktime.h> |
6 | #include <linux/stddef.h> | 6 | #include <linux/stddef.h> |
7 | #include <linux/debugobjects.h> | 7 | #include <linux/debugobjects.h> |
8 | #include <linux/stringify.h> | ||
8 | 9 | ||
9 | struct tvec_base; | 10 | struct tvec_base; |
10 | 11 | ||
@@ -21,52 +22,126 @@ struct timer_list { | |||
21 | char start_comm[16]; | 22 | char start_comm[16]; |
22 | int start_pid; | 23 | int start_pid; |
23 | #endif | 24 | #endif |
25 | #ifdef CONFIG_LOCKDEP | ||
26 | struct lockdep_map lockdep_map; | ||
27 | #endif | ||
24 | }; | 28 | }; |
25 | 29 | ||
26 | extern struct tvec_base boot_tvec_bases; | 30 | extern struct tvec_base boot_tvec_bases; |
27 | 31 | ||
32 | #ifdef CONFIG_LOCKDEP | ||
33 | /* | ||
34 | * NB: because we have to copy the lockdep_map, setting the lockdep_map key | ||
35 | * (second argument) here is required, otherwise it could be initialised to | ||
36 | * the copy of the lockdep_map later! We use the pointer to and the string | ||
37 | * "<file>:<line>" as the key resp. the name of the lockdep_map. | ||
38 | */ | ||
39 | #define __TIMER_LOCKDEP_MAP_INITIALIZER(_kn) \ | ||
40 | .lockdep_map = STATIC_LOCKDEP_MAP_INIT(_kn, &_kn), | ||
41 | #else | ||
42 | #define __TIMER_LOCKDEP_MAP_INITIALIZER(_kn) | ||
43 | #endif | ||
44 | |||
28 | #define TIMER_INITIALIZER(_function, _expires, _data) { \ | 45 | #define TIMER_INITIALIZER(_function, _expires, _data) { \ |
29 | .entry = { .prev = TIMER_ENTRY_STATIC }, \ | 46 | .entry = { .prev = TIMER_ENTRY_STATIC }, \ |
30 | .function = (_function), \ | 47 | .function = (_function), \ |
31 | .expires = (_expires), \ | 48 | .expires = (_expires), \ |
32 | .data = (_data), \ | 49 | .data = (_data), \ |
33 | .base = &boot_tvec_bases, \ | 50 | .base = &boot_tvec_bases, \ |
51 | __TIMER_LOCKDEP_MAP_INITIALIZER( \ | ||
52 | __FILE__ ":" __stringify(__LINE__)) \ | ||
34 | } | 53 | } |
35 | 54 | ||
36 | #define DEFINE_TIMER(_name, _function, _expires, _data) \ | 55 | #define DEFINE_TIMER(_name, _function, _expires, _data) \ |
37 | struct timer_list _name = \ | 56 | struct timer_list _name = \ |
38 | TIMER_INITIALIZER(_function, _expires, _data) | 57 | TIMER_INITIALIZER(_function, _expires, _data) |
39 | 58 | ||
40 | void init_timer(struct timer_list *timer); | 59 | void init_timer_key(struct timer_list *timer, |
41 | void init_timer_deferrable(struct timer_list *timer); | 60 | const char *name, |
61 | struct lock_class_key *key); | ||
62 | void init_timer_deferrable_key(struct timer_list *timer, | ||
63 | const char *name, | ||
64 | struct lock_class_key *key); | ||
65 | |||
66 | #ifdef CONFIG_LOCKDEP | ||
67 | #define init_timer(timer) \ | ||
68 | do { \ | ||
69 | static struct lock_class_key __key; \ | ||
70 | init_timer_key((timer), #timer, &__key); \ | ||
71 | } while (0) | ||
72 | |||
73 | #define init_timer_deferrable(timer) \ | ||
74 | do { \ | ||
75 | static struct lock_class_key __key; \ | ||
76 | init_timer_deferrable_key((timer), #timer, &__key); \ | ||
77 | } while (0) | ||
78 | |||
79 | #define init_timer_on_stack(timer) \ | ||
80 | do { \ | ||
81 | static struct lock_class_key __key; \ | ||
82 | init_timer_on_stack_key((timer), #timer, &__key); \ | ||
83 | } while (0) | ||
84 | |||
85 | #define setup_timer(timer, fn, data) \ | ||
86 | do { \ | ||
87 | static struct lock_class_key __key; \ | ||
88 | setup_timer_key((timer), #timer, &__key, (fn), (data));\ | ||
89 | } while (0) | ||
90 | |||
91 | #define setup_timer_on_stack(timer, fn, data) \ | ||
92 | do { \ | ||
93 | static struct lock_class_key __key; \ | ||
94 | setup_timer_on_stack_key((timer), #timer, &__key, \ | ||
95 | (fn), (data)); \ | ||
96 | } while (0) | ||
97 | #else | ||
98 | #define init_timer(timer)\ | ||
99 | init_timer_key((timer), NULL, NULL) | ||
100 | #define init_timer_deferrable(timer)\ | ||
101 | init_timer_deferrable_key((timer), NULL, NULL) | ||
102 | #define init_timer_on_stack(timer)\ | ||
103 | init_timer_on_stack_key((timer), NULL, NULL) | ||
104 | #define setup_timer(timer, fn, data)\ | ||
105 | setup_timer_key((timer), NULL, NULL, (fn), (data)) | ||
106 | #define setup_timer_on_stack(timer, fn, data)\ | ||
107 | setup_timer_on_stack_key((timer), NULL, NULL, (fn), (data)) | ||
108 | #endif | ||
42 | 109 | ||
43 | #ifdef CONFIG_DEBUG_OBJECTS_TIMERS | 110 | #ifdef CONFIG_DEBUG_OBJECTS_TIMERS |
44 | extern void init_timer_on_stack(struct timer_list *timer); | 111 | extern void init_timer_on_stack_key(struct timer_list *timer, |
112 | const char *name, | ||
113 | struct lock_class_key *key); | ||
45 | extern void destroy_timer_on_stack(struct timer_list *timer); | 114 | extern void destroy_timer_on_stack(struct timer_list *timer); |
46 | #else | 115 | #else |
47 | static inline void destroy_timer_on_stack(struct timer_list *timer) { } | 116 | static inline void destroy_timer_on_stack(struct timer_list *timer) { } |
48 | static inline void init_timer_on_stack(struct timer_list *timer) | 117 | static inline void init_timer_on_stack_key(struct timer_list *timer, |
118 | const char *name, | ||
119 | struct lock_class_key *key) | ||
49 | { | 120 | { |
50 | init_timer(timer); | 121 | init_timer_key(timer, name, key); |
51 | } | 122 | } |
52 | #endif | 123 | #endif |
53 | 124 | ||
54 | static inline void setup_timer(struct timer_list * timer, | 125 | static inline void setup_timer_key(struct timer_list * timer, |
126 | const char *name, | ||
127 | struct lock_class_key *key, | ||
55 | void (*function)(unsigned long), | 128 | void (*function)(unsigned long), |
56 | unsigned long data) | 129 | unsigned long data) |
57 | { | 130 | { |
58 | timer->function = function; | 131 | timer->function = function; |
59 | timer->data = data; | 132 | timer->data = data; |
60 | init_timer(timer); | 133 | init_timer_key(timer, name, key); |
61 | } | 134 | } |
62 | 135 | ||
63 | static inline void setup_timer_on_stack(struct timer_list *timer, | 136 | static inline void setup_timer_on_stack_key(struct timer_list *timer, |
137 | const char *name, | ||
138 | struct lock_class_key *key, | ||
64 | void (*function)(unsigned long), | 139 | void (*function)(unsigned long), |
65 | unsigned long data) | 140 | unsigned long data) |
66 | { | 141 | { |
67 | timer->function = function; | 142 | timer->function = function; |
68 | timer->data = data; | 143 | timer->data = data; |
69 | init_timer_on_stack(timer); | 144 | init_timer_on_stack_key(timer, name, key); |
70 | } | 145 | } |
71 | 146 | ||
72 | /** | 147 | /** |