1/* 2 * Copyright (c) 2000-2008 Apple Inc. All rights reserved. 3 * 4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@ 5 * 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. 14 * 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 20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 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. 25 * 26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@ 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 */ 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 */ 69 70#include <sys/param.h> 71#include <sys/resourcevar.h> 72#include <sys/kernel.h> 73#include <sys/systm.h> 74#include <sys/proc_internal.h> 75#include <sys/kauth.h> 76#include <sys/vnode.h> 77#include <sys/time.h> 78#include <sys/priv.h> 79 80#include <sys/mount_internal.h> 81#include <sys/sysproto.h> 82#include <sys/signalvar.h> 83#include <sys/protosw.h> /* for net_uptime2timeval() */ 84 85#include <kern/clock.h> 86#include <kern/task.h> 87#include <kern/thread_call.h> 88#if CONFIG_MACF 89#include <security/mac_framework.h> 90#endif 91 92#define HZ 100 /* XXX */ 93 94/* simple lock used to access timezone, tz structure */ 95lck_spin_t * tz_slock; 96lck_grp_t * tz_slock_grp; 97lck_attr_t * tz_slock_attr; 98lck_grp_attr_t *tz_slock_grp_attr; 99 100static void setthetime( 101 struct timeval *tv); 102 103void time_zone_slock_init(void); 104 105/* 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 */ 114/* ARGSUSED */ 115int 116gettimeofday( 117__unused struct proc *p, 118 struct gettimeofday_args *uap, 119 int32_t *retval) 120{ 121 int error = 0; 122 struct timezone ltz; /* local copy */ 123 124 if (uap->tp) { 125 clock_sec_t secs; 126 clock_usec_t usecs; 127 128 clock_gettimeofday(&secs, &usecs); 129 retval[0] = secs; 130 retval[1] = usecs; 131 } 132 133 if (uap->tzp) { 134 lck_spin_lock(tz_slock); 135 ltz = tz; 136 lck_spin_unlock(tz_slock); 137 138 error = copyout((caddr_t)<z, CAST_USER_ADDR_T(uap->tzp), sizeof (tz)); 139 } 140 141 return (error); 142} 143 144/* 145 * XXX Y2038 bug because of setthetime() argument 146 */ 147/* ARGSUSED */ 148int 149settimeofday(__unused struct proc *p, struct settimeofday_args *uap, __unused int32_t *retval) 150{ 151 struct timeval atv; 152 struct timezone atz; 153 int error; 154 155 bzero(&atv, sizeof(atv)); 156 157#if CONFIG_MACF 158 error = mac_system_check_settime(kauth_cred_get()); 159 if (error) 160 return (error); 161#endif 162 if ((error = suser(kauth_cred_get(), &p->p_acflag))) 163 return (error); 164 /* Verify all parameters before changing time */ 165 if (uap->tv) { 166 if (IS_64BIT_PROCESS(p)) { 167 struct user64_timeval user_atv; 168 error = copyin(uap->tv, &user_atv, sizeof(user_atv)); 169 atv.tv_sec = user_atv.tv_sec; 170 atv.tv_usec = user_atv.tv_usec; 171 } else { 172 struct user32_timeval user_atv; 173 error = copyin(uap->tv, &user_atv, sizeof(user_atv)); 174 atv.tv_sec = user_atv.tv_sec; 175 atv.tv_usec = user_atv.tv_usec; 176 } 177 if (error) 178 return (error); 179 } 180 if (uap->tzp && (error = copyin(uap->tzp, (caddr_t)&atz, sizeof(atz)))) 181 return (error); 182 if (uap->tv) { 183 timevalfix(&atv); 184 if (atv.tv_sec < 0 || (atv.tv_sec == 0 && atv.tv_usec < 0)) 185 return (EPERM); 186 setthetime(&atv); 187 } 188 if (uap->tzp) { 189 lck_spin_lock(tz_slock); 190 tz = atz; 191 lck_spin_unlock(tz_slock); 192 } 193 return (0); 194} 195 196static void 197setthetime( 198 struct timeval *tv) 199{ 200 clock_set_calendar_microtime(tv->tv_sec, tv->tv_usec); 201} 202 203/* 204 * XXX Y2038 bug because of clock_adjtime() first argument 205 */ 206/* ARGSUSED */ 207int 208adjtime(struct proc *p, struct adjtime_args *uap, __unused int32_t *retval) 209{ 210 struct timeval atv; 211 int error; 212 213#if CONFIG_MACF 214 error = mac_system_check_settime(kauth_cred_get()); 215 if (error) 216 return (error); 217#endif 218 if ((error = priv_check_cred(kauth_cred_get(), PRIV_ADJTIME, 0))) 219 return (error); 220 if (IS_64BIT_PROCESS(p)) { 221 struct user64_timeval user_atv; 222 error = copyin(uap->delta, &user_atv, sizeof(user_atv)); 223 atv.tv_sec = user_atv.tv_sec; 224 atv.tv_usec = user_atv.tv_usec; 225 } else { 226 struct user32_timeval user_atv; 227 error = copyin(uap->delta, &user_atv, sizeof(user_atv)); 228 atv.tv_sec = user_atv.tv_sec; 229 atv.tv_usec = user_atv.tv_usec; 230 } 231 if (error) 232 return (error); 233 234 /* 235 * Compute the total correction and the rate at which to apply it. 236 */ 237 clock_adjtime(&atv.tv_sec, &atv.tv_usec); 238 239 if (uap->olddelta) { 240 if (IS_64BIT_PROCESS(p)) { 241 struct user64_timeval user_atv; 242 user_atv.tv_sec = atv.tv_sec; 243 user_atv.tv_usec = atv.tv_usec; 244 error = copyout(&user_atv, uap->olddelta, sizeof(user_atv)); 245 } else { 246 struct user32_timeval user_atv; 247 user_atv.tv_sec = atv.tv_sec; 248 user_atv.tv_usec = atv.tv_usec; 249 error = copyout(&user_atv, uap->olddelta, sizeof(user_atv)); 250 } 251 } 252 253 return (0); 254} 255 256/* 257 * Verify the calendar value. If negative, 258 * reset to zero (the epoch). 259 */ 260void 261inittodr( 262 __unused time_t base) 263{ 264 struct timeval tv; 265 266 /* 267 * Assertion: 268 * The calendar has already been 269 * set up from the platform clock. 270 * 271 * The value returned by microtime() 272 * is gotten from the calendar. 273 */ 274 microtime(&tv); 275 276 if (tv.tv_sec < 0 || tv.tv_usec < 0) { 277 printf ("WARNING: preposterous time in Real Time Clock"); 278 tv.tv_sec = 0; /* the UNIX epoch */ 279 tv.tv_usec = 0; 280 setthetime(&tv); 281 printf(" -- CHECK AND RESET THE DATE!\n"); 282 } 283} 284 285time_t 286boottime_sec(void) 287{ 288 clock_sec_t secs; 289 clock_nsec_t nanosecs; 290 291 clock_get_boottime_nanotime(&secs, &nanosecs); 292 return (secs); 293} 294 295/* 296 * Get value of an interval timer. The process virtual and 297 * profiling virtual time timers are kept internally in the 298 * way they are specified externally: in time until they expire. 299 * 300 * The real time interval timer expiration time (p_rtime) 301 * is kept as an absolute time rather than as a delta, so that 302 * it is easy to keep periodic real-time signals from drifting. 303 * 304 * The real time timer is processed by a callout routine. 305 * Since a callout may be delayed in real time due to 306 * other processing in the system, it is possible for the real 307 * time callout routine (realitexpire, given below), to be delayed 308 * in real time past when it is supposed to occur. It does not 309 * suffice, therefore, to reload the real time .it_value from the 310 * real time .it_interval. Rather, we compute the next time in 311 * absolute time when the timer should go off. 312 * 313 * Returns: 0 Success 314 * EINVAL Invalid argument 315 * copyout:EFAULT Bad address 316 */ 317/* ARGSUSED */ 318int 319getitimer(struct proc *p, struct getitimer_args *uap, __unused int32_t *retval) 320{ 321 struct itimerval aitv; 322 323 if (uap->which > ITIMER_PROF) 324 return(EINVAL); 325 326 bzero(&aitv, sizeof(aitv)); 327 328 proc_spinlock(p); 329 switch (uap->which) { 330 331 case ITIMER_REAL: 332 /* 333 * If time for real time timer has passed return 0, 334 * else return difference between current time and 335 * time for the timer to go off. 336 */ 337 aitv = p->p_realtimer; 338 if (timerisset(&p->p_rtime)) { 339 struct timeval now; 340 341 microuptime(&now); 342 if (timercmp(&p->p_rtime, &now, <)) 343 timerclear(&aitv.it_value); 344 else { 345 aitv.it_value = p->p_rtime; 346 timevalsub(&aitv.it_value, &now); 347 } 348 } 349 else 350 timerclear(&aitv.it_value); 351 break; 352 353 case ITIMER_VIRTUAL: 354 aitv = p->p_vtimer_user; 355 break; 356 357 case ITIMER_PROF: 358 aitv = p->p_vtimer_prof; 359 break; 360 } 361 362 proc_spinunlock(p); 363 364 if (IS_64BIT_PROCESS(p)) { 365 struct user64_itimerval user_itv; 366 user_itv.it_interval.tv_sec = aitv.it_interval.tv_sec; 367 user_itv.it_interval.tv_usec = aitv.it_interval.tv_usec; 368 user_itv.it_value.tv_sec = aitv.it_value.tv_sec; 369 user_itv.it_value.tv_usec = aitv.it_value.tv_usec; 370 return (copyout((caddr_t)&user_itv, uap->itv, sizeof (user_itv))); 371 } else { 372 struct user32_itimerval user_itv; 373 user_itv.it_interval.tv_sec = aitv.it_interval.tv_sec; 374 user_itv.it_interval.tv_usec = aitv.it_interval.tv_usec; 375 user_itv.it_value.tv_sec = aitv.it_value.tv_sec; 376 user_itv.it_value.tv_usec = aitv.it_value.tv_usec; 377 return (copyout((caddr_t)&user_itv, uap->itv, sizeof (user_itv))); 378 } 379} 380 381/* 382 * Returns: 0 Success 383 * EINVAL Invalid argument 384 * copyin:EFAULT Bad address 385 * getitimer:EINVAL Invalid argument 386 * getitimer:EFAULT Bad address 387 */ 388/* ARGSUSED */ 389int 390setitimer(struct proc *p, struct setitimer_args *uap, int32_t *retval) 391{ 392 struct itimerval aitv; 393 user_addr_t itvp; 394 int error; 395 396 bzero(&aitv, sizeof(aitv)); 397 398 if (uap->which > ITIMER_PROF) 399 return (EINVAL); 400 if ((itvp = uap->itv)) { 401 if (IS_64BIT_PROCESS(p)) { 402 struct user64_itimerval user_itv; 403 if ((error = copyin(itvp, (caddr_t)&user_itv, sizeof (user_itv)))) 404 return (error); 405 aitv.it_interval.tv_sec = user_itv.it_interval.tv_sec; 406 aitv.it_interval.tv_usec = user_itv.it_interval.tv_usec; 407 aitv.it_value.tv_sec = user_itv.it_value.tv_sec; 408 aitv.it_value.tv_usec = user_itv.it_value.tv_usec; 409 } else { 410 struct user32_itimerval user_itv; 411 if ((error = copyin(itvp, (caddr_t)&user_itv, sizeof (user_itv)))) 412 return (error); 413 aitv.it_interval.tv_sec = user_itv.it_interval.tv_sec; 414 aitv.it_interval.tv_usec = user_itv.it_interval.tv_usec; 415 aitv.it_value.tv_sec = user_itv.it_value.tv_sec; 416 aitv.it_value.tv_usec = user_itv.it_value.tv_usec; 417 } 418 } 419 if ((uap->itv = uap->oitv) && (error = getitimer(p, (struct getitimer_args *)uap, retval))) 420 return (error); 421 if (itvp == 0) 422 return (0); 423 if (itimerfix(&aitv.it_value) || itimerfix(&aitv.it_interval)) 424 return (EINVAL); 425 426 switch (uap->which) { 427 428 case ITIMER_REAL: 429 proc_spinlock(p); 430 if (timerisset(&aitv.it_value)) { 431 microuptime(&p->p_rtime); 432 timevaladd(&p->p_rtime, &aitv.it_value); 433 p->p_realtimer = aitv; 434 if (!thread_call_enter_delayed_with_leeway(p->p_rcall, NULL, 435 tvtoabstime(&p->p_rtime), 0, THREAD_CALL_DELAY_USER_NORMAL)) 436 p->p_ractive++; 437 } else { 438 timerclear(&p->p_rtime); 439 p->p_realtimer = aitv; 440 if (thread_call_cancel(p->p_rcall)) 441 p->p_ractive--; 442 } 443 proc_spinunlock(p); 444 445 break; 446 447 448 case ITIMER_VIRTUAL: 449 if (timerisset(&aitv.it_value)) 450 task_vtimer_set(p->task, TASK_VTIMER_USER); 451 else 452 task_vtimer_clear(p->task, TASK_VTIMER_USER); 453 454 proc_spinlock(p); 455 p->p_vtimer_user = aitv; 456 proc_spinunlock(p); 457 break; 458 459 case ITIMER_PROF: 460 if (timerisset(&aitv.it_value)) 461 task_vtimer_set(p->task, TASK_VTIMER_PROF); 462 else 463 task_vtimer_clear(p->task, TASK_VTIMER_PROF); 464 465 proc_spinlock(p); 466 p->p_vtimer_prof = aitv; 467 proc_spinunlock(p); 468 break; 469 } 470 471 return (0); 472} 473 474/* 475 * Real interval timer expired: 476 * send process whose timer expired an alarm signal. 477 * If time is not set up to reload, then just return. 478 * Else compute next time timer should go off which is > current time. 479 * This is where delay in processing this timeout causes multiple 480 * SIGALRM calls to be compressed into one. 481 */ 482void 483realitexpire( 484 struct proc *p) 485{ 486 struct proc *r; 487 struct timeval t; 488 489 r = proc_find(p->p_pid); 490 491 proc_spinlock(p); 492 493 if (--p->p_ractive > 0 || r != p) { 494 proc_spinunlock(p); 495 496 if (r != NULL) 497 proc_rele(r); 498 return; 499 } 500 501 if (!timerisset(&p->p_realtimer.it_interval)) { 502 timerclear(&p->p_rtime); 503 proc_spinunlock(p); 504 505 psignal(p, SIGALRM); 506 proc_rele(p); 507 return; 508 } 509 510 microuptime(&t); 511 timevaladd(&p->p_rtime, &p->p_realtimer.it_interval); 512 if (timercmp(&p->p_rtime, &t, <=)) { 513 if ((p->p_rtime.tv_sec + 2) >= t.tv_sec) { 514 for (;;) { 515 timevaladd(&p->p_rtime, &p->p_realtimer.it_interval); 516 if (timercmp(&p->p_rtime, &t, >)) 517 break; 518 } 519 } 520 else { 521 p->p_rtime = p->p_realtimer.it_interval; 522 timevaladd(&p->p_rtime, &t); 523 } 524 } 525 526 if (!thread_call_enter_delayed(p->p_rcall, tvtoabstime(&p->p_rtime))) 527 p->p_ractive++; 528 proc_spinunlock(p); 529 530 psignal(p, SIGALRM); 531 proc_rele(p); 532} 533 534/* 535 * Check that a proposed value to load into the .it_value or 536 * .it_interval part of an interval timer is acceptable. 537 */ 538int 539itimerfix( 540 struct timeval *tv) 541{ 542 543 if (tv->tv_sec < 0 || tv->tv_sec > 100000000 || 544 tv->tv_usec < 0 || tv->tv_usec >= 1000000) 545 return (EINVAL); 546 return (0); 547} 548 549/* 550 * Decrement an interval timer by a specified number 551 * of microseconds, which must be less than a second, 552 * i.e. < 1000000. If the timer expires, then reload 553 * it. In this case, carry over (usec - old value) to 554 * reduce the value reloaded into the timer so that 555 * the timer does not drift. This routine assumes 556 * that it is called in a context where the timers 557 * on which it is operating cannot change in value. 558 */ 559int 560itimerdecr(proc_t p, 561 struct itimerval *itp, int usec) 562{ 563 564 proc_spinlock(p); 565 566 if (itp->it_value.tv_usec < usec) { 567 if (itp->it_value.tv_sec == 0) { 568 /* expired, and already in next interval */ 569 usec -= itp->it_value.tv_usec; 570 goto expire; 571 } 572 itp->it_value.tv_usec += 1000000; 573 itp->it_value.tv_sec--; 574 } 575 itp->it_value.tv_usec -= usec; 576 usec = 0; 577 if (timerisset(&itp->it_value)) { 578 proc_spinunlock(p); 579 return (1); 580 } 581 /* expired, exactly at end of interval */ 582expire: 583 if (timerisset(&itp->it_interval)) { 584 itp->it_value = itp->it_interval; 585 if (itp->it_value.tv_sec > 0) { 586 itp->it_value.tv_usec -= usec; 587 if (itp->it_value.tv_usec < 0) { 588 itp->it_value.tv_usec += 1000000; 589 itp->it_value.tv_sec--; 590 } 591 } 592 } else 593 itp->it_value.tv_usec = 0; /* sec is already 0 */ 594 proc_spinunlock(p); 595 return (0); 596} 597 598/* 599 * Add and subtract routines for timevals. 600 * N.B.: subtract routine doesn't deal with 601 * results which are before the beginning, 602 * it just gets very confused in this case. 603 * Caveat emptor. 604 */ 605void 606timevaladd( 607 struct timeval *t1, 608 struct timeval *t2) 609{ 610 611 t1->tv_sec += t2->tv_sec; 612 t1->tv_usec += t2->tv_usec; 613 timevalfix(t1); 614} 615void 616timevalsub( 617 struct timeval *t1, 618 struct timeval *t2) 619{ 620 621 t1->tv_sec -= t2->tv_sec; 622 t1->tv_usec -= t2->tv_usec; 623 timevalfix(t1); 624} 625void 626timevalfix( 627 struct timeval *t1) 628{ 629 630 if (t1->tv_usec < 0) { 631 t1->tv_sec--; 632 t1->tv_usec += 1000000; 633 } 634 if (t1->tv_usec >= 1000000) { 635 t1->tv_sec++; 636 t1->tv_usec -= 1000000; 637 } 638} 639 640/* 641 * Return the best possible estimate of the time in the timeval 642 * to which tvp points. 643 */ 644void 645microtime( 646 struct timeval *tvp) 647{ 648 clock_sec_t tv_sec; 649 clock_usec_t tv_usec; 650 651 clock_get_calendar_microtime(&tv_sec, &tv_usec); 652 653 tvp->tv_sec = tv_sec; 654 tvp->tv_usec = tv_usec; 655} 656 657void 658microtime_with_abstime( 659 struct timeval *tvp, uint64_t *abstime) 660{ 661 clock_sec_t tv_sec; 662 clock_usec_t tv_usec; 663 664 clock_get_calendar_absolute_and_microtime(&tv_sec, &tv_usec, abstime); 665 666 tvp->tv_sec = tv_sec; 667 tvp->tv_usec = tv_usec; 668} 669 670void 671microuptime( 672 struct timeval *tvp) 673{ 674 clock_sec_t tv_sec; 675 clock_usec_t tv_usec; 676 677 clock_get_system_microtime(&tv_sec, &tv_usec); 678 679 tvp->tv_sec = tv_sec; 680 tvp->tv_usec = tv_usec; 681} 682 683/* 684 * Ditto for timespec. 685 */ 686void 687nanotime( 688 struct timespec *tsp) 689{ 690 clock_sec_t tv_sec; 691 clock_nsec_t tv_nsec; 692 693 clock_get_calendar_nanotime(&tv_sec, &tv_nsec); 694 695 tsp->tv_sec = tv_sec; 696 tsp->tv_nsec = tv_nsec; 697} 698 699void 700nanouptime( 701 struct timespec *tsp) 702{ 703 clock_sec_t tv_sec; 704 clock_nsec_t tv_nsec; 705 706 clock_get_system_nanotime(&tv_sec, &tv_nsec); 707 708 tsp->tv_sec = tv_sec; 709 tsp->tv_nsec = tv_nsec; 710} 711 712uint64_t 713tvtoabstime( 714 struct timeval *tvp) 715{ 716 uint64_t result, usresult; 717 718 clock_interval_to_absolutetime_interval( 719 tvp->tv_sec, NSEC_PER_SEC, &result); 720 clock_interval_to_absolutetime_interval( 721 tvp->tv_usec, NSEC_PER_USEC, &usresult); 722 723 return (result + usresult); 724} 725 726#if NETWORKING 727/* 728 * ratecheck(): simple time-based rate-limit checking. 729 */ 730int 731ratecheck(struct timeval *lasttime, const struct timeval *mininterval) 732{ 733 struct timeval tv, delta; 734 int rv = 0; 735 736 net_uptime2timeval(&tv); 737 delta = tv; 738 timevalsub(&delta, lasttime); 739 740 /* 741 * check for 0,0 is so that the message will be seen at least once, 742 * even if interval is huge. 743 */ 744 if (timevalcmp(&delta, mininterval, >=) || 745 (lasttime->tv_sec == 0 && lasttime->tv_usec == 0)) { 746 *lasttime = tv; 747 rv = 1; 748 } 749 750 return (rv); 751} 752 753/* 754 * ppsratecheck(): packets (or events) per second limitation. 755 */ 756int 757ppsratecheck(struct timeval *lasttime, int *curpps, int maxpps) 758{ 759 struct timeval tv, delta; 760 int rv; 761 762 net_uptime2timeval(&tv); 763 764 timersub(&tv, lasttime, &delta); 765 766 /* 767 * Check for 0,0 so that the message will be seen at least once. 768 * If more than one second has passed since the last update of 769 * lasttime, reset the counter. 770 * 771 * we do increment *curpps even in *curpps < maxpps case, as some may 772 * try to use *curpps for stat purposes as well. 773 */ 774 if ((lasttime->tv_sec == 0 && lasttime->tv_usec == 0) || 775 delta.tv_sec >= 1) { 776 *lasttime = tv; 777 *curpps = 0; 778 rv = 1; 779 } else if (maxpps < 0) 780 rv = 1; 781 else if (*curpps < maxpps) 782 rv = 1; 783 else 784 rv = 0; 785 786#if 1 /* DIAGNOSTIC? */ 787 /* be careful about wrap-around */ 788 if (*curpps + 1 > 0) 789 *curpps = *curpps + 1; 790#else 791 /* 792 * assume that there's not too many calls to this function. 793 * not sure if the assumption holds, as it depends on *caller's* 794 * behavior, not the behavior of this function. 795 * IMHO it is wrong to make assumption on the caller's behavior, 796 * so the above #if is #if 1, not #ifdef DIAGNOSTIC. 797 */ 798 *curpps = *curpps + 1; 799#endif 800 801 return (rv); 802} 803#endif /* NETWORKING */ 804 805void 806time_zone_slock_init(void) 807{ 808 /* allocate lock group attribute and group */ 809 tz_slock_grp_attr = lck_grp_attr_alloc_init(); 810 811 tz_slock_grp = lck_grp_alloc_init("tzlock", tz_slock_grp_attr); 812 813 /* Allocate lock attribute */ 814 tz_slock_attr = lck_attr_alloc_init(); 815 816 /* Allocate the spin lock */ 817 tz_slock = lck_spin_alloc_init(tz_slock_grp, tz_slock_attr); 818} 819