[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[PATCH] Add host_get_time64 RPC to return the time as time_value64_t.
From: |
Flavio Cruz |
Subject: |
[PATCH] Add host_get_time64 RPC to return the time as time_value64_t. |
Date: |
Fri, 13 Jan 2023 03:27:05 -0500 |
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
- [PATCH] Add host_get_time64 RPC to return the time as time_value64_t.,
Flavio Cruz <=