]> git.saurik.com Git - apple/xnu.git/blobdiff - osfmk/kern/clock.c
xnu-517.tar.gz
[apple/xnu.git] / osfmk / kern / clock.c
index 32cac4ebad409d01f09d81bf8d1f926047d7eeaf..79b348c776daa7e4814a862b7cac4d48de9af2bb 100644 (file)
@@ -3,19 +3,22 @@
  *
  * @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
  */
@@ -73,6 +72,13 @@ static struct        alarm           *alrmdone;              /* alarm done list pointer */
 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 !!! */
@@ -102,6 +108,16 @@ void       clock_alarm_deliver(
                        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.
  */
@@ -126,10 +142,17 @@ clock_config(void)
        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) {
@@ -161,6 +184,18 @@ clock_init(void)
        }
 }
 
+/*
+ * 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.
  */
@@ -170,8 +205,6 @@ clock_service_create(void)
        clock_t                 clock;
        register int    i;
 
-       mk_timer_initialize();
-
        /*
         * Initialize ipc clock services.
         */
@@ -184,15 +217,11 @@ clock_service_create(void)
        }
 
        /*
-        * 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);
 }
 
 /*
@@ -466,6 +495,8 @@ clock_sleep_internal(
                return (KERN_INVALID_VALUE);
        rvalue = KERN_SUCCESS;
        if (chkstat > 0) {
+               wait_result_t wait_result;
+
                /*
                 * Get alarm and add to clock alarm list.
                 */
@@ -481,34 +512,37 @@ clock_sleep_internal(
                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);
@@ -783,36 +817,22 @@ clock_get_calendar_value(void)
        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;
        }
 }
 
@@ -857,11 +877,79 @@ mach_wait_until(
 {
        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();
+}