|
|
1.1 ! root 1: /* ! 2: * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. ! 3: * ! 4: * @APPLE_LICENSE_HEADER_START@ ! 5: * ! 6: * The contents of this file constitute Original Code as defined in and ! 7: * are subject to the Apple Public Source License Version 1.1 (the ! 8: * "License"). You may not use this file except in compliance with the ! 9: * License. Please obtain a copy of the License at ! 10: * http://www.apple.com/publicsource and read it before using this file. ! 11: * ! 12: * This Original Code and all software distributed under the License are ! 13: * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER ! 14: * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, ! 15: * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, ! 16: * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the ! 17: * License for the specific language governing rights and limitations ! 18: * under the License. ! 19: * ! 20: * @APPLE_LICENSE_HEADER_END@ ! 21: */ ! 22: /* ! 23: * @OSF_COPYRIGHT@ ! 24: */ ! 25: /* ! 26: * File: kern/clock.c ! 27: * Purpose: Routines for the creation and use of kernel ! 28: * alarm clock services. This file and the ipc ! 29: * routines in kern/ipc_clock.c constitute the ! 30: * machine-independent clock service layer. ! 31: */ ! 32: ! 33: #include <cpus.h> ! 34: #include <mach_host.h> ! 35: ! 36: #include <mach/boolean.h> ! 37: #include <mach/policy.h> ! 38: #include <mach/processor_info.h> ! 39: #include <mach/vm_param.h> ! 40: #include <machine/mach_param.h> ! 41: #include <kern/cpu_number.h> ! 42: #include <kern/misc_protos.h> ! 43: #include <kern/lock.h> ! 44: #include <kern/host.h> ! 45: #include <kern/processor.h> ! 46: #include <kern/sched.h> ! 47: #include <kern/spl.h> ! 48: #include <kern/thread.h> ! 49: #include <kern/thread_swap.h> ! 50: #include <kern/ipc_host.h> ! 51: #include <kern/clock.h> ! 52: #include <kern/zalloc.h> ! 53: #include <kern/sf.h> ! 54: #include <ipc/ipc_port.h> ! 55: #include <mach/mach_syscalls.h> ! 56: ! 57: #include <mach/clock_reply.h> ! 58: ! 59: /* ! 60: * Exported interface ! 61: */ ! 62: ! 63: #include <mach/clock_server.h> ! 64: #include <mach/mach_host_server.h> ! 65: ! 66: /* local data declarations */ ! 67: decl_simple_lock_data(static,ClockLock) /* clock system synchronization */ ! 68: static struct zone *alarm_zone; /* zone for user alarms */ ! 69: static struct alarm *alrmfree; /* alarm free list pointer */ ! 70: static struct alarm *alrmdone; /* alarm done list pointer */ ! 71: static long alrm_seqno; /* uniquely identifies alarms */ ! 72: static thread_call_data_t alarm_deliver; ! 73: ! 74: /* backwards compatibility */ ! 75: int hz = HZ; /* GET RID OF THIS !!! */ ! 76: int tick = (1000000 / HZ); /* GET RID OF THIS !!! */ ! 77: ! 78: /* external declarations */ ! 79: extern struct clock clock_list[]; ! 80: extern int clock_count; ! 81: ! 82: /* local clock subroutines */ ! 83: static ! 84: void flush_alarms( ! 85: clock_t clock); ! 86: ! 87: static ! 88: void post_alarm( ! 89: clock_t clock, ! 90: alarm_t alarm); ! 91: ! 92: static ! 93: int check_time( ! 94: alarm_type_t alarm_type, ! 95: mach_timespec_t *alarm_time, ! 96: mach_timespec_t *clock_time); ! 97: ! 98: static void clock_alarm_deliver(void); ! 99: ! 100: /* ! 101: * Macros to lock/unlock clock system. ! 102: */ ! 103: #define LOCK_CLOCK(s) \ ! 104: s = splclock(); \ ! 105: simple_lock(&ClockLock); ! 106: ! 107: #define UNLOCK_CLOCK(s) \ ! 108: simple_unlock(&ClockLock); \ ! 109: splx(s); ! 110: ! 111: /* ! 112: * Configure the clock system. (Not sure if we need this, ! 113: * as separate from clock_init()). ! 114: */ ! 115: void ! 116: clock_config(void) ! 117: { ! 118: clock_t clock; ! 119: register int i; ! 120: ! 121: if (cpu_number() != master_cpu) ! 122: panic("clock_config"); ! 123: ! 124: /* ! 125: * Configure clock devices. ! 126: */ ! 127: simple_lock_init(&ClockLock, ETAP_MISC_CLOCK); ! 128: for (i = 0; i < clock_count; i++) { ! 129: clock = &clock_list[i]; ! 130: if (clock->cl_ops) { ! 131: if ((*clock->cl_ops->c_config)() == 0) ! 132: clock->cl_ops = 0; ! 133: } ! 134: } ! 135: ! 136: /* start alarm sequence numbers at 0 */ ! 137: alrm_seqno = 0; ! 138: } ! 139: ! 140: /* ! 141: * Initialize the clock system. ! 142: */ ! 143: void ! 144: clock_init(void) ! 145: { ! 146: clock_t clock; ! 147: register int i; ! 148: ! 149: /* ! 150: * Initialize basic clock structures. ! 151: */ ! 152: for (i = 0; i < clock_count; i++) { ! 153: clock = &clock_list[i]; ! 154: if (clock->cl_ops) ! 155: (*clock->cl_ops->c_init)(); ! 156: } ! 157: } ! 158: ! 159: /* ! 160: * Initialize the clock ipc service facility. ! 161: */ ! 162: void ! 163: clock_service_create(void) ! 164: { ! 165: clock_t clock; ! 166: register int i; ! 167: ! 168: /* ! 169: * Initialize ipc clock services. ! 170: */ ! 171: for (i = 0; i < clock_count; i++) { ! 172: clock = &clock_list[i]; ! 173: if (clock->cl_ops) { ! 174: ipc_clock_init(clock); ! 175: ipc_clock_enable(clock); ! 176: } ! 177: } ! 178: ! 179: /* ! 180: * Initialize clock service alarms. ! 181: */ ! 182: i = sizeof(struct alarm); ! 183: alarm_zone = zinit(i, (4096/i)*i, 10*i, "alarms"); ! 184: ! 185: /* ! 186: * Initialize the clock alarm delivery mechanism. ! 187: */ ! 188: thread_call_setup(&alarm_deliver, clock_alarm_deliver, NULL); ! 189: } ! 190: ! 191: /* ! 192: * Get the service port on a clock. ! 193: */ ! 194: kern_return_t ! 195: host_get_clock_service( ! 196: host_t host, ! 197: clock_id_t clock_id, ! 198: clock_t *clock) /* OUT */ ! 199: { ! 200: if (host == HOST_NULL || clock_id < 0 || clock_id >= clock_count) { ! 201: *clock = CLOCK_NULL; ! 202: return (KERN_INVALID_ARGUMENT); ! 203: } ! 204: ! 205: *clock = &clock_list[clock_id]; ! 206: if ((*clock)->cl_ops == 0) ! 207: return (KERN_FAILURE); ! 208: return (KERN_SUCCESS); ! 209: } ! 210: ! 211: /* ! 212: * Get the control port on a clock. ! 213: */ ! 214: kern_return_t ! 215: host_get_clock_control( ! 216: host_t host, ! 217: clock_id_t clock_id, ! 218: clock_t *clock) /* OUT */ ! 219: { ! 220: if (host == HOST_NULL || clock_id < 0 || clock_id >= clock_count) { ! 221: *clock = CLOCK_NULL; ! 222: return (KERN_INVALID_ARGUMENT); ! 223: } ! 224: ! 225: *clock = &clock_list[clock_id]; ! 226: if ((*clock)->cl_ops == 0) ! 227: return (KERN_FAILURE); ! 228: return (KERN_SUCCESS); ! 229: } ! 230: ! 231: /* ! 232: * Get the current clock time. ! 233: */ ! 234: kern_return_t ! 235: clock_get_time( ! 236: clock_t clock, ! 237: mach_timespec_t *cur_time) /* OUT */ ! 238: { ! 239: if (clock == CLOCK_NULL) ! 240: return (KERN_INVALID_ARGUMENT); ! 241: return ((*clock->cl_ops->c_gettime)(cur_time)); ! 242: } ! 243: ! 244: /* ! 245: * Get clock attributes. ! 246: */ ! 247: kern_return_t ! 248: clock_get_attributes( ! 249: clock_t clock, ! 250: clock_flavor_t flavor, ! 251: clock_attr_t attr, /* OUT */ ! 252: mach_msg_type_number_t *count) /* IN/OUT */ ! 253: { ! 254: kern_return_t (*getattr)( ! 255: clock_flavor_t flavor, ! 256: clock_attr_t attr, ! 257: mach_msg_type_number_t *count); ! 258: ! 259: if (clock == CLOCK_NULL) ! 260: return (KERN_INVALID_ARGUMENT); ! 261: if (getattr = clock->cl_ops->c_getattr) ! 262: return((*getattr)(flavor, attr, count)); ! 263: else ! 264: return (KERN_FAILURE); ! 265: } ! 266: ! 267: /* ! 268: * Set the current clock time. ! 269: */ ! 270: kern_return_t ! 271: clock_set_time( ! 272: clock_t clock, ! 273: mach_timespec_t new_time) ! 274: { ! 275: mach_timespec_t *clock_time; ! 276: kern_return_t (*settime)( ! 277: mach_timespec_t *clock_time); ! 278: ! 279: if (clock == CLOCK_NULL) ! 280: return (KERN_INVALID_ARGUMENT); ! 281: if ((settime = clock->cl_ops->c_settime) == 0) ! 282: return (KERN_FAILURE); ! 283: clock_time = &new_time; ! 284: if (BAD_MACH_TIMESPEC(clock_time)) ! 285: return (KERN_INVALID_VALUE); ! 286: ! 287: /* ! 288: * Flush all outstanding alarms. ! 289: */ ! 290: flush_alarms(clock); ! 291: ! 292: /* ! 293: * Set the new time. ! 294: */ ! 295: return ((*settime)(clock_time)); ! 296: } ! 297: ! 298: /* ! 299: * Set the clock alarm resolution. ! 300: */ ! 301: kern_return_t ! 302: clock_set_attributes( ! 303: clock_t clock, ! 304: clock_flavor_t flavor, ! 305: clock_attr_t attr, ! 306: mach_msg_type_number_t count) ! 307: { ! 308: kern_return_t (*setattr)( ! 309: clock_flavor_t flavor, ! 310: clock_attr_t attr, ! 311: mach_msg_type_number_t count); ! 312: ! 313: if (clock == CLOCK_NULL) ! 314: return (KERN_INVALID_ARGUMENT); ! 315: if (setattr = clock->cl_ops->c_setattr) ! 316: return ((*setattr)(flavor, attr, count)); ! 317: else ! 318: return (KERN_FAILURE); ! 319: } ! 320: ! 321: /* ! 322: * Setup a clock alarm. ! 323: */ ! 324: kern_return_t ! 325: clock_alarm( ! 326: clock_t clock, ! 327: alarm_type_t alarm_type, ! 328: mach_timespec_t alarm_time, ! 329: ipc_port_t alarm_port, ! 330: mach_msg_type_name_t alarm_port_type) ! 331: { ! 332: alarm_t alarm; ! 333: mach_timespec_t clock_time; ! 334: int chkstat; ! 335: kern_return_t reply_code; ! 336: spl_t s; ! 337: ! 338: if (clock == CLOCK_NULL) ! 339: return (KERN_INVALID_ARGUMENT); ! 340: if (clock->cl_ops->c_setalrm == 0) ! 341: return (KERN_FAILURE); ! 342: if (IP_VALID(alarm_port) == 0) ! 343: return (KERN_INVALID_CAPABILITY); ! 344: ! 345: /* ! 346: * Check alarm parameters. If parameters are invalid, ! 347: * send alarm message immediately. ! 348: */ ! 349: (*clock->cl_ops->c_gettime)(&clock_time); ! 350: chkstat = check_time(alarm_type, &alarm_time, &clock_time); ! 351: if (chkstat <= 0) { ! 352: reply_code = (chkstat < 0 ? KERN_INVALID_VALUE : KERN_SUCCESS); ! 353: clock_alarm_reply(alarm_port, alarm_port_type, ! 354: reply_code, alarm_type, clock_time); ! 355: return (KERN_SUCCESS); ! 356: } ! 357: ! 358: /* ! 359: * Get alarm and add to clock alarm list. ! 360: */ ! 361: ! 362: LOCK_CLOCK(s); ! 363: if ((alarm = alrmfree) == 0) { ! 364: UNLOCK_CLOCK(s); ! 365: alarm = (alarm_t) zalloc(alarm_zone); ! 366: if (alarm == 0) ! 367: return (KERN_RESOURCE_SHORTAGE); ! 368: LOCK_CLOCK(s); ! 369: } ! 370: else ! 371: alrmfree = alarm->al_next; ! 372: ! 373: alarm->al_status = ALARM_CLOCK; ! 374: alarm->al_time = alarm_time; ! 375: alarm->al_type = alarm_type; ! 376: alarm->al_port = alarm_port; ! 377: alarm->al_port_type = alarm_port_type; ! 378: alarm->al_clock = clock; ! 379: alarm->al_policy = POLICY_NULL; ! 380: alarm->al_seqno = alrm_seqno++; ! 381: post_alarm(clock, alarm); ! 382: UNLOCK_CLOCK(s); ! 383: ! 384: return (KERN_SUCCESS); ! 385: } ! 386: ! 387: /* ! 388: * Set a clock alarm for a scheduling policy. ! 389: */ ! 390: kern_return_t ! 391: clock_alarm_sp( ! 392: alarm_type_t alarm_type, ! 393: mach_timespec_t alarm_time, ! 394: long *alarm_id, ! 395: int policy, ! 396: void *alarm_data, ! 397: alarm_t alarm) ! 398: { ! 399: clock_t clock; ! 400: mach_timespec_t clock_time; ! 401: int chkstat; ! 402: spl_t s; ! 403: ! 404: /* Always use system clock. */ ! 405: clock = &clock_list[SYSTEM_CLOCK]; ! 406: ! 407: if (clock->cl_ops->c_setalrm == 0) ! 408: return (KERN_FAILURE); ! 409: ! 410: assert(alarm != 0); ! 411: ! 412: /* ! 413: * Check alarm parameters. If parameters are invalid, ! 414: * send alarm message immediately. ! 415: */ ! 416: (*clock->cl_ops->c_gettime)(&clock_time); ! 417: chkstat = check_time(alarm_type, &alarm_time, &clock_time); ! 418: if (chkstat <= 0) { ! 419: return(chkstat < 0 ? KERN_INVALID_VALUE : KERN_RETURN_MAX); ! 420: /*** ??? define a better value for `KERN_RETURN_MAX' ***/ ! 421: } ! 422: ! 423: /* ! 424: * Get alarm and add to clock alarm list. ! 425: */ ! 426: ! 427: LOCK_CLOCK(s); ! 428: alarm->al_status = ALARM_CLOCK; ! 429: alarm->al_time = alarm_time; ! 430: alarm->al_type = alarm_type; ! 431: alarm->al_port = IP_NULL; ! 432: alarm->al_port_type = 0; ! 433: alarm->al_clock = clock; ! 434: alarm->al_data = alarm_data; ! 435: alarm->al_policy = policy; ! 436: alarm->al_seqno = alrm_seqno++; ! 437: *alarm_id = alarm->al_seqno; ! 438: post_alarm(clock, alarm); ! 439: UNLOCK_CLOCK(s); ! 440: ! 441: return (KERN_SUCCESS); ! 442: } ! 443: ! 444: /* ! 445: * Cancel a clock alarm on behalf of a scheduling policy. ! 446: */ ! 447: kern_return_t ! 448: clock_alarm_cancel_sp( ! 449: long alarm_id) ! 450: { ! 451: clock_t clock; ! 452: alarm_t alrm1, alrm2; ! 453: kern_return_t kr = KERN_FAILURE; ! 454: spl_t s; ! 455: ! 456: /* ! 457: * Cancel alarm with ID `alarm_id.' ! 458: */ ! 459: ! 460: /* Always use system clock. */ ! 461: clock = &clock_list[SYSTEM_CLOCK]; ! 462: ! 463: /* Assume you can't cancel alarms if you can't set them */ ! 464: if (clock->cl_ops->c_setalrm == 0) ! 465: return (KERN_FAILURE); ! 466: ! 467: LOCK_CLOCK(s); ! 468: alrm1 = (alarm_t) &clock->cl_alarm; ! 469: while (alrm2 = alrm1->al_next) { ! 470: /* ! 471: * See if alarm is still in alarm list. ! 472: */ ! 473: if (alrm2->al_seqno == alarm_id) { ! 474: /* Found it. Now remove it. */ ! 475: if (alrm1->al_next = alrm2->al_next) { ! 476: (alrm1->al_next)->al_prev = alrm1; ! 477: } ! 478: ! 479: /* Indicate success */ ! 480: kr = KERN_SUCCESS; ! 481: ! 482: /* ! 483: * If the canceled alarm is the 'earliest' alarm, ! 484: * reset the device layer alarm time accordingly. ! 485: */ ! 486: if (clock->cl_alarm.al_next == alrm2) ! 487: (*clock->cl_ops->c_setalrm) ! 488: (&((clock->cl_alarm.al_next)->al_time)); ! 489: ! 490: /* Quit looking */ ! 491: break; ! 492: } ! 493: } ! 494: UNLOCK_CLOCK(s); ! 495: ! 496: return(kr); ! 497: } ! 498: ! 499: /* ! 500: * Sleep on a clock. System trap. User-level libmach clock_sleep ! 501: * interface call takes a mach_timespec_t sleep_time argument which it ! 502: * converts to sleep_sec and sleep_nsec arguments which are then ! 503: * passed to clock_sleep_trap. ! 504: */ ! 505: kern_return_t ! 506: clock_sleep_trap( ! 507: mach_port_name_t clock_name, ! 508: sleep_type_t sleep_type, ! 509: int sleep_sec, ! 510: int sleep_nsec, ! 511: mach_timespec_t *wakeup_time) ! 512: { ! 513: clock_t clock; ! 514: mach_timespec_t swtime; ! 515: kern_return_t rvalue; ! 516: ! 517: /* ! 518: * Convert the trap parameters. ! 519: */ ! 520: clock = port_name_to_clock(clock_name); ! 521: swtime.tv_sec = sleep_sec; ! 522: swtime.tv_nsec = sleep_nsec; ! 523: ! 524: /* ! 525: * Call the actual clock_sleep routine. ! 526: */ ! 527: rvalue = clock_sleep_internal(clock, sleep_type, &swtime); ! 528: ! 529: /* ! 530: * Return current time as wakeup time. ! 531: */ ! 532: if (rvalue != KERN_INVALID_ARGUMENT && rvalue != KERN_FAILURE) { ! 533: copyout((char *)&swtime, (char *)wakeup_time, ! 534: sizeof(mach_timespec_t)); ! 535: } ! 536: return (rvalue); ! 537: } ! 538: ! 539: /* ! 540: * Kernel internally callable clock sleep routine. The calling ! 541: * thread is suspended until the requested sleep time is reached. ! 542: */ ! 543: kern_return_t ! 544: clock_sleep_internal( ! 545: clock_t clock, ! 546: sleep_type_t sleep_type, ! 547: mach_timespec_t *sleep_time) ! 548: { ! 549: alarm_t alarm; ! 550: mach_timespec_t clock_time; ! 551: kern_return_t rvalue; ! 552: int chkstat; ! 553: spl_t s; ! 554: ! 555: if (clock == CLOCK_NULL) ! 556: return (KERN_INVALID_ARGUMENT); ! 557: if (clock->cl_ops->c_setalrm == 0) ! 558: return (KERN_FAILURE); ! 559: ! 560: /* ! 561: * Check sleep parameters. If parameters are invalid ! 562: * return an error, otherwise post alarm request. ! 563: */ ! 564: (*clock->cl_ops->c_gettime)(&clock_time); ! 565: ! 566: chkstat = check_time(sleep_type, sleep_time, &clock_time); ! 567: if (chkstat < 0) ! 568: return (KERN_INVALID_VALUE); ! 569: rvalue = KERN_SUCCESS; ! 570: if (chkstat > 0) { ! 571: /* ! 572: * Get alarm and add to clock alarm list. ! 573: */ ! 574: ! 575: LOCK_CLOCK(s); ! 576: if ((alarm = alrmfree) == 0) { ! 577: UNLOCK_CLOCK(s); ! 578: alarm = (alarm_t) zalloc(alarm_zone); ! 579: if (alarm == 0) ! 580: return (KERN_RESOURCE_SHORTAGE); ! 581: LOCK_CLOCK(s); ! 582: } ! 583: else ! 584: alrmfree = alarm->al_next; ! 585: ! 586: alarm->al_time = *sleep_time; ! 587: alarm->al_status = ALARM_SLEEP; ! 588: post_alarm(clock, alarm); ! 589: ! 590: /* ! 591: * Wait for alarm to occur. ! 592: */ ! 593: assert_wait((event_t)alarm, THREAD_ABORTSAFE); ! 594: UNLOCK_CLOCK(s); ! 595: /* should we force spl(0) at this point? */ ! 596: thread_block((void (*)(void)) 0); ! 597: /* we should return here at ipl0 */ ! 598: ! 599: /* ! 600: * Note if alarm expired normally or whether it ! 601: * was aborted. If aborted, delete alarm from ! 602: * clock alarm list. Return alarm to free list. ! 603: */ ! 604: LOCK_CLOCK(s); ! 605: if (alarm->al_status != ALARM_DONE) { ! 606: /* This means we were interrupted and that ! 607: thread->wait_result != THREAD_AWAKENED. */ ! 608: if ((alarm->al_prev)->al_next = alarm->al_next) ! 609: (alarm->al_next)->al_prev = alarm->al_prev; ! 610: rvalue = KERN_ABORTED; ! 611: } ! 612: *sleep_time = alarm->al_time; ! 613: alarm->al_status = ALARM_FREE; ! 614: alarm->al_next = alrmfree; ! 615: alrmfree = alarm; ! 616: UNLOCK_CLOCK(s); ! 617: } ! 618: else ! 619: *sleep_time = clock_time; ! 620: ! 621: return (rvalue); ! 622: } ! 623: ! 624: /* ! 625: * CLOCK INTERRUPT SERVICE ROUTINES. ! 626: */ ! 627: ! 628: /* ! 629: * Service clock alarm interrupts. Called from machine dependent ! 630: * layer at splclock(). The clock_id argument specifies the clock, ! 631: * and the clock_time argument gives that clock's current time. ! 632: */ ! 633: void ! 634: clock_alarm_intr( ! 635: clock_id_t clock_id, ! 636: mach_timespec_t *clock_time) ! 637: { ! 638: clock_t clock; ! 639: register alarm_t alrm1; ! 640: register alarm_t alrm2; ! 641: mach_timespec_t *alarm_time; ! 642: spl_t s; ! 643: ! 644: clock = &clock_list[clock_id]; ! 645: ! 646: /* ! 647: * Update clock alarm list. All alarms that are due are moved ! 648: * to the alarmdone list to be serviced by the alarm_thread. ! 649: */ ! 650: ! 651: LOCK_CLOCK(s); ! 652: alrm1 = (alarm_t) &clock->cl_alarm; ! 653: while (alrm2 = alrm1->al_next) { ! 654: alarm_time = &alrm2->al_time; ! 655: if (CMP_MACH_TIMESPEC(alarm_time, clock_time) > 0) ! 656: break; ! 657: ! 658: /* ! 659: * Alarm has expired, so remove it from the ! 660: * clock alarm list. ! 661: */ ! 662: if (alrm1->al_next = alrm2->al_next) ! 663: (alrm1->al_next)->al_prev = alrm1; ! 664: ! 665: /* ! 666: * If a clock_sleep() alarm, wakeup the thread ! 667: * which issued the clock_sleep() call. ! 668: */ ! 669: if (alrm2->al_status == ALARM_SLEEP) { ! 670: alrm2->al_next = 0; ! 671: alrm2->al_status = ALARM_DONE; ! 672: alrm2->al_time = *clock_time; ! 673: thread_wakeup((event_t)alrm2); ! 674: } ! 675: ! 676: /* ! 677: * If a clock_alarm() alarm, place the alarm on ! 678: * the alarm done list and schedule the alarm ! 679: * delivery mechanism. ! 680: */ ! 681: else { ! 682: assert(alrm2->al_status == ALARM_CLOCK); ! 683: if (alrm2->al_next = alrmdone) ! 684: alrmdone->al_prev = alrm2; ! 685: else ! 686: thread_call_enter(&alarm_deliver); ! 687: alrm2->al_prev = (alarm_t) &alrmdone; ! 688: alrmdone = alrm2; ! 689: alrm2->al_status = ALARM_DONE; ! 690: alrm2->al_time = *clock_time; ! 691: } ! 692: } ! 693: ! 694: /* ! 695: * Setup the clock dependent layer to deliver another ! 696: * interrupt for the next pending alarm. ! 697: */ ! 698: if (alrm2) ! 699: (*clock->cl_ops->c_setalrm)(alarm_time); ! 700: UNLOCK_CLOCK(s); ! 701: } ! 702: ! 703: /* ! 704: * ALARM DELIVERY ROUTINES. ! 705: */ ! 706: ! 707: static ! 708: void ! 709: clock_alarm_deliver(void) ! 710: { ! 711: register alarm_t alrm; ! 712: kern_return_t code; ! 713: sched_policy_t *policy; ! 714: spl_t s; ! 715: ! 716: LOCK_CLOCK(s); ! 717: while (alrm = alrmdone) { ! 718: if (alrmdone = alrm->al_next) ! 719: alrmdone->al_prev = (alarm_t) &alrmdone; ! 720: UNLOCK_CLOCK(s); ! 721: ! 722: code = (alrm->al_status == ALARM_DONE? KERN_SUCCESS: KERN_ABORTED); ! 723: if (alrm->al_port != IP_NULL) { ! 724: /* Deliver message to designated port */ ! 725: if (IP_VALID(alrm->al_port)) { ! 726: clock_alarm_reply(alrm->al_port, alrm->al_port_type, code, ! 727: alrm->al_type, alrm->al_time); ! 728: } ! 729: ! 730: LOCK_CLOCK(s); ! 731: alrm->al_status = ALARM_FREE; ! 732: alrm->al_next = alrmfree; ! 733: alrmfree = alrm; ! 734: } ! 735: else { ! 736: /* Call designated scheduling policy's alarm routine */ ! 737: assert(alrm->al_policy != POLICY_NULL); ! 738: policy = &sched_policy[alrm->al_policy]; ! 739: policy->sp_ops.sp_alarm_expired(policy, alrm->al_seqno, code, ! 740: alrm->al_type, alrm->al_time, alrm->al_data); ! 741: ! 742: LOCK_CLOCK(s); ! 743: } ! 744: } ! 745: ! 746: UNLOCK_CLOCK(s); ! 747: } ! 748: ! 749: /* ! 750: * CLOCK PRIVATE SERVICING SUBROUTINES. ! 751: */ ! 752: ! 753: /* ! 754: * Flush all pending alarms on a clock. All alarms ! 755: * are activated and timestamped correctly, so any ! 756: * programs waiting on alarms/threads will proceed ! 757: * with accurate information. ! 758: */ ! 759: static ! 760: void ! 761: flush_alarms( ! 762: clock_t clock) ! 763: { ! 764: register alarm_t alrm1, alrm2; ! 765: spl_t s; ! 766: ! 767: /* ! 768: * Flush all outstanding alarms. ! 769: */ ! 770: LOCK_CLOCK(s); ! 771: alrm1 = (alarm_t) &clock->cl_alarm; ! 772: while (alrm2 = alrm1->al_next) { ! 773: /* ! 774: * Remove alarm from the clock alarm list. ! 775: */ ! 776: if (alrm1->al_next = alrm2->al_next) ! 777: (alrm1->al_next)->al_prev = alrm1; ! 778: ! 779: /* ! 780: * If a clock_sleep() alarm, wakeup the thread ! 781: * which issued the clock_sleep() call. ! 782: */ ! 783: if (alrm2->al_status == ALARM_SLEEP) { ! 784: alrm2->al_next = 0; ! 785: thread_wakeup((event_t)alrm2); ! 786: } ! 787: else { ! 788: /* ! 789: * If a clock_alarm() alarm, place the alarm on ! 790: * the alarm done list and wakeup the dedicated ! 791: * kernel alarm_thread to service the alarm. ! 792: */ ! 793: assert(alrm2->al_status == ALARM_CLOCK); ! 794: if (alrm2->al_next = alrmdone) ! 795: alrmdone->al_prev = alrm2; ! 796: else ! 797: thread_wakeup((event_t)&alrmdone); ! 798: alrm2->al_prev = (alarm_t) &alrmdone; ! 799: alrmdone = alrm2; ! 800: } ! 801: } ! 802: UNLOCK_CLOCK(s); ! 803: } ! 804: ! 805: /* ! 806: * Post an alarm on a clock's active alarm list. The alarm is ! 807: * inserted in time-order into the clock's active alarm list. ! 808: * Always called from within a LOCK_CLOCK() code section. ! 809: */ ! 810: static ! 811: void ! 812: post_alarm( ! 813: clock_t clock, ! 814: alarm_t alarm) ! 815: { ! 816: register alarm_t alrm1, alrm2; ! 817: mach_timespec_t *alarm_time; ! 818: mach_timespec_t *queue_time; ! 819: ! 820: /* ! 821: * Traverse alarm list until queue time is greater ! 822: * than alarm time, then insert alarm. ! 823: */ ! 824: alarm_time = &alarm->al_time; ! 825: alrm1 = (alarm_t) &clock->cl_alarm; ! 826: while (alrm2 = alrm1->al_next) { ! 827: queue_time = &alrm2->al_time; ! 828: if (CMP_MACH_TIMESPEC(queue_time, alarm_time) > 0) ! 829: break; ! 830: alrm1 = alrm2; ! 831: } ! 832: alrm1->al_next = alarm; ! 833: alarm->al_next = alrm2; ! 834: alarm->al_prev = alrm1; ! 835: if (alrm2) ! 836: alrm2->al_prev = alarm; ! 837: ! 838: /* ! 839: * If the inserted alarm is the 'earliest' alarm, ! 840: * reset the device layer alarm time accordingly. ! 841: */ ! 842: if (clock->cl_alarm.al_next == alarm) ! 843: (*clock->cl_ops->c_setalrm)(alarm_time); ! 844: } ! 845: ! 846: /* ! 847: * Check the validity of 'alarm_time' and 'alarm_type'. If either ! 848: * argument is invalid, return a negative value. If the 'alarm_time' ! 849: * is now, return a 0 value. If the 'alarm_time' is in the future, ! 850: * return a positive value. ! 851: */ ! 852: static ! 853: int ! 854: check_time( ! 855: alarm_type_t alarm_type, ! 856: mach_timespec_t *alarm_time, ! 857: mach_timespec_t *clock_time) ! 858: { ! 859: int result; ! 860: ! 861: if (BAD_ALRMTYPE(alarm_type)) ! 862: return (-1); ! 863: if (BAD_MACH_TIMESPEC(alarm_time)) ! 864: return (-1); ! 865: if ((alarm_type & ALRMTYPE) == TIME_RELATIVE) ! 866: ADD_MACH_TIMESPEC(alarm_time, clock_time); ! 867: ! 868: result = CMP_MACH_TIMESPEC(alarm_time, clock_time); ! 869: ! 870: return ((result >= 0)? result: 0); ! 871: } ! 872: ! 873: mach_timespec_t ! 874: clock_get_system_value(void) ! 875: { ! 876: clock_t clock = &clock_list[SYSTEM_CLOCK]; ! 877: mach_timespec_t value; ! 878: ! 879: (void) (*clock->cl_ops->c_gettime)(&value); ! 880: ! 881: return value; ! 882: } ! 883: ! 884: mach_timespec_t ! 885: clock_get_calendar_value(void) ! 886: { ! 887: clock_t clock = &clock_list[CALENDAR_CLOCK]; ! 888: mach_timespec_t value = MACH_TIMESPEC_ZERO; ! 889: ! 890: (void) (*clock->cl_ops->c_gettime)(&value); ! 891: ! 892: return value; ! 893: } ! 894: ! 895: void ! 896: clock_set_calendar_value( ! 897: mach_timespec_t value) ! 898: { ! 899: clock_t clock = &clock_list[CALENDAR_CLOCK]; ! 900: ! 901: (void) (*clock->cl_ops->c_settime)(&value); ! 902: } ! 903: ! 904: void ! 905: clock_deadline_for_periodic_event( ! 906: AbsoluteTime interval, ! 907: AbsoluteTime abstime, ! 908: AbsoluteTime *deadline) ! 909: { ! 910: assert(AbsoluteTime_to_scalar(&interval) != 0); ! 911: ! 912: ADD_ABSOLUTETIME(deadline, &interval); ! 913: ! 914: if ( AbsoluteTime_to_scalar(deadline) <= ! 915: AbsoluteTime_to_scalar(&abstime) ) { ! 916: *deadline = abstime; ! 917: clock_get_uptime(&abstime); ! 918: ADD_ABSOLUTETIME(deadline, &interval); ! 919: ! 920: if ( AbsoluteTime_to_scalar(deadline) <= ! 921: AbsoluteTime_to_scalar(&abstime) ) { ! 922: *deadline = abstime; ! 923: ADD_ABSOLUTETIME(deadline, &interval); ! 924: } ! 925: } ! 926: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.