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 | ||
