@@ -660,20 +660,16 @@ static s64 common_hrtimer_forward(struct k_itimer *timr, ktime_t now)
660
660
}
661
661
662
662
/*
663
- * Get the time remaining on a POSIX.1b interval timer. This function
664
- * is ALWAYS called with spin_lock_irq on the timer, thus it must not
665
- * mess with irq.
663
+ * Get the time remaining on a POSIX.1b interval timer.
666
664
*
667
- * We have a couple of messes to clean up here. First there is the case
668
- * of a timer that has a requeue pending. These timers should appear to
669
- * be in the timer list with an expiry as if we were to requeue them
670
- * now.
665
+ * Two issues to handle here:
671
666
*
672
- * The second issue is the SIGEV_NONE timer which may be active but is
673
- * not really ever put in the timer list (to save system resources).
674
- * This timer may be expired, and if so, we will do it here. Otherwise
675
- * it is the same as a requeue pending timer WRT to what we should
676
- * report.
667
+ * 1) The timer has a requeue pending. The return value must appear as
668
+ * if the timer has been requeued right now.
669
+ *
670
+ * 2) The timer is a SIGEV_NONE timer. These timers are never enqueued
671
+ * into the hrtimer queue and therefore never expired. Emulate expiry
672
+ * here taking #1 into account.
677
673
*/
678
674
void common_timer_get (struct k_itimer * timr , struct itimerspec64 * cur_setting )
679
675
{
@@ -689,8 +685,12 @@ void common_timer_get(struct k_itimer *timr, struct itimerspec64 *cur_setting)
689
685
cur_setting -> it_interval = ktime_to_timespec64 (iv );
690
686
} else if (!timr -> it_active ) {
691
687
/*
692
- * SIGEV_NONE oneshot timers are never queued. Check them
693
- * below.
688
+ * SIGEV_NONE oneshot timers are never queued and therefore
689
+ * timr->it_active is always false. The check below
690
+ * vs. remaining time will handle this case.
691
+ *
692
+ * For all other timers there is nothing to update here, so
693
+ * return.
694
694
*/
695
695
if (!sig_none )
696
696
return ;
@@ -699,18 +699,29 @@ void common_timer_get(struct k_itimer *timr, struct itimerspec64 *cur_setting)
699
699
now = kc -> clock_get_ktime (timr -> it_clock );
700
700
701
701
/*
702
- * When a requeue is pending or this is a SIGEV_NONE timer move the
703
- * expiry time forward by intervals, so expiry is > now.
702
+ * If this is an interval timer and either has requeue pending or
703
+ * is a SIGEV_NONE timer move the expiry time forward by intervals,
704
+ * so expiry is > now.
704
705
*/
705
706
if (iv && (timr -> it_requeue_pending & REQUEUE_PENDING || sig_none ))
706
707
timr -> it_overrun += kc -> timer_forward (timr , now );
707
708
708
709
remaining = kc -> timer_remaining (timr , now );
709
- /* Return 0 only, when the timer is expired and not pending */
710
+ /*
711
+ * As @now is retrieved before a possible timer_forward() and
712
+ * cannot be reevaluated by the compiler @remaining is based on the
713
+ * same @now value. Therefore @remaining is consistent vs. @now.
714
+ *
715
+ * Consequently all interval timers, i.e. @iv > 0, cannot have a
716
+ * remaining time <= 0 because timer_forward() guarantees to move
717
+ * them forward so that the next timer expiry is > @now.
718
+ */
710
719
if (remaining <= 0 ) {
711
720
/*
712
- * A single shot SIGEV_NONE timer must return 0, when
713
- * it is expired !
721
+ * A single shot SIGEV_NONE timer must return 0, when it is
722
+ * expired! Timers which have a real signal delivery mode
723
+ * must return a remaining time greater than 0 because the
724
+ * signal has not yet been delivered.
714
725
*/
715
726
if (!sig_none )
716
727
cur_setting -> it_value .tv_nsec = 1 ;
@@ -719,7 +730,6 @@ void common_timer_get(struct k_itimer *timr, struct itimerspec64 *cur_setting)
719
730
}
720
731
}
721
732
722
- /* Get the time remaining on a POSIX.1b interval timer. */
723
733
static int do_timer_gettime (timer_t timer_id , struct itimerspec64 * setting )
724
734
{
725
735
struct k_itimer * timr ;
0 commit comments