Magellan Linux

Contents of /alx-src/tags/kernel26-2.6.12-alx-r9/kernel/itimer.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 630 - (show annotations) (download)
Wed Mar 4 11:03:09 2009 UTC (15 years, 3 months ago) by niro
File MIME type: text/plain
File size: 6918 byte(s)
Tag kernel26-2.6.12-alx-r9
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 spin_lock_irq(&tsk->sighand->siglock);
157 interval = tsk->signal->it_real_incr;
158 val = it_real_value(tsk->signal);
159 if (val)
160 del_timer_sync(&tsk->signal->real_timer);
161 tsk->signal->it_real_incr =
162 timeval_to_jiffies(&value->it_interval);
163 it_real_arm(tsk, timeval_to_jiffies(&value->it_value));
164 spin_unlock_irq(&tsk->sighand->siglock);
165 if (ovalue) {
166 jiffies_to_timeval(val, &ovalue->it_value);
167 jiffies_to_timeval(interval,
168 &ovalue->it_interval);
169 }
170 break;
171 case ITIMER_VIRTUAL:
172 nval = timeval_to_cputime(&value->it_value);
173 ninterval = timeval_to_cputime(&value->it_interval);
174 read_lock(&tasklist_lock);
175 spin_lock_irq(&tsk->sighand->siglock);
176 cval = tsk->signal->it_virt_expires;
177 cinterval = tsk->signal->it_virt_incr;
178 if (!cputime_eq(cval, cputime_zero) ||
179 !cputime_eq(nval, cputime_zero)) {
180 if (cputime_gt(nval, cputime_zero))
181 nval = cputime_add(nval,
182 jiffies_to_cputime(1));
183 set_process_cpu_timer(tsk, CPUCLOCK_VIRT,
184 &nval, &cval);
185 }
186 tsk->signal->it_virt_expires = nval;
187 tsk->signal->it_virt_incr = ninterval;
188 spin_unlock_irq(&tsk->sighand->siglock);
189 read_unlock(&tasklist_lock);
190 if (ovalue) {
191 cputime_to_timeval(cval, &ovalue->it_value);
192 cputime_to_timeval(cinterval, &ovalue->it_interval);
193 }
194 break;
195 case ITIMER_PROF:
196 nval = timeval_to_cputime(&value->it_value);
197 ninterval = timeval_to_cputime(&value->it_interval);
198 read_lock(&tasklist_lock);
199 spin_lock_irq(&tsk->sighand->siglock);
200 cval = tsk->signal->it_prof_expires;
201 cinterval = tsk->signal->it_prof_incr;
202 if (!cputime_eq(cval, cputime_zero) ||
203 !cputime_eq(nval, cputime_zero)) {
204 if (cputime_gt(nval, cputime_zero))
205 nval = cputime_add(nval,
206 jiffies_to_cputime(1));
207 set_process_cpu_timer(tsk, CPUCLOCK_PROF,
208 &nval, &cval);
209 }
210 tsk->signal->it_prof_expires = nval;
211 tsk->signal->it_prof_incr = ninterval;
212 spin_unlock_irq(&tsk->sighand->siglock);
213 read_unlock(&tasklist_lock);
214 if (ovalue) {
215 cputime_to_timeval(cval, &ovalue->it_value);
216 cputime_to_timeval(cinterval, &ovalue->it_interval);
217 }
218 break;
219 default:
220 return -EINVAL;
221 }
222 return 0;
223 }
224
225 asmlinkage long sys_setitimer(int which,
226 struct itimerval __user *value,
227 struct itimerval __user *ovalue)
228 {
229 struct itimerval set_buffer, get_buffer;
230 int error;
231
232 if (value) {
233 if(copy_from_user(&set_buffer, value, sizeof(set_buffer)))
234 return -EFAULT;
235 } else
236 memset((char *) &set_buffer, 0, sizeof(set_buffer));
237
238 error = do_setitimer(which, &set_buffer, ovalue ? &get_buffer : NULL);
239 if (error || !ovalue)
240 return error;
241
242 if (copy_to_user(ovalue, &get_buffer, sizeof(get_buffer)))
243 return -EFAULT;
244 return 0;
245 }