[PATCH] hrtimer: switch itimers to hrtimer
switch itimers to a hrtimers-based implementation Signed-off-by: Thomas Gleixner <tglx@linutronix.de> Signed-off-by: Ingo Molnar <mingo@elte.hu> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org>
This commit is contained in:
parent
df78488de7
commit
2ff678b8da
@ -632,10 +632,10 @@ static inline int de_thread(struct task_struct *tsk)
|
|||||||
* synchronize with any firing (by calling del_timer_sync)
|
* synchronize with any firing (by calling del_timer_sync)
|
||||||
* before we can safely let the old group leader die.
|
* before we can safely let the old group leader die.
|
||||||
*/
|
*/
|
||||||
sig->real_timer.data = (unsigned long)current;
|
sig->real_timer.data = current;
|
||||||
spin_unlock_irq(lock);
|
spin_unlock_irq(lock);
|
||||||
if (del_timer_sync(&sig->real_timer))
|
if (hrtimer_cancel(&sig->real_timer))
|
||||||
add_timer(&sig->real_timer);
|
hrtimer_restart(&sig->real_timer);
|
||||||
spin_lock_irq(lock);
|
spin_lock_irq(lock);
|
||||||
}
|
}
|
||||||
while (atomic_read(&sig->count) > count) {
|
while (atomic_read(&sig->count) > count) {
|
||||||
|
@ -330,7 +330,7 @@ static int do_task_stat(struct task_struct *task, char * buffer, int whole)
|
|||||||
unsigned long min_flt = 0, maj_flt = 0;
|
unsigned long min_flt = 0, maj_flt = 0;
|
||||||
cputime_t cutime, cstime, utime, stime;
|
cputime_t cutime, cstime, utime, stime;
|
||||||
unsigned long rsslim = 0;
|
unsigned long rsslim = 0;
|
||||||
unsigned long it_real_value = 0;
|
DEFINE_KTIME(it_real_value);
|
||||||
struct task_struct *t;
|
struct task_struct *t;
|
||||||
char tcomm[sizeof(task->comm)];
|
char tcomm[sizeof(task->comm)];
|
||||||
|
|
||||||
@ -386,7 +386,7 @@ static int do_task_stat(struct task_struct *task, char * buffer, int whole)
|
|||||||
utime = cputime_add(utime, task->signal->utime);
|
utime = cputime_add(utime, task->signal->utime);
|
||||||
stime = cputime_add(stime, task->signal->stime);
|
stime = cputime_add(stime, task->signal->stime);
|
||||||
}
|
}
|
||||||
it_real_value = task->signal->it_real_value;
|
it_real_value = task->signal->real_timer.expires;
|
||||||
}
|
}
|
||||||
ppid = pid_alive(task) ? task->group_leader->real_parent->tgid : 0;
|
ppid = pid_alive(task) ? task->group_leader->real_parent->tgid : 0;
|
||||||
read_unlock(&tasklist_lock);
|
read_unlock(&tasklist_lock);
|
||||||
@ -435,7 +435,7 @@ static int do_task_stat(struct task_struct *task, char * buffer, int whole)
|
|||||||
priority,
|
priority,
|
||||||
nice,
|
nice,
|
||||||
num_threads,
|
num_threads,
|
||||||
jiffies_to_clock_t(it_real_value),
|
(long) ktime_to_clock_t(it_real_value),
|
||||||
start_time,
|
start_time,
|
||||||
vsize,
|
vsize,
|
||||||
mm ? get_mm_rss(mm) : 0,
|
mm ? get_mm_rss(mm) : 0,
|
||||||
|
@ -105,6 +105,7 @@ extern unsigned long nr_iowait(void);
|
|||||||
#include <linux/param.h>
|
#include <linux/param.h>
|
||||||
#include <linux/resource.h>
|
#include <linux/resource.h>
|
||||||
#include <linux/timer.h>
|
#include <linux/timer.h>
|
||||||
|
#include <linux/hrtimer.h>
|
||||||
|
|
||||||
#include <asm/processor.h>
|
#include <asm/processor.h>
|
||||||
|
|
||||||
@ -398,8 +399,8 @@ struct signal_struct {
|
|||||||
struct list_head posix_timers;
|
struct list_head posix_timers;
|
||||||
|
|
||||||
/* ITIMER_REAL timer for the process */
|
/* ITIMER_REAL timer for the process */
|
||||||
struct timer_list real_timer;
|
struct hrtimer real_timer;
|
||||||
unsigned long it_real_value, it_real_incr;
|
ktime_t it_real_incr;
|
||||||
|
|
||||||
/* ITIMER_PROF and ITIMER_VIRTUAL timers for the process */
|
/* ITIMER_PROF and ITIMER_VIRTUAL timers for the process */
|
||||||
cputime_t it_prof_expires, it_virt_expires;
|
cputime_t it_prof_expires, it_virt_expires;
|
||||||
|
@ -96,6 +96,6 @@ static inline void add_timer(struct timer_list *timer)
|
|||||||
|
|
||||||
extern void init_timers(void);
|
extern void init_timers(void);
|
||||||
extern void run_local_timers(void);
|
extern void run_local_timers(void);
|
||||||
extern void it_real_fn(unsigned long);
|
extern int it_real_fn(void *);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -842,7 +842,7 @@ fastcall NORET_TYPE void do_exit(long code)
|
|||||||
}
|
}
|
||||||
group_dead = atomic_dec_and_test(&tsk->signal->live);
|
group_dead = atomic_dec_and_test(&tsk->signal->live);
|
||||||
if (group_dead) {
|
if (group_dead) {
|
||||||
del_timer_sync(&tsk->signal->real_timer);
|
hrtimer_cancel(&tsk->signal->real_timer);
|
||||||
exit_itimers(tsk->signal);
|
exit_itimers(tsk->signal);
|
||||||
acct_process(code);
|
acct_process(code);
|
||||||
}
|
}
|
||||||
|
@ -801,10 +801,10 @@ static inline int copy_signal(unsigned long clone_flags, struct task_struct * ts
|
|||||||
init_sigpending(&sig->shared_pending);
|
init_sigpending(&sig->shared_pending);
|
||||||
INIT_LIST_HEAD(&sig->posix_timers);
|
INIT_LIST_HEAD(&sig->posix_timers);
|
||||||
|
|
||||||
sig->it_real_value = sig->it_real_incr = 0;
|
hrtimer_init(&sig->real_timer, CLOCK_MONOTONIC);
|
||||||
|
sig->it_real_incr.tv64 = 0;
|
||||||
sig->real_timer.function = it_real_fn;
|
sig->real_timer.function = it_real_fn;
|
||||||
sig->real_timer.data = (unsigned long) tsk;
|
sig->real_timer.data = tsk;
|
||||||
init_timer(&sig->real_timer);
|
|
||||||
|
|
||||||
sig->it_virt_expires = cputime_zero;
|
sig->it_virt_expires = cputime_zero;
|
||||||
sig->it_virt_incr = cputime_zero;
|
sig->it_virt_incr = cputime_zero;
|
||||||
|
106
kernel/itimer.c
106
kernel/itimer.c
@ -12,36 +12,46 @@
|
|||||||
#include <linux/syscalls.h>
|
#include <linux/syscalls.h>
|
||||||
#include <linux/time.h>
|
#include <linux/time.h>
|
||||||
#include <linux/posix-timers.h>
|
#include <linux/posix-timers.h>
|
||||||
|
#include <linux/hrtimer.h>
|
||||||
|
|
||||||
#include <asm/uaccess.h>
|
#include <asm/uaccess.h>
|
||||||
|
|
||||||
static unsigned long it_real_value(struct signal_struct *sig)
|
/**
|
||||||
|
* itimer_get_remtime - get remaining time for the timer
|
||||||
|
*
|
||||||
|
* @timer: the timer to read
|
||||||
|
*
|
||||||
|
* Returns the delta between the expiry time and now, which can be
|
||||||
|
* less than zero or 1usec for an pending expired timer
|
||||||
|
*/
|
||||||
|
static struct timeval itimer_get_remtime(struct hrtimer *timer)
|
||||||
{
|
{
|
||||||
unsigned long val = 0;
|
ktime_t rem = hrtimer_get_remaining(timer);
|
||||||
if (timer_pending(&sig->real_timer)) {
|
|
||||||
val = sig->real_timer.expires - jiffies;
|
|
||||||
|
|
||||||
/* look out for negative/zero itimer.. */
|
/*
|
||||||
if ((long) val <= 0)
|
* Racy but safe: if the itimer expires after the above
|
||||||
val = 1;
|
* hrtimer_get_remtime() call but before this condition
|
||||||
}
|
* then we return 0 - which is correct.
|
||||||
return val;
|
*/
|
||||||
|
if (hrtimer_active(timer)) {
|
||||||
|
if (rem.tv64 <= 0)
|
||||||
|
rem.tv64 = NSEC_PER_USEC;
|
||||||
|
} else
|
||||||
|
rem.tv64 = 0;
|
||||||
|
|
||||||
|
return ktime_to_timeval(rem);
|
||||||
}
|
}
|
||||||
|
|
||||||
int do_getitimer(int which, struct itimerval *value)
|
int do_getitimer(int which, struct itimerval *value)
|
||||||
{
|
{
|
||||||
struct task_struct *tsk = current;
|
struct task_struct *tsk = current;
|
||||||
unsigned long interval, val;
|
|
||||||
cputime_t cinterval, cval;
|
cputime_t cinterval, cval;
|
||||||
|
|
||||||
switch (which) {
|
switch (which) {
|
||||||
case ITIMER_REAL:
|
case ITIMER_REAL:
|
||||||
spin_lock_irq(&tsk->sighand->siglock);
|
value->it_value = itimer_get_remtime(&tsk->signal->real_timer);
|
||||||
interval = tsk->signal->it_real_incr;
|
value->it_interval =
|
||||||
val = it_real_value(tsk->signal);
|
ktime_to_timeval(tsk->signal->it_real_incr);
|
||||||
spin_unlock_irq(&tsk->sighand->siglock);
|
|
||||||
jiffies_to_timeval(val, &value->it_value);
|
|
||||||
jiffies_to_timeval(interval, &value->it_interval);
|
|
||||||
break;
|
break;
|
||||||
case ITIMER_VIRTUAL:
|
case ITIMER_VIRTUAL:
|
||||||
read_lock(&tasklist_lock);
|
read_lock(&tasklist_lock);
|
||||||
@ -113,59 +123,45 @@ asmlinkage long sys_getitimer(int which, struct itimerval __user *value)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void it_real_fn(unsigned long __data)
|
/*
|
||||||
|
* The timer is automagically restarted, when interval != 0
|
||||||
|
*/
|
||||||
|
int it_real_fn(void *data)
|
||||||
{
|
{
|
||||||
struct task_struct * p = (struct task_struct *) __data;
|
struct task_struct *tsk = (struct task_struct *) data;
|
||||||
unsigned long inc = p->signal->it_real_incr;
|
|
||||||
|
|
||||||
send_group_sig_info(SIGALRM, SEND_SIG_PRIV, p);
|
send_group_sig_info(SIGALRM, SEND_SIG_PRIV, tsk);
|
||||||
|
|
||||||
/*
|
if (tsk->signal->it_real_incr.tv64 != 0) {
|
||||||
* Now restart the timer if necessary. We don't need any locking
|
hrtimer_forward(&tsk->signal->real_timer,
|
||||||
* here because do_setitimer makes sure we have finished running
|
tsk->signal->it_real_incr);
|
||||||
* before it touches anything.
|
|
||||||
* Note, we KNOW we are (or should be) at a jiffie edge here so
|
return HRTIMER_RESTART;
|
||||||
* we don't need the +1 stuff. Also, we want to use the prior
|
}
|
||||||
* expire value so as to not "slip" a jiffie if we are late.
|
return HRTIMER_NORESTART;
|
||||||
* Deal with requesting a time prior to "now" here rather than
|
|
||||||
* in add_timer.
|
|
||||||
*/
|
|
||||||
if (!inc)
|
|
||||||
return;
|
|
||||||
while (time_before_eq(p->signal->real_timer.expires, jiffies))
|
|
||||||
p->signal->real_timer.expires += inc;
|
|
||||||
add_timer(&p->signal->real_timer);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int do_setitimer(int which, struct itimerval *value, struct itimerval *ovalue)
|
int do_setitimer(int which, struct itimerval *value, struct itimerval *ovalue)
|
||||||
{
|
{
|
||||||
struct task_struct *tsk = current;
|
struct task_struct *tsk = current;
|
||||||
unsigned long val, interval, expires;
|
struct hrtimer *timer;
|
||||||
|
ktime_t expires;
|
||||||
cputime_t cval, cinterval, nval, ninterval;
|
cputime_t cval, cinterval, nval, ninterval;
|
||||||
|
|
||||||
switch (which) {
|
switch (which) {
|
||||||
case ITIMER_REAL:
|
case ITIMER_REAL:
|
||||||
again:
|
timer = &tsk->signal->real_timer;
|
||||||
spin_lock_irq(&tsk->sighand->siglock);
|
hrtimer_cancel(timer);
|
||||||
interval = tsk->signal->it_real_incr;
|
if (ovalue) {
|
||||||
val = it_real_value(tsk->signal);
|
ovalue->it_value = itimer_get_remtime(timer);
|
||||||
/* We are sharing ->siglock with it_real_fn() */
|
ovalue->it_interval
|
||||||
if (try_to_del_timer_sync(&tsk->signal->real_timer) < 0) {
|
= ktime_to_timeval(tsk->signal->it_real_incr);
|
||||||
spin_unlock_irq(&tsk->sighand->siglock);
|
|
||||||
goto again;
|
|
||||||
}
|
}
|
||||||
tsk->signal->it_real_incr =
|
tsk->signal->it_real_incr =
|
||||||
timeval_to_jiffies(&value->it_interval);
|
timeval_to_ktime(value->it_interval);
|
||||||
expires = timeval_to_jiffies(&value->it_value);
|
expires = timeval_to_ktime(value->it_value);
|
||||||
if (expires)
|
if (expires.tv64 != 0)
|
||||||
mod_timer(&tsk->signal->real_timer,
|
hrtimer_start(timer, expires, HRTIMER_REL);
|
||||||
jiffies + 1 + expires);
|
|
||||||
spin_unlock_irq(&tsk->sighand->siglock);
|
|
||||||
if (ovalue) {
|
|
||||||
jiffies_to_timeval(val, &ovalue->it_value);
|
|
||||||
jiffies_to_timeval(interval,
|
|
||||||
&ovalue->it_interval);
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
case ITIMER_VIRTUAL:
|
case ITIMER_VIRTUAL:
|
||||||
nval = timeval_to_cputime(&value->it_value);
|
nval = timeval_to_cputime(&value->it_value);
|
||||||
|
Loading…
Reference in New Issue
Block a user