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
)))