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