clock_oldops.c
1 /* 2 * Copyright (c) 2000-2020 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 /* 29 * @OSF_COPYRIGHT@ 30 */ 31 /* 32 * DEPRECATED INTERFACES - Should be removed 33 * 34 * Purpose: Routines for the creation and use of kernel 35 * alarm clock services. This file and the ipc 36 * routines in kern/ipc_clock.c constitute the 37 * machine-independent clock service layer. 38 */ 39 40 #include <mach/mach_types.h> 41 42 #include <kern/host.h> 43 #include <kern/spl.h> 44 #include <kern/sched_prim.h> 45 #include <kern/thread.h> 46 #include <kern/ipc_host.h> 47 #include <kern/clock.h> 48 #include <kern/zalloc.h> 49 50 #include <ipc/ipc_types.h> 51 #include <ipc/ipc_port.h> 52 53 #include <mach/mach_traps.h> 54 #include <mach/mach_time.h> 55 56 #include <mach/clock_server.h> 57 #include <mach/clock_reply.h> 58 #include <mach/clock_priv_server.h> 59 60 #include <mach/mach_host_server.h> 61 #include <mach/host_priv_server.h> 62 #include <libkern/section_keywords.h> 63 64 /* 65 * Actual clock alarm structure. Used for user clock_sleep() and 66 * clock_alarm() calls. Alarms are allocated from the alarm free 67 * list and entered in time priority order into the active alarm 68 * chain of the target clock. 69 */ 70 struct alarm { 71 struct alarm *al_next; /* next alarm in chain */ 72 struct alarm *al_prev; /* previous alarm in chain */ 73 int al_status; /* alarm status */ 74 mach_timespec_t al_time; /* alarm time */ 75 struct { /* message alarm data */ 76 int type; /* alarm type */ 77 ipc_port_t port; /* alarm port */ 78 mach_msg_type_name_t 79 port_type; /* alarm port type */ 80 struct clock *clock; /* alarm clock */ 81 void *data; /* alarm data */ 82 } al_alrm; 83 #define al_type al_alrm.type 84 #define al_port al_alrm.port 85 #define al_port_type al_alrm.port_type 86 #define al_clock al_alrm.clock 87 #define al_data al_alrm.data 88 long al_seqno; /* alarm sequence number */ 89 }; 90 typedef struct alarm alarm_data_t; 91 92 /* alarm status */ 93 #define ALARM_FREE 0 /* alarm is on free list */ 94 #define ALARM_SLEEP 1 /* active clock_sleep() */ 95 #define ALARM_CLOCK 2 /* active clock_alarm() */ 96 #define ALARM_DONE 4 /* alarm has expired */ 97 98 /* local data declarations */ 99 decl_simple_lock_data(static, alarm_lock); /* alarm synchronization */ 100 /* zone for user alarms */ 101 static ZONE_DECLARE(alarm_zone, "alarms", sizeof(struct alarm), ZC_NONE); 102 static struct alarm *alrmfree; /* alarm free list pointer */ 103 static struct alarm *alrmdone; /* alarm done list pointer */ 104 static struct alarm *alrmlist; 105 static long alrm_seqno; /* uniquely identifies alarms */ 106 static thread_call_data_t alarm_done_call; 107 static timer_call_data_t alarm_expire_timer; 108 109 extern struct clock clock_list[]; 110 extern int clock_count; 111 112 static void post_alarm( 113 alarm_t alarm); 114 115 static void set_alarm( 116 mach_timespec_t *alarm_time); 117 118 static int check_time( 119 alarm_type_t alarm_type, 120 mach_timespec_t *alarm_time, 121 mach_timespec_t *clock_time); 122 123 static void alarm_done(void); 124 125 static void alarm_expire(void); 126 127 static kern_return_t clock_sleep_internal( 128 clock_t clock, 129 sleep_type_t sleep_type, 130 mach_timespec_t *sleep_time); 131 132 int rtclock_init(void); 133 134 kern_return_t rtclock_gettime( 135 mach_timespec_t *cur_time); 136 137 kern_return_t rtclock_getattr( 138 clock_flavor_t flavor, 139 clock_attr_t attr, 140 mach_msg_type_number_t *count); 141 142 SECURITY_READ_ONLY_EARLY(struct clock_ops) sysclk_ops = { 143 .c_config = NULL, 144 .c_init = rtclock_init, 145 .c_gettime = rtclock_gettime, 146 .c_getattr = rtclock_getattr, 147 }; 148 149 kern_return_t calend_gettime( 150 mach_timespec_t *cur_time); 151 152 kern_return_t calend_getattr( 153 clock_flavor_t flavor, 154 clock_attr_t attr, 155 mach_msg_type_number_t *count); 156 157 SECURITY_READ_ONLY_EARLY(struct clock_ops) calend_ops = { 158 .c_config = NULL, 159 .c_init = NULL, 160 .c_gettime = calend_gettime, 161 .c_getattr = calend_getattr, 162 }; 163 164 /* 165 * List of clock devices. 166 */ 167 SECURITY_READ_ONLY_LATE(struct clock) clock_list[] = { 168 [SYSTEM_CLOCK] = { 169 .cl_ops = &sysclk_ops, 170 .cl_service = IPC_PORT_NULL, 171 .cl_control = IPC_PORT_NULL, 172 }, 173 [CALENDAR_CLOCK] = { 174 .cl_ops = &calend_ops, 175 .cl_service = IPC_PORT_NULL, 176 .cl_control = IPC_PORT_NULL, 177 }, 178 }; 179 int clock_count = sizeof(clock_list) / sizeof(clock_list[0]); 180 181 /* 182 * Macros to lock/unlock clock system. 183 */ 184 #define LOCK_ALARM(s) \ 185 s = splclock(); \ 186 simple_lock(&alarm_lock, LCK_GRP_NULL); 187 188 #define UNLOCK_ALARM(s) \ 189 simple_unlock(&alarm_lock); \ 190 splx(s); 191 192 void 193 clock_oldconfig(void) 194 { 195 clock_t clock; 196 int i; 197 198 simple_lock_init(&alarm_lock, 0); 199 thread_call_setup(&alarm_done_call, (thread_call_func_t)alarm_done, NULL); 200 timer_call_setup(&alarm_expire_timer, (timer_call_func_t)alarm_expire, NULL); 201 202 /* 203 * Configure clock devices. 204 */ 205 for (i = 0; i < clock_count; i++) { 206 clock = &clock_list[i]; 207 if (clock->cl_ops && clock->cl_ops->c_config) { 208 if ((*clock->cl_ops->c_config)() == 0) { 209 clock->cl_ops = NULL; 210 } 211 } 212 } 213 214 /* start alarm sequence numbers at 0 */ 215 alrm_seqno = 0; 216 } 217 218 void 219 clock_oldinit(void) 220 { 221 clock_t clock; 222 int i; 223 224 /* 225 * Initialize basic clock structures. 226 */ 227 for (i = 0; i < clock_count; i++) { 228 clock = &clock_list[i]; 229 if (clock->cl_ops && clock->cl_ops->c_init) { 230 (*clock->cl_ops->c_init)(); 231 } 232 } 233 } 234 235 /* 236 * Initialize the clock ipc service facility. 237 */ 238 void 239 clock_service_create(void) 240 { 241 /* 242 * Initialize ipc clock services. 243 */ 244 for (int i = 0; i < clock_count; i++) { 245 clock_t clock = &clock_list[i]; 246 if (clock->cl_ops) { 247 ipc_clock_init(clock); 248 ipc_clock_enable(clock); 249 } 250 } 251 } 252 253 /* 254 * Get the service port on a clock. 255 */ 256 kern_return_t 257 host_get_clock_service( 258 host_t host, 259 clock_id_t clock_id, 260 clock_t *clock) /* OUT */ 261 { 262 if (host == HOST_NULL || clock_id < 0 || clock_id >= clock_count) { 263 *clock = CLOCK_NULL; 264 return KERN_INVALID_ARGUMENT; 265 } 266 267 *clock = &clock_list[clock_id]; 268 if ((*clock)->cl_ops == 0) { 269 return KERN_FAILURE; 270 } 271 return KERN_SUCCESS; 272 } 273 274 /* 275 * Get the control port on a clock. 276 */ 277 kern_return_t 278 host_get_clock_control( 279 host_priv_t host_priv, 280 clock_id_t clock_id, 281 clock_t *clock) /* OUT */ 282 { 283 if (host_priv == HOST_PRIV_NULL || 284 clock_id < 0 || clock_id >= clock_count) { 285 *clock = CLOCK_NULL; 286 return KERN_INVALID_ARGUMENT; 287 } 288 289 *clock = &clock_list[clock_id]; 290 if ((*clock)->cl_ops == 0) { 291 return KERN_FAILURE; 292 } 293 return KERN_SUCCESS; 294 } 295 296 /* 297 * Get the current clock time. 298 */ 299 kern_return_t 300 clock_get_time( 301 clock_t clock, 302 mach_timespec_t *cur_time) /* OUT */ 303 { 304 if (clock == CLOCK_NULL) { 305 return KERN_INVALID_ARGUMENT; 306 } 307 return (*clock->cl_ops->c_gettime)(cur_time); 308 } 309 310 kern_return_t 311 rtclock_gettime( 312 mach_timespec_t *time) /* OUT */ 313 { 314 clock_sec_t secs; 315 clock_nsec_t nsecs; 316 317 clock_get_system_nanotime(&secs, &nsecs); 318 time->tv_sec = (unsigned int)secs; 319 time->tv_nsec = nsecs; 320 321 return KERN_SUCCESS; 322 } 323 324 kern_return_t 325 calend_gettime( 326 mach_timespec_t *time) /* OUT */ 327 { 328 clock_sec_t secs; 329 clock_nsec_t nsecs; 330 331 clock_get_calendar_nanotime(&secs, &nsecs); 332 time->tv_sec = (unsigned int)secs; 333 time->tv_nsec = nsecs; 334 335 return KERN_SUCCESS; 336 } 337 338 /* 339 * Get clock attributes. 340 */ 341 kern_return_t 342 clock_get_attributes( 343 clock_t clock, 344 clock_flavor_t flavor, 345 clock_attr_t attr, /* OUT */ 346 mach_msg_type_number_t *count) /* IN/OUT */ 347 { 348 if (clock == CLOCK_NULL) { 349 return KERN_INVALID_ARGUMENT; 350 } 351 if (clock->cl_ops->c_getattr) { 352 return clock->cl_ops->c_getattr(flavor, attr, count); 353 } 354 return KERN_FAILURE; 355 } 356 357 kern_return_t 358 rtclock_getattr( 359 clock_flavor_t flavor, 360 clock_attr_t attr, /* OUT */ 361 mach_msg_type_number_t *count) /* IN/OUT */ 362 { 363 if (*count != 1) { 364 return KERN_FAILURE; 365 } 366 367 switch (flavor) { 368 case CLOCK_GET_TIME_RES: /* >0 res */ 369 case CLOCK_ALARM_CURRES: /* =0 no alarm */ 370 case CLOCK_ALARM_MINRES: 371 case CLOCK_ALARM_MAXRES: 372 *(clock_res_t *) attr = NSEC_PER_SEC / 100; 373 break; 374 375 default: 376 return KERN_INVALID_VALUE; 377 } 378 379 return KERN_SUCCESS; 380 } 381 382 kern_return_t 383 calend_getattr( 384 clock_flavor_t flavor, 385 clock_attr_t attr, /* OUT */ 386 mach_msg_type_number_t *count) /* IN/OUT */ 387 { 388 if (*count != 1) { 389 return KERN_FAILURE; 390 } 391 392 switch (flavor) { 393 case CLOCK_GET_TIME_RES: /* >0 res */ 394 *(clock_res_t *) attr = NSEC_PER_SEC / 100; 395 break; 396 397 case CLOCK_ALARM_CURRES: /* =0 no alarm */ 398 case CLOCK_ALARM_MINRES: 399 case CLOCK_ALARM_MAXRES: 400 *(clock_res_t *) attr = 0; 401 break; 402 403 default: 404 return KERN_INVALID_VALUE; 405 } 406 407 return KERN_SUCCESS; 408 } 409 410 /* 411 * Set the current clock time. 412 */ 413 kern_return_t 414 clock_set_time( 415 clock_t clock, 416 __unused mach_timespec_t new_time) 417 { 418 if (clock == CLOCK_NULL) { 419 return KERN_INVALID_ARGUMENT; 420 } 421 return KERN_FAILURE; 422 } 423 424 /* 425 * Set the clock alarm resolution. 426 */ 427 kern_return_t 428 clock_set_attributes( 429 clock_t clock, 430 __unused clock_flavor_t flavor, 431 __unused clock_attr_t attr, 432 __unused mach_msg_type_number_t count) 433 { 434 if (clock == CLOCK_NULL) { 435 return KERN_INVALID_ARGUMENT; 436 } 437 return KERN_FAILURE; 438 } 439 440 /* 441 * Setup a clock alarm. 442 */ 443 kern_return_t 444 clock_alarm( 445 clock_t clock, 446 alarm_type_t alarm_type, 447 mach_timespec_t alarm_time, 448 ipc_port_t alarm_port, 449 mach_msg_type_name_t alarm_port_type) 450 { 451 alarm_t alarm; 452 mach_timespec_t clock_time; 453 int chkstat; 454 kern_return_t reply_code; 455 spl_t s; 456 457 if (clock == CLOCK_NULL) { 458 return KERN_INVALID_ARGUMENT; 459 } 460 if (clock != &clock_list[SYSTEM_CLOCK]) { 461 return KERN_FAILURE; 462 } 463 if (IP_VALID(alarm_port) == 0) { 464 return KERN_INVALID_CAPABILITY; 465 } 466 467 /* 468 * Check alarm parameters. If parameters are invalid, 469 * send alarm message immediately. 470 */ 471 (*clock->cl_ops->c_gettime)(&clock_time); 472 chkstat = check_time(alarm_type, &alarm_time, &clock_time); 473 if (chkstat <= 0) { 474 reply_code = (chkstat < 0 ? KERN_INVALID_VALUE : KERN_SUCCESS); 475 clock_alarm_reply(alarm_port, alarm_port_type, 476 reply_code, alarm_type, clock_time); 477 return KERN_SUCCESS; 478 } 479 480 /* 481 * Get alarm and add to clock alarm list. 482 */ 483 484 LOCK_ALARM(s); 485 if ((alarm = alrmfree) == 0) { 486 UNLOCK_ALARM(s); 487 alarm = (alarm_t) zalloc(alarm_zone); 488 if (alarm == 0) { 489 return KERN_RESOURCE_SHORTAGE; 490 } 491 LOCK_ALARM(s); 492 } else { 493 alrmfree = alarm->al_next; 494 } 495 496 alarm->al_status = ALARM_CLOCK; 497 alarm->al_time = alarm_time; 498 alarm->al_type = alarm_type; 499 alarm->al_port = alarm_port; 500 alarm->al_port_type = alarm_port_type; 501 alarm->al_clock = clock; 502 alarm->al_seqno = alrm_seqno++; 503 post_alarm(alarm); 504 UNLOCK_ALARM(s); 505 506 return KERN_SUCCESS; 507 } 508 509 /* 510 * Sleep on a clock. System trap. User-level libmach clock_sleep 511 * interface call takes a mach_timespec_t sleep_time argument which it 512 * converts to sleep_sec and sleep_nsec arguments which are then 513 * passed to clock_sleep_trap. 514 */ 515 kern_return_t 516 clock_sleep_trap( 517 struct clock_sleep_trap_args *args) 518 { 519 mach_port_name_t clock_name = args->clock_name; 520 sleep_type_t sleep_type = args->sleep_type; 521 int sleep_sec = args->sleep_sec; 522 int sleep_nsec = args->sleep_nsec; 523 mach_vm_address_t wakeup_time_addr = args->wakeup_time; 524 clock_t clock; 525 mach_timespec_t swtime = {}; 526 kern_return_t rvalue; 527 528 /* 529 * Convert the trap parameters. 530 */ 531 if (clock_name == MACH_PORT_NULL) { 532 clock = &clock_list[SYSTEM_CLOCK]; 533 } else { 534 clock = port_name_to_clock(clock_name); 535 } 536 537 swtime.tv_sec = sleep_sec; 538 swtime.tv_nsec = sleep_nsec; 539 540 /* 541 * Call the actual clock_sleep routine. 542 */ 543 rvalue = clock_sleep_internal(clock, sleep_type, &swtime); 544 545 /* 546 * Return current time as wakeup time. 547 */ 548 if (rvalue != KERN_INVALID_ARGUMENT && rvalue != KERN_FAILURE) { 549 copyout((char *)&swtime, wakeup_time_addr, sizeof(mach_timespec_t)); 550 } 551 return rvalue; 552 } 553 554 static kern_return_t 555 clock_sleep_internal( 556 clock_t clock, 557 sleep_type_t sleep_type, 558 mach_timespec_t *sleep_time) 559 { 560 alarm_t alarm; 561 mach_timespec_t clock_time; 562 kern_return_t rvalue; 563 int chkstat; 564 spl_t s; 565 566 if (clock == CLOCK_NULL) { 567 return KERN_INVALID_ARGUMENT; 568 } 569 570 if (clock != &clock_list[SYSTEM_CLOCK]) { 571 return KERN_FAILURE; 572 } 573 574 /* 575 * Check sleep parameters. If parameters are invalid 576 * return an error, otherwise post alarm request. 577 */ 578 (*clock->cl_ops->c_gettime)(&clock_time); 579 580 chkstat = check_time(sleep_type, sleep_time, &clock_time); 581 if (chkstat < 0) { 582 return KERN_INVALID_VALUE; 583 } 584 rvalue = KERN_SUCCESS; 585 if (chkstat > 0) { 586 wait_result_t wait_result; 587 588 /* 589 * Get alarm and add to clock alarm list. 590 */ 591 592 LOCK_ALARM(s); 593 if ((alarm = alrmfree) == 0) { 594 UNLOCK_ALARM(s); 595 alarm = (alarm_t) zalloc(alarm_zone); 596 if (alarm == 0) { 597 return KERN_RESOURCE_SHORTAGE; 598 } 599 LOCK_ALARM(s); 600 } else { 601 alrmfree = alarm->al_next; 602 } 603 604 /* 605 * Wait for alarm to occur. 606 */ 607 wait_result = assert_wait((event_t)alarm, THREAD_ABORTSAFE); 608 if (wait_result == THREAD_WAITING) { 609 alarm->al_time = *sleep_time; 610 alarm->al_status = ALARM_SLEEP; 611 post_alarm(alarm); 612 UNLOCK_ALARM(s); 613 614 wait_result = thread_block(THREAD_CONTINUE_NULL); 615 616 /* 617 * Note if alarm expired normally or whether it 618 * was aborted. If aborted, delete alarm from 619 * clock alarm list. Return alarm to free list. 620 */ 621 LOCK_ALARM(s); 622 if (alarm->al_status != ALARM_DONE) { 623 assert(wait_result != THREAD_AWAKENED); 624 if (((alarm->al_prev)->al_next = alarm->al_next) != NULL) { 625 (alarm->al_next)->al_prev = alarm->al_prev; 626 } 627 rvalue = KERN_ABORTED; 628 } 629 *sleep_time = alarm->al_time; 630 alarm->al_status = ALARM_FREE; 631 } else { 632 assert(wait_result == THREAD_INTERRUPTED); 633 assert(alarm->al_status == ALARM_FREE); 634 rvalue = KERN_ABORTED; 635 } 636 alarm->al_next = alrmfree; 637 alrmfree = alarm; 638 UNLOCK_ALARM(s); 639 } else { 640 *sleep_time = clock_time; 641 } 642 643 return rvalue; 644 } 645 646 /* 647 * Service clock alarm expirations. 648 */ 649 static void 650 alarm_expire(void) 651 { 652 clock_t clock; 653 alarm_t alrm1; 654 alarm_t alrm2; 655 mach_timespec_t clock_time; 656 mach_timespec_t *alarm_time; 657 spl_t s; 658 659 clock = &clock_list[SYSTEM_CLOCK]; 660 (*clock->cl_ops->c_gettime)(&clock_time); 661 662 /* 663 * Update clock alarm list. Alarms that are due are moved 664 * to the alarmdone list to be serviced by a thread callout. 665 */ 666 LOCK_ALARM(s); 667 alrm1 = (alarm_t)&alrmlist; 668 while ((alrm2 = alrm1->al_next) != NULL) { 669 alarm_time = &alrm2->al_time; 670 if (CMP_MACH_TIMESPEC(alarm_time, &clock_time) > 0) { 671 break; 672 } 673 674 /* 675 * Alarm has expired, so remove it from the 676 * clock alarm list. 677 */ 678 if ((alrm1->al_next = alrm2->al_next) != NULL) { 679 (alrm1->al_next)->al_prev = alrm1; 680 } 681 682 /* 683 * If a clock_sleep() alarm, wakeup the thread 684 * which issued the clock_sleep() call. 685 */ 686 if (alrm2->al_status == ALARM_SLEEP) { 687 alrm2->al_next = NULL; 688 alrm2->al_status = ALARM_DONE; 689 alrm2->al_time = clock_time; 690 thread_wakeup((event_t)alrm2); 691 } 692 /* 693 * If a clock_alarm() alarm, place the alarm on 694 * the alarm done list and schedule the alarm 695 * delivery mechanism. 696 */ 697 else { 698 assert(alrm2->al_status == ALARM_CLOCK); 699 if ((alrm2->al_next = alrmdone) != NULL) { 700 alrmdone->al_prev = alrm2; 701 } else { 702 thread_call_enter(&alarm_done_call); 703 } 704 alrm2->al_prev = (alarm_t)&alrmdone; 705 alrmdone = alrm2; 706 alrm2->al_status = ALARM_DONE; 707 alrm2->al_time = clock_time; 708 } 709 } 710 711 /* 712 * Setup to expire for the next pending alarm. 713 */ 714 if (alrm2) { 715 set_alarm(alarm_time); 716 } 717 UNLOCK_ALARM(s); 718 } 719 720 static void 721 alarm_done(void) 722 { 723 alarm_t alrm; 724 kern_return_t code; 725 spl_t s; 726 727 LOCK_ALARM(s); 728 while ((alrm = alrmdone) != NULL) { 729 if ((alrmdone = alrm->al_next) != NULL) { 730 alrmdone->al_prev = (alarm_t)&alrmdone; 731 } 732 UNLOCK_ALARM(s); 733 734 code = (alrm->al_status == ALARM_DONE? KERN_SUCCESS: KERN_ABORTED); 735 if (alrm->al_port != IP_NULL) { 736 /* Deliver message to designated port */ 737 if (IP_VALID(alrm->al_port)) { 738 clock_alarm_reply(alrm->al_port, alrm->al_port_type, code, 739 alrm->al_type, alrm->al_time); 740 } 741 742 LOCK_ALARM(s); 743 alrm->al_status = ALARM_FREE; 744 alrm->al_next = alrmfree; 745 alrmfree = alrm; 746 } else { 747 panic("clock_alarm_deliver"); 748 } 749 } 750 751 UNLOCK_ALARM(s); 752 } 753 754 /* 755 * Post an alarm on the active alarm list. 756 * 757 * Always called from within a LOCK_ALARM() code section. 758 */ 759 static void 760 post_alarm( 761 alarm_t alarm) 762 { 763 alarm_t alrm1, alrm2; 764 mach_timespec_t *alarm_time; 765 mach_timespec_t *queue_time; 766 767 /* 768 * Traverse alarm list until queue time is greater 769 * than alarm time, then insert alarm. 770 */ 771 alarm_time = &alarm->al_time; 772 alrm1 = (alarm_t)&alrmlist; 773 while ((alrm2 = alrm1->al_next) != NULL) { 774 queue_time = &alrm2->al_time; 775 if (CMP_MACH_TIMESPEC(queue_time, alarm_time) > 0) { 776 break; 777 } 778 alrm1 = alrm2; 779 } 780 alrm1->al_next = alarm; 781 alarm->al_next = alrm2; 782 alarm->al_prev = alrm1; 783 if (alrm2) { 784 alrm2->al_prev = alarm; 785 } 786 787 /* 788 * If the inserted alarm is the 'earliest' alarm, 789 * reset the device layer alarm time accordingly. 790 */ 791 if (alrmlist == alarm) { 792 set_alarm(alarm_time); 793 } 794 } 795 796 static void 797 set_alarm( 798 mach_timespec_t *alarm_time) 799 { 800 uint64_t abstime; 801 802 nanotime_to_absolutetime(alarm_time->tv_sec, alarm_time->tv_nsec, &abstime); 803 timer_call_enter_with_leeway(&alarm_expire_timer, NULL, abstime, 0, TIMER_CALL_USER_NORMAL, FALSE); 804 } 805 806 /* 807 * Check the validity of 'alarm_time' and 'alarm_type'. If either 808 * argument is invalid, return a negative value. If the 'alarm_time' 809 * is now, return a 0 value. If the 'alarm_time' is in the future, 810 * return a positive value. 811 */ 812 static int 813 check_time( 814 alarm_type_t alarm_type, 815 mach_timespec_t *alarm_time, 816 mach_timespec_t *clock_time) 817 { 818 int result; 819 820 if (BAD_ALRMTYPE(alarm_type)) { 821 return -1; 822 } 823 if (BAD_MACH_TIMESPEC(alarm_time)) { 824 return -1; 825 } 826 if ((alarm_type & ALRMTYPE) == TIME_RELATIVE) { 827 ADD_MACH_TIMESPEC(alarm_time, clock_time); 828 } 829 830 result = CMP_MACH_TIMESPEC(alarm_time, clock_time); 831 832 return (result >= 0)? result: 0; 833 } 834 835 #ifndef __LP64__ 836 837 mach_timespec_t 838 clock_get_system_value(void) 839 { 840 clock_t clock = &clock_list[SYSTEM_CLOCK]; 841 mach_timespec_t value; 842 843 (void) (*clock->cl_ops->c_gettime)(&value); 844 845 return value; 846 } 847 848 mach_timespec_t 849 clock_get_calendar_value(void) 850 { 851 clock_t clock = &clock_list[CALENDAR_CLOCK]; 852 mach_timespec_t value = MACH_TIMESPEC_ZERO; 853 854 (void) (*clock->cl_ops->c_gettime)(&value); 855 856 return value; 857 } 858 859 #endif /* __LP64__ */