<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/a8e29aad52a33e0c5a710a75db4222ca675a0728">https://github.com/macports/macports-legacy-support/commit/a8e29aad52a33e0c5a710a75db4222ca675a0728</a></p>
<pre style="white-space: pre; background: #F8F8F8"><span style='display:block; white-space:pre;color:#808000;'>commit a8e29aad52a33e0c5a710a75db4222ca675a0728
</span>Author: Fred Wright <fw@fwright.net>
AuthorDate: Thu Jan 16 18:19:31 2025 -0800

<span style='display:block; white-space:pre;color:#404040;'>    Add manual test for clock_settime().
</span><span style='display:block; white-space:pre;color:#404040;'>    
</span><span style='display:block; white-space:pre;color:#404040;'>    This test naturally requires running as root.  It goes to considerable
</span><span style='display:block; white-space:pre;color:#404040;'>    lengths to avoid leaving the time screwed up if something goes wrong,
</span><span style='display:block; white-space:pre;color:#404040;'>    and to hide its temporary adjustment from other programs.
</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;'>    Fails where expected without the new support.
</span><span style='display:block; white-space:pre;color:#404040;'>    Passes on all platforms with it.
</span>---
 manual_tests/libtest_settime.c | 324 +++++++++++++++++++++++++++++++++++++++++
 1 file changed, 324 insertions(+)

<span style='display:block; white-space:pre;color:#808080;'>diff --git a/manual_tests/libtest_settime.c b/manual_tests/libtest_settime.c
</span>new file mode 100644
<span style='display:block; white-space:pre;color:#808080;'>index 0000000..e340a6f
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>--- /dev/null
</span><span style='display:block; white-space:pre;background:#e0e0ff;'>+++ b/manual_tests/libtest_settime.c
</span><span style='display:block; white-space:pre;background:#e0e0e0;'>@@ -0,0 +1,324 @@
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+/*
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * Copyright (c) 2025 Frederick H. G. Wright II <fw@fwright.net>
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ *
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * Permission to use, copy, modify, and distribute this software for any
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * purpose with or without fee is hereby granted, provided that the above
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * copyright notice and this permission notice appear in all copies.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ *
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
</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;'>+/*
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * This is a test of the clock_settime() function.  Because it requires
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * invasively altering the system time, it's a manual test that must be
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * run as root.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ *
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * We take a few precautions to minimize the potential trouble:
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ *   1) The time adjustment is only 100ms, which is less than the typical
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ *  NTP threshold for making step adjustments.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ *   2) We attempt to almost immediately undo the adjustment.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ *   3) The adjustment is first forward and then backward, so if the test
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ *  dies in midstream, we're left with the less troublesome forard step.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ *   4) We set our priority to the maximum, and launch as many threads
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ *  as there are CPUs, to mostly lock out other programs (briefly).
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ *   5) We begin with 100ms sleep, to start with a fresh quantum and
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ *  minimize the chance of a reschedule in midstream.
</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;'>+#include <errno.h>
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#include <libgen.h>
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#include <pthread.h>
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#include <stdio.h>
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#include <stddef.h>
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#include <stdlib.h>
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#include <string.h>
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#include <time.h>
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#include <unistd.h>
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#include <sys/resource.h>
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#include <sys/sysctl.h>
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#include <sys/time.h>
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#include <sys/types.h>
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#define SLEEP_MS 500
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#define TIME_BUMP_MS 100
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+/* Fudge factor in validity checks */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#define FUDGE_NS 1000
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#define TARGET_PRIO -20
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#define MILLION 1000000LL
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#define BILLION (MILLION * 1000)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+typedef long long nstime_t;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+typedef struct info_s {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  nstime_t init_raw;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  nstime_t init_real;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  nstime_t first_set;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  nstime_t first_real;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  nstime_t middle_raw;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  nstime_t middle_real;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  nstime_t second_set;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  nstime_t second_real;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  nstime_t final_raw;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+} info_t;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+static nstime_t
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+timespec2ns(const struct timespec *ts)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+{
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  return ts->tv_sec * BILLION + ts->tv_nsec;
</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;'>+static struct timespec
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ns2timespec(nstime_t nsec)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+{
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  struct timespec ts;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  ts.tv_sec = nsec / BILLION;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  ts.tv_nsec = nsec % BILLION;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  return ts;
</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;'>+static int
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+clock_getns(clockid_t clock_id, nstime_t *nsp)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+{
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  struct timespec ts;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  if (clock_gettime(clock_id, &ts) < 0) return errno;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  *nsp = timespec2ns(&ts);
</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;'>+static int
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+clock_setns(nstime_t nsec)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+{
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  struct timespec ts = ns2timespec(nsec);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  if (clock_settime(CLOCK_REALTIME, &ts) < 0) return -1;
</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;'>+static int
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+do_test(info_t *tp)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+{
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  int err, tverr;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  nstime_t delta;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  struct timeval orig_tv;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  /* First warm up the clocks */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  (void) clock_getns(CLOCK_MONOTONIC_RAW, &tp->init_raw);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  (void) clock_getns(CLOCK_REALTIME, &tp->init_raw);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  /* Get us a fresh quantum */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  (void) usleep(SLEEP_MS * 1000);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  /* Save original gettimeofday() time */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  tverr = gettimeofday(&orig_tv, NULL);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  /* Get both real and raw times */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  if (clock_getns(CLOCK_MONOTONIC_RAW, &tp->init_raw)) return errno;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  if (clock_getns(CLOCK_REALTIME, &tp->init_real)) return errno;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  /* Adjust clock forward */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  tp->first_set = tp->init_real + TIME_BUMP_MS * MILLION;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  if (clock_setns(tp->first_set)) return errno;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  /* While clock is futzed, try to undo it on any error */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  do {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    /* Capture times from the middle */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    if ((err = clock_getns(CLOCK_REALTIME, &tp->first_real))) break;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    if ((err = clock_getns(CLOCK_MONOTONIC_RAW, &tp->middle_raw))) break;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    if ((err = clock_getns(CLOCK_REALTIME, &tp->middle_real))) break;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    /* Adjust clock backward, can't fix it if it doesn't work */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    tp->second_set = tp->middle_real - TIME_BUMP_MS * MILLION;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    err = clock_setns(tp->second_set);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  } while (0);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  /* If anything went wrong, try to put the clock back to the start */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  if (err) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    err = errno;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    if (!tverr) (void) settimeofday(&orig_tv, NULL);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    return err;
</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;'>+  /* Otherwise, finish up with a couple more captures */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  if (clock_getns(CLOCK_REALTIME, &tp->second_real)) return errno;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  if (clock_getns(CLOCK_MONOTONIC_RAW, &tp->final_raw)) return errno;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  /* Just to be safe, restore the time via settimeofday() */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  if (!tverr) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    delta = tp->final_raw - tp->init_raw;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    orig_tv.tv_sec += delta / BILLION;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    orig_tv.tv_usec += delta % BILLION / 1000;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    if (orig_tv.tv_usec >= MILLION) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+      ++orig_tv.tv_sec; orig_tv.tv_usec -= MILLION;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    (void) settimeofday(&orig_tv, NULL);
</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;'>+  /* All's good if here */
</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;'>+#define PRINT_TIME(ptr,name) printf("  " #name " = %lld ns\n", \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    (long long) ptr->name)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+static void
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+print_times(info_t *tp) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  PRINT_TIME(tp, init_raw);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  PRINT_TIME(tp, init_real);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  PRINT_TIME(tp, first_set);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  PRINT_TIME(tp, first_real);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  PRINT_TIME(tp, middle_raw);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  PRINT_TIME(tp, middle_real);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  PRINT_TIME(tp, second_set);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  PRINT_TIME(tp, second_real);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  PRINT_TIME(tp, final_raw);
</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;'>+static void *
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+thread_spin(void *arg)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+{
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  while (1) ;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  return NULL;
</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;'>+static void
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+unhog_cpus(pthread_t threads[], int nthreads)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+{
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  while (--nthreads >= 0) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    (void) pthread_cancel(threads[nthreads]);
</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;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+static int
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+hog_cpus(pthread_t threads[], int nthreads)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+{
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  int i, err;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  for (i = 0; i < nthreads; ++i) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    if (pthread_create(&threads[i], NULL, thread_spin, NULL)) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+      err = errno;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+      unhog_cpus(threads, i);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+      return err;
</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;'>+  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;'>+int
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+main(int argc, char *argv[])
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+{
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  int verbose = 0;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  int nc_mib[] = {CTL_HW, HW_NCPU};
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  size_t nc_miblen = sizeof(nc_mib) / sizeof(nc_mib[0]);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  int ncpus;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  size_t ncpus_sz = sizeof(ncpus);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  int orig_prio;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  pthread_t *threads;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  int err;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  nstime_t dur1, dur2, diff1, diff2;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  info_t info = {0};
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  if (argc > 1 && !strcmp(argv[1], "-v")) verbose = 1;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  if (verbose) printf("%s starting.\n", basename(argv[0]));
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  if (sysctl(nc_mib, nc_miblen, &ncpus, &ncpus_sz, NULL, 0) < 0) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    perror("sysctl for ncpus failed");
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    return 1;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  if (verbose) printf("Number of CPUs = %d\n", ncpus);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  if (!(threads = calloc(ncpus, sizeof(pthread_t)))) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    perror("unable to allocate thread array");
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    return 1;
</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;'>+  errno = 0;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  orig_prio = getpriority(PRIO_PROCESS, 0);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  if (orig_prio == -1 && errno) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    perror("can't get current priority");
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    free(threads);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    return 1;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  if (verbose) printf("Initial priority = %d\n", orig_prio);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  if (setpriority(PRIO_PROCESS, 0, TARGET_PRIO) < 0) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    perror("Unable to set priority");
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    fprintf(stderr, "Continuing anyway (will probably fail)\n");
</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;'>+  /* Try to lock out everyone else while we screw with the clock */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  if ((err = hog_cpus(threads, ncpus))) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    fprintf(stderr, "Unable to hog CPU with threads: %s\n", strerror(err));
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    free(threads);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    return 1;
</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;'>+  /* Do the test */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  err = do_test(&info);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  /* Undo our hogging */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  unhog_cpus(threads, ncpus);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  /* Clean up before reporting */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  (void) setpriority(PRIO_PROCESS, 0, orig_prio);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  free(threads);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  if (err) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    printf("Error encountered: %s\n", strerror(err));
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    printf("Dumping partial results:\n");
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    print_times(&info);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    return 1;
</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;'>+  /* See if the results are plausible */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  dur1 = info.middle_raw - info.init_raw;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  dur2 = info.final_raw - info.middle_raw;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  diff1 = info.first_real - info.first_set;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  diff2 = info.second_real - info.second_set;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  /* First check raw monotonicity (very unlikely wrong) */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  if (dur1 < 0) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    printf("Middle raw %lld < init raw %lld\n",
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           info.middle_raw, info.init_raw);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    err = 1;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  if (dur2 < 0) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    printf("Final raw %lld < middle raw %lld\n",
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           info.final_raw, info.middle_raw);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    err = 1;
</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;'>+  /* Now see if clock setting had reasonable effect */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  if (llabs(diff1) > dur1 + FUDGE_NS) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    printf("First set/read delta was %lld ns, bracketed by %lld ns\n",
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           diff1, dur1);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    err = 1;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  if (llabs(diff2) > dur2 + FUDGE_NS) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    printf("Second set/read delta was %lld ns, bracketed by %lld ns\n",
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           diff2, dur2);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    err = 1;
</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;'>+  if (verbose) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    print_times(&info);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    printf("Total ns = %lld\n", info.final_raw - info.init_raw);
</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;'>+  printf("%s %s.\n", basename(argv[0]), err ? "failed" : "passed");
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  return err;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+}
</span></pre><pre style='margin:0'>

</pre>