xref: /xnu-8020.140.41/osfmk/kern/clock_oldops.c (revision 27b03b360a988dfd3dfdf34262bb0042026747cc)
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