Пример #1
0
/**
 * 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;
}
Пример #2
0
/**
 * 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;
}
Пример #3
0
/**
 * 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;
}