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
;
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
);
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
);
170 jiffies_to_timeval(val
, &ovalue
->it_value
);
171 jiffies_to_timeval(interval
,
172 &ovalue
->it_interval
);
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
,
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
);
195 cputime_to_timeval(cval
, &ovalue
->it_value
);
196 cputime_to_timeval(cinterval
, &ovalue
->it_interval
);
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
,
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
);
219 cputime_to_timeval(cval
, &ovalue
->it_value
);
220 cputime_to_timeval(cinterval
, &ovalue
->it_interval
);
229 asmlinkage
long sys_setitimer(int which
,
230 struct itimerval __user
*value
,
231 struct itimerval __user
*ovalue
)
233 struct itimerval set_buffer
, get_buffer
;
237 if(copy_from_user(&set_buffer
, value
, sizeof(set_buffer
)))
240 memset((char *) &set_buffer
, 0, sizeof(set_buffer
));
242 error
= do_setitimer(which
, &set_buffer
, ovalue
? &get_buffer
: NULL
);
243 if (error
|| !ovalue
)
246 if (copy_to_user(ovalue
, &get_buffer
, sizeof(get_buffer
)))