/** * Get the count of overruns for the last tick. * * This service returns the count of pending overruns for the last tick of a * given timer, as measured by the difference between the expected expiry date * of the timer and the date @a now passed as argument. * * @param timer The address of a valid timer descriptor. * * @param now current date (in the monotonic time base) * * @return the number of overruns of @a timer at date @a now */ unsigned long xntimer_get_overruns(xntimer_t *timer, xnticks_t now) { xnticks_t period = xntimer_interval(timer); xnsticks_t delta = now - timer->pexpect; unsigned long overruns = 0; if (unlikely(delta >= (xnsticks_t) period)) { overruns = xnarch_div64(delta, period); timer->pexpect += period * overruns; } timer->pexpect += period; return overruns; }
/** * Get the count of overruns for the last tick. * * This service returns the count of pending overruns for the last * tick of a given timer, as measured by the difference between the * expected expiry date of the timer and the date @a now passed as * argument. * * @param timer The address of a valid timer descriptor. * * @param now current date (as * xnclock_read_raw(xntimer_clock(timer))) * * @return the number of overruns of @a timer at date @a now * * @coretags{unrestricted, atomic-entry} */ unsigned long long xntimer_get_overruns(struct xntimer *timer, xnticks_t now) { xnticks_t period = timer->interval; xnsticks_t delta; unsigned long long overruns = 0; delta = now - xntimer_pexpect(timer); if (unlikely(delta >= (xnsticks_t) period)) { period = timer->interval_ns; delta = xnclock_ticks_to_ns(xntimer_clock(timer), delta); overruns = xnarch_div64(delta, period); timer->pexpect_ticks += overruns; } timer->pexpect_ticks++; return overruns; }
/** * Arm a timer. * * Activates a timer so that the associated timeout handler will be * fired after each expiration time. A timer can be either periodic or * one-shot, depending on the reload value passed to this routine. The * given timer must have been previously initialized. * * A timer is attached to the clock specified in xntimer_init(). * * @param timer The address of a valid timer descriptor. * * @param value The date of the initial timer shot, expressed in * nanoseconds. * * @param interval The reload value of the timer. It is a periodic * interval value to be used for reprogramming the next timer shot, * expressed in nanoseconds. If @a interval is equal to XN_INFINITE, * the timer will not be reloaded after it has expired. * * @param mode The timer mode. It can be XN_RELATIVE if @a value shall * be interpreted as a relative date, XN_ABSOLUTE for an absolute date * based on the monotonic clock of the related time base (as returned * my xnclock_read_monotonic()), or XN_REALTIME if the absolute date * is based on the adjustable real-time date for the relevant clock * (obtained from xnclock_read_realtime()). * * @return 0 is returned upon success, or -ETIMEDOUT if an absolute * date in the past has been given. In such an event, the timer is * nevertheless armed for the next shot in the timeline if @a interval * is different from XN_INFINITE. * * @coretags{unrestricted, atomic-entry} */ int xntimer_start(struct xntimer *timer, xnticks_t value, xnticks_t interval, xntmode_t mode) { struct xnclock *clock = xntimer_clock(timer); xntimerq_t *q = xntimer_percpu_queue(timer); xnticks_t date, now, delay, period; unsigned long gravity; struct xnsched *sched; int ret = 0; trace_cobalt_timer_start(timer, value, interval, mode); if ((timer->status & XNTIMER_DEQUEUED) == 0) xntimer_dequeue(timer, q); now = xnclock_read_raw(clock); timer->status &= ~(XNTIMER_REALTIME | XNTIMER_FIRED | XNTIMER_PERIODIC); switch (mode) { case XN_RELATIVE: if ((xnsticks_t)value < 0) return -ETIMEDOUT; date = xnclock_ns_to_ticks(clock, value) + now; break; case XN_REALTIME: timer->status |= XNTIMER_REALTIME; value -= xnclock_get_offset(clock); /* fall through */ default: /* XN_ABSOLUTE || XN_REALTIME */ date = xnclock_ns_to_ticks(clock, value); if ((xnsticks_t)(date - now) <= 0) { ret = -ETIMEDOUT; if (interval == XN_INFINITE) return ret; /* * We are late on arrival for the first * delivery, wait for the next shot on the * periodic time line. */ delay = now - date; period = xnclock_ns_to_ticks(clock, interval); date += period * (xnarch_div64(delay, period) + 1); } break; } /* * To cope with the basic system latency, we apply a clock * gravity value, which is the amount of time expressed in * clock ticks by which we should anticipate the shot for any * outstanding timer. The gravity value varies with the type * of context the timer wakes up, i.e. irq handler, kernel or * user thread. */ gravity = xntimer_gravity(timer); xntimerh_date(&timer->aplink) = date - gravity; if (now >= xntimerh_date(&timer->aplink)) xntimerh_date(&timer->aplink) += gravity / 2; timer->interval_ns = XN_INFINITE; timer->interval = XN_INFINITE; if (interval != XN_INFINITE) { timer->interval_ns = interval; timer->interval = xnclock_ns_to_ticks(clock, interval); timer->periodic_ticks = 0; timer->start_date = date; timer->pexpect_ticks = 0; timer->status |= XNTIMER_PERIODIC; } xntimer_enqueue(timer, q); timer->status |= XNTIMER_RUNNING; if (xntimer_heading_p(timer)) { sched = xntimer_sched(timer); if (sched != xnsched_current()) xnclock_remote_shot(clock, sched); else xnclock_program_shot(clock, sched); } return ret; }