| Commit | Line | Data |
|---|---|---|
| 984263bc MD |
1 | /* |
| 2 | * Copyright (c) 1982, 1986, 1989, 1993 | |
| 3 | * The Regents of the University of California. All rights reserved. | |
| 4 | * | |
| 5 | * Redistribution and use in source and binary forms, with or without | |
| 6 | * modification, are permitted provided that the following conditions | |
| 7 | * are met: | |
| 8 | * 1. Redistributions of source code must retain the above copyright | |
| 9 | * notice, this list of conditions and the following disclaimer. | |
| 10 | * 2. Redistributions in binary form must reproduce the above copyright | |
| 11 | * notice, this list of conditions and the following disclaimer in the | |
| 12 | * documentation and/or other materials provided with the distribution. | |
| 13 | * 3. All advertising materials mentioning features or use of this software | |
| 14 | * must display the following acknowledgement: | |
| 15 | * This product includes software developed by the University of | |
| 16 | * California, Berkeley and its contributors. | |
| 17 | * 4. Neither the name of the University nor the names of its contributors | |
| 18 | * may be used to endorse or promote products derived from this software | |
| 19 | * without specific prior written permission. | |
| 20 | * | |
| 21 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND | |
| 22 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | |
| 23 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | |
| 24 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE | |
| 25 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | |
| 26 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | |
| 27 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | |
| 28 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | |
| 29 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | |
| 30 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | |
| 31 | * SUCH DAMAGE. | |
| 32 | * | |
| 33 | * @(#)kern_time.c 8.1 (Berkeley) 6/10/93 | |
| 34 | * $FreeBSD: src/sys/kern/kern_time.c,v 1.68.2.1 2002/10/01 08:00:41 bde Exp $ | |
| 35 | */ | |
| 36 | ||
| 37 | #include <sys/param.h> | |
| 38 | #include <sys/systm.h> | |
| 39 | #include <sys/buf.h> | |
| 40 | #include <sys/sysproto.h> | |
| 41 | #include <sys/resourcevar.h> | |
| 42 | #include <sys/signalvar.h> | |
| 43 | #include <sys/kernel.h> | |
| 984263bc | 44 | #include <sys/sysent.h> |
| df2244e3 | 45 | #include <sys/sysunion.h> |
| 984263bc | 46 | #include <sys/proc.h> |
| 895c1f85 | 47 | #include <sys/priv.h> |
| 984263bc MD |
48 | #include <sys/time.h> |
| 49 | #include <sys/vnode.h> | |
| a94976ad | 50 | #include <sys/sysctl.h> |
| b3ce8a64 | 51 | #include <sys/kern_syscall.h> |
| 984263bc MD |
52 | #include <vm/vm.h> |
| 53 | #include <vm/vm_extern.h> | |
| 684a93c4 | 54 | |
| 245e4f17 | 55 | #include <sys/msgport2.h> |
| 88c4d2f6 | 56 | #include <sys/thread2.h> |
| 684a93c4 | 57 | #include <sys/mplock2.h> |
| 984263bc MD |
58 | |
| 59 | struct timezone tz; | |
| 60 | ||
| 61 | /* | |
| 62 | * Time of day and interval timer support. | |
| 63 | * | |
| 64 | * These routines provide the kernel entry points to get and set | |
| 65 | * the time-of-day and per-process interval timers. Subroutines | |
| 66 | * here provide support for adding and subtracting timeval structures | |
| 67 | * and decrementing interval timers, optionally reloading the interval | |
| 68 | * timers when they expire. | |
| 69 | */ | |
| 70 | ||
| b3ce8a64 MD |
71 | static int settime(struct timeval *); |
| 72 | static void timevalfix(struct timeval *); | |
| 984263bc | 73 | |
| 3b58baa0 MD |
74 | /* |
| 75 | * Nanosleep tries very hard to sleep for a precisely requested time | |
| 76 | * interval, down to 1uS. The administrator can impose a minimum delay | |
| 77 | * and a delay below which we hard-loop instead of initiate a timer | |
| 78 | * interrupt and sleep. | |
| 79 | * | |
| 80 | * For machines under high loads it might be beneficial to increase min_us | |
| 81 | * to e.g. 1000uS (1ms) so spining processes sleep meaningfully. | |
| 82 | */ | |
| 83 | static int nanosleep_min_us = 10; | |
| 84 | static int nanosleep_hard_us = 100; | |
| 85 | SYSCTL_INT(_kern, OID_AUTO, nanosleep_min_us, CTLFLAG_RW, | |
| 86 | &nanosleep_min_us, 0, "") | |
| 87 | SYSCTL_INT(_kern, OID_AUTO, nanosleep_hard_us, CTLFLAG_RW, | |
| 88 | &nanosleep_hard_us, 0, "") | |
| a94976ad | 89 | |
| 984263bc | 90 | static int |
| c972a82f | 91 | settime(struct timeval *tv) |
| 984263bc MD |
92 | { |
| 93 | struct timeval delta, tv1, tv2; | |
| 94 | static struct timeval maxtime, laststep; | |
| 95 | struct timespec ts; | |
| 33924148 JS |
96 | int origcpu; |
| 97 | ||
| 157202af | 98 | if ((origcpu = mycpu->gd_cpuid) != 0) |
| 33924148 | 99 | lwkt_setcpu_self(globaldata_find(0)); |
| 984263bc | 100 | |
| 88c4d2f6 | 101 | crit_enter(); |
| 984263bc MD |
102 | microtime(&tv1); |
| 103 | delta = *tv; | |
| 104 | timevalsub(&delta, &tv1); | |
| 105 | ||
| 106 | /* | |
| 107 | * If the system is secure, we do not allow the time to be | |
| 108 | * set to a value earlier than 1 second less than the highest | |
| 109 | * time we have yet seen. The worst a miscreant can do in | |
| 110 | * this circumstance is "freeze" time. He couldn't go | |
| 111 | * back to the past. | |
| 112 | * | |
| 113 | * We similarly do not allow the clock to be stepped more | |
| 114 | * than one second, nor more than once per second. This allows | |
| 115 | * a miscreant to make the clock march double-time, but no worse. | |
| 116 | */ | |
| 117 | if (securelevel > 1) { | |
| 118 | if (delta.tv_sec < 0 || delta.tv_usec < 0) { | |
| 119 | /* | |
| 120 | * Update maxtime to latest time we've seen. | |
| 121 | */ | |
| 122 | if (tv1.tv_sec > maxtime.tv_sec) | |
| 123 | maxtime = tv1; | |
| 124 | tv2 = *tv; | |
| 125 | timevalsub(&tv2, &maxtime); | |
| 126 | if (tv2.tv_sec < -1) { | |
| 127 | tv->tv_sec = maxtime.tv_sec - 1; | |
| 6ea70f76 | 128 | kprintf("Time adjustment clamped to -1 second\n"); |
| 984263bc MD |
129 | } |
| 130 | } else { | |
| 131 | if (tv1.tv_sec == laststep.tv_sec) { | |
| 88c4d2f6 | 132 | crit_exit(); |
| 984263bc MD |
133 | return (EPERM); |
| 134 | } | |
| 135 | if (delta.tv_sec > 1) { | |
| 136 | tv->tv_sec = tv1.tv_sec + 1; | |
| 6ea70f76 | 137 | kprintf("Time adjustment clamped to +1 second\n"); |
| 984263bc MD |
138 | } |
| 139 | laststep = *tv; | |
| 140 | } | |
| 141 | } | |
| 142 | ||
| 143 | ts.tv_sec = tv->tv_sec; | |
| 144 | ts.tv_nsec = tv->tv_usec * 1000; | |
| 88c4d2f6 | 145 | set_timeofday(&ts); |
| 88c4d2f6 | 146 | crit_exit(); |
| 33924148 | 147 | |
| 157202af | 148 | if (origcpu != 0) |
| 33924148 | 149 | lwkt_setcpu_self(globaldata_find(origcpu)); |
| 33924148 | 150 | |
| 984263bc MD |
151 | resettodr(); |
| 152 | return (0); | |
| 153 | } | |
| 154 | ||
| 3919ced0 MD |
155 | /* |
| 156 | * MPSAFE | |
| 157 | */ | |
| 984263bc | 158 | int |
| b3ce8a64 | 159 | kern_clock_gettime(clockid_t clock_id, struct timespec *ats) |
| 984263bc | 160 | { |
| b3ce8a64 | 161 | int error = 0; |
| 984263bc | 162 | |
| b3ce8a64 | 163 | switch(clock_id) { |
| 26be1876 | 164 | case CLOCK_REALTIME: |
| b3ce8a64 MD |
165 | nanotime(ats); |
| 166 | break; | |
| 26be1876 | 167 | case CLOCK_MONOTONIC: |
| b3ce8a64 MD |
168 | nanouptime(ats); |
| 169 | break; | |
| 26be1876 | 170 | default: |
| b3ce8a64 MD |
171 | error = EINVAL; |
| 172 | break; | |
| 26be1876 | 173 | } |
| b3ce8a64 | 174 | return (error); |
| 984263bc MD |
175 | } |
| 176 | ||
| 3919ced0 MD |
177 | /* |
| 178 | * MPSAFE | |
| 179 | */ | |
| 984263bc | 180 | int |
| b3ce8a64 MD |
181 | sys_clock_gettime(struct clock_gettime_args *uap) |
| 182 | { | |
| 183 | struct timespec ats; | |
| 184 | int error; | |
| 185 | ||
| 186 | error = kern_clock_gettime(uap->clock_id, &ats); | |
| 187 | if (error == 0) | |
| 188 | error = copyout(&ats, uap->tp, sizeof(ats)); | |
| 189 | ||
| 190 | return (error); | |
| 191 | } | |
| 192 | ||
| 193 | int | |
| 194 | kern_clock_settime(clockid_t clock_id, struct timespec *ats) | |
| 984263bc | 195 | { |
| dadab5e9 | 196 | struct thread *td = curthread; |
| 984263bc | 197 | struct timeval atv; |
| 984263bc MD |
198 | int error; |
| 199 | ||
| cc125f38 | 200 | if ((error = priv_check(td, PRIV_CLOCK_SETTIME)) != 0) |
| 984263bc | 201 | return (error); |
| b3ce8a64 | 202 | if (clock_id != CLOCK_REALTIME) |
| 984263bc | 203 | return (EINVAL); |
| b3ce8a64 MD |
204 | if (ats->tv_nsec < 0 || ats->tv_nsec >= 1000000000) |
| 205 | return (EINVAL); | |
| 206 | ||
| 207 | TIMESPEC_TO_TIMEVAL(&atv, ats); | |
| 208 | error = settime(&atv); | |
| 209 | return (error); | |
| 984263bc MD |
210 | } |
| 211 | ||
| 3919ced0 MD |
212 | /* |
| 213 | * MPALMOSTSAFE | |
| 214 | */ | |
| 984263bc | 215 | int |
| b3ce8a64 | 216 | sys_clock_settime(struct clock_settime_args *uap) |
| 984263bc | 217 | { |
| b3ce8a64 MD |
218 | struct timespec ats; |
| 219 | int error; | |
| 220 | ||
| 221 | if ((error = copyin(uap->tp, &ats, sizeof(ats))) != 0) | |
| 222 | return (error); | |
| 223 | ||
| 3919ced0 MD |
224 | get_mplock(); |
| 225 | error = kern_clock_settime(uap->clock_id, &ats); | |
| 226 | rel_mplock(); | |
| 227 | return (error); | |
| b3ce8a64 MD |
228 | } |
| 229 | ||
| 3919ced0 MD |
230 | /* |
| 231 | * MPSAFE | |
| 232 | */ | |
| b3ce8a64 MD |
233 | int |
| 234 | kern_clock_getres(clockid_t clock_id, struct timespec *ts) | |
| 235 | { | |
| 236 | int error; | |
| 984263bc | 237 | |
| b3ce8a64 | 238 | switch(clock_id) { |
| 26be1876 MD |
239 | case CLOCK_REALTIME: |
| 240 | case CLOCK_MONOTONIC: | |
| 984263bc | 241 | /* |
| 26be1876 MD |
242 | * Round up the result of the division cheaply |
| 243 | * by adding 1. Rounding up is especially important | |
| 244 | * if rounding down would give 0. Perfect rounding | |
| 245 | * is unimportant. | |
| 984263bc | 246 | */ |
| b3ce8a64 MD |
247 | ts->tv_sec = 0; |
| 248 | ts->tv_nsec = 1000000000 / sys_cputimer->freq + 1; | |
| 249 | error = 0; | |
| 250 | break; | |
| 26be1876 | 251 | default: |
| b3ce8a64 MD |
252 | error = EINVAL; |
| 253 | break; | |
| 984263bc | 254 | } |
| b3ce8a64 MD |
255 | |
| 256 | return(error); | |
| 257 | } | |
| 258 | ||
| 3919ced0 MD |
259 | /* |
| 260 | * MPSAFE | |
| 261 | */ | |
| b3ce8a64 MD |
262 | int |
| 263 | sys_clock_getres(struct clock_getres_args *uap) | |
| 264 | { | |
| 265 | int error; | |
| 266 | struct timespec ts; | |
| 267 | ||
| 268 | error = kern_clock_getres(uap->clock_id, &ts); | |
| 269 | if (error == 0) | |
| 270 | error = copyout(&ts, uap->tp, sizeof(ts)); | |
| 271 | ||
| 272 | return (error); | |
| 984263bc MD |
273 | } |
| 274 | ||
| 88c4d2f6 MD |
275 | /* |
| 276 | * nanosleep1() | |
| 277 | * | |
| 278 | * This is a general helper function for nanosleep() (aka sleep() aka | |
| 279 | * usleep()). | |
| 280 | * | |
| 281 | * If there is less then one tick's worth of time left and | |
| 282 | * we haven't done a yield, or the remaining microseconds is | |
| 283 | * ridiculously low, do a yield. This avoids having | |
| 284 | * to deal with systimer overheads when the system is under | |
| 285 | * heavy loads. If we have done a yield already then use | |
| 286 | * a systimer and an uninterruptable thread wait. | |
| 287 | * | |
| 288 | * If there is more then a tick's worth of time left, | |
| 289 | * calculate the baseline ticks and use an interruptable | |
| 290 | * tsleep, then handle the fine-grained delay on the next | |
| 291 | * loop. This usually results in two sleeps occuring, a long one | |
| 292 | * and a short one. | |
| 3919ced0 MD |
293 | * |
| 294 | * MPSAFE | |
| 88c4d2f6 MD |
295 | */ |
| 296 | static void | |
| 96d52ac8 SZ |
297 | ns1_systimer(systimer_t info, int in_ipi __unused, |
| 298 | struct intrframe *frame __unused) | |
| 88c4d2f6 MD |
299 | { |
| 300 | lwkt_schedule(info->data); | |
| 301 | } | |
| 984263bc | 302 | |
| 8ba5f7ef | 303 | int |
| 41c20dac | 304 | nanosleep1(struct timespec *rqt, struct timespec *rmt) |
| 984263bc | 305 | { |
| 88c4d2f6 | 306 | static int nanowait; |
| 984263bc MD |
307 | struct timespec ts, ts2, ts3; |
| 308 | struct timeval tv; | |
| 309 | int error; | |
| 310 | ||
| 311 | if (rqt->tv_nsec < 0 || rqt->tv_nsec >= 1000000000) | |
| 312 | return (EINVAL); | |
| 8ba5f7ef | 313 | /* XXX: imho this should return EINVAL at least for tv_sec < 0 */ |
| 984263bc MD |
314 | if (rqt->tv_sec < 0 || (rqt->tv_sec == 0 && rqt->tv_nsec == 0)) |
| 315 | return (0); | |
| a94976ad MD |
316 | nanouptime(&ts); |
| 317 | timespecadd(&ts, rqt); /* ts = target timestamp compare */ | |
| 318 | TIMESPEC_TO_TIMEVAL(&tv, rqt); /* tv = sleep interval */ | |
| 88c4d2f6 | 319 | |
| 984263bc | 320 | for (;;) { |
| 88c4d2f6 MD |
321 | int ticks; |
| 322 | struct systimer info; | |
| 323 | ||
| a591f597 | 324 | ticks = tv.tv_usec / ustick; /* approximate */ |
| a94976ad | 325 | |
| 88c4d2f6 | 326 | if (tv.tv_sec == 0 && ticks == 0) { |
| 37af14fe | 327 | thread_t td = curthread; |
| 3b58baa0 MD |
328 | if (tv.tv_usec > 0 && tv.tv_usec < nanosleep_min_us) |
| 329 | tv.tv_usec = nanosleep_min_us; | |
| 330 | if (tv.tv_usec < nanosleep_hard_us) { | |
| f9235b6d | 331 | lwkt_user_yield(); |
| 3b58baa0 | 332 | cpu_pause(); |
| a94976ad | 333 | } else { |
| 37af14fe | 334 | crit_enter_quick(td); |
| 88c4d2f6 | 335 | systimer_init_oneshot(&info, ns1_systimer, |
| 37af14fe MD |
336 | td, tv.tv_usec); |
| 337 | lwkt_deschedule_self(td); | |
| 338 | crit_exit_quick(td); | |
| 88c4d2f6 MD |
339 | lwkt_switch(); |
| 340 | systimer_del(&info); /* make sure it's gone */ | |
| a94976ad | 341 | } |
| 08f2f1bb | 342 | error = iscaught(td->td_lwp); |
| 88c4d2f6 MD |
343 | } else if (tv.tv_sec == 0) { |
| 344 | error = tsleep(&nanowait, PCATCH, "nanslp", ticks); | |
| a94976ad | 345 | } else { |
| 88c4d2f6 MD |
346 | ticks = tvtohz_low(&tv); /* also handles overflow */ |
| 347 | error = tsleep(&nanowait, PCATCH, "nanslp", ticks); | |
| a94976ad MD |
348 | } |
| 349 | nanouptime(&ts2); | |
| 88c4d2f6 | 350 | if (error && error != EWOULDBLOCK) { |
| 984263bc MD |
351 | if (error == ERESTART) |
| 352 | error = EINTR; | |
| 353 | if (rmt != NULL) { | |
| 354 | timespecsub(&ts, &ts2); | |
| 355 | if (ts.tv_sec < 0) | |
| 356 | timespecclear(&ts); | |
| 357 | *rmt = ts; | |
| 358 | } | |
| 359 | return (error); | |
| 360 | } | |
| 361 | if (timespeccmp(&ts2, &ts, >=)) | |
| 362 | return (0); | |
| 363 | ts3 = ts; | |
| 364 | timespecsub(&ts3, &ts2); | |
| 365 | TIMESPEC_TO_TIMEVAL(&tv, &ts3); | |
| 366 | } | |
| 367 | } | |
| 368 | ||
| 3919ced0 MD |
369 | /* |
| 370 | * MPSAFE | |
| 371 | */ | |
| 984263bc | 372 | int |
| 753fd850 | 373 | sys_nanosleep(struct nanosleep_args *uap) |
| 984263bc | 374 | { |
| 245e4f17 | 375 | int error; |
| f9a13fc4 MD |
376 | struct timespec rqt; |
| 377 | struct timespec rmt; | |
| 984263bc | 378 | |
| f9a13fc4 | 379 | error = copyin(uap->rqtp, &rqt, sizeof(rqt)); |
| 984263bc MD |
380 | if (error) |
| 381 | return (error); | |
| f9a13fc4 MD |
382 | |
| 383 | error = nanosleep1(&rqt, &rmt); | |
| 384 | ||
| 245e4f17 | 385 | /* |
| f9a13fc4 | 386 | * copyout the residual if nanosleep was interrupted. |
| 245e4f17 | 387 | */ |
| 55d25c87 SS |
388 | if (error && uap->rmtp) { |
| 389 | int error2; | |
| 390 | ||
| 391 | error2 = copyout(&rmt, uap->rmtp, sizeof(rmt)); | |
| 392 | if (error2) | |
| 393 | error = error2; | |
| 394 | } | |
| 984263bc MD |
395 | return (error); |
| 396 | } | |
| 397 | ||
| 3919ced0 MD |
398 | /* |
| 399 | * MPSAFE | |
| 400 | */ | |
| 984263bc | 401 | int |
| 753fd850 | 402 | sys_gettimeofday(struct gettimeofday_args *uap) |
| 984263bc MD |
403 | { |
| 404 | struct timeval atv; | |
| 405 | int error = 0; | |
| 406 | ||
| 407 | if (uap->tp) { | |
| 408 | microtime(&atv); | |
| 409 | if ((error = copyout((caddr_t)&atv, (caddr_t)uap->tp, | |
| 410 | sizeof (atv)))) | |
| 411 | return (error); | |
| 412 | } | |
| 413 | if (uap->tzp) | |
| 414 | error = copyout((caddr_t)&tz, (caddr_t)uap->tzp, | |
| 415 | sizeof (tz)); | |
| 416 | return (error); | |
| 417 | } | |
| 418 | ||
| 3919ced0 MD |
419 | /* |
| 420 | * MPALMOSTSAFE | |
| 421 | */ | |
| 984263bc | 422 | int |
| 753fd850 | 423 | sys_settimeofday(struct settimeofday_args *uap) |
| 984263bc | 424 | { |
| dadab5e9 | 425 | struct thread *td = curthread; |
| 984263bc MD |
426 | struct timeval atv; |
| 427 | struct timezone atz; | |
| 428 | int error; | |
| 429 | ||
| cc125f38 | 430 | if ((error = priv_check(td, PRIV_SETTIMEOFDAY))) |
| 984263bc | 431 | return (error); |
| f59ccd43 MD |
432 | /* |
| 433 | * Verify all parameters before changing time. | |
| 434 | * | |
| 435 | * NOTE: We do not allow the time to be set to 0.0, which also by | |
| 436 | * happy coincidence works around a pkgsrc bulk build bug. | |
| 437 | */ | |
| 984263bc MD |
438 | if (uap->tv) { |
| 439 | if ((error = copyin((caddr_t)uap->tv, (caddr_t)&atv, | |
| 440 | sizeof(atv)))) | |
| 441 | return (error); | |
| 442 | if (atv.tv_usec < 0 || atv.tv_usec >= 1000000) | |
| 443 | return (EINVAL); | |
| f59ccd43 MD |
444 | if (atv.tv_sec == 0 && atv.tv_usec == 0) |
| 445 | return (EINVAL); | |
| 984263bc MD |
446 | } |
| 447 | if (uap->tzp && | |
| 448 | (error = copyin((caddr_t)uap->tzp, (caddr_t)&atz, sizeof(atz)))) | |
| 449 | return (error); | |
| 3919ced0 MD |
450 | |
| 451 | get_mplock(); | |
| 452 | if (uap->tv && (error = settime(&atv))) { | |
| 453 | rel_mplock(); | |
| 984263bc | 454 | return (error); |
| 3919ced0 MD |
455 | } |
| 456 | rel_mplock(); | |
| 984263bc MD |
457 | if (uap->tzp) |
| 458 | tz = atz; | |
| 459 | return (0); | |
| 460 | } | |
| 461 | ||
| 4026c000 JS |
462 | static void |
| 463 | kern_adjtime_common(void) | |
| 464 | { | |
| 465 | if ((ntp_delta >= 0 && ntp_delta < ntp_default_tick_delta) || | |
| 7df7080b | 466 | (ntp_delta < 0 && ntp_delta > -ntp_default_tick_delta)) |
| 4026c000 JS |
467 | ntp_tick_delta = ntp_delta; |
| 468 | else if (ntp_delta > ntp_big_delta) | |
| 469 | ntp_tick_delta = 10 * ntp_default_tick_delta; | |
| 470 | else if (ntp_delta < -ntp_big_delta) | |
| 471 | ntp_tick_delta = -10 * ntp_default_tick_delta; | |
| 472 | else if (ntp_delta > 0) | |
| 473 | ntp_tick_delta = ntp_default_tick_delta; | |
| 474 | else | |
| 475 | ntp_tick_delta = -ntp_default_tick_delta; | |
| 476 | } | |
| 477 | ||
| 478 | void | |
| 479 | kern_adjtime(int64_t delta, int64_t *odelta) | |
| 480 | { | |
| 481 | int origcpu; | |
| 482 | ||
| 157202af | 483 | if ((origcpu = mycpu->gd_cpuid) != 0) |
| 4026c000 | 484 | lwkt_setcpu_self(globaldata_find(0)); |
| 4026c000 JS |
485 | |
| 486 | crit_enter(); | |
| 487 | *odelta = ntp_delta; | |
| 08f95c49 | 488 | ntp_delta = delta; |
| 4026c000 JS |
489 | kern_adjtime_common(); |
| 490 | crit_exit(); | |
| 491 | ||
| 157202af | 492 | if (origcpu != 0) |
| 4026c000 | 493 | lwkt_setcpu_self(globaldata_find(origcpu)); |
| 4026c000 JS |
494 | } |
| 495 | ||
| b6da4cbb JS |
496 | static void |
| 497 | kern_get_ntp_delta(int64_t *delta) | |
| 498 | { | |
| 499 | int origcpu; | |
| 500 | ||
| 501 | if ((origcpu = mycpu->gd_cpuid) != 0) | |
| 502 | lwkt_setcpu_self(globaldata_find(0)); | |
| 503 | ||
| 504 | crit_enter(); | |
| 505 | *delta = ntp_delta; | |
| 506 | crit_exit(); | |
| 507 | ||
| 508 | if (origcpu != 0) | |
| 509 | lwkt_setcpu_self(globaldata_find(origcpu)); | |
| 510 | } | |
| 511 | ||
| 4026c000 JS |
512 | void |
| 513 | kern_reladjtime(int64_t delta) | |
| 514 | { | |
| 515 | int origcpu; | |
| 516 | ||
| 157202af | 517 | if ((origcpu = mycpu->gd_cpuid) != 0) |
| 4026c000 | 518 | lwkt_setcpu_self(globaldata_find(0)); |
| 4026c000 JS |
519 | |
| 520 | crit_enter(); | |
| 521 | ntp_delta += delta; | |
| 522 | kern_adjtime_common(); | |
| 523 | crit_exit(); | |
| 524 | ||
| 157202af | 525 | if (origcpu != 0) |
| 4026c000 | 526 | lwkt_setcpu_self(globaldata_find(origcpu)); |
| 4026c000 | 527 | } |
| 984263bc | 528 | |
| 0143455b JS |
529 | static void |
| 530 | kern_adjfreq(int64_t rate) | |
| 531 | { | |
| 532 | int origcpu; | |
| 533 | ||
| 157202af | 534 | if ((origcpu = mycpu->gd_cpuid) != 0) |
| 0143455b | 535 | lwkt_setcpu_self(globaldata_find(0)); |
| 0143455b JS |
536 | |
| 537 | crit_enter(); | |
| 538 | ntp_tick_permanent = rate; | |
| 539 | crit_exit(); | |
| 540 | ||
| 157202af | 541 | if (origcpu != 0) |
| 0143455b | 542 | lwkt_setcpu_self(globaldata_find(origcpu)); |
| 0143455b JS |
543 | } |
| 544 | ||
| 3919ced0 MD |
545 | /* |
| 546 | * MPALMOSTSAFE | |
| 547 | */ | |
| 984263bc | 548 | int |
| 753fd850 | 549 | sys_adjtime(struct adjtime_args *uap) |
| 984263bc | 550 | { |
| dadab5e9 | 551 | struct thread *td = curthread; |
| 984263bc | 552 | struct timeval atv; |
| 4026c000 | 553 | int64_t ndelta, odelta; |
| 88c4d2f6 | 554 | int error; |
| 984263bc | 555 | |
| cc125f38 | 556 | if ((error = priv_check(td, PRIV_ADJTIME))) |
| 984263bc | 557 | return (error); |
| 3919ced0 MD |
558 | error = copyin(uap->delta, &atv, sizeof(struct timeval)); |
| 559 | if (error) | |
| 984263bc MD |
560 | return (error); |
| 561 | ||
| 562 | /* | |
| 563 | * Compute the total correction and the rate at which to apply it. | |
| 564 | * Round the adjustment down to a whole multiple of the per-tick | |
| 565 | * delta, so that after some number of incremental changes in | |
| 566 | * hardclock(), tickdelta will become zero, lest the correction | |
| 567 | * overshoot and start taking us away from the desired final time. | |
| 568 | */ | |
| 08f95c49 | 569 | ndelta = (int64_t)atv.tv_sec * 1000000000 + atv.tv_usec * 1000; |
| 3919ced0 | 570 | get_mplock(); |
| 4026c000 | 571 | kern_adjtime(ndelta, &odelta); |
| 3919ced0 | 572 | rel_mplock(); |
| 984263bc MD |
573 | |
| 574 | if (uap->olddelta) { | |
| 4026c000 | 575 | atv.tv_sec = odelta / 1000000000; |
| a821f7fc | 576 | atv.tv_usec = odelta % 1000000000 / 1000; |
| 3919ced0 | 577 | copyout(&atv, uap->olddelta, sizeof(struct timeval)); |
| 984263bc MD |
578 | } |
| 579 | return (0); | |
| 580 | } | |
| 581 | ||
| 4026c000 JS |
582 | static int |
| 583 | sysctl_adjtime(SYSCTL_HANDLER_ARGS) | |
| 584 | { | |
| 585 | int64_t delta; | |
| 586 | int error; | |
| 587 | ||
| 4026c000 | 588 | if (req->newptr != NULL) { |
| 895c1f85 | 589 | if (priv_check(curthread, PRIV_ROOT)) |
| 4026c000 JS |
590 | return (EPERM); |
| 591 | error = SYSCTL_IN(req, &delta, sizeof(delta)); | |
| 592 | if (error) | |
| 593 | return (error); | |
| 594 | kern_reladjtime(delta); | |
| 595 | } | |
| 5eb5a6bc MD |
596 | |
| 597 | if (req->oldptr) | |
| 598 | kern_get_ntp_delta(&delta); | |
| 599 | error = SYSCTL_OUT(req, &delta, sizeof(delta)); | |
| 600 | return (error); | |
| 4026c000 JS |
601 | } |
| 602 | ||
| 08f95c49 MD |
603 | /* |
| 604 | * delta is in nanoseconds. | |
| 605 | */ | |
| 0143455b | 606 | static int |
| b6da4cbb JS |
607 | sysctl_delta(SYSCTL_HANDLER_ARGS) |
| 608 | { | |
| 609 | int64_t delta, old_delta; | |
| 610 | int error; | |
| 611 | ||
| 612 | if (req->newptr != NULL) { | |
| 895c1f85 | 613 | if (priv_check(curthread, PRIV_ROOT)) |
| b6da4cbb JS |
614 | return (EPERM); |
| 615 | error = SYSCTL_IN(req, &delta, sizeof(delta)); | |
| 616 | if (error) | |
| 617 | return (error); | |
| 618 | kern_adjtime(delta, &old_delta); | |
| b6da4cbb JS |
619 | } |
| 620 | ||
| 5eb5a6bc MD |
621 | if (req->oldptr != NULL) |
| 622 | kern_get_ntp_delta(&old_delta); | |
| cebaad99 | 623 | error = SYSCTL_OUT(req, &old_delta, sizeof(old_delta)); |
| 5eb5a6bc | 624 | return (error); |
| b6da4cbb JS |
625 | } |
| 626 | ||
| 08f95c49 MD |
627 | /* |
| 628 | * frequency is in nanoseconds per second shifted left 32. | |
| 629 | * kern_adjfreq() needs it in nanoseconds per tick shifted left 32. | |
| 630 | */ | |
| b6da4cbb | 631 | static int |
| 0143455b JS |
632 | sysctl_adjfreq(SYSCTL_HANDLER_ARGS) |
| 633 | { | |
| 634 | int64_t freqdelta; | |
| 635 | int error; | |
| 636 | ||
| 0143455b | 637 | if (req->newptr != NULL) { |
| 895c1f85 | 638 | if (priv_check(curthread, PRIV_ROOT)) |
| 0143455b JS |
639 | return (EPERM); |
| 640 | error = SYSCTL_IN(req, &freqdelta, sizeof(freqdelta)); | |
| 641 | if (error) | |
| 642 | return (error); | |
| 643 | ||
| 644 | freqdelta /= hz; | |
| 645 | kern_adjfreq(freqdelta); | |
| 646 | } | |
| 5eb5a6bc MD |
647 | |
| 648 | if (req->oldptr != NULL) | |
| 649 | freqdelta = ntp_tick_permanent * hz; | |
| 650 | error = SYSCTL_OUT(req, &freqdelta, sizeof(freqdelta)); | |
| 651 | if (error) | |
| 652 | return (error); | |
| 653 | ||
| 0143455b JS |
654 | return (0); |
| 655 | } | |
| 656 | ||
| 4026c000 | 657 | SYSCTL_NODE(_kern, OID_AUTO, ntp, CTLFLAG_RW, 0, "NTP related controls"); |
| 5eb5a6bc MD |
658 | SYSCTL_PROC(_kern_ntp, OID_AUTO, permanent, |
| 659 | CTLTYPE_QUAD|CTLFLAG_RW, 0, 0, | |
| cebaad99 | 660 | sysctl_adjfreq, "Q", "permanent correction per second"); |
| b6da4cbb | 661 | SYSCTL_PROC(_kern_ntp, OID_AUTO, delta, |
| 5eb5a6bc | 662 | CTLTYPE_QUAD|CTLFLAG_RW, 0, 0, |
| cebaad99 | 663 | sysctl_delta, "Q", "one-time delta"); |
| 5eb5a6bc MD |
664 | SYSCTL_OPAQUE(_kern_ntp, OID_AUTO, big_delta, CTLFLAG_RD, |
| 665 | &ntp_big_delta, sizeof(ntp_big_delta), "Q", | |
| 666 | "threshold for fast adjustment"); | |
| 667 | SYSCTL_OPAQUE(_kern_ntp, OID_AUTO, tick_delta, CTLFLAG_RD, | |
| 668 | &ntp_tick_delta, sizeof(ntp_tick_delta), "LU", | |
| 669 | "per-tick adjustment"); | |
| 670 | SYSCTL_OPAQUE(_kern_ntp, OID_AUTO, default_tick_delta, CTLFLAG_RD, | |
| 671 | &ntp_default_tick_delta, sizeof(ntp_default_tick_delta), "LU", | |
| 672 | "default per-tick adjustment"); | |
| 48590578 | 673 | SYSCTL_OPAQUE(_kern_ntp, OID_AUTO, next_leap_second, CTLFLAG_RW, |
| 5eb5a6bc MD |
674 | &ntp_leap_second, sizeof(ntp_leap_second), "LU", |
| 675 | "next leap second"); | |
| 48590578 JS |
676 | SYSCTL_INT(_kern_ntp, OID_AUTO, insert_leap_second, CTLFLAG_RW, |
| 677 | &ntp_leap_insert, 0, "insert or remove leap second"); | |
| 4026c000 | 678 | SYSCTL_PROC(_kern_ntp, OID_AUTO, adjust, |
| cebaad99 JS |
679 | CTLTYPE_QUAD|CTLFLAG_RW, 0, 0, |
| 680 | sysctl_adjtime, "Q", "relative adjust for delta"); | |
| 4026c000 | 681 | |
| 984263bc MD |
682 | /* |
| 683 | * Get value of an interval timer. The process virtual and | |
| 684 | * profiling virtual time timers are kept in the p_stats area, since | |
| 685 | * they can be swapped out. These are kept internally in the | |
| 686 | * way they are specified externally: in time until they expire. | |
| 687 | * | |
| 688 | * The real time interval timer is kept in the process table slot | |
| 689 | * for the process, and its value (it_value) is kept as an | |
| 690 | * absolute time rather than as a delta, so that it is easy to keep | |
| 691 | * periodic real-time signals from drifting. | |
| 692 | * | |
| 693 | * Virtual time timers are processed in the hardclock() routine of | |
| 694 | * kern_clock.c. The real time timer is processed by a timeout | |
| 695 | * routine, called from the softclock() routine. Since a callout | |
| 696 | * may be delayed in real time due to interrupt processing in the system, | |
| 697 | * it is possible for the real time timeout routine (realitexpire, given below), | |
| 698 | * to be delayed in real time past when it is supposed to occur. It | |
| 699 | * does not suffice, therefore, to reload the real timer .it_value from the | |
| 700 | * real time timers .it_interval. Rather, we compute the next time in | |
| 701 | * absolute time the timer should go off. | |
| 3919ced0 MD |
702 | * |
| 703 | * MPALMOSTSAFE | |
| 984263bc | 704 | */ |
| 984263bc | 705 | int |
| 753fd850 | 706 | sys_getitimer(struct getitimer_args *uap) |
| 984263bc | 707 | { |
| 41c20dac | 708 | struct proc *p = curproc; |
| 984263bc MD |
709 | struct timeval ctv; |
| 710 | struct itimerval aitv; | |
| 984263bc MD |
711 | |
| 712 | if (uap->which > ITIMER_PROF) | |
| 713 | return (EINVAL); | |
| d7f4c458 | 714 | lwkt_gettoken(&p->p_token); |
| 984263bc MD |
715 | if (uap->which == ITIMER_REAL) { |
| 716 | /* | |
| 717 | * Convert from absolute to relative time in .it_value | |
| 718 | * part of real time timer. If time for real time timer | |
| 719 | * has passed return 0, else return difference between | |
| 720 | * current time and time for the timer to go off. | |
| 721 | */ | |
| 722 | aitv = p->p_realtimer; | |
| 723 | if (timevalisset(&aitv.it_value)) { | |
| 724 | getmicrouptime(&ctv); | |
| 725 | if (timevalcmp(&aitv.it_value, &ctv, <)) | |
| 726 | timevalclear(&aitv.it_value); | |
| 727 | else | |
| 728 | timevalsub(&aitv.it_value, &ctv); | |
| 729 | } | |
| 88c4d2f6 | 730 | } else { |
| 93328593 | 731 | aitv = p->p_timer[uap->which]; |
| 88c4d2f6 | 732 | } |
| d7f4c458 | 733 | lwkt_reltoken(&p->p_token); |
| 3919ced0 | 734 | return (copyout(&aitv, uap->itv, sizeof (struct itimerval))); |
| 984263bc MD |
735 | } |
| 736 | ||
| 3919ced0 MD |
737 | /* |
| 738 | * MPALMOSTSAFE | |
| 739 | */ | |
| 984263bc | 740 | int |
| 753fd850 | 741 | sys_setitimer(struct setitimer_args *uap) |
| 984263bc MD |
742 | { |
| 743 | struct itimerval aitv; | |
| 744 | struct timeval ctv; | |
| 41c20dac MD |
745 | struct itimerval *itvp; |
| 746 | struct proc *p = curproc; | |
| 88c4d2f6 | 747 | int error; |
| 984263bc MD |
748 | |
| 749 | if (uap->which > ITIMER_PROF) | |
| 750 | return (EINVAL); | |
| 751 | itvp = uap->itv; | |
| 752 | if (itvp && (error = copyin((caddr_t)itvp, (caddr_t)&aitv, | |
| 753 | sizeof(struct itimerval)))) | |
| 754 | return (error); | |
| 755 | if ((uap->itv = uap->oitv) && | |
| 753fd850 | 756 | (error = sys_getitimer((struct getitimer_args *)uap))) |
| 984263bc | 757 | return (error); |
| 4090d6ff | 758 | if (itvp == NULL) |
| 984263bc MD |
759 | return (0); |
| 760 | if (itimerfix(&aitv.it_value)) | |
| 761 | return (EINVAL); | |
| 762 | if (!timevalisset(&aitv.it_value)) | |
| 763 | timevalclear(&aitv.it_interval); | |
| 764 | else if (itimerfix(&aitv.it_interval)) | |
| 765 | return (EINVAL); | |
| d7f4c458 | 766 | lwkt_gettoken(&p->p_token); |
| 984263bc MD |
767 | if (uap->which == ITIMER_REAL) { |
| 768 | if (timevalisset(&p->p_realtimer.it_value)) | |
| a471eac5 | 769 | callout_stop_sync(&p->p_ithandle); |
| 984263bc | 770 | if (timevalisset(&aitv.it_value)) |
| 8fbf9130 JS |
771 | callout_reset(&p->p_ithandle, |
| 772 | tvtohz_high(&aitv.it_value), realitexpire, p); | |
| 984263bc MD |
773 | getmicrouptime(&ctv); |
| 774 | timevaladd(&aitv.it_value, &ctv); | |
| 775 | p->p_realtimer = aitv; | |
| 88c4d2f6 | 776 | } else { |
| 93328593 | 777 | p->p_timer[uap->which] = aitv; |
| 898e34b3 MD |
778 | switch(uap->which) { |
| 779 | case ITIMER_VIRTUAL: | |
| 4643740a | 780 | p->p_flags &= ~P_SIGVTALRM; |
| 898e34b3 MD |
781 | break; |
| 782 | case ITIMER_PROF: | |
| 4643740a | 783 | p->p_flags &= ~P_SIGPROF; |
| 898e34b3 MD |
784 | break; |
| 785 | } | |
| 88c4d2f6 | 786 | } |
| d7f4c458 | 787 | lwkt_reltoken(&p->p_token); |
| 984263bc MD |
788 | return (0); |
| 789 | } | |
| 790 | ||
| 791 | /* | |
| 792 | * Real interval timer expired: | |
| 793 | * send process whose timer expired an alarm signal. | |
| 794 | * If time is not set up to reload, then just return. | |
| 795 | * Else compute next time timer should go off which is > current time. | |
| 796 | * This is where delay in processing this timeout causes multiple | |
| 797 | * SIGALRM calls to be compressed into one. | |
| a94976ad | 798 | * tvtohz_high() always adds 1 to allow for the time until the next clock |
| 984263bc MD |
799 | * interrupt being strictly less than 1 clock tick, but we don't want |
| 800 | * that here since we want to appear to be in sync with the clock | |
| 801 | * interrupt even when we're delayed. | |
| 802 | */ | |
| 803 | void | |
| c972a82f | 804 | realitexpire(void *arg) |
| 984263bc | 805 | { |
| 1fd87d54 | 806 | struct proc *p; |
| 984263bc | 807 | struct timeval ctv, ntv; |
| 984263bc MD |
808 | |
| 809 | p = (struct proc *)arg; | |
| a471eac5 | 810 | PHOLD(p); |
| d7f4c458 | 811 | lwkt_gettoken(&p->p_token); |
| 84204577 | 812 | ksignal(p, SIGALRM); |
| 984263bc MD |
813 | if (!timevalisset(&p->p_realtimer.it_interval)) { |
| 814 | timevalclear(&p->p_realtimer.it_value); | |
| a471eac5 | 815 | goto done; |
| 984263bc MD |
816 | } |
| 817 | for (;;) { | |
| 984263bc | 818 | timevaladd(&p->p_realtimer.it_value, |
| d7f4c458 | 819 | &p->p_realtimer.it_interval); |
| 984263bc MD |
820 | getmicrouptime(&ctv); |
| 821 | if (timevalcmp(&p->p_realtimer.it_value, &ctv, >)) { | |
| 822 | ntv = p->p_realtimer.it_value; | |
| 823 | timevalsub(&ntv, &ctv); | |
| 8fbf9130 JS |
824 | callout_reset(&p->p_ithandle, tvtohz_low(&ntv), |
| 825 | realitexpire, p); | |
| a471eac5 | 826 | goto done; |
| 984263bc | 827 | } |
| 984263bc | 828 | } |
| a471eac5 | 829 | done: |
| d7f4c458 | 830 | lwkt_reltoken(&p->p_token); |
| a471eac5 | 831 | PRELE(p); |
| 984263bc MD |
832 | } |
| 833 | ||
| 834 | /* | |
| 835 | * Check that a proposed value to load into the .it_value or | |
| 836 | * .it_interval part of an interval timer is acceptable, and | |
| 837 | * fix it to have at least minimal value (i.e. if it is less | |
| 838 | * than the resolution of the clock, round it up.) | |
| 3919ced0 MD |
839 | * |
| 840 | * MPSAFE | |
| 984263bc MD |
841 | */ |
| 842 | int | |
| c972a82f | 843 | itimerfix(struct timeval *tv) |
| 984263bc MD |
844 | { |
| 845 | ||
| 846 | if (tv->tv_sec < 0 || tv->tv_sec > 100000000 || | |
| 847 | tv->tv_usec < 0 || tv->tv_usec >= 1000000) | |
| 848 | return (EINVAL); | |
| a591f597 MD |
849 | if (tv->tv_sec == 0 && tv->tv_usec != 0 && tv->tv_usec < ustick) |
| 850 | tv->tv_usec = ustick; | |
| 984263bc MD |
851 | return (0); |
| 852 | } | |
| 853 | ||
| 854 | /* | |
| 855 | * Decrement an interval timer by a specified number | |
| 856 | * of microseconds, which must be less than a second, | |
| 857 | * i.e. < 1000000. If the timer expires, then reload | |
| 858 | * it. In this case, carry over (usec - old value) to | |
| 859 | * reduce the value reloaded into the timer so that | |
| 860 | * the timer does not drift. This routine assumes | |
| 861 | * that it is called in a context where the timers | |
| 862 | * on which it is operating cannot change in value. | |
| 863 | */ | |
| 864 | int | |
| c972a82f | 865 | itimerdecr(struct itimerval *itp, int usec) |
| 984263bc MD |
866 | { |
| 867 | ||
| 868 | if (itp->it_value.tv_usec < usec) { | |
| 869 | if (itp->it_value.tv_sec == 0) { | |
| 870 | /* expired, and already in next interval */ | |
| 871 | usec -= itp->it_value.tv_usec; | |
| 872 | goto expire; | |
| 873 | } | |
| 874 | itp->it_value.tv_usec += 1000000; | |
| 875 | itp->it_value.tv_sec--; | |
| 876 | } | |
| 877 | itp->it_value.tv_usec -= usec; | |
| 878 | usec = 0; | |
| 879 | if (timevalisset(&itp->it_value)) | |
| 880 | return (1); | |
| 881 | /* expired, exactly at end of interval */ | |
| 882 | expire: | |
| 883 | if (timevalisset(&itp->it_interval)) { | |
| 884 | itp->it_value = itp->it_interval; | |
| 885 | itp->it_value.tv_usec -= usec; | |
| 886 | if (itp->it_value.tv_usec < 0) { | |
| 887 | itp->it_value.tv_usec += 1000000; | |
| 888 | itp->it_value.tv_sec--; | |
| 889 | } | |
| 890 | } else | |
| 891 | itp->it_value.tv_usec = 0; /* sec is already 0 */ | |
| 892 | return (0); | |
| 893 | } | |
| 894 | ||
| 895 | /* | |
| 896 | * Add and subtract routines for timevals. | |
| 897 | * N.B.: subtract routine doesn't deal with | |
| 898 | * results which are before the beginning, | |
| 899 | * it just gets very confused in this case. | |
| 900 | * Caveat emptor. | |
| 901 | */ | |
| 902 | void | |
| 9deadd02 | 903 | timevaladd(struct timeval *t1, const struct timeval *t2) |
| 984263bc MD |
904 | { |
| 905 | ||
| 906 | t1->tv_sec += t2->tv_sec; | |
| 907 | t1->tv_usec += t2->tv_usec; | |
| 908 | timevalfix(t1); | |
| 909 | } | |
| 910 | ||
| 911 | void | |
| 9deadd02 | 912 | timevalsub(struct timeval *t1, const struct timeval *t2) |
| 984263bc MD |
913 | { |
| 914 | ||
| 915 | t1->tv_sec -= t2->tv_sec; | |
| 916 | t1->tv_usec -= t2->tv_usec; | |
| 917 | timevalfix(t1); | |
| 918 | } | |
| 919 | ||
| 920 | static void | |
| c972a82f | 921 | timevalfix(struct timeval *t1) |
| 984263bc MD |
922 | { |
| 923 | ||
| 924 | if (t1->tv_usec < 0) { | |
| 925 | t1->tv_sec--; | |
| 926 | t1->tv_usec += 1000000; | |
| 927 | } | |
| 928 | if (t1->tv_usec >= 1000000) { | |
| 929 | t1->tv_sec++; | |
| 930 | t1->tv_usec -= 1000000; | |
| 931 | } | |
| 932 | } | |
| cea4446f HP |
933 | |
| 934 | /* | |
| 935 | * ratecheck(): simple time-based rate-limit checking. | |
| 936 | */ | |
| 937 | int | |
| 938 | ratecheck(struct timeval *lasttime, const struct timeval *mininterval) | |
| 939 | { | |
| 940 | struct timeval tv, delta; | |
| 941 | int rv = 0; | |
| 942 | ||
| 943 | getmicrouptime(&tv); /* NB: 10ms precision */ | |
| 944 | delta = tv; | |
| 945 | timevalsub(&delta, lasttime); | |
| 946 | ||
| 947 | /* | |
| 948 | * check for 0,0 is so that the message will be seen at least once, | |
| 949 | * even if interval is huge. | |
| 950 | */ | |
| 951 | if (timevalcmp(&delta, mininterval, >=) || | |
| 952 | (lasttime->tv_sec == 0 && lasttime->tv_usec == 0)) { | |
| 953 | *lasttime = tv; | |
| 954 | rv = 1; | |
| 955 | } | |
| 956 | ||
| 957 | return (rv); | |
| 958 | } | |
| 959 | ||
| 960 | /* | |
| 961 | * ppsratecheck(): packets (or events) per second limitation. | |
| 962 | * | |
| 963 | * Return 0 if the limit is to be enforced (e.g. the caller | |
| 964 | * should drop a packet because of the rate limitation). | |
| 965 | * | |
| 966 | * maxpps of 0 always causes zero to be returned. maxpps of -1 | |
| 967 | * always causes 1 to be returned; this effectively defeats rate | |
| 968 | * limiting. | |
| 969 | * | |
| 970 | * Note that we maintain the struct timeval for compatibility | |
| 971 | * with other bsd systems. We reuse the storage and just monitor | |
| 972 | * clock ticks for minimal overhead. | |
| 973 | */ | |
| 974 | int | |
| 975 | ppsratecheck(struct timeval *lasttime, int *curpps, int maxpps) | |
| 976 | { | |
| 977 | int now; | |
| 978 | ||
| 979 | /* | |
| 980 | * Reset the last time and counter if this is the first call | |
| 981 | * or more than a second has passed since the last update of | |
| 982 | * lasttime. | |
| 983 | */ | |
| 984 | now = ticks; | |
| 985 | if (lasttime->tv_sec == 0 || (u_int)(now - lasttime->tv_sec) >= hz) { | |
| 986 | lasttime->tv_sec = now; | |
| 987 | *curpps = 1; | |
| 988 | return (maxpps != 0); | |
| 989 | } else { | |
| 990 | (*curpps)++; /* NB: ignore potential overflow */ | |
| 991 | return (maxpps < 0 || *curpps < maxpps); | |
| 992 | } | |
| 993 | } | |
| 994 |