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 */
33
34#include <mach/mach_types.h>
35
36#include <kern/spl.h>
37#include <kern/sched_prim.h>
38#include <kern/thread.h>
39#include <kern/clock.h>
40#include <kern/host_notify.h>
41
42#include <IOKit/IOPlatformExpert.h>
43
44#include <machine/commpage.h>
45
46#include <mach/mach_traps.h>
47#include <mach/mach_time.h>
48
49uint32_t	hz_tick_interval = 1;
50
51
52decl_simple_lock_data(,clock_lock)
53
54#define clock_lock()	\
55	simple_lock(&clock_lock)
56
57#define clock_unlock()	\
58	simple_unlock(&clock_lock)
59
60#define clock_lock_init()	\
61	simple_lock_init(&clock_lock, 0)
62
63
64/*
65 *	Time of day (calendar) variables.
66 *
67 *	Algorithm:
68 *
69 *	TOD <- (seconds + epoch, fraction) <- CONV(current absolute time + offset)
70 *
71 *	where CONV converts absolute time units into seconds and a fraction.
72 */
73static struct clock_calend {
74	uint64_t	epoch;
75	uint64_t	offset;
76
77	int32_t		adjdelta;	/* Nanosecond time delta for this adjustment period */
78	uint64_t	adjstart;	/* Absolute time value for start of this adjustment period */
79	uint32_t	adjoffset;	/* Absolute time offset for this adjustment period as absolute value */
80} clock_calend;
81
82#if	CONFIG_DTRACE
83
84/*
85 *	Unlocked calendar flipflop; this is used to track a clock_calend such
86 *	that we can safely access a snapshot of a valid  clock_calend structure
87 *	without needing to take any locks to do it.
88 *
89 *	The trick is to use a generation count and set the low bit when it is
90 *	being updated/read; by doing this, we guarantee, through use of the
91 *	hw_atomic functions, that the generation is incremented when the bit
92 *	is cleared atomically (by using a 1 bit add).
93 */
94static struct unlocked_clock_calend {
95	struct clock_calend	calend;		/* copy of calendar */
96	uint32_t		gen;		/* generation count */
97} flipflop[ 2];
98
99static void clock_track_calend_nowait(void);
100
101#endif
102
103/*
104 *	Calendar adjustment variables and values.
105 */
106#define calend_adjperiod	(NSEC_PER_SEC / 100)	/* adjustment period, ns */
107#define calend_adjskew		(40 * NSEC_PER_USEC)	/* "standard" skew, ns / period */
108#define	calend_adjbig		(NSEC_PER_SEC)			/* use 10x skew above adjbig ns */
109
110static int64_t				calend_adjtotal;		/* Nanosecond remaining total adjustment */
111static uint64_t				calend_adjdeadline;		/* Absolute time value for next adjustment period */
112static uint32_t				calend_adjinterval;		/* Absolute time interval of adjustment period */
113
114static timer_call_data_t	calend_adjcall;
115static uint32_t				calend_adjactive;
116
117static uint32_t		calend_set_adjustment(
118						long			*secs,
119						int				*microsecs);
120
121static void			calend_adjust_call(void);
122static uint32_t		calend_adjust(void);
123
124static thread_call_data_t	calend_wakecall;
125
126extern	void	IOKitResetTime(void);
127
128void _clock_delay_until_deadline(uint64_t		interval,
129								 uint64_t		deadline);
130
131static uint64_t		clock_boottime;				/* Seconds boottime epoch */
132
133#define TIME_ADD(rsecs, secs, rfrac, frac, unit)	\
134MACRO_BEGIN											\
135	if (((rfrac) += (frac)) >= (unit)) {			\
136		(rfrac) -= (unit);							\
137		(rsecs) += 1;								\
138	}												\
139	(rsecs) += (secs);								\
140MACRO_END
141
142#define TIME_SUB(rsecs, secs, rfrac, frac, unit)	\
143MACRO_BEGIN											\
144	if ((int)((rfrac) -= (frac)) < 0) {				\
145		(rfrac) += (unit);							\
146		(rsecs) -= 1;								\
147	}												\
148	(rsecs) -= (secs);								\
149MACRO_END
150
151/*
152 *	clock_config:
153 *
154 *	Called once at boot to configure the clock subsystem.
155 */
156void
157clock_config(void)
158{
159	clock_lock_init();
160
161	timer_call_setup(&calend_adjcall, (timer_call_func_t)calend_adjust_call, NULL);
162	thread_call_setup(&calend_wakecall, (thread_call_func_t)IOKitResetTime, NULL);
163
164	clock_oldconfig();
165}
166
167/*
168 *	clock_init:
169 *
170 *	Called on a processor each time started.
171 */
172void
173clock_init(void)
174{
175	clock_oldinit();
176}
177
178/*
179 *	clock_timebase_init:
180 *
181 *	Called by machine dependent code
182 *	to initialize areas dependent on the
183 *	timebase value.  May be called multiple
184 *	times during start up.
185 */
186void
187clock_timebase_init(void)
188{
189	uint64_t	abstime;
190
191	nanoseconds_to_absolutetime(calend_adjperiod, &abstime);
192	calend_adjinterval = (uint32_t)abstime;
193
194	nanoseconds_to_absolutetime(NSEC_PER_SEC / 100, &abstime);
195	hz_tick_interval = (uint32_t)abstime;
196
197	sched_timebase_init();
198}
199
200/*
201 *	mach_timebase_info_trap:
202 *
203 *	User trap returns timebase constant.
204 */
205kern_return_t
206mach_timebase_info_trap(
207	struct mach_timebase_info_trap_args *args)
208{
209	mach_vm_address_t 			out_info_addr = args->info;
210	mach_timebase_info_data_t	info;
211
212	clock_timebase_info(&info);
213
214	copyout((void *)&info, out_info_addr, sizeof (info));
215
216	return (KERN_SUCCESS);
217}
218
219/*
220 *	Calendar routines.
221 */
222
223/*
224 *	clock_get_calendar_microtime:
225 *
226 *	Returns the current calendar value,
227 *	microseconds as the fraction.
228 */
229void
230clock_get_calendar_microtime(
231	clock_sec_t			*secs,
232	clock_usec_t		*microsecs)
233{
234	clock_get_calendar_absolute_and_microtime(secs, microsecs, NULL);
235}
236
237/*
238 *	clock_get_calendar_absolute_and_microtime:
239 *
240 *	Returns the current calendar value,
241 *	microseconds as the fraction. Also
242 *	returns mach_absolute_time if abstime
243 *	is not NULL.
244 */
245void
246clock_get_calendar_absolute_and_microtime(
247	clock_sec_t			*secs,
248	clock_usec_t		*microsecs,
249	uint64_t    		*abstime)
250{
251	uint64_t		now;
252	spl_t			s;
253
254	s = splclock();
255	clock_lock();
256
257	now = mach_absolute_time();
258	if (abstime)
259		*abstime = now;
260
261	if (clock_calend.adjdelta < 0) {
262		uint32_t	t32;
263
264		/*
265		 * Since offset is decremented during a negative adjustment,
266		 * ensure that time increases monotonically without going
267		 * temporarily backwards.
268		 * If the delta has not yet passed, now is set to the start
269		 * of the current adjustment period; otherwise, we're between
270		 * the expiry of the delta and the next call to calend_adjust(),
271		 * and we offset accordingly.
272		 */
273		if (now > clock_calend.adjstart) {
274			t32 = (uint32_t)(now - clock_calend.adjstart);
275
276			if (t32 > clock_calend.adjoffset)
277				now -= clock_calend.adjoffset;
278			else
279				now = clock_calend.adjstart;
280		}
281	}
282
283	now += clock_calend.offset;
284
285	absolutetime_to_microtime(now, secs, microsecs);
286
287	*secs += (clock_sec_t)clock_calend.epoch;
288
289	clock_unlock();
290	splx(s);
291}
292
293/*
294 *	clock_get_calendar_nanotime:
295 *
296 *	Returns the current calendar value,
297 *	nanoseconds as the fraction.
298 *
299 *	Since we do not have an interface to
300 *	set the calendar with resolution greater
301 *	than a microsecond, we honor that here.
302 */
303void
304clock_get_calendar_nanotime(
305	clock_sec_t			*secs,
306	clock_nsec_t		*nanosecs)
307{
308	uint64_t		now;
309	spl_t			s;
310
311	s = splclock();
312	clock_lock();
313
314	now = mach_absolute_time();
315
316	if (clock_calend.adjdelta < 0) {
317		uint32_t	t32;
318
319		if (now > clock_calend.adjstart) {
320			t32 = (uint32_t)(now - clock_calend.adjstart);
321
322			if (t32 > clock_calend.adjoffset)
323				now -= clock_calend.adjoffset;
324			else
325				now = clock_calend.adjstart;
326		}
327	}
328
329	now += clock_calend.offset;
330
331	absolutetime_to_microtime(now, secs, nanosecs);
332
333	*nanosecs *= NSEC_PER_USEC;
334
335	*secs += (clock_sec_t)clock_calend.epoch;
336
337	clock_unlock();
338	splx(s);
339}
340
341/*
342 *	clock_gettimeofday:
343 *
344 *	Kernel interface for commpage implementation of
345 *	gettimeofday() syscall.
346 *
347 *	Returns the current calendar value, and updates the
348 *	commpage info as appropriate.  Because most calls to
349 *	gettimeofday() are handled in user mode by the commpage,
350 *	this routine should be used infrequently.
351 */
352void
353clock_gettimeofday(
354	clock_sec_t		*secs,
355	clock_usec_t	*microsecs)
356{
357	uint64_t		now;
358	spl_t			s;
359
360	s = splclock();
361	clock_lock();
362
363	now = mach_absolute_time();
364
365	if (clock_calend.adjdelta >= 0) {
366		clock_gettimeofday_set_commpage(now, clock_calend.epoch, clock_calend.offset, secs, microsecs);
367	}
368	else {
369		uint32_t	t32;
370
371		if (now > clock_calend.adjstart) {
372			t32 = (uint32_t)(now - clock_calend.adjstart);
373
374			if (t32 > clock_calend.adjoffset)
375				now -= clock_calend.adjoffset;
376			else
377				now = clock_calend.adjstart;
378		}
379
380		now += clock_calend.offset;
381
382		absolutetime_to_microtime(now, secs, microsecs);
383
384		*secs += (clock_sec_t)clock_calend.epoch;
385	}
386
387	clock_unlock();
388	splx(s);
389}
390
391/*
392 *	clock_set_calendar_microtime:
393 *
394 *	Sets the current calendar value by
395 *	recalculating the epoch and offset
396 *	from the system clock.
397 *
398 *	Also adjusts the boottime to keep the
399 *	value consistent, writes the new
400 *	calendar value to the platform clock,
401 *	and sends calendar change notifications.
402 */
403void
404clock_set_calendar_microtime(
405	clock_sec_t			secs,
406	clock_usec_t		microsecs)
407{
408	clock_sec_t			sys;
409	clock_usec_t		microsys;
410	clock_sec_t			newsecs;
411    clock_usec_t        newmicrosecs;
412	spl_t				s;
413
414    newsecs = secs;
415    newmicrosecs = microsecs;
416
417	s = splclock();
418	clock_lock();
419
420	commpage_disable_timestamp();
421
422	/*
423	 *	Calculate the new calendar epoch based on
424	 *	the new value and the system clock.
425	 */
426	clock_get_system_microtime(&sys, &microsys);
427	TIME_SUB(secs, sys, microsecs, microsys, USEC_PER_SEC);
428
429	/*
430	 *	Adjust the boottime based on the delta.
431	 */
432	clock_boottime += secs - clock_calend.epoch;
433
434	/*
435	 *	Set the new calendar epoch.
436	 */
437	clock_calend.epoch = secs;
438
439	nanoseconds_to_absolutetime((uint64_t)microsecs * NSEC_PER_USEC, &clock_calend.offset);
440
441	/*
442	 *	Cancel any adjustment in progress.
443	 */
444	calend_adjtotal = clock_calend.adjdelta = 0;
445
446	clock_unlock();
447
448	/*
449	 *	Set the new value for the platform clock.
450	 */
451	PESetUTCTimeOfDay(newsecs, newmicrosecs);
452
453	splx(s);
454
455	/*
456	 *	Send host notifications.
457	 */
458	host_notify_calendar_change();
459
460#if CONFIG_DTRACE
461	clock_track_calend_nowait();
462#endif
463}
464
465/*
466 *	clock_initialize_calendar:
467 *
468 *	Set the calendar and related clocks
469 *	from the platform clock at boot or
470 *	wake event.
471 *
472 *	Also sends host notifications.
473 */
474void
475clock_initialize_calendar(void)
476{
477	clock_sec_t			sys, secs;
478	clock_usec_t 		microsys, microsecs;
479	spl_t				s;
480
481    PEGetUTCTimeOfDay(&secs, &microsecs);
482
483	s = splclock();
484	clock_lock();
485
486	commpage_disable_timestamp();
487
488	if ((long)secs >= (long)clock_boottime) {
489		/*
490		 *	Initialize the boot time based on the platform clock.
491		 */
492		if (clock_boottime == 0)
493			clock_boottime = secs;
494
495		/*
496		 *	Calculate the new calendar epoch based on
497		 *	the platform clock and the system clock.
498		 */
499		clock_get_system_microtime(&sys, &microsys);
500		TIME_SUB(secs, sys, microsecs, microsys, USEC_PER_SEC);
501
502		/*
503		 *	Set the new calendar epoch.
504		 */
505		clock_calend.epoch = secs;
506
507		nanoseconds_to_absolutetime((uint64_t)microsecs * NSEC_PER_USEC, &clock_calend.offset);
508
509		/*
510		 *	 Cancel any adjustment in progress.
511		 */
512		calend_adjtotal = clock_calend.adjdelta = 0;
513	}
514
515	clock_unlock();
516	splx(s);
517
518	/*
519	 *	Send host notifications.
520	 */
521	host_notify_calendar_change();
522
523#if CONFIG_DTRACE
524	clock_track_calend_nowait();
525#endif
526}
527
528/*
529 *	clock_get_boottime_nanotime:
530 *
531 *	Return the boottime, used by sysctl.
532 */
533void
534clock_get_boottime_nanotime(
535	clock_sec_t			*secs,
536	clock_nsec_t		*nanosecs)
537{
538	spl_t	s;
539
540	s = splclock();
541	clock_lock();
542
543	*secs = (clock_sec_t)clock_boottime;
544	*nanosecs = 0;
545
546	clock_unlock();
547	splx(s);
548}
549
550/*
551 *	clock_adjtime:
552 *
553 *	Interface to adjtime() syscall.
554 *
555 *	Calculates adjustment variables and
556 *	initiates adjustment.
557 */
558void
559clock_adjtime(
560	long		*secs,
561	int			*microsecs)
562{
563	uint32_t	interval;
564	spl_t		s;
565
566	s = splclock();
567	clock_lock();
568
569	interval = calend_set_adjustment(secs, microsecs);
570	if (interval != 0) {
571		calend_adjdeadline = mach_absolute_time() + interval;
572		if (!timer_call_enter(&calend_adjcall, calend_adjdeadline, TIMER_CALL_SYS_CRITICAL))
573			calend_adjactive++;
574	}
575	else
576	if (timer_call_cancel(&calend_adjcall))
577		calend_adjactive--;
578
579	clock_unlock();
580	splx(s);
581}
582
583static uint32_t
584calend_set_adjustment(
585	long			*secs,
586	int				*microsecs)
587{
588	uint64_t		now, t64;
589	int64_t			total, ototal;
590	uint32_t		interval = 0;
591
592	/*
593	 * Compute the total adjustment time in nanoseconds.
594	 */
595	total = ((int64_t)*secs * (int64_t)NSEC_PER_SEC) + (*microsecs * (int64_t)NSEC_PER_USEC);
596
597	/*
598	 * Disable commpage gettimeofday().
599	 */
600	commpage_disable_timestamp();
601
602	/*
603	 * Get current absolute time.
604	 */
605	now = mach_absolute_time();
606
607	/*
608	 * Save the old adjustment total for later return.
609	 */
610	ototal = calend_adjtotal;
611
612	/*
613	 * Is a new correction specified?
614	 */
615	if (total != 0) {
616		/*
617		 * Set delta to the standard, small, adjustment skew.
618		 */
619		int32_t		delta = calend_adjskew;
620
621		if (total > 0) {
622			/*
623			 * Positive adjustment. If greater than the preset 'big'
624			 * threshold, slew at a faster rate, capping if necessary.
625			 */
626			if (total > (int64_t) calend_adjbig)
627				delta *= 10;
628			if (delta > total)
629				delta = (int32_t)total;
630
631			/*
632			 * Convert the delta back from ns to absolute time and store in adjoffset.
633			 */
634			nanoseconds_to_absolutetime((uint64_t)delta, &t64);
635			clock_calend.adjoffset = (uint32_t)t64;
636		}
637		else {
638			/*
639			 * Negative adjustment; therefore, negate the delta. If
640			 * greater than the preset 'big' threshold, slew at a faster
641			 * rate, capping if necessary.
642			 */
643			if (total < (int64_t) -calend_adjbig)
644				delta *= 10;
645			delta = -delta;
646			if (delta < total)
647				delta = (int32_t)total;
648
649			/*
650			 * Save the current absolute time. Subsequent time operations occuring
651			 * during this negative correction can make use of this value to ensure
652			 * that time increases monotonically.
653			 */
654			clock_calend.adjstart = now;
655
656			/*
657			 * Convert the delta back from ns to absolute time and store in adjoffset.
658			 */
659			nanoseconds_to_absolutetime((uint64_t)-delta, &t64);
660			clock_calend.adjoffset = (uint32_t)t64;
661		}
662
663		/*
664		 * Store the total adjustment time in ns.
665		 */
666		calend_adjtotal = total;
667
668		/*
669		 * Store the delta for this adjustment period in ns.
670		 */
671		clock_calend.adjdelta = delta;
672
673		/*
674		 * Set the interval in absolute time for later return.
675		 */
676		interval = calend_adjinterval;
677	}
678	else {
679		/*
680		 * No change; clear any prior adjustment.
681		 */
682		calend_adjtotal = clock_calend.adjdelta = 0;
683	}
684
685	/*
686	 * If an prior correction was in progress, return the
687	 * remaining uncorrected time from it.
688	 */
689	if (ototal != 0) {
690		*secs = (long)(ototal / (long)NSEC_PER_SEC);
691		*microsecs = (int)((ototal % (int)NSEC_PER_SEC) / (int)NSEC_PER_USEC);
692	}
693	else
694		*secs = *microsecs = 0;
695
696#if CONFIG_DTRACE
697	clock_track_calend_nowait();
698#endif
699
700	return (interval);
701}
702
703static void
704calend_adjust_call(void)
705{
706	uint32_t	interval;
707	spl_t		s;
708
709	s = splclock();
710	clock_lock();
711
712	if (--calend_adjactive == 0) {
713		interval = calend_adjust();
714		if (interval != 0) {
715			clock_deadline_for_periodic_event(interval, mach_absolute_time(), &calend_adjdeadline);
716
717			if (!timer_call_enter(&calend_adjcall, calend_adjdeadline, TIMER_CALL_SYS_CRITICAL))
718				calend_adjactive++;
719		}
720	}
721
722	clock_unlock();
723	splx(s);
724}
725
726static uint32_t
727calend_adjust(void)
728{
729	uint64_t		now, t64;
730	int32_t			delta;
731	uint32_t		interval = 0;
732
733	commpage_disable_timestamp();
734
735	now = mach_absolute_time();
736
737	delta = clock_calend.adjdelta;
738
739	if (delta > 0) {
740		clock_calend.offset += clock_calend.adjoffset;
741
742		calend_adjtotal -= delta;
743		if (delta > calend_adjtotal) {
744			clock_calend.adjdelta = delta = (int32_t)calend_adjtotal;
745
746			nanoseconds_to_absolutetime((uint64_t)delta, &t64);
747			clock_calend.adjoffset = (uint32_t)t64;
748		}
749	}
750	else
751		if (delta < 0) {
752			clock_calend.offset -= clock_calend.adjoffset;
753
754			calend_adjtotal -= delta;
755			if (delta < calend_adjtotal) {
756				clock_calend.adjdelta = delta = (int32_t)calend_adjtotal;
757
758				nanoseconds_to_absolutetime((uint64_t)-delta, &t64);
759				clock_calend.adjoffset = (uint32_t)t64;
760			}
761
762			if (clock_calend.adjdelta != 0)
763				clock_calend.adjstart = now;
764		}
765
766	if (clock_calend.adjdelta != 0)
767		interval = calend_adjinterval;
768
769#if CONFIG_DTRACE
770	clock_track_calend_nowait();
771#endif
772
773	return (interval);
774}
775
776/*
777 *	clock_wakeup_calendar:
778 *
779 *	Interface to power management, used
780 *	to initiate the reset of the calendar
781 *	on wake from sleep event.
782 */
783void
784clock_wakeup_calendar(void)
785{
786	thread_call_enter(&calend_wakecall);
787}
788
789/*
790 *	Wait / delay routines.
791 */
792static void
793mach_wait_until_continue(
794	__unused void	*parameter,
795	wait_result_t	wresult)
796{
797	thread_syscall_return((wresult == THREAD_INTERRUPTED)? KERN_ABORTED: KERN_SUCCESS);
798	/*NOTREACHED*/
799}
800
801/*
802 * mach_wait_until_trap: Suspend execution of calling thread until the specified time has passed
803 *
804 * Parameters:    args->deadline          Amount of time to wait
805 *
806 * Returns:        0                      Success
807 *                !0                      Not success
808 *
809 */
810kern_return_t
811mach_wait_until_trap(
812	struct mach_wait_until_trap_args	*args)
813{
814	uint64_t		deadline = args->deadline;
815	wait_result_t	wresult;
816
817	wresult = assert_wait_deadline_with_leeway((event_t)mach_wait_until_trap, THREAD_ABORTSAFE,
818						   TIMEOUT_URGENCY_USER_NORMAL, deadline, 0);
819	if (wresult == THREAD_WAITING)
820		wresult = thread_block(mach_wait_until_continue);
821
822	return ((wresult == THREAD_INTERRUPTED)? KERN_ABORTED: KERN_SUCCESS);
823}
824
825void
826clock_delay_until(
827	uint64_t		deadline)
828{
829	uint64_t		now = mach_absolute_time();
830
831	if (now >= deadline)
832		return;
833
834	_clock_delay_until_deadline(deadline - now, deadline);
835}
836
837/*
838 * Preserve the original precise interval that the client
839 * requested for comparison to the spin threshold.
840 */
841void
842_clock_delay_until_deadline(
843	uint64_t		interval,
844	uint64_t		deadline)
845{
846
847	if (interval == 0)
848		return;
849
850	if (	ml_delay_should_spin(interval)	||
851			get_preemption_level() != 0				||
852			ml_get_interrupts_enabled() == FALSE	) {
853		machine_delay_until(interval, deadline);
854	} else {
855		assert_wait_deadline((event_t)clock_delay_until, THREAD_UNINT, deadline);
856
857		thread_block(THREAD_CONTINUE_NULL);
858	}
859}
860
861
862void
863delay_for_interval(
864	uint32_t		interval,
865	uint32_t		scale_factor)
866{
867	uint64_t		abstime;
868
869	clock_interval_to_absolutetime_interval(interval, scale_factor, &abstime);
870
871	_clock_delay_until_deadline(abstime, mach_absolute_time() + abstime);
872}
873
874void
875delay(
876	int		usec)
877{
878	delay_for_interval((usec < 0)? -usec: usec, NSEC_PER_USEC);
879}
880
881/*
882 *	Miscellaneous routines.
883 */
884void
885clock_interval_to_deadline(
886	uint32_t			interval,
887	uint32_t			scale_factor,
888	uint64_t			*result)
889{
890	uint64_t	abstime;
891
892	clock_interval_to_absolutetime_interval(interval, scale_factor, &abstime);
893
894	*result = mach_absolute_time() + abstime;
895}
896
897void
898clock_absolutetime_interval_to_deadline(
899	uint64_t			abstime,
900	uint64_t			*result)
901{
902	*result = mach_absolute_time() + abstime;
903}
904
905void
906clock_get_uptime(
907	uint64_t	*result)
908{
909	*result = mach_absolute_time();
910}
911
912void
913clock_deadline_for_periodic_event(
914	uint64_t			interval,
915	uint64_t			abstime,
916	uint64_t			*deadline)
917{
918	assert(interval != 0);
919
920	*deadline += interval;
921
922	if (*deadline <= abstime) {
923		*deadline = abstime + interval;
924		abstime = mach_absolute_time();
925
926		if (*deadline <= abstime)
927			*deadline = abstime + interval;
928	}
929}
930
931#if	CONFIG_DTRACE
932
933/*
934 * clock_get_calendar_nanotime_nowait
935 *
936 * Description:	Non-blocking version of clock_get_calendar_nanotime()
937 *
938 * Notes:	This function operates by separately tracking calendar time
939 *		updates using a two element structure to copy the calendar
940 *		state, which may be asynchronously modified.  It utilizes
941 *		barrier instructions in the tracking process and in the local
942 *		stable snapshot process in order to ensure that a consistent
943 *		snapshot is used to perform the calculation.
944 */
945void
946clock_get_calendar_nanotime_nowait(
947	clock_sec_t			*secs,
948	clock_nsec_t		*nanosecs)
949{
950	int i = 0;
951	uint64_t		now;
952	struct unlocked_clock_calend stable;
953
954	for (;;) {
955		stable = flipflop[i];		/* take snapshot */
956
957		/*
958		 * Use a barrier instructions to ensure atomicity.  We AND
959		 * off the "in progress" bit to get the current generation
960		 * count.
961		 */
962		(void)hw_atomic_and(&stable.gen, ~(uint32_t)1);
963
964		/*
965		 * If an update _is_ in progress, the generation count will be
966		 * off by one, if it _was_ in progress, it will be off by two,
967		 * and if we caught it at a good time, it will be equal (and
968		 * our snapshot is threfore stable).
969		 */
970		if (flipflop[i].gen == stable.gen)
971			break;
972
973		/* Switch to the oher element of the flipflop, and try again. */
974		i ^= 1;
975	}
976
977	now = mach_absolute_time();
978
979	if (stable.calend.adjdelta < 0) {
980		uint32_t	t32;
981
982		if (now > stable.calend.adjstart) {
983			t32 = (uint32_t)(now - stable.calend.adjstart);
984
985			if (t32 > stable.calend.adjoffset)
986				now -= stable.calend.adjoffset;
987			else
988				now = stable.calend.adjstart;
989		}
990	}
991
992	now += stable.calend.offset;
993
994	absolutetime_to_microtime(now, secs, nanosecs);
995	*nanosecs *= NSEC_PER_USEC;
996
997	*secs += (clock_sec_t)stable.calend.epoch;
998}
999
1000static void
1001clock_track_calend_nowait(void)
1002{
1003	int i;
1004
1005	for (i = 0; i < 2; i++) {
1006		struct clock_calend tmp = clock_calend;
1007
1008		/*
1009		 * Set the low bit if the generation count; since we use a
1010		 * barrier instruction to do this, we are guaranteed that this
1011		 * will flag an update in progress to an async caller trying
1012		 * to examine the contents.
1013		 */
1014		(void)hw_atomic_or(&flipflop[i].gen, 1);
1015
1016		flipflop[i].calend = tmp;
1017
1018		/*
1019		 * Increment the generation count to clear the low bit to
1020		 * signal completion.  If a caller compares the generation
1021		 * count after taking a copy while in progress, the count
1022		 * will be off by two.
1023		 */
1024		(void)hw_atomic_add(&flipflop[i].gen, 1);
1025	}
1026}
1027
1028#endif	/* CONFIG_DTRACE */
1029
1030