| @@ -1,1164 +1,1159 @@ | | | @@ -1,1164 +1,1159 @@ |
1 | /* $NetBSD: kern_time.c,v 1.201 2019/10/05 12:57:40 kamil Exp $ */ | | 1 | /* $NetBSD: kern_time.c,v 1.202 2020/01/01 17:28:17 thorpej Exp $ */ |
2 | | | 2 | |
3 | /*- | | 3 | /*- |
4 | * Copyright (c) 2000, 2004, 2005, 2007, 2008, 2009 The NetBSD Foundation, Inc. | | 4 | * Copyright (c) 2000, 2004, 2005, 2007, 2008, 2009 The NetBSD Foundation, Inc. |
5 | * All rights reserved. | | 5 | * All rights reserved. |
6 | * | | 6 | * |
7 | * This code is derived from software contributed to The NetBSD Foundation | | 7 | * This code is derived from software contributed to The NetBSD Foundation |
8 | * by Christopher G. Demetriou, and by Andrew Doran. | | 8 | * by Christopher G. Demetriou, and by Andrew Doran. |
9 | * | | 9 | * |
10 | * Redistribution and use in source and binary forms, with or without | | 10 | * Redistribution and use in source and binary forms, with or without |
11 | * modification, are permitted provided that the following conditions | | 11 | * modification, are permitted provided that the following conditions |
12 | * are met: | | 12 | * are met: |
13 | * 1. Redistributions of source code must retain the above copyright | | 13 | * 1. Redistributions of source code must retain the above copyright |
14 | * notice, this list of conditions and the following disclaimer. | | 14 | * notice, this list of conditions and the following disclaimer. |
15 | * 2. Redistributions in binary form must reproduce the above copyright | | 15 | * 2. Redistributions in binary form must reproduce the above copyright |
16 | * notice, this list of conditions and the following disclaimer in the | | 16 | * notice, this list of conditions and the following disclaimer in the |
17 | * documentation and/or other materials provided with the distribution. | | 17 | * documentation and/or other materials provided with the distribution. |
18 | * | | 18 | * |
19 | * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS | | 19 | * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS |
20 | * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED | | 20 | * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED |
21 | * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR | | 21 | * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
22 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS | | 22 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS |
23 | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | | 23 | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
24 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | | 24 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
25 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS | | 25 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
26 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN | | 26 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
27 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | | 27 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
28 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | | 28 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
29 | * POSSIBILITY OF SUCH DAMAGE. | | 29 | * POSSIBILITY OF SUCH DAMAGE. |
30 | */ | | 30 | */ |
31 | | | 31 | |
32 | /* | | 32 | /* |
33 | * Copyright (c) 1982, 1986, 1989, 1993 | | 33 | * Copyright (c) 1982, 1986, 1989, 1993 |
34 | * The Regents of the University of California. All rights reserved. | | 34 | * The Regents of the University of California. All rights reserved. |
35 | * | | 35 | * |
36 | * Redistribution and use in source and binary forms, with or without | | 36 | * Redistribution and use in source and binary forms, with or without |
37 | * modification, are permitted provided that the following conditions | | 37 | * modification, are permitted provided that the following conditions |
38 | * are met: | | 38 | * are met: |
39 | * 1. Redistributions of source code must retain the above copyright | | 39 | * 1. Redistributions of source code must retain the above copyright |
40 | * notice, this list of conditions and the following disclaimer. | | 40 | * notice, this list of conditions and the following disclaimer. |
41 | * 2. Redistributions in binary form must reproduce the above copyright | | 41 | * 2. Redistributions in binary form must reproduce the above copyright |
42 | * notice, this list of conditions and the following disclaimer in the | | 42 | * notice, this list of conditions and the following disclaimer in the |
43 | * documentation and/or other materials provided with the distribution. | | 43 | * documentation and/or other materials provided with the distribution. |
44 | * 3. Neither the name of the University nor the names of its contributors | | 44 | * 3. Neither the name of the University nor the names of its contributors |
45 | * may be used to endorse or promote products derived from this software | | 45 | * may be used to endorse or promote products derived from this software |
46 | * without specific prior written permission. | | 46 | * without specific prior written permission. |
47 | * | | 47 | * |
48 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND | | 48 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND |
49 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | | 49 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
50 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | | 50 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
51 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE | | 51 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE |
52 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | | 52 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
53 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | | 53 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS |
54 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | | 54 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
55 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | | 55 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
56 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | | 56 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY |
57 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | | 57 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
58 | * SUCH DAMAGE. | | 58 | * SUCH DAMAGE. |
59 | * | | 59 | * |
60 | * @(#)kern_time.c 8.4 (Berkeley) 5/26/95 | | 60 | * @(#)kern_time.c 8.4 (Berkeley) 5/26/95 |
61 | */ | | 61 | */ |
62 | | | 62 | |
63 | #include <sys/cdefs.h> | | 63 | #include <sys/cdefs.h> |
64 | __KERNEL_RCSID(0, "$NetBSD: kern_time.c,v 1.201 2019/10/05 12:57:40 kamil Exp $"); | | 64 | __KERNEL_RCSID(0, "$NetBSD: kern_time.c,v 1.202 2020/01/01 17:28:17 thorpej Exp $"); |
65 | | | 65 | |
66 | #include <sys/param.h> | | 66 | #include <sys/param.h> |
67 | #include <sys/resourcevar.h> | | 67 | #include <sys/resourcevar.h> |
68 | #include <sys/kernel.h> | | 68 | #include <sys/kernel.h> |
69 | #include <sys/systm.h> | | 69 | #include <sys/systm.h> |
70 | #include <sys/proc.h> | | 70 | #include <sys/proc.h> |
71 | #include <sys/vnode.h> | | 71 | #include <sys/vnode.h> |
72 | #include <sys/signalvar.h> | | 72 | #include <sys/signalvar.h> |
73 | #include <sys/syslog.h> | | 73 | #include <sys/syslog.h> |
74 | #include <sys/timetc.h> | | 74 | #include <sys/timetc.h> |
75 | #include <sys/timex.h> | | 75 | #include <sys/timex.h> |
76 | #include <sys/kauth.h> | | 76 | #include <sys/kauth.h> |
77 | #include <sys/mount.h> | | 77 | #include <sys/mount.h> |
78 | #include <sys/syscallargs.h> | | 78 | #include <sys/syscallargs.h> |
79 | #include <sys/cpu.h> | | 79 | #include <sys/cpu.h> |
80 | | | 80 | |
81 | static void timer_intr(void *); | | 81 | static void timer_intr(void *); |
82 | static void itimerfire(struct ptimer *); | | 82 | static void itimerfire(struct ptimer *); |
83 | static void itimerfree(struct ptimers *, int); | | 83 | static void itimerfree(struct ptimers *, int); |
84 | | | 84 | |
85 | kmutex_t timer_lock; | | 85 | kmutex_t timer_lock; |
86 | | | 86 | |
87 | static void *timer_sih; | | 87 | static void *timer_sih; |
88 | static TAILQ_HEAD(, ptimer) timer_queue; | | 88 | static TAILQ_HEAD(, ptimer) timer_queue; |
89 | | | 89 | |
90 | struct pool ptimer_pool, ptimers_pool; | | 90 | struct pool ptimer_pool, ptimers_pool; |
91 | | | 91 | |
92 | #define CLOCK_VIRTUAL_P(clockid) \ | | 92 | #define CLOCK_VIRTUAL_P(clockid) \ |
93 | ((clockid) == CLOCK_VIRTUAL || (clockid) == CLOCK_PROF) | | 93 | ((clockid) == CLOCK_VIRTUAL || (clockid) == CLOCK_PROF) |
94 | | | 94 | |
95 | CTASSERT(ITIMER_REAL == CLOCK_REALTIME); | | 95 | CTASSERT(ITIMER_REAL == CLOCK_REALTIME); |
96 | CTASSERT(ITIMER_VIRTUAL == CLOCK_VIRTUAL); | | 96 | CTASSERT(ITIMER_VIRTUAL == CLOCK_VIRTUAL); |
97 | CTASSERT(ITIMER_PROF == CLOCK_PROF); | | 97 | CTASSERT(ITIMER_PROF == CLOCK_PROF); |
98 | CTASSERT(ITIMER_MONOTONIC == CLOCK_MONOTONIC); | | 98 | CTASSERT(ITIMER_MONOTONIC == CLOCK_MONOTONIC); |
99 | | | 99 | |
100 | #define DELAYTIMER_MAX 32 | | 100 | #define DELAYTIMER_MAX 32 |
101 | | | 101 | |
102 | /* | | 102 | /* |
103 | * Initialize timekeeping. | | 103 | * Initialize timekeeping. |
104 | */ | | 104 | */ |
105 | void | | 105 | void |
106 | time_init(void) | | 106 | time_init(void) |
107 | { | | 107 | { |
108 | | | 108 | |
109 | pool_init(&ptimer_pool, sizeof(struct ptimer), 0, 0, 0, "ptimerpl", | | 109 | pool_init(&ptimer_pool, sizeof(struct ptimer), 0, 0, 0, "ptimerpl", |
110 | &pool_allocator_nointr, IPL_NONE); | | 110 | &pool_allocator_nointr, IPL_NONE); |
111 | pool_init(&ptimers_pool, sizeof(struct ptimers), 0, 0, 0, "ptimerspl", | | 111 | pool_init(&ptimers_pool, sizeof(struct ptimers), 0, 0, 0, "ptimerspl", |
112 | &pool_allocator_nointr, IPL_NONE); | | 112 | &pool_allocator_nointr, IPL_NONE); |
113 | } | | 113 | } |
114 | | | 114 | |
115 | void | | 115 | void |
116 | time_init2(void) | | 116 | time_init2(void) |
117 | { | | 117 | { |
118 | | | 118 | |
119 | TAILQ_INIT(&timer_queue); | | 119 | TAILQ_INIT(&timer_queue); |
120 | mutex_init(&timer_lock, MUTEX_DEFAULT, IPL_SCHED); | | 120 | mutex_init(&timer_lock, MUTEX_DEFAULT, IPL_SCHED); |
121 | timer_sih = softint_establish(SOFTINT_CLOCK | SOFTINT_MPSAFE, | | 121 | timer_sih = softint_establish(SOFTINT_CLOCK | SOFTINT_MPSAFE, |
122 | timer_intr, NULL); | | 122 | timer_intr, NULL); |
123 | } | | 123 | } |
124 | | | 124 | |
125 | /* Time of day and interval timer support. | | 125 | /* Time of day and interval timer support. |
126 | * | | 126 | * |
127 | * These routines provide the kernel entry points to get and set | | 127 | * These routines provide the kernel entry points to get and set |
128 | * the time-of-day and per-process interval timers. Subroutines | | 128 | * the time-of-day and per-process interval timers. Subroutines |
129 | * here provide support for adding and subtracting timeval structures | | 129 | * here provide support for adding and subtracting timeval structures |
130 | * and decrementing interval timers, optionally reloading the interval | | 130 | * and decrementing interval timers, optionally reloading the interval |
131 | * timers when they expire. | | 131 | * timers when they expire. |
132 | */ | | 132 | */ |
133 | | | 133 | |
134 | /* This function is used by clock_settime and settimeofday */ | | 134 | /* This function is used by clock_settime and settimeofday */ |
135 | static int | | 135 | static int |
136 | settime1(struct proc *p, const struct timespec *ts, bool check_kauth) | | 136 | settime1(struct proc *p, const struct timespec *ts, bool check_kauth) |
137 | { | | 137 | { |
138 | struct timespec delta, now; | | 138 | struct timespec delta, now; |
139 | int s; | | | |
140 | | | 139 | |
141 | /* WHAT DO WE DO ABOUT PENDING REAL-TIME TIMEOUTS??? */ | | 140 | /* WHAT DO WE DO ABOUT PENDING REAL-TIME TIMEOUTS??? */ |
142 | s = splclock(); | | | |
143 | nanotime(&now); | | 141 | nanotime(&now); |
144 | timespecsub(ts, &now, &delta); | | 142 | timespecsub(ts, &now, &delta); |
145 | | | 143 | |
146 | if (check_kauth && kauth_authorize_system(kauth_cred_get(), | | 144 | if (check_kauth && kauth_authorize_system(kauth_cred_get(), |
147 | KAUTH_SYSTEM_TIME, KAUTH_REQ_SYSTEM_TIME_SYSTEM, __UNCONST(ts), | | 145 | KAUTH_SYSTEM_TIME, KAUTH_REQ_SYSTEM_TIME_SYSTEM, __UNCONST(ts), |
148 | &delta, KAUTH_ARG(check_kauth ? false : true)) != 0) { | | 146 | &delta, KAUTH_ARG(check_kauth ? false : true)) != 0) { |
149 | splx(s); | | | |
150 | return (EPERM); | | 147 | return (EPERM); |
151 | } | | 148 | } |
152 | | | 149 | |
153 | #ifdef notyet | | 150 | #ifdef notyet |
154 | if ((delta.tv_sec < 86400) && securelevel > 0) { /* XXX elad - notyet */ | | 151 | if ((delta.tv_sec < 86400) && securelevel > 0) { /* XXX elad - notyet */ |
155 | splx(s); | | | |
156 | return (EPERM); | | 152 | return (EPERM); |
157 | } | | 153 | } |
158 | #endif | | 154 | #endif |
159 | | | 155 | |
160 | tc_setclock(ts); | | 156 | tc_setclock(ts); |
161 | | | 157 | |
162 | timespecadd(&boottime, &delta, &boottime); | | 158 | timespecadd(&boottime, &delta, &boottime); |
163 | | | 159 | |
164 | resettodr(); | | 160 | resettodr(); |
165 | splx(s); | | | |
166 | | | 161 | |
167 | return (0); | | 162 | return (0); |
168 | } | | 163 | } |
169 | | | 164 | |
170 | int | | 165 | int |
171 | settime(struct proc *p, struct timespec *ts) | | 166 | settime(struct proc *p, struct timespec *ts) |
172 | { | | 167 | { |
173 | return (settime1(p, ts, true)); | | 168 | return (settime1(p, ts, true)); |
174 | } | | 169 | } |
175 | | | 170 | |
176 | /* ARGSUSED */ | | 171 | /* ARGSUSED */ |
177 | int | | 172 | int |
178 | sys___clock_gettime50(struct lwp *l, | | 173 | sys___clock_gettime50(struct lwp *l, |
179 | const struct sys___clock_gettime50_args *uap, register_t *retval) | | 174 | const struct sys___clock_gettime50_args *uap, register_t *retval) |
180 | { | | 175 | { |
181 | /* { | | 176 | /* { |
182 | syscallarg(clockid_t) clock_id; | | 177 | syscallarg(clockid_t) clock_id; |
183 | syscallarg(struct timespec *) tp; | | 178 | syscallarg(struct timespec *) tp; |
184 | } */ | | 179 | } */ |
185 | int error; | | 180 | int error; |
186 | struct timespec ats; | | 181 | struct timespec ats; |
187 | | | 182 | |
188 | error = clock_gettime1(SCARG(uap, clock_id), &ats); | | 183 | error = clock_gettime1(SCARG(uap, clock_id), &ats); |
189 | if (error != 0) | | 184 | if (error != 0) |
190 | return error; | | 185 | return error; |
191 | | | 186 | |
192 | return copyout(&ats, SCARG(uap, tp), sizeof(ats)); | | 187 | return copyout(&ats, SCARG(uap, tp), sizeof(ats)); |
193 | } | | 188 | } |
194 | | | 189 | |
195 | /* ARGSUSED */ | | 190 | /* ARGSUSED */ |
196 | int | | 191 | int |
197 | sys___clock_settime50(struct lwp *l, | | 192 | sys___clock_settime50(struct lwp *l, |
198 | const struct sys___clock_settime50_args *uap, register_t *retval) | | 193 | const struct sys___clock_settime50_args *uap, register_t *retval) |
199 | { | | 194 | { |
200 | /* { | | 195 | /* { |
201 | syscallarg(clockid_t) clock_id; | | 196 | syscallarg(clockid_t) clock_id; |
202 | syscallarg(const struct timespec *) tp; | | 197 | syscallarg(const struct timespec *) tp; |
203 | } */ | | 198 | } */ |
204 | int error; | | 199 | int error; |
205 | struct timespec ats; | | 200 | struct timespec ats; |
206 | | | 201 | |
207 | if ((error = copyin(SCARG(uap, tp), &ats, sizeof(ats))) != 0) | | 202 | if ((error = copyin(SCARG(uap, tp), &ats, sizeof(ats))) != 0) |
208 | return error; | | 203 | return error; |
209 | | | 204 | |
210 | return clock_settime1(l->l_proc, SCARG(uap, clock_id), &ats, true); | | 205 | return clock_settime1(l->l_proc, SCARG(uap, clock_id), &ats, true); |
211 | } | | 206 | } |
212 | | | 207 | |
213 | | | 208 | |
214 | int | | 209 | int |
215 | clock_settime1(struct proc *p, clockid_t clock_id, const struct timespec *tp, | | 210 | clock_settime1(struct proc *p, clockid_t clock_id, const struct timespec *tp, |
216 | bool check_kauth) | | 211 | bool check_kauth) |
217 | { | | 212 | { |
218 | int error; | | 213 | int error; |
219 | | | 214 | |
220 | if (tp->tv_nsec < 0 || tp->tv_nsec >= 1000000000L) | | 215 | if (tp->tv_nsec < 0 || tp->tv_nsec >= 1000000000L) |
221 | return EINVAL; | | 216 | return EINVAL; |
222 | | | 217 | |
223 | switch (clock_id) { | | 218 | switch (clock_id) { |
224 | case CLOCK_REALTIME: | | 219 | case CLOCK_REALTIME: |
225 | if ((error = settime1(p, tp, check_kauth)) != 0) | | 220 | if ((error = settime1(p, tp, check_kauth)) != 0) |
226 | return (error); | | 221 | return (error); |
227 | break; | | 222 | break; |
228 | case CLOCK_MONOTONIC: | | 223 | case CLOCK_MONOTONIC: |
229 | return (EINVAL); /* read-only clock */ | | 224 | return (EINVAL); /* read-only clock */ |
230 | default: | | 225 | default: |
231 | return (EINVAL); | | 226 | return (EINVAL); |
232 | } | | 227 | } |
233 | | | 228 | |
234 | return 0; | | 229 | return 0; |
235 | } | | 230 | } |
236 | | | 231 | |
237 | int | | 232 | int |
238 | sys___clock_getres50(struct lwp *l, const struct sys___clock_getres50_args *uap, | | 233 | sys___clock_getres50(struct lwp *l, const struct sys___clock_getres50_args *uap, |
239 | register_t *retval) | | 234 | register_t *retval) |
240 | { | | 235 | { |
241 | /* { | | 236 | /* { |
242 | syscallarg(clockid_t) clock_id; | | 237 | syscallarg(clockid_t) clock_id; |
243 | syscallarg(struct timespec *) tp; | | 238 | syscallarg(struct timespec *) tp; |
244 | } */ | | 239 | } */ |
245 | struct timespec ts; | | 240 | struct timespec ts; |
246 | int error; | | 241 | int error; |
247 | | | 242 | |
248 | if ((error = clock_getres1(SCARG(uap, clock_id), &ts)) != 0) | | 243 | if ((error = clock_getres1(SCARG(uap, clock_id), &ts)) != 0) |
249 | return error; | | 244 | return error; |
250 | | | 245 | |
251 | if (SCARG(uap, tp)) | | 246 | if (SCARG(uap, tp)) |
252 | error = copyout(&ts, SCARG(uap, tp), sizeof(ts)); | | 247 | error = copyout(&ts, SCARG(uap, tp), sizeof(ts)); |
253 | | | 248 | |
254 | return error; | | 249 | return error; |
255 | } | | 250 | } |
256 | | | 251 | |
257 | int | | 252 | int |
258 | clock_getres1(clockid_t clock_id, struct timespec *ts) | | 253 | clock_getres1(clockid_t clock_id, struct timespec *ts) |
259 | { | | 254 | { |
260 | | | 255 | |
261 | switch (clock_id) { | | 256 | switch (clock_id) { |
262 | case CLOCK_REALTIME: | | 257 | case CLOCK_REALTIME: |
263 | case CLOCK_MONOTONIC: | | 258 | case CLOCK_MONOTONIC: |
264 | ts->tv_sec = 0; | | 259 | ts->tv_sec = 0; |
265 | if (tc_getfrequency() > 1000000000) | | 260 | if (tc_getfrequency() > 1000000000) |
266 | ts->tv_nsec = 1; | | 261 | ts->tv_nsec = 1; |
267 | else | | 262 | else |
268 | ts->tv_nsec = 1000000000 / tc_getfrequency(); | | 263 | ts->tv_nsec = 1000000000 / tc_getfrequency(); |
269 | break; | | 264 | break; |
270 | default: | | 265 | default: |
271 | return EINVAL; | | 266 | return EINVAL; |
272 | } | | 267 | } |
273 | | | 268 | |
274 | return 0; | | 269 | return 0; |
275 | } | | 270 | } |
276 | | | 271 | |
277 | /* ARGSUSED */ | | 272 | /* ARGSUSED */ |
278 | int | | 273 | int |
279 | sys___nanosleep50(struct lwp *l, const struct sys___nanosleep50_args *uap, | | 274 | sys___nanosleep50(struct lwp *l, const struct sys___nanosleep50_args *uap, |
280 | register_t *retval) | | 275 | register_t *retval) |
281 | { | | 276 | { |
282 | /* { | | 277 | /* { |
283 | syscallarg(struct timespec *) rqtp; | | 278 | syscallarg(struct timespec *) rqtp; |
284 | syscallarg(struct timespec *) rmtp; | | 279 | syscallarg(struct timespec *) rmtp; |
285 | } */ | | 280 | } */ |
286 | struct timespec rmt, rqt; | | 281 | struct timespec rmt, rqt; |
287 | int error, error1; | | 282 | int error, error1; |
288 | | | 283 | |
289 | error = copyin(SCARG(uap, rqtp), &rqt, sizeof(struct timespec)); | | 284 | error = copyin(SCARG(uap, rqtp), &rqt, sizeof(struct timespec)); |
290 | if (error) | | 285 | if (error) |
291 | return (error); | | 286 | return (error); |
292 | | | 287 | |
293 | error = nanosleep1(l, CLOCK_MONOTONIC, 0, &rqt, | | 288 | error = nanosleep1(l, CLOCK_MONOTONIC, 0, &rqt, |
294 | SCARG(uap, rmtp) ? &rmt : NULL); | | 289 | SCARG(uap, rmtp) ? &rmt : NULL); |
295 | if (SCARG(uap, rmtp) == NULL || (error != 0 && error != EINTR)) | | 290 | if (SCARG(uap, rmtp) == NULL || (error != 0 && error != EINTR)) |
296 | return error; | | 291 | return error; |
297 | | | 292 | |
298 | error1 = copyout(&rmt, SCARG(uap, rmtp), sizeof(rmt)); | | 293 | error1 = copyout(&rmt, SCARG(uap, rmtp), sizeof(rmt)); |
299 | return error1 ? error1 : error; | | 294 | return error1 ? error1 : error; |
300 | } | | 295 | } |
301 | | | 296 | |
302 | /* ARGSUSED */ | | 297 | /* ARGSUSED */ |
303 | int | | 298 | int |
304 | sys_clock_nanosleep(struct lwp *l, const struct sys_clock_nanosleep_args *uap, | | 299 | sys_clock_nanosleep(struct lwp *l, const struct sys_clock_nanosleep_args *uap, |
305 | register_t *retval) | | 300 | register_t *retval) |
306 | { | | 301 | { |
307 | /* { | | 302 | /* { |
308 | syscallarg(clockid_t) clock_id; | | 303 | syscallarg(clockid_t) clock_id; |
309 | syscallarg(int) flags; | | 304 | syscallarg(int) flags; |
310 | syscallarg(struct timespec *) rqtp; | | 305 | syscallarg(struct timespec *) rqtp; |
311 | syscallarg(struct timespec *) rmtp; | | 306 | syscallarg(struct timespec *) rmtp; |
312 | } */ | | 307 | } */ |
313 | struct timespec rmt, rqt; | | 308 | struct timespec rmt, rqt; |
314 | int error, error1; | | 309 | int error, error1; |
315 | | | 310 | |
316 | error = copyin(SCARG(uap, rqtp), &rqt, sizeof(struct timespec)); | | 311 | error = copyin(SCARG(uap, rqtp), &rqt, sizeof(struct timespec)); |
317 | if (error) | | 312 | if (error) |
318 | goto out; | | 313 | goto out; |
319 | | | 314 | |
320 | error = nanosleep1(l, SCARG(uap, clock_id), SCARG(uap, flags), &rqt, | | 315 | error = nanosleep1(l, SCARG(uap, clock_id), SCARG(uap, flags), &rqt, |
321 | SCARG(uap, rmtp) ? &rmt : NULL); | | 316 | SCARG(uap, rmtp) ? &rmt : NULL); |
322 | if (SCARG(uap, rmtp) == NULL || (error != 0 && error != EINTR)) | | 317 | if (SCARG(uap, rmtp) == NULL || (error != 0 && error != EINTR)) |
323 | goto out; | | 318 | goto out; |
324 | | | 319 | |
325 | if ((SCARG(uap, flags) & TIMER_ABSTIME) == 0 && | | 320 | if ((SCARG(uap, flags) & TIMER_ABSTIME) == 0 && |
326 | (error1 = copyout(&rmt, SCARG(uap, rmtp), sizeof(rmt))) != 0) | | 321 | (error1 = copyout(&rmt, SCARG(uap, rmtp), sizeof(rmt))) != 0) |
327 | error = error1; | | 322 | error = error1; |
328 | out: | | 323 | out: |
329 | *retval = error; | | 324 | *retval = error; |
330 | return 0; | | 325 | return 0; |
331 | } | | 326 | } |
332 | | | 327 | |
333 | int | | 328 | int |
334 | nanosleep1(struct lwp *l, clockid_t clock_id, int flags, struct timespec *rqt, | | 329 | nanosleep1(struct lwp *l, clockid_t clock_id, int flags, struct timespec *rqt, |
335 | struct timespec *rmt) | | 330 | struct timespec *rmt) |
336 | { | | 331 | { |
337 | struct timespec rmtstart; | | 332 | struct timespec rmtstart; |
338 | int error, timo; | | 333 | int error, timo; |
339 | | | 334 | |
340 | if ((error = ts2timo(clock_id, flags, rqt, &timo, &rmtstart)) != 0) { | | 335 | if ((error = ts2timo(clock_id, flags, rqt, &timo, &rmtstart)) != 0) { |
341 | if (error == ETIMEDOUT) { | | 336 | if (error == ETIMEDOUT) { |
342 | error = 0; | | 337 | error = 0; |
343 | if (rmt != NULL) | | 338 | if (rmt != NULL) |
344 | rmt->tv_sec = rmt->tv_nsec = 0; | | 339 | rmt->tv_sec = rmt->tv_nsec = 0; |
345 | } | | 340 | } |
346 | return error; | | 341 | return error; |
347 | } | | 342 | } |
348 | | | 343 | |
349 | /* | | 344 | /* |
350 | * Avoid inadvertently sleeping forever | | 345 | * Avoid inadvertently sleeping forever |
351 | */ | | 346 | */ |
352 | if (timo == 0) | | 347 | if (timo == 0) |
353 | timo = 1; | | 348 | timo = 1; |
354 | again: | | 349 | again: |
355 | error = kpause("nanoslp", true, timo, NULL); | | 350 | error = kpause("nanoslp", true, timo, NULL); |
356 | if (error == EWOULDBLOCK) | | 351 | if (error == EWOULDBLOCK) |
357 | error = 0; | | 352 | error = 0; |
358 | if (rmt != NULL || error == 0) { | | 353 | if (rmt != NULL || error == 0) { |
359 | struct timespec rmtend; | | 354 | struct timespec rmtend; |
360 | struct timespec t0; | | 355 | struct timespec t0; |
361 | struct timespec *t; | | 356 | struct timespec *t; |
362 | | | 357 | |
363 | (void)clock_gettime1(clock_id, &rmtend); | | 358 | (void)clock_gettime1(clock_id, &rmtend); |
364 | t = (rmt != NULL) ? rmt : &t0; | | 359 | t = (rmt != NULL) ? rmt : &t0; |
365 | if (flags & TIMER_ABSTIME) { | | 360 | if (flags & TIMER_ABSTIME) { |
366 | timespecsub(rqt, &rmtend, t); | | 361 | timespecsub(rqt, &rmtend, t); |
367 | } else { | | 362 | } else { |
368 | timespecsub(&rmtend, &rmtstart, t); | | 363 | timespecsub(&rmtend, &rmtstart, t); |
369 | timespecsub(rqt, t, t); | | 364 | timespecsub(rqt, t, t); |
370 | } | | 365 | } |
371 | if (t->tv_sec < 0) | | 366 | if (t->tv_sec < 0) |
372 | timespecclear(t); | | 367 | timespecclear(t); |
373 | if (error == 0) { | | 368 | if (error == 0) { |
374 | timo = tstohz(t); | | 369 | timo = tstohz(t); |
375 | if (timo > 0) | | 370 | if (timo > 0) |
376 | goto again; | | 371 | goto again; |
377 | } | | 372 | } |
378 | } | | 373 | } |
379 | | | 374 | |
380 | if (error == ERESTART) | | 375 | if (error == ERESTART) |
381 | error = EINTR; | | 376 | error = EINTR; |
382 | | | 377 | |
383 | return error; | | 378 | return error; |
384 | } | | 379 | } |
385 | | | 380 | |
386 | int | | 381 | int |
387 | sys_clock_getcpuclockid2(struct lwp *l, | | 382 | sys_clock_getcpuclockid2(struct lwp *l, |
388 | const struct sys_clock_getcpuclockid2_args *uap, | | 383 | const struct sys_clock_getcpuclockid2_args *uap, |
389 | register_t *retval) | | 384 | register_t *retval) |
390 | { | | 385 | { |
391 | /* { | | 386 | /* { |
392 | syscallarg(idtype_t idtype; | | 387 | syscallarg(idtype_t idtype; |
393 | syscallarg(id_t id); | | 388 | syscallarg(id_t id); |
394 | syscallarg(clockid_t *)clock_id; | | 389 | syscallarg(clockid_t *)clock_id; |
395 | } */ | | 390 | } */ |
396 | pid_t pid; | | 391 | pid_t pid; |
397 | lwpid_t lid; | | 392 | lwpid_t lid; |
398 | clockid_t clock_id; | | 393 | clockid_t clock_id; |
399 | id_t id = SCARG(uap, id); | | 394 | id_t id = SCARG(uap, id); |
400 | | | 395 | |
401 | switch (SCARG(uap, idtype)) { | | 396 | switch (SCARG(uap, idtype)) { |
402 | case P_PID: | | 397 | case P_PID: |
403 | pid = id == 0 ? l->l_proc->p_pid : id; | | 398 | pid = id == 0 ? l->l_proc->p_pid : id; |
404 | clock_id = CLOCK_PROCESS_CPUTIME_ID | pid; | | 399 | clock_id = CLOCK_PROCESS_CPUTIME_ID | pid; |
405 | break; | | 400 | break; |
406 | case P_LWPID: | | 401 | case P_LWPID: |
407 | lid = id == 0 ? l->l_lid : id; | | 402 | lid = id == 0 ? l->l_lid : id; |
408 | clock_id = CLOCK_THREAD_CPUTIME_ID | lid; | | 403 | clock_id = CLOCK_THREAD_CPUTIME_ID | lid; |
409 | break; | | 404 | break; |
410 | default: | | 405 | default: |
411 | return EINVAL; | | 406 | return EINVAL; |
412 | } | | 407 | } |
413 | return copyout(&clock_id, SCARG(uap, clock_id), sizeof(clock_id)); | | 408 | return copyout(&clock_id, SCARG(uap, clock_id), sizeof(clock_id)); |
414 | } | | 409 | } |
415 | | | 410 | |
416 | /* ARGSUSED */ | | 411 | /* ARGSUSED */ |
417 | int | | 412 | int |
418 | sys___gettimeofday50(struct lwp *l, const struct sys___gettimeofday50_args *uap, | | 413 | sys___gettimeofday50(struct lwp *l, const struct sys___gettimeofday50_args *uap, |
419 | register_t *retval) | | 414 | register_t *retval) |
420 | { | | 415 | { |
421 | /* { | | 416 | /* { |
422 | syscallarg(struct timeval *) tp; | | 417 | syscallarg(struct timeval *) tp; |
423 | syscallarg(void *) tzp; really "struct timezone *"; | | 418 | syscallarg(void *) tzp; really "struct timezone *"; |
424 | } */ | | 419 | } */ |
425 | struct timeval atv; | | 420 | struct timeval atv; |
426 | int error = 0; | | 421 | int error = 0; |
427 | struct timezone tzfake; | | 422 | struct timezone tzfake; |
428 | | | 423 | |
429 | if (SCARG(uap, tp)) { | | 424 | if (SCARG(uap, tp)) { |
430 | memset(&atv, 0, sizeof(atv)); | | 425 | memset(&atv, 0, sizeof(atv)); |
431 | microtime(&atv); | | 426 | microtime(&atv); |
432 | error = copyout(&atv, SCARG(uap, tp), sizeof(atv)); | | 427 | error = copyout(&atv, SCARG(uap, tp), sizeof(atv)); |
433 | if (error) | | 428 | if (error) |
434 | return (error); | | 429 | return (error); |
435 | } | | 430 | } |
436 | if (SCARG(uap, tzp)) { | | 431 | if (SCARG(uap, tzp)) { |
437 | /* | | 432 | /* |
438 | * NetBSD has no kernel notion of time zone, so we just | | 433 | * NetBSD has no kernel notion of time zone, so we just |
439 | * fake up a timezone struct and return it if demanded. | | 434 | * fake up a timezone struct and return it if demanded. |
440 | */ | | 435 | */ |
441 | tzfake.tz_minuteswest = 0; | | 436 | tzfake.tz_minuteswest = 0; |
442 | tzfake.tz_dsttime = 0; | | 437 | tzfake.tz_dsttime = 0; |
443 | error = copyout(&tzfake, SCARG(uap, tzp), sizeof(tzfake)); | | 438 | error = copyout(&tzfake, SCARG(uap, tzp), sizeof(tzfake)); |
444 | } | | 439 | } |
445 | return (error); | | 440 | return (error); |
446 | } | | 441 | } |
447 | | | 442 | |
448 | /* ARGSUSED */ | | 443 | /* ARGSUSED */ |
449 | int | | 444 | int |
450 | sys___settimeofday50(struct lwp *l, const struct sys___settimeofday50_args *uap, | | 445 | sys___settimeofday50(struct lwp *l, const struct sys___settimeofday50_args *uap, |
451 | register_t *retval) | | 446 | register_t *retval) |
452 | { | | 447 | { |
453 | /* { | | 448 | /* { |
454 | syscallarg(const struct timeval *) tv; | | 449 | syscallarg(const struct timeval *) tv; |
455 | syscallarg(const void *) tzp; really "const struct timezone *"; | | 450 | syscallarg(const void *) tzp; really "const struct timezone *"; |
456 | } */ | | 451 | } */ |
457 | | | 452 | |
458 | return settimeofday1(SCARG(uap, tv), true, SCARG(uap, tzp), l, true); | | 453 | return settimeofday1(SCARG(uap, tv), true, SCARG(uap, tzp), l, true); |
459 | } | | 454 | } |
460 | | | 455 | |
461 | int | | 456 | int |
462 | settimeofday1(const struct timeval *utv, bool userspace, | | 457 | settimeofday1(const struct timeval *utv, bool userspace, |
463 | const void *utzp, struct lwp *l, bool check_kauth) | | 458 | const void *utzp, struct lwp *l, bool check_kauth) |
464 | { | | 459 | { |
465 | struct timeval atv; | | 460 | struct timeval atv; |
466 | struct timespec ts; | | 461 | struct timespec ts; |
467 | int error; | | 462 | int error; |
468 | | | 463 | |
469 | /* Verify all parameters before changing time. */ | | 464 | /* Verify all parameters before changing time. */ |
470 | | | 465 | |
471 | /* | | 466 | /* |
472 | * NetBSD has no kernel notion of time zone, and only an | | 467 | * NetBSD has no kernel notion of time zone, and only an |
473 | * obsolete program would try to set it, so we log a warning. | | 468 | * obsolete program would try to set it, so we log a warning. |
474 | */ | | 469 | */ |
475 | if (utzp) | | 470 | if (utzp) |
476 | log(LOG_WARNING, "pid %d attempted to set the " | | 471 | log(LOG_WARNING, "pid %d attempted to set the " |
477 | "(obsolete) kernel time zone\n", l->l_proc->p_pid); | | 472 | "(obsolete) kernel time zone\n", l->l_proc->p_pid); |
478 | | | 473 | |
479 | if (utv == NULL) | | 474 | if (utv == NULL) |
480 | return 0; | | 475 | return 0; |
481 | | | 476 | |
482 | if (userspace) { | | 477 | if (userspace) { |
483 | if ((error = copyin(utv, &atv, sizeof(atv))) != 0) | | 478 | if ((error = copyin(utv, &atv, sizeof(atv))) != 0) |
484 | return error; | | 479 | return error; |
485 | utv = &atv; | | 480 | utv = &atv; |
486 | } | | 481 | } |
487 | | | 482 | |
488 | if (utv->tv_usec < 0 || utv->tv_usec >= 1000000) | | 483 | if (utv->tv_usec < 0 || utv->tv_usec >= 1000000) |
489 | return EINVAL; | | 484 | return EINVAL; |
490 | | | 485 | |
491 | TIMEVAL_TO_TIMESPEC(utv, &ts); | | 486 | TIMEVAL_TO_TIMESPEC(utv, &ts); |
492 | return settime1(l->l_proc, &ts, check_kauth); | | 487 | return settime1(l->l_proc, &ts, check_kauth); |
493 | } | | 488 | } |
494 | | | 489 | |
495 | int time_adjusted; /* set if an adjustment is made */ | | 490 | int time_adjusted; /* set if an adjustment is made */ |
496 | | | 491 | |
497 | /* ARGSUSED */ | | 492 | /* ARGSUSED */ |
498 | int | | 493 | int |
499 | sys___adjtime50(struct lwp *l, const struct sys___adjtime50_args *uap, | | 494 | sys___adjtime50(struct lwp *l, const struct sys___adjtime50_args *uap, |
500 | register_t *retval) | | 495 | register_t *retval) |
501 | { | | 496 | { |
502 | /* { | | 497 | /* { |
503 | syscallarg(const struct timeval *) delta; | | 498 | syscallarg(const struct timeval *) delta; |
504 | syscallarg(struct timeval *) olddelta; | | 499 | syscallarg(struct timeval *) olddelta; |
505 | } */ | | 500 | } */ |
506 | int error; | | 501 | int error; |
507 | struct timeval atv, oldatv; | | 502 | struct timeval atv, oldatv; |
508 | | | 503 | |
509 | if ((error = kauth_authorize_system(l->l_cred, KAUTH_SYSTEM_TIME, | | 504 | if ((error = kauth_authorize_system(l->l_cred, KAUTH_SYSTEM_TIME, |
510 | KAUTH_REQ_SYSTEM_TIME_ADJTIME, NULL, NULL, NULL)) != 0) | | 505 | KAUTH_REQ_SYSTEM_TIME_ADJTIME, NULL, NULL, NULL)) != 0) |
511 | return error; | | 506 | return error; |
512 | | | 507 | |
513 | if (SCARG(uap, delta)) { | | 508 | if (SCARG(uap, delta)) { |
514 | error = copyin(SCARG(uap, delta), &atv, | | 509 | error = copyin(SCARG(uap, delta), &atv, |
515 | sizeof(*SCARG(uap, delta))); | | 510 | sizeof(*SCARG(uap, delta))); |
516 | if (error) | | 511 | if (error) |
517 | return (error); | | 512 | return (error); |
518 | } | | 513 | } |
519 | adjtime1(SCARG(uap, delta) ? &atv : NULL, | | 514 | adjtime1(SCARG(uap, delta) ? &atv : NULL, |
520 | SCARG(uap, olddelta) ? &oldatv : NULL, l->l_proc); | | 515 | SCARG(uap, olddelta) ? &oldatv : NULL, l->l_proc); |
521 | if (SCARG(uap, olddelta)) | | 516 | if (SCARG(uap, olddelta)) |
522 | error = copyout(&oldatv, SCARG(uap, olddelta), | | 517 | error = copyout(&oldatv, SCARG(uap, olddelta), |
523 | sizeof(*SCARG(uap, olddelta))); | | 518 | sizeof(*SCARG(uap, olddelta))); |
524 | return error; | | 519 | return error; |
525 | } | | 520 | } |
526 | | | 521 | |
527 | void | | 522 | void |
528 | adjtime1(const struct timeval *delta, struct timeval *olddelta, struct proc *p) | | 523 | adjtime1(const struct timeval *delta, struct timeval *olddelta, struct proc *p) |
529 | { | | 524 | { |
530 | extern int64_t time_adjtime; /* in kern_ntptime.c */ | | 525 | extern int64_t time_adjtime; /* in kern_ntptime.c */ |
531 | | | 526 | |
532 | if (olddelta) { | | 527 | if (olddelta) { |
533 | memset(olddelta, 0, sizeof(*olddelta)); | | 528 | memset(olddelta, 0, sizeof(*olddelta)); |
534 | mutex_spin_enter(&timecounter_lock); | | 529 | mutex_spin_enter(&timecounter_lock); |
535 | olddelta->tv_sec = time_adjtime / 1000000; | | 530 | olddelta->tv_sec = time_adjtime / 1000000; |
536 | olddelta->tv_usec = time_adjtime % 1000000; | | 531 | olddelta->tv_usec = time_adjtime % 1000000; |
537 | if (olddelta->tv_usec < 0) { | | 532 | if (olddelta->tv_usec < 0) { |
538 | olddelta->tv_usec += 1000000; | | 533 | olddelta->tv_usec += 1000000; |
539 | olddelta->tv_sec--; | | 534 | olddelta->tv_sec--; |
540 | } | | 535 | } |
541 | mutex_spin_exit(&timecounter_lock); | | 536 | mutex_spin_exit(&timecounter_lock); |
542 | } | | 537 | } |
543 | | | 538 | |
544 | if (delta) { | | 539 | if (delta) { |
545 | mutex_spin_enter(&timecounter_lock); | | 540 | mutex_spin_enter(&timecounter_lock); |
546 | time_adjtime = delta->tv_sec * 1000000 + delta->tv_usec; | | 541 | time_adjtime = delta->tv_sec * 1000000 + delta->tv_usec; |
547 | | | 542 | |
548 | if (time_adjtime) { | | 543 | if (time_adjtime) { |
549 | /* We need to save the system time during shutdown */ | | 544 | /* We need to save the system time during shutdown */ |
550 | time_adjusted |= 1; | | 545 | time_adjusted |= 1; |
551 | } | | 546 | } |
552 | mutex_spin_exit(&timecounter_lock); | | 547 | mutex_spin_exit(&timecounter_lock); |
553 | } | | 548 | } |
554 | } | | 549 | } |
555 | | | 550 | |
556 | /* | | 551 | /* |
557 | * Interval timer support. Both the BSD getitimer() family and the POSIX | | 552 | * Interval timer support. Both the BSD getitimer() family and the POSIX |
558 | * timer_*() family of routines are supported. | | 553 | * timer_*() family of routines are supported. |
559 | * | | 554 | * |
560 | * All timers are kept in an array pointed to by p_timers, which is | | 555 | * All timers are kept in an array pointed to by p_timers, which is |
561 | * allocated on demand - many processes don't use timers at all. The | | 556 | * allocated on demand - many processes don't use timers at all. The |
562 | * first four elements in this array are reserved for the BSD timers: | | 557 | * first four elements in this array are reserved for the BSD timers: |
563 | * element 0 is ITIMER_REAL, element 1 is ITIMER_VIRTUAL, element | | 558 | * element 0 is ITIMER_REAL, element 1 is ITIMER_VIRTUAL, element |
564 | * 2 is ITIMER_PROF, and element 3 is ITIMER_MONOTONIC. The rest may be | | 559 | * 2 is ITIMER_PROF, and element 3 is ITIMER_MONOTONIC. The rest may be |
565 | * allocated by the timer_create() syscall. | | 560 | * allocated by the timer_create() syscall. |
566 | * | | 561 | * |
567 | * Realtime timers are kept in the ptimer structure as an absolute | | 562 | * Realtime timers are kept in the ptimer structure as an absolute |
568 | * time; virtual time timers are kept as a linked list of deltas. | | 563 | * time; virtual time timers are kept as a linked list of deltas. |
569 | * Virtual time timers are processed in the hardclock() routine of | | 564 | * Virtual time timers are processed in the hardclock() routine of |
570 | * kern_clock.c. The real time timer is processed by a callout | | 565 | * kern_clock.c. The real time timer is processed by a callout |
571 | * routine, called from the softclock() routine. Since a callout may | | 566 | * routine, called from the softclock() routine. Since a callout may |
572 | * be delayed in real time due to interrupt processing in the system, | | 567 | * be delayed in real time due to interrupt processing in the system, |
573 | * it is possible for the real time timeout routine (realtimeexpire, | | 568 | * it is possible for the real time timeout routine (realtimeexpire, |
574 | * given below), to be delayed in real time past when it is supposed | | 569 | * given below), to be delayed in real time past when it is supposed |
575 | * to occur. It does not suffice, therefore, to reload the real timer | | 570 | * to occur. It does not suffice, therefore, to reload the real timer |
576 | * .it_value from the real time timers .it_interval. Rather, we | | 571 | * .it_value from the real time timers .it_interval. Rather, we |
577 | * compute the next time in absolute time the timer should go off. */ | | 572 | * compute the next time in absolute time the timer should go off. */ |
578 | | | 573 | |
579 | /* Allocate a POSIX realtime timer. */ | | 574 | /* Allocate a POSIX realtime timer. */ |
580 | int | | 575 | int |
581 | sys_timer_create(struct lwp *l, const struct sys_timer_create_args *uap, | | 576 | sys_timer_create(struct lwp *l, const struct sys_timer_create_args *uap, |
582 | register_t *retval) | | 577 | register_t *retval) |
583 | { | | 578 | { |
584 | /* { | | 579 | /* { |
585 | syscallarg(clockid_t) clock_id; | | 580 | syscallarg(clockid_t) clock_id; |
586 | syscallarg(struct sigevent *) evp; | | 581 | syscallarg(struct sigevent *) evp; |
587 | syscallarg(timer_t *) timerid; | | 582 | syscallarg(timer_t *) timerid; |
588 | } */ | | 583 | } */ |
589 | | | 584 | |
590 | return timer_create1(SCARG(uap, timerid), SCARG(uap, clock_id), | | 585 | return timer_create1(SCARG(uap, timerid), SCARG(uap, clock_id), |
591 | SCARG(uap, evp), copyin, l); | | 586 | SCARG(uap, evp), copyin, l); |
592 | } | | 587 | } |
593 | | | 588 | |
594 | int | | 589 | int |
595 | timer_create1(timer_t *tid, clockid_t id, struct sigevent *evp, | | 590 | timer_create1(timer_t *tid, clockid_t id, struct sigevent *evp, |
596 | copyin_t fetch_event, struct lwp *l) | | 591 | copyin_t fetch_event, struct lwp *l) |
597 | { | | 592 | { |
598 | int error; | | 593 | int error; |
599 | timer_t timerid; | | 594 | timer_t timerid; |
600 | struct ptimers *pts; | | 595 | struct ptimers *pts; |
601 | struct ptimer *pt; | | 596 | struct ptimer *pt; |
602 | struct proc *p; | | 597 | struct proc *p; |
603 | | | 598 | |
604 | p = l->l_proc; | | 599 | p = l->l_proc; |
605 | | | 600 | |
606 | if ((u_int)id > CLOCK_MONOTONIC) | | 601 | if ((u_int)id > CLOCK_MONOTONIC) |
607 | return (EINVAL); | | 602 | return (EINVAL); |
608 | | | 603 | |
609 | if ((pts = p->p_timers) == NULL) | | 604 | if ((pts = p->p_timers) == NULL) |
610 | pts = timers_alloc(p); | | 605 | pts = timers_alloc(p); |
611 | | | 606 | |
612 | pt = pool_get(&ptimer_pool, PR_WAITOK | PR_ZERO); | | 607 | pt = pool_get(&ptimer_pool, PR_WAITOK | PR_ZERO); |
613 | if (evp != NULL) { | | 608 | if (evp != NULL) { |
614 | if (((error = | | 609 | if (((error = |
615 | (*fetch_event)(evp, &pt->pt_ev, sizeof(pt->pt_ev))) != 0) || | | 610 | (*fetch_event)(evp, &pt->pt_ev, sizeof(pt->pt_ev))) != 0) || |
616 | ((pt->pt_ev.sigev_notify < SIGEV_NONE) || | | 611 | ((pt->pt_ev.sigev_notify < SIGEV_NONE) || |
617 | (pt->pt_ev.sigev_notify > SIGEV_SA)) || | | 612 | (pt->pt_ev.sigev_notify > SIGEV_SA)) || |
618 | (pt->pt_ev.sigev_notify == SIGEV_SIGNAL && | | 613 | (pt->pt_ev.sigev_notify == SIGEV_SIGNAL && |
619 | (pt->pt_ev.sigev_signo <= 0 || | | 614 | (pt->pt_ev.sigev_signo <= 0 || |
620 | pt->pt_ev.sigev_signo >= NSIG))) { | | 615 | pt->pt_ev.sigev_signo >= NSIG))) { |
621 | pool_put(&ptimer_pool, pt); | | 616 | pool_put(&ptimer_pool, pt); |
622 | return (error ? error : EINVAL); | | 617 | return (error ? error : EINVAL); |
623 | } | | 618 | } |
624 | } | | 619 | } |
625 | | | 620 | |
626 | /* Find a free timer slot, skipping those reserved for setitimer(). */ | | 621 | /* Find a free timer slot, skipping those reserved for setitimer(). */ |
627 | mutex_spin_enter(&timer_lock); | | 622 | mutex_spin_enter(&timer_lock); |
628 | for (timerid = TIMER_MIN; timerid < TIMER_MAX; timerid++) | | 623 | for (timerid = TIMER_MIN; timerid < TIMER_MAX; timerid++) |
629 | if (pts->pts_timers[timerid] == NULL) | | 624 | if (pts->pts_timers[timerid] == NULL) |
630 | break; | | 625 | break; |
631 | if (timerid == TIMER_MAX) { | | 626 | if (timerid == TIMER_MAX) { |
632 | mutex_spin_exit(&timer_lock); | | 627 | mutex_spin_exit(&timer_lock); |
633 | pool_put(&ptimer_pool, pt); | | 628 | pool_put(&ptimer_pool, pt); |
634 | return EAGAIN; | | 629 | return EAGAIN; |
635 | } | | 630 | } |
636 | if (evp == NULL) { | | 631 | if (evp == NULL) { |
637 | pt->pt_ev.sigev_notify = SIGEV_SIGNAL; | | 632 | pt->pt_ev.sigev_notify = SIGEV_SIGNAL; |
638 | switch (id) { | | 633 | switch (id) { |
639 | case CLOCK_REALTIME: | | 634 | case CLOCK_REALTIME: |
640 | case CLOCK_MONOTONIC: | | 635 | case CLOCK_MONOTONIC: |
641 | pt->pt_ev.sigev_signo = SIGALRM; | | 636 | pt->pt_ev.sigev_signo = SIGALRM; |
642 | break; | | 637 | break; |
643 | case CLOCK_VIRTUAL: | | 638 | case CLOCK_VIRTUAL: |
644 | pt->pt_ev.sigev_signo = SIGVTALRM; | | 639 | pt->pt_ev.sigev_signo = SIGVTALRM; |
645 | break; | | 640 | break; |
646 | case CLOCK_PROF: | | 641 | case CLOCK_PROF: |
647 | pt->pt_ev.sigev_signo = SIGPROF; | | 642 | pt->pt_ev.sigev_signo = SIGPROF; |
648 | break; | | 643 | break; |
649 | } | | 644 | } |
650 | pt->pt_ev.sigev_value.sival_int = timerid; | | 645 | pt->pt_ev.sigev_value.sival_int = timerid; |
651 | } | | 646 | } |
652 | pt->pt_info.ksi_signo = pt->pt_ev.sigev_signo; | | 647 | pt->pt_info.ksi_signo = pt->pt_ev.sigev_signo; |
653 | pt->pt_info.ksi_errno = 0; | | 648 | pt->pt_info.ksi_errno = 0; |
654 | pt->pt_info.ksi_code = 0; | | 649 | pt->pt_info.ksi_code = 0; |
655 | pt->pt_info.ksi_pid = p->p_pid; | | 650 | pt->pt_info.ksi_pid = p->p_pid; |
656 | pt->pt_info.ksi_uid = kauth_cred_getuid(l->l_cred); | | 651 | pt->pt_info.ksi_uid = kauth_cred_getuid(l->l_cred); |
657 | pt->pt_info.ksi_value = pt->pt_ev.sigev_value; | | 652 | pt->pt_info.ksi_value = pt->pt_ev.sigev_value; |
658 | pt->pt_type = id; | | 653 | pt->pt_type = id; |
659 | pt->pt_proc = p; | | 654 | pt->pt_proc = p; |
660 | pt->pt_overruns = 0; | | 655 | pt->pt_overruns = 0; |
661 | pt->pt_poverruns = 0; | | 656 | pt->pt_poverruns = 0; |
662 | pt->pt_entry = timerid; | | 657 | pt->pt_entry = timerid; |
663 | pt->pt_queued = false; | | 658 | pt->pt_queued = false; |
664 | timespecclear(&pt->pt_time.it_value); | | 659 | timespecclear(&pt->pt_time.it_value); |
665 | if (!CLOCK_VIRTUAL_P(id)) | | 660 | if (!CLOCK_VIRTUAL_P(id)) |
666 | callout_init(&pt->pt_ch, CALLOUT_MPSAFE); | | 661 | callout_init(&pt->pt_ch, CALLOUT_MPSAFE); |
667 | else | | 662 | else |
668 | pt->pt_active = 0; | | 663 | pt->pt_active = 0; |
669 | | | 664 | |
670 | pts->pts_timers[timerid] = pt; | | 665 | pts->pts_timers[timerid] = pt; |
671 | mutex_spin_exit(&timer_lock); | | 666 | mutex_spin_exit(&timer_lock); |
672 | | | 667 | |
673 | return copyout(&timerid, tid, sizeof(timerid)); | | 668 | return copyout(&timerid, tid, sizeof(timerid)); |
674 | } | | 669 | } |
675 | | | 670 | |
676 | /* Delete a POSIX realtime timer */ | | 671 | /* Delete a POSIX realtime timer */ |
677 | int | | 672 | int |
678 | sys_timer_delete(struct lwp *l, const struct sys_timer_delete_args *uap, | | 673 | sys_timer_delete(struct lwp *l, const struct sys_timer_delete_args *uap, |
679 | register_t *retval) | | 674 | register_t *retval) |
680 | { | | 675 | { |
681 | /* { | | 676 | /* { |
682 | syscallarg(timer_t) timerid; | | 677 | syscallarg(timer_t) timerid; |
683 | } */ | | 678 | } */ |
684 | struct proc *p = l->l_proc; | | 679 | struct proc *p = l->l_proc; |
685 | timer_t timerid; | | 680 | timer_t timerid; |
686 | struct ptimers *pts; | | 681 | struct ptimers *pts; |
687 | struct ptimer *pt, *ptn; | | 682 | struct ptimer *pt, *ptn; |
688 | | | 683 | |
689 | timerid = SCARG(uap, timerid); | | 684 | timerid = SCARG(uap, timerid); |
690 | pts = p->p_timers; | | 685 | pts = p->p_timers; |
691 | | | 686 | |
692 | if (pts == NULL || timerid < 2 || timerid >= TIMER_MAX) | | 687 | if (pts == NULL || timerid < 2 || timerid >= TIMER_MAX) |
693 | return (EINVAL); | | 688 | return (EINVAL); |
694 | | | 689 | |
695 | mutex_spin_enter(&timer_lock); | | 690 | mutex_spin_enter(&timer_lock); |
696 | if ((pt = pts->pts_timers[timerid]) == NULL) { | | 691 | if ((pt = pts->pts_timers[timerid]) == NULL) { |
697 | mutex_spin_exit(&timer_lock); | | 692 | mutex_spin_exit(&timer_lock); |
698 | return (EINVAL); | | 693 | return (EINVAL); |
699 | } | | 694 | } |
700 | if (CLOCK_VIRTUAL_P(pt->pt_type)) { | | 695 | if (CLOCK_VIRTUAL_P(pt->pt_type)) { |
701 | if (pt->pt_active) { | | 696 | if (pt->pt_active) { |
702 | ptn = LIST_NEXT(pt, pt_list); | | 697 | ptn = LIST_NEXT(pt, pt_list); |
703 | LIST_REMOVE(pt, pt_list); | | 698 | LIST_REMOVE(pt, pt_list); |
704 | for ( ; ptn; ptn = LIST_NEXT(ptn, pt_list)) | | 699 | for ( ; ptn; ptn = LIST_NEXT(ptn, pt_list)) |
705 | timespecadd(&pt->pt_time.it_value, | | 700 | timespecadd(&pt->pt_time.it_value, |
706 | &ptn->pt_time.it_value, | | 701 | &ptn->pt_time.it_value, |
707 | &ptn->pt_time.it_value); | | 702 | &ptn->pt_time.it_value); |
708 | pt->pt_active = 0; | | 703 | pt->pt_active = 0; |
709 | } | | 704 | } |
710 | } | | 705 | } |
711 | | | 706 | |
712 | /* Free the timer and release the lock. */ | | 707 | /* Free the timer and release the lock. */ |
713 | itimerfree(pts, timerid); | | 708 | itimerfree(pts, timerid); |
714 | | | 709 | |
715 | return (0); | | 710 | return (0); |
716 | } | | 711 | } |
717 | | | 712 | |
718 | /* | | 713 | /* |
719 | * Set up the given timer. The value in pt->pt_time.it_value is taken | | 714 | * Set up the given timer. The value in pt->pt_time.it_value is taken |
720 | * to be an absolute time for CLOCK_REALTIME/CLOCK_MONOTONIC timers and | | 715 | * to be an absolute time for CLOCK_REALTIME/CLOCK_MONOTONIC timers and |
721 | * a relative time for CLOCK_VIRTUAL/CLOCK_PROF timers. | | 716 | * a relative time for CLOCK_VIRTUAL/CLOCK_PROF timers. |
722 | * | | 717 | * |
723 | * If the callout had already fired but not yet run, fails with | | 718 | * If the callout had already fired but not yet run, fails with |
724 | * ERESTART -- caller must restart from the top to look up a timer. | | 719 | * ERESTART -- caller must restart from the top to look up a timer. |
725 | */ | | 720 | */ |
726 | int | | 721 | int |
727 | timer_settime(struct ptimer *pt) | | 722 | timer_settime(struct ptimer *pt) |
728 | { | | 723 | { |
729 | struct ptimer *ptn, *pptn; | | 724 | struct ptimer *ptn, *pptn; |
730 | struct ptlist *ptl; | | 725 | struct ptlist *ptl; |
731 | | | 726 | |
732 | KASSERT(mutex_owned(&timer_lock)); | | 727 | KASSERT(mutex_owned(&timer_lock)); |
733 | | | 728 | |
734 | if (!CLOCK_VIRTUAL_P(pt->pt_type)) { | | 729 | if (!CLOCK_VIRTUAL_P(pt->pt_type)) { |
735 | /* | | 730 | /* |
736 | * Try to stop the callout. However, if it had already | | 731 | * Try to stop the callout. However, if it had already |
737 | * fired, we have to drop the lock to wait for it, so | | 732 | * fired, we have to drop the lock to wait for it, so |
738 | * the world may have changed and pt may not be there | | 733 | * the world may have changed and pt may not be there |
739 | * any more. In that case, tell the caller to start | | 734 | * any more. In that case, tell the caller to start |
740 | * over from the top. | | 735 | * over from the top. |
741 | */ | | 736 | */ |
742 | if (callout_halt(&pt->pt_ch, &timer_lock)) | | 737 | if (callout_halt(&pt->pt_ch, &timer_lock)) |
743 | return ERESTART; | | 738 | return ERESTART; |
744 | | | 739 | |
745 | /* Now we can touch pt and start it up again. */ | | 740 | /* Now we can touch pt and start it up again. */ |
746 | if (timespecisset(&pt->pt_time.it_value)) { | | 741 | if (timespecisset(&pt->pt_time.it_value)) { |
747 | /* | | 742 | /* |
748 | * Don't need to check tshzto() return value, here. | | 743 | * Don't need to check tshzto() return value, here. |
749 | * callout_reset() does it for us. | | 744 | * callout_reset() does it for us. |
750 | */ | | 745 | */ |
751 | callout_reset(&pt->pt_ch, | | 746 | callout_reset(&pt->pt_ch, |
752 | pt->pt_type == CLOCK_MONOTONIC ? | | 747 | pt->pt_type == CLOCK_MONOTONIC ? |
753 | tshztoup(&pt->pt_time.it_value) : | | 748 | tshztoup(&pt->pt_time.it_value) : |
754 | tshzto(&pt->pt_time.it_value), | | 749 | tshzto(&pt->pt_time.it_value), |
755 | realtimerexpire, pt); | | 750 | realtimerexpire, pt); |
756 | } | | 751 | } |
757 | } else { | | 752 | } else { |
758 | if (pt->pt_active) { | | 753 | if (pt->pt_active) { |
759 | ptn = LIST_NEXT(pt, pt_list); | | 754 | ptn = LIST_NEXT(pt, pt_list); |
760 | LIST_REMOVE(pt, pt_list); | | 755 | LIST_REMOVE(pt, pt_list); |
761 | for ( ; ptn; ptn = LIST_NEXT(ptn, pt_list)) | | 756 | for ( ; ptn; ptn = LIST_NEXT(ptn, pt_list)) |
762 | timespecadd(&pt->pt_time.it_value, | | 757 | timespecadd(&pt->pt_time.it_value, |
763 | &ptn->pt_time.it_value, | | 758 | &ptn->pt_time.it_value, |
764 | &ptn->pt_time.it_value); | | 759 | &ptn->pt_time.it_value); |
765 | } | | 760 | } |
766 | if (timespecisset(&pt->pt_time.it_value)) { | | 761 | if (timespecisset(&pt->pt_time.it_value)) { |
767 | if (pt->pt_type == CLOCK_VIRTUAL) | | 762 | if (pt->pt_type == CLOCK_VIRTUAL) |
768 | ptl = &pt->pt_proc->p_timers->pts_virtual; | | 763 | ptl = &pt->pt_proc->p_timers->pts_virtual; |
769 | else | | 764 | else |
770 | ptl = &pt->pt_proc->p_timers->pts_prof; | | 765 | ptl = &pt->pt_proc->p_timers->pts_prof; |
771 | | | 766 | |
772 | for (ptn = LIST_FIRST(ptl), pptn = NULL; | | 767 | for (ptn = LIST_FIRST(ptl), pptn = NULL; |
773 | ptn && timespeccmp(&pt->pt_time.it_value, | | 768 | ptn && timespeccmp(&pt->pt_time.it_value, |
774 | &ptn->pt_time.it_value, >); | | 769 | &ptn->pt_time.it_value, >); |
775 | pptn = ptn, ptn = LIST_NEXT(ptn, pt_list)) | | 770 | pptn = ptn, ptn = LIST_NEXT(ptn, pt_list)) |
776 | timespecsub(&pt->pt_time.it_value, | | 771 | timespecsub(&pt->pt_time.it_value, |
777 | &ptn->pt_time.it_value, | | 772 | &ptn->pt_time.it_value, |
778 | &pt->pt_time.it_value); | | 773 | &pt->pt_time.it_value); |
779 | | | 774 | |
780 | if (pptn) | | 775 | if (pptn) |
781 | LIST_INSERT_AFTER(pptn, pt, pt_list); | | 776 | LIST_INSERT_AFTER(pptn, pt, pt_list); |
782 | else | | 777 | else |
783 | LIST_INSERT_HEAD(ptl, pt, pt_list); | | 778 | LIST_INSERT_HEAD(ptl, pt, pt_list); |
784 | | | 779 | |
785 | for ( ; ptn ; ptn = LIST_NEXT(ptn, pt_list)) | | 780 | for ( ; ptn ; ptn = LIST_NEXT(ptn, pt_list)) |
786 | timespecsub(&ptn->pt_time.it_value, | | 781 | timespecsub(&ptn->pt_time.it_value, |
787 | &pt->pt_time.it_value, | | 782 | &pt->pt_time.it_value, |
788 | &ptn->pt_time.it_value); | | 783 | &ptn->pt_time.it_value); |
789 | | | 784 | |
790 | pt->pt_active = 1; | | 785 | pt->pt_active = 1; |
791 | } else | | 786 | } else |
792 | pt->pt_active = 0; | | 787 | pt->pt_active = 0; |
793 | } | | 788 | } |
794 | | | 789 | |
795 | /* Success! */ | | 790 | /* Success! */ |
796 | return 0; | | 791 | return 0; |
797 | } | | 792 | } |
798 | | | 793 | |
799 | void | | 794 | void |
800 | timer_gettime(struct ptimer *pt, struct itimerspec *aits) | | 795 | timer_gettime(struct ptimer *pt, struct itimerspec *aits) |
801 | { | | 796 | { |
802 | struct timespec now; | | 797 | struct timespec now; |
803 | struct ptimer *ptn; | | 798 | struct ptimer *ptn; |
804 | | | 799 | |
805 | KASSERT(mutex_owned(&timer_lock)); | | 800 | KASSERT(mutex_owned(&timer_lock)); |
806 | | | 801 | |
807 | *aits = pt->pt_time; | | 802 | *aits = pt->pt_time; |
808 | if (!CLOCK_VIRTUAL_P(pt->pt_type)) { | | 803 | if (!CLOCK_VIRTUAL_P(pt->pt_type)) { |
809 | /* | | 804 | /* |
810 | * Convert from absolute to relative time in .it_value | | 805 | * Convert from absolute to relative time in .it_value |
811 | * part of real time timer. If time for real time | | 806 | * part of real time timer. If time for real time |
812 | * timer has passed return 0, else return difference | | 807 | * timer has passed return 0, else return difference |
813 | * between current time and time for the timer to go | | 808 | * between current time and time for the timer to go |
814 | * off. | | 809 | * off. |
815 | */ | | 810 | */ |
816 | if (timespecisset(&aits->it_value)) { | | 811 | if (timespecisset(&aits->it_value)) { |
817 | if (pt->pt_type == CLOCK_REALTIME) { | | 812 | if (pt->pt_type == CLOCK_REALTIME) { |
818 | getnanotime(&now); | | 813 | getnanotime(&now); |
819 | } else { /* CLOCK_MONOTONIC */ | | 814 | } else { /* CLOCK_MONOTONIC */ |
820 | getnanouptime(&now); | | 815 | getnanouptime(&now); |
821 | } | | 816 | } |
822 | if (timespeccmp(&aits->it_value, &now, <)) | | 817 | if (timespeccmp(&aits->it_value, &now, <)) |
823 | timespecclear(&aits->it_value); | | 818 | timespecclear(&aits->it_value); |
824 | else | | 819 | else |
825 | timespecsub(&aits->it_value, &now, | | 820 | timespecsub(&aits->it_value, &now, |
826 | &aits->it_value); | | 821 | &aits->it_value); |
827 | } | | 822 | } |
828 | } else if (pt->pt_active) { | | 823 | } else if (pt->pt_active) { |
829 | if (pt->pt_type == CLOCK_VIRTUAL) | | 824 | if (pt->pt_type == CLOCK_VIRTUAL) |
830 | ptn = LIST_FIRST(&pt->pt_proc->p_timers->pts_virtual); | | 825 | ptn = LIST_FIRST(&pt->pt_proc->p_timers->pts_virtual); |
831 | else | | 826 | else |
832 | ptn = LIST_FIRST(&pt->pt_proc->p_timers->pts_prof); | | 827 | ptn = LIST_FIRST(&pt->pt_proc->p_timers->pts_prof); |
833 | for ( ; ptn && ptn != pt; ptn = LIST_NEXT(ptn, pt_list)) | | 828 | for ( ; ptn && ptn != pt; ptn = LIST_NEXT(ptn, pt_list)) |
834 | timespecadd(&aits->it_value, | | 829 | timespecadd(&aits->it_value, |
835 | &ptn->pt_time.it_value, &aits->it_value); | | 830 | &ptn->pt_time.it_value, &aits->it_value); |
836 | KASSERT(ptn != NULL); /* pt should be findable on the list */ | | 831 | KASSERT(ptn != NULL); /* pt should be findable on the list */ |
837 | } else | | 832 | } else |
838 | timespecclear(&aits->it_value); | | 833 | timespecclear(&aits->it_value); |
839 | } | | 834 | } |
840 | | | 835 | |
841 | | | 836 | |
842 | | | 837 | |
843 | /* Set and arm a POSIX realtime timer */ | | 838 | /* Set and arm a POSIX realtime timer */ |
844 | int | | 839 | int |
845 | sys___timer_settime50(struct lwp *l, | | 840 | sys___timer_settime50(struct lwp *l, |
846 | const struct sys___timer_settime50_args *uap, | | 841 | const struct sys___timer_settime50_args *uap, |
847 | register_t *retval) | | 842 | register_t *retval) |
848 | { | | 843 | { |
849 | /* { | | 844 | /* { |
850 | syscallarg(timer_t) timerid; | | 845 | syscallarg(timer_t) timerid; |
851 | syscallarg(int) flags; | | 846 | syscallarg(int) flags; |
852 | syscallarg(const struct itimerspec *) value; | | 847 | syscallarg(const struct itimerspec *) value; |
853 | syscallarg(struct itimerspec *) ovalue; | | 848 | syscallarg(struct itimerspec *) ovalue; |
854 | } */ | | 849 | } */ |
855 | int error; | | 850 | int error; |
856 | struct itimerspec value, ovalue, *ovp = NULL; | | 851 | struct itimerspec value, ovalue, *ovp = NULL; |
857 | | | 852 | |
858 | if ((error = copyin(SCARG(uap, value), &value, | | 853 | if ((error = copyin(SCARG(uap, value), &value, |
859 | sizeof(struct itimerspec))) != 0) | | 854 | sizeof(struct itimerspec))) != 0) |
860 | return (error); | | 855 | return (error); |
861 | | | 856 | |
862 | if (SCARG(uap, ovalue)) | | 857 | if (SCARG(uap, ovalue)) |
863 | ovp = &ovalue; | | 858 | ovp = &ovalue; |
864 | | | 859 | |
865 | if ((error = dotimer_settime(SCARG(uap, timerid), &value, ovp, | | 860 | if ((error = dotimer_settime(SCARG(uap, timerid), &value, ovp, |
866 | SCARG(uap, flags), l->l_proc)) != 0) | | 861 | SCARG(uap, flags), l->l_proc)) != 0) |
867 | return error; | | 862 | return error; |
868 | | | 863 | |
869 | if (ovp) | | 864 | if (ovp) |
870 | return copyout(&ovalue, SCARG(uap, ovalue), | | 865 | return copyout(&ovalue, SCARG(uap, ovalue), |
871 | sizeof(struct itimerspec)); | | 866 | sizeof(struct itimerspec)); |
872 | return 0; | | 867 | return 0; |
873 | } | | 868 | } |
874 | | | 869 | |
875 | int | | 870 | int |
876 | dotimer_settime(int timerid, struct itimerspec *value, | | 871 | dotimer_settime(int timerid, struct itimerspec *value, |
877 | struct itimerspec *ovalue, int flags, struct proc *p) | | 872 | struct itimerspec *ovalue, int flags, struct proc *p) |
878 | { | | 873 | { |
879 | struct timespec now; | | 874 | struct timespec now; |
880 | struct itimerspec val, oval; | | 875 | struct itimerspec val, oval; |
881 | struct ptimers *pts; | | 876 | struct ptimers *pts; |
882 | struct ptimer *pt; | | 877 | struct ptimer *pt; |
883 | int error; | | 878 | int error; |
884 | | | 879 | |
885 | pts = p->p_timers; | | 880 | pts = p->p_timers; |
886 | | | 881 | |
887 | if (pts == NULL || timerid < 2 || timerid >= TIMER_MAX) | | 882 | if (pts == NULL || timerid < 2 || timerid >= TIMER_MAX) |
888 | return EINVAL; | | 883 | return EINVAL; |
889 | val = *value; | | 884 | val = *value; |
890 | if ((error = itimespecfix(&val.it_value)) != 0 || | | 885 | if ((error = itimespecfix(&val.it_value)) != 0 || |
891 | (error = itimespecfix(&val.it_interval)) != 0) | | 886 | (error = itimespecfix(&val.it_interval)) != 0) |
892 | return error; | | 887 | return error; |
893 | | | 888 | |
894 | mutex_spin_enter(&timer_lock); | | 889 | mutex_spin_enter(&timer_lock); |
895 | restart: | | 890 | restart: |
896 | if ((pt = pts->pts_timers[timerid]) == NULL) { | | 891 | if ((pt = pts->pts_timers[timerid]) == NULL) { |
897 | mutex_spin_exit(&timer_lock); | | 892 | mutex_spin_exit(&timer_lock); |
898 | return EINVAL; | | 893 | return EINVAL; |
899 | } | | 894 | } |
900 | | | 895 | |
901 | oval = pt->pt_time; | | 896 | oval = pt->pt_time; |
902 | pt->pt_time = val; | | 897 | pt->pt_time = val; |
903 | | | 898 | |
904 | /* | | 899 | /* |
905 | * If we've been passed a relative time for a realtime timer, | | 900 | * If we've been passed a relative time for a realtime timer, |
906 | * convert it to absolute; if an absolute time for a virtual | | 901 | * convert it to absolute; if an absolute time for a virtual |
907 | * timer, convert it to relative and make sure we don't set it | | 902 | * timer, convert it to relative and make sure we don't set it |
908 | * to zero, which would cancel the timer, or let it go | | 903 | * to zero, which would cancel the timer, or let it go |
909 | * negative, which would confuse the comparison tests. | | 904 | * negative, which would confuse the comparison tests. |
910 | */ | | 905 | */ |
911 | if (timespecisset(&pt->pt_time.it_value)) { | | 906 | if (timespecisset(&pt->pt_time.it_value)) { |
912 | if (!CLOCK_VIRTUAL_P(pt->pt_type)) { | | 907 | if (!CLOCK_VIRTUAL_P(pt->pt_type)) { |
913 | if ((flags & TIMER_ABSTIME) == 0) { | | 908 | if ((flags & TIMER_ABSTIME) == 0) { |
914 | if (pt->pt_type == CLOCK_REALTIME) { | | 909 | if (pt->pt_type == CLOCK_REALTIME) { |
915 | getnanotime(&now); | | 910 | getnanotime(&now); |
916 | } else { /* CLOCK_MONOTONIC */ | | 911 | } else { /* CLOCK_MONOTONIC */ |
917 | getnanouptime(&now); | | 912 | getnanouptime(&now); |
918 | } | | 913 | } |
919 | timespecadd(&pt->pt_time.it_value, &now, | | 914 | timespecadd(&pt->pt_time.it_value, &now, |
920 | &pt->pt_time.it_value); | | 915 | &pt->pt_time.it_value); |
921 | } | | 916 | } |
922 | } else { | | 917 | } else { |
923 | if ((flags & TIMER_ABSTIME) != 0) { | | 918 | if ((flags & TIMER_ABSTIME) != 0) { |
924 | getnanotime(&now); | | 919 | getnanotime(&now); |
925 | timespecsub(&pt->pt_time.it_value, &now, | | 920 | timespecsub(&pt->pt_time.it_value, &now, |
926 | &pt->pt_time.it_value); | | 921 | &pt->pt_time.it_value); |
927 | if (!timespecisset(&pt->pt_time.it_value) || | | 922 | if (!timespecisset(&pt->pt_time.it_value) || |
928 | pt->pt_time.it_value.tv_sec < 0) { | | 923 | pt->pt_time.it_value.tv_sec < 0) { |
929 | pt->pt_time.it_value.tv_sec = 0; | | 924 | pt->pt_time.it_value.tv_sec = 0; |
930 | pt->pt_time.it_value.tv_nsec = 1; | | 925 | pt->pt_time.it_value.tv_nsec = 1; |
931 | } | | 926 | } |
932 | } | | 927 | } |
933 | } | | 928 | } |
934 | } | | 929 | } |
935 | | | 930 | |
936 | error = timer_settime(pt); | | 931 | error = timer_settime(pt); |
937 | if (error == ERESTART) { | | 932 | if (error == ERESTART) { |
938 | KASSERT(!CLOCK_VIRTUAL_P(pt->pt_type)); | | 933 | KASSERT(!CLOCK_VIRTUAL_P(pt->pt_type)); |
939 | goto restart; | | 934 | goto restart; |
940 | } | | 935 | } |
941 | KASSERT(error == 0); | | 936 | KASSERT(error == 0); |
942 | mutex_spin_exit(&timer_lock); | | 937 | mutex_spin_exit(&timer_lock); |
943 | | | 938 | |
944 | if (ovalue) | | 939 | if (ovalue) |
945 | *ovalue = oval; | | 940 | *ovalue = oval; |
946 | | | 941 | |
947 | return (0); | | 942 | return (0); |
948 | } | | 943 | } |
949 | | | 944 | |
950 | /* Return the time remaining until a POSIX timer fires. */ | | 945 | /* Return the time remaining until a POSIX timer fires. */ |
951 | int | | 946 | int |
952 | sys___timer_gettime50(struct lwp *l, | | 947 | sys___timer_gettime50(struct lwp *l, |
953 | const struct sys___timer_gettime50_args *uap, register_t *retval) | | 948 | const struct sys___timer_gettime50_args *uap, register_t *retval) |
954 | { | | 949 | { |
955 | /* { | | 950 | /* { |
956 | syscallarg(timer_t) timerid; | | 951 | syscallarg(timer_t) timerid; |
957 | syscallarg(struct itimerspec *) value; | | 952 | syscallarg(struct itimerspec *) value; |
958 | } */ | | 953 | } */ |
959 | struct itimerspec its; | | 954 | struct itimerspec its; |
960 | int error; | | 955 | int error; |
961 | | | 956 | |
962 | if ((error = dotimer_gettime(SCARG(uap, timerid), l->l_proc, | | 957 | if ((error = dotimer_gettime(SCARG(uap, timerid), l->l_proc, |
963 | &its)) != 0) | | 958 | &its)) != 0) |
964 | return error; | | 959 | return error; |
965 | | | 960 | |
966 | return copyout(&its, SCARG(uap, value), sizeof(its)); | | 961 | return copyout(&its, SCARG(uap, value), sizeof(its)); |
967 | } | | 962 | } |
968 | | | 963 | |
969 | int | | 964 | int |
970 | dotimer_gettime(int timerid, struct proc *p, struct itimerspec *its) | | 965 | dotimer_gettime(int timerid, struct proc *p, struct itimerspec *its) |
971 | { | | 966 | { |
972 | struct ptimer *pt; | | 967 | struct ptimer *pt; |
973 | struct ptimers *pts; | | 968 | struct ptimers *pts; |
974 | | | 969 | |
975 | pts = p->p_timers; | | 970 | pts = p->p_timers; |
976 | if (pts == NULL || timerid < 2 || timerid >= TIMER_MAX) | | 971 | if (pts == NULL || timerid < 2 || timerid >= TIMER_MAX) |
977 | return (EINVAL); | | 972 | return (EINVAL); |
978 | mutex_spin_enter(&timer_lock); | | 973 | mutex_spin_enter(&timer_lock); |
979 | if ((pt = pts->pts_timers[timerid]) == NULL) { | | 974 | if ((pt = pts->pts_timers[timerid]) == NULL) { |
980 | mutex_spin_exit(&timer_lock); | | 975 | mutex_spin_exit(&timer_lock); |
981 | return (EINVAL); | | 976 | return (EINVAL); |
982 | } | | 977 | } |
983 | timer_gettime(pt, its); | | 978 | timer_gettime(pt, its); |
984 | mutex_spin_exit(&timer_lock); | | 979 | mutex_spin_exit(&timer_lock); |
985 | | | 980 | |
986 | return 0; | | 981 | return 0; |
987 | } | | 982 | } |
988 | | | 983 | |
989 | /* | | 984 | /* |
990 | * Return the count of the number of times a periodic timer expired | | 985 | * Return the count of the number of times a periodic timer expired |
991 | * while a notification was already pending. The counter is reset when | | 986 | * while a notification was already pending. The counter is reset when |
992 | * a timer expires and a notification can be posted. | | 987 | * a timer expires and a notification can be posted. |
993 | */ | | 988 | */ |
994 | int | | 989 | int |
995 | sys_timer_getoverrun(struct lwp *l, const struct sys_timer_getoverrun_args *uap, | | 990 | sys_timer_getoverrun(struct lwp *l, const struct sys_timer_getoverrun_args *uap, |
996 | register_t *retval) | | 991 | register_t *retval) |
997 | { | | 992 | { |
998 | /* { | | 993 | /* { |
999 | syscallarg(timer_t) timerid; | | 994 | syscallarg(timer_t) timerid; |
1000 | } */ | | 995 | } */ |
1001 | struct proc *p = l->l_proc; | | 996 | struct proc *p = l->l_proc; |
1002 | struct ptimers *pts; | | 997 | struct ptimers *pts; |
1003 | int timerid; | | 998 | int timerid; |
1004 | struct ptimer *pt; | | 999 | struct ptimer *pt; |
1005 | | | 1000 | |
1006 | timerid = SCARG(uap, timerid); | | 1001 | timerid = SCARG(uap, timerid); |
1007 | | | 1002 | |
1008 | pts = p->p_timers; | | 1003 | pts = p->p_timers; |
1009 | if (pts == NULL || timerid < 2 || timerid >= TIMER_MAX) | | 1004 | if (pts == NULL || timerid < 2 || timerid >= TIMER_MAX) |
1010 | return (EINVAL); | | 1005 | return (EINVAL); |
1011 | mutex_spin_enter(&timer_lock); | | 1006 | mutex_spin_enter(&timer_lock); |
1012 | if ((pt = pts->pts_timers[timerid]) == NULL) { | | 1007 | if ((pt = pts->pts_timers[timerid]) == NULL) { |
1013 | mutex_spin_exit(&timer_lock); | | 1008 | mutex_spin_exit(&timer_lock); |
1014 | return (EINVAL); | | 1009 | return (EINVAL); |
1015 | } | | 1010 | } |
1016 | *retval = pt->pt_poverruns; | | 1011 | *retval = pt->pt_poverruns; |
1017 | if (*retval >= DELAYTIMER_MAX) | | 1012 | if (*retval >= DELAYTIMER_MAX) |
1018 | *retval = DELAYTIMER_MAX; | | 1013 | *retval = DELAYTIMER_MAX; |
1019 | mutex_spin_exit(&timer_lock); | | 1014 | mutex_spin_exit(&timer_lock); |
1020 | | | 1015 | |
1021 | return (0); | | 1016 | return (0); |
1022 | } | | 1017 | } |
1023 | | | 1018 | |
1024 | /* | | 1019 | /* |
1025 | * Real interval timer expired: | | 1020 | * Real interval timer expired: |
1026 | * send process whose timer expired an alarm signal. | | 1021 | * send process whose timer expired an alarm signal. |
1027 | * If time is not set up to reload, then just return. | | 1022 | * If time is not set up to reload, then just return. |
1028 | * Else compute next time timer should go off which is > current time. | | 1023 | * Else compute next time timer should go off which is > current time. |
1029 | * This is where delay in processing this timeout causes multiple | | 1024 | * This is where delay in processing this timeout causes multiple |
1030 | * SIGALRM calls to be compressed into one. | | 1025 | * SIGALRM calls to be compressed into one. |
1031 | */ | | 1026 | */ |
1032 | void | | 1027 | void |
1033 | realtimerexpire(void *arg) | | 1028 | realtimerexpire(void *arg) |
1034 | { | | 1029 | { |
1035 | uint64_t last_val, next_val, interval, now_ns; | | 1030 | uint64_t last_val, next_val, interval, now_ns; |
1036 | struct timespec now, next; | | 1031 | struct timespec now, next; |
1037 | struct ptimer *pt; | | 1032 | struct ptimer *pt; |
1038 | int backwards; | | 1033 | int backwards; |
1039 | | | 1034 | |
1040 | pt = arg; | | 1035 | pt = arg; |
1041 | | | 1036 | |
1042 | mutex_spin_enter(&timer_lock); | | 1037 | mutex_spin_enter(&timer_lock); |
1043 | itimerfire(pt); | | 1038 | itimerfire(pt); |
1044 | | | 1039 | |
1045 | if (!timespecisset(&pt->pt_time.it_interval)) { | | 1040 | if (!timespecisset(&pt->pt_time.it_interval)) { |
1046 | timespecclear(&pt->pt_time.it_value); | | 1041 | timespecclear(&pt->pt_time.it_value); |
1047 | mutex_spin_exit(&timer_lock); | | 1042 | mutex_spin_exit(&timer_lock); |
1048 | return; | | 1043 | return; |
1049 | } | | 1044 | } |
1050 | | | 1045 | |
1051 | if (pt->pt_type == CLOCK_MONOTONIC) { | | 1046 | if (pt->pt_type == CLOCK_MONOTONIC) { |
1052 | getnanouptime(&now); | | 1047 | getnanouptime(&now); |
1053 | } else { | | 1048 | } else { |
1054 | getnanotime(&now); | | 1049 | getnanotime(&now); |
1055 | } | | 1050 | } |
1056 | backwards = (timespeccmp(&pt->pt_time.it_value, &now, >)); | | 1051 | backwards = (timespeccmp(&pt->pt_time.it_value, &now, >)); |
1057 | timespecadd(&pt->pt_time.it_value, &pt->pt_time.it_interval, &next); | | 1052 | timespecadd(&pt->pt_time.it_value, &pt->pt_time.it_interval, &next); |
1058 | /* Handle the easy case of non-overflown timers first. */ | | 1053 | /* Handle the easy case of non-overflown timers first. */ |
1059 | if (!backwards && timespeccmp(&next, &now, >)) { | | 1054 | if (!backwards && timespeccmp(&next, &now, >)) { |
1060 | pt->pt_time.it_value = next; | | 1055 | pt->pt_time.it_value = next; |
1061 | } else { | | 1056 | } else { |
1062 | now_ns = timespec2ns(&now); | | 1057 | now_ns = timespec2ns(&now); |
1063 | last_val = timespec2ns(&pt->pt_time.it_value); | | 1058 | last_val = timespec2ns(&pt->pt_time.it_value); |
1064 | interval = timespec2ns(&pt->pt_time.it_interval); | | 1059 | interval = timespec2ns(&pt->pt_time.it_interval); |
1065 | | | 1060 | |
1066 | next_val = now_ns + | | 1061 | next_val = now_ns + |
1067 | (now_ns - last_val + interval - 1) % interval; | | 1062 | (now_ns - last_val + interval - 1) % interval; |
1068 | | | 1063 | |
1069 | if (backwards) | | 1064 | if (backwards) |
1070 | next_val += interval; | | 1065 | next_val += interval; |
1071 | else | | 1066 | else |
1072 | pt->pt_overruns += (now_ns - last_val) / interval; | | 1067 | pt->pt_overruns += (now_ns - last_val) / interval; |
1073 | | | 1068 | |
1074 | pt->pt_time.it_value.tv_sec = next_val / 1000000000; | | 1069 | pt->pt_time.it_value.tv_sec = next_val / 1000000000; |
1075 | pt->pt_time.it_value.tv_nsec = next_val % 1000000000; | | 1070 | pt->pt_time.it_value.tv_nsec = next_val % 1000000000; |
1076 | } | | 1071 | } |
1077 | | | 1072 | |
1078 | /* | | 1073 | /* |
1079 | * Reset the callout, if it's not going away. | | 1074 | * Reset the callout, if it's not going away. |
1080 | * | | 1075 | * |
1081 | * Don't need to check tshzto() return value, here. | | 1076 | * Don't need to check tshzto() return value, here. |
1082 | * callout_reset() does it for us. | | 1077 | * callout_reset() does it for us. |
1083 | */ | | 1078 | */ |
1084 | if (!pt->pt_dying) | | 1079 | if (!pt->pt_dying) |
1085 | callout_reset(&pt->pt_ch, | | 1080 | callout_reset(&pt->pt_ch, |
1086 | (pt->pt_type == CLOCK_MONOTONIC | | 1081 | (pt->pt_type == CLOCK_MONOTONIC |
1087 | ? tshztoup(&pt->pt_time.it_value) | | 1082 | ? tshztoup(&pt->pt_time.it_value) |
1088 | : tshzto(&pt->pt_time.it_value)), | | 1083 | : tshzto(&pt->pt_time.it_value)), |
1089 | realtimerexpire, pt); | | 1084 | realtimerexpire, pt); |
1090 | mutex_spin_exit(&timer_lock); | | 1085 | mutex_spin_exit(&timer_lock); |
1091 | } | | 1086 | } |
1092 | | | 1087 | |
1093 | /* BSD routine to get the value of an interval timer. */ | | 1088 | /* BSD routine to get the value of an interval timer. */ |
1094 | /* ARGSUSED */ | | 1089 | /* ARGSUSED */ |
1095 | int | | 1090 | int |
1096 | sys___getitimer50(struct lwp *l, const struct sys___getitimer50_args *uap, | | 1091 | sys___getitimer50(struct lwp *l, const struct sys___getitimer50_args *uap, |
1097 | register_t *retval) | | 1092 | register_t *retval) |
1098 | { | | 1093 | { |
1099 | /* { | | 1094 | /* { |
1100 | syscallarg(int) which; | | 1095 | syscallarg(int) which; |
1101 | syscallarg(struct itimerval *) itv; | | 1096 | syscallarg(struct itimerval *) itv; |
1102 | } */ | | 1097 | } */ |
1103 | struct proc *p = l->l_proc; | | 1098 | struct proc *p = l->l_proc; |
1104 | struct itimerval aitv; | | 1099 | struct itimerval aitv; |
1105 | int error; | | 1100 | int error; |
1106 | | | 1101 | |
1107 | memset(&aitv, 0, sizeof(aitv)); | | 1102 | memset(&aitv, 0, sizeof(aitv)); |
1108 | error = dogetitimer(p, SCARG(uap, which), &aitv); | | 1103 | error = dogetitimer(p, SCARG(uap, which), &aitv); |
1109 | if (error) | | 1104 | if (error) |
1110 | return error; | | 1105 | return error; |
1111 | return (copyout(&aitv, SCARG(uap, itv), sizeof(struct itimerval))); | | 1106 | return (copyout(&aitv, SCARG(uap, itv), sizeof(struct itimerval))); |
1112 | } | | 1107 | } |
1113 | | | 1108 | |
1114 | int | | 1109 | int |
1115 | dogetitimer(struct proc *p, int which, struct itimerval *itvp) | | 1110 | dogetitimer(struct proc *p, int which, struct itimerval *itvp) |
1116 | { | | 1111 | { |
1117 | struct ptimers *pts; | | 1112 | struct ptimers *pts; |
1118 | struct ptimer *pt; | | 1113 | struct ptimer *pt; |
1119 | struct itimerspec its; | | 1114 | struct itimerspec its; |
1120 | | | 1115 | |
1121 | if ((u_int)which > ITIMER_MONOTONIC) | | 1116 | if ((u_int)which > ITIMER_MONOTONIC) |
1122 | return (EINVAL); | | 1117 | return (EINVAL); |
1123 | | | 1118 | |
1124 | mutex_spin_enter(&timer_lock); | | 1119 | mutex_spin_enter(&timer_lock); |
1125 | pts = p->p_timers; | | 1120 | pts = p->p_timers; |
1126 | if (pts == NULL || (pt = pts->pts_timers[which]) == NULL) { | | 1121 | if (pts == NULL || (pt = pts->pts_timers[which]) == NULL) { |
1127 | timerclear(&itvp->it_value); | | 1122 | timerclear(&itvp->it_value); |
1128 | timerclear(&itvp->it_interval); | | 1123 | timerclear(&itvp->it_interval); |
1129 | } else { | | 1124 | } else { |
1130 | timer_gettime(pt, &its); | | 1125 | timer_gettime(pt, &its); |
1131 | TIMESPEC_TO_TIMEVAL(&itvp->it_value, &its.it_value); | | 1126 | TIMESPEC_TO_TIMEVAL(&itvp->it_value, &its.it_value); |
1132 | TIMESPEC_TO_TIMEVAL(&itvp->it_interval, &its.it_interval); | | 1127 | TIMESPEC_TO_TIMEVAL(&itvp->it_interval, &its.it_interval); |
1133 | } | | 1128 | } |
1134 | mutex_spin_exit(&timer_lock); | | 1129 | mutex_spin_exit(&timer_lock); |
1135 | | | 1130 | |
1136 | return 0; | | 1131 | return 0; |
1137 | } | | 1132 | } |
1138 | | | 1133 | |
1139 | /* BSD routine to set/arm an interval timer. */ | | 1134 | /* BSD routine to set/arm an interval timer. */ |
1140 | /* ARGSUSED */ | | 1135 | /* ARGSUSED */ |
1141 | int | | 1136 | int |
1142 | sys___setitimer50(struct lwp *l, const struct sys___setitimer50_args *uap, | | 1137 | sys___setitimer50(struct lwp *l, const struct sys___setitimer50_args *uap, |
1143 | register_t *retval) | | 1138 | register_t *retval) |
1144 | { | | 1139 | { |
1145 | /* { | | 1140 | /* { |
1146 | syscallarg(int) which; | | 1141 | syscallarg(int) which; |
1147 | syscallarg(const struct itimerval *) itv; | | 1142 | syscallarg(const struct itimerval *) itv; |
1148 | syscallarg(struct itimerval *) oitv; | | 1143 | syscallarg(struct itimerval *) oitv; |
1149 | } */ | | 1144 | } */ |
1150 | struct proc *p = l->l_proc; | | 1145 | struct proc *p = l->l_proc; |
1151 | int which = SCARG(uap, which); | | 1146 | int which = SCARG(uap, which); |
1152 | struct sys___getitimer50_args getargs; | | 1147 | struct sys___getitimer50_args getargs; |
1153 | const struct itimerval *itvp; | | 1148 | const struct itimerval *itvp; |
1154 | struct itimerval aitv; | | 1149 | struct itimerval aitv; |
1155 | int error; | | 1150 | int error; |
1156 | | | 1151 | |
1157 | if ((u_int)which > ITIMER_MONOTONIC) | | 1152 | if ((u_int)which > ITIMER_MONOTONIC) |
1158 | return (EINVAL); | | 1153 | return (EINVAL); |
1159 | itvp = SCARG(uap, itv); | | 1154 | itvp = SCARG(uap, itv); |
1160 | if (itvp && | | 1155 | if (itvp && |
1161 | (error = copyin(itvp, &aitv, sizeof(struct itimerval))) != 0) | | 1156 | (error = copyin(itvp, &aitv, sizeof(struct itimerval))) != 0) |
1162 | return (error); | | 1157 | return (error); |
1163 | if (SCARG(uap, oitv) != NULL) { | | 1158 | if (SCARG(uap, oitv) != NULL) { |
1164 | SCARG(&getargs, which) = which; | | 1159 | SCARG(&getargs, which) = which; |