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 /* 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
);
134 void it_real_fn(unsigned long __data
)
136 struct task_struct
* p
= (struct task_struct
*) __data
;
138 send_group_sig_info(SIGALRM
, SEND_SIG_PRIV
, p
);
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.
145 it_real_arm(p
, p
->signal
->it_real_incr
);
148 int do_setitimer(int which
, struct itimerval
*value
, struct itimerval
*ovalue
)
150 struct task_struct
*tsk
= current
;
151 unsigned long val
, interval
;
152 cputime_t cval
, cinterval
, nval
, ninterval
;
156 spin_lock_irq(&tsk
->sighand
->siglock
);
157 interval
= tsk
->signal
->it_real_incr
;
158 val
= it_real_value(tsk
->signal
);
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
);
166 jiffies_to_timeval(val
, &ovalue
->it_value
);
167 jiffies_to_timeval(interval
,
168 &ovalue
->it_interval
);
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
,
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
);
191 cputime_to_timeval(cval
, &ovalue
->it_value
);
192 cputime_to_timeval(cinterval
, &ovalue
->it_interval
);
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
,
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
);
215 cputime_to_timeval(cval
, &ovalue
->it_value
);
216 cputime_to_timeval(cinterval
, &ovalue
->it_interval
);
225 asmlinkage
long sys_setitimer(int which
,
226 struct itimerval __user
*value
,
227 struct itimerval __user
*ovalue
)
229 struct itimerval set_buffer
, get_buffer
;
233 if(copy_from_user(&set_buffer
, value
, sizeof(set_buffer
)))
236 memset((char *) &set_buffer
, 0, sizeof(set_buffer
));
238 error
= do_setitimer(which
, &set_buffer
, ovalue
? &get_buffer
: NULL
);
239 if (error
|| !ovalue
)
242 if (copy_to_user(ovalue
, &get_buffer
, sizeof(get_buffer
)))