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