/*
* The timer bases:
+ *
+ * Note: If we want to add new timer bases, we have to skip the two
+ * clock ids captured by the cpu-timers. We do this by holding empty
+ * entries rather than doing math adjustment of the clock ids.
+ * This ensures that we capture erroneous accesses to these clock ids
+ * rather than moving them into the range of valid clock id's.
*/
#define MAX_HRTIMER_BASES 2
}
/**
- * hrtimer_rebase - rebase an initialized hrtimer to a different base
+ * hrtimer_init - initialize a timer to the given clock
*
- * @timer: the timer to be rebased
+ * @timer: the timer to be initialized
* @clock_id: the clock to be used
+ * @mode: timer mode abs/rel
*/
-void hrtimer_rebase(struct hrtimer *timer, const clockid_t clock_id)
+void hrtimer_init(struct hrtimer *timer, clockid_t clock_id,
+ enum hrtimer_mode mode)
{
struct hrtimer_base *bases;
+ memset(timer, 0, sizeof(struct hrtimer));
+
bases = per_cpu(hrtimer_bases, raw_smp_processor_id());
- timer->base = &bases[clock_id];
-}
-/**
- * hrtimer_init - initialize a timer to the given clock
- *
- * @timer: the timer to be initialized
- * @clock_id: the clock to be used
- */
-void hrtimer_init(struct hrtimer *timer, const clockid_t clock_id)
-{
- memset(timer, 0, sizeof(struct hrtimer));
- hrtimer_rebase(timer, clock_id);
+ if (clock_id == CLOCK_REALTIME && mode != HRTIMER_ABS)
+ clock_id = CLOCK_MONOTONIC;
+
+ timer->base = &bases[clock_id];
}
/**
return schedule_hrtimer(timer, mode);
}
-static long __sched
-nanosleep_restart(struct restart_block *restart, clockid_t clockid)
+static long __sched nanosleep_restart(struct restart_block *restart)
{
struct timespec __user *rmtp;
struct timespec tu;
restart->fn = do_no_restart_syscall;
- hrtimer_init(&timer, clockid);
+ hrtimer_init(&timer, (clockid_t) restart->arg3, HRTIMER_ABS);
timer.expires.tv64 = ((u64)restart->arg1 << 32) | (u64) restart->arg0;
return -ERESTART_RESTARTBLOCK;
}
-static long __sched nanosleep_restart_mono(struct restart_block *restart)
-{
- return nanosleep_restart(restart, CLOCK_MONOTONIC);
-}
-
-static long __sched nanosleep_restart_real(struct restart_block *restart)
-{
- return nanosleep_restart(restart, CLOCK_REALTIME);
-}
-
long hrtimer_nanosleep(struct timespec *rqtp, struct timespec __user *rmtp,
const enum hrtimer_mode mode, const clockid_t clockid)
{
struct timespec tu;
ktime_t rem;
- hrtimer_init(&timer, clockid);
+ hrtimer_init(&timer, clockid, mode);
timer.expires = timespec_to_ktime(*rqtp);
if (rem.tv64 <= 0)
return 0;
- /* Absolute timers do not update the rmtp value: */
+ /* Absolute timers do not update the rmtp value and restart: */
if (mode == HRTIMER_ABS)
return -ERESTARTNOHAND;
return -EFAULT;
restart = ¤t_thread_info()->restart_block;
- restart->fn = (clockid == CLOCK_MONOTONIC) ?
- nanosleep_restart_mono : nanosleep_restart_real;
+ restart->fn = nanosleep_restart;
restart->arg0 = timer.expires.tv64 & 0xFFFFFFFF;
restart->arg1 = timer.expires.tv64 >> 32;
restart->arg2 = (unsigned long) rmtp;
+ restart->arg3 = (unsigned long) timer.base->index;
return -ERESTART_RESTARTBLOCK;
}
struct hrtimer_base *base = per_cpu(hrtimer_bases, cpu);
int i;
- for (i = 0; i < MAX_HRTIMER_BASES; i++) {
+ for (i = 0; i < MAX_HRTIMER_BASES; i++, base++)
spin_lock_init(&base->lock);
- base++;
- }
}
#ifdef CONFIG_HOTPLUG_CPU
static int common_timer_create(struct k_itimer *new_timer)
{
- hrtimer_init(&new_timer->it.real.timer, new_timer->it_clock);
- new_timer->it.real.timer.data = new_timer;
- new_timer->it.real.timer.function = posix_timer_fn;
+ hrtimer_init(&new_timer->it.real.timer, new_timer->it_clock, 0);
return 0;
}
struct itimerspec *new_setting, struct itimerspec *old_setting)
{
struct hrtimer *timer = &timr->it.real.timer;
+ enum hrtimer_mode mode;
if (old_setting)
common_timer_get(timr, old_setting);
if (!new_setting->it_value.tv_sec && !new_setting->it_value.tv_nsec)
return 0;
- /* Posix madness. Only absolute CLOCK_REALTIME timers
- * are affected by clock sets. So we must reiniatilize
- * the timer.
- */
- if (timr->it_clock == CLOCK_REALTIME && (flags & TIMER_ABSTIME))
- hrtimer_rebase(timer, CLOCK_REALTIME);
- else
- hrtimer_rebase(timer, CLOCK_MONOTONIC);
+ mode = flags & TIMER_ABSTIME ? HRTIMER_ABS : HRTIMER_REL;
+ hrtimer_init(&timr->it.real.timer, timr->it_clock, mode);
+ timr->it.real.timer.data = timr;
+ timr->it.real.timer.function = posix_timer_fn;
timer->expires = timespec_to_ktime(new_setting->it_value);
if (((timr->it_sigev_notify & ~SIGEV_THREAD_ID) == SIGEV_NONE))
return 0;
- hrtimer_start(timer, timer->expires, (flags & TIMER_ABSTIME) ?
- HRTIMER_ABS : HRTIMER_REL);
+ hrtimer_start(timer, timer->expires, mode);
return 0;
}
static int common_nsleep(const clockid_t which_clock, int flags,
struct timespec *tsave, struct timespec __user *rmtp)
{
- int mode = flags & TIMER_ABSTIME ? HRTIMER_ABS : HRTIMER_REL;
- int clockid = which_clock;
-
- switch (which_clock) {
- case CLOCK_REALTIME:
- /* Posix madness. Only absolute timers on clock realtime
- are affected by clock set. */
- if (mode != HRTIMER_ABS)
- clockid = CLOCK_MONOTONIC;
- case CLOCK_MONOTONIC:
- break;
- default:
- return -EINVAL;
- }
- return hrtimer_nanosleep(tsave, rmtp, mode, clockid);
+ return hrtimer_nanosleep(tsave, rmtp, flags & TIMER_ABSTIME ?
+ HRTIMER_ABS : HRTIMER_REL, which_clock);
}
asmlinkage long