2 * linux/kernel/itimer.c
4 * Copyright (C) 1992 Darren Senn
7 /* These are all the functions necessary to implement itimers */
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>
16 #include <asm/uaccess.h>
18 static unsigned long it_real_value(struct signal_struct *sig)
20 unsigned long val = 0;
21 if (timer_pending(&sig->real_timer)) {
22 val = sig->real_timer.expires - jiffies;
24 /* look out for negative/zero itimer.. */
31 int do_getitimer(int which, struct itimerval *value)
33 struct task_struct *tsk = current;
34 unsigned long interval, val;
35 cputime_t cinterval, cval;
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);
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;
55 utime = cputime_add(utime, t->utime);
58 if (cputime_le(cval, utime)) { /* about to fire */
59 cval = jiffies_to_cputime(1);
61 cval = cputime_sub(cval, utime);
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);
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,
79 ptime = cputime_add(ptime,
84 if (cputime_le(cval, ptime)) { /* about to fire */
85 cval = jiffies_to_cputime(1);
87 cval = cputime_sub(cval, ptime);
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);
101 asmlinkage long sys_getitimer(int which, struct itimerval __user *value)
104 struct itimerval get_buffer;
107 error = do_getitimer(which, &get_buffer);
109 copy_to_user(value, &get_buffer, sizeof(get_buffer)))
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.
119 static inline void it_real_arm(struct task_struct *p, unsigned long interval)
121 p->signal->it_real_value = interval; /* XXX unnecessary field?? */
124 if (interval > (unsigned long) LONG_MAX)
126 p->signal->real_timer.expires = jiffies + interval;
127 add_timer(&p->signal->real_timer);
130 void it_real_fn(unsigned long __data)
132 struct task_struct * p = (struct task_struct *) __data;
134 send_group_sig_info(SIGALRM, SEND_SIG_PRIV, p);
137 * Now restart the timer if necessary. We don't need any locking
138 * here because do_setitimer makes sure we have finished running
139 * before it touches anything.
141 it_real_arm(p, p->signal->it_real_incr);
144 int do_setitimer(int which, struct itimerval *value, struct itimerval *ovalue)
146 struct task_struct *tsk = current;
147 unsigned long val, interval;
148 cputime_t cval, cinterval, nval, ninterval;
152 spin_lock_irq(&tsk->sighand->siglock);
153 interval = tsk->signal->it_real_incr;
154 val = it_real_value(tsk->signal);
156 del_timer_sync(&tsk->signal->real_timer);
157 tsk->signal->it_real_incr =
158 timeval_to_jiffies(&value->it_interval);
159 it_real_arm(tsk, timeval_to_jiffies(&value->it_value));
160 spin_unlock_irq(&tsk->sighand->siglock);
162 jiffies_to_timeval(val, &ovalue->it_value);
163 jiffies_to_timeval(interval,
164 &ovalue->it_interval);
168 nval = timeval_to_cputime(&value->it_value);
169 ninterval = timeval_to_cputime(&value->it_interval);
170 read_lock(&tasklist_lock);
171 spin_lock_irq(&tsk->sighand->siglock);
172 cval = tsk->signal->it_virt_expires;
173 cinterval = tsk->signal->it_virt_incr;
174 if (!cputime_eq(cval, cputime_zero) ||
175 !cputime_eq(nval, cputime_zero)) {
176 if (cputime_gt(nval, cputime_zero))
177 nval = cputime_add(nval,
178 jiffies_to_cputime(1));
179 set_process_cpu_timer(tsk, CPUCLOCK_VIRT,
182 tsk->signal->it_virt_expires = nval;
183 tsk->signal->it_virt_incr = ninterval;
184 spin_unlock_irq(&tsk->sighand->siglock);
185 read_unlock(&tasklist_lock);
187 cputime_to_timeval(cval, &ovalue->it_value);
188 cputime_to_timeval(cinterval, &ovalue->it_interval);
192 nval = timeval_to_cputime(&value->it_value);
193 ninterval = timeval_to_cputime(&value->it_interval);
194 read_lock(&tasklist_lock);
195 spin_lock_irq(&tsk->sighand->siglock);
196 cval = tsk->signal->it_prof_expires;
197 cinterval = tsk->signal->it_prof_incr;
198 if (!cputime_eq(cval, cputime_zero) ||
199 !cputime_eq(nval, cputime_zero)) {
200 if (cputime_gt(nval, cputime_zero))
201 nval = cputime_add(nval,
202 jiffies_to_cputime(1));
203 set_process_cpu_timer(tsk, CPUCLOCK_PROF,
206 tsk->signal->it_prof_expires = nval;
207 tsk->signal->it_prof_incr = ninterval;
208 spin_unlock_irq(&tsk->sighand->siglock);
209 read_unlock(&tasklist_lock);
211 cputime_to_timeval(cval, &ovalue->it_value);
212 cputime_to_timeval(cinterval, &ovalue->it_interval);
221 asmlinkage long sys_setitimer(int which,
222 struct itimerval __user *value,
223 struct itimerval __user *ovalue)
225 struct itimerval set_buffer, get_buffer;
229 if(copy_from_user(&set_buffer, value, sizeof(set_buffer)))
232 memset((char *) &set_buffer, 0, sizeof(set_buffer));
234 error = do_setitimer(which, &set_buffer, ovalue ? &get_buffer : NULL);
235 if (error || !ovalue)
238 if (copy_to_user(ovalue, &get_buffer, sizeof(get_buffer)))