aboutsummaryrefslogtreecommitdiffstats
path: root/kernel/itimer.c
diff options
context:
space:
mode:
Diffstat (limited to 'kernel/itimer.c')
-rw-r--r--kernel/itimer.c164
1 files changed, 86 insertions, 78 deletions
diff --git a/kernel/itimer.c b/kernel/itimer.c
index 58762f7077ec..8078a32d3b10 100644
--- a/kernel/itimer.c
+++ b/kernel/itimer.c
@@ -41,10 +41,43 @@ static struct timeval itimer_get_remtime(struct hrtimer *timer)
41 return ktime_to_timeval(rem); 41 return ktime_to_timeval(rem);
42} 42}
43 43
44static void get_cpu_itimer(struct task_struct *tsk, unsigned int clock_id,
45 struct itimerval *const value)
46{
47 cputime_t cval, cinterval;
48 struct cpu_itimer *it = &tsk->signal->it[clock_id];
49
50 spin_lock_irq(&tsk->sighand->siglock);
51
52 cval = it->expires;
53 cinterval = it->incr;
54 if (!cputime_eq(cval, cputime_zero)) {
55 struct task_cputime cputime;
56 cputime_t t;
57
58 thread_group_cputimer(tsk, &cputime);
59 if (clock_id == CPUCLOCK_PROF)
60 t = cputime_add(cputime.utime, cputime.stime);
61 else
62 /* CPUCLOCK_VIRT */
63 t = cputime.utime;
64
65 if (cputime_le(cval, t))
66 /* about to fire */
67 cval = cputime_one_jiffy;
68 else
69 cval = cputime_sub(cval, t);
70 }
71
72 spin_unlock_irq(&tsk->sighand->siglock);
73
74 cputime_to_timeval(cval, &value->it_value);
75 cputime_to_timeval(cinterval, &value->it_interval);
76}
77
44int do_getitimer(int which, struct itimerval *value) 78int do_getitimer(int which, struct itimerval *value)
45{ 79{
46 struct task_struct *tsk = current; 80 struct task_struct *tsk = current;
47 cputime_t cinterval, cval;
48 81
49 switch (which) { 82 switch (which) {
50 case ITIMER_REAL: 83 case ITIMER_REAL:
@@ -55,44 +88,10 @@ int do_getitimer(int which, struct itimerval *value)
55 spin_unlock_irq(&tsk->sighand->siglock); 88 spin_unlock_irq(&tsk->sighand->siglock);
56 break; 89 break;
57 case ITIMER_VIRTUAL: 90 case ITIMER_VIRTUAL:
58 spin_lock_irq(&tsk->sighand->siglock); 91 get_cpu_itimer(tsk, CPUCLOCK_VIRT, value);
59 cval = tsk->signal->it_virt_expires;
60 cinterval = tsk->signal->it_virt_incr;
61 if (!cputime_eq(cval, cputime_zero)) {
62 struct task_cputime cputime;
63 cputime_t utime;
64
65 thread_group_cputimer(tsk, &cputime);
66 utime = cputime.utime;
67 if (cputime_le(cval, utime)) { /* about to fire */
68 cval = jiffies_to_cputime(1);
69 } else {
70 cval = cputime_sub(cval, utime);
71 }
72 }
73 spin_unlock_irq(&tsk->sighand->siglock);
74 cputime_to_timeval(cval, &value->it_value);
75 cputime_to_timeval(cinterval, &value->it_interval);
76 break; 92 break;
77 case ITIMER_PROF: 93 case ITIMER_PROF:
78 spin_lock_irq(&tsk->sighand->siglock); 94 get_cpu_itimer(tsk, CPUCLOCK_PROF, value);
79 cval = tsk->signal->it_prof_expires;
80 cinterval = tsk->signal->it_prof_incr;
81 if (!cputime_eq(cval, cputime_zero)) {
82 struct task_cputime times;
83 cputime_t ptime;
84
85 thread_group_cputimer(tsk, &times);
86 ptime = cputime_add(times.utime, times.stime);
87 if (cputime_le(cval, ptime)) { /* about to fire */
88 cval = jiffies_to_cputime(1);
89 } else {
90 cval = cputime_sub(cval, ptime);
91 }
92 }
93 spin_unlock_irq(&tsk->sighand->siglock);
94 cputime_to_timeval(cval, &value->it_value);
95 cputime_to_timeval(cinterval, &value->it_interval);
96 break; 95 break;
97 default: 96 default:
98 return(-EINVAL); 97 return(-EINVAL);
@@ -128,6 +127,54 @@ enum hrtimer_restart it_real_fn(struct hrtimer *timer)
128 return HRTIMER_NORESTART; 127 return HRTIMER_NORESTART;
129} 128}
130 129
130static inline u32 cputime_sub_ns(cputime_t ct, s64 real_ns)
131{
132 struct timespec ts;
133 s64 cpu_ns;
134
135 cputime_to_timespec(ct, &ts);
136 cpu_ns = timespec_to_ns(&ts);
137
138 return (cpu_ns <= real_ns) ? 0 : cpu_ns - real_ns;
139}
140
141static void set_cpu_itimer(struct task_struct *tsk, unsigned int clock_id,
142 const struct itimerval *const value,
143 struct itimerval *const ovalue)
144{
145 cputime_t cval, nval, cinterval, ninterval;
146 s64 ns_ninterval, ns_nval;
147 struct cpu_itimer *it = &tsk->signal->it[clock_id];
148
149 nval = timeval_to_cputime(&value->it_value);
150 ns_nval = timeval_to_ns(&value->it_value);
151 ninterval = timeval_to_cputime(&value->it_interval);
152 ns_ninterval = timeval_to_ns(&value->it_interval);
153
154 it->incr_error = cputime_sub_ns(ninterval, ns_ninterval);
155 it->error = cputime_sub_ns(nval, ns_nval);
156
157 spin_lock_irq(&tsk->sighand->siglock);
158
159 cval = it->expires;
160 cinterval = it->incr;
161 if (!cputime_eq(cval, cputime_zero) ||
162 !cputime_eq(nval, cputime_zero)) {
163 if (cputime_gt(nval, cputime_zero))
164 nval = cputime_add(nval, cputime_one_jiffy);
165 set_process_cpu_timer(tsk, clock_id, &nval, &cval);
166 }
167 it->expires = nval;
168 it->incr = ninterval;
169
170 spin_unlock_irq(&tsk->sighand->siglock);
171
172 if (ovalue) {
173 cputime_to_timeval(cval, &ovalue->it_value);
174 cputime_to_timeval(cinterval, &ovalue->it_interval);
175 }
176}
177
131/* 178/*
132 * Returns true if the timeval is in canonical form 179 * Returns true if the timeval is in canonical form
133 */ 180 */
@@ -139,7 +186,6 @@ int do_setitimer(int which, struct itimerval *value, struct itimerval *ovalue)
139 struct task_struct *tsk = current; 186 struct task_struct *tsk = current;
140 struct hrtimer *timer; 187 struct hrtimer *timer;
141 ktime_t expires; 188 ktime_t expires;
142 cputime_t cval, cinterval, nval, ninterval;
143 189
144 /* 190 /*
145 * Validate the timevals in value. 191 * Validate the timevals in value.
@@ -174,48 +220,10 @@ again:
174 spin_unlock_irq(&tsk->sighand->siglock); 220 spin_unlock_irq(&tsk->sighand->siglock);
175 break; 221 break;
176 case ITIMER_VIRTUAL: 222 case ITIMER_VIRTUAL:
177 nval = timeval_to_cputime(&value->it_value); 223 set_cpu_itimer(tsk, CPUCLOCK_VIRT, value, ovalue);
178 ninterval = timeval_to_cputime(&value->it_interval);
179 spin_lock_irq(&tsk->sighand->siglock);
180 cval = tsk->signal->it_virt_expires;
181 cinterval = tsk->signal->it_virt_incr;
182 if (!cputime_eq(cval, cputime_zero) ||
183 !cputime_eq(nval, cputime_zero)) {
184 if (cputime_gt(nval, cputime_zero))
185 nval = cputime_add(nval,
186 jiffies_to_cputime(1));
187 set_process_cpu_timer(tsk, CPUCLOCK_VIRT,
188 &nval, &cval);
189 }
190 tsk->signal->it_virt_expires = nval;
191 tsk->signal->it_virt_incr = ninterval;
192 spin_unlock_irq(&tsk->sighand->siglock);
193 if (ovalue) {
194 cputime_to_timeval(cval, &ovalue->it_value);
195 cputime_to_timeval(cinterval, &ovalue->it_interval);
196 }
197 break; 224 break;
198 case ITIMER_PROF: 225 case ITIMER_PROF:
199 nval = timeval_to_cputime(&value->it_value); 226 set_cpu_itimer(tsk, CPUCLOCK_PROF, value, ovalue);
200 ninterval = timeval_to_cputime(&value->it_interval);
201 spin_lock_irq(&tsk->sighand->siglock);
202 cval = tsk->signal->it_prof_expires;
203 cinterval = tsk->signal->it_prof_incr;
204 if (!cputime_eq(cval, cputime_zero) ||
205 !cputime_eq(nval, cputime_zero)) {
206 if (cputime_gt(nval, cputime_zero))
207 nval = cputime_add(nval,
208 jiffies_to_cputime(1));
209 set_process_cpu_timer(tsk, CPUCLOCK_PROF,
210 &nval, &cval);
211 }
212 tsk->signal->it_prof_expires = nval;
213 tsk->signal->it_prof_incr = ninterval;
214 spin_unlock_irq(&tsk->sighand->siglock);
215 if (ovalue) {
216 cputime_to_timeval(cval, &ovalue->it_value);
217 cputime_to_timeval(cinterval, &ovalue->it_interval);
218 }
219 break; 227 break;
220 default: 228 default:
221 return -EINVAL; 229 return -EINVAL;