[PATCH] x86: i8253/i8259A lock cleanup
[pandora-kernel.git] / 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
16 #include <asm/uaccess.h>
17
18 static 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
31 int 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
101 asmlinkage 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
115 /*
116  * Called with P->sighand->siglock held and P->signal->real_timer inactive.
117  * If interval is nonzero, arm the timer for interval ticks from now.
118  */
119 static inline void it_real_arm(struct task_struct *p, unsigned long interval)
120 {
121         p->signal->it_real_value = interval; /* XXX unnecessary field?? */
122         if (interval == 0)
123                 return;
124         if (interval > (unsigned long) LONG_MAX)
125                 interval = LONG_MAX;
126         /* the "+ 1" below makes sure that the timer doesn't go off before
127          * the interval requested. This could happen if
128          * time requested % (usecs per jiffy) is more than the usecs left
129          * in the current jiffy */
130         p->signal->real_timer.expires = jiffies + interval + 1;
131         add_timer(&p->signal->real_timer);
132 }
133
134 void it_real_fn(unsigned long __data)
135 {
136         struct task_struct * p = (struct task_struct *) __data;
137
138         send_group_sig_info(SIGALRM, SEND_SIG_PRIV, p);
139
140         /*
141          * Now restart the timer if necessary.  We don't need any locking
142          * here because do_setitimer makes sure we have finished running
143          * before it touches anything.
144          */
145         it_real_arm(p, p->signal->it_real_incr);
146 }
147
148 int do_setitimer(int which, struct itimerval *value, struct itimerval *ovalue)
149 {
150         struct task_struct *tsk = current;
151         unsigned long val, interval;
152         cputime_t cval, cinterval, nval, ninterval;
153
154         switch (which) {
155         case ITIMER_REAL:
156 again:
157                 spin_lock_irq(&tsk->sighand->siglock);
158                 interval = tsk->signal->it_real_incr;
159                 val = it_real_value(tsk->signal);
160                 /* We are sharing ->siglock with it_real_fn() */
161                 if (try_to_del_timer_sync(&tsk->signal->real_timer) < 0) {
162                         spin_unlock_irq(&tsk->sighand->siglock);
163                         goto again;
164                 }
165                 tsk->signal->it_real_incr =
166                         timeval_to_jiffies(&value->it_interval);
167                 it_real_arm(tsk, timeval_to_jiffies(&value->it_value));
168                 spin_unlock_irq(&tsk->sighand->siglock);
169                 if (ovalue) {
170                         jiffies_to_timeval(val, &ovalue->it_value);
171                         jiffies_to_timeval(interval,
172                                            &ovalue->it_interval);
173                 }
174                 break;
175         case ITIMER_VIRTUAL:
176                 nval = timeval_to_cputime(&value->it_value);
177                 ninterval = timeval_to_cputime(&value->it_interval);
178                 read_lock(&tasklist_lock);
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                 read_unlock(&tasklist_lock);
194                 if (ovalue) {
195                         cputime_to_timeval(cval, &ovalue->it_value);
196                         cputime_to_timeval(cinterval, &ovalue->it_interval);
197                 }
198                 break;
199         case ITIMER_PROF:
200                 nval = timeval_to_cputime(&value->it_value);
201                 ninterval = timeval_to_cputime(&value->it_interval);
202                 read_lock(&tasklist_lock);
203                 spin_lock_irq(&tsk->sighand->siglock);
204                 cval = tsk->signal->it_prof_expires;
205                 cinterval = tsk->signal->it_prof_incr;
206                 if (!cputime_eq(cval, cputime_zero) ||
207                     !cputime_eq(nval, cputime_zero)) {
208                         if (cputime_gt(nval, cputime_zero))
209                                 nval = cputime_add(nval,
210                                                    jiffies_to_cputime(1));
211                         set_process_cpu_timer(tsk, CPUCLOCK_PROF,
212                                               &nval, &cval);
213                 }
214                 tsk->signal->it_prof_expires = nval;
215                 tsk->signal->it_prof_incr = ninterval;
216                 spin_unlock_irq(&tsk->sighand->siglock);
217                 read_unlock(&tasklist_lock);
218                 if (ovalue) {
219                         cputime_to_timeval(cval, &ovalue->it_value);
220                         cputime_to_timeval(cinterval, &ovalue->it_interval);
221                 }
222                 break;
223         default:
224                 return -EINVAL;
225         }
226         return 0;
227 }
228
229 asmlinkage long sys_setitimer(int which,
230                               struct itimerval __user *value,
231                               struct itimerval __user *ovalue)
232 {
233         struct itimerval set_buffer, get_buffer;
234         int error;
235
236         if (value) {
237                 if(copy_from_user(&set_buffer, value, sizeof(set_buffer)))
238                         return -EFAULT;
239         } else
240                 memset((char *) &set_buffer, 0, sizeof(set_buffer));
241
242         error = do_setitimer(which, &set_buffer, ovalue ? &get_buffer : NULL);
243         if (error || !ovalue)
244                 return error;
245
246         if (copy_to_user(ovalue, &get_buffer, sizeof(get_buffer)))
247                 return -EFAULT; 
248         return 0;
249 }