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