Merge branch 'upstream' of git://ftp.linux-mips.org/pub/scm/upstream-linus
[linux-2.6] / kernel / itimer.c
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 #include <linux/hrtimer.h>
16
17 #include <asm/uaccess.h>
18
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)
28 {
29         ktime_t rem = hrtimer_get_remaining(timer);
30
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);
43 }
44
45 int do_getitimer(int which, struct itimerval *value)
46 {
47         struct task_struct *tsk = current;
48         cputime_t cinterval, cval;
49
50         switch (which) {
51         case ITIMER_REAL:
52                 value->it_value = itimer_get_remtime(&tsk->signal->real_timer);
53                 value->it_interval =
54                         ktime_to_timeval(tsk->signal->it_real_incr);
55                 break;
56         case ITIMER_VIRTUAL:
57                 read_lock(&tasklist_lock);
58                 spin_lock_irq(&tsk->sighand->siglock);
59                 cval = tsk->signal->it_virt_expires;
60                 cinterval = tsk->signal->it_virt_incr;
61                 if (!cputime_eq(cval, cputime_zero)) {
62                         struct task_struct *t = tsk;
63                         cputime_t utime = tsk->signal->utime;
64                         do {
65                                 utime = cputime_add(utime, t->utime);
66                                 t = next_thread(t);
67                         } while (t != tsk);
68                         if (cputime_le(cval, utime)) { /* about to fire */
69                                 cval = jiffies_to_cputime(1);
70                         } else {
71                                 cval = cputime_sub(cval, utime);
72                         }
73                 }
74                 spin_unlock_irq(&tsk->sighand->siglock);
75                 read_unlock(&tasklist_lock);
76                 cputime_to_timeval(cval, &value->it_value);
77                 cputime_to_timeval(cinterval, &value->it_interval);
78                 break;
79         case ITIMER_PROF:
80                 read_lock(&tasklist_lock);
81                 spin_lock_irq(&tsk->sighand->siglock);
82                 cval = tsk->signal->it_prof_expires;
83                 cinterval = tsk->signal->it_prof_incr;
84                 if (!cputime_eq(cval, cputime_zero)) {
85                         struct task_struct *t = tsk;
86                         cputime_t ptime = cputime_add(tsk->signal->utime,
87                                                       tsk->signal->stime);
88                         do {
89                                 ptime = cputime_add(ptime,
90                                                     cputime_add(t->utime,
91                                                                 t->stime));
92                                 t = next_thread(t);
93                         } while (t != tsk);
94                         if (cputime_le(cval, ptime)) { /* about to fire */
95                                 cval = jiffies_to_cputime(1);
96                         } else {
97                                 cval = cputime_sub(cval, ptime);
98                         }
99                 }
100                 spin_unlock_irq(&tsk->sighand->siglock);
101                 read_unlock(&tasklist_lock);
102                 cputime_to_timeval(cval, &value->it_value);
103                 cputime_to_timeval(cinterval, &value->it_interval);
104                 break;
105         default:
106                 return(-EINVAL);
107         }
108         return 0;
109 }
110
111 asmlinkage long sys_getitimer(int which, struct itimerval __user *value)
112 {
113         int error = -EFAULT;
114         struct itimerval get_buffer;
115
116         if (value) {
117                 error = do_getitimer(which, &get_buffer);
118                 if (!error &&
119                     copy_to_user(value, &get_buffer, sizeof(get_buffer)))
120                         error = -EFAULT;
121         }
122         return error;
123 }
124
125
126 /*
127  * The timer is automagically restarted, when interval != 0
128  */
129 int it_real_fn(void *data)
130 {
131         struct task_struct *tsk = (struct task_struct *) data;
132
133         send_group_sig_info(SIGALRM, SEND_SIG_PRIV, tsk);
134
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;
142 }
143
144 int do_setitimer(int which, struct itimerval *value, struct itimerval *ovalue)
145 {
146         struct task_struct *tsk = current;
147         struct hrtimer *timer;
148         ktime_t expires;
149         cputime_t cval, cinterval, nval, ninterval;
150
151         switch (which) {
152         case ITIMER_REAL:
153                 timer = &tsk->signal->real_timer;
154                 hrtimer_cancel(timer);
155                 if (ovalue) {
156                         ovalue->it_value = itimer_get_remtime(timer);
157                         ovalue->it_interval
158                                 = ktime_to_timeval(tsk->signal->it_real_incr);
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);
165                 break;
166         case ITIMER_VIRTUAL:
167                 nval = timeval_to_cputime(&value->it_value);
168                 ninterval = timeval_to_cputime(&value->it_interval);
169                 read_lock(&tasklist_lock);
170                 spin_lock_irq(&tsk->sighand->siglock);
171                 cval = tsk->signal->it_virt_expires;
172                 cinterval = tsk->signal->it_virt_incr;
173                 if (!cputime_eq(cval, cputime_zero) ||
174                     !cputime_eq(nval, cputime_zero)) {
175                         if (cputime_gt(nval, cputime_zero))
176                                 nval = cputime_add(nval,
177                                                    jiffies_to_cputime(1));
178                         set_process_cpu_timer(tsk, CPUCLOCK_VIRT,
179                                               &nval, &cval);
180                 }
181                 tsk->signal->it_virt_expires = nval;
182                 tsk->signal->it_virt_incr = ninterval;
183                 spin_unlock_irq(&tsk->sighand->siglock);
184                 read_unlock(&tasklist_lock);
185                 if (ovalue) {
186                         cputime_to_timeval(cval, &ovalue->it_value);
187                         cputime_to_timeval(cinterval, &ovalue->it_interval);
188                 }
189                 break;
190         case ITIMER_PROF:
191                 nval = timeval_to_cputime(&value->it_value);
192                 ninterval = timeval_to_cputime(&value->it_interval);
193                 read_lock(&tasklist_lock);
194                 spin_lock_irq(&tsk->sighand->siglock);
195                 cval = tsk->signal->it_prof_expires;
196                 cinterval = tsk->signal->it_prof_incr;
197                 if (!cputime_eq(cval, cputime_zero) ||
198                     !cputime_eq(nval, cputime_zero)) {
199                         if (cputime_gt(nval, cputime_zero))
200                                 nval = cputime_add(nval,
201                                                    jiffies_to_cputime(1));
202                         set_process_cpu_timer(tsk, CPUCLOCK_PROF,
203                                               &nval, &cval);
204                 }
205                 tsk->signal->it_prof_expires = nval;
206                 tsk->signal->it_prof_incr = ninterval;
207                 spin_unlock_irq(&tsk->sighand->siglock);
208                 read_unlock(&tasklist_lock);
209                 if (ovalue) {
210                         cputime_to_timeval(cval, &ovalue->it_value);
211                         cputime_to_timeval(cinterval, &ovalue->it_interval);
212                 }
213                 break;
214         default:
215                 return -EINVAL;
216         }
217         return 0;
218 }
219
220 asmlinkage long sys_setitimer(int which,
221                               struct itimerval __user *value,
222                               struct itimerval __user *ovalue)
223 {
224         struct itimerval set_buffer, get_buffer;
225         int error;
226
227         if (value) {
228                 if(copy_from_user(&set_buffer, value, sizeof(set_buffer)))
229                         return -EFAULT;
230         } else
231                 memset((char *) &set_buffer, 0, sizeof(set_buffer));
232
233         error = do_setitimer(which, &set_buffer, ovalue ? &get_buffer : NULL);
234         if (error || !ovalue)
235                 return error;
236
237         if (copy_to_user(ovalue, &get_buffer, sizeof(get_buffer)))
238                 return -EFAULT; 
239         return 0;
240 }