hrtimers: Avoid touching inactive timer bases
Instead of iterating over all possible timer bases avoid it by marking the active bases in the cpu base. Signed-off-by: Thomas Gleixner <tglx@linutronix.de> Reviewed-by: Peter Zijlstra <peterz@infradead.org>
This commit is contained in:
parent
f24444b01b
commit
ab8177bc53
6 changed files with 29 additions and 19 deletions
|
@ -143,7 +143,8 @@ struct hrtimer_sleeper {
|
|||
*/
|
||||
struct hrtimer_clock_base {
|
||||
struct hrtimer_cpu_base *cpu_base;
|
||||
clockid_t index;
|
||||
int index;
|
||||
clockid_t clockid;
|
||||
struct timerqueue_head active;
|
||||
ktime_t resolution;
|
||||
ktime_t (*get_time)(void);
|
||||
|
@ -162,7 +163,7 @@ enum hrtimer_base_type {
|
|||
* struct hrtimer_cpu_base - the per cpu clock bases
|
||||
* @lock: lock protecting the base and associated clock bases
|
||||
* and timers
|
||||
* @clock_base: array of clock bases for this cpu
|
||||
* @active_bases: Bitfield to mark bases with active timers
|
||||
* @expires_next: absolute time of the next event which was scheduled
|
||||
* via clock_set_next_event()
|
||||
* @hres_active: State of high resolution mode
|
||||
|
@ -171,9 +172,11 @@ enum hrtimer_base_type {
|
|||
* @nr_retries: Total number of hrtimer interrupt retries
|
||||
* @nr_hangs: Total number of hrtimer interrupt hangs
|
||||
* @max_hang_time: Maximum time spent in hrtimer_interrupt
|
||||
* @clock_base: array of clock bases for this cpu
|
||||
*/
|
||||
struct hrtimer_cpu_base {
|
||||
raw_spinlock_t lock;
|
||||
unsigned long active_bases;
|
||||
#ifdef CONFIG_HIGH_RES_TIMERS
|
||||
ktime_t expires_next;
|
||||
int hres_active;
|
||||
|
|
|
@ -29,7 +29,7 @@ struct restart_block {
|
|||
} futex;
|
||||
/* For nanosleep */
|
||||
struct {
|
||||
clockid_t index;
|
||||
clockid_t clockid;
|
||||
struct timespec __user *rmtp;
|
||||
#ifdef CONFIG_COMPAT
|
||||
struct compat_timespec __user *compat_rmtp;
|
||||
|
|
|
@ -64,17 +64,20 @@ DEFINE_PER_CPU(struct hrtimer_cpu_base, hrtimer_bases) =
|
|||
.clock_base =
|
||||
{
|
||||
{
|
||||
.index = CLOCK_REALTIME,
|
||||
.index = HRTIMER_BASE_REALTIME,
|
||||
.clockid = CLOCK_REALTIME,
|
||||
.get_time = &ktime_get_real,
|
||||
.resolution = KTIME_LOW_RES,
|
||||
},
|
||||
{
|
||||
.index = CLOCK_MONOTONIC,
|
||||
.index = HRTIMER_BASE_MONOTONIC,
|
||||
.clockid = CLOCK_MONOTONIC,
|
||||
.get_time = &ktime_get,
|
||||
.resolution = KTIME_LOW_RES,
|
||||
},
|
||||
{
|
||||
.index = CLOCK_BOOTTIME,
|
||||
.index = HRTIMER_BASE_BOOTTIME,
|
||||
.clockid = CLOCK_BOOTTIME,
|
||||
.get_time = &ktime_get_boottime,
|
||||
.resolution = KTIME_LOW_RES,
|
||||
},
|
||||
|
@ -196,7 +199,7 @@ switch_hrtimer_base(struct hrtimer *timer, struct hrtimer_clock_base *base,
|
|||
struct hrtimer_cpu_base *new_cpu_base;
|
||||
int this_cpu = smp_processor_id();
|
||||
int cpu = hrtimer_get_target(this_cpu, pinned);
|
||||
int basenum = hrtimer_clockid_to_base(base->index);
|
||||
int basenum = base->index;
|
||||
|
||||
again:
|
||||
new_cpu_base = &per_cpu(hrtimer_bases, cpu);
|
||||
|
@ -857,6 +860,7 @@ static int enqueue_hrtimer(struct hrtimer *timer,
|
|||
debug_activate(timer);
|
||||
|
||||
timerqueue_add(&base->active, &timer->node);
|
||||
base->cpu_base->active_bases |= 1 << base->index;
|
||||
|
||||
/*
|
||||
* HRTIMER_STATE_ENQUEUED is or'ed to the current state to preserve the
|
||||
|
@ -898,6 +902,8 @@ static void __remove_hrtimer(struct hrtimer *timer,
|
|||
#endif
|
||||
}
|
||||
timerqueue_del(&base->active, &timer->node);
|
||||
if (!timerqueue_getnext(&base->active))
|
||||
base->cpu_base->active_bases &= ~(1 << base->index);
|
||||
out:
|
||||
timer->state = newstate;
|
||||
}
|
||||
|
@ -1235,7 +1241,6 @@ static void __run_hrtimer(struct hrtimer *timer, ktime_t *now)
|
|||
void hrtimer_interrupt(struct clock_event_device *dev)
|
||||
{
|
||||
struct hrtimer_cpu_base *cpu_base = &__get_cpu_var(hrtimer_bases);
|
||||
struct hrtimer_clock_base *base;
|
||||
ktime_t expires_next, now, entry_time, delta;
|
||||
int i, retries = 0;
|
||||
|
||||
|
@ -1257,12 +1262,15 @@ void hrtimer_interrupt(struct clock_event_device *dev)
|
|||
*/
|
||||
cpu_base->expires_next.tv64 = KTIME_MAX;
|
||||
|
||||
base = cpu_base->clock_base;
|
||||
|
||||
for (i = 0; i < HRTIMER_MAX_CLOCK_BASES; i++) {
|
||||
ktime_t basenow;
|
||||
struct hrtimer_clock_base *base;
|
||||
struct timerqueue_node *node;
|
||||
ktime_t basenow;
|
||||
|
||||
if (!(cpu_base->active_bases & (1 << i)))
|
||||
continue;
|
||||
|
||||
base = cpu_base->clock_base + i;
|
||||
basenow = ktime_add(now, base->offset);
|
||||
|
||||
while ((node = timerqueue_getnext(&base->active))) {
|
||||
|
@ -1295,7 +1303,6 @@ void hrtimer_interrupt(struct clock_event_device *dev)
|
|||
|
||||
__run_hrtimer(timer, &basenow);
|
||||
}
|
||||
base++;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -1526,7 +1533,7 @@ long __sched hrtimer_nanosleep_restart(struct restart_block *restart)
|
|||
struct timespec __user *rmtp;
|
||||
int ret = 0;
|
||||
|
||||
hrtimer_init_on_stack(&t.timer, restart->nanosleep.index,
|
||||
hrtimer_init_on_stack(&t.timer, restart->nanosleep.clockid,
|
||||
HRTIMER_MODE_ABS);
|
||||
hrtimer_set_expires_tv64(&t.timer, restart->nanosleep.expires);
|
||||
|
||||
|
@ -1578,7 +1585,7 @@ long hrtimer_nanosleep(struct timespec *rqtp, struct timespec __user *rmtp,
|
|||
|
||||
restart = ¤t_thread_info()->restart_block;
|
||||
restart->fn = hrtimer_nanosleep_restart;
|
||||
restart->nanosleep.index = t.timer.base->index;
|
||||
restart->nanosleep.clockid = t.timer.base->clockid;
|
||||
restart->nanosleep.rmtp = rmtp;
|
||||
restart->nanosleep.expires = hrtimer_get_expires_tv64(&t.timer);
|
||||
|
||||
|
|
|
@ -1514,7 +1514,7 @@ static int posix_cpu_nsleep(const clockid_t which_clock, int flags,
|
|||
return -EFAULT;
|
||||
|
||||
restart_block->fn = posix_cpu_nsleep_restart;
|
||||
restart_block->nanosleep.index = which_clock;
|
||||
restart_block->nanosleep.clockid = which_clock;
|
||||
restart_block->nanosleep.rmtp = rmtp;
|
||||
restart_block->nanosleep.expires = timespec_to_ns(rqtp);
|
||||
}
|
||||
|
@ -1523,7 +1523,7 @@ static int posix_cpu_nsleep(const clockid_t which_clock, int flags,
|
|||
|
||||
static long posix_cpu_nsleep_restart(struct restart_block *restart_block)
|
||||
{
|
||||
clockid_t which_clock = restart_block->nanosleep.index;
|
||||
clockid_t which_clock = restart_block->nanosleep.clockid;
|
||||
struct timespec t;
|
||||
struct itimerspec it;
|
||||
int error;
|
||||
|
|
|
@ -1056,7 +1056,7 @@ SYSCALL_DEFINE4(clock_nanosleep, const clockid_t, which_clock, int, flags,
|
|||
*/
|
||||
long clock_nanosleep_restart(struct restart_block *restart_block)
|
||||
{
|
||||
clockid_t which_clock = restart_block->nanosleep.index;
|
||||
clockid_t which_clock = restart_block->nanosleep.clockid;
|
||||
struct k_clock *kc = clockid_to_kclock(which_clock);
|
||||
|
||||
if (WARN_ON_ONCE(!kc || !kc->nsleep_restart))
|
||||
|
|
|
@ -494,7 +494,7 @@ static int update_rmtp(ktime_t exp, enum alarmtimer_type type,
|
|||
*/
|
||||
static long __sched alarm_timer_nsleep_restart(struct restart_block *restart)
|
||||
{
|
||||
enum alarmtimer_type type = restart->nanosleep.index;
|
||||
enum alarmtimer_type type = restart->nanosleep.clockid;
|
||||
ktime_t exp;
|
||||
struct timespec __user *rmtp;
|
||||
struct alarm alarm;
|
||||
|
@ -573,7 +573,7 @@ static int alarm_timer_nsleep(const clockid_t which_clock, int flags,
|
|||
|
||||
restart = ¤t_thread_info()->restart_block;
|
||||
restart->fn = alarm_timer_nsleep_restart;
|
||||
restart->nanosleep.index = type;
|
||||
restart->nanosleep.clockid = type;
|
||||
restart->nanosleep.expires = exp.tv64;
|
||||
restart->nanosleep.rmtp = rmtp;
|
||||
ret = -ERESTART_RESTARTBLOCK;
|
||||
|
|
Loading…
Reference in a new issue