diff options
author | Thomas Gleixner <tglx@linutronix.de> | 2006-01-09 23:52:34 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@g5.osdl.org> | 2006-01-10 11:01:38 -0500 |
commit | 2ff678b8da6478d861c1b0ecb3ac14575760e906 (patch) | |
tree | 0ca983ce820ac8bb9f6e8b193926e0804116a7e0 | |
parent | df78488de7befd387e9d060da6e18bb5d1cb882c (diff) |
[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>
-rw-r--r-- | fs/exec.c | 6 | ||||
-rw-r--r-- | fs/proc/array.c | 6 | ||||
-rw-r--r-- | include/linux/sched.h | 5 | ||||
-rw-r--r-- | include/linux/timer.h | 2 | ||||
-rw-r--r-- | kernel/exit.c | 2 | ||||
-rw-r--r-- | kernel/fork.c | 6 | ||||
-rw-r--r-- | kernel/itimer.c | 106 |
7 files changed, 65 insertions, 68 deletions
@@ -632,10 +632,10 @@ static inline int de_thread(struct task_struct *tsk) | |||
632 | * synchronize with any firing (by calling del_timer_sync) | 632 | * synchronize with any firing (by calling del_timer_sync) |
633 | * before we can safely let the old group leader die. | 633 | * before we can safely let the old group leader die. |
634 | */ | 634 | */ |
635 | sig->real_timer.data = (unsigned long)current; | 635 | sig->real_timer.data = current; |
636 | spin_unlock_irq(lock); | 636 | spin_unlock_irq(lock); |
637 | if (del_timer_sync(&sig->real_timer)) | 637 | if (hrtimer_cancel(&sig->real_timer)) |
638 | add_timer(&sig->real_timer); | 638 | hrtimer_restart(&sig->real_timer); |
639 | spin_lock_irq(lock); | 639 | spin_lock_irq(lock); |
640 | } | 640 | } |
641 | while (atomic_read(&sig->count) > count) { | 641 | while (atomic_read(&sig->count) > count) { |
diff --git a/fs/proc/array.c b/fs/proc/array.c index 5e9251f65317..7eb1bd7f800c 100644 --- a/fs/proc/array.c +++ b/fs/proc/array.c | |||
@@ -330,7 +330,7 @@ static int do_task_stat(struct task_struct *task, char * buffer, int whole) | |||
330 | unsigned long min_flt = 0, maj_flt = 0; | 330 | unsigned long min_flt = 0, maj_flt = 0; |
331 | cputime_t cutime, cstime, utime, stime; | 331 | cputime_t cutime, cstime, utime, stime; |
332 | unsigned long rsslim = 0; | 332 | unsigned long rsslim = 0; |
333 | unsigned long it_real_value = 0; | 333 | DEFINE_KTIME(it_real_value); |
334 | struct task_struct *t; | 334 | struct task_struct *t; |
335 | char tcomm[sizeof(task->comm)]; | 335 | char tcomm[sizeof(task->comm)]; |
336 | 336 | ||
@@ -386,7 +386,7 @@ static int do_task_stat(struct task_struct *task, char * buffer, int whole) | |||
386 | utime = cputime_add(utime, task->signal->utime); | 386 | utime = cputime_add(utime, task->signal->utime); |
387 | stime = cputime_add(stime, task->signal->stime); | 387 | stime = cputime_add(stime, task->signal->stime); |
388 | } | 388 | } |
389 | it_real_value = task->signal->it_real_value; | 389 | it_real_value = task->signal->real_timer.expires; |
390 | } | 390 | } |
391 | ppid = pid_alive(task) ? task->group_leader->real_parent->tgid : 0; | 391 | ppid = pid_alive(task) ? task->group_leader->real_parent->tgid : 0; |
392 | read_unlock(&tasklist_lock); | 392 | read_unlock(&tasklist_lock); |
@@ -435,7 +435,7 @@ static int do_task_stat(struct task_struct *task, char * buffer, int whole) | |||
435 | priority, | 435 | priority, |
436 | nice, | 436 | nice, |
437 | num_threads, | 437 | num_threads, |
438 | jiffies_to_clock_t(it_real_value), | 438 | (long) ktime_to_clock_t(it_real_value), |
439 | start_time, | 439 | start_time, |
440 | vsize, | 440 | vsize, |
441 | mm ? get_mm_rss(mm) : 0, | 441 | mm ? get_mm_rss(mm) : 0, |
diff --git a/include/linux/sched.h b/include/linux/sched.h index 85b53f87c703..ee4677ad204e 100644 --- a/include/linux/sched.h +++ b/include/linux/sched.h | |||
@@ -105,6 +105,7 @@ extern unsigned long nr_iowait(void); | |||
105 | #include <linux/param.h> | 105 | #include <linux/param.h> |
106 | #include <linux/resource.h> | 106 | #include <linux/resource.h> |
107 | #include <linux/timer.h> | 107 | #include <linux/timer.h> |
108 | #include <linux/hrtimer.h> | ||
108 | 109 | ||
109 | #include <asm/processor.h> | 110 | #include <asm/processor.h> |
110 | 111 | ||
@@ -398,8 +399,8 @@ struct signal_struct { | |||
398 | struct list_head posix_timers; | 399 | struct list_head posix_timers; |
399 | 400 | ||
400 | /* ITIMER_REAL timer for the process */ | 401 | /* ITIMER_REAL timer for the process */ |
401 | struct timer_list real_timer; | 402 | struct hrtimer real_timer; |
402 | unsigned long it_real_value, it_real_incr; | 403 | ktime_t it_real_incr; |
403 | 404 | ||
404 | /* ITIMER_PROF and ITIMER_VIRTUAL timers for the process */ | 405 | /* ITIMER_PROF and ITIMER_VIRTUAL timers for the process */ |
405 | cputime_t it_prof_expires, it_virt_expires; | 406 | cputime_t it_prof_expires, it_virt_expires; |
diff --git a/include/linux/timer.h b/include/linux/timer.h index 72f3a7781106..9b9877fd2505 100644 --- a/include/linux/timer.h +++ b/include/linux/timer.h | |||
@@ -96,6 +96,6 @@ static inline void add_timer(struct timer_list *timer) | |||
96 | 96 | ||
97 | extern void init_timers(void); | 97 | extern void init_timers(void); |
98 | extern void run_local_timers(void); | 98 | extern void run_local_timers(void); |
99 | extern void it_real_fn(unsigned long); | 99 | extern int it_real_fn(void *); |
100 | 100 | ||
101 | #endif | 101 | #endif |
diff --git a/kernel/exit.c b/kernel/exit.c index 309a46fa16f8..e75a51f33768 100644 --- a/kernel/exit.c +++ b/kernel/exit.c | |||
@@ -842,7 +842,7 @@ fastcall NORET_TYPE void do_exit(long code) | |||
842 | } | 842 | } |
843 | group_dead = atomic_dec_and_test(&tsk->signal->live); | 843 | group_dead = atomic_dec_and_test(&tsk->signal->live); |
844 | if (group_dead) { | 844 | if (group_dead) { |
845 | del_timer_sync(&tsk->signal->real_timer); | 845 | hrtimer_cancel(&tsk->signal->real_timer); |
846 | exit_itimers(tsk->signal); | 846 | exit_itimers(tsk->signal); |
847 | acct_process(code); | 847 | acct_process(code); |
848 | } | 848 | } |
diff --git a/kernel/fork.c b/kernel/fork.c index b18d64554feb..3bdcab49998d 100644 --- a/kernel/fork.c +++ b/kernel/fork.c | |||
@@ -801,10 +801,10 @@ static inline int copy_signal(unsigned long clone_flags, struct task_struct * ts | |||
801 | init_sigpending(&sig->shared_pending); | 801 | init_sigpending(&sig->shared_pending); |
802 | INIT_LIST_HEAD(&sig->posix_timers); | 802 | INIT_LIST_HEAD(&sig->posix_timers); |
803 | 803 | ||
804 | sig->it_real_value = sig->it_real_incr = 0; | 804 | hrtimer_init(&sig->real_timer, CLOCK_MONOTONIC); |
805 | sig->it_real_incr.tv64 = 0; | ||
805 | sig->real_timer.function = it_real_fn; | 806 | sig->real_timer.function = it_real_fn; |
806 | sig->real_timer.data = (unsigned long) tsk; | 807 | sig->real_timer.data = tsk; |
807 | init_timer(&sig->real_timer); | ||
808 | 808 | ||
809 | sig->it_virt_expires = cputime_zero; | 809 | sig->it_virt_expires = cputime_zero; |
810 | sig->it_virt_incr = cputime_zero; | 810 | sig->it_virt_incr = cputime_zero; |
diff --git a/kernel/itimer.c b/kernel/itimer.c index 7c1b25e25e47..c2c05c4ff28d 100644 --- a/kernel/itimer.c +++ b/kernel/itimer.c | |||
@@ -12,36 +12,46 @@ | |||
12 | #include <linux/syscalls.h> | 12 | #include <linux/syscalls.h> |
13 | #include <linux/time.h> | 13 | #include <linux/time.h> |
14 | #include <linux/posix-timers.h> | 14 | #include <linux/posix-timers.h> |
15 | #include <linux/hrtimer.h> | ||
15 | 16 | ||
16 | #include <asm/uaccess.h> | 17 | #include <asm/uaccess.h> |
17 | 18 | ||
18 | static unsigned long it_real_value(struct signal_struct *sig) | 19 | /** |
20 | * itimer_get_remtime - get remaining time for the timer | ||
21 | * | ||
22 | * @timer: the timer to read | ||
23 | * | ||
24 | * Returns the delta between the expiry time and now, which can be | ||
25 | * less than zero or 1usec for an pending expired timer | ||
26 | */ | ||
27 | static struct timeval itimer_get_remtime(struct hrtimer *timer) | ||
19 | { | 28 | { |
20 | unsigned long val = 0; | 29 | ktime_t rem = hrtimer_get_remaining(timer); |
21 | if (timer_pending(&sig->real_timer)) { | ||
22 | val = sig->real_timer.expires - jiffies; | ||
23 | 30 | ||
24 | /* look out for negative/zero itimer.. */ | 31 | /* |
25 | if ((long) val <= 0) | 32 | * Racy but safe: if the itimer expires after the above |
26 | val = 1; | 33 | * hrtimer_get_remtime() call but before this condition |
27 | } | 34 | * then we return 0 - which is correct. |
28 | return val; | 35 | */ |
36 | if (hrtimer_active(timer)) { | ||
37 | if (rem.tv64 <= 0) | ||
38 | rem.tv64 = NSEC_PER_USEC; | ||
39 | } else | ||
40 | rem.tv64 = 0; | ||
41 | |||
42 | return ktime_to_timeval(rem); | ||
29 | } | 43 | } |
30 | 44 | ||
31 | int do_getitimer(int which, struct itimerval *value) | 45 | int do_getitimer(int which, struct itimerval *value) |
32 | { | 46 | { |
33 | struct task_struct *tsk = current; | 47 | struct task_struct *tsk = current; |
34 | unsigned long interval, val; | ||
35 | cputime_t cinterval, cval; | 48 | cputime_t cinterval, cval; |
36 | 49 | ||
37 | switch (which) { | 50 | switch (which) { |
38 | case ITIMER_REAL: | 51 | case ITIMER_REAL: |
39 | spin_lock_irq(&tsk->sighand->siglock); | 52 | value->it_value = itimer_get_remtime(&tsk->signal->real_timer); |
40 | interval = tsk->signal->it_real_incr; | 53 | value->it_interval = |
41 | val = it_real_value(tsk->signal); | 54 | ktime_to_timeval(tsk->signal->it_real_incr); |
42 | spin_unlock_irq(&tsk->sighand->siglock); | ||
43 | jiffies_to_timeval(val, &value->it_value); | ||
44 | jiffies_to_timeval(interval, &value->it_interval); | ||
45 | break; | 55 | break; |
46 | case ITIMER_VIRTUAL: | 56 | case ITIMER_VIRTUAL: |
47 | read_lock(&tasklist_lock); | 57 | read_lock(&tasklist_lock); |
@@ -113,59 +123,45 @@ asmlinkage long sys_getitimer(int which, struct itimerval __user *value) | |||
113 | } | 123 | } |
114 | 124 | ||
115 | 125 | ||
116 | void it_real_fn(unsigned long __data) | 126 | /* |
127 | * The timer is automagically restarted, when interval != 0 | ||
128 | */ | ||
129 | int it_real_fn(void *data) | ||
117 | { | 130 | { |
118 | struct task_struct * p = (struct task_struct *) __data; | 131 | struct task_struct *tsk = (struct task_struct *) data; |
119 | unsigned long inc = p->signal->it_real_incr; | ||
120 | 132 | ||
121 | send_group_sig_info(SIGALRM, SEND_SIG_PRIV, p); | 133 | send_group_sig_info(SIGALRM, SEND_SIG_PRIV, tsk); |
122 | 134 | ||
123 | /* | 135 | if (tsk->signal->it_real_incr.tv64 != 0) { |
124 | * Now restart the timer if necessary. We don't need any locking | 136 | hrtimer_forward(&tsk->signal->real_timer, |
125 | * here because do_setitimer makes sure we have finished running | 137 | tsk->signal->it_real_incr); |
126 | * before it touches anything. | 138 | |
127 | * Note, we KNOW we are (or should be) at a jiffie edge here so | 139 | return HRTIMER_RESTART; |
128 | * we don't need the +1 stuff. Also, we want to use the prior | 140 | } |
129 | * expire value so as to not "slip" a jiffie if we are late. | 141 | return HRTIMER_NORESTART; |
130 | * Deal with requesting a time prior to "now" here rather than | ||
131 | * in add_timer. | ||
132 | */ | ||
133 | if (!inc) | ||
134 | return; | ||
135 | while (time_before_eq(p->signal->real_timer.expires, jiffies)) | ||
136 | p->signal->real_timer.expires += inc; | ||
137 | add_timer(&p->signal->real_timer); | ||
138 | } | 142 | } |
139 | 143 | ||
140 | int do_setitimer(int which, struct itimerval *value, struct itimerval *ovalue) | 144 | int do_setitimer(int which, struct itimerval *value, struct itimerval *ovalue) |
141 | { | 145 | { |
142 | struct task_struct *tsk = current; | 146 | struct task_struct *tsk = current; |
143 | unsigned long val, interval, expires; | 147 | struct hrtimer *timer; |
148 | ktime_t expires; | ||
144 | cputime_t cval, cinterval, nval, ninterval; | 149 | cputime_t cval, cinterval, nval, ninterval; |
145 | 150 | ||
146 | switch (which) { | 151 | switch (which) { |
147 | case ITIMER_REAL: | 152 | case ITIMER_REAL: |
148 | again: | 153 | timer = &tsk->signal->real_timer; |
149 | spin_lock_irq(&tsk->sighand->siglock); | 154 | hrtimer_cancel(timer); |
150 | interval = tsk->signal->it_real_incr; | ||
151 | val = it_real_value(tsk->signal); | ||
152 | /* We are sharing ->siglock with it_real_fn() */ | ||
153 | if (try_to_del_timer_sync(&tsk->signal->real_timer) < 0) { | ||
154 | spin_unlock_irq(&tsk->sighand->siglock); | ||
155 | goto again; | ||
156 | } | ||
157 | tsk->signal->it_real_incr = | ||
158 | timeval_to_jiffies(&value->it_interval); | ||
159 | expires = timeval_to_jiffies(&value->it_value); | ||
160 | if (expires) | ||
161 | mod_timer(&tsk->signal->real_timer, | ||
162 | jiffies + 1 + expires); | ||
163 | spin_unlock_irq(&tsk->sighand->siglock); | ||
164 | if (ovalue) { | 155 | if (ovalue) { |
165 | jiffies_to_timeval(val, &ovalue->it_value); | 156 | ovalue->it_value = itimer_get_remtime(timer); |
166 | jiffies_to_timeval(interval, | 157 | ovalue->it_interval |
167 | &ovalue->it_interval); | 158 | = ktime_to_timeval(tsk->signal->it_real_incr); |
168 | } | 159 | } |
160 | tsk->signal->it_real_incr = | ||
161 | timeval_to_ktime(value->it_interval); | ||
162 | expires = timeval_to_ktime(value->it_value); | ||
163 | if (expires.tv64 != 0) | ||
164 | hrtimer_start(timer, expires, HRTIMER_REL); | ||
169 | break; | 165 | break; |
170 | case ITIMER_VIRTUAL: | 166 | case ITIMER_VIRTUAL: |
171 | nval = timeval_to_cputime(&value->it_value); | 167 | nval = timeval_to_cputime(&value->it_value); |