*
* @APPLE_LICENSE_HEADER_START@
*
- * The contents of this file constitute Original Code as defined in and
- * are subject to the Apple Public Source License Version 1.1 (the
- * "License"). You may not use this file except in compliance with the
- * License. Please obtain a copy of the License at
- * http://www.apple.com/publicsource and read it before using this file.
+ * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved.
*
- * This Original Code and all software distributed under the License are
- * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
* EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
* INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
- * License for the specific language governing rights and limitations
- * under the License.
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
*
* @APPLE_LICENSE_HEADER_END@
*/
#include <kern/misc_protos.h>
#include <kern/lock.h>
#include <kern/host.h>
-#include <kern/processor.h>
-#include <kern/sched.h>
#include <kern/spl.h>
+#include <kern/sched_prim.h>
#include <kern/thread.h>
#include <kern/thread_swap.h>
#include <kern/ipc_host.h>
#include <kern/clock.h>
#include <kern/zalloc.h>
-#include <kern/sf.h>
#include <ipc/ipc_port.h>
#include <mach/mach_syscalls.h>
#include <mach/clock_reply.h>
#include <mach/mach_time.h>
-#include <kern/mk_timer.h>
-
/*
* Exported interface
*/
static long alrm_seqno; /* uniquely identifies alarms */
static thread_call_data_t alarm_deliver;
+decl_simple_lock_data(static,calend_adjlock)
+
+static timer_call_data_t calend_adjcall;
+static uint64_t calend_adjinterval, calend_adjdeadline;
+
+static thread_call_data_t calend_wakecall;
+
/* backwards compatibility */
int hz = HZ; /* GET RID OF THIS !!! */
int tick = (1000000 / HZ); /* GET RID OF THIS !!! */
thread_call_param_t p0,
thread_call_param_t p1);
+static
+void calend_adjust_call(
+ timer_call_param_t p0,
+ timer_call_param_t p1);
+
+static
+void calend_dowakeup(
+ thread_call_param_t p0,
+ thread_call_param_t p1);
+
/*
* Macros to lock/unlock clock system.
*/
if (cpu_number() != master_cpu)
panic("clock_config");
+ simple_lock_init(&ClockLock, ETAP_MISC_CLOCK);
+ thread_call_setup(&alarm_deliver, clock_alarm_deliver, NULL);
+
+ simple_lock_init(&calend_adjlock, ETAP_MISC_CLOCK);
+ timer_call_setup(&calend_adjcall, calend_adjust_call, NULL);
+
+ thread_call_setup(&calend_wakecall, calend_dowakeup, NULL);
+
/*
* Configure clock devices.
*/
- simple_lock_init(&ClockLock, ETAP_MISC_CLOCK);
for (i = 0; i < clock_count; i++) {
clock = &clock_list[i];
if (clock->cl_ops) {
}
}
+/*
+ * Called by machine dependent code
+ * to initialize areas dependent on the
+ * timebase value. May be called multiple
+ * times during start up.
+ */
+void
+clock_timebase_init(void)
+{
+ sched_timebase_init();
+}
+
/*
* Initialize the clock ipc service facility.
*/
clock_t clock;
register int i;
- mk_timer_initialize();
-
/*
* Initialize ipc clock services.
*/
}
/*
- * Initialize clock service alarms.
+ * Perform miscellaneous late
+ * initialization.
*/
i = sizeof(struct alarm);
alarm_zone = zinit(i, (4096/i)*i, 10*i, "alarms");
-
- /*
- * Initialize the clock alarm delivery mechanism.
- */
- thread_call_setup(&alarm_deliver, clock_alarm_deliver, NULL);
}
/*
return (KERN_INVALID_VALUE);
rvalue = KERN_SUCCESS;
if (chkstat > 0) {
+ wait_result_t wait_result;
+
/*
* Get alarm and add to clock alarm list.
*/
else
alrmfree = alarm->al_next;
- alarm->al_time = *sleep_time;
- alarm->al_status = ALARM_SLEEP;
- post_alarm(clock, alarm);
-
/*
* Wait for alarm to occur.
*/
- assert_wait((event_t)alarm, THREAD_ABORTSAFE);
- UNLOCK_CLOCK(s);
- /* should we force spl(0) at this point? */
- thread_block((void (*)(void)) 0);
- /* we should return here at ipl0 */
+ wait_result = assert_wait((event_t)alarm, THREAD_ABORTSAFE);
+ if (wait_result == THREAD_WAITING) {
+ alarm->al_time = *sleep_time;
+ alarm->al_status = ALARM_SLEEP;
+ post_alarm(clock, alarm);
+ UNLOCK_CLOCK(s);
- /*
- * Note if alarm expired normally or whether it
- * was aborted. If aborted, delete alarm from
- * clock alarm list. Return alarm to free list.
- */
- LOCK_CLOCK(s);
- if (alarm->al_status != ALARM_DONE) {
- /* This means we were interrupted and that
- thread->wait_result != THREAD_AWAKENED. */
- if ((alarm->al_prev)->al_next = alarm->al_next)
- (alarm->al_next)->al_prev = alarm->al_prev;
+ wait_result = thread_block(THREAD_CONTINUE_NULL);
+
+ /*
+ * Note if alarm expired normally or whether it
+ * was aborted. If aborted, delete alarm from
+ * clock alarm list. Return alarm to free list.
+ */
+ LOCK_CLOCK(s);
+ if (alarm->al_status != ALARM_DONE) {
+ assert(wait_result != THREAD_AWAKENED);
+ if ((alarm->al_prev)->al_next = alarm->al_next)
+ (alarm->al_next)->al_prev = alarm->al_prev;
+ rvalue = KERN_ABORTED;
+ }
+ *sleep_time = alarm->al_time;
+ alarm->al_status = ALARM_FREE;
+ } else {
+ assert(wait_result == THREAD_INTERRUPTED);
+ assert(alarm->al_status == ALARM_FREE);
rvalue = KERN_ABORTED;
}
- *sleep_time = alarm->al_time;
- alarm->al_status = ALARM_FREE;
alarm->al_next = alrmfree;
alrmfree = alarm;
UNLOCK_CLOCK(s);
return value;
}
-void
-clock_set_calendar_value(
- mach_timespec_t value)
-{
- clock_t clock = &clock_list[CALENDAR_CLOCK];
-
- (void) (*clock->cl_ops->c_settime)(&value);
-}
-
void
clock_deadline_for_periodic_event(
- AbsoluteTime interval,
- AbsoluteTime abstime,
- AbsoluteTime *deadline)
+ uint64_t interval,
+ uint64_t abstime,
+ uint64_t *deadline)
{
- assert(AbsoluteTime_to_scalar(&interval) != 0);
+ assert(interval != 0);
- ADD_ABSOLUTETIME(deadline, &interval);
+ *deadline += interval;
- if ( AbsoluteTime_to_scalar(deadline) <=
- AbsoluteTime_to_scalar(&abstime) ) {
- *deadline = abstime;
- clock_get_uptime(&abstime);
- ADD_ABSOLUTETIME(deadline, &interval);
+ if (*deadline <= abstime) {
+ *deadline = abstime + interval;
+ abstime = mach_absolute_time();
- if ( AbsoluteTime_to_scalar(deadline) <=
- AbsoluteTime_to_scalar(&abstime) ) {
- *deadline = abstime;
- ADD_ABSOLUTETIME(deadline, &interval);
- }
+ if (*deadline <= abstime)
+ *deadline = abstime + interval;
}
}
{
int wait_result;
- assert_wait((event_t)&mach_wait_until, THREAD_ABORTSAFE);
- thread_set_timer_deadline(scalar_to_AbsoluteTime(&deadline));
- wait_result = thread_block((void (*)) 0);
- if (wait_result != THREAD_TIMED_OUT)
- thread_cancel_timer();
+ wait_result = assert_wait((event_t)&mach_wait_until, THREAD_ABORTSAFE);
+ if (wait_result == THREAD_WAITING) {
+ thread_set_timer_deadline(deadline);
+ wait_result = thread_block(THREAD_CONTINUE_NULL);
+ if (wait_result != THREAD_TIMED_OUT)
+ thread_cancel_timer();
+ }
return ((wait_result == THREAD_INTERRUPTED)? KERN_ABORTED: KERN_SUCCESS);
}
+
+void
+clock_adjtime(
+ int32_t *secs,
+ int32_t *microsecs)
+{
+ uint32_t interval;
+ spl_t s;
+
+ s = splclock();
+ simple_lock(&calend_adjlock);
+
+ interval = clock_set_calendar_adjtime(secs, microsecs);
+ if (interval != 0) {
+ if (calend_adjdeadline >= interval)
+ calend_adjdeadline -= interval;
+ clock_deadline_for_periodic_event(interval, mach_absolute_time(),
+ &calend_adjdeadline);
+
+ timer_call_enter(&calend_adjcall, calend_adjdeadline);
+ }
+ else
+ timer_call_cancel(&calend_adjcall);
+
+ simple_unlock(&calend_adjlock);
+ splx(s);
+}
+
+static void
+calend_adjust_call(
+ timer_call_param_t p0,
+ timer_call_param_t p1)
+{
+ uint32_t interval;
+ spl_t s;
+
+ s = splclock();
+ simple_lock(&calend_adjlock);
+
+ interval = clock_adjust_calendar();
+ if (interval != 0) {
+ clock_deadline_for_periodic_event(interval, mach_absolute_time(),
+ &calend_adjdeadline);
+
+ timer_call_enter(&calend_adjcall, calend_adjdeadline);
+ }
+
+ simple_unlock(&calend_adjlock);
+ splx(s);
+}
+
+void
+clock_wakeup_calendar(void)
+{
+ thread_call_enter(&calend_wakecall);
+}
+
+static void
+calend_dowakeup(
+ thread_call_param_t p0,
+ thread_call_param_t p1)
+{
+ void IOKitResetTime(void);
+
+ IOKitResetTime();
+}