]> bbs.cooldavid.org Git - net-next-2.6.git/blame - kernel/itimer.c
[PATCH] x86: bogus tls from gdt
[net-next-2.6.git] / kernel / itimer.c
CommitLineData
1da177e4
LT
1/*
2 * linux/kernel/itimer.c
3 *
4 * Copyright (C) 1992 Darren Senn
5 */
6
7/* These are all the functions necessary to implement itimers */
8
9#include <linux/mm.h>
10#include <linux/smp_lock.h>
11#include <linux/interrupt.h>
12#include <linux/syscalls.h>
13#include <linux/time.h>
14#include <linux/posix-timers.h>
15
16#include <asm/uaccess.h>
17
18static unsigned long it_real_value(struct signal_struct *sig)
19{
20 unsigned long val = 0;
21 if (timer_pending(&sig->real_timer)) {
22 val = sig->real_timer.expires - jiffies;
23
24 /* look out for negative/zero itimer.. */
25 if ((long) val <= 0)
26 val = 1;
27 }
28 return val;
29}
30
31int do_getitimer(int which, struct itimerval *value)
32{
33 struct task_struct *tsk = current;
34 unsigned long interval, val;
35 cputime_t cinterval, cval;
36
37 switch (which) {
38 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);
45 break;
46 case ITIMER_VIRTUAL:
47 read_lock(&tasklist_lock);
48 spin_lock_irq(&tsk->sighand->siglock);
49 cval = tsk->signal->it_virt_expires;
50 cinterval = tsk->signal->it_virt_incr;
51 if (!cputime_eq(cval, cputime_zero)) {
52 struct task_struct *t = tsk;
53 cputime_t utime = tsk->signal->utime;
54 do {
55 utime = cputime_add(utime, t->utime);
56 t = next_thread(t);
57 } while (t != tsk);
58 if (cputime_le(cval, utime)) { /* about to fire */
59 cval = jiffies_to_cputime(1);
60 } else {
61 cval = cputime_sub(cval, utime);
62 }
63 }
64 spin_unlock_irq(&tsk->sighand->siglock);
65 read_unlock(&tasklist_lock);
66 cputime_to_timeval(cval, &value->it_value);
67 cputime_to_timeval(cinterval, &value->it_interval);
68 break;
69 case ITIMER_PROF:
70 read_lock(&tasklist_lock);
71 spin_lock_irq(&tsk->sighand->siglock);
72 cval = tsk->signal->it_prof_expires;
73 cinterval = tsk->signal->it_prof_incr;
74 if (!cputime_eq(cval, cputime_zero)) {
75 struct task_struct *t = tsk;
76 cputime_t ptime = cputime_add(tsk->signal->utime,
77 tsk->signal->stime);
78 do {
79 ptime = cputime_add(ptime,
80 cputime_add(t->utime,
81 t->stime));
82 t = next_thread(t);
83 } while (t != tsk);
84 if (cputime_le(cval, ptime)) { /* about to fire */
85 cval = jiffies_to_cputime(1);
86 } else {
87 cval = cputime_sub(cval, ptime);
88 }
89 }
90 spin_unlock_irq(&tsk->sighand->siglock);
91 read_unlock(&tasklist_lock);
92 cputime_to_timeval(cval, &value->it_value);
93 cputime_to_timeval(cinterval, &value->it_interval);
94 break;
95 default:
96 return(-EINVAL);
97 }
98 return 0;
99}
100
101asmlinkage long sys_getitimer(int which, struct itimerval __user *value)
102{
103 int error = -EFAULT;
104 struct itimerval get_buffer;
105
106 if (value) {
107 error = do_getitimer(which, &get_buffer);
108 if (!error &&
109 copy_to_user(value, &get_buffer, sizeof(get_buffer)))
110 error = -EFAULT;
111 }
112 return error;
113}
114
1da177e4
LT
115
116void it_real_fn(unsigned long __data)
117{
118 struct task_struct * p = (struct task_struct *) __data;
d912d1ff 119 unsigned long inc = p->signal->it_real_incr;
1da177e4
LT
120
121 send_group_sig_info(SIGALRM, SEND_SIG_PRIV, p);
122
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.
d912d1ff
GA
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.
1da177e4 132 */
d912d1ff
GA
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);
1da177e4
LT
138}
139
140int do_setitimer(int which, struct itimerval *value, struct itimerval *ovalue)
141{
142 struct task_struct *tsk = current;
d912d1ff 143 unsigned long val, interval, expires;
1da177e4
LT
144 cputime_t cval, cinterval, nval, ninterval;
145
146 switch (which) {
147 case ITIMER_REAL:
f01b1b0b 148again:
1da177e4
LT
149 spin_lock_irq(&tsk->sighand->siglock);
150 interval = tsk->signal->it_real_incr;
151 val = it_real_value(tsk->signal);
f01b1b0b
ON
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 }
1da177e4
LT
157 tsk->signal->it_real_incr =
158 timeval_to_jiffies(&value->it_interval);
d912d1ff
GA
159 expires = timeval_to_jiffies(&value->it_value);
160 if (expires)
161 mod_timer(&tsk->signal->real_timer,
162 jiffies + 1 + expires);
1da177e4
LT
163 spin_unlock_irq(&tsk->sighand->siglock);
164 if (ovalue) {
165 jiffies_to_timeval(val, &ovalue->it_value);
166 jiffies_to_timeval(interval,
167 &ovalue->it_interval);
168 }
169 break;
170 case ITIMER_VIRTUAL:
171 nval = timeval_to_cputime(&value->it_value);
172 ninterval = timeval_to_cputime(&value->it_interval);
173 read_lock(&tasklist_lock);
174 spin_lock_irq(&tsk->sighand->siglock);
175 cval = tsk->signal->it_virt_expires;
176 cinterval = tsk->signal->it_virt_incr;
177 if (!cputime_eq(cval, cputime_zero) ||
178 !cputime_eq(nval, cputime_zero)) {
179 if (cputime_gt(nval, cputime_zero))
180 nval = cputime_add(nval,
181 jiffies_to_cputime(1));
182 set_process_cpu_timer(tsk, CPUCLOCK_VIRT,
183 &nval, &cval);
184 }
185 tsk->signal->it_virt_expires = nval;
186 tsk->signal->it_virt_incr = ninterval;
187 spin_unlock_irq(&tsk->sighand->siglock);
188 read_unlock(&tasklist_lock);
189 if (ovalue) {
190 cputime_to_timeval(cval, &ovalue->it_value);
191 cputime_to_timeval(cinterval, &ovalue->it_interval);
192 }
193 break;
194 case ITIMER_PROF:
195 nval = timeval_to_cputime(&value->it_value);
196 ninterval = timeval_to_cputime(&value->it_interval);
197 read_lock(&tasklist_lock);
198 spin_lock_irq(&tsk->sighand->siglock);
199 cval = tsk->signal->it_prof_expires;
200 cinterval = tsk->signal->it_prof_incr;
201 if (!cputime_eq(cval, cputime_zero) ||
202 !cputime_eq(nval, cputime_zero)) {
203 if (cputime_gt(nval, cputime_zero))
204 nval = cputime_add(nval,
205 jiffies_to_cputime(1));
206 set_process_cpu_timer(tsk, CPUCLOCK_PROF,
207 &nval, &cval);
208 }
209 tsk->signal->it_prof_expires = nval;
210 tsk->signal->it_prof_incr = ninterval;
211 spin_unlock_irq(&tsk->sighand->siglock);
212 read_unlock(&tasklist_lock);
213 if (ovalue) {
214 cputime_to_timeval(cval, &ovalue->it_value);
215 cputime_to_timeval(cinterval, &ovalue->it_interval);
216 }
217 break;
218 default:
219 return -EINVAL;
220 }
221 return 0;
222}
223
224asmlinkage long sys_setitimer(int which,
225 struct itimerval __user *value,
226 struct itimerval __user *ovalue)
227{
228 struct itimerval set_buffer, get_buffer;
229 int error;
230
231 if (value) {
232 if(copy_from_user(&set_buffer, value, sizeof(set_buffer)))
233 return -EFAULT;
234 } else
235 memset((char *) &set_buffer, 0, sizeof(set_buffer));
236
237 error = do_setitimer(which, &set_buffer, ovalue ? &get_buffer : NULL);
238 if (error || !ovalue)
239 return error;
240
241 if (copy_to_user(ovalue, &get_buffer, sizeof(get_buffer)))
242 return -EFAULT;
243 return 0;
244}