1 | #include <machine/rtems-bsd-kernel-space.h> |
---|
2 | |
---|
3 | /*- |
---|
4 | * Copyright (c) 1982, 1986, 1989, 1993 |
---|
5 | * The Regents of the University of California. All rights reserved. |
---|
6 | * |
---|
7 | * Redistribution and use in source and binary forms, with or without |
---|
8 | * modification, are permitted provided that the following conditions |
---|
9 | * are met: |
---|
10 | * 1. Redistributions of source code must retain the above copyright |
---|
11 | * notice, this list of conditions and the following disclaimer. |
---|
12 | * 2. Redistributions in binary form must reproduce the above copyright |
---|
13 | * notice, this list of conditions and the following disclaimer in the |
---|
14 | * documentation and/or other materials provided with the distribution. |
---|
15 | * 4. Neither the name of the University nor the names of its contributors |
---|
16 | * may be used to endorse or promote products derived from this software |
---|
17 | * without specific prior written permission. |
---|
18 | * |
---|
19 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND |
---|
20 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
---|
21 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
---|
22 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE |
---|
23 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
---|
24 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS |
---|
25 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
---|
26 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
---|
27 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY |
---|
28 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
---|
29 | * SUCH DAMAGE. |
---|
30 | * |
---|
31 | * @(#)kern_time.c 8.1 (Berkeley) 6/10/93 |
---|
32 | */ |
---|
33 | |
---|
34 | #include <sys/cdefs.h> |
---|
35 | __FBSDID("$FreeBSD$"); |
---|
36 | |
---|
37 | #include <rtems/bsd/sys/param.h> |
---|
38 | #include <sys/systm.h> |
---|
39 | #include <sys/limits.h> |
---|
40 | #include <sys/clock.h> |
---|
41 | #include <rtems/bsd/sys/lock.h> |
---|
42 | #include <sys/mutex.h> |
---|
43 | #include <sys/sysproto.h> |
---|
44 | #include <sys/eventhandler.h> |
---|
45 | #include <sys/resourcevar.h> |
---|
46 | #include <sys/signalvar.h> |
---|
47 | #include <sys/kernel.h> |
---|
48 | #include <sys/syscallsubr.h> |
---|
49 | #include <sys/sysctl.h> |
---|
50 | #include <sys/sysent.h> |
---|
51 | #include <sys/priv.h> |
---|
52 | #include <sys/proc.h> |
---|
53 | #include <sys/posix4.h> |
---|
54 | #include <sys/time.h> |
---|
55 | #include <sys/timers.h> |
---|
56 | #include <sys/timetc.h> |
---|
57 | #include <sys/vnode.h> |
---|
58 | |
---|
59 | #include <vm/vm.h> |
---|
60 | #include <vm/vm_extern.h> |
---|
61 | |
---|
62 | #define MAX_CLOCKS (CLOCK_MONOTONIC+1) |
---|
63 | #define CPUCLOCK_BIT 0x80000000 |
---|
64 | #define CPUCLOCK_PROCESS_BIT 0x40000000 |
---|
65 | #define CPUCLOCK_ID_MASK (~(CPUCLOCK_BIT|CPUCLOCK_PROCESS_BIT)) |
---|
66 | #define MAKE_THREAD_CPUCLOCK(tid) (CPUCLOCK_BIT|(tid)) |
---|
67 | #define MAKE_PROCESS_CPUCLOCK(pid) \ |
---|
68 | (CPUCLOCK_BIT|CPUCLOCK_PROCESS_BIT|(pid)) |
---|
69 | |
---|
70 | #ifndef __rtems__ |
---|
71 | static struct kclock posix_clocks[MAX_CLOCKS]; |
---|
72 | static uma_zone_t itimer_zone = NULL; |
---|
73 | |
---|
74 | /* |
---|
75 | * Time of day and interval timer support. |
---|
76 | * |
---|
77 | * These routines provide the kernel entry points to get and set |
---|
78 | * the time-of-day and per-process interval timers. Subroutines |
---|
79 | * here provide support for adding and subtracting timeval structures |
---|
80 | * and decrementing interval timers, optionally reloading the interval |
---|
81 | * timers when they expire. |
---|
82 | */ |
---|
83 | |
---|
84 | static int settime(struct thread *, struct timeval *); |
---|
85 | #endif /* __rtems__ */ |
---|
86 | static void timevalfix(struct timeval *); |
---|
87 | |
---|
88 | #ifndef __rtems__ |
---|
89 | static void itimer_start(void); |
---|
90 | static int itimer_init(void *, int, int); |
---|
91 | static void itimer_fini(void *, int); |
---|
92 | static void itimer_enter(struct itimer *); |
---|
93 | static void itimer_leave(struct itimer *); |
---|
94 | static struct itimer *itimer_find(struct proc *, int); |
---|
95 | static void itimers_alloc(struct proc *); |
---|
96 | static void itimers_event_hook_exec(void *arg, struct proc *p, struct image_params *imgp); |
---|
97 | static void itimers_event_hook_exit(void *arg, struct proc *p); |
---|
98 | static int realtimer_create(struct itimer *); |
---|
99 | static int realtimer_gettime(struct itimer *, struct itimerspec *); |
---|
100 | static int realtimer_settime(struct itimer *, int, |
---|
101 | struct itimerspec *, struct itimerspec *); |
---|
102 | static int realtimer_delete(struct itimer *); |
---|
103 | static void realtimer_clocktime(clockid_t, struct timespec *); |
---|
104 | static void realtimer_expire(void *); |
---|
105 | |
---|
106 | int register_posix_clock(int, struct kclock *); |
---|
107 | void itimer_fire(struct itimer *it); |
---|
108 | int itimespecfix(struct timespec *ts); |
---|
109 | |
---|
110 | #define CLOCK_CALL(clock, call, arglist) \ |
---|
111 | ((*posix_clocks[clock].call) arglist) |
---|
112 | |
---|
113 | SYSINIT(posix_timer, SI_SUB_P1003_1B, SI_ORDER_FIRST+4, itimer_start, NULL); |
---|
114 | |
---|
115 | |
---|
116 | static int |
---|
117 | settime(struct thread *td, struct timeval *tv) |
---|
118 | { |
---|
119 | struct timeval delta, tv1, tv2; |
---|
120 | static struct timeval maxtime, laststep; |
---|
121 | struct timespec ts; |
---|
122 | int s; |
---|
123 | |
---|
124 | s = splclock(); |
---|
125 | microtime(&tv1); |
---|
126 | delta = *tv; |
---|
127 | timevalsub(&delta, &tv1); |
---|
128 | |
---|
129 | /* |
---|
130 | * If the system is secure, we do not allow the time to be |
---|
131 | * set to a value earlier than 1 second less than the highest |
---|
132 | * time we have yet seen. The worst a miscreant can do in |
---|
133 | * this circumstance is "freeze" time. He couldn't go |
---|
134 | * back to the past. |
---|
135 | * |
---|
136 | * We similarly do not allow the clock to be stepped more |
---|
137 | * than one second, nor more than once per second. This allows |
---|
138 | * a miscreant to make the clock march double-time, but no worse. |
---|
139 | */ |
---|
140 | if (securelevel_gt(td->td_ucred, 1) != 0) { |
---|
141 | if (delta.tv_sec < 0 || delta.tv_usec < 0) { |
---|
142 | /* |
---|
143 | * Update maxtime to latest time we've seen. |
---|
144 | */ |
---|
145 | if (tv1.tv_sec > maxtime.tv_sec) |
---|
146 | maxtime = tv1; |
---|
147 | tv2 = *tv; |
---|
148 | timevalsub(&tv2, &maxtime); |
---|
149 | if (tv2.tv_sec < -1) { |
---|
150 | tv->tv_sec = maxtime.tv_sec - 1; |
---|
151 | printf("Time adjustment clamped to -1 second\n"); |
---|
152 | } |
---|
153 | } else { |
---|
154 | if (tv1.tv_sec == laststep.tv_sec) { |
---|
155 | splx(s); |
---|
156 | return (EPERM); |
---|
157 | } |
---|
158 | if (delta.tv_sec > 1) { |
---|
159 | tv->tv_sec = tv1.tv_sec + 1; |
---|
160 | printf("Time adjustment clamped to +1 second\n"); |
---|
161 | } |
---|
162 | laststep = *tv; |
---|
163 | } |
---|
164 | } |
---|
165 | |
---|
166 | ts.tv_sec = tv->tv_sec; |
---|
167 | ts.tv_nsec = tv->tv_usec * 1000; |
---|
168 | mtx_lock(&Giant); |
---|
169 | tc_setclock(&ts); |
---|
170 | resettodr(); |
---|
171 | mtx_unlock(&Giant); |
---|
172 | return (0); |
---|
173 | } |
---|
174 | |
---|
175 | #ifndef _SYS_SYSPROTO_H_ |
---|
176 | struct clock_getcpuclockid2_args { |
---|
177 | id_t id; |
---|
178 | int which, |
---|
179 | clockid_t *clock_id; |
---|
180 | }; |
---|
181 | #endif |
---|
182 | /* ARGSUSED */ |
---|
183 | int |
---|
184 | sys_clock_getcpuclockid2(struct thread *td, struct clock_getcpuclockid2_args *uap) |
---|
185 | { |
---|
186 | clockid_t clk_id; |
---|
187 | int error; |
---|
188 | |
---|
189 | error = kern_clock_getcpuclockid2(td, uap->id, uap->which, &clk_id); |
---|
190 | if (error == 0) |
---|
191 | error = copyout(&clk_id, uap->clock_id, sizeof(clockid_t)); |
---|
192 | return (error); |
---|
193 | } |
---|
194 | |
---|
195 | int |
---|
196 | kern_clock_getcpuclockid2(struct thread *td, id_t id, int which, |
---|
197 | clockid_t *clk_id) |
---|
198 | { |
---|
199 | struct proc *p; |
---|
200 | pid_t pid; |
---|
201 | lwpid_t tid; |
---|
202 | int error; |
---|
203 | |
---|
204 | switch (which) { |
---|
205 | case CPUCLOCK_WHICH_PID: |
---|
206 | if (id != 0) { |
---|
207 | error = pget(id, PGET_CANSEE | PGET_NOTID, &p); |
---|
208 | if (error != 0) |
---|
209 | return (error); |
---|
210 | PROC_UNLOCK(p); |
---|
211 | pid = id; |
---|
212 | } else { |
---|
213 | pid = td->td_proc->p_pid; |
---|
214 | } |
---|
215 | *clk_id = MAKE_PROCESS_CPUCLOCK(pid); |
---|
216 | return (0); |
---|
217 | case CPUCLOCK_WHICH_TID: |
---|
218 | tid = id == 0 ? td->td_tid : id; |
---|
219 | *clk_id = MAKE_THREAD_CPUCLOCK(tid); |
---|
220 | return (0); |
---|
221 | default: |
---|
222 | return (EINVAL); |
---|
223 | } |
---|
224 | } |
---|
225 | |
---|
226 | #ifndef _SYS_SYSPROTO_H_ |
---|
227 | struct clock_gettime_args { |
---|
228 | clockid_t clock_id; |
---|
229 | struct timespec *tp; |
---|
230 | }; |
---|
231 | #endif |
---|
232 | #ifndef __rtems__ |
---|
233 | /* ARGSUSED */ |
---|
234 | int |
---|
235 | sys_clock_gettime(struct thread *td, struct clock_gettime_args *uap) |
---|
236 | { |
---|
237 | struct timespec ats; |
---|
238 | int error; |
---|
239 | |
---|
240 | error = kern_clock_gettime(td, uap->clock_id, &ats); |
---|
241 | if (error == 0) |
---|
242 | error = copyout(&ats, uap->tp, sizeof(ats)); |
---|
243 | |
---|
244 | return (error); |
---|
245 | } |
---|
246 | #endif |
---|
247 | |
---|
248 | #ifndef __rtems__ |
---|
249 | static inline void |
---|
250 | cputick2timespec(uint64_t runtime, struct timespec *ats) |
---|
251 | { |
---|
252 | runtime = cputick2usec(runtime); |
---|
253 | ats->tv_sec = runtime / 1000000; |
---|
254 | ats->tv_nsec = runtime % 1000000 * 1000; |
---|
255 | } |
---|
256 | |
---|
257 | static void |
---|
258 | get_thread_cputime(struct thread *targettd, struct timespec *ats) |
---|
259 | { |
---|
260 | uint64_t runtime, curtime, switchtime; |
---|
261 | |
---|
262 | if (targettd == NULL) { /* current thread */ |
---|
263 | critical_enter(); |
---|
264 | switchtime = PCPU_GET(switchtime); |
---|
265 | curtime = cpu_ticks(); |
---|
266 | runtime = curthread->td_runtime; |
---|
267 | critical_exit(); |
---|
268 | runtime += curtime - switchtime; |
---|
269 | } else { |
---|
270 | thread_lock(targettd); |
---|
271 | runtime = targettd->td_runtime; |
---|
272 | thread_unlock(targettd); |
---|
273 | } |
---|
274 | cputick2timespec(runtime, ats); |
---|
275 | } |
---|
276 | |
---|
277 | static void |
---|
278 | get_process_cputime(struct proc *targetp, struct timespec *ats) |
---|
279 | { |
---|
280 | uint64_t runtime; |
---|
281 | struct rusage ru; |
---|
282 | |
---|
283 | PROC_SLOCK(targetp); |
---|
284 | rufetch(targetp, &ru); |
---|
285 | runtime = targetp->p_rux.rux_runtime; |
---|
286 | PROC_SUNLOCK(targetp); |
---|
287 | cputick2timespec(runtime, ats); |
---|
288 | } |
---|
289 | |
---|
290 | static int |
---|
291 | get_cputime(struct thread *td, clockid_t clock_id, struct timespec *ats) |
---|
292 | { |
---|
293 | struct proc *p, *p2; |
---|
294 | struct thread *td2; |
---|
295 | lwpid_t tid; |
---|
296 | pid_t pid; |
---|
297 | int error; |
---|
298 | |
---|
299 | p = td->td_proc; |
---|
300 | if ((clock_id & CPUCLOCK_PROCESS_BIT) == 0) { |
---|
301 | tid = clock_id & CPUCLOCK_ID_MASK; |
---|
302 | td2 = tdfind(tid, p->p_pid); |
---|
303 | if (td2 == NULL) |
---|
304 | return (EINVAL); |
---|
305 | get_thread_cputime(td2, ats); |
---|
306 | PROC_UNLOCK(td2->td_proc); |
---|
307 | } else { |
---|
308 | pid = clock_id & CPUCLOCK_ID_MASK; |
---|
309 | error = pget(pid, PGET_CANSEE, &p2); |
---|
310 | if (error != 0) |
---|
311 | return (EINVAL); |
---|
312 | get_process_cputime(p2, ats); |
---|
313 | PROC_UNLOCK(p2); |
---|
314 | } |
---|
315 | return (0); |
---|
316 | } |
---|
317 | |
---|
318 | int |
---|
319 | kern_clock_gettime(struct thread *td, clockid_t clock_id, struct timespec *ats) |
---|
320 | { |
---|
321 | struct timeval sys, user; |
---|
322 | struct proc *p; |
---|
323 | |
---|
324 | p = td->td_proc; |
---|
325 | switch (clock_id) { |
---|
326 | case CLOCK_REALTIME: /* Default to precise. */ |
---|
327 | case CLOCK_REALTIME_PRECISE: |
---|
328 | nanotime(ats); |
---|
329 | break; |
---|
330 | case CLOCK_REALTIME_FAST: |
---|
331 | getnanotime(ats); |
---|
332 | break; |
---|
333 | case CLOCK_VIRTUAL: |
---|
334 | PROC_LOCK(p); |
---|
335 | PROC_SLOCK(p); |
---|
336 | calcru(p, &user, &sys); |
---|
337 | PROC_SUNLOCK(p); |
---|
338 | PROC_UNLOCK(p); |
---|
339 | TIMEVAL_TO_TIMESPEC(&user, ats); |
---|
340 | break; |
---|
341 | case CLOCK_PROF: |
---|
342 | PROC_LOCK(p); |
---|
343 | PROC_SLOCK(p); |
---|
344 | calcru(p, &user, &sys); |
---|
345 | PROC_SUNLOCK(p); |
---|
346 | PROC_UNLOCK(p); |
---|
347 | timevaladd(&user, &sys); |
---|
348 | TIMEVAL_TO_TIMESPEC(&user, ats); |
---|
349 | break; |
---|
350 | case CLOCK_MONOTONIC: /* Default to precise. */ |
---|
351 | case CLOCK_MONOTONIC_PRECISE: |
---|
352 | case CLOCK_UPTIME: |
---|
353 | case CLOCK_UPTIME_PRECISE: |
---|
354 | nanouptime(ats); |
---|
355 | break; |
---|
356 | case CLOCK_UPTIME_FAST: |
---|
357 | case CLOCK_MONOTONIC_FAST: |
---|
358 | getnanouptime(ats); |
---|
359 | break; |
---|
360 | case CLOCK_SECOND: |
---|
361 | ats->tv_sec = time_second; |
---|
362 | ats->tv_nsec = 0; |
---|
363 | break; |
---|
364 | case CLOCK_THREAD_CPUTIME_ID: |
---|
365 | get_thread_cputime(NULL, ats); |
---|
366 | break; |
---|
367 | case CLOCK_PROCESS_CPUTIME_ID: |
---|
368 | PROC_LOCK(p); |
---|
369 | get_process_cputime(p, ats); |
---|
370 | PROC_UNLOCK(p); |
---|
371 | break; |
---|
372 | default: |
---|
373 | if ((int)clock_id >= 0) |
---|
374 | return (EINVAL); |
---|
375 | return (get_cputime(td, clock_id, ats)); |
---|
376 | } |
---|
377 | return (0); |
---|
378 | } |
---|
379 | #endif |
---|
380 | |
---|
381 | #ifndef _SYS_SYSPROTO_H_ |
---|
382 | struct clock_settime_args { |
---|
383 | clockid_t clock_id; |
---|
384 | const struct timespec *tp; |
---|
385 | }; |
---|
386 | #endif |
---|
387 | #ifndef __rtems__ |
---|
388 | /* ARGSUSED */ |
---|
389 | int |
---|
390 | sys_clock_settime(struct thread *td, struct clock_settime_args *uap) |
---|
391 | { |
---|
392 | struct timespec ats; |
---|
393 | int error; |
---|
394 | |
---|
395 | if ((error = copyin(uap->tp, &ats, sizeof(ats))) != 0) |
---|
396 | return (error); |
---|
397 | return (kern_clock_settime(td, uap->clock_id, &ats)); |
---|
398 | } |
---|
399 | |
---|
400 | int |
---|
401 | kern_clock_settime(struct thread *td, clockid_t clock_id, struct timespec *ats) |
---|
402 | { |
---|
403 | struct timeval atv; |
---|
404 | int error; |
---|
405 | |
---|
406 | if ((error = priv_check(td, PRIV_CLOCK_SETTIME)) != 0) |
---|
407 | return (error); |
---|
408 | if (clock_id != CLOCK_REALTIME) |
---|
409 | return (EINVAL); |
---|
410 | if (ats->tv_nsec < 0 || ats->tv_nsec >= 1000000000) |
---|
411 | return (EINVAL); |
---|
412 | /* XXX Don't convert nsec->usec and back */ |
---|
413 | TIMESPEC_TO_TIMEVAL(&atv, ats); |
---|
414 | error = settime(td, &atv); |
---|
415 | return (error); |
---|
416 | } |
---|
417 | #endif |
---|
418 | |
---|
419 | #ifndef _SYS_SYSPROTO_H_ |
---|
420 | struct clock_getres_args { |
---|
421 | clockid_t clock_id; |
---|
422 | struct timespec *tp; |
---|
423 | }; |
---|
424 | #endif |
---|
425 | #ifndef __rtems__ |
---|
426 | int |
---|
427 | sys_clock_getres(struct thread *td, struct clock_getres_args *uap) |
---|
428 | { |
---|
429 | struct timespec ts; |
---|
430 | int error; |
---|
431 | |
---|
432 | if (uap->tp == NULL) |
---|
433 | return (0); |
---|
434 | |
---|
435 | error = kern_clock_getres(td, uap->clock_id, &ts); |
---|
436 | if (error == 0) |
---|
437 | error = copyout(&ts, uap->tp, sizeof(ts)); |
---|
438 | return (error); |
---|
439 | } |
---|
440 | |
---|
441 | int |
---|
442 | kern_clock_getres(struct thread *td, clockid_t clock_id, struct timespec *ts) |
---|
443 | { |
---|
444 | |
---|
445 | ts->tv_sec = 0; |
---|
446 | switch (clock_id) { |
---|
447 | case CLOCK_REALTIME: |
---|
448 | case CLOCK_REALTIME_FAST: |
---|
449 | case CLOCK_REALTIME_PRECISE: |
---|
450 | case CLOCK_MONOTONIC: |
---|
451 | case CLOCK_MONOTONIC_FAST: |
---|
452 | case CLOCK_MONOTONIC_PRECISE: |
---|
453 | case CLOCK_UPTIME: |
---|
454 | case CLOCK_UPTIME_FAST: |
---|
455 | case CLOCK_UPTIME_PRECISE: |
---|
456 | /* |
---|
457 | * Round up the result of the division cheaply by adding 1. |
---|
458 | * Rounding up is especially important if rounding down |
---|
459 | * would give 0. Perfect rounding is unimportant. |
---|
460 | */ |
---|
461 | ts->tv_nsec = 1000000000 / tc_getfrequency() + 1; |
---|
462 | break; |
---|
463 | case CLOCK_VIRTUAL: |
---|
464 | case CLOCK_PROF: |
---|
465 | /* Accurately round up here because we can do so cheaply. */ |
---|
466 | ts->tv_nsec = (1000000000 + hz - 1) / hz; |
---|
467 | break; |
---|
468 | case CLOCK_SECOND: |
---|
469 | ts->tv_sec = 1; |
---|
470 | ts->tv_nsec = 0; |
---|
471 | break; |
---|
472 | case CLOCK_THREAD_CPUTIME_ID: |
---|
473 | case CLOCK_PROCESS_CPUTIME_ID: |
---|
474 | cputime: |
---|
475 | /* sync with cputick2usec */ |
---|
476 | ts->tv_nsec = 1000000 / cpu_tickrate(); |
---|
477 | if (ts->tv_nsec == 0) |
---|
478 | ts->tv_nsec = 1000; |
---|
479 | break; |
---|
480 | default: |
---|
481 | if ((int)clock_id < 0) |
---|
482 | goto cputime; |
---|
483 | return (EINVAL); |
---|
484 | } |
---|
485 | return (0); |
---|
486 | } |
---|
487 | #endif |
---|
488 | |
---|
489 | static int nanowait; |
---|
490 | |
---|
491 | int |
---|
492 | kern_nanosleep(struct thread *td, struct timespec *rqt, struct timespec *rmt) |
---|
493 | { |
---|
494 | struct timespec ts, ts2, ts3; |
---|
495 | struct timeval tv; |
---|
496 | int error; |
---|
497 | |
---|
498 | if (rqt->tv_nsec < 0 || rqt->tv_nsec >= 1000000000) |
---|
499 | return (EINVAL); |
---|
500 | if (rqt->tv_sec < 0 || (rqt->tv_sec == 0 && rqt->tv_nsec == 0)) |
---|
501 | return (0); |
---|
502 | getnanouptime(&ts); |
---|
503 | timespecadd(&ts, rqt); |
---|
504 | TIMESPEC_TO_TIMEVAL(&tv, rqt); |
---|
505 | for (;;) { |
---|
506 | error = tsleep(&nanowait, PWAIT | PCATCH, "nanslp", |
---|
507 | tvtohz(&tv)); |
---|
508 | getnanouptime(&ts2); |
---|
509 | if (error != EWOULDBLOCK) { |
---|
510 | if (error == ERESTART) |
---|
511 | error = EINTR; |
---|
512 | if (rmt != NULL) { |
---|
513 | timespecsub(&ts, &ts2); |
---|
514 | if (ts.tv_sec < 0) |
---|
515 | timespecclear(&ts); |
---|
516 | *rmt = ts; |
---|
517 | } |
---|
518 | return (error); |
---|
519 | } |
---|
520 | if (timespeccmp(&ts2, &ts, >=)) |
---|
521 | return (0); |
---|
522 | ts3 = ts; |
---|
523 | timespecsub(&ts3, &ts2); |
---|
524 | TIMESPEC_TO_TIMEVAL(&tv, &ts3); |
---|
525 | } |
---|
526 | } |
---|
527 | |
---|
528 | #ifndef _SYS_SYSPROTO_H_ |
---|
529 | struct nanosleep_args { |
---|
530 | struct timespec *rqtp; |
---|
531 | struct timespec *rmtp; |
---|
532 | }; |
---|
533 | #endif |
---|
534 | /* ARGSUSED */ |
---|
535 | int |
---|
536 | sys_nanosleep(struct thread *td, struct nanosleep_args *uap) |
---|
537 | { |
---|
538 | struct timespec rmt, rqt; |
---|
539 | int error; |
---|
540 | |
---|
541 | error = copyin(uap->rqtp, &rqt, sizeof(rqt)); |
---|
542 | if (error) |
---|
543 | return (error); |
---|
544 | |
---|
545 | if (uap->rmtp && |
---|
546 | !useracc((caddr_t)uap->rmtp, sizeof(rmt), VM_PROT_WRITE)) |
---|
547 | return (EFAULT); |
---|
548 | error = kern_nanosleep(td, &rqt, &rmt); |
---|
549 | if (error && uap->rmtp) { |
---|
550 | int error2; |
---|
551 | |
---|
552 | error2 = copyout(&rmt, uap->rmtp, sizeof(rmt)); |
---|
553 | if (error2) |
---|
554 | error = error2; |
---|
555 | } |
---|
556 | return (error); |
---|
557 | } |
---|
558 | |
---|
559 | #ifndef _SYS_SYSPROTO_H_ |
---|
560 | struct gettimeofday_args { |
---|
561 | struct timeval *tp; |
---|
562 | struct timezone *tzp; |
---|
563 | }; |
---|
564 | #endif |
---|
565 | /* ARGSUSED */ |
---|
566 | int |
---|
567 | sys_gettimeofday(struct thread *td, struct gettimeofday_args *uap) |
---|
568 | { |
---|
569 | struct timeval atv; |
---|
570 | struct timezone rtz; |
---|
571 | int error = 0; |
---|
572 | |
---|
573 | if (uap->tp) { |
---|
574 | microtime(&atv); |
---|
575 | error = copyout(&atv, uap->tp, sizeof (atv)); |
---|
576 | } |
---|
577 | if (error == 0 && uap->tzp != NULL) { |
---|
578 | rtz.tz_minuteswest = tz_minuteswest; |
---|
579 | rtz.tz_dsttime = tz_dsttime; |
---|
580 | error = copyout(&rtz, uap->tzp, sizeof (rtz)); |
---|
581 | } |
---|
582 | return (error); |
---|
583 | } |
---|
584 | |
---|
585 | #ifndef _SYS_SYSPROTO_H_ |
---|
586 | struct settimeofday_args { |
---|
587 | struct timeval *tv; |
---|
588 | struct timezone *tzp; |
---|
589 | }; |
---|
590 | #endif |
---|
591 | /* ARGSUSED */ |
---|
592 | int |
---|
593 | sys_settimeofday(struct thread *td, struct settimeofday_args *uap) |
---|
594 | { |
---|
595 | struct timeval atv, *tvp; |
---|
596 | struct timezone atz, *tzp; |
---|
597 | int error; |
---|
598 | |
---|
599 | if (uap->tv) { |
---|
600 | error = copyin(uap->tv, &atv, sizeof(atv)); |
---|
601 | if (error) |
---|
602 | return (error); |
---|
603 | tvp = &atv; |
---|
604 | } else |
---|
605 | tvp = NULL; |
---|
606 | if (uap->tzp) { |
---|
607 | error = copyin(uap->tzp, &atz, sizeof(atz)); |
---|
608 | if (error) |
---|
609 | return (error); |
---|
610 | tzp = &atz; |
---|
611 | } else |
---|
612 | tzp = NULL; |
---|
613 | return (kern_settimeofday(td, tvp, tzp)); |
---|
614 | } |
---|
615 | |
---|
616 | int |
---|
617 | kern_settimeofday(struct thread *td, struct timeval *tv, struct timezone *tzp) |
---|
618 | { |
---|
619 | int error; |
---|
620 | |
---|
621 | error = priv_check(td, PRIV_SETTIMEOFDAY); |
---|
622 | if (error) |
---|
623 | return (error); |
---|
624 | /* Verify all parameters before changing time. */ |
---|
625 | if (tv) { |
---|
626 | if (tv->tv_usec < 0 || tv->tv_usec >= 1000000) |
---|
627 | return (EINVAL); |
---|
628 | error = settime(td, tv); |
---|
629 | } |
---|
630 | if (tzp && error == 0) { |
---|
631 | tz_minuteswest = tzp->tz_minuteswest; |
---|
632 | tz_dsttime = tzp->tz_dsttime; |
---|
633 | } |
---|
634 | return (error); |
---|
635 | } |
---|
636 | |
---|
637 | /* |
---|
638 | * Get value of an interval timer. The process virtual and profiling virtual |
---|
639 | * time timers are kept in the p_stats area, since they can be swapped out. |
---|
640 | * These are kept internally in the way they are specified externally: in |
---|
641 | * time until they expire. |
---|
642 | * |
---|
643 | * The real time interval timer is kept in the process table slot for the |
---|
644 | * process, and its value (it_value) is kept as an absolute time rather than |
---|
645 | * as a delta, so that it is easy to keep periodic real-time signals from |
---|
646 | * drifting. |
---|
647 | * |
---|
648 | * Virtual time timers are processed in the hardclock() routine of |
---|
649 | * kern_clock.c. The real time timer is processed by a timeout routine, |
---|
650 | * called from the softclock() routine. Since a callout may be delayed in |
---|
651 | * real time due to interrupt processing in the system, it is possible for |
---|
652 | * the real time timeout routine (realitexpire, given below), to be delayed |
---|
653 | * in real time past when it is supposed to occur. It does not suffice, |
---|
654 | * therefore, to reload the real timer .it_value from the real time timers |
---|
655 | * .it_interval. Rather, we compute the next time in absolute time the timer |
---|
656 | * should go off. |
---|
657 | */ |
---|
658 | #ifndef _SYS_SYSPROTO_H_ |
---|
659 | struct getitimer_args { |
---|
660 | u_int which; |
---|
661 | struct itimerval *itv; |
---|
662 | }; |
---|
663 | #endif |
---|
664 | int |
---|
665 | sys_getitimer(struct thread *td, struct getitimer_args *uap) |
---|
666 | { |
---|
667 | struct itimerval aitv; |
---|
668 | int error; |
---|
669 | |
---|
670 | error = kern_getitimer(td, uap->which, &aitv); |
---|
671 | if (error != 0) |
---|
672 | return (error); |
---|
673 | return (copyout(&aitv, uap->itv, sizeof (struct itimerval))); |
---|
674 | } |
---|
675 | |
---|
676 | int |
---|
677 | kern_getitimer(struct thread *td, u_int which, struct itimerval *aitv) |
---|
678 | { |
---|
679 | struct proc *p = td->td_proc; |
---|
680 | struct timeval ctv; |
---|
681 | |
---|
682 | if (which > ITIMER_PROF) |
---|
683 | return (EINVAL); |
---|
684 | |
---|
685 | if (which == ITIMER_REAL) { |
---|
686 | /* |
---|
687 | * Convert from absolute to relative time in .it_value |
---|
688 | * part of real time timer. If time for real time timer |
---|
689 | * has passed return 0, else return difference between |
---|
690 | * current time and time for the timer to go off. |
---|
691 | */ |
---|
692 | PROC_LOCK(p); |
---|
693 | *aitv = p->p_realtimer; |
---|
694 | PROC_UNLOCK(p); |
---|
695 | if (timevalisset(&aitv->it_value)) { |
---|
696 | getmicrouptime(&ctv); |
---|
697 | if (timevalcmp(&aitv->it_value, &ctv, <)) |
---|
698 | timevalclear(&aitv->it_value); |
---|
699 | else |
---|
700 | timevalsub(&aitv->it_value, &ctv); |
---|
701 | } |
---|
702 | } else { |
---|
703 | PROC_SLOCK(p); |
---|
704 | *aitv = p->p_stats->p_timer[which]; |
---|
705 | PROC_SUNLOCK(p); |
---|
706 | } |
---|
707 | return (0); |
---|
708 | } |
---|
709 | |
---|
710 | #ifndef _SYS_SYSPROTO_H_ |
---|
711 | struct setitimer_args { |
---|
712 | u_int which; |
---|
713 | struct itimerval *itv, *oitv; |
---|
714 | }; |
---|
715 | #endif |
---|
716 | int |
---|
717 | sys_setitimer(struct thread *td, struct setitimer_args *uap) |
---|
718 | { |
---|
719 | struct itimerval aitv, oitv; |
---|
720 | int error; |
---|
721 | |
---|
722 | if (uap->itv == NULL) { |
---|
723 | uap->itv = uap->oitv; |
---|
724 | return (sys_getitimer(td, (struct getitimer_args *)uap)); |
---|
725 | } |
---|
726 | |
---|
727 | if ((error = copyin(uap->itv, &aitv, sizeof(struct itimerval)))) |
---|
728 | return (error); |
---|
729 | error = kern_setitimer(td, uap->which, &aitv, &oitv); |
---|
730 | if (error != 0 || uap->oitv == NULL) |
---|
731 | return (error); |
---|
732 | return (copyout(&oitv, uap->oitv, sizeof(struct itimerval))); |
---|
733 | } |
---|
734 | |
---|
735 | int |
---|
736 | kern_setitimer(struct thread *td, u_int which, struct itimerval *aitv, |
---|
737 | struct itimerval *oitv) |
---|
738 | { |
---|
739 | struct proc *p = td->td_proc; |
---|
740 | struct timeval ctv; |
---|
741 | |
---|
742 | if (aitv == NULL) |
---|
743 | return (kern_getitimer(td, which, oitv)); |
---|
744 | |
---|
745 | if (which > ITIMER_PROF) |
---|
746 | return (EINVAL); |
---|
747 | if (itimerfix(&aitv->it_value)) |
---|
748 | return (EINVAL); |
---|
749 | if (!timevalisset(&aitv->it_value)) |
---|
750 | timevalclear(&aitv->it_interval); |
---|
751 | else if (itimerfix(&aitv->it_interval)) |
---|
752 | return (EINVAL); |
---|
753 | |
---|
754 | if (which == ITIMER_REAL) { |
---|
755 | PROC_LOCK(p); |
---|
756 | if (timevalisset(&p->p_realtimer.it_value)) |
---|
757 | callout_stop(&p->p_itcallout); |
---|
758 | getmicrouptime(&ctv); |
---|
759 | if (timevalisset(&aitv->it_value)) { |
---|
760 | callout_reset(&p->p_itcallout, tvtohz(&aitv->it_value), |
---|
761 | realitexpire, p); |
---|
762 | timevaladd(&aitv->it_value, &ctv); |
---|
763 | } |
---|
764 | *oitv = p->p_realtimer; |
---|
765 | p->p_realtimer = *aitv; |
---|
766 | PROC_UNLOCK(p); |
---|
767 | if (timevalisset(&oitv->it_value)) { |
---|
768 | if (timevalcmp(&oitv->it_value, &ctv, <)) |
---|
769 | timevalclear(&oitv->it_value); |
---|
770 | else |
---|
771 | timevalsub(&oitv->it_value, &ctv); |
---|
772 | } |
---|
773 | } else { |
---|
774 | PROC_SLOCK(p); |
---|
775 | *oitv = p->p_stats->p_timer[which]; |
---|
776 | p->p_stats->p_timer[which] = *aitv; |
---|
777 | PROC_SUNLOCK(p); |
---|
778 | } |
---|
779 | return (0); |
---|
780 | } |
---|
781 | |
---|
782 | /* |
---|
783 | * Real interval timer expired: |
---|
784 | * send process whose timer expired an alarm signal. |
---|
785 | * If time is not set up to reload, then just return. |
---|
786 | * Else compute next time timer should go off which is > current time. |
---|
787 | * This is where delay in processing this timeout causes multiple |
---|
788 | * SIGALRM calls to be compressed into one. |
---|
789 | * tvtohz() always adds 1 to allow for the time until the next clock |
---|
790 | * interrupt being strictly less than 1 clock tick, but we don't want |
---|
791 | * that here since we want to appear to be in sync with the clock |
---|
792 | * interrupt even when we're delayed. |
---|
793 | */ |
---|
794 | void |
---|
795 | realitexpire(void *arg) |
---|
796 | { |
---|
797 | struct proc *p; |
---|
798 | struct timeval ctv, ntv; |
---|
799 | |
---|
800 | p = (struct proc *)arg; |
---|
801 | kern_psignal(p, SIGALRM); |
---|
802 | if (!timevalisset(&p->p_realtimer.it_interval)) { |
---|
803 | timevalclear(&p->p_realtimer.it_value); |
---|
804 | if (p->p_flag & P_WEXIT) |
---|
805 | wakeup(&p->p_itcallout); |
---|
806 | return; |
---|
807 | } |
---|
808 | for (;;) { |
---|
809 | timevaladd(&p->p_realtimer.it_value, |
---|
810 | &p->p_realtimer.it_interval); |
---|
811 | getmicrouptime(&ctv); |
---|
812 | if (timevalcmp(&p->p_realtimer.it_value, &ctv, >)) { |
---|
813 | ntv = p->p_realtimer.it_value; |
---|
814 | timevalsub(&ntv, &ctv); |
---|
815 | callout_reset(&p->p_itcallout, tvtohz(&ntv) - 1, |
---|
816 | realitexpire, p); |
---|
817 | return; |
---|
818 | } |
---|
819 | } |
---|
820 | /*NOTREACHED*/ |
---|
821 | } |
---|
822 | #endif /* __rtems__ */ |
---|
823 | |
---|
824 | /* |
---|
825 | * Check that a proposed value to load into the .it_value or |
---|
826 | * .it_interval part of an interval timer is acceptable, and |
---|
827 | * fix it to have at least minimal value (i.e. if it is less |
---|
828 | * than the resolution of the clock, round it up.) |
---|
829 | */ |
---|
830 | int |
---|
831 | itimerfix(struct timeval *tv) |
---|
832 | { |
---|
833 | |
---|
834 | if (tv->tv_sec < 0 || tv->tv_usec < 0 || tv->tv_usec >= 1000000) |
---|
835 | return (EINVAL); |
---|
836 | if (tv->tv_sec == 0 && tv->tv_usec != 0 && tv->tv_usec < tick) |
---|
837 | tv->tv_usec = tick; |
---|
838 | return (0); |
---|
839 | } |
---|
840 | |
---|
841 | #ifndef __rtems__ |
---|
842 | /* |
---|
843 | * Decrement an interval timer by a specified number |
---|
844 | * of microseconds, which must be less than a second, |
---|
845 | * i.e. < 1000000. If the timer expires, then reload |
---|
846 | * it. In this case, carry over (usec - old value) to |
---|
847 | * reduce the value reloaded into the timer so that |
---|
848 | * the timer does not drift. This routine assumes |
---|
849 | * that it is called in a context where the timers |
---|
850 | * on which it is operating cannot change in value. |
---|
851 | */ |
---|
852 | int |
---|
853 | itimerdecr(struct itimerval *itp, int usec) |
---|
854 | { |
---|
855 | |
---|
856 | if (itp->it_value.tv_usec < usec) { |
---|
857 | if (itp->it_value.tv_sec == 0) { |
---|
858 | /* expired, and already in next interval */ |
---|
859 | usec -= itp->it_value.tv_usec; |
---|
860 | goto expire; |
---|
861 | } |
---|
862 | itp->it_value.tv_usec += 1000000; |
---|
863 | itp->it_value.tv_sec--; |
---|
864 | } |
---|
865 | itp->it_value.tv_usec -= usec; |
---|
866 | usec = 0; |
---|
867 | if (timevalisset(&itp->it_value)) |
---|
868 | return (1); |
---|
869 | /* expired, exactly at end of interval */ |
---|
870 | expire: |
---|
871 | if (timevalisset(&itp->it_interval)) { |
---|
872 | itp->it_value = itp->it_interval; |
---|
873 | itp->it_value.tv_usec -= usec; |
---|
874 | if (itp->it_value.tv_usec < 0) { |
---|
875 | itp->it_value.tv_usec += 1000000; |
---|
876 | itp->it_value.tv_sec--; |
---|
877 | } |
---|
878 | } else |
---|
879 | itp->it_value.tv_usec = 0; /* sec is already 0 */ |
---|
880 | return (0); |
---|
881 | } |
---|
882 | #endif /* __rtems__ */ |
---|
883 | |
---|
884 | /* |
---|
885 | * Add and subtract routines for timevals. |
---|
886 | * N.B.: subtract routine doesn't deal with |
---|
887 | * results which are before the beginning, |
---|
888 | * it just gets very confused in this case. |
---|
889 | * Caveat emptor. |
---|
890 | */ |
---|
891 | void |
---|
892 | timevaladd(struct timeval *t1, const struct timeval *t2) |
---|
893 | { |
---|
894 | |
---|
895 | t1->tv_sec += t2->tv_sec; |
---|
896 | t1->tv_usec += t2->tv_usec; |
---|
897 | timevalfix(t1); |
---|
898 | } |
---|
899 | |
---|
900 | void |
---|
901 | timevalsub(struct timeval *t1, const struct timeval *t2) |
---|
902 | { |
---|
903 | |
---|
904 | t1->tv_sec -= t2->tv_sec; |
---|
905 | t1->tv_usec -= t2->tv_usec; |
---|
906 | timevalfix(t1); |
---|
907 | } |
---|
908 | |
---|
909 | static void |
---|
910 | timevalfix(struct timeval *t1) |
---|
911 | { |
---|
912 | |
---|
913 | if (t1->tv_usec < 0) { |
---|
914 | t1->tv_sec--; |
---|
915 | t1->tv_usec += 1000000; |
---|
916 | } |
---|
917 | if (t1->tv_usec >= 1000000) { |
---|
918 | t1->tv_sec++; |
---|
919 | t1->tv_usec -= 1000000; |
---|
920 | } |
---|
921 | } |
---|
922 | |
---|
923 | /* |
---|
924 | * ratecheck(): simple time-based rate-limit checking. |
---|
925 | */ |
---|
926 | int |
---|
927 | ratecheck(struct timeval *lasttime, const struct timeval *mininterval) |
---|
928 | { |
---|
929 | struct timeval tv, delta; |
---|
930 | int rv = 0; |
---|
931 | |
---|
932 | getmicrouptime(&tv); /* NB: 10ms precision */ |
---|
933 | delta = tv; |
---|
934 | timevalsub(&delta, lasttime); |
---|
935 | |
---|
936 | /* |
---|
937 | * check for 0,0 is so that the message will be seen at least once, |
---|
938 | * even if interval is huge. |
---|
939 | */ |
---|
940 | if (timevalcmp(&delta, mininterval, >=) || |
---|
941 | (lasttime->tv_sec == 0 && lasttime->tv_usec == 0)) { |
---|
942 | *lasttime = tv; |
---|
943 | rv = 1; |
---|
944 | } |
---|
945 | |
---|
946 | return (rv); |
---|
947 | } |
---|
948 | |
---|
949 | /* |
---|
950 | * ppsratecheck(): packets (or events) per second limitation. |
---|
951 | * |
---|
952 | * Return 0 if the limit is to be enforced (e.g. the caller |
---|
953 | * should drop a packet because of the rate limitation). |
---|
954 | * |
---|
955 | * maxpps of 0 always causes zero to be returned. maxpps of -1 |
---|
956 | * always causes 1 to be returned; this effectively defeats rate |
---|
957 | * limiting. |
---|
958 | * |
---|
959 | * Note that we maintain the struct timeval for compatibility |
---|
960 | * with other bsd systems. We reuse the storage and just monitor |
---|
961 | * clock ticks for minimal overhead. |
---|
962 | */ |
---|
963 | int |
---|
964 | ppsratecheck(struct timeval *lasttime, int *curpps, int maxpps) |
---|
965 | { |
---|
966 | int now; |
---|
967 | |
---|
968 | /* |
---|
969 | * Reset the last time and counter if this is the first call |
---|
970 | * or more than a second has passed since the last update of |
---|
971 | * lasttime. |
---|
972 | */ |
---|
973 | now = ticks; |
---|
974 | if (lasttime->tv_sec == 0 || (u_int)(now - lasttime->tv_sec) >= hz) { |
---|
975 | lasttime->tv_sec = now; |
---|
976 | *curpps = 1; |
---|
977 | return (maxpps != 0); |
---|
978 | } else { |
---|
979 | (*curpps)++; /* NB: ignore potential overflow */ |
---|
980 | return (maxpps < 0 || *curpps < maxpps); |
---|
981 | } |
---|
982 | } |
---|
983 | |
---|
984 | #ifndef __rtems__ |
---|
985 | static void |
---|
986 | itimer_start(void) |
---|
987 | { |
---|
988 | struct kclock rt_clock = { |
---|
989 | .timer_create = realtimer_create, |
---|
990 | .timer_delete = realtimer_delete, |
---|
991 | .timer_settime = realtimer_settime, |
---|
992 | .timer_gettime = realtimer_gettime, |
---|
993 | .event_hook = NULL |
---|
994 | }; |
---|
995 | |
---|
996 | itimer_zone = uma_zcreate("itimer", sizeof(struct itimer), |
---|
997 | NULL, NULL, itimer_init, itimer_fini, UMA_ALIGN_PTR, 0); |
---|
998 | register_posix_clock(CLOCK_REALTIME, &rt_clock); |
---|
999 | register_posix_clock(CLOCK_MONOTONIC, &rt_clock); |
---|
1000 | p31b_setcfg(CTL_P1003_1B_TIMERS, 200112L); |
---|
1001 | p31b_setcfg(CTL_P1003_1B_DELAYTIMER_MAX, INT_MAX); |
---|
1002 | p31b_setcfg(CTL_P1003_1B_TIMER_MAX, TIMER_MAX); |
---|
1003 | EVENTHANDLER_REGISTER(process_exit, itimers_event_hook_exit, |
---|
1004 | (void *)ITIMER_EV_EXIT, EVENTHANDLER_PRI_ANY); |
---|
1005 | EVENTHANDLER_REGISTER(process_exec, itimers_event_hook_exec, |
---|
1006 | (void *)ITIMER_EV_EXEC, EVENTHANDLER_PRI_ANY); |
---|
1007 | } |
---|
1008 | |
---|
1009 | int |
---|
1010 | register_posix_clock(int clockid, struct kclock *clk) |
---|
1011 | { |
---|
1012 | if ((unsigned)clockid >= MAX_CLOCKS) { |
---|
1013 | printf("%s: invalid clockid\n", __func__); |
---|
1014 | return (0); |
---|
1015 | } |
---|
1016 | posix_clocks[clockid] = *clk; |
---|
1017 | return (1); |
---|
1018 | } |
---|
1019 | |
---|
1020 | static int |
---|
1021 | itimer_init(void *mem, int size, int flags) |
---|
1022 | { |
---|
1023 | struct itimer *it; |
---|
1024 | |
---|
1025 | it = (struct itimer *)mem; |
---|
1026 | mtx_init(&it->it_mtx, "itimer lock", NULL, MTX_DEF); |
---|
1027 | return (0); |
---|
1028 | } |
---|
1029 | |
---|
1030 | static void |
---|
1031 | itimer_fini(void *mem, int size) |
---|
1032 | { |
---|
1033 | struct itimer *it; |
---|
1034 | |
---|
1035 | it = (struct itimer *)mem; |
---|
1036 | mtx_destroy(&it->it_mtx); |
---|
1037 | } |
---|
1038 | |
---|
1039 | static void |
---|
1040 | itimer_enter(struct itimer *it) |
---|
1041 | { |
---|
1042 | |
---|
1043 | mtx_assert(&it->it_mtx, MA_OWNED); |
---|
1044 | it->it_usecount++; |
---|
1045 | } |
---|
1046 | |
---|
1047 | static void |
---|
1048 | itimer_leave(struct itimer *it) |
---|
1049 | { |
---|
1050 | |
---|
1051 | mtx_assert(&it->it_mtx, MA_OWNED); |
---|
1052 | KASSERT(it->it_usecount > 0, ("invalid it_usecount")); |
---|
1053 | |
---|
1054 | if (--it->it_usecount == 0 && (it->it_flags & ITF_WANTED) != 0) |
---|
1055 | wakeup(it); |
---|
1056 | } |
---|
1057 | |
---|
1058 | #ifndef _SYS_SYSPROTO_H_ |
---|
1059 | struct ktimer_create_args { |
---|
1060 | clockid_t clock_id; |
---|
1061 | struct sigevent * evp; |
---|
1062 | int * timerid; |
---|
1063 | }; |
---|
1064 | #endif |
---|
1065 | int |
---|
1066 | sys_ktimer_create(struct thread *td, struct ktimer_create_args *uap) |
---|
1067 | { |
---|
1068 | struct sigevent *evp, ev; |
---|
1069 | int id; |
---|
1070 | int error; |
---|
1071 | |
---|
1072 | if (uap->evp == NULL) { |
---|
1073 | evp = NULL; |
---|
1074 | } else { |
---|
1075 | error = copyin(uap->evp, &ev, sizeof(ev)); |
---|
1076 | if (error != 0) |
---|
1077 | return (error); |
---|
1078 | evp = &ev; |
---|
1079 | } |
---|
1080 | error = kern_ktimer_create(td, uap->clock_id, evp, &id, -1); |
---|
1081 | if (error == 0) { |
---|
1082 | error = copyout(&id, uap->timerid, sizeof(int)); |
---|
1083 | if (error != 0) |
---|
1084 | kern_ktimer_delete(td, id); |
---|
1085 | } |
---|
1086 | return (error); |
---|
1087 | } |
---|
1088 | |
---|
1089 | int |
---|
1090 | kern_ktimer_create(struct thread *td, clockid_t clock_id, struct sigevent *evp, |
---|
1091 | int *timerid, int preset_id) |
---|
1092 | { |
---|
1093 | struct proc *p = td->td_proc; |
---|
1094 | struct itimer *it; |
---|
1095 | int id; |
---|
1096 | int error; |
---|
1097 | |
---|
1098 | if (clock_id < 0 || clock_id >= MAX_CLOCKS) |
---|
1099 | return (EINVAL); |
---|
1100 | |
---|
1101 | if (posix_clocks[clock_id].timer_create == NULL) |
---|
1102 | return (EINVAL); |
---|
1103 | |
---|
1104 | if (evp != NULL) { |
---|
1105 | if (evp->sigev_notify != SIGEV_NONE && |
---|
1106 | evp->sigev_notify != SIGEV_SIGNAL && |
---|
1107 | evp->sigev_notify != SIGEV_THREAD_ID) |
---|
1108 | return (EINVAL); |
---|
1109 | if ((evp->sigev_notify == SIGEV_SIGNAL || |
---|
1110 | evp->sigev_notify == SIGEV_THREAD_ID) && |
---|
1111 | !_SIG_VALID(evp->sigev_signo)) |
---|
1112 | return (EINVAL); |
---|
1113 | } |
---|
1114 | |
---|
1115 | if (p->p_itimers == NULL) |
---|
1116 | itimers_alloc(p); |
---|
1117 | |
---|
1118 | it = uma_zalloc(itimer_zone, M_WAITOK); |
---|
1119 | it->it_flags = 0; |
---|
1120 | it->it_usecount = 0; |
---|
1121 | it->it_active = 0; |
---|
1122 | timespecclear(&it->it_time.it_value); |
---|
1123 | timespecclear(&it->it_time.it_interval); |
---|
1124 | it->it_overrun = 0; |
---|
1125 | it->it_overrun_last = 0; |
---|
1126 | it->it_clockid = clock_id; |
---|
1127 | it->it_timerid = -1; |
---|
1128 | it->it_proc = p; |
---|
1129 | ksiginfo_init(&it->it_ksi); |
---|
1130 | it->it_ksi.ksi_flags |= KSI_INS | KSI_EXT; |
---|
1131 | error = CLOCK_CALL(clock_id, timer_create, (it)); |
---|
1132 | if (error != 0) |
---|
1133 | goto out; |
---|
1134 | |
---|
1135 | PROC_LOCK(p); |
---|
1136 | if (preset_id != -1) { |
---|
1137 | KASSERT(preset_id >= 0 && preset_id < 3, ("invalid preset_id")); |
---|
1138 | id = preset_id; |
---|
1139 | if (p->p_itimers->its_timers[id] != NULL) { |
---|
1140 | PROC_UNLOCK(p); |
---|
1141 | error = 0; |
---|
1142 | goto out; |
---|
1143 | } |
---|
1144 | } else { |
---|
1145 | /* |
---|
1146 | * Find a free timer slot, skipping those reserved |
---|
1147 | * for setitimer(). |
---|
1148 | */ |
---|
1149 | for (id = 3; id < TIMER_MAX; id++) |
---|
1150 | if (p->p_itimers->its_timers[id] == NULL) |
---|
1151 | break; |
---|
1152 | if (id == TIMER_MAX) { |
---|
1153 | PROC_UNLOCK(p); |
---|
1154 | error = EAGAIN; |
---|
1155 | goto out; |
---|
1156 | } |
---|
1157 | } |
---|
1158 | it->it_timerid = id; |
---|
1159 | p->p_itimers->its_timers[id] = it; |
---|
1160 | if (evp != NULL) |
---|
1161 | it->it_sigev = *evp; |
---|
1162 | else { |
---|
1163 | it->it_sigev.sigev_notify = SIGEV_SIGNAL; |
---|
1164 | switch (clock_id) { |
---|
1165 | default: |
---|
1166 | case CLOCK_REALTIME: |
---|
1167 | it->it_sigev.sigev_signo = SIGALRM; |
---|
1168 | break; |
---|
1169 | case CLOCK_VIRTUAL: |
---|
1170 | it->it_sigev.sigev_signo = SIGVTALRM; |
---|
1171 | break; |
---|
1172 | case CLOCK_PROF: |
---|
1173 | it->it_sigev.sigev_signo = SIGPROF; |
---|
1174 | break; |
---|
1175 | } |
---|
1176 | it->it_sigev.sigev_value.sival_int = id; |
---|
1177 | } |
---|
1178 | |
---|
1179 | if (it->it_sigev.sigev_notify == SIGEV_SIGNAL || |
---|
1180 | it->it_sigev.sigev_notify == SIGEV_THREAD_ID) { |
---|
1181 | it->it_ksi.ksi_signo = it->it_sigev.sigev_signo; |
---|
1182 | it->it_ksi.ksi_code = SI_TIMER; |
---|
1183 | it->it_ksi.ksi_value = it->it_sigev.sigev_value; |
---|
1184 | it->it_ksi.ksi_timerid = id; |
---|
1185 | } |
---|
1186 | PROC_UNLOCK(p); |
---|
1187 | *timerid = id; |
---|
1188 | return (0); |
---|
1189 | |
---|
1190 | out: |
---|
1191 | ITIMER_LOCK(it); |
---|
1192 | CLOCK_CALL(it->it_clockid, timer_delete, (it)); |
---|
1193 | ITIMER_UNLOCK(it); |
---|
1194 | uma_zfree(itimer_zone, it); |
---|
1195 | return (error); |
---|
1196 | } |
---|
1197 | |
---|
1198 | #ifndef _SYS_SYSPROTO_H_ |
---|
1199 | struct ktimer_delete_args { |
---|
1200 | int timerid; |
---|
1201 | }; |
---|
1202 | #endif |
---|
1203 | int |
---|
1204 | sys_ktimer_delete(struct thread *td, struct ktimer_delete_args *uap) |
---|
1205 | { |
---|
1206 | |
---|
1207 | return (kern_ktimer_delete(td, uap->timerid)); |
---|
1208 | } |
---|
1209 | |
---|
1210 | static struct itimer * |
---|
1211 | itimer_find(struct proc *p, int timerid) |
---|
1212 | { |
---|
1213 | struct itimer *it; |
---|
1214 | |
---|
1215 | PROC_LOCK_ASSERT(p, MA_OWNED); |
---|
1216 | if ((p->p_itimers == NULL) || |
---|
1217 | (timerid < 0) || (timerid >= TIMER_MAX) || |
---|
1218 | (it = p->p_itimers->its_timers[timerid]) == NULL) { |
---|
1219 | return (NULL); |
---|
1220 | } |
---|
1221 | ITIMER_LOCK(it); |
---|
1222 | if ((it->it_flags & ITF_DELETING) != 0) { |
---|
1223 | ITIMER_UNLOCK(it); |
---|
1224 | it = NULL; |
---|
1225 | } |
---|
1226 | return (it); |
---|
1227 | } |
---|
1228 | |
---|
1229 | int |
---|
1230 | kern_ktimer_delete(struct thread *td, int timerid) |
---|
1231 | { |
---|
1232 | struct proc *p = td->td_proc; |
---|
1233 | struct itimer *it; |
---|
1234 | |
---|
1235 | PROC_LOCK(p); |
---|
1236 | it = itimer_find(p, timerid); |
---|
1237 | if (it == NULL) { |
---|
1238 | PROC_UNLOCK(p); |
---|
1239 | return (EINVAL); |
---|
1240 | } |
---|
1241 | PROC_UNLOCK(p); |
---|
1242 | |
---|
1243 | it->it_flags |= ITF_DELETING; |
---|
1244 | while (it->it_usecount > 0) { |
---|
1245 | it->it_flags |= ITF_WANTED; |
---|
1246 | msleep(it, &it->it_mtx, PPAUSE, "itimer", 0); |
---|
1247 | } |
---|
1248 | it->it_flags &= ~ITF_WANTED; |
---|
1249 | CLOCK_CALL(it->it_clockid, timer_delete, (it)); |
---|
1250 | ITIMER_UNLOCK(it); |
---|
1251 | |
---|
1252 | PROC_LOCK(p); |
---|
1253 | if (KSI_ONQ(&it->it_ksi)) |
---|
1254 | sigqueue_take(&it->it_ksi); |
---|
1255 | p->p_itimers->its_timers[timerid] = NULL; |
---|
1256 | PROC_UNLOCK(p); |
---|
1257 | uma_zfree(itimer_zone, it); |
---|
1258 | return (0); |
---|
1259 | } |
---|
1260 | |
---|
1261 | #ifndef _SYS_SYSPROTO_H_ |
---|
1262 | struct ktimer_settime_args { |
---|
1263 | int timerid; |
---|
1264 | int flags; |
---|
1265 | const struct itimerspec * value; |
---|
1266 | struct itimerspec * ovalue; |
---|
1267 | }; |
---|
1268 | #endif |
---|
1269 | int |
---|
1270 | sys_ktimer_settime(struct thread *td, struct ktimer_settime_args *uap) |
---|
1271 | { |
---|
1272 | struct itimerspec val, oval, *ovalp; |
---|
1273 | int error; |
---|
1274 | |
---|
1275 | error = copyin(uap->value, &val, sizeof(val)); |
---|
1276 | if (error != 0) |
---|
1277 | return (error); |
---|
1278 | ovalp = uap->ovalue != NULL ? &oval : NULL; |
---|
1279 | error = kern_ktimer_settime(td, uap->timerid, uap->flags, &val, ovalp); |
---|
1280 | if (error == 0 && uap->ovalue != NULL) |
---|
1281 | error = copyout(ovalp, uap->ovalue, sizeof(*ovalp)); |
---|
1282 | return (error); |
---|
1283 | } |
---|
1284 | |
---|
1285 | int |
---|
1286 | kern_ktimer_settime(struct thread *td, int timer_id, int flags, |
---|
1287 | struct itimerspec *val, struct itimerspec *oval) |
---|
1288 | { |
---|
1289 | struct proc *p; |
---|
1290 | struct itimer *it; |
---|
1291 | int error; |
---|
1292 | |
---|
1293 | p = td->td_proc; |
---|
1294 | PROC_LOCK(p); |
---|
1295 | if (timer_id < 3 || (it = itimer_find(p, timer_id)) == NULL) { |
---|
1296 | PROC_UNLOCK(p); |
---|
1297 | error = EINVAL; |
---|
1298 | } else { |
---|
1299 | PROC_UNLOCK(p); |
---|
1300 | itimer_enter(it); |
---|
1301 | error = CLOCK_CALL(it->it_clockid, timer_settime, (it, |
---|
1302 | flags, val, oval)); |
---|
1303 | itimer_leave(it); |
---|
1304 | ITIMER_UNLOCK(it); |
---|
1305 | } |
---|
1306 | return (error); |
---|
1307 | } |
---|
1308 | |
---|
1309 | #ifndef _SYS_SYSPROTO_H_ |
---|
1310 | struct ktimer_gettime_args { |
---|
1311 | int timerid; |
---|
1312 | struct itimerspec * value; |
---|
1313 | }; |
---|
1314 | #endif |
---|
1315 | int |
---|
1316 | sys_ktimer_gettime(struct thread *td, struct ktimer_gettime_args *uap) |
---|
1317 | { |
---|
1318 | struct itimerspec val; |
---|
1319 | int error; |
---|
1320 | |
---|
1321 | error = kern_ktimer_gettime(td, uap->timerid, &val); |
---|
1322 | if (error == 0) |
---|
1323 | error = copyout(&val, uap->value, sizeof(val)); |
---|
1324 | return (error); |
---|
1325 | } |
---|
1326 | |
---|
1327 | int |
---|
1328 | kern_ktimer_gettime(struct thread *td, int timer_id, struct itimerspec *val) |
---|
1329 | { |
---|
1330 | struct proc *p; |
---|
1331 | struct itimer *it; |
---|
1332 | int error; |
---|
1333 | |
---|
1334 | p = td->td_proc; |
---|
1335 | PROC_LOCK(p); |
---|
1336 | if (timer_id < 3 || (it = itimer_find(p, timer_id)) == NULL) { |
---|
1337 | PROC_UNLOCK(p); |
---|
1338 | error = EINVAL; |
---|
1339 | } else { |
---|
1340 | PROC_UNLOCK(p); |
---|
1341 | itimer_enter(it); |
---|
1342 | error = CLOCK_CALL(it->it_clockid, timer_gettime, (it, val)); |
---|
1343 | itimer_leave(it); |
---|
1344 | ITIMER_UNLOCK(it); |
---|
1345 | } |
---|
1346 | return (error); |
---|
1347 | } |
---|
1348 | |
---|
1349 | #ifndef _SYS_SYSPROTO_H_ |
---|
1350 | struct timer_getoverrun_args { |
---|
1351 | int timerid; |
---|
1352 | }; |
---|
1353 | #endif |
---|
1354 | int |
---|
1355 | sys_ktimer_getoverrun(struct thread *td, struct ktimer_getoverrun_args *uap) |
---|
1356 | { |
---|
1357 | |
---|
1358 | return (kern_ktimer_getoverrun(td, uap->timerid)); |
---|
1359 | } |
---|
1360 | |
---|
1361 | int |
---|
1362 | kern_ktimer_getoverrun(struct thread *td, int timer_id) |
---|
1363 | { |
---|
1364 | struct proc *p = td->td_proc; |
---|
1365 | struct itimer *it; |
---|
1366 | int error ; |
---|
1367 | |
---|
1368 | PROC_LOCK(p); |
---|
1369 | if (timer_id < 3 || |
---|
1370 | (it = itimer_find(p, timer_id)) == NULL) { |
---|
1371 | PROC_UNLOCK(p); |
---|
1372 | error = EINVAL; |
---|
1373 | } else { |
---|
1374 | td->td_retval[0] = it->it_overrun_last; |
---|
1375 | ITIMER_UNLOCK(it); |
---|
1376 | PROC_UNLOCK(p); |
---|
1377 | error = 0; |
---|
1378 | } |
---|
1379 | return (error); |
---|
1380 | } |
---|
1381 | |
---|
1382 | static int |
---|
1383 | realtimer_create(struct itimer *it) |
---|
1384 | { |
---|
1385 | callout_init_mtx(&it->it_callout, &it->it_mtx, 0); |
---|
1386 | return (0); |
---|
1387 | } |
---|
1388 | |
---|
1389 | static int |
---|
1390 | realtimer_delete(struct itimer *it) |
---|
1391 | { |
---|
1392 | mtx_assert(&it->it_mtx, MA_OWNED); |
---|
1393 | |
---|
1394 | /* |
---|
1395 | * clear timer's value and interval to tell realtimer_expire |
---|
1396 | * to not rearm the timer. |
---|
1397 | */ |
---|
1398 | timespecclear(&it->it_time.it_value); |
---|
1399 | timespecclear(&it->it_time.it_interval); |
---|
1400 | ITIMER_UNLOCK(it); |
---|
1401 | callout_drain(&it->it_callout); |
---|
1402 | ITIMER_LOCK(it); |
---|
1403 | return (0); |
---|
1404 | } |
---|
1405 | |
---|
1406 | static int |
---|
1407 | realtimer_gettime(struct itimer *it, struct itimerspec *ovalue) |
---|
1408 | { |
---|
1409 | struct timespec cts; |
---|
1410 | |
---|
1411 | mtx_assert(&it->it_mtx, MA_OWNED); |
---|
1412 | |
---|
1413 | realtimer_clocktime(it->it_clockid, &cts); |
---|
1414 | *ovalue = it->it_time; |
---|
1415 | if (ovalue->it_value.tv_sec != 0 || ovalue->it_value.tv_nsec != 0) { |
---|
1416 | timespecsub(&ovalue->it_value, &cts); |
---|
1417 | if (ovalue->it_value.tv_sec < 0 || |
---|
1418 | (ovalue->it_value.tv_sec == 0 && |
---|
1419 | ovalue->it_value.tv_nsec == 0)) { |
---|
1420 | ovalue->it_value.tv_sec = 0; |
---|
1421 | ovalue->it_value.tv_nsec = 1; |
---|
1422 | } |
---|
1423 | } |
---|
1424 | return (0); |
---|
1425 | } |
---|
1426 | |
---|
1427 | static int |
---|
1428 | realtimer_settime(struct itimer *it, int flags, |
---|
1429 | struct itimerspec *value, struct itimerspec *ovalue) |
---|
1430 | { |
---|
1431 | struct timespec cts, ts; |
---|
1432 | struct timeval tv; |
---|
1433 | struct itimerspec val; |
---|
1434 | |
---|
1435 | mtx_assert(&it->it_mtx, MA_OWNED); |
---|
1436 | |
---|
1437 | val = *value; |
---|
1438 | if (itimespecfix(&val.it_value)) |
---|
1439 | return (EINVAL); |
---|
1440 | |
---|
1441 | if (timespecisset(&val.it_value)) { |
---|
1442 | if (itimespecfix(&val.it_interval)) |
---|
1443 | return (EINVAL); |
---|
1444 | } else { |
---|
1445 | timespecclear(&val.it_interval); |
---|
1446 | } |
---|
1447 | |
---|
1448 | if (ovalue != NULL) |
---|
1449 | realtimer_gettime(it, ovalue); |
---|
1450 | |
---|
1451 | it->it_time = val; |
---|
1452 | if (timespecisset(&val.it_value)) { |
---|
1453 | realtimer_clocktime(it->it_clockid, &cts); |
---|
1454 | ts = val.it_value; |
---|
1455 | if ((flags & TIMER_ABSTIME) == 0) { |
---|
1456 | /* Convert to absolute time. */ |
---|
1457 | timespecadd(&it->it_time.it_value, &cts); |
---|
1458 | } else { |
---|
1459 | timespecsub(&ts, &cts); |
---|
1460 | /* |
---|
1461 | * We don't care if ts is negative, tztohz will |
---|
1462 | * fix it. |
---|
1463 | */ |
---|
1464 | } |
---|
1465 | TIMESPEC_TO_TIMEVAL(&tv, &ts); |
---|
1466 | callout_reset(&it->it_callout, tvtohz(&tv), |
---|
1467 | realtimer_expire, it); |
---|
1468 | } else { |
---|
1469 | callout_stop(&it->it_callout); |
---|
1470 | } |
---|
1471 | |
---|
1472 | return (0); |
---|
1473 | } |
---|
1474 | |
---|
1475 | static void |
---|
1476 | realtimer_clocktime(clockid_t id, struct timespec *ts) |
---|
1477 | { |
---|
1478 | if (id == CLOCK_REALTIME) |
---|
1479 | getnanotime(ts); |
---|
1480 | else /* CLOCK_MONOTONIC */ |
---|
1481 | getnanouptime(ts); |
---|
1482 | } |
---|
1483 | |
---|
1484 | int |
---|
1485 | itimer_accept(struct proc *p, int timerid, ksiginfo_t *ksi) |
---|
1486 | { |
---|
1487 | struct itimer *it; |
---|
1488 | |
---|
1489 | PROC_LOCK_ASSERT(p, MA_OWNED); |
---|
1490 | it = itimer_find(p, timerid); |
---|
1491 | if (it != NULL) { |
---|
1492 | ksi->ksi_overrun = it->it_overrun; |
---|
1493 | it->it_overrun_last = it->it_overrun; |
---|
1494 | it->it_overrun = 0; |
---|
1495 | ITIMER_UNLOCK(it); |
---|
1496 | return (0); |
---|
1497 | } |
---|
1498 | return (EINVAL); |
---|
1499 | } |
---|
1500 | |
---|
1501 | int |
---|
1502 | itimespecfix(struct timespec *ts) |
---|
1503 | { |
---|
1504 | |
---|
1505 | if (ts->tv_sec < 0 || ts->tv_nsec < 0 || ts->tv_nsec >= 1000000000) |
---|
1506 | return (EINVAL); |
---|
1507 | if (ts->tv_sec == 0 && ts->tv_nsec != 0 && ts->tv_nsec < tick * 1000) |
---|
1508 | ts->tv_nsec = tick * 1000; |
---|
1509 | return (0); |
---|
1510 | } |
---|
1511 | |
---|
1512 | /* Timeout callback for realtime timer */ |
---|
1513 | static void |
---|
1514 | realtimer_expire(void *arg) |
---|
1515 | { |
---|
1516 | struct timespec cts, ts; |
---|
1517 | struct timeval tv; |
---|
1518 | struct itimer *it; |
---|
1519 | |
---|
1520 | it = (struct itimer *)arg; |
---|
1521 | |
---|
1522 | realtimer_clocktime(it->it_clockid, &cts); |
---|
1523 | /* Only fire if time is reached. */ |
---|
1524 | if (timespeccmp(&cts, &it->it_time.it_value, >=)) { |
---|
1525 | if (timespecisset(&it->it_time.it_interval)) { |
---|
1526 | timespecadd(&it->it_time.it_value, |
---|
1527 | &it->it_time.it_interval); |
---|
1528 | while (timespeccmp(&cts, &it->it_time.it_value, >=)) { |
---|
1529 | if (it->it_overrun < INT_MAX) |
---|
1530 | it->it_overrun++; |
---|
1531 | else |
---|
1532 | it->it_ksi.ksi_errno = ERANGE; |
---|
1533 | timespecadd(&it->it_time.it_value, |
---|
1534 | &it->it_time.it_interval); |
---|
1535 | } |
---|
1536 | } else { |
---|
1537 | /* single shot timer ? */ |
---|
1538 | timespecclear(&it->it_time.it_value); |
---|
1539 | } |
---|
1540 | if (timespecisset(&it->it_time.it_value)) { |
---|
1541 | ts = it->it_time.it_value; |
---|
1542 | timespecsub(&ts, &cts); |
---|
1543 | TIMESPEC_TO_TIMEVAL(&tv, &ts); |
---|
1544 | callout_reset(&it->it_callout, tvtohz(&tv), |
---|
1545 | realtimer_expire, it); |
---|
1546 | } |
---|
1547 | itimer_enter(it); |
---|
1548 | ITIMER_UNLOCK(it); |
---|
1549 | itimer_fire(it); |
---|
1550 | ITIMER_LOCK(it); |
---|
1551 | itimer_leave(it); |
---|
1552 | } else if (timespecisset(&it->it_time.it_value)) { |
---|
1553 | ts = it->it_time.it_value; |
---|
1554 | timespecsub(&ts, &cts); |
---|
1555 | TIMESPEC_TO_TIMEVAL(&tv, &ts); |
---|
1556 | callout_reset(&it->it_callout, tvtohz(&tv), realtimer_expire, |
---|
1557 | it); |
---|
1558 | } |
---|
1559 | } |
---|
1560 | |
---|
1561 | void |
---|
1562 | itimer_fire(struct itimer *it) |
---|
1563 | { |
---|
1564 | struct proc *p = it->it_proc; |
---|
1565 | struct thread *td; |
---|
1566 | |
---|
1567 | if (it->it_sigev.sigev_notify == SIGEV_SIGNAL || |
---|
1568 | it->it_sigev.sigev_notify == SIGEV_THREAD_ID) { |
---|
1569 | if (sigev_findtd(p, &it->it_sigev, &td) != 0) { |
---|
1570 | ITIMER_LOCK(it); |
---|
1571 | timespecclear(&it->it_time.it_value); |
---|
1572 | timespecclear(&it->it_time.it_interval); |
---|
1573 | callout_stop(&it->it_callout); |
---|
1574 | ITIMER_UNLOCK(it); |
---|
1575 | return; |
---|
1576 | } |
---|
1577 | if (!KSI_ONQ(&it->it_ksi)) { |
---|
1578 | it->it_ksi.ksi_errno = 0; |
---|
1579 | ksiginfo_set_sigev(&it->it_ksi, &it->it_sigev); |
---|
1580 | tdsendsignal(p, td, it->it_ksi.ksi_signo, &it->it_ksi); |
---|
1581 | } else { |
---|
1582 | if (it->it_overrun < INT_MAX) |
---|
1583 | it->it_overrun++; |
---|
1584 | else |
---|
1585 | it->it_ksi.ksi_errno = ERANGE; |
---|
1586 | } |
---|
1587 | PROC_UNLOCK(p); |
---|
1588 | } |
---|
1589 | } |
---|
1590 | |
---|
1591 | static void |
---|
1592 | itimers_alloc(struct proc *p) |
---|
1593 | { |
---|
1594 | struct itimers *its; |
---|
1595 | int i; |
---|
1596 | |
---|
1597 | its = malloc(sizeof (struct itimers), M_SUBPROC, M_WAITOK | M_ZERO); |
---|
1598 | LIST_INIT(&its->its_virtual); |
---|
1599 | LIST_INIT(&its->its_prof); |
---|
1600 | TAILQ_INIT(&its->its_worklist); |
---|
1601 | for (i = 0; i < TIMER_MAX; i++) |
---|
1602 | its->its_timers[i] = NULL; |
---|
1603 | PROC_LOCK(p); |
---|
1604 | if (p->p_itimers == NULL) { |
---|
1605 | p->p_itimers = its; |
---|
1606 | PROC_UNLOCK(p); |
---|
1607 | } |
---|
1608 | else { |
---|
1609 | PROC_UNLOCK(p); |
---|
1610 | free(its, M_SUBPROC); |
---|
1611 | } |
---|
1612 | } |
---|
1613 | |
---|
1614 | static void |
---|
1615 | itimers_event_hook_exec(void *arg, struct proc *p, struct image_params *imgp __unused) |
---|
1616 | { |
---|
1617 | itimers_event_hook_exit(arg, p); |
---|
1618 | } |
---|
1619 | |
---|
1620 | /* Clean up timers when some process events are being triggered. */ |
---|
1621 | static void |
---|
1622 | itimers_event_hook_exit(void *arg, struct proc *p) |
---|
1623 | { |
---|
1624 | struct itimers *its; |
---|
1625 | struct itimer *it; |
---|
1626 | int event = (int)(intptr_t)arg; |
---|
1627 | int i; |
---|
1628 | |
---|
1629 | if (p->p_itimers != NULL) { |
---|
1630 | its = p->p_itimers; |
---|
1631 | for (i = 0; i < MAX_CLOCKS; ++i) { |
---|
1632 | if (posix_clocks[i].event_hook != NULL) |
---|
1633 | CLOCK_CALL(i, event_hook, (p, i, event)); |
---|
1634 | } |
---|
1635 | /* |
---|
1636 | * According to susv3, XSI interval timers should be inherited |
---|
1637 | * by new image. |
---|
1638 | */ |
---|
1639 | if (event == ITIMER_EV_EXEC) |
---|
1640 | i = 3; |
---|
1641 | else if (event == ITIMER_EV_EXIT) |
---|
1642 | i = 0; |
---|
1643 | else |
---|
1644 | panic("unhandled event"); |
---|
1645 | for (; i < TIMER_MAX; ++i) { |
---|
1646 | if ((it = its->its_timers[i]) != NULL) |
---|
1647 | kern_ktimer_delete(curthread, i); |
---|
1648 | } |
---|
1649 | if (its->its_timers[0] == NULL && |
---|
1650 | its->its_timers[1] == NULL && |
---|
1651 | its->its_timers[2] == NULL) { |
---|
1652 | free(its, M_SUBPROC); |
---|
1653 | p->p_itimers = NULL; |
---|
1654 | } |
---|
1655 | } |
---|
1656 | } |
---|
1657 | #endif /* __rtems__ */ |
---|