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>
13 #include <asm/uaccess.h>
16 * change timeval to jiffies, trying to avoid the
17 * most obvious overflows..
19 * The tv_*sec values are signed, but nothing seems to
20 * indicate whether we really should use them as signed values
21 * when doing itimers. POSIX doesn't mention this (but if
22 * alarm() uses itimers without checking, we have to use unsigned
25 static unsigned long tvtojiffies(struct timeval
*value
)
27 unsigned long sec
= (unsigned) value
->tv_sec
;
28 unsigned long usec
= (unsigned) value
->tv_usec
;
30 if (sec
> (ULONG_MAX
/ HZ
))
32 usec
+= 1000000 / HZ
- 1;
37 static void jiffiestotv(unsigned long jiffies
, struct timeval
*value
)
39 value
->tv_usec
= (jiffies
% HZ
) * (1000000 / HZ
);
40 value
->tv_sec
= jiffies
/ HZ
;
43 int do_getitimer(int which
, struct itimerval
*value
)
45 register unsigned long val
, interval
;
49 interval
= current
->it_real_incr
;
52 * FIXME! This needs to be atomic, in case the kernel timer happens!
54 if (timer_pending(¤t
->real_timer
)) {
55 val
= current
->real_timer
.expires
- jiffies
;
57 /* look out for negative/zero itimer.. */
63 val
= current
->it_virt_value
;
64 interval
= current
->it_virt_incr
;
67 val
= current
->it_prof_value
;
68 interval
= current
->it_prof_incr
;
73 jiffiestotv(val
, &value
->it_value
);
74 jiffiestotv(interval
, &value
->it_interval
);
78 /* SMP: Only we modify our itimer values. */
79 asmlinkage
long sys_getitimer(int which
, struct itimerval
*value
)
82 struct itimerval get_buffer
;
85 error
= do_getitimer(which
, &get_buffer
);
87 copy_to_user(value
, &get_buffer
, sizeof(get_buffer
)))
93 void it_real_fn(unsigned long __data
)
95 struct task_struct
* p
= (struct task_struct
*) __data
;
96 unsigned long interval
;
98 send_sig(SIGALRM
, p
, 1);
99 interval
= p
->it_real_incr
;
101 if (interval
> (unsigned long) LONG_MAX
)
103 p
->real_timer
.expires
= jiffies
+ interval
;
104 add_timer(&p
->real_timer
);
108 int do_setitimer(int which
, struct itimerval
*value
, struct itimerval
*ovalue
)
110 register unsigned long i
, j
;
113 i
= tvtojiffies(&value
->it_interval
);
114 j
= tvtojiffies(&value
->it_value
);
115 if (ovalue
&& (k
= do_getitimer(which
, ovalue
)) < 0)
119 del_timer_sync(¤t
->real_timer
);
120 current
->it_real_value
= j
;
121 current
->it_real_incr
= i
;
124 if (j
> (unsigned long) LONG_MAX
)
127 current
->real_timer
.expires
= i
;
128 add_timer(¤t
->real_timer
);
133 current
->it_virt_value
= j
;
134 current
->it_virt_incr
= i
;
139 current
->it_prof_value
= j
;
140 current
->it_prof_incr
= i
;
148 /* SMP: Again, only we play with our itimers, and signals are SMP safe
149 * now so that is not an issue at all anymore.
151 asmlinkage
long sys_setitimer(int which
, struct itimerval
*value
,
152 struct itimerval
*ovalue
)
154 struct itimerval set_buffer
, get_buffer
;
158 if(copy_from_user(&set_buffer
, value
, sizeof(set_buffer
)))
161 memset((char *) &set_buffer
, 0, sizeof(set_buffer
));
163 error
= do_setitimer(which
, &set_buffer
, ovalue
? &get_buffer
: 0);
164 if (error
|| !ovalue
)
167 if (copy_to_user(ovalue
, &get_buffer
, sizeof(get_buffer
)))