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