1
2
3
4
5
6
7
8
9#include <linux/signal.h>
10#include <linux/sched.h>
11#include <linux/string.h>
12#include <linux/errno.h>
13#include <linux/time.h>
14#include <linux/mm.h>
15#include <linux/smp.h>
16#include <linux/smp_lock.h>
17
18#include <asm/uaccess.h>
19
20
21
22
23
24
25
26
27
28
29
30static unsigned long tvtojiffies(struct timeval *value)
31{
32 unsigned long sec = (unsigned) value->tv_sec;
33 unsigned long usec = (unsigned) value->tv_usec;
34
35 if (sec > (ULONG_MAX / HZ))
36 return ULONG_MAX;
37 usec += 1000000 / HZ - 1;
38 usec /= 1000000 / HZ;
39 return HZ*sec+usec;
40}
41
42static void jiffiestotv(unsigned long jiffies, struct timeval *value)
43{
44 value->tv_usec = (jiffies % HZ) * (1000000 / HZ);
45 value->tv_sec = jiffies / HZ;
46}
47
48static int _getitimer(int which, struct itimerval *value)
49{
50 register unsigned long val, interval;
51
52 switch (which) {
53 case ITIMER_REAL:
54 interval = current->it_real_incr;
55 val = 0;
56 if (del_timer(¤t->real_timer)) {
57 unsigned long now = jiffies;
58 val = current->real_timer.expires;
59 add_timer(¤t->real_timer);
60
61 if (val <= now)
62 val = now+1;
63 val -= now;
64 }
65 break;
66 case ITIMER_VIRTUAL:
67 val = current->it_virt_value;
68 interval = current->it_virt_incr;
69 break;
70 case ITIMER_PROF:
71 val = current->it_prof_value;
72 interval = current->it_prof_incr;
73 break;
74 default:
75 return(-EINVAL);
76 }
77 jiffiestotv(val, &value->it_value);
78 jiffiestotv(interval, &value->it_interval);
79 return 0;
80}
81
82
83asmlinkage int sys_getitimer(int which, struct itimerval *value)
84{
85 int error = -EFAULT;
86 struct itimerval get_buffer;
87
88 if (value) {
89 error = _getitimer(which, &get_buffer);
90 if (!error)
91 error = copy_to_user(value, &get_buffer, sizeof(get_buffer))
92 ? -EFAULT : 0;
93 }
94 return error;
95}
96
97void it_real_fn(unsigned long __data)
98{
99 struct task_struct * p = (struct task_struct *) __data;
100 unsigned long interval;
101
102 send_sig(SIGALRM, p, 1);
103 interval = p->it_real_incr;
104 if (interval) {
105 unsigned long timeout = jiffies + interval;
106
107 if (timeout < interval)
108 timeout = ULONG_MAX;
109 p->real_timer.expires = timeout;
110 add_timer(&p->real_timer);
111 }
112}
113
114int _setitimer(int which, struct itimerval *value, struct itimerval *ovalue)
115{
116 register unsigned long i, j;
117 int k;
118
119 i = tvtojiffies(&value->it_interval);
120 j = tvtojiffies(&value->it_value);
121 if (ovalue && (k = _getitimer(which, ovalue)) < 0)
122 return k;
123 switch (which) {
124 case ITIMER_REAL:
125 del_timer(¤t->real_timer);
126 current->it_real_value = j;
127 current->it_real_incr = i;
128 if (!j)
129 break;
130 i = j + jiffies;
131
132 if (i < j)
133 i = ULONG_MAX;
134 current->real_timer.expires = i;
135 add_timer(¤t->real_timer);
136 break;
137 case ITIMER_VIRTUAL:
138 if (j)
139 j++;
140 current->it_virt_value = j;
141 current->it_virt_incr = i;
142 break;
143 case ITIMER_PROF:
144 if (j)
145 j++;
146 current->it_prof_value = j;
147 current->it_prof_incr = i;
148 break;
149 default:
150 return -EINVAL;
151 }
152 return 0;
153}
154
155
156
157
158asmlinkage int sys_setitimer(int which, struct itimerval *value, struct itimerval *ovalue)
159{
160 struct itimerval set_buffer, get_buffer;
161 int error;
162
163 if (value) {
164 if(verify_area(VERIFY_READ, value, sizeof(*value)))
165 return -EFAULT;
166 if(copy_from_user(&set_buffer, value, sizeof(set_buffer)))
167 return -EFAULT;
168 } else
169 memset((char *) &set_buffer, 0, sizeof(set_buffer));
170
171 error = _setitimer(which, &set_buffer, ovalue ? &get_buffer : 0);
172 if (error || !ovalue)
173 return error;
174
175 if (copy_to_user(ovalue, &get_buffer, sizeof(get_buffer)))
176 return -EFAULT;
177 return 0;
178}
179