--- Gnu-Mach/kern/mach_clock.c 2020/09/02 04:47:38 1.1.1.5 +++ Gnu-Mach/kern/mach_clock.c 2020/09/02 04:49:56 1.1.1.6 @@ -85,26 +85,36 @@ int bigadj = 1000000; /* adjust 10*tick * 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) */ @@ -222,8 +232,16 @@ void clock_interrupt( 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; @@ -367,17 +385,47 @@ void init_timeout(void) 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); } @@ -392,11 +440,7 @@ host_get_time(host, current_time) 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); } @@ -423,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();