aboutsummaryrefslogtreecommitdiff
path: root/kern/mach_clock.c
diff options
context:
space:
mode:
Diffstat (limited to 'kern/mach_clock.c')
-rw-r--r--kern/mach_clock.c162
1 files changed, 102 insertions, 60 deletions
diff --git a/kern/mach_clock.c b/kern/mach_clock.c
index edf87f07..1817ce22 100644
--- a/kern/mach_clock.c
+++ b/kern/mach_clock.c
@@ -27,7 +27,7 @@
* the rights to redistribute these changes.
*/
/*
- * File: clock_prim.c
+ * File: mach_clock.c
* Author: Avadis Tevanian, Jr.
* Date: 1986
*
@@ -54,6 +54,7 @@
#include <kern/thread.h>
#include <kern/time_stamp.h>
#include <kern/timer.h>
+#include <kern/priority.h>
#include <vm/vm_kern.h>
#include <sys/time.h>
#include <machine/mach_param.h> /* HZ */
@@ -64,8 +65,6 @@
#include <kern/pc_sample.h>
#endif
-void softclock(); /* forward */
-
int hz = HZ; /* number of ticks per second */
int tick = (1000000 / HZ); /* number of usec per tick */
time_value_t time = { 0, 0 }; /* time since bootup (uncorrected) */
@@ -86,26 +85,36 @@ int bigadj = 1000000; /* adjust 10*tickadj if adjustment
* This update protocol, with a check value, allows
* do {
* secs = mtime->seconds;
+ * __sync_synchronize();
* usecs = mtime->microseconds;
+ * __sync_synchronize();
* } while (secs != mtime->check_seconds);
- * to read the time correctly. (On a multiprocessor this assumes
- * that processors see each other's writes in the correct order.
- * We have to insert write fence operations.) FIXME
+ * to read the time correctly.
*/
-mapped_time_value_t *mtime = 0;
+volatile mapped_time_value_t *mtime = 0;
#define update_mapped_time(time) \
MACRO_BEGIN \
if (mtime != 0) { \
mtime->check_seconds = (time)->seconds; \
- asm volatile("":::"memory"); \
+ __sync_synchronize(); \
mtime->microseconds = (time)->microseconds; \
- asm volatile("":::"memory"); \
+ __sync_synchronize(); \
mtime->seconds = (time)->seconds; \
} \
MACRO_END
+#define read_mapped_time(time) \
+MACRO_BEGIN \
+ do { \
+ time->seconds = mtime->seconds; \
+ __sync_synchronize(); \
+ time->microseconds = mtime->microseconds; \
+ __sync_synchronize(); \
+ } while (time->seconds != mtime->check_seconds); \
+MACRO_END
+
decl_simple_lock_data(, timer_lock) /* lock for ... */
timer_elt_data_t timer_head; /* ordered list of timeouts */
/* (doubles as end-of-list) */
@@ -121,13 +130,13 @@ timer_elt_data_t timer_head; /* ordered list of timeouts */
* the accuracy of the hardware clock.
*
*/
-void clock_interrupt(usec, usermode, basepri)
- register int usec; /* microseconds per tick */
- boolean_t usermode; /* executing user code */
- boolean_t basepri; /* at base priority */
+void clock_interrupt(
+ int usec, /* microseconds per tick */
+ boolean_t usermode, /* executing user code */
+ boolean_t basepri) /* at base priority */
{
- register int my_cpu = cpu_number();
- register thread_t thread = current_thread();
+ int my_cpu = cpu_number();
+ thread_t thread = current_thread();
counter(c_clock_ticks++);
counter(c_threads_total += c_threads_current);
@@ -150,8 +159,7 @@ void clock_interrupt(usec, usermode, basepri)
* Increment the CPU time statistics.
*/
{
- extern void thread_quantum_update(); /* in priority.c */
- register int state;
+ int state;
if (usermode)
state = CPU_STATE_USER;
@@ -187,8 +195,8 @@ void clock_interrupt(usec, usermode, basepri)
*/
if (my_cpu == master_cpu) {
- register spl_t s;
- register timer_elt_t telt;
+ spl_t s;
+ timer_elt_t telt;
boolean_t needsoft = FALSE;
#if TS_FORMAT == 1
@@ -221,11 +229,19 @@ void clock_interrupt(usec, usermode, basepri)
time_value_add_usec(&time, usec);
}
else {
- register int delta;
+ int delta;
if (timedelta < 0) {
- delta = usec - tickdelta;
- timedelta += tickdelta;
+ if (usec > tickdelta) {
+ delta = usec - tickdelta;
+ timedelta += tickdelta;
+ } else {
+ /* Not enough time has passed, defer overflowing
+ * correction for later, keep only one microsecond
+ * delta */
+ delta = 1;
+ timedelta += usec - 1;
+ }
}
else {
delta = usec + tickdelta;
@@ -236,7 +252,7 @@ void clock_interrupt(usec, usermode, basepri)
update_mapped_time(&time);
/*
- * Schedule soft-interupt for timeout if needed
+ * Schedule soft-interrupt for timeout if needed
*/
if (needsoft) {
if (basepri) {
@@ -272,15 +288,15 @@ void clock_interrupt(usec, usermode, basepri)
* and corrupts it.
*/
-void softclock()
+void softclock(void)
{
/*
* Handle timeouts.
*/
spl_t s;
- register timer_elt_t telt;
- register void (*fcn)( void * param );
- register void *param;
+ timer_elt_t telt;
+ void (*fcn)( void * param );
+ void *param;
while (TRUE) {
s = splsched();
@@ -311,12 +327,12 @@ void softclock()
* telt timer element. Function and param are already set.
* interval time-out interval, in hz.
*/
-void set_timeout(telt, interval)
- register timer_elt_t telt; /* already loaded */
- register unsigned int interval;
+void set_timeout(
+ timer_elt_t telt, /* already loaded */
+ unsigned int interval)
{
spl_t s;
- register timer_elt_t next;
+ timer_elt_t next;
s = splsched();
simple_lock(&timer_lock);
@@ -341,8 +357,7 @@ void set_timeout(telt, interval)
splx(s);
}
-boolean_t reset_timeout(telt)
- register timer_elt_t telt;
+boolean_t reset_timeout(timer_elt_t telt)
{
spl_t s;
@@ -362,7 +377,7 @@ boolean_t reset_timeout(telt)
}
}
-void init_timeout()
+void init_timeout(void)
{
simple_lock_init(&timer_lock);
queue_init(&timer_head.chain);
@@ -370,17 +385,47 @@ void init_timeout()
elapsed_ticks = 0;
}
+
+/*
+ * We record timestamps using the boot-time clock. We keep track of
+ * the boot-time clock by storing the difference to the real-time
+ * clock.
+ */
+struct time_value clock_boottime_offset;
+
+/*
+ * Update the offset of the boot-time clock from the real-time clock.
+ * This function must be called when the real-time clock is updated.
+ * This function must be called at SPLHIGH.
+ */
+void
+clock_boottime_update(struct time_value *new_time)
+{
+ struct time_value delta = time;
+ time_value_sub(&delta, new_time);
+ time_value_add(&clock_boottime_offset, &delta);
+}
/*
- * Record a timestamp in STAMP.
+ * Record a timestamp in STAMP. Records values in the boot-time clock
+ * frame.
*/
void
record_time_stamp (time_value_t *stamp)
{
- do {
- stamp->seconds = mtime->seconds;
- stamp->microseconds = mtime->microseconds;
- } while (stamp->seconds != mtime->check_seconds);
+ read_mapped_time(stamp);
+ time_value_add(stamp, &clock_boottime_offset);
+}
+
+/*
+ * Read a timestamp in STAMP into RESULT. Returns values in the
+ * real-time clock frame.
+ */
+void
+read_time_stamp (time_value_t *stamp, time_value_t *result)
+{
+ *result = *stamp;
+ time_value_sub(result, &clock_boottime_offset);
}
@@ -389,17 +434,13 @@ record_time_stamp (time_value_t *stamp)
*/
kern_return_t
host_get_time(host, current_time)
- host_t host;
+ const host_t host;
time_value_t *current_time; /* OUT */
{
if (host == HOST_NULL)
return(KERN_INVALID_HOST);
- do {
- current_time->seconds = mtime->seconds;
- current_time->microseconds = mtime->microseconds;
- } while (current_time->seconds != mtime->check_seconds);
-
+ read_mapped_time(current_time);
return (KERN_SUCCESS);
}
@@ -408,7 +449,7 @@ host_get_time(host, current_time)
*/
kern_return_t
host_set_time(host, new_time)
- host_t host;
+ const host_t host;
time_value_t new_time;
{
spl_t s;
@@ -426,6 +467,7 @@ host_set_time(host, new_time)
#endif /* NCPUS > 1 */
s = splhigh();
+ clock_boottime_update(&new_time);
time = new_time;
update_mapped_time(&time);
resettodr();
@@ -446,7 +488,7 @@ host_set_time(host, new_time)
*/
kern_return_t
host_adjust_time(host, new_adjustment, old_adjustment)
- host_t host;
+ const host_t host;
time_value_t new_adjustment;
time_value_t *old_adjustment; /* OUT */
{
@@ -492,22 +534,22 @@ host_adjust_time(host, new_adjustment, old_adjustment)
return (KERN_SUCCESS);
}
-void mapable_time_init()
+void mapable_time_init(void)
{
if (kmem_alloc_wired(kernel_map, (vm_offset_t *) &mtime, PAGE_SIZE)
!= KERN_SUCCESS)
panic("mapable_time_init");
- memset(mtime, 0, PAGE_SIZE);
+ memset((void *) mtime, 0, PAGE_SIZE);
update_mapped_time(&time);
}
-int timeopen()
+int timeopen(dev_t dev, int flag, io_req_t ior)
{
return(0);
}
-int timeclose()
+void timeclose(dev_t dev, int flag)
{
- return(0);
+ return;
}
/*
@@ -528,13 +570,13 @@ timer_elt_data_t timeout_timers[NTIMERS];
* param: parameter to pass to function
* interval: timeout interval, in hz.
*/
-void timeout(fcn, param, interval)
- void (*fcn)( void * param );
- void * param;
- int interval;
+void timeout(
+ void (*fcn)(void *param),
+ void * param,
+ int interval)
{
spl_t s;
- register timer_elt_t elt;
+ timer_elt_t elt;
s = splsched();
simple_lock(&timer_lock);
@@ -557,11 +599,11 @@ void timeout(fcn, param, interval)
* and removed.
*/
boolean_t untimeout(fcn, param)
- register void (*fcn)( void * param );
- register void * param;
+ void (*fcn)( void * param );
+ const void * param;
{
spl_t s;
- register timer_elt_t elt;
+ timer_elt_t elt;
s = splsched();
simple_lock(&timer_lock);