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 KALLOC_TYPE_DEFINE(alarm_zone, struct alarm, KT_DEFAULT);
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
clock_oldconfig(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
clock_oldinit(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
clock_service_create(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 }
249 }
250 }
251
252 /*
253 * Get the service port on a clock.
254 */
255 kern_return_t
host_get_clock_service(host_t host,clock_id_t clock_id,clock_t * clock)256 host_get_clock_service(
257 host_t host,
258 clock_id_t clock_id,
259 clock_t *clock) /* OUT */
260 {
261 if (host == HOST_NULL || clock_id < 0 || clock_id >= clock_count) {
262 *clock = CLOCK_NULL;
263 return KERN_INVALID_ARGUMENT;
264 }
265
266 *clock = &clock_list[clock_id];
267 if ((*clock)->cl_ops == 0) {
268 return KERN_FAILURE;
269 }
270 return KERN_SUCCESS;
271 }
272
273 /*
274 * Get the control port on a clock.
275 */
276 kern_return_t
host_get_clock_control(host_priv_t host_priv,clock_id_t clock_id,clock_t * clock)277 host_get_clock_control(
278 host_priv_t host_priv,
279 clock_id_t clock_id,
280 clock_t *clock) /* OUT */
281 {
282 if (host_priv == HOST_PRIV_NULL ||
283 clock_id < 0 || clock_id >= clock_count) {
284 *clock = CLOCK_NULL;
285 return KERN_INVALID_ARGUMENT;
286 }
287
288 *clock = &clock_list[clock_id];
289 if ((*clock)->cl_ops == 0) {
290 return KERN_FAILURE;
291 }
292 return KERN_SUCCESS;
293 }
294
295 /*
296 * Get the current clock time.
297 */
298 kern_return_t
clock_get_time(clock_t clock,mach_timespec_t * cur_time)299 clock_get_time(
300 clock_t clock,
301 mach_timespec_t *cur_time) /* OUT */
302 {
303 if (clock == CLOCK_NULL) {
304 return KERN_INVALID_ARGUMENT;
305 }
306 return (*clock->cl_ops->c_gettime)(cur_time);
307 }
308
309 kern_return_t
rtclock_gettime(mach_timespec_t * time)310 rtclock_gettime(
311 mach_timespec_t *time) /* OUT */
312 {
313 clock_sec_t secs;
314 clock_nsec_t nsecs;
315
316 clock_get_system_nanotime(&secs, &nsecs);
317 time->tv_sec = (unsigned int)secs;
318 time->tv_nsec = nsecs;
319
320 return KERN_SUCCESS;
321 }
322
323 kern_return_t
calend_gettime(mach_timespec_t * time)324 calend_gettime(
325 mach_timespec_t *time) /* OUT */
326 {
327 clock_sec_t secs;
328 clock_nsec_t nsecs;
329
330 clock_get_calendar_nanotime(&secs, &nsecs);
331 time->tv_sec = (unsigned int)secs;
332 time->tv_nsec = nsecs;
333
334 return KERN_SUCCESS;
335 }
336
337 /*
338 * Get clock attributes.
339 */
340 kern_return_t
clock_get_attributes(clock_t clock,clock_flavor_t flavor,clock_attr_t attr,mach_msg_type_number_t * count)341 clock_get_attributes(
342 clock_t clock,
343 clock_flavor_t flavor,
344 clock_attr_t attr, /* OUT */
345 mach_msg_type_number_t *count) /* IN/OUT */
346 {
347 if (clock == CLOCK_NULL) {
348 return KERN_INVALID_ARGUMENT;
349 }
350 if (clock->cl_ops->c_getattr) {
351 return clock->cl_ops->c_getattr(flavor, attr, count);
352 }
353 return KERN_FAILURE;
354 }
355
356 kern_return_t
rtclock_getattr(clock_flavor_t flavor,clock_attr_t attr,mach_msg_type_number_t * count)357 rtclock_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 case CLOCK_ALARM_CURRES: /* =0 no alarm */
369 case CLOCK_ALARM_MINRES:
370 case CLOCK_ALARM_MAXRES:
371 *(clock_res_t *) attr = NSEC_PER_SEC / 100;
372 break;
373
374 default:
375 return KERN_INVALID_VALUE;
376 }
377
378 return KERN_SUCCESS;
379 }
380
381 kern_return_t
calend_getattr(clock_flavor_t flavor,clock_attr_t attr,mach_msg_type_number_t * count)382 calend_getattr(
383 clock_flavor_t flavor,
384 clock_attr_t attr, /* OUT */
385 mach_msg_type_number_t *count) /* IN/OUT */
386 {
387 if (*count != 1) {
388 return KERN_FAILURE;
389 }
390
391 switch (flavor) {
392 case CLOCK_GET_TIME_RES: /* >0 res */
393 *(clock_res_t *) attr = NSEC_PER_SEC / 100;
394 break;
395
396 case CLOCK_ALARM_CURRES: /* =0 no alarm */
397 case CLOCK_ALARM_MINRES:
398 case CLOCK_ALARM_MAXRES:
399 *(clock_res_t *) attr = 0;
400 break;
401
402 default:
403 return KERN_INVALID_VALUE;
404 }
405
406 return KERN_SUCCESS;
407 }
408
409 /*
410 * Set the current clock time.
411 */
412 kern_return_t
clock_set_time(clock_t clock,__unused mach_timespec_t new_time)413 clock_set_time(
414 clock_t clock,
415 __unused mach_timespec_t new_time)
416 {
417 if (clock == CLOCK_NULL) {
418 return KERN_INVALID_ARGUMENT;
419 }
420 return KERN_FAILURE;
421 }
422
423 /*
424 * Set the clock alarm resolution.
425 */
426 kern_return_t
clock_set_attributes(clock_t clock,__unused clock_flavor_t flavor,__unused clock_attr_t attr,__unused mach_msg_type_number_t count)427 clock_set_attributes(
428 clock_t clock,
429 __unused clock_flavor_t flavor,
430 __unused clock_attr_t attr,
431 __unused mach_msg_type_number_t count)
432 {
433 if (clock == CLOCK_NULL) {
434 return KERN_INVALID_ARGUMENT;
435 }
436 return KERN_FAILURE;
437 }
438
439 /*
440 * Setup a clock alarm.
441 */
442 kern_return_t
clock_alarm(clock_t clock,alarm_type_t alarm_type,mach_timespec_t alarm_time,ipc_port_t alarm_port,mach_msg_type_name_t alarm_port_type)443 clock_alarm(
444 clock_t clock,
445 alarm_type_t alarm_type,
446 mach_timespec_t alarm_time,
447 ipc_port_t alarm_port,
448 mach_msg_type_name_t alarm_port_type)
449 {
450 alarm_t alarm;
451 mach_timespec_t clock_time;
452 int chkstat;
453 kern_return_t reply_code;
454 spl_t s;
455
456 if (clock == CLOCK_NULL) {
457 return KERN_INVALID_ARGUMENT;
458 }
459 if (clock != &clock_list[SYSTEM_CLOCK]) {
460 return KERN_FAILURE;
461 }
462 if (IP_VALID(alarm_port) == 0) {
463 return KERN_INVALID_CAPABILITY;
464 }
465
466 /*
467 * Check alarm parameters. If parameters are invalid,
468 * send alarm message immediately.
469 */
470 (*clock->cl_ops->c_gettime)(&clock_time);
471 chkstat = check_time(alarm_type, &alarm_time, &clock_time);
472 if (chkstat <= 0) {
473 reply_code = (chkstat < 0 ? KERN_INVALID_VALUE : KERN_SUCCESS);
474 clock_alarm_reply(alarm_port, alarm_port_type,
475 reply_code, alarm_type, clock_time);
476 return KERN_SUCCESS;
477 }
478
479 /*
480 * Get alarm and add to clock alarm list.
481 */
482
483 LOCK_ALARM(s);
484 if ((alarm = alrmfree) == 0) {
485 UNLOCK_ALARM(s);
486 alarm = zalloc_flags(alarm_zone, Z_WAITOK | Z_NOFAIL);
487 LOCK_ALARM(s);
488 } else {
489 alrmfree = alarm->al_next;
490 }
491
492 alarm->al_status = ALARM_CLOCK;
493 alarm->al_time = alarm_time;
494 alarm->al_type = alarm_type;
495 alarm->al_port = alarm_port;
496 alarm->al_port_type = alarm_port_type;
497 alarm->al_clock = clock;
498 alarm->al_seqno = alrm_seqno++;
499 post_alarm(alarm);
500 UNLOCK_ALARM(s);
501
502 return KERN_SUCCESS;
503 }
504
505 /*
506 * Sleep on a clock. System trap. User-level libmach clock_sleep
507 * interface call takes a mach_timespec_t sleep_time argument which it
508 * converts to sleep_sec and sleep_nsec arguments which are then
509 * passed to clock_sleep_trap.
510 */
511 kern_return_t
clock_sleep_trap(struct clock_sleep_trap_args * args)512 clock_sleep_trap(
513 struct clock_sleep_trap_args *args)
514 {
515 mach_port_name_t clock_name = args->clock_name;
516 sleep_type_t sleep_type = args->sleep_type;
517 int sleep_sec = args->sleep_sec;
518 int sleep_nsec = args->sleep_nsec;
519 mach_vm_address_t wakeup_time_addr = args->wakeup_time;
520 clock_t clock;
521 mach_timespec_t swtime = {};
522 kern_return_t rvalue;
523
524 /*
525 * Convert the trap parameters.
526 */
527 if (clock_name == MACH_PORT_NULL) {
528 clock = &clock_list[SYSTEM_CLOCK];
529 } else {
530 clock = port_name_to_clock(clock_name);
531 }
532
533 swtime.tv_sec = sleep_sec;
534 swtime.tv_nsec = sleep_nsec;
535
536 /*
537 * Call the actual clock_sleep routine.
538 */
539 rvalue = clock_sleep_internal(clock, sleep_type, &swtime);
540
541 /*
542 * Return current time as wakeup time.
543 */
544 if (rvalue != KERN_INVALID_ARGUMENT && rvalue != KERN_FAILURE) {
545 copyout((char *)&swtime, wakeup_time_addr, sizeof(mach_timespec_t));
546 }
547 return rvalue;
548 }
549
550 static kern_return_t
clock_sleep_internal(clock_t clock,sleep_type_t sleep_type,mach_timespec_t * sleep_time)551 clock_sleep_internal(
552 clock_t clock,
553 sleep_type_t sleep_type,
554 mach_timespec_t *sleep_time)
555 {
556 alarm_t alarm;
557 mach_timespec_t clock_time;
558 kern_return_t rvalue;
559 int chkstat;
560 spl_t s;
561
562 if (clock == CLOCK_NULL) {
563 return KERN_INVALID_ARGUMENT;
564 }
565
566 if (clock != &clock_list[SYSTEM_CLOCK]) {
567 return KERN_FAILURE;
568 }
569
570 /*
571 * Check sleep parameters. If parameters are invalid
572 * return an error, otherwise post alarm request.
573 */
574 (*clock->cl_ops->c_gettime)(&clock_time);
575
576 chkstat = check_time(sleep_type, sleep_time, &clock_time);
577 if (chkstat < 0) {
578 return KERN_INVALID_VALUE;
579 }
580 rvalue = KERN_SUCCESS;
581 if (chkstat > 0) {
582 wait_result_t wait_result;
583
584 /*
585 * Get alarm and add to clock alarm list.
586 */
587
588 LOCK_ALARM(s);
589 if ((alarm = alrmfree) == 0) {
590 UNLOCK_ALARM(s);
591 alarm = zalloc_flags(alarm_zone, Z_WAITOK | Z_NOFAIL);
592 LOCK_ALARM(s);
593 } else {
594 alrmfree = alarm->al_next;
595 }
596
597 /*
598 * Wait for alarm to occur.
599 */
600 wait_result = assert_wait((event_t)alarm, THREAD_ABORTSAFE);
601 if (wait_result == THREAD_WAITING) {
602 alarm->al_time = *sleep_time;
603 alarm->al_status = ALARM_SLEEP;
604 post_alarm(alarm);
605 UNLOCK_ALARM(s);
606
607 wait_result = thread_block(THREAD_CONTINUE_NULL);
608
609 /*
610 * Note if alarm expired normally or whether it
611 * was aborted. If aborted, delete alarm from
612 * clock alarm list. Return alarm to free list.
613 */
614 LOCK_ALARM(s);
615 if (alarm->al_status != ALARM_DONE) {
616 assert(wait_result != THREAD_AWAKENED);
617 if (((alarm->al_prev)->al_next = alarm->al_next) != NULL) {
618 (alarm->al_next)->al_prev = alarm->al_prev;
619 }
620 rvalue = KERN_ABORTED;
621 }
622 *sleep_time = alarm->al_time;
623 alarm->al_status = ALARM_FREE;
624 } else {
625 assert(wait_result == THREAD_INTERRUPTED);
626 assert(alarm->al_status == ALARM_FREE);
627 rvalue = KERN_ABORTED;
628 }
629 alarm->al_next = alrmfree;
630 alrmfree = alarm;
631 UNLOCK_ALARM(s);
632 } else {
633 *sleep_time = clock_time;
634 }
635
636 return rvalue;
637 }
638
639 /*
640 * Service clock alarm expirations.
641 */
642 static void
alarm_expire(void)643 alarm_expire(void)
644 {
645 clock_t clock;
646 alarm_t alrm1;
647 alarm_t alrm2;
648 mach_timespec_t clock_time;
649 mach_timespec_t *alarm_time;
650 spl_t s;
651
652 clock = &clock_list[SYSTEM_CLOCK];
653 (*clock->cl_ops->c_gettime)(&clock_time);
654
655 /*
656 * Update clock alarm list. Alarms that are due are moved
657 * to the alarmdone list to be serviced by a thread callout.
658 */
659 LOCK_ALARM(s);
660 alrm1 = (alarm_t)&alrmlist;
661 while ((alrm2 = alrm1->al_next) != NULL) {
662 alarm_time = &alrm2->al_time;
663 if (CMP_MACH_TIMESPEC(alarm_time, &clock_time) > 0) {
664 break;
665 }
666
667 /*
668 * Alarm has expired, so remove it from the
669 * clock alarm list.
670 */
671 if ((alrm1->al_next = alrm2->al_next) != NULL) {
672 (alrm1->al_next)->al_prev = alrm1;
673 }
674
675 /*
676 * If a clock_sleep() alarm, wakeup the thread
677 * which issued the clock_sleep() call.
678 */
679 if (alrm2->al_status == ALARM_SLEEP) {
680 alrm2->al_next = NULL;
681 alrm2->al_status = ALARM_DONE;
682 alrm2->al_time = clock_time;
683 thread_wakeup((event_t)alrm2);
684 }
685 /*
686 * If a clock_alarm() alarm, place the alarm on
687 * the alarm done list and schedule the alarm
688 * delivery mechanism.
689 */
690 else {
691 assert(alrm2->al_status == ALARM_CLOCK);
692 if ((alrm2->al_next = alrmdone) != NULL) {
693 alrmdone->al_prev = alrm2;
694 } else {
695 thread_call_enter(&alarm_done_call);
696 }
697 alrm2->al_prev = (alarm_t)&alrmdone;
698 alrmdone = alrm2;
699 alrm2->al_status = ALARM_DONE;
700 alrm2->al_time = clock_time;
701 }
702 }
703
704 /*
705 * Setup to expire for the next pending alarm.
706 */
707 if (alrm2) {
708 set_alarm(alarm_time);
709 }
710 UNLOCK_ALARM(s);
711 }
712
713 static void
alarm_done(void)714 alarm_done(void)
715 {
716 alarm_t alrm;
717 kern_return_t code;
718 spl_t s;
719
720 LOCK_ALARM(s);
721 while ((alrm = alrmdone) != NULL) {
722 if ((alrmdone = alrm->al_next) != NULL) {
723 alrmdone->al_prev = (alarm_t)&alrmdone;
724 }
725 UNLOCK_ALARM(s);
726
727 code = (alrm->al_status == ALARM_DONE? KERN_SUCCESS: KERN_ABORTED);
728 if (alrm->al_port != IP_NULL) {
729 /* Deliver message to designated port */
730 if (IP_VALID(alrm->al_port)) {
731 clock_alarm_reply(alrm->al_port, alrm->al_port_type, code,
732 alrm->al_type, alrm->al_time);
733 }
734
735 LOCK_ALARM(s);
736 alrm->al_status = ALARM_FREE;
737 alrm->al_next = alrmfree;
738 alrmfree = alrm;
739 } else {
740 panic("clock_alarm_deliver");
741 }
742 }
743
744 UNLOCK_ALARM(s);
745 }
746
747 /*
748 * Post an alarm on the active alarm list.
749 *
750 * Always called from within a LOCK_ALARM() code section.
751 */
752 static void
post_alarm(alarm_t alarm)753 post_alarm(
754 alarm_t alarm)
755 {
756 alarm_t alrm1, alrm2;
757 mach_timespec_t *alarm_time;
758 mach_timespec_t *queue_time;
759
760 /*
761 * Traverse alarm list until queue time is greater
762 * than alarm time, then insert alarm.
763 */
764 alarm_time = &alarm->al_time;
765 alrm1 = (alarm_t)&alrmlist;
766 while ((alrm2 = alrm1->al_next) != NULL) {
767 queue_time = &alrm2->al_time;
768 if (CMP_MACH_TIMESPEC(queue_time, alarm_time) > 0) {
769 break;
770 }
771 alrm1 = alrm2;
772 }
773 alrm1->al_next = alarm;
774 alarm->al_next = alrm2;
775 alarm->al_prev = alrm1;
776 if (alrm2) {
777 alrm2->al_prev = alarm;
778 }
779
780 /*
781 * If the inserted alarm is the 'earliest' alarm,
782 * reset the device layer alarm time accordingly.
783 */
784 if (alrmlist == alarm) {
785 set_alarm(alarm_time);
786 }
787 }
788
789 static void
set_alarm(mach_timespec_t * alarm_time)790 set_alarm(
791 mach_timespec_t *alarm_time)
792 {
793 uint64_t abstime;
794
795 nanotime_to_absolutetime(alarm_time->tv_sec, alarm_time->tv_nsec, &abstime);
796 timer_call_enter_with_leeway(&alarm_expire_timer, NULL, abstime, 0, TIMER_CALL_USER_NORMAL, FALSE);
797 }
798
799 /*
800 * Check the validity of 'alarm_time' and 'alarm_type'. If either
801 * argument is invalid, return a negative value. If the 'alarm_time'
802 * is now, return a 0 value. If the 'alarm_time' is in the future,
803 * return a positive value.
804 */
805 static int
check_time(alarm_type_t alarm_type,mach_timespec_t * alarm_time,mach_timespec_t * clock_time)806 check_time(
807 alarm_type_t alarm_type,
808 mach_timespec_t *alarm_time,
809 mach_timespec_t *clock_time)
810 {
811 int result;
812
813 if (BAD_ALRMTYPE(alarm_type)) {
814 return -1;
815 }
816 if (BAD_MACH_TIMESPEC(alarm_time)) {
817 return -1;
818 }
819 if ((alarm_type & ALRMTYPE) == TIME_RELATIVE) {
820 ADD_MACH_TIMESPEC(alarm_time, clock_time);
821 }
822
823 result = CMP_MACH_TIMESPEC(alarm_time, clock_time);
824
825 return (result >= 0)? result: 0;
826 }
827
828 #ifndef __LP64__
829
830 mach_timespec_t
clock_get_system_value(void)831 clock_get_system_value(void)
832 {
833 clock_t clock = &clock_list[SYSTEM_CLOCK];
834 mach_timespec_t value;
835
836 (void) (*clock->cl_ops->c_gettime)(&value);
837
838 return value;
839 }
840
841 mach_timespec_t
clock_get_calendar_value(void)842 clock_get_calendar_value(void)
843 {
844 clock_t clock = &clock_list[CALENDAR_CLOCK];
845 mach_timespec_t value = MACH_TIMESPEC_ZERO;
846
847 (void) (*clock->cl_ops->c_gettime)(&value);
848
849 return value;
850 }
851
852 #endif /* __LP64__ */
853