Loading...
--- /dev/null
+++ Libc/Libc-1725.40.4/tests/clock.c
@@ -0,0 +1,269 @@
+#include <time.h>
+#include <sys/time.h>
+#include <mach/mach_time.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#include <darwintest.h>
+
+static void burn_cpu(void){
+ static char *dummy_text = "Four score and seven years ago our fathers brought forth on this continent a new nation, conceived in liberty, and dedicated to the";
+
+ for (int i = 0; i < 100; i++){
+ char key[64]; char txt[64];
+ strncpy(txt, dummy_text, 64);
+ for (int j = 0; i < 64; i++){
+ key[j] = rand() % 1;
+ }
+ setkey(key);
+ encrypt(txt, 0);
+ encrypt(txt, 1);
+ }
+}
+
+T_DECL(clock_gettime_realtime, "clock_gettime(CLOCK_REALTIME, tp)")
+{
+ struct timespec ts;
+ T_ASSERT_POSIX_ZERO(clock_gettime(CLOCK_REALTIME, &ts), NULL);
+
+ struct timeval tv;
+ T_ASSERT_POSIX_ZERO(gettimeofday(&tv, NULL), NULL);
+
+ T_EXPECT_LE((unsigned long)tv.tv_sec - (unsigned long)ts.tv_sec, (unsigned long)1,
+ "gettimeofday() should return same as clock_gettime(CLOCK_REALTIME)");
+}
+
+T_DECL(clock_gettime_monotonic, "clock_gettime(CLOCK_MONOTONIC, tp)")
+{
+ struct timespec ts1, ts2;
+ T_ASSERT_POSIX_ZERO(clock_gettime(CLOCK_MONOTONIC, &ts1), NULL);
+
+ sleep(1);
+
+ T_ASSERT_POSIX_ZERO(clock_gettime(CLOCK_MONOTONIC, &ts2), NULL);
+
+ uint64_t nsec1 = (uint64_t)ts1.tv_sec * NSEC_PER_SEC + (uint64_t)ts1.tv_nsec;
+ uint64_t nsec2 = (uint64_t)ts2.tv_sec * NSEC_PER_SEC + (uint64_t)ts2.tv_nsec;
+ uint64_t nsec_diff = (uint64_t)llabs((int64_t)nsec2 - (int64_t)nsec1);
+
+ T_EXPECT_GE(nsec_diff, 100 * NSEC_PER_MSEC, "clock_gettime(CLOCK_MONOTONIC) should advance at least 100ms");
+ T_EXPECT_LE(nsec_diff, 10 * NSEC_PER_SEC, "clock_gettime(CLOCK_MONOTONIC) should advance no more than 10s");
+}
+T_DECL(clock_gettime_monotonic_raw, "clock_gettime(CLOCK_MONOTONIC_RAW, tp)")
+{
+ struct timespec ts1, ts2;
+ T_ASSERT_POSIX_ZERO(clock_gettime(CLOCK_MONOTONIC_RAW, &ts1), NULL);
+
+ sleep(1);
+
+ T_ASSERT_POSIX_ZERO(clock_gettime(CLOCK_MONOTONIC_RAW, &ts2), NULL);
+
+ uint64_t nsec1 = (uint64_t)ts1.tv_sec * NSEC_PER_SEC + (uint64_t)ts1.tv_nsec;
+ uint64_t nsec2 = (uint64_t)ts2.tv_sec * NSEC_PER_SEC + (uint64_t)ts2.tv_nsec;
+ uint64_t nsec_diff = (uint64_t)llabs((int64_t)nsec2 - (int64_t)nsec1);
+
+ T_EXPECT_GE(nsec_diff, 100 * NSEC_PER_MSEC, "clock_gettime(CLOCK_MONOTONIC_RAW) should advance at least 100ms");
+ T_EXPECT_LE(nsec_diff, 10 * NSEC_PER_SEC, "clock_gettime(CLOCK_MONOTONIC_RAW) should advance no more than 10s");
+}
+
+T_DECL(clock_gettime_uptime_raw, "clock_gettime(CLOCK_UPTIME_RAW, tp)")
+{
+ struct timespec ts1, ts2;
+ T_ASSERT_POSIX_ZERO(clock_gettime(CLOCK_UPTIME_RAW, &ts1), NULL);
+
+ sleep(1);
+
+ T_ASSERT_POSIX_ZERO(clock_gettime(CLOCK_UPTIME_RAW, &ts2), NULL);
+
+ uint64_t nsec1 = (uint64_t)ts1.tv_sec * NSEC_PER_SEC + (uint64_t)ts1.tv_nsec;
+ uint64_t nsec2 = (uint64_t)ts2.tv_sec * NSEC_PER_SEC + (uint64_t)ts2.tv_nsec;
+ uint64_t nsec_diff = (uint64_t)llabs((int64_t)nsec2 - (int64_t)nsec1);
+
+ T_EXPECT_GE(nsec_diff, 100 * NSEC_PER_MSEC, "clock_gettime(CLOCK_UPTIME_RAW) should advance at least 100ms");
+ T_EXPECT_LE(nsec_diff, 10 * NSEC_PER_SEC, "clock_gettime(CLOCK_UPTIME_RAW) should advance no more than 10s");
+}
+
+T_DECL(clock_gettime_cputime, "clock_gettime(CLOCK_*_CPUTIME_ID, tp)")
+{
+ struct timespec thread_ts1, thread_ts2;
+ struct timespec process_ts1, process_ts2;
+ T_ASSERT_POSIX_ZERO(clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &process_ts1), NULL);
+ T_ASSERT_POSIX_ZERO(clock_gettime(CLOCK_THREAD_CPUTIME_ID, &thread_ts1), NULL);
+
+ burn_cpu();
+
+ T_ASSERT_POSIX_ZERO(clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &process_ts2), NULL);
+ T_ASSERT_POSIX_ZERO(clock_gettime(CLOCK_THREAD_CPUTIME_ID, &thread_ts1), NULL);
+
+ uint64_t nsec1, nsec2, nsec_diff;
+
+ // CLOCK_PROCESS_CPUTIME_ID
+ nsec1 = (uint64_t)process_ts1.tv_sec * NSEC_PER_SEC + (uint64_t)process_ts1.tv_nsec;
+ nsec2 = (uint64_t)process_ts2.tv_sec * NSEC_PER_SEC + (uint64_t)process_ts2.tv_nsec;
+ nsec_diff = (uint64_t)llabs((int64_t)nsec2 - (int64_t)nsec1);
+ T_EXPECT_GE(nsec_diff, NSEC_PER_USEC, "clock_gettime(CLOCK_PROCESS_CPUTIME_ID) should advance at least 1us");
+ T_EXPECT_LE(nsec_diff, 10 * NSEC_PER_SEC, "clock_gettime(CLOCK_PROCESS_CPUTIME_ID) should advance no more than 10s");
+
+ // CLOCK_THREAD_CPUTIME_ID
+ nsec1 = (uint64_t)thread_ts1.tv_sec * NSEC_PER_SEC + (uint64_t)thread_ts1.tv_nsec;
+ nsec2 = (uint64_t)thread_ts2.tv_sec * NSEC_PER_SEC + (uint64_t)thread_ts2.tv_nsec;
+ nsec_diff = (uint64_t)llabs((int64_t)nsec2 - (int64_t)nsec1);
+ T_EXPECT_GE(nsec_diff, NSEC_PER_USEC, "clock_gettime(CLOCK_THREAD_CPUTIME_ID) should advance at least 1us");
+ T_EXPECT_LE(nsec_diff, 10 * NSEC_PER_SEC, "clock_gettime(CLOCK_THREAD_CPUTIME_ID) should advance no more than 10s");
+}
+
+T_DECL(clock_gettime_monotonic_comparison, "compare CLOCK_MONOTONIC to CLOCK_MONOTONIC_RAW")
+{
+ struct timespec ts1, ts2;
+ bool should_retry = true;
+
+retry:
+ T_ASSERT_POSIX_ZERO(clock_gettime(CLOCK_MONOTONIC, &ts1), NULL);
+ T_ASSERT_POSIX_ZERO(clock_gettime(CLOCK_MONOTONIC_RAW, &ts2), NULL);
+
+ uint64_t nsec1 = (uint64_t)ts1.tv_sec * NSEC_PER_SEC + (uint64_t)ts1.tv_nsec;
+ uint64_t nsec2 = (uint64_t)ts2.tv_sec * NSEC_PER_SEC + (uint64_t)ts2.tv_nsec;
+ uint64_t nsec_diff = (uint64_t)llabs((int64_t)nsec2 - (int64_t)nsec1);
+
+ if (should_retry && nsec_diff > nsec2/20){
+ should_retry = false;
+ goto retry;
+ }
+
+ T_EXPECT_LE(nsec_diff, nsec2/20, "CLOCK_MONOTONIC and CLOCK_MONOTONIC_RAW should be within 5%%");
+}
+
+T_DECL(clock_gettime_nsec_np, "clock_gettime_nsec_np()")
+{
+ struct timespec ts;
+ uint64_t nsec, ts_nsec, diff;
+
+ T_ASSERT_POSIX_ZERO(clock_gettime(CLOCK_REALTIME, &ts), NULL);
+ T_WITH_ERRNO; T_ASSERT_NE((nsec = clock_gettime_nsec_np(CLOCK_REALTIME)), (uint64_t)0, NULL);
+ ts_nsec = (uint64_t)ts.tv_sec * NSEC_PER_SEC + (uint64_t)ts.tv_nsec;
+ diff = (uint64_t)llabs((int64_t)nsec - (int64_t)ts_nsec);
+ T_EXPECT_LE(diff, 100 * NSEC_PER_MSEC, "CLOCK_REALTIME: clock_gettime() and clock_gettime_nsec_np() should be within 100ms");
+
+ T_ASSERT_POSIX_ZERO(clock_gettime(CLOCK_MONOTONIC, &ts), NULL);
+ T_WITH_ERRNO; T_ASSERT_NE((nsec = clock_gettime_nsec_np(CLOCK_MONOTONIC)), (uint64_t)0, NULL);
+ ts_nsec = (uint64_t)ts.tv_sec * NSEC_PER_SEC + (uint64_t)ts.tv_nsec;
+ diff = (uint64_t)llabs((int64_t)nsec - (int64_t)ts_nsec);
+ T_EXPECT_LE(diff, 100 * NSEC_PER_MSEC, "CLOCK_MONOTONIC: clock_gettime() and clock_gettime_nsec_np() should be within 100ms");
+
+ T_ASSERT_POSIX_ZERO(clock_gettime(CLOCK_MONOTONIC_RAW, &ts), NULL);
+ T_WITH_ERRNO; T_ASSERT_NE((nsec = clock_gettime_nsec_np(CLOCK_MONOTONIC_RAW)), (uint64_t)0, NULL);
+ ts_nsec = (uint64_t)ts.tv_sec * NSEC_PER_SEC + (uint64_t)ts.tv_nsec;
+ diff = (uint64_t)llabs((int64_t)nsec - (int64_t)ts_nsec);
+ T_EXPECT_LE(diff, 100 * NSEC_PER_MSEC, "CLOCK_MONOTONIC_RAW: clock_gettime() and clock_gettime_nsec_np() should be within 100ms");
+
+ T_ASSERT_POSIX_ZERO(clock_gettime(CLOCK_UPTIME_RAW, &ts), NULL);
+ T_WITH_ERRNO; T_ASSERT_NE((nsec = clock_gettime_nsec_np(CLOCK_UPTIME_RAW)), (uint64_t)0, NULL);
+ ts_nsec = (uint64_t)ts.tv_sec * NSEC_PER_SEC + (uint64_t)ts.tv_nsec;
+ diff = (uint64_t)llabs((int64_t)nsec - (int64_t)ts_nsec);
+ T_EXPECT_LE(diff, 100 * NSEC_PER_MSEC, "CLOCK_UPTIME_RAW: clock_gettime() and clock_gettime_nsec_np() should be within 100ms");
+
+ T_ASSERT_POSIX_ZERO(clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &ts), NULL);
+ T_WITH_ERRNO; T_ASSERT_NE((nsec = clock_gettime_nsec_np(CLOCK_PROCESS_CPUTIME_ID)), (uint64_t)0, NULL);
+ ts_nsec = (uint64_t)ts.tv_sec * NSEC_PER_SEC + (uint64_t)ts.tv_nsec;
+ diff = (uint64_t)llabs((int64_t)nsec - (int64_t)ts_nsec);
+ T_EXPECT_LE(diff, 100 * NSEC_PER_MSEC, "CLOCK_PROCESS_CPUTIME_ID: clock_gettime() and clock_gettime_nsec_np() should be within 100ms");
+
+ T_ASSERT_POSIX_ZERO(clock_gettime(CLOCK_THREAD_CPUTIME_ID, &ts), NULL);
+ T_WITH_ERRNO; T_ASSERT_NE((nsec = clock_gettime_nsec_np(CLOCK_THREAD_CPUTIME_ID)), (uint64_t)0, NULL);
+ ts_nsec = (uint64_t)ts.tv_sec * NSEC_PER_SEC + (uint64_t)ts.tv_nsec;
+ diff = (uint64_t)llabs((int64_t)nsec - (int64_t)ts_nsec);
+ T_EXPECT_LE(diff, 100 * NSEC_PER_MSEC, "CLOCK_THREAD_CPUTIME_ID: clock_gettime() and clock_gettime_nsec_np() should be within 100ms");
+}
+
+T_DECL(clock_getres, "clock_getres()")
+{
+ struct timespec ts;
+
+ T_ASSERT_POSIX_ZERO(clock_getres(CLOCK_REALTIME, &ts), NULL);
+ T_LOG("Resolution of CLOCK_REALTIME is %ld ns", ts.tv_nsec);
+ T_EXPECT_EQ(ts.tv_sec, (long)0, NULL);
+ T_EXPECT_GT(ts.tv_nsec, (long)0, NULL);
+
+ T_ASSERT_POSIX_ZERO(clock_getres(CLOCK_MONOTONIC, &ts), NULL);
+ T_LOG("Resolution of CLOCK_MONOTONIC is %ld ns", ts.tv_nsec);
+ T_EXPECT_EQ(ts.tv_sec, (long)0, NULL);
+ T_EXPECT_GT(ts.tv_nsec, (long)0, NULL);
+
+ T_ASSERT_POSIX_ZERO(clock_getres(CLOCK_MONOTONIC_RAW, &ts), NULL);
+ T_LOG("Resolution of CLOCK_MONOTONIC_RAW is %ld ns", ts.tv_nsec);
+ T_EXPECT_EQ(ts.tv_sec, (long)0, NULL);
+ T_EXPECT_GT(ts.tv_nsec, (long)0, NULL);
+
+ T_ASSERT_POSIX_ZERO(clock_getres(CLOCK_UPTIME_RAW, &ts), NULL);
+ T_LOG("Resolution of CLOCK_UPTIME_RAW is %ld ns", ts.tv_nsec);
+ T_EXPECT_EQ(ts.tv_sec, (long)0, NULL);
+ T_EXPECT_GT(ts.tv_nsec, (long)0, NULL);
+
+ T_ASSERT_POSIX_ZERO(clock_getres(CLOCK_PROCESS_CPUTIME_ID, &ts), NULL);
+ T_LOG("Resolution of CLOCK_MONOTONIC_RAW is %ld ns", ts.tv_nsec);
+ T_EXPECT_EQ(ts.tv_sec, (long)0, NULL);
+ T_EXPECT_GT(ts.tv_nsec, (long)0, NULL);
+
+ T_ASSERT_POSIX_ZERO(clock_getres(CLOCK_THREAD_CPUTIME_ID, &ts), NULL);
+ T_LOG("Resolution of CLOCK_MONOTONIC_RAW is %ld ns", ts.tv_nsec);
+ T_EXPECT_EQ(ts.tv_sec, (long)0, NULL);
+ T_EXPECT_GT(ts.tv_nsec, (long)0, NULL);
+}
+
+T_DECL(clock_settime_realtime, "clock_settime(CLOCK_REALTIME, tp)",
+ T_META("as_root", "true"))
+{
+ struct timespec ts;
+ T_ASSERT_POSIX_ZERO(clock_gettime(CLOCK_REALTIME, &ts), NULL);
+
+ time_t initial_time = ts.tv_sec;
+
+ ts.tv_nsec += 1 * NSEC_PER_SEC;
+ T_ASSERT_POSIX_ZERO(clock_settime(CLOCK_REALTIME, &ts), NULL);
+
+ T_ASSERT_POSIX_ZERO(clock_gettime(CLOCK_REALTIME, &ts), NULL);
+ T_EXPECT_GT(ts.tv_sec - initial_time, (time_t)0, "time should move forward at least one second");
+ T_EXPECT_LE(ts.tv_sec - initial_time, (time_t)2, "time should move forward less than two seconds");
+}
+T_DECL(clock_settime_other, "clock_settime(CLOCK_*, tp)",
+ T_META("as_root", "true"))
+{
+ struct timespec ts;;
+ T_ASSERT_POSIX_ZERO(clock_gettime(CLOCK_MONOTONIC_RAW, &ts), NULL);
+ T_EXPECT_EQ(clock_settime(CLOCK_MONOTONIC_RAW, &ts), -1, NULL);
+ T_EXPECT_EQ(errno, EINVAL, NULL);
+
+ T_ASSERT_POSIX_ZERO(clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &ts), NULL);
+ T_EXPECT_EQ(clock_settime(CLOCK_PROCESS_CPUTIME_ID, &ts), -1, NULL);
+ T_EXPECT_EQ(errno, EINVAL, NULL);
+
+ T_ASSERT_POSIX_ZERO(clock_gettime(CLOCK_UPTIME_RAW, &ts), NULL);
+ T_EXPECT_EQ(clock_settime(CLOCK_UPTIME_RAW, &ts), -1, NULL);
+ T_EXPECT_EQ(errno, EINVAL, NULL);
+
+ T_ASSERT_POSIX_ZERO(clock_gettime(CLOCK_THREAD_CPUTIME_ID, &ts), NULL);
+ T_EXPECT_EQ(clock_settime(CLOCK_THREAD_CPUTIME_ID, &ts), -1, NULL);
+ T_EXPECT_EQ(errno, EINVAL, NULL);
+}
+
+T_DECL(clock_settime_negative, "make sure clock_settime(CLOCK_REALTIME, tp) doesn't allow negative values in any fields",
+ T_META("as_root", "true"))
+{
+ struct timespec new, old;
+ T_ASSERT_POSIX_ZERO(clock_gettime(CLOCK_REALTIME, &old), NULL);
+
+ new.tv_sec = 1624297339;
+ new.tv_nsec = -28946484;
+ T_EXPECT_EQ(clock_settime(CLOCK_REALTIME, &new), -1, NULL);
+
+ new.tv_sec = -12;
+ new.tv_nsec = 28946484;
+ T_EXPECT_EQ(clock_settime(CLOCK_REALTIME, &new), -1, NULL);
+
+ new.tv_sec = -12;
+ new.tv_nsec = -28946484;
+ T_EXPECT_EQ(clock_settime(CLOCK_REALTIME, &new), -1, NULL);
+
+ // Put things roughly back where they were
+ T_ASSERT_POSIX_ZERO(clock_settime(CLOCK_REALTIME, &old), NULL);
+}