Also updated the mapped time to support the new 64-bit time while keeping compatibility with the user land programs currently using it so they can be migrated in parallel. --- doc/mach.texi | 42 ++++++++++++-------- include/mach/mach_host.defs | 8 ++++ include/mach/mach_types.defs | 5 +++ include/mach/time_value.h | 36 ++++++++++------- kern/mach_clock.c | 75 ++++++++++++++++++++++++------------ kern/mach_clock.h | 2 +- 6 files changed, 111 insertions(+), 57 deletions(-)
diff --git a/doc/mach.texi b/doc/mach.texi index 86a557cb..53026d0b 100644 --- a/doc/mach.texi +++ b/doc/mach.texi @@ -5612,39 +5612,39 @@ necessarily null-terminated. @node Host Time @section Host Time -@deftp {Data type} time_value_t +@deftp {Data type} time_value64_t This is the representation of a time in Mach. It is a @code{struct -time_value} and consists of the following members: +time_value64} and consists of the following members: @table @code -@item integer_t seconds +@item int64_t seconds The number of seconds. -@item integer_t microseconds -The number of microseconds. +@item int64_t nanoseconds +The number of nanoseconds. @end table @end deftp -The number of microseconds should always be smaller than -@code{TIME_MICROS_MAX} (100000). A time with this property is +The number of nanoseconds should always be smaller than +@code{TIME_NANOS_MAX} (100000000). A time with this property is @dfn{normalized}. Normalized time values can be manipulated with the following macros: -@defmac time_value_add_usec (@w{time_value_t *@var{val}}, @w{integer_t *@var{micros}}) -Add @var{micros} microseconds to @var{val}. If @var{val} is normalized -and @var{micros} smaller than @code{TIME_MICROS_MAX}, @var{val} will be +@defmac time_value64_add_nanos (@w{time_value64_t *@var{val}}, @w{int64_t *@var{nanos}}) +Add @var{nanos} nanoseconds to @var{val}. If @var{val} is normalized +and @var{nanos} smaller than @code{TIME_NANOS_MAX}, @var{val} will be normalized afterwards. @end defmac -@defmac time_value_add (@w{time_value_t *@var{result}}, @w{time_value_t *@var{addend}}) +@defmac time_value64_add (@w{time_value64_t *@var{result}}, @w{time_value64_t *@var{addend}}) Add the values in @var{addend} to @var{result}. If both are normalized, @var{result} will be normalized afterwards. @end defmac -A variable of type @code{time_value_t} can either represent a duration +A variable of type @code{time_value64_t} can either represent a duration or a fixed point in time. In the latter case, it shall be interpreted as -the number of seconds and microseconds after the epoch 1. Jan 1970. +the number of seconds and nanoseconds after the epoch 1. Jan 1970. -@deftypefun kern_return_t host_get_time (@w{host_t @var{host}}, @w{time_value_t *@var{current_time}}) +@deftypefun kern_return_t host_get_time64 (@w{host_t @var{host}}, @w{time_value64_t *@var{current_time}}) Get the current time as seen by @var{host}. On success, the time passed since the epoch is returned in @var{current_time}. @end deftypefun @@ -5675,6 +5675,14 @@ The number of microseconds. @item integer_t check_seconds This is a copy of the seconds value, which must be checked to protect +against a race condition when reading out the two time values. This +should only be used when getting the 32 bit version of @code{time_value64_t}. + +@item time_value64_t time_value +The current time. + +@item int64_t check_seconds64 +This is a copy of the seconds value in @var{time_value}, which must be checked to protect against a race condition when reading out the two time values. @end table @end deftp @@ -5686,12 +5694,12 @@ mapped-time interface: @example do @{ - secs = mtime->seconds; + secs = mtime->time_value.seconds; __sync_synchronize(); - usecs = mtime->microseconds; + nanos = mtime->time_value.nanoseconds; __sync_synchronize(); @} -while (secs != mtime->check_seconds); +while (secs != mtime->check_seconds64); @end example diff --git a/include/mach/mach_host.defs b/include/mach/mach_host.defs index 28439a01..0674c859 100644 --- a/include/mach/mach_host.defs +++ b/include/mach/mach_host.defs @@ -352,3 +352,11 @@ routine processor_control( routine host_get_boot_info( host_priv : host_priv_t; out boot_info : kernel_boot_info_t); + +/* + * Get the time on this host. + * Available to all. + */ +routine host_get_time64( + host : host_t; + out current_time : time_value64_t); diff --git a/include/mach/mach_types.defs b/include/mach/mach_types.defs index a98e5c67..8f22137a 100644 --- a/include/mach/mach_types.defs +++ b/include/mach/mach_types.defs @@ -272,6 +272,11 @@ type time_value_t = rpc_time_value_t #endif ; +type time_value64_t = struct { + int64_t seconds; + int64_t nanoseconds; +}; + type emulation_vector_t = ^array[] of vm_offset_t; type rpc_signature_info_t = array[*:1024] of int; diff --git a/include/mach/time_value.h b/include/mach/time_value.h index 9ecdd28e..01f86644 100644 --- a/include/mach/time_value.h +++ b/include/mach/time_value.h @@ -86,7 +86,7 @@ static __inline__ time_value_t convert_time_value_from_user(rpc_time_value_t tv) assert(0 <= (val)->microseconds && (val)->microseconds < TIME_MICROS_MAX); #define time_value64_assert(val) \ - assert(0 <= (val)->nanoseconds && (val)->nanoseconds < TIME_NANOS_MAX); + assert(0 <= (val).nanoseconds && (val).nanoseconds < TIME_NANOS_MAX); #define time_value_add_usec(val, micros) { \ time_value_assert(val); \ @@ -98,23 +98,23 @@ static __inline__ time_value_t convert_time_value_from_user(rpc_time_value_t tv) time_value_assert(val); \ } -#define time_value64_add_usec(val, micros) { \ - time_value64_assert(val); \ - if (((val)->nanoseconds += (micros) * 1000) \ +#define time_value64_add_nanos(val, nanos) { \ + time_value64_assert(*val); \ + if (((val)->nanoseconds += (nanos)) \ >= TIME_NANOS_MAX) { \ (val)->nanoseconds -= TIME_NANOS_MAX; \ (val)->seconds++; \ } \ - time_value64_assert(val); \ + time_value64_assert(*val); \ } -#define time_value_sub_usec(val, micros) { \ - time_value_assert(val); \ - if (((val)->microseconds -= (micros)) < 0) { \ - (val)->microseconds += TIME_MICROS_MAX; \ +#define time_value64_sub_nanos(val, nanos) { \ + time_value64_assert(*val); \ + if (((val)->nanoseconds -= (nanos)) < 0) { \ + (val)->nanoseconds += TIME_NANOS_MAX; \ (val)->seconds--; \ } \ - time_value_assert(val); \ + time_value64_assert(*val); \ } #define time_value_add(result, addend) { \ @@ -123,10 +123,16 @@ static __inline__ time_value_t convert_time_value_from_user(rpc_time_value_t tv) time_value_add_usec(result, (addend)->microseconds); \ } -#define time_value_sub(result, subtrahend) { \ - time_value_assert(subtrahend); \ - (result)->seconds -= (subtrahend)->seconds; \ - time_value_sub_usec(result, (subtrahend)->microseconds); \ +#define time_value64_add(result, addend) { \ + time_value64_assert(addend); \ + (result)->seconds += (addend).seconds; \ + time_value64_add_nanos(result, (addend).nanoseconds); \ + } + +#define time_value64_sub(result, subtrahend) { \ + time_value64_assert(subtrahend); \ + (result)->seconds -= (subtrahend).seconds; \ + time_value64_sub_nanos(result, (subtrahend).nanoseconds); \ } /* @@ -144,6 +150,8 @@ typedef struct mapped_time_value { integer_t seconds; integer_t microseconds; integer_t check_seconds; + struct time_value64 time_value; + int64_t check_seconds64; } mapped_time_value_t; /* Macros for converting between struct timespec and time_value_t. */ diff --git a/kern/mach_clock.c b/kern/mach_clock.c index 7383684b..c7725ce5 100644 --- a/kern/mach_clock.c +++ b/kern/mach_clock.c @@ -96,21 +96,24 @@ volatile mapped_time_value_t *mtime = 0; MACRO_BEGIN \ if (mtime != 0) { \ mtime->check_seconds = (time)->seconds; \ + mtime->check_seconds64 = (time)->seconds; \ __sync_synchronize(); \ mtime->microseconds = (time)->nanoseconds / 1000; \ + mtime->time_value.nanoseconds = (time)->nanoseconds; \ __sync_synchronize(); \ mtime->seconds = (time)->seconds; \ + mtime->time_value.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); \ +#define read_mapped_time(time) \ +MACRO_BEGIN \ + do { \ + (time)->seconds = mtime->time_value.seconds; \ + __sync_synchronize(); \ + (time)->nanoseconds = mtime->time_value.nanoseconds; \ + __sync_synchronize(); \ + } while ((time)->seconds != mtime->check_seconds64); \ MACRO_END decl_simple_lock_data(, timer_lock) /* lock for ... */ @@ -225,7 +228,7 @@ void clock_interrupt( * Increment the time-of-day clock. */ if (timedelta == 0) { - time_value64_add_usec(&time, usec); + time_value64_add_nanos(&time, usec * 1000); } else { int delta; @@ -246,7 +249,7 @@ void clock_interrupt( delta = usec + tickdelta; timedelta -= tickdelta; } - time_value64_add_usec(&time, delta); + time_value64_add_nanos(&time, delta * 1000); } update_mapped_time(&time); @@ -390,7 +393,7 @@ void init_timeout(void) * the boot-time clock by storing the difference to the real-time * clock. */ -struct time_value clock_boottime_offset; +struct time_value64 clock_boottime_offset; /* * Update the offset of the boot-time clock from the real-time clock. @@ -398,11 +401,11 @@ struct time_value clock_boottime_offset; * This function must be called at SPLHIGH. */ static void -clock_boottime_update(struct time_value *new_time) +clock_boottime_update(const struct time_value64 *new_time) { - struct time_value delta = {.seconds = time.seconds, .microseconds = time.nanoseconds / 1000}; - time_value_sub(&delta, new_time); - time_value_add(&clock_boottime_offset, &delta); + struct time_value64 delta = time; + time_value64_sub(&delta, *new_time); + time_value64_add(&clock_boottime_offset, delta); } /* @@ -410,10 +413,13 @@ clock_boottime_update(struct time_value *new_time) * frame. */ void -record_time_stamp (time_value_t *stamp) +record_time_stamp(time_value_t *stamp) { - read_mapped_time(stamp); - time_value_add(stamp, &clock_boottime_offset); + time_value64_t stamp64; + read_mapped_time(&stamp64); + time_value64_add(&stamp64, clock_boottime_offset); + stamp->seconds = stamp64.seconds; + stamp->microseconds = stamp64.nanoseconds / 1000; } /* @@ -421,18 +427,36 @@ record_time_stamp (time_value_t *stamp) * real-time clock frame. */ void -read_time_stamp (time_value_t *stamp, time_value_t *result) +read_time_stamp (const time_value_t *stamp, time_value_t *result) { - *result = *stamp; - time_value_sub(result, &clock_boottime_offset); + time_value64_t result64 = {.seconds = stamp->seconds, .nanoseconds = stamp->microseconds * 1000}; + time_value64_sub(&result64, clock_boottime_offset); + result->seconds = result64.seconds; + result->microseconds = result64.nanoseconds / 1000; } /* - * Read the time. + * Read the time (deprecated version). */ kern_return_t host_get_time(const host_t host, time_value_t *current_time) +{ + if (host == HOST_NULL) + return(KERN_INVALID_HOST); + + time_value64_t current_time64; + read_mapped_time(¤t_time64); + current_time->seconds = current_time64.seconds; + current_time->microseconds = current_time64.nanoseconds / 1000; + return (KERN_SUCCESS); +} + +/* + * Read the time. + */ +kern_return_t +host_get_time64(const host_t host, time_value64_t *current_time) { if (host == HOST_NULL) return(KERN_INVALID_HOST); @@ -462,9 +486,10 @@ host_set_time(const host_t host, time_value_t new_time) #endif /* NCPUS > 1 */ s = splhigh(); - clock_boottime_update(&new_time); - time.seconds = new_time.seconds; - time.nanoseconds = new_time.microseconds * 1000; + const time_value64_t new_time64 = {.seconds = new_time.seconds, + .nanoseconds = new_time.microseconds * 1000}; + clock_boottime_update(&new_time64); + time = new_time64; update_mapped_time(&time); resettodr(); splx(s); diff --git a/kern/mach_clock.h b/kern/mach_clock.h index 903492e6..2da311d1 100644 --- a/kern/mach_clock.h +++ b/kern/mach_clock.h @@ -98,7 +98,7 @@ extern void record_time_stamp (time_value_t *stamp); * Read a timestamp in STAMP into RESULT. Returns values in the * real-time clock frame. */ -extern void read_time_stamp (time_value_t *stamp, time_value_t *result); +extern void read_time_stamp (const time_value_t *stamp, time_value_t *result); extern kern_return_t host_get_time( host_t host, -- 2.39.0