From: Michael Kelly <[email protected]>
It's awkward to support an interface that returns 'old_adjustment'
without modifying 'new_adjustment' because the latter is not an
optional parameter. This solution disregards 'new_adjustment'
specifically when the nanoseconds component has the value
MACH_ADJTIME_NSECS_OMIT (which is beyond the normally permissible
range).
---
include/mach/time_value.h | 9 +++++++++
kern/mach_clock.c | 30 +++++++++++++++++-------------
2 files changed, 26 insertions(+), 13 deletions(-)
diff --git a/include/mach/time_value.h b/include/mach/time_value.h
index 9c660e7e..fe8d0d6d 100644
--- a/include/mach/time_value.h
+++ b/include/mach/time_value.h
@@ -87,6 +87,15 @@ static __inline__ time_value_t
convert_time_value_from_user(rpc_time_value_t tv)
#define TIME_MICROS_MAX (1000000)
#define TIME_NANOS_MAX (1000000000)
+/* The host_adjust_time/host_adjust_time64 interfaces do not directly
+ support returning the outstanding time adjustment without
+ specifiying a new time adjustment. To overcome this limitation
+ these calls will not modify the time adjustment when the following
+ MACH_ADJTIME_ constants are specified as the sub-second component.
+ */
+#define MACH_ADJTIME_USECS_OMIT TIME_MICROS_MAX
+#define MACH_ADJTIME_NSECS_OMIT TIME_NANOS_MAX
+
#define time_value_assert(val) \
assert(0 <= (val)->microseconds && (val)->microseconds < TIME_MICROS_MAX);
diff --git a/kern/mach_clock.c b/kern/mach_clock.c
index c59ed7ad..04ae8291 100644
--- a/kern/mach_clock.c
+++ b/kern/mach_clock.c
@@ -667,16 +667,11 @@ host_adjust_time64(
time_value64_t *old_adjustment /* OUT */)
{
time_value64_t oadj;
- uint64_t ndelta_microseconds;
spl_t s;
if (host == HOST_NULL)
return (KERN_INVALID_HOST);
- /* Note we only adjust up to microsecond precision */
- ndelta_microseconds = new_adjustment.seconds *
MICROSECONDS_IN_ONE_SECOND
- + new_adjustment.nanoseconds / 1000;
-
#if NCPUS > 1
thread_bind(current_thread(), master_processor);
if (current_processor() != master_processor)
@@ -688,17 +683,26 @@ host_adjust_time64(
oadj.seconds = timedelta / MICROSECONDS_IN_ONE_SECOND;
oadj.nanoseconds = (timedelta % MICROSECONDS_IN_ONE_SECOND) * 1000;
- if (timedelta == 0) {
- if (ndelta_microseconds > bigadj)
+ if (new_adjustment.nanoseconds != MACH_ADJTIME_NSECS_OMIT)
+ {
+ int64_t ndelta_microseconds;
+
+ /* Note we only adjust up to microsecond precision */
+ ndelta_microseconds = new_adjustment.seconds *
MICROSECONDS_IN_ONE_SECOND
+ + new_adjustment.nanoseconds / 1000;
+
+ if (timedelta == 0) {
+ if (ndelta_microseconds > bigadj || ndelta_microseconds < -bigadj)
tickdelta = 10 * tickadj;
- else
+ else
tickdelta = tickadj;
- }
- /* Make ndelta_microseconds a multiple of tickdelta */
- if (ndelta_microseconds % tickdelta)
- ndelta_microseconds = ndelta_microseconds / tickdelta * tickdelta;
+ }
+ /* Make ndelta_microseconds a multiple of tickdelta */
+ if (ndelta_microseconds % tickdelta)
+ ndelta_microseconds = ndelta_microseconds / tickdelta * tickdelta;
- timedelta = ndelta_microseconds;
+ timedelta = ndelta_microseconds;
+ }
splx(s);
#if NCPUS > 1
--
2.47.3