Import 2.3.9
[davej-history.git] / kernel / itimer.c
blob1b4661c397deb7552c8f10e7862c1840444b63a9
1 /*
2 * linux/kernel/itimer.c
4 * Copyright (C) 1992 Darren Senn
5 */
7 /* These are all the functions necessary to implement itimers */
9 #include <linux/mm.h>
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
23 * arithmetic).
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))
31 return ULONG_MAX;
32 usec += 1000000 / HZ - 1;
33 usec /= 1000000 / HZ;
34 return HZ*sec+usec;
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;
47 switch (which) {
48 case ITIMER_REAL:
49 interval = current->it_real_incr;
50 val = 0;
51 start_bh_atomic();
52 if (timer_pending(&current->real_timer)) {
53 val = current->real_timer.expires - jiffies;
55 /* look out for negative/zero itimer.. */
56 if ((long) val <= 0)
57 val = 1;
59 end_bh_atomic();
60 break;
61 case ITIMER_VIRTUAL:
62 val = current->it_virt_value;
63 interval = current->it_virt_incr;
64 break;
65 case ITIMER_PROF:
66 val = current->it_prof_value;
67 interval = current->it_prof_incr;
68 break;
69 default:
70 return(-EINVAL);
72 jiffiestotv(val, &value->it_value);
73 jiffiestotv(interval, &value->it_interval);
74 return 0;
77 /* SMP: Only we modify our itimer values. */
78 asmlinkage int sys_getitimer(int which, struct itimerval *value)
80 int error = -EFAULT;
81 struct itimerval get_buffer;
83 if (value) {
84 error = do_getitimer(which, &get_buffer);
85 if (!error &&
86 copy_to_user(value, &get_buffer, sizeof(get_buffer)))
87 error = -EFAULT;
89 return error;
92 void it_real_fn(unsigned long __data)
94 struct task_struct * p = (struct task_struct *) __data;
95 unsigned long interval;
97 send_sig(SIGALRM, p, 1);
98 interval = p->it_real_incr;
99 if (interval) {
100 if (interval > (unsigned long) LONG_MAX)
101 interval = LONG_MAX;
102 p->real_timer.expires = jiffies + interval;
103 add_timer(&p->real_timer);
107 int do_setitimer(int which, struct itimerval *value, struct itimerval *ovalue)
109 register unsigned long i, j;
110 int k;
112 i = tvtojiffies(&value->it_interval);
113 j = tvtojiffies(&value->it_value);
114 if (ovalue && (k = do_getitimer(which, ovalue)) < 0)
115 return k;
116 switch (which) {
117 case ITIMER_REAL:
118 start_bh_atomic();
119 del_timer(&current->real_timer);
120 end_bh_atomic();
121 current->it_real_value = j;
122 current->it_real_incr = i;
123 if (!j)
124 break;
125 if (j > (unsigned long) LONG_MAX)
126 j = LONG_MAX;
127 i = j + jiffies;
128 current->real_timer.expires = i;
129 add_timer(&current->real_timer);
130 break;
131 case ITIMER_VIRTUAL:
132 if (j)
133 j++;
134 current->it_virt_value = j;
135 current->it_virt_incr = i;
136 break;
137 case ITIMER_PROF:
138 if (j)
139 j++;
140 current->it_prof_value = j;
141 current->it_prof_incr = i;
142 break;
143 default:
144 return -EINVAL;
146 return 0;
149 /* SMP: Again, only we play with our itimers, and signals are SMP safe
150 * now so that is not an issue at all anymore.
152 asmlinkage int sys_setitimer(int which, struct itimerval *value,
153 struct itimerval *ovalue)
155 struct itimerval set_buffer, get_buffer;
156 int error;
158 if (value) {
159 if(verify_area(VERIFY_READ, value, sizeof(*value)))
160 return -EFAULT;
161 if(copy_from_user(&set_buffer, value, sizeof(set_buffer)))
162 return -EFAULT;
163 } else
164 memset((char *) &set_buffer, 0, sizeof(set_buffer));
166 error = do_setitimer(which, &set_buffer, ovalue ? &get_buffer : 0);
167 if (error || !ovalue)
168 return error;
170 if (copy_to_user(ovalue, &get_buffer, sizeof(get_buffer)))
171 return -EFAULT;
172 return 0;