]> git.saurik.com Git - apple/xnu.git/blob - osfmk/kern/clock_oldops.c
xnu-7195.50.7.100.1.tar.gz
[apple/xnu.git] / osfmk / kern / 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__ */