Commit 2ff678b8da6478d861c1b0ecb3ac14575760e906
Committed by
Linus Torvalds
1 parent
df78488de7
Exists in
master
and in
4 other branches
[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>
Showing 7 changed files with 65 additions and 68 deletions Side-by-side Diff
fs/exec.c
... | ... | @@ -632,10 +632,10 @@ |
632 | 632 | * synchronize with any firing (by calling del_timer_sync) |
633 | 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 | 636 | spin_unlock_irq(lock); |
637 | - if (del_timer_sync(&sig->real_timer)) | |
638 | - add_timer(&sig->real_timer); | |
637 | + if (hrtimer_cancel(&sig->real_timer)) | |
638 | + hrtimer_restart(&sig->real_timer); | |
639 | 639 | spin_lock_irq(lock); |
640 | 640 | } |
641 | 641 | while (atomic_read(&sig->count) > count) { |
fs/proc/array.c
... | ... | @@ -330,7 +330,7 @@ |
330 | 330 | unsigned long min_flt = 0, maj_flt = 0; |
331 | 331 | cputime_t cutime, cstime, utime, stime; |
332 | 332 | unsigned long rsslim = 0; |
333 | - unsigned long it_real_value = 0; | |
333 | + DEFINE_KTIME(it_real_value); | |
334 | 334 | struct task_struct *t; |
335 | 335 | char tcomm[sizeof(task->comm)]; |
336 | 336 | |
... | ... | @@ -386,7 +386,7 @@ |
386 | 386 | utime = cputime_add(utime, task->signal->utime); |
387 | 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 | 391 | ppid = pid_alive(task) ? task->group_leader->real_parent->tgid : 0; |
392 | 392 | read_unlock(&tasklist_lock); |
... | ... | @@ -435,7 +435,7 @@ |
435 | 435 | priority, |
436 | 436 | nice, |
437 | 437 | num_threads, |
438 | - jiffies_to_clock_t(it_real_value), | |
438 | + (long) ktime_to_clock_t(it_real_value), | |
439 | 439 | start_time, |
440 | 440 | vsize, |
441 | 441 | mm ? get_mm_rss(mm) : 0, |
include/linux/sched.h
... | ... | @@ -105,6 +105,7 @@ |
105 | 105 | #include <linux/param.h> |
106 | 106 | #include <linux/resource.h> |
107 | 107 | #include <linux/timer.h> |
108 | +#include <linux/hrtimer.h> | |
108 | 109 | |
109 | 110 | #include <asm/processor.h> |
110 | 111 | |
... | ... | @@ -398,8 +399,8 @@ |
398 | 399 | struct list_head posix_timers; |
399 | 400 | |
400 | 401 | /* ITIMER_REAL timer for the process */ |
401 | - struct timer_list real_timer; | |
402 | - unsigned long it_real_value, it_real_incr; | |
402 | + struct hrtimer real_timer; | |
403 | + ktime_t it_real_incr; | |
403 | 404 | |
404 | 405 | /* ITIMER_PROF and ITIMER_VIRTUAL timers for the process */ |
405 | 406 | cputime_t it_prof_expires, it_virt_expires; |
include/linux/timer.h
kernel/exit.c
kernel/fork.c
... | ... | @@ -801,10 +801,10 @@ |
801 | 801 | init_sigpending(&sig->shared_pending); |
802 | 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 | 806 | sig->real_timer.function = it_real_fn; |
806 | - sig->real_timer.data = (unsigned long) tsk; | |
807 | - init_timer(&sig->real_timer); | |
807 | + sig->real_timer.data = tsk; | |
808 | 808 | |
809 | 809 | sig->it_virt_expires = cputime_zero; |
810 | 810 | sig->it_virt_incr = cputime_zero; |
kernel/itimer.c
... | ... | @@ -12,36 +12,46 @@ |
12 | 12 | #include <linux/syscalls.h> |
13 | 13 | #include <linux/time.h> |
14 | 14 | #include <linux/posix-timers.h> |
15 | +#include <linux/hrtimer.h> | |
15 | 16 | |
16 | 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; | |
21 | - if (timer_pending(&sig->real_timer)) { | |
22 | - val = sig->real_timer.expires - jiffies; | |
29 | + ktime_t rem = hrtimer_get_remaining(timer); | |
23 | 30 | |
24 | - /* look out for negative/zero itimer.. */ | |
25 | - if ((long) val <= 0) | |
26 | - val = 1; | |
27 | - } | |
28 | - return val; | |
31 | + /* | |
32 | + * Racy but safe: if the itimer expires after the above | |
33 | + * hrtimer_get_remtime() call but before this condition | |
34 | + * then we return 0 - which is correct. | |
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 | 45 | int do_getitimer(int which, struct itimerval *value) |
32 | 46 | { |
33 | 47 | struct task_struct *tsk = current; |
34 | - unsigned long interval, val; | |
35 | 48 | cputime_t cinterval, cval; |
36 | 49 | |
37 | 50 | switch (which) { |
38 | 51 | case ITIMER_REAL: |
39 | - spin_lock_irq(&tsk->sighand->siglock); | |
40 | - interval = tsk->signal->it_real_incr; | |
41 | - val = it_real_value(tsk->signal); | |
42 | - spin_unlock_irq(&tsk->sighand->siglock); | |
43 | - jiffies_to_timeval(val, &value->it_value); | |
44 | - jiffies_to_timeval(interval, &value->it_interval); | |
52 | + value->it_value = itimer_get_remtime(&tsk->signal->real_timer); | |
53 | + value->it_interval = | |
54 | + ktime_to_timeval(tsk->signal->it_real_incr); | |
45 | 55 | break; |
46 | 56 | case ITIMER_VIRTUAL: |
47 | 57 | read_lock(&tasklist_lock); |
48 | 58 | |
49 | 59 | |
50 | 60 | |
51 | 61 | |
52 | 62 | |
53 | 63 | |
54 | 64 | |
... | ... | @@ -113,59 +123,45 @@ |
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; | |
119 | - unsigned long inc = p->signal->it_real_incr; | |
131 | + struct task_struct *tsk = (struct task_struct *) data; | |
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 | - /* | |
124 | - * Now restart the timer if necessary. We don't need any locking | |
125 | - * here because do_setitimer makes sure we have finished running | |
126 | - * before it touches anything. | |
127 | - * Note, we KNOW we are (or should be) at a jiffie edge here so | |
128 | - * we don't need the +1 stuff. Also, we want to use the prior | |
129 | - * expire value so as to not "slip" a jiffie if we are late. | |
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); | |
135 | + if (tsk->signal->it_real_incr.tv64 != 0) { | |
136 | + hrtimer_forward(&tsk->signal->real_timer, | |
137 | + tsk->signal->it_real_incr); | |
138 | + | |
139 | + return HRTIMER_RESTART; | |
140 | + } | |
141 | + return HRTIMER_NORESTART; | |
138 | 142 | } |
139 | 143 | |
140 | 144 | int do_setitimer(int which, struct itimerval *value, struct itimerval *ovalue) |
141 | 145 | { |
142 | 146 | struct task_struct *tsk = current; |
143 | - unsigned long val, interval, expires; | |
147 | + struct hrtimer *timer; | |
148 | + ktime_t expires; | |
144 | 149 | cputime_t cval, cinterval, nval, ninterval; |
145 | 150 | |
146 | 151 | switch (which) { |
147 | 152 | case ITIMER_REAL: |
148 | -again: | |
149 | - spin_lock_irq(&tsk->sighand->siglock); | |
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); | |
153 | + timer = &tsk->signal->real_timer; | |
154 | + hrtimer_cancel(timer); | |
164 | 155 | if (ovalue) { |
165 | - jiffies_to_timeval(val, &ovalue->it_value); | |
166 | - jiffies_to_timeval(interval, | |
167 | - &ovalue->it_interval); | |
156 | + ovalue->it_value = itimer_get_remtime(timer); | |
157 | + 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 | 165 | break; |
170 | 166 | case ITIMER_VIRTUAL: |
171 | 167 | nval = timeval_to_cputime(&value->it_value); |