xref: /xnu-10002.61.3/osfmk/kern/clock_oldops.c (revision 0f4c859e951fba394238ab619495c4e1d54d0f34)
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  */
69 struct  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 };
89 typedef 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 */
98 decl_simple_lock_data(static, alarm_lock);       /* alarm synchronization */
99 /* zone for user alarms */
100 static KALLOC_TYPE_DEFINE(alarm_zone, struct alarm, KT_DEFAULT);
101 static struct   alarm           *alrmfree;              /* alarm free list pointer */
102 static struct   alarm           *alrmdone;              /* alarm done list pointer */
103 static struct   alarm           *alrmlist;
104 static long                     alrm_seqno;             /* uniquely identifies alarms */
105 static thread_call_data_t       alarm_done_call;
106 static timer_call_data_t        alarm_expire_timer;
107 
108 extern  struct clock    clock_list[];
109 extern  int             clock_count;
110 
111 static void             post_alarm(
112 	alarm_t                 alarm);
113 
114 static void             set_alarm(
115 	mach_timespec_t *alarm_time);
116 
117 static int              check_time(
118 	alarm_type_t    alarm_type,
119 	mach_timespec_t *alarm_time,
120 	mach_timespec_t *clock_time);
121 
122 static void             alarm_done(void);
123 
124 static void             alarm_expire(void);
125 
126 static kern_return_t    clock_sleep_internal(
127 	clock_t                         clock,
128 	sleep_type_t            sleep_type,
129 	mach_timespec_t         *sleep_time);
130 
131 int             rtclock_init(void);
132 
133 kern_return_t   rtclock_gettime(
134 	mach_timespec_t                 *cur_time);
135 
136 kern_return_t   rtclock_getattr(
137 	clock_flavor_t                  flavor,
138 	clock_attr_t                    attr,
139 	mach_msg_type_number_t  *count);
140 
141 SECURITY_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 
148 kern_return_t   calend_gettime(
149 	mach_timespec_t                 *cur_time);
150 
151 kern_return_t   calend_getattr(
152 	clock_flavor_t                  flavor,
153 	clock_attr_t                    attr,
154 	mach_msg_type_number_t  *count);
155 
156 SECURITY_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  */
166 SECURITY_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 };
176 int     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 
189 void
clock_oldconfig(void)190 clock_oldconfig(void)
191 {
192 	clock_t                 clock;
193 	int     i;
194 
195 	simple_lock_init(&alarm_lock, 0);
196 	thread_call_setup(&alarm_done_call, (thread_call_func_t)alarm_done, NULL);
197 	timer_call_setup(&alarm_expire_timer, (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 
215 void
clock_oldinit(void)216 clock_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  */
235 void
clock_service_create(void)236 clock_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  */
252 kern_return_t
host_get_clock_service(host_t host,clock_id_t clock_id,clock_t * clock)253 host_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  */
273 kern_return_t
clock_get_time(clock_t clock,mach_timespec_t * cur_time)274 clock_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 
284 kern_return_t
rtclock_gettime(mach_timespec_t * time)285 rtclock_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, &nsecs);
292 	time->tv_sec = (unsigned int)secs;
293 	time->tv_nsec = nsecs;
294 
295 	return KERN_SUCCESS;
296 }
297 
298 kern_return_t
calend_gettime(mach_timespec_t * time)299 calend_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, &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  */
315 kern_return_t
clock_get_attributes(clock_t clock,clock_flavor_t flavor,clock_attr_t attr,mach_msg_type_number_t * count)316 clock_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 
331 kern_return_t
rtclock_getattr(clock_flavor_t flavor,clock_attr_t attr,mach_msg_type_number_t * count)332 rtclock_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 
356 kern_return_t
calend_getattr(clock_flavor_t flavor,clock_attr_t attr,mach_msg_type_number_t * count)357 calend_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  */
387 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)388 clock_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, &clock_time);
417 	if (chkstat <= 0) {
418 		reply_code = (chkstat < 0 ? KERN_INVALID_VALUE : KERN_SUCCESS);
419 		clock_alarm_reply(alarm_port, alarm_port_type,
420 		    reply_code, alarm_type, 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  */
456 kern_return_t
clock_sleep_trap(struct clock_sleep_trap_args * args)457 clock_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, &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 
495 static kern_return_t
clock_sleep_internal(clock_t clock,sleep_type_t sleep_type,mach_timespec_t * sleep_time)496 clock_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(sleep_type, sleep_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_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  */
587 static void
alarm_expire(void)588 alarm_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(&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 
658 static void
alarm_done(void)659 alarm_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(alrm->al_port, alrm->al_port_type, code,
677 				    alrm->al_type, 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  */
697 static void
post_alarm(alarm_t alarm)698 post_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 
734 static void
set_alarm(mach_timespec_t * alarm_time)735 set_alarm(
736 	mach_timespec_t         *alarm_time)
737 {
738 	uint64_t        abstime;
739 
740 	nanotime_to_absolutetime(alarm_time->tv_sec, alarm_time->tv_nsec, &abstime);
741 	timer_call_enter_with_leeway(&alarm_expire_timer, NULL, abstime, 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  */
750 static int
check_time(alarm_type_t alarm_type,mach_timespec_t * alarm_time,mach_timespec_t * clock_time)751 check_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 
775 mach_timespec_t
clock_get_system_value(void)776 clock_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 
786 mach_timespec_t
clock_get_calendar_value(void)787 clock_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