diff options
-rw-r--r-- | include/linux/alarmtimer.h | 34 | ||||
-rw-r--r-- | kernel/time/alarmtimer.c | 21 |
2 files changed, 47 insertions, 8 deletions
diff --git a/include/linux/alarmtimer.h b/include/linux/alarmtimer.h index c854a8efa863..304124a6c982 100644 --- a/include/linux/alarmtimer.h +++ b/include/linux/alarmtimer.h | |||
@@ -18,6 +18,11 @@ enum alarmtimer_restart { | |||
18 | ALARMTIMER_RESTART, | 18 | ALARMTIMER_RESTART, |
19 | }; | 19 | }; |
20 | 20 | ||
21 | |||
22 | #define ALARMTIMER_STATE_INACTIVE 0x00 | ||
23 | #define ALARMTIMER_STATE_ENQUEUED 0x01 | ||
24 | #define ALARMTIMER_STATE_CALLBACK 0x02 | ||
25 | |||
21 | /** | 26 | /** |
22 | * struct alarm - Alarm timer structure | 27 | * struct alarm - Alarm timer structure |
23 | * @node: timerqueue node for adding to the event list this value | 28 | * @node: timerqueue node for adding to the event list this value |
@@ -32,7 +37,7 @@ struct alarm { | |||
32 | struct timerqueue_node node; | 37 | struct timerqueue_node node; |
33 | enum alarmtimer_restart (*function)(struct alarm *, ktime_t now); | 38 | enum alarmtimer_restart (*function)(struct alarm *, ktime_t now); |
34 | enum alarmtimer_type type; | 39 | enum alarmtimer_type type; |
35 | bool enabled; | 40 | int state; |
36 | void *data; | 41 | void *data; |
37 | }; | 42 | }; |
38 | 43 | ||
@@ -43,4 +48,31 @@ void alarm_cancel(struct alarm *alarm); | |||
43 | 48 | ||
44 | u64 alarm_forward(struct alarm *alarm, ktime_t now, ktime_t interval); | 49 | u64 alarm_forward(struct alarm *alarm, ktime_t now, ktime_t interval); |
45 | 50 | ||
51 | /* | ||
52 | * A alarmtimer is active, when it is enqueued into timerqueue or the | ||
53 | * callback function is running. | ||
54 | */ | ||
55 | static inline int alarmtimer_active(const struct alarm *timer) | ||
56 | { | ||
57 | return timer->state != ALARMTIMER_STATE_INACTIVE; | ||
58 | } | ||
59 | |||
60 | /* | ||
61 | * Helper function to check, whether the timer is on one of the queues | ||
62 | */ | ||
63 | static inline int alarmtimer_is_queued(struct alarm *timer) | ||
64 | { | ||
65 | return timer->state & ALARMTIMER_STATE_ENQUEUED; | ||
66 | } | ||
67 | |||
68 | /* | ||
69 | * Helper function to check, whether the timer is running the callback | ||
70 | * function | ||
71 | */ | ||
72 | static inline int alarmtimer_callback_running(struct alarm *timer) | ||
73 | { | ||
74 | return timer->state & ALARMTIMER_STATE_CALLBACK; | ||
75 | } | ||
76 | |||
77 | |||
46 | #endif | 78 | #endif |
diff --git a/kernel/time/alarmtimer.c b/kernel/time/alarmtimer.c index 90935591dd44..5b14cc29b6a6 100644 --- a/kernel/time/alarmtimer.c +++ b/kernel/time/alarmtimer.c | |||
@@ -126,6 +126,8 @@ static struct rtc_device *alarmtimer_get_rtcdev(void) | |||
126 | static void alarmtimer_enqueue(struct alarm_base *base, struct alarm *alarm) | 126 | static void alarmtimer_enqueue(struct alarm_base *base, struct alarm *alarm) |
127 | { | 127 | { |
128 | timerqueue_add(&base->timerqueue, &alarm->node); | 128 | timerqueue_add(&base->timerqueue, &alarm->node); |
129 | alarm->state |= ALARMTIMER_STATE_ENQUEUED; | ||
130 | |||
129 | if (&alarm->node == timerqueue_getnext(&base->timerqueue)) { | 131 | if (&alarm->node == timerqueue_getnext(&base->timerqueue)) { |
130 | hrtimer_try_to_cancel(&base->timer); | 132 | hrtimer_try_to_cancel(&base->timer); |
131 | hrtimer_start(&base->timer, alarm->node.expires, | 133 | hrtimer_start(&base->timer, alarm->node.expires, |
@@ -147,7 +149,12 @@ static void alarmtimer_remove(struct alarm_base *base, struct alarm *alarm) | |||
147 | { | 149 | { |
148 | struct timerqueue_node *next = timerqueue_getnext(&base->timerqueue); | 150 | struct timerqueue_node *next = timerqueue_getnext(&base->timerqueue); |
149 | 151 | ||
152 | if (!(alarm->state & ALARMTIMER_STATE_ENQUEUED)) | ||
153 | return; | ||
154 | |||
150 | timerqueue_del(&base->timerqueue, &alarm->node); | 155 | timerqueue_del(&base->timerqueue, &alarm->node); |
156 | alarm->state &= ~ALARMTIMER_STATE_ENQUEUED; | ||
157 | |||
151 | if (next == &alarm->node) { | 158 | if (next == &alarm->node) { |
152 | hrtimer_try_to_cancel(&base->timer); | 159 | hrtimer_try_to_cancel(&base->timer); |
153 | next = timerqueue_getnext(&base->timerqueue); | 160 | next = timerqueue_getnext(&base->timerqueue); |
@@ -188,16 +195,18 @@ static enum hrtimer_restart alarmtimer_fired(struct hrtimer *timer) | |||
188 | alarm = container_of(next, struct alarm, node); | 195 | alarm = container_of(next, struct alarm, node); |
189 | 196 | ||
190 | timerqueue_del(&base->timerqueue, &alarm->node); | 197 | timerqueue_del(&base->timerqueue, &alarm->node); |
191 | alarm->enabled = 0; | 198 | alarm->state &= ~ALARMTIMER_STATE_ENQUEUED; |
192 | 199 | ||
200 | alarm->state |= ALARMTIMER_STATE_CALLBACK; | ||
193 | spin_unlock_irqrestore(&base->lock, flags); | 201 | spin_unlock_irqrestore(&base->lock, flags); |
194 | if (alarm->function) | 202 | if (alarm->function) |
195 | restart = alarm->function(alarm, now); | 203 | restart = alarm->function(alarm, now); |
196 | spin_lock_irqsave(&base->lock, flags); | 204 | spin_lock_irqsave(&base->lock, flags); |
205 | alarm->state &= ~ALARMTIMER_STATE_CALLBACK; | ||
197 | 206 | ||
198 | if (restart != ALARMTIMER_NORESTART) { | 207 | if (restart != ALARMTIMER_NORESTART) { |
199 | timerqueue_add(&base->timerqueue, &alarm->node); | 208 | timerqueue_add(&base->timerqueue, &alarm->node); |
200 | alarm->enabled = 1; | 209 | alarm->state |= ALARMTIMER_STATE_ENQUEUED; |
201 | } | 210 | } |
202 | } | 211 | } |
203 | 212 | ||
@@ -305,7 +314,7 @@ void alarm_init(struct alarm *alarm, enum alarmtimer_type type, | |||
305 | timerqueue_init(&alarm->node); | 314 | timerqueue_init(&alarm->node); |
306 | alarm->function = function; | 315 | alarm->function = function; |
307 | alarm->type = type; | 316 | alarm->type = type; |
308 | alarm->enabled = 0; | 317 | alarm->state = ALARMTIMER_STATE_INACTIVE; |
309 | } | 318 | } |
310 | 319 | ||
311 | /** | 320 | /** |
@@ -319,11 +328,10 @@ void alarm_start(struct alarm *alarm, ktime_t start) | |||
319 | unsigned long flags; | 328 | unsigned long flags; |
320 | 329 | ||
321 | spin_lock_irqsave(&base->lock, flags); | 330 | spin_lock_irqsave(&base->lock, flags); |
322 | if (alarm->enabled) | 331 | if (alarmtimer_active(alarm)) |
323 | alarmtimer_remove(base, alarm); | 332 | alarmtimer_remove(base, alarm); |
324 | alarm->node.expires = start; | 333 | alarm->node.expires = start; |
325 | alarmtimer_enqueue(base, alarm); | 334 | alarmtimer_enqueue(base, alarm); |
326 | alarm->enabled = 1; | ||
327 | spin_unlock_irqrestore(&base->lock, flags); | 335 | spin_unlock_irqrestore(&base->lock, flags); |
328 | } | 336 | } |
329 | 337 | ||
@@ -337,9 +345,8 @@ void alarm_cancel(struct alarm *alarm) | |||
337 | unsigned long flags; | 345 | unsigned long flags; |
338 | 346 | ||
339 | spin_lock_irqsave(&base->lock, flags); | 347 | spin_lock_irqsave(&base->lock, flags); |
340 | if (alarm->enabled) | 348 | if (alarmtimer_is_queued(alarm)) |
341 | alarmtimer_remove(base, alarm); | 349 | alarmtimer_remove(base, alarm); |
342 | alarm->enabled = 0; | ||
343 | spin_unlock_irqrestore(&base->lock, flags); | 350 | spin_unlock_irqrestore(&base->lock, flags); |
344 | } | 351 | } |
345 | 352 | ||