aboutsummaryrefslogtreecommitdiffstats
path: root/kernel/time
diff options
context:
space:
mode:
authorJohn Stultz <john.stultz@linaro.org>2011-08-10 15:41:36 -0400
committerJohn Stultz <john.stultz@linaro.org>2011-08-10 17:55:29 -0400
commit9082c465a5403f4a98734193e078552991a2e283 (patch)
tree387e564f326488abe9ee84b0c723294ea573de1e /kernel/time
parenta28cde81ab13cc251748a4c4ef06883dd09a10ea (diff)
alarmtimers: Add try_to_cancel functionality
There's a number of edge cases when cancelling a alarm, so to be sure we accurately do so, introduce try_to_cancel, which returns proper failure errors if it cannot. Also modify cancel to spin until the alarm is properly disabled. CC: Thomas Gleixner <tglx@linutronix.de> Signed-off-by: John Stultz <john.stultz@linaro.org>
Diffstat (limited to 'kernel/time')
-rw-r--r--kernel/time/alarmtimer.c43
1 files changed, 37 insertions, 6 deletions
diff --git a/kernel/time/alarmtimer.c b/kernel/time/alarmtimer.c
index 5b14cc29b6a6..bdb7342b6896 100644
--- a/kernel/time/alarmtimer.c
+++ b/kernel/time/alarmtimer.c
@@ -336,21 +336,49 @@ void alarm_start(struct alarm *alarm, ktime_t start)
336} 336}
337 337
338/** 338/**
339 * alarm_cancel - Tries to cancel an alarm timer 339 * alarm_try_to_cancel - Tries to cancel an alarm timer
340 * @alarm: ptr to alarm to be canceled 340 * @alarm: ptr to alarm to be canceled
341 *
342 * Returns 1 if the timer was canceled, 0 if it was not running,
343 * and -1 if the callback was running
341 */ 344 */
342void alarm_cancel(struct alarm *alarm) 345int alarm_try_to_cancel(struct alarm *alarm)
343{ 346{
344 struct alarm_base *base = &alarm_bases[alarm->type]; 347 struct alarm_base *base = &alarm_bases[alarm->type];
345 unsigned long flags; 348 unsigned long flags;
346 349 int ret = -1;
347 spin_lock_irqsave(&base->lock, flags); 350 spin_lock_irqsave(&base->lock, flags);
348 if (alarmtimer_is_queued(alarm)) 351
352 if (alarmtimer_callback_running(alarm))
353 goto out;
354
355 if (alarmtimer_is_queued(alarm)) {
349 alarmtimer_remove(base, alarm); 356 alarmtimer_remove(base, alarm);
357 ret = 1;
358 } else
359 ret = 0;
360out:
350 spin_unlock_irqrestore(&base->lock, flags); 361 spin_unlock_irqrestore(&base->lock, flags);
362 return ret;
351} 363}
352 364
353 365
366/**
367 * alarm_cancel - Spins trying to cancel an alarm timer until it is done
368 * @alarm: ptr to alarm to be canceled
369 *
370 * Returns 1 if the timer was canceled, 0 if it was not active.
371 */
372int alarm_cancel(struct alarm *alarm)
373{
374 for (;;) {
375 int ret = alarm_try_to_cancel(alarm);
376 if (ret >= 0)
377 return ret;
378 cpu_relax();
379 }
380}
381
354 382
355u64 alarm_forward(struct alarm *alarm, ktime_t now, ktime_t interval) 383u64 alarm_forward(struct alarm *alarm, ktime_t now, ktime_t interval)
356{ 384{
@@ -510,7 +538,9 @@ static int alarm_timer_del(struct k_itimer *timr)
510 if (!rtcdev) 538 if (!rtcdev)
511 return -ENOTSUPP; 539 return -ENOTSUPP;
512 540
513 alarm_cancel(&timr->it.alarm.alarmtimer); 541 if (alarm_try_to_cancel(&timr->it.alarm.alarmtimer) < 0)
542 return TIMER_RETRY;
543
514 return 0; 544 return 0;
515} 545}
516 546
@@ -534,7 +564,8 @@ static int alarm_timer_set(struct k_itimer *timr, int flags,
534 alarm_timer_get(timr, old_setting); 564 alarm_timer_get(timr, old_setting);
535 565
536 /* If the timer was already set, cancel it */ 566 /* If the timer was already set, cancel it */
537 alarm_cancel(&timr->it.alarm.alarmtimer); 567 if (alarm_try_to_cancel(&timr->it.alarm.alarmtimer) < 0)
568 return TIMER_RETRY;
538 569
539 /* start the timer */ 570 /* start the timer */
540 timr->it.alarm.interval = timespec_to_ktime(new_setting->it_interval); 571 timr->it.alarm.interval = timespec_to_ktime(new_setting->it_interval);