]>
Commit | Line | Data |
---|---|---|
1c79356b | 1 | /* |
b0d623f7 | 2 | * Copyright (c) 2000-2008 Apple Inc. All rights reserved. |
5d5c5d0d | 3 | * |
2d21ac55 | 4 | * @APPLE_OSREFERENCE_LICENSE_HEADER_START@ |
1c79356b | 5 | * |
2d21ac55 A |
6 | * This file contains Original Code and/or Modifications of Original Code |
7 | * as defined in and that are subject to the Apple Public Source License | |
8 | * Version 2.0 (the 'License'). You may not use this file except in | |
9 | * compliance with the License. The rights granted to you under the License | |
10 | * may not be used to create, or enable the creation or redistribution of, | |
11 | * unlawful or unlicensed copies of an Apple operating system, or to | |
12 | * circumvent, violate, or enable the circumvention or violation of, any | |
13 | * terms of an Apple operating system software license agreement. | |
8f6c56a5 | 14 | * |
2d21ac55 A |
15 | * Please obtain a copy of the License at |
16 | * http://www.opensource.apple.com/apsl/ and read it before using this file. | |
17 | * | |
18 | * The Original Code and all software distributed under the License are | |
19 | * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER | |
8f6c56a5 A |
20 | * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, |
21 | * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, | |
2d21ac55 A |
22 | * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. |
23 | * Please see the License for the specific language governing rights and | |
24 | * limitations under the License. | |
8f6c56a5 | 25 | * |
2d21ac55 | 26 | * @APPLE_OSREFERENCE_LICENSE_HEADER_END@ |
1c79356b A |
27 | */ |
28 | /* Copyright (c) 1995 NeXT Computer, Inc. All Rights Reserved */ | |
29 | /* | |
30 | * Copyright (c) 1982, 1986, 1989, 1993 | |
31 | * The Regents of the University of California. All rights reserved. | |
32 | * | |
33 | * Redistribution and use in source and binary forms, with or without | |
34 | * modification, are permitted provided that the following conditions | |
35 | * are met: | |
36 | * 1. Redistributions of source code must retain the above copyright | |
37 | * notice, this list of conditions and the following disclaimer. | |
38 | * 2. Redistributions in binary form must reproduce the above copyright | |
39 | * notice, this list of conditions and the following disclaimer in the | |
40 | * documentation and/or other materials provided with the distribution. | |
41 | * 3. All advertising materials mentioning features or use of this software | |
42 | * must display the following acknowledgement: | |
43 | * This product includes software developed by the University of | |
44 | * California, Berkeley and its contributors. | |
45 | * 4. Neither the name of the University nor the names of its contributors | |
46 | * may be used to endorse or promote products derived from this software | |
47 | * without specific prior written permission. | |
48 | * | |
49 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND | |
50 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | |
51 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | |
52 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE | |
53 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | |
54 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | |
55 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | |
56 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | |
57 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | |
58 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | |
59 | * SUCH DAMAGE. | |
60 | * | |
61 | * @(#)kern_time.c 8.4 (Berkeley) 5/26/95 | |
62 | */ | |
2d21ac55 A |
63 | /* |
64 | * NOTICE: This file was modified by SPARTA, Inc. in 2005 to introduce | |
65 | * support for mandatory and extensible security protections. This notice | |
66 | * is included in support of clause 2.2 (b) of the Apple Public License, | |
67 | * Version 2.0. | |
68 | */ | |
1c79356b A |
69 | |
70 | #include <sys/param.h> | |
71 | #include <sys/resourcevar.h> | |
72 | #include <sys/kernel.h> | |
73 | #include <sys/systm.h> | |
91447636 A |
74 | #include <sys/proc_internal.h> |
75 | #include <sys/kauth.h> | |
1c79356b | 76 | #include <sys/vnode.h> |
b0d623f7 | 77 | #include <sys/time.h> |
6d2010ae | 78 | #include <sys/priv.h> |
1c79356b | 79 | |
91447636 A |
80 | #include <sys/mount_internal.h> |
81 | #include <sys/sysproto.h> | |
82 | #include <sys/signalvar.h> | |
39236c6e | 83 | #include <sys/protosw.h> /* for net_uptime2timeval() */ |
1c79356b | 84 | |
1c79356b | 85 | #include <kern/clock.h> |
2d21ac55 | 86 | #include <kern/task.h> |
91447636 | 87 | #include <kern/thread_call.h> |
2d21ac55 A |
88 | #if CONFIG_MACF |
89 | #include <security/mac_framework.h> | |
90 | #endif | |
1c79356b A |
91 | |
92 | #define HZ 100 /* XXX */ | |
93 | ||
9bccf70c | 94 | /* simple lock used to access timezone, tz structure */ |
91447636 A |
95 | lck_spin_t * tz_slock; |
96 | lck_grp_t * tz_slock_grp; | |
97 | lck_attr_t * tz_slock_attr; | |
98 | lck_grp_attr_t *tz_slock_grp_attr; | |
99 | ||
100 | static void setthetime( | |
101 | struct timeval *tv); | |
102 | ||
39236c6e | 103 | void time_zone_slock_init(void); |
91447636 | 104 | |
39037602 | 105 | /* |
1c79356b A |
106 | * Time of day and interval timer support. |
107 | * | |
108 | * These routines provide the kernel entry points to get and set | |
109 | * the time-of-day and per-process interval timers. Subroutines | |
110 | * here provide support for adding and subtracting timeval structures | |
111 | * and decrementing interval timers, optionally reloading the interval | |
112 | * timers when they expire. | |
113 | */ | |
1c79356b A |
114 | /* ARGSUSED */ |
115 | int | |
0c530ab8 | 116 | gettimeofday( |
39037602 A |
117 | struct proc *p, |
118 | struct gettimeofday_args *uap, | |
119 | __unused int32_t *retval) | |
1c79356b | 120 | { |
1c79356b | 121 | int error = 0; |
9bccf70c | 122 | struct timezone ltz; /* local copy */ |
39037602 A |
123 | clock_sec_t secs; |
124 | clock_usec_t usecs; | |
125 | uint64_t mach_time; | |
9bccf70c | 126 | |
39037602 A |
127 | if (uap->tp || uap->mach_absolute_time) { |
128 | clock_gettimeofday_and_absolute_time(&secs, &usecs, &mach_time); | |
129 | } | |
b0d623f7 | 130 | |
39037602 A |
131 | if (uap->tp) { |
132 | /* Casting secs through a uint32_t to match arm64 commpage */ | |
133 | if (IS_64BIT_PROCESS(p)) { | |
134 | struct user64_timeval user_atv = {}; | |
135 | user_atv.tv_sec = (uint32_t)secs; | |
136 | user_atv.tv_usec = usecs; | |
137 | error = copyout(&user_atv, uap->tp, sizeof(user_atv)); | |
138 | } else { | |
139 | struct user32_timeval user_atv = {}; | |
140 | user_atv.tv_sec = (uint32_t)secs; | |
141 | user_atv.tv_usec = usecs; | |
142 | error = copyout(&user_atv, uap->tp, sizeof(user_atv)); | |
143 | } | |
144 | if (error) { | |
145 | return error; | |
146 | } | |
b0d623f7 | 147 | } |
39037602 | 148 | |
9bccf70c | 149 | if (uap->tzp) { |
91447636 | 150 | lck_spin_lock(tz_slock); |
9bccf70c | 151 | ltz = tz; |
91447636 | 152 | lck_spin_unlock(tz_slock); |
0c530ab8 | 153 | |
39037602 | 154 | error = copyout((caddr_t)<z, CAST_USER_ADDR_T(uap->tzp), sizeof(tz)); |
9bccf70c | 155 | } |
1c79356b | 156 | |
39037602 A |
157 | if (error == 0 && uap->mach_absolute_time) { |
158 | error = copyout(&mach_time, uap->mach_absolute_time, sizeof(mach_time)); | |
159 | } | |
160 | ||
161 | return error; | |
1c79356b A |
162 | } |
163 | ||
91447636 A |
164 | /* |
165 | * XXX Y2038 bug because of setthetime() argument | |
166 | */ | |
1c79356b A |
167 | /* ARGSUSED */ |
168 | int | |
b0d623f7 | 169 | settimeofday(__unused struct proc *p, struct settimeofday_args *uap, __unused int32_t *retval) |
1c79356b A |
170 | { |
171 | struct timeval atv; | |
172 | struct timezone atz; | |
91447636 | 173 | int error; |
1c79356b | 174 | |
b0d623f7 A |
175 | bzero(&atv, sizeof(atv)); |
176 | ||
2d21ac55 A |
177 | #if CONFIG_MACF |
178 | error = mac_system_check_settime(kauth_cred_get()); | |
179 | if (error) | |
180 | return (error); | |
181 | #endif | |
91447636 | 182 | if ((error = suser(kauth_cred_get(), &p->p_acflag))) |
1c79356b | 183 | return (error); |
91447636 A |
184 | /* Verify all parameters before changing time */ |
185 | if (uap->tv) { | |
186 | if (IS_64BIT_PROCESS(p)) { | |
b0d623f7 A |
187 | struct user64_timeval user_atv; |
188 | error = copyin(uap->tv, &user_atv, sizeof(user_atv)); | |
91447636 A |
189 | atv.tv_sec = user_atv.tv_sec; |
190 | atv.tv_usec = user_atv.tv_usec; | |
191 | } else { | |
b0d623f7 A |
192 | struct user32_timeval user_atv; |
193 | error = copyin(uap->tv, &user_atv, sizeof(user_atv)); | |
194 | atv.tv_sec = user_atv.tv_sec; | |
195 | atv.tv_usec = user_atv.tv_usec; | |
91447636 A |
196 | } |
197 | if (error) | |
198 | return (error); | |
199 | } | |
200 | if (uap->tzp && (error = copyin(uap->tzp, (caddr_t)&atz, sizeof(atz)))) | |
1c79356b | 201 | return (error); |
91447636 A |
202 | if (uap->tv) { |
203 | timevalfix(&atv); | |
204 | if (atv.tv_sec < 0 || (atv.tv_sec == 0 && atv.tv_usec < 0)) | |
205 | return (EPERM); | |
1c79356b | 206 | setthetime(&atv); |
91447636 | 207 | } |
9bccf70c | 208 | if (uap->tzp) { |
91447636 | 209 | lck_spin_lock(tz_slock); |
1c79356b | 210 | tz = atz; |
91447636 | 211 | lck_spin_unlock(tz_slock); |
9bccf70c | 212 | } |
1c79356b A |
213 | return (0); |
214 | } | |
215 | ||
91447636 A |
216 | static void |
217 | setthetime( | |
218 | struct timeval *tv) | |
1c79356b | 219 | { |
55e303ae | 220 | clock_set_calendar_microtime(tv->tv_sec, tv->tv_usec); |
1c79356b A |
221 | } |
222 | ||
91447636 A |
223 | /* |
224 | * XXX Y2038 bug because of clock_adjtime() first argument | |
225 | */ | |
1c79356b A |
226 | /* ARGSUSED */ |
227 | int | |
b0d623f7 | 228 | adjtime(struct proc *p, struct adjtime_args *uap, __unused int32_t *retval) |
1c79356b | 229 | { |
9bccf70c | 230 | struct timeval atv; |
9bccf70c | 231 | int error; |
1c79356b | 232 | |
2d21ac55 A |
233 | #if CONFIG_MACF |
234 | error = mac_system_check_settime(kauth_cred_get()); | |
235 | if (error) | |
236 | return (error); | |
237 | #endif | |
6d2010ae | 238 | if ((error = priv_check_cred(kauth_cred_get(), PRIV_ADJTIME, 0))) |
1c79356b | 239 | return (error); |
91447636 | 240 | if (IS_64BIT_PROCESS(p)) { |
b0d623f7 A |
241 | struct user64_timeval user_atv; |
242 | error = copyin(uap->delta, &user_atv, sizeof(user_atv)); | |
91447636 A |
243 | atv.tv_sec = user_atv.tv_sec; |
244 | atv.tv_usec = user_atv.tv_usec; | |
245 | } else { | |
b0d623f7 A |
246 | struct user32_timeval user_atv; |
247 | error = copyin(uap->delta, &user_atv, sizeof(user_atv)); | |
248 | atv.tv_sec = user_atv.tv_sec; | |
249 | atv.tv_usec = user_atv.tv_usec; | |
91447636 A |
250 | } |
251 | if (error) | |
9bccf70c | 252 | return (error); |
1c79356b | 253 | |
91447636 A |
254 | /* |
255 | * Compute the total correction and the rate at which to apply it. | |
256 | */ | |
b0d623f7 | 257 | clock_adjtime(&atv.tv_sec, &atv.tv_usec); |
1c79356b | 258 | |
1c79356b | 259 | if (uap->olddelta) { |
91447636 | 260 | if (IS_64BIT_PROCESS(p)) { |
b0d623f7 | 261 | struct user64_timeval user_atv; |
91447636 A |
262 | user_atv.tv_sec = atv.tv_sec; |
263 | user_atv.tv_usec = atv.tv_usec; | |
b0d623f7 | 264 | error = copyout(&user_atv, uap->olddelta, sizeof(user_atv)); |
91447636 | 265 | } else { |
b0d623f7 A |
266 | struct user32_timeval user_atv; |
267 | user_atv.tv_sec = atv.tv_sec; | |
268 | user_atv.tv_usec = atv.tv_usec; | |
269 | error = copyout(&user_atv, uap->olddelta, sizeof(user_atv)); | |
91447636 | 270 | } |
1c79356b | 271 | } |
1c79356b | 272 | |
9bccf70c | 273 | return (0); |
1c79356b A |
274 | } |
275 | ||
1c79356b | 276 | /* |
91447636 A |
277 | * Verify the calendar value. If negative, |
278 | * reset to zero (the epoch). | |
1c79356b A |
279 | */ |
280 | void | |
91447636 A |
281 | inittodr( |
282 | __unused time_t base) | |
1c79356b | 283 | { |
55e303ae A |
284 | struct timeval tv; |
285 | ||
1c79356b | 286 | /* |
0b4e3aa0 A |
287 | * Assertion: |
288 | * The calendar has already been | |
91447636 | 289 | * set up from the platform clock. |
0b4e3aa0 | 290 | * |
1c79356b A |
291 | * The value returned by microtime() |
292 | * is gotten from the calendar. | |
293 | */ | |
55e303ae | 294 | microtime(&tv); |
1c79356b | 295 | |
91447636 | 296 | if (tv.tv_sec < 0 || tv.tv_usec < 0) { |
1c79356b | 297 | printf ("WARNING: preposterous time in Real Time Clock"); |
91447636 A |
298 | tv.tv_sec = 0; /* the UNIX epoch */ |
299 | tv.tv_usec = 0; | |
300 | setthetime(&tv); | |
1c79356b A |
301 | printf(" -- CHECK AND RESET THE DATE!\n"); |
302 | } | |
1c79356b A |
303 | } |
304 | ||
91447636 A |
305 | time_t |
306 | boottime_sec(void) | |
307 | { | |
b0d623f7 A |
308 | clock_sec_t secs; |
309 | clock_nsec_t nanosecs; | |
9bccf70c | 310 | |
b0d623f7 A |
311 | clock_get_boottime_nanotime(&secs, &nanosecs); |
312 | return (secs); | |
313 | } | |
9bccf70c | 314 | |
39037602 A |
315 | void |
316 | boottime_timeval(struct timeval *tv) | |
317 | { | |
318 | clock_sec_t secs; | |
319 | clock_usec_t microsecs; | |
320 | ||
321 | clock_get_boottime_microtime(&secs, µsecs); | |
322 | ||
323 | tv->tv_sec = secs; | |
324 | tv->tv_usec = microsecs; | |
325 | } | |
326 | ||
1c79356b A |
327 | /* |
328 | * Get value of an interval timer. The process virtual and | |
9bccf70c | 329 | * profiling virtual time timers are kept internally in the |
1c79356b A |
330 | * way they are specified externally: in time until they expire. |
331 | * | |
9bccf70c A |
332 | * The real time interval timer expiration time (p_rtime) |
333 | * is kept as an absolute time rather than as a delta, so that | |
334 | * it is easy to keep periodic real-time signals from drifting. | |
1c79356b | 335 | * |
2d21ac55 A |
336 | * The real time timer is processed by a callout routine. |
337 | * Since a callout may be delayed in real time due to | |
9bccf70c A |
338 | * other processing in the system, it is possible for the real |
339 | * time callout routine (realitexpire, given below), to be delayed | |
340 | * in real time past when it is supposed to occur. It does not | |
341 | * suffice, therefore, to reload the real time .it_value from the | |
342 | * real time .it_interval. Rather, we compute the next time in | |
343 | * absolute time when the timer should go off. | |
2d21ac55 A |
344 | * |
345 | * Returns: 0 Success | |
346 | * EINVAL Invalid argument | |
347 | * copyout:EFAULT Bad address | |
1c79356b | 348 | */ |
1c79356b A |
349 | /* ARGSUSED */ |
350 | int | |
b0d623f7 | 351 | getitimer(struct proc *p, struct getitimer_args *uap, __unused int32_t *retval) |
1c79356b A |
352 | { |
353 | struct itimerval aitv; | |
1c79356b A |
354 | |
355 | if (uap->which > ITIMER_PROF) | |
356 | return(EINVAL); | |
2d21ac55 | 357 | |
b0d623f7 A |
358 | bzero(&aitv, sizeof(aitv)); |
359 | ||
2d21ac55 A |
360 | proc_spinlock(p); |
361 | switch (uap->which) { | |
362 | ||
363 | case ITIMER_REAL: | |
1c79356b | 364 | /* |
9bccf70c A |
365 | * If time for real time timer has passed return 0, |
366 | * else return difference between current time and | |
367 | * time for the timer to go off. | |
1c79356b A |
368 | */ |
369 | aitv = p->p_realtimer; | |
9bccf70c A |
370 | if (timerisset(&p->p_rtime)) { |
371 | struct timeval now; | |
372 | ||
373 | microuptime(&now); | |
374 | if (timercmp(&p->p_rtime, &now, <)) | |
1c79356b | 375 | timerclear(&aitv.it_value); |
9bccf70c A |
376 | else { |
377 | aitv.it_value = p->p_rtime; | |
378 | timevalsub(&aitv.it_value, &now); | |
379 | } | |
380 | } | |
381 | else | |
382 | timerclear(&aitv.it_value); | |
2d21ac55 A |
383 | break; |
384 | ||
385 | case ITIMER_VIRTUAL: | |
386 | aitv = p->p_vtimer_user; | |
387 | break; | |
388 | ||
389 | case ITIMER_PROF: | |
390 | aitv = p->p_vtimer_prof; | |
391 | break; | |
9bccf70c | 392 | } |
2d21ac55 A |
393 | |
394 | proc_spinunlock(p); | |
9bccf70c | 395 | |
91447636 | 396 | if (IS_64BIT_PROCESS(p)) { |
b0d623f7 | 397 | struct user64_itimerval user_itv; |
d190cdc3 | 398 | bzero(&user_itv, sizeof (user_itv)); |
91447636 A |
399 | user_itv.it_interval.tv_sec = aitv.it_interval.tv_sec; |
400 | user_itv.it_interval.tv_usec = aitv.it_interval.tv_usec; | |
401 | user_itv.it_value.tv_sec = aitv.it_value.tv_sec; | |
402 | user_itv.it_value.tv_usec = aitv.it_value.tv_usec; | |
b0d623f7 | 403 | return (copyout((caddr_t)&user_itv, uap->itv, sizeof (user_itv))); |
91447636 | 404 | } else { |
b0d623f7 | 405 | struct user32_itimerval user_itv; |
d190cdc3 | 406 | bzero(&user_itv, sizeof (user_itv)); |
b0d623f7 A |
407 | user_itv.it_interval.tv_sec = aitv.it_interval.tv_sec; |
408 | user_itv.it_interval.tv_usec = aitv.it_interval.tv_usec; | |
409 | user_itv.it_value.tv_sec = aitv.it_value.tv_sec; | |
410 | user_itv.it_value.tv_usec = aitv.it_value.tv_usec; | |
411 | return (copyout((caddr_t)&user_itv, uap->itv, sizeof (user_itv))); | |
91447636 | 412 | } |
1c79356b A |
413 | } |
414 | ||
2d21ac55 A |
415 | /* |
416 | * Returns: 0 Success | |
417 | * EINVAL Invalid argument | |
418 | * copyin:EFAULT Bad address | |
419 | * getitimer:EINVAL Invalid argument | |
420 | * getitimer:EFAULT Bad address | |
421 | */ | |
1c79356b A |
422 | /* ARGSUSED */ |
423 | int | |
b0d623f7 | 424 | setitimer(struct proc *p, struct setitimer_args *uap, int32_t *retval) |
1c79356b A |
425 | { |
426 | struct itimerval aitv; | |
91447636 | 427 | user_addr_t itvp; |
9bccf70c | 428 | int error; |
1c79356b | 429 | |
b0d623f7 A |
430 | bzero(&aitv, sizeof(aitv)); |
431 | ||
1c79356b | 432 | if (uap->which > ITIMER_PROF) |
9bccf70c | 433 | return (EINVAL); |
91447636 A |
434 | if ((itvp = uap->itv)) { |
435 | if (IS_64BIT_PROCESS(p)) { | |
b0d623f7 A |
436 | struct user64_itimerval user_itv; |
437 | if ((error = copyin(itvp, (caddr_t)&user_itv, sizeof (user_itv)))) | |
91447636 A |
438 | return (error); |
439 | aitv.it_interval.tv_sec = user_itv.it_interval.tv_sec; | |
440 | aitv.it_interval.tv_usec = user_itv.it_interval.tv_usec; | |
441 | aitv.it_value.tv_sec = user_itv.it_value.tv_sec; | |
442 | aitv.it_value.tv_usec = user_itv.it_value.tv_usec; | |
443 | } else { | |
b0d623f7 A |
444 | struct user32_itimerval user_itv; |
445 | if ((error = copyin(itvp, (caddr_t)&user_itv, sizeof (user_itv)))) | |
91447636 | 446 | return (error); |
b0d623f7 A |
447 | aitv.it_interval.tv_sec = user_itv.it_interval.tv_sec; |
448 | aitv.it_interval.tv_usec = user_itv.it_interval.tv_usec; | |
449 | aitv.it_value.tv_sec = user_itv.it_value.tv_sec; | |
450 | aitv.it_value.tv_usec = user_itv.it_value.tv_usec; | |
91447636 A |
451 | } |
452 | } | |
453 | if ((uap->itv = uap->oitv) && (error = getitimer(p, (struct getitimer_args *)uap, retval))) | |
1c79356b A |
454 | return (error); |
455 | if (itvp == 0) | |
456 | return (0); | |
457 | if (itimerfix(&aitv.it_value) || itimerfix(&aitv.it_interval)) | |
458 | return (EINVAL); | |
2d21ac55 A |
459 | |
460 | switch (uap->which) { | |
461 | ||
462 | case ITIMER_REAL: | |
463 | proc_spinlock(p); | |
1c79356b | 464 | if (timerisset(&aitv.it_value)) { |
9bccf70c A |
465 | microuptime(&p->p_rtime); |
466 | timevaladd(&p->p_rtime, &aitv.it_value); | |
2d21ac55 | 467 | p->p_realtimer = aitv; |
39236c6e A |
468 | if (!thread_call_enter_delayed_with_leeway(p->p_rcall, NULL, |
469 | tvtoabstime(&p->p_rtime), 0, THREAD_CALL_DELAY_USER_NORMAL)) | |
2d21ac55 A |
470 | p->p_ractive++; |
471 | } else { | |
472 | timerclear(&p->p_rtime); | |
473 | p->p_realtimer = aitv; | |
474 | if (thread_call_cancel(p->p_rcall)) | |
475 | p->p_ractive--; | |
1c79356b | 476 | } |
2d21ac55 A |
477 | proc_spinunlock(p); |
478 | ||
479 | break; | |
480 | ||
481 | ||
482 | case ITIMER_VIRTUAL: | |
483 | if (timerisset(&aitv.it_value)) | |
484 | task_vtimer_set(p->task, TASK_VTIMER_USER); | |
485 | else | |
486 | task_vtimer_clear(p->task, TASK_VTIMER_USER); | |
487 | ||
488 | proc_spinlock(p); | |
489 | p->p_vtimer_user = aitv; | |
490 | proc_spinunlock(p); | |
491 | break; | |
492 | ||
493 | case ITIMER_PROF: | |
494 | if (timerisset(&aitv.it_value)) | |
495 | task_vtimer_set(p->task, TASK_VTIMER_PROF); | |
9bccf70c | 496 | else |
2d21ac55 | 497 | task_vtimer_clear(p->task, TASK_VTIMER_PROF); |
9bccf70c | 498 | |
2d21ac55 A |
499 | proc_spinlock(p); |
500 | p->p_vtimer_prof = aitv; | |
501 | proc_spinunlock(p); | |
502 | break; | |
9bccf70c | 503 | } |
9bccf70c A |
504 | |
505 | return (0); | |
1c79356b A |
506 | } |
507 | ||
508 | /* | |
509 | * Real interval timer expired: | |
510 | * send process whose timer expired an alarm signal. | |
511 | * If time is not set up to reload, then just return. | |
512 | * Else compute next time timer should go off which is > current time. | |
513 | * This is where delay in processing this timeout causes multiple | |
514 | * SIGALRM calls to be compressed into one. | |
515 | */ | |
516 | void | |
9bccf70c | 517 | realitexpire( |
39037602 | 518 | struct proc *p) |
1c79356b | 519 | { |
2d21ac55 | 520 | struct proc *r; |
39037602 | 521 | struct timeval t; |
2d21ac55 A |
522 | |
523 | r = proc_find(p->p_pid); | |
524 | ||
525 | proc_spinlock(p); | |
526 | ||
39037602 A |
527 | assert(p->p_ractive > 0); |
528 | ||
2d21ac55 | 529 | if (--p->p_ractive > 0 || r != p) { |
39037602 A |
530 | /* |
531 | * bail, because either proc is exiting | |
532 | * or there's another active thread call | |
533 | */ | |
2d21ac55 A |
534 | proc_spinunlock(p); |
535 | ||
536 | if (r != NULL) | |
537 | proc_rele(r); | |
1c79356b A |
538 | return; |
539 | } | |
39037602 | 540 | |
9bccf70c | 541 | if (!timerisset(&p->p_realtimer.it_interval)) { |
39037602 A |
542 | /* |
543 | * p_realtimer was cleared while this call was pending, | |
544 | * send one last SIGALRM, but don't re-arm | |
545 | */ | |
9bccf70c | 546 | timerclear(&p->p_rtime); |
2d21ac55 | 547 | proc_spinunlock(p); |
9bccf70c | 548 | |
2d21ac55 A |
549 | psignal(p, SIGALRM); |
550 | proc_rele(p); | |
1c79356b | 551 | return; |
1c79356b | 552 | } |
9bccf70c | 553 | |
39037602 A |
554 | proc_spinunlock(p); |
555 | ||
556 | /* | |
557 | * Send the signal before re-arming the next thread call, | |
558 | * so in case psignal blocks, we won't create yet another thread call. | |
559 | */ | |
560 | ||
561 | psignal(p, SIGALRM); | |
562 | ||
563 | proc_spinlock(p); | |
564 | ||
565 | /* Should we still re-arm the next thread call? */ | |
566 | if (!timerisset(&p->p_realtimer.it_interval)) { | |
567 | timerclear(&p->p_rtime); | |
568 | proc_spinunlock(p); | |
569 | ||
570 | proc_rele(p); | |
571 | return; | |
572 | } | |
573 | ||
2d21ac55 | 574 | microuptime(&t); |
9bccf70c | 575 | timevaladd(&p->p_rtime, &p->p_realtimer.it_interval); |
39037602 | 576 | |
2d21ac55 A |
577 | if (timercmp(&p->p_rtime, &t, <=)) { |
578 | if ((p->p_rtime.tv_sec + 2) >= t.tv_sec) { | |
9bccf70c A |
579 | for (;;) { |
580 | timevaladd(&p->p_rtime, &p->p_realtimer.it_interval); | |
2d21ac55 | 581 | if (timercmp(&p->p_rtime, &t, >)) |
9bccf70c A |
582 | break; |
583 | } | |
39037602 | 584 | } else { |
9bccf70c | 585 | p->p_rtime = p->p_realtimer.it_interval; |
2d21ac55 | 586 | timevaladd(&p->p_rtime, &t); |
1c79356b | 587 | } |
1c79356b | 588 | } |
9bccf70c | 589 | |
39037602 A |
590 | assert(p->p_rcall != NULL); |
591 | ||
592 | if (!thread_call_enter_delayed_with_leeway(p->p_rcall, NULL, tvtoabstime(&p->p_rtime), 0, | |
593 | THREAD_CALL_DELAY_USER_NORMAL)) { | |
2d21ac55 | 594 | p->p_ractive++; |
39037602 A |
595 | } |
596 | ||
2d21ac55 | 597 | proc_spinunlock(p); |
55e303ae | 598 | |
2d21ac55 | 599 | proc_rele(p); |
1c79356b A |
600 | } |
601 | ||
39037602 A |
602 | /* |
603 | * Called once in proc_exit to clean up after an armed or pending realitexpire | |
604 | * | |
605 | * This will only be called after the proc refcount is drained, | |
606 | * so realitexpire cannot be currently holding a proc ref. | |
607 | * i.e. it will/has gotten PROC_NULL from proc_find. | |
608 | */ | |
609 | void | |
610 | proc_free_realitimer(proc_t p) | |
611 | { | |
612 | proc_spinlock(p); | |
613 | ||
614 | assert(p->p_rcall != NULL); | |
615 | assert(p->p_refcount == 0); | |
616 | ||
617 | timerclear(&p->p_realtimer.it_interval); | |
618 | ||
619 | if (thread_call_cancel(p->p_rcall)) { | |
620 | assert(p->p_ractive > 0); | |
621 | p->p_ractive--; | |
622 | } | |
623 | ||
624 | while (p->p_ractive > 0) { | |
625 | proc_spinunlock(p); | |
626 | ||
627 | delay(1); | |
628 | ||
629 | proc_spinlock(p); | |
630 | } | |
631 | ||
632 | thread_call_t call = p->p_rcall; | |
633 | p->p_rcall = NULL; | |
634 | ||
635 | proc_spinunlock(p); | |
636 | ||
637 | thread_call_free(call); | |
638 | } | |
639 | ||
1c79356b A |
640 | /* |
641 | * Check that a proposed value to load into the .it_value or | |
2d21ac55 | 642 | * .it_interval part of an interval timer is acceptable. |
1c79356b A |
643 | */ |
644 | int | |
2d21ac55 A |
645 | itimerfix( |
646 | struct timeval *tv) | |
1c79356b A |
647 | { |
648 | ||
649 | if (tv->tv_sec < 0 || tv->tv_sec > 100000000 || | |
650 | tv->tv_usec < 0 || tv->tv_usec >= 1000000) | |
651 | return (EINVAL); | |
1c79356b A |
652 | return (0); |
653 | } | |
654 | ||
4bd07ac2 A |
655 | int |
656 | timespec_is_valid(const struct timespec *ts) | |
657 | { | |
658 | /* The INT32_MAX limit ensures the timespec is safe for clock_*() functions | |
659 | * which accept 32-bit ints. */ | |
660 | if (ts->tv_sec < 0 || ts->tv_sec > INT32_MAX || | |
661 | ts->tv_nsec < 0 || (unsigned long long)ts->tv_nsec > NSEC_PER_SEC) { | |
662 | return 0; | |
663 | } | |
664 | return 1; | |
665 | } | |
666 | ||
1c79356b A |
667 | /* |
668 | * Decrement an interval timer by a specified number | |
669 | * of microseconds, which must be less than a second, | |
670 | * i.e. < 1000000. If the timer expires, then reload | |
671 | * it. In this case, carry over (usec - old value) to | |
2d21ac55 | 672 | * reduce the value reloaded into the timer so that |
1c79356b A |
673 | * the timer does not drift. This routine assumes |
674 | * that it is called in a context where the timers | |
675 | * on which it is operating cannot change in value. | |
676 | */ | |
677 | int | |
2d21ac55 A |
678 | itimerdecr(proc_t p, |
679 | struct itimerval *itp, int usec) | |
1c79356b A |
680 | { |
681 | ||
2d21ac55 A |
682 | proc_spinlock(p); |
683 | ||
1c79356b A |
684 | if (itp->it_value.tv_usec < usec) { |
685 | if (itp->it_value.tv_sec == 0) { | |
686 | /* expired, and already in next interval */ | |
687 | usec -= itp->it_value.tv_usec; | |
688 | goto expire; | |
689 | } | |
690 | itp->it_value.tv_usec += 1000000; | |
691 | itp->it_value.tv_sec--; | |
692 | } | |
693 | itp->it_value.tv_usec -= usec; | |
694 | usec = 0; | |
2d21ac55 A |
695 | if (timerisset(&itp->it_value)) { |
696 | proc_spinunlock(p); | |
1c79356b | 697 | return (1); |
2d21ac55 | 698 | } |
1c79356b A |
699 | /* expired, exactly at end of interval */ |
700 | expire: | |
701 | if (timerisset(&itp->it_interval)) { | |
702 | itp->it_value = itp->it_interval; | |
2d21ac55 | 703 | if (itp->it_value.tv_sec > 0) { |
1c79356b A |
704 | itp->it_value.tv_usec -= usec; |
705 | if (itp->it_value.tv_usec < 0) { | |
706 | itp->it_value.tv_usec += 1000000; | |
707 | itp->it_value.tv_sec--; | |
2d21ac55 | 708 | } |
1c79356b A |
709 | } |
710 | } else | |
711 | itp->it_value.tv_usec = 0; /* sec is already 0 */ | |
2d21ac55 | 712 | proc_spinunlock(p); |
1c79356b A |
713 | return (0); |
714 | } | |
715 | ||
716 | /* | |
717 | * Add and subtract routines for timevals. | |
718 | * N.B.: subtract routine doesn't deal with | |
719 | * results which are before the beginning, | |
720 | * it just gets very confused in this case. | |
721 | * Caveat emptor. | |
722 | */ | |
723 | void | |
9bccf70c A |
724 | timevaladd( |
725 | struct timeval *t1, | |
726 | struct timeval *t2) | |
1c79356b A |
727 | { |
728 | ||
729 | t1->tv_sec += t2->tv_sec; | |
730 | t1->tv_usec += t2->tv_usec; | |
731 | timevalfix(t1); | |
732 | } | |
733 | void | |
9bccf70c A |
734 | timevalsub( |
735 | struct timeval *t1, | |
736 | struct timeval *t2) | |
1c79356b A |
737 | { |
738 | ||
739 | t1->tv_sec -= t2->tv_sec; | |
740 | t1->tv_usec -= t2->tv_usec; | |
741 | timevalfix(t1); | |
742 | } | |
743 | void | |
9bccf70c A |
744 | timevalfix( |
745 | struct timeval *t1) | |
1c79356b A |
746 | { |
747 | ||
748 | if (t1->tv_usec < 0) { | |
749 | t1->tv_sec--; | |
750 | t1->tv_usec += 1000000; | |
751 | } | |
752 | if (t1->tv_usec >= 1000000) { | |
753 | t1->tv_sec++; | |
754 | t1->tv_usec -= 1000000; | |
755 | } | |
756 | } | |
757 | ||
758 | /* | |
759 | * Return the best possible estimate of the time in the timeval | |
760 | * to which tvp points. | |
761 | */ | |
762 | void | |
9bccf70c A |
763 | microtime( |
764 | struct timeval *tvp) | |
1c79356b | 765 | { |
b0d623f7 A |
766 | clock_sec_t tv_sec; |
767 | clock_usec_t tv_usec; | |
768 | ||
769 | clock_get_calendar_microtime(&tv_sec, &tv_usec); | |
770 | ||
771 | tvp->tv_sec = tv_sec; | |
772 | tvp->tv_usec = tv_usec; | |
1c79356b | 773 | } |
9bccf70c | 774 | |
39236c6e A |
775 | void |
776 | microtime_with_abstime( | |
777 | struct timeval *tvp, uint64_t *abstime) | |
778 | { | |
779 | clock_sec_t tv_sec; | |
780 | clock_usec_t tv_usec; | |
781 | ||
782 | clock_get_calendar_absolute_and_microtime(&tv_sec, &tv_usec, abstime); | |
783 | ||
784 | tvp->tv_sec = tv_sec; | |
785 | tvp->tv_usec = tv_usec; | |
786 | } | |
787 | ||
9bccf70c A |
788 | void |
789 | microuptime( | |
790 | struct timeval *tvp) | |
791 | { | |
b0d623f7 A |
792 | clock_sec_t tv_sec; |
793 | clock_usec_t tv_usec; | |
794 | ||
795 | clock_get_system_microtime(&tv_sec, &tv_usec); | |
796 | ||
797 | tvp->tv_sec = tv_sec; | |
798 | tvp->tv_usec = tv_usec; | |
9bccf70c A |
799 | } |
800 | ||
801 | /* | |
802 | * Ditto for timespec. | |
803 | */ | |
804 | void | |
805 | nanotime( | |
806 | struct timespec *tsp) | |
807 | { | |
b0d623f7 A |
808 | clock_sec_t tv_sec; |
809 | clock_nsec_t tv_nsec; | |
810 | ||
811 | clock_get_calendar_nanotime(&tv_sec, &tv_nsec); | |
812 | ||
813 | tsp->tv_sec = tv_sec; | |
814 | tsp->tv_nsec = tv_nsec; | |
9bccf70c A |
815 | } |
816 | ||
817 | void | |
818 | nanouptime( | |
819 | struct timespec *tsp) | |
820 | { | |
b0d623f7 A |
821 | clock_sec_t tv_sec; |
822 | clock_nsec_t tv_nsec; | |
823 | ||
824 | clock_get_system_nanotime(&tv_sec, &tv_nsec); | |
825 | ||
826 | tsp->tv_sec = tv_sec; | |
827 | tsp->tv_nsec = tv_nsec; | |
9bccf70c A |
828 | } |
829 | ||
830 | uint64_t | |
831 | tvtoabstime( | |
832 | struct timeval *tvp) | |
833 | { | |
834 | uint64_t result, usresult; | |
835 | ||
836 | clock_interval_to_absolutetime_interval( | |
837 | tvp->tv_sec, NSEC_PER_SEC, &result); | |
838 | clock_interval_to_absolutetime_interval( | |
839 | tvp->tv_usec, NSEC_PER_USEC, &usresult); | |
840 | ||
841 | return (result + usresult); | |
842 | } | |
39236c6e | 843 | |
4bd07ac2 A |
844 | uint64_t |
845 | tstoabstime(struct timespec *ts) | |
846 | { | |
847 | uint64_t abstime_s, abstime_ns; | |
848 | clock_interval_to_absolutetime_interval(ts->tv_sec, NSEC_PER_SEC, &abstime_s); | |
849 | clock_interval_to_absolutetime_interval(ts->tv_nsec, 1, &abstime_ns); | |
850 | return abstime_s + abstime_ns; | |
851 | } | |
852 | ||
39236c6e A |
853 | #if NETWORKING |
854 | /* | |
855 | * ratecheck(): simple time-based rate-limit checking. | |
856 | */ | |
857 | int | |
858 | ratecheck(struct timeval *lasttime, const struct timeval *mininterval) | |
859 | { | |
860 | struct timeval tv, delta; | |
861 | int rv = 0; | |
862 | ||
863 | net_uptime2timeval(&tv); | |
864 | delta = tv; | |
865 | timevalsub(&delta, lasttime); | |
866 | ||
867 | /* | |
868 | * check for 0,0 is so that the message will be seen at least once, | |
869 | * even if interval is huge. | |
870 | */ | |
871 | if (timevalcmp(&delta, mininterval, >=) || | |
872 | (lasttime->tv_sec == 0 && lasttime->tv_usec == 0)) { | |
873 | *lasttime = tv; | |
874 | rv = 1; | |
875 | } | |
876 | ||
877 | return (rv); | |
878 | } | |
879 | ||
880 | /* | |
881 | * ppsratecheck(): packets (or events) per second limitation. | |
882 | */ | |
883 | int | |
884 | ppsratecheck(struct timeval *lasttime, int *curpps, int maxpps) | |
885 | { | |
886 | struct timeval tv, delta; | |
887 | int rv; | |
888 | ||
889 | net_uptime2timeval(&tv); | |
890 | ||
891 | timersub(&tv, lasttime, &delta); | |
892 | ||
893 | /* | |
894 | * Check for 0,0 so that the message will be seen at least once. | |
895 | * If more than one second has passed since the last update of | |
896 | * lasttime, reset the counter. | |
897 | * | |
898 | * we do increment *curpps even in *curpps < maxpps case, as some may | |
899 | * try to use *curpps for stat purposes as well. | |
900 | */ | |
901 | if ((lasttime->tv_sec == 0 && lasttime->tv_usec == 0) || | |
902 | delta.tv_sec >= 1) { | |
903 | *lasttime = tv; | |
904 | *curpps = 0; | |
905 | rv = 1; | |
906 | } else if (maxpps < 0) | |
907 | rv = 1; | |
908 | else if (*curpps < maxpps) | |
909 | rv = 1; | |
910 | else | |
911 | rv = 0; | |
912 | ||
913 | #if 1 /* DIAGNOSTIC? */ | |
914 | /* be careful about wrap-around */ | |
915 | if (*curpps + 1 > 0) | |
916 | *curpps = *curpps + 1; | |
917 | #else | |
918 | /* | |
919 | * assume that there's not too many calls to this function. | |
920 | * not sure if the assumption holds, as it depends on *caller's* | |
921 | * behavior, not the behavior of this function. | |
922 | * IMHO it is wrong to make assumption on the caller's behavior, | |
923 | * so the above #if is #if 1, not #ifdef DIAGNOSTIC. | |
924 | */ | |
925 | *curpps = *curpps + 1; | |
926 | #endif | |
927 | ||
928 | return (rv); | |
929 | } | |
930 | #endif /* NETWORKING */ | |
931 | ||
9bccf70c A |
932 | void |
933 | time_zone_slock_init(void) | |
934 | { | |
91447636 A |
935 | /* allocate lock group attribute and group */ |
936 | tz_slock_grp_attr = lck_grp_attr_alloc_init(); | |
9bccf70c | 937 | |
91447636 | 938 | tz_slock_grp = lck_grp_alloc_init("tzlock", tz_slock_grp_attr); |
9bccf70c | 939 | |
91447636 A |
940 | /* Allocate lock attribute */ |
941 | tz_slock_attr = lck_attr_alloc_init(); | |
9bccf70c | 942 | |
91447636 A |
943 | /* Allocate the spin lock */ |
944 | tz_slock = lck_spin_alloc_init(tz_slock_grp, tz_slock_attr); | |
9bccf70c | 945 | } |