<pre style='margin:0'>
Christopher Nielsen (mascguy) pushed a commit to branch master
in repository macports-legacy-support.

</pre>
<p><a href="https://github.com/macports/macports-legacy-support/commit/356216430b5534f252d1dc0a58647deb5e0b4754">https://github.com/macports/macports-legacy-support/commit/356216430b5534f252d1dc0a58647deb5e0b4754</a></p>
<pre style="white-space: pre; background: #F8F8F8"><span style='display:block; white-space:pre;color:#808000;'>commit 356216430b5534f252d1dc0a58647deb5e0b4754
</span>Author: Fred Wright <fw@fwright.net>
AuthorDate: Sat Jan 25 22:08:33 2025 -0800

<span style='display:block; white-space:pre;color:#404040;'>    Rewrite clock_gettime_nsec_np()
</span><span style='display:block; white-space:pre;color:#404040;'>    
</span><span style='display:block; white-space:pre;color:#404040;'>    This rewrites clock_gettime_nsec_np() as a separate function, rather
</span><span style='display:block; white-space:pre;color:#404040;'>    than as a wrapper around clock_gettime().  It does not redo the
</span><span style='display:block; white-space:pre;color:#404040;'>    mach_time scaling, which is left for another commit.  It does
</span><span style='display:block; white-space:pre;color:#404040;'>    provide some groundwork for improvements to clock_gettime().
</span><span style='display:block; white-space:pre;color:#404040;'>    
</span><span style='display:block; white-space:pre;color:#404040;'>    Also adds the missing "sandwich" to get a consistent
</span><span style='display:block; white-space:pre;color:#404040;'>    boottime/timeofday pair, to avoid a race.
</span><span style='display:block; white-space:pre;color:#404040;'>    
</span><span style='display:block; white-space:pre;color:#404040;'>    TESTED:
</span><span style='display:block; white-space:pre;color:#404040;'>    Passes new clock test on all platforms, with temporary forgiveness for
</span><span style='display:block; white-space:pre;color:#404040;'>    inaccurate mach_time scaling on PPC.
</span>---
 src/time.c | 114 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++---
 1 file changed, 110 insertions(+), 4 deletions(-)

<span style='display:block; white-space:pre;color:#808080;'>diff --git a/src/time.c b/src/time.c
</span><span style='display:block; white-space:pre;color:#808080;'>index 3b23aa7..aa79484 100644
</span><span style='display:block; white-space:pre;background:#e0e0ff;'>--- a/src/time.c
</span><span style='display:block; white-space:pre;background:#e0e0ff;'>+++ b/src/time.c
</span><span style='display:block; white-space:pre;background:#e0e0e0;'>@@ -36,13 +36,119 @@
</span> #define BILLION32 1000000000U
 #define BILLION64 1000000000ULL
 
<span style='display:block; white-space:pre;background:#ffe0e0;'>-/* Interim implementation of clock_gettime_nsec_np() as wrapper */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+/*
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * Get the system boot time.  The faster means of doing this via a
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * communication page wasn't introduced until 10.12, where this code is
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * inapplicable, so we're stuck with doing it the slow way.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ *
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * Apple's similar code uses sysctlbyname(), which not only is slower
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * but also doesn't work on 10.4.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+static int
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+get_boottime(struct timeval *bt)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+{
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  size_t boottime_len = sizeof(*bt);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  int bt_mib[] = {CTL_KERN, KERN_BOOTTIME};
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  size_t bt_miblen = sizeof(bt_mib) / sizeof(bt_mib[0]);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  return sysctl(bt_mib, bt_miblen, bt, &boottime_len, NULL, 0);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+}
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+/* Get a consistent boot time / time of day pair. */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+static int
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+get_boot_and_tod(struct timeval *bt, struct timeval *tod)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+{
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  int ret;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  /*
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   * Note that older systems that only have one-second resolution on boottime
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   * don't store the tv_usec field at all, making initialization mandatory.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   * Otherwise, infinite loops may result.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  struct timeval tv1 = {0, 0}, tv2 = {0, 0};
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  do {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    if ((ret = get_boottime(&tv1))) return ret;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    if ((ret = gettimeofday(tod, NULL))) return ret;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    if ((ret = get_boottime(&tv2))) return ret;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  } while (tv1.tv_sec != tv2.tv_sec || tv1.tv_usec != tv2.tv_usec);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  *bt = tv1;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  return 0;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+}
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+/* Get the CPU usage of the current thread into user/system timevals. */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+static int
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+get_thread_usage(time_value_t *ut, time_value_t *st)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+{
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  int ret;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  mach_msg_type_number_t count = THREAD_BASIC_INFO_COUNT;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  thread_basic_info_data_t info;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  thread_port_t thread = mach_thread_self();
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  ret = thread_info(thread, THREAD_BASIC_INFO, (thread_info_t) &info, &count);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  mach_port_deallocate(mach_task_self(), thread);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  if (ret) return ret;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  *ut = info.user_time;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  *st = info.system_time;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  return 0;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+}
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span> uint64_t
 clock_gettime_nsec_np(clockid_t clk_id)
 {
<span style='display:block; white-space:pre;background:#ffe0e0;'>-  struct timespec ts;
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-  if (clock_gettime(clk_id, &ts)) return 0;
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-  return ts.tv_sec * BILLION64 + ts.tv_nsec;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  uint64_t mach_time;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  struct timeval tod, bt;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  struct rusage ru;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  time_value_t ut, st;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  static mach_timebase_info_data_t tbinfo;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  switch (clk_id) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  case CLOCK_REALTIME:
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    if (gettimeofday(&tod, NULL)) return 0;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    return tod.tv_sec * BILLION64 + tod.tv_usec * 1000;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  case CLOCK_MONOTONIC:
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    if (get_boot_and_tod(&bt, &tod)) return 0;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    return (tod.tv_sec - bt.tv_sec) * BILLION64
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           + (tod.tv_usec - bt.tv_usec) * 1000;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  case CLOCK_PROCESS_CPUTIME_ID:
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    if (getrusage(RUSAGE_SELF, &ru)) return 0;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    return (ru.ru_utime.tv_sec + ru.ru_stime.tv_sec) * BILLION64
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           + (ru.ru_utime.tv_usec + ru.ru_stime.tv_usec) * 1000;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  case CLOCK_THREAD_CPUTIME_ID:
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    if (get_thread_usage(&ut, &st)) return 0;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    return (ut.seconds + st.seconds) * BILLION64
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           + (ut.microseconds + st.microseconds) * 1000;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  /* For now these are all the same, matching CLOCK_UPTIME_RAW */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  case CLOCK_MONOTONIC_RAW:
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  case CLOCK_MONOTONIC_RAW_APPROX:
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  case CLOCK_UPTIME_RAW:
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  case CLOCK_UPTIME_RAW_APPROX:
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    mach_time = mach_absolute_time();
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    break;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  default:
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    errno = EINVAL;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    return 0;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  /* Obtain and cache mach_time scale factor (as a rational) */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  if (!tbinfo.numer || !tbinfo.denom) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    if (mach_timebase_info(&tbinfo)) return 0;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  /* Scale mach_time to nanoseconds and return it */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  /* Note that 1/1 is a common case worth special-casing */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  if (tbinfo.numer == tbinfo.denom) return mach_time;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  /* Temporary low-accuracy conversion */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  /* Multiplying first overflows on some old platforms */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  return mach_time * (tbinfo.numer / tbinfo.denom);
</span> }
 
 int clock_gettime( clockid_t clk_id, struct timespec *ts )
</pre><pre style='margin:0'>

</pre>