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