diff --git a/libc/calls/BUILD.mk b/libc/calls/BUILD.mk index 03f6bcf8e..ea3b8b75d 100644 --- a/libc/calls/BUILD.mk +++ b/libc/calls/BUILD.mk @@ -48,12 +48,13 @@ LIBC_CALLS_A_DIRECTDEPS = \ LIBC_NT_PDH \ LIBC_NT_POWRPROF \ LIBC_NT_PSAPI \ + LIBC_NT_REALTIME \ LIBC_NT_SYNCHRONIZATION \ LIBC_NT_WS2_32 \ LIBC_STR \ LIBC_SYSV \ LIBC_SYSV_CALLS \ - THIRD_PARTY_COMPILER_RT + THIRD_PARTY_COMPILER_RT \ LIBC_CALLS_A_DEPS := \ $(call uniq,$(foreach x,$(LIBC_CALLS_A_DIRECTDEPS),$($(x)))) diff --git a/libc/calls/clock_getres.c b/libc/calls/clock_getres.c index fae7959c4..39ba39fc0 100644 --- a/libc/calls/clock_getres.c +++ b/libc/calls/clock_getres.c @@ -20,24 +20,37 @@ #include "libc/dce.h" #include "libc/intrin/describeflags.h" #include "libc/intrin/strace.h" +#include "libc/runtime/clktck.h" #include "libc/sysv/consts/clock.h" #include "libc/sysv/errfuns.h" #include "libc/time.h" -static int sys_clock_getres_poly(int clock, struct timespec *ts, int64_t real, - int64_t real_coarse, int64_t boot) { - ts->tv_sec = 0; - if (clock == CLOCK_REALTIME) { - ts->tv_nsec = real; +static uint64_t hz_to_nanos(uint64_t frequency) { + if (!frequency) return 0; - } else if (clock == CLOCK_REALTIME_COARSE) { - ts->tv_nsec = real_coarse; + uint64_t quotient = 1000000000 / frequency; + uint64_t remainder = 1000000000 % frequency; + if (remainder > 0) + quotient += 1; + return quotient; +} + +static int sys_clock_getres_poly(int clock, struct timespec *ts, int64_t prec) { + if (ts) + ts->tv_sec = 0; + if (clock == CLOCK_REALTIME || // + clock == CLOCK_BOOTTIME || // + clock == CLOCK_MONOTONIC || // + clock == CLOCK_MONOTONIC_RAW) { + if (ts) + ts->tv_nsec = prec; return 0; - } else if (clock == CLOCK_MONOTONIC) { - ts->tv_nsec = 10; - return 0; - } else if (clock == CLOCK_BOOTTIME) { - ts->tv_nsec = boot; + } else if (clock == CLOCK_REALTIME_COARSE || + clock == CLOCK_MONOTONIC_COARSE || + clock == CLOCK_THREAD_CPUTIME_ID || + clock == CLOCK_PROCESS_CPUTIME_ID) { + if (ts) + *ts = timespec_fromnanos(hz_to_nanos(CLK_TCK)); return 0; } else { return einval(); @@ -45,11 +58,11 @@ static int sys_clock_getres_poly(int clock, struct timespec *ts, int64_t real, } static int sys_clock_getres_nt(int clock, struct timespec *ts) { - return sys_clock_getres_poly(clock, ts, 100, 1000000, 1000000); + return sys_clock_getres_poly(clock, ts, 100); } static int sys_clock_getres_xnu(int clock, struct timespec *ts) { - return sys_clock_getres_poly(clock, ts, 1000, 1000, 1000); + return sys_clock_getres_poly(clock, ts, 1000); } /** diff --git a/libc/calls/clock_gettime-mono.c b/libc/calls/clock_gettime-mono.c index 3bc38f37f..937967f57 100644 --- a/libc/calls/clock_gettime-mono.c +++ b/libc/calls/clock_gettime-mono.c @@ -18,42 +18,63 @@ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/atomic.h" #include "libc/calls/struct/timespec.h" +#include "libc/calls/struct/timespec.internal.h" +#include "libc/calls/struct/timeval.h" #include "libc/cosmo.h" -#include "libc/errno.h" +#include "libc/dce.h" #include "libc/nexgen32e/rdtsc.h" -#include "libc/nexgen32e/x86feature.h" /** - * @fileoverview Fast Monotonic Clock Polyfill for XNU/NT. + * @fileoverview Monotonic clock polyfill. + * + * This isn't quite `CLOCK_MONOTONIC` and isn't quite `CLOCK_BOOTTIME` + * either; however it is fast and almost always goes in one direction. + * + * Intel architecture guarantees that a mapping exists between rdtsc & + * nanoseconds only if the cpu advertises invariant timestamps support + * however this shouldn't matter for a monotonic clock since we really + * don't want to have it tick while suspended. Sadly that shall happen + * since nearly all x86 microprocessors support invariant tsc which is + * why we try to avoid this fallback when possible. */ +int sys_sysctl(int *, unsigned, void *, size_t *, void *, size_t) libcesque; + static struct { atomic_uint once; - struct timespec base_wall; - uint64_t base_tick; + unsigned long base; + struct timespec boot; } g_mono; +static struct timespec get_boot_time_xnu(void) { + struct timeval t; + size_t n = sizeof(t); + int mib[] = {1 /* CTL_KERN */, 21 /* KERN_BOOTTIME */}; + if (sys_sysctl(mib, 2, &t, &n, 0, 0) == -1) + __builtin_trap(); + return timeval_totimespec(t); +} + static void sys_clock_gettime_mono_init(void) { - g_mono.base_wall = timespec_real(); - g_mono.base_tick = rdtsc(); + g_mono.base = rdtsc(); + if (IsXnu()) { + g_mono.boot = get_boot_time_xnu(); + } else { + __builtin_trap(); + } } int sys_clock_gettime_mono(struct timespec *time) { uint64_t nanos; uint64_t cycles; -#ifdef __x86_64__ - // intel architecture guarantees that a mapping exists between rdtsc & - // nanoseconds only if the cpu advertises invariant timestamps support - if (!X86_HAVE(INVTSC)) - return -EINVAL; -#endif cosmo_once(&g_mono.once, sys_clock_gettime_mono_init); - cycles = rdtsc() - g_mono.base_tick; + // ensure we get the full 64 bits of counting, which avoids wraparound + cycles = rdtsc() - g_mono.base; // this is a crude approximation, that's worked reasonably well so far // only the kernel knows the actual mapping between rdtsc and nanosecs // which we could attempt to measure ourselves using clock_gettime but // we'd need to impose 100 ms of startup latency for a guess this good nanos = cycles / 3; - *time = timespec_add(g_mono.base_wall, timespec_fromnanos(nanos)); + *time = timespec_add(g_mono.boot, timespec_fromnanos(nanos)); return 0; } diff --git a/libc/calls/clock_gettime-nt.c b/libc/calls/clock_gettime-nt.c index 5a6464e42..68fbad19e 100644 --- a/libc/calls/clock_gettime-nt.c +++ b/libc/calls/clock_gettime-nt.c @@ -25,6 +25,7 @@ #include "libc/nt/runtime.h" #include "libc/nt/synchronization.h" #include "libc/nt/thread.h" +#include "libc/nt/time.h" #define _CLOCK_REALTIME 0 #define _CLOCK_MONOTONIC 1 @@ -32,64 +33,82 @@ #define _CLOCK_BOOTTIME 3 #define _CLOCK_PROCESS_CPUTIME_ID 4 #define _CLOCK_THREAD_CPUTIME_ID 5 - -static struct { - uint64_t base; - uint64_t freq; -} g_winclock; +#define _CLOCK_MONOTONIC_COARSE 6 textwindows int sys_clock_gettime_nt(int clock, struct timespec *ts) { - uint64_t t; + uint64_t hectons; struct NtFileTime ft, ftExit, ftUser, ftKernel, ftCreation; switch (clock) { case _CLOCK_REALTIME: - if (ts) { - GetSystemTimePreciseAsFileTime(&ft); - *ts = FileTimeToTimeSpec(ft); - } + GetSystemTimePreciseAsFileTime(&ft); + *ts = FileTimeToTimeSpec(ft); return 0; case _CLOCK_REALTIME_COARSE: - if (ts) { - GetSystemTimeAsFileTime(&ft); - *ts = FileTimeToTimeSpec(ft); - } + GetSystemTimeAsFileTime(&ft); + *ts = FileTimeToTimeSpec(ft); return 0; case _CLOCK_MONOTONIC: - if (ts) { - QueryPerformanceCounter(&t); - t = ((t - g_winclock.base) * 1000000000) / g_winclock.freq; - *ts = timespec_fromnanos(t); - } + // + // "If you need a higher resolution timer, use the + // QueryUnbiasedInterruptTime function, a multimedia timer, or a + // high-resolution timer. The elapsed time retrieved by the + // QueryUnbiasedInterruptTime function includes only time that + // the system spends in the working state." + // + // —Quoth MSDN § Windows Time + // + QueryUnbiasedInterruptTimePrecise(&hectons); + *ts = timespec_fromnanos(hectons * 100); + return 0; + case _CLOCK_MONOTONIC_COARSE: + // + // "QueryUnbiasedInterruptTimePrecise is similar to the + // QueryUnbiasedInterruptTime routine, but is more precise. The + // interrupt time reported by QueryUnbiasedInterruptTime is based + // on the latest tick of the system clock timer. The system clock + // timer is the hardware timer that periodically generates + // interrupts for the system clock. The uniform period between + // system clock timer interrupts is referred to as a system clock + // tick, and is typically in the range of 0.5 milliseconds to + // 15.625 milliseconds, depending on the hardware platform. The + // interrupt time value retrieved by QueryUnbiasedInterruptTime + // is accurate within a system clock tick. ¶To provide a system + // time value that is more precise than that of + // QueryUnbiasedInterruptTime, QueryUnbiasedInterruptTimePrecise + // reads the timer hardware directly, therefore a + // QueryUnbiasedInterruptTimePrecise call can be slower than a + // QueryUnbiasedInterruptTime call." + // + // —Quoth MSDN § QueryUnbiasedInterruptTimePrecise + // + QueryUnbiasedInterruptTime(&hectons); + *ts = timespec_fromnanos(hectons * 100); return 0; case _CLOCK_BOOTTIME: - if (ts) { - *ts = timespec_frommillis(GetTickCount64()); - } + // + // "Unbiased interrupt-time means that only time that the system + // is in the working state is counted; therefore, the interrupt + // time count is not "biased" by time the system spends in sleep + // or hibernation." + // + // —Quoth MSDN § Interrupt Time + // + QueryInterruptTimePrecise(&hectons); + *ts = timespec_fromnanos(hectons * 100); return 0; case _CLOCK_PROCESS_CPUTIME_ID: - if (ts) { - GetProcessTimes(GetCurrentProcess(), &ftCreation, &ftExit, &ftKernel, - &ftUser); - *ts = WindowsDurationToTimeSpec(ReadFileTime(ftUser) + - ReadFileTime(ftKernel)); - } + GetProcessTimes(GetCurrentProcess(), &ftCreation, &ftExit, &ftKernel, + &ftUser); + *ts = WindowsDurationToTimeSpec(ReadFileTime(ftUser) + + ReadFileTime(ftKernel)); return 0; case _CLOCK_THREAD_CPUTIME_ID: - if (ts) { - GetThreadTimes(GetCurrentThread(), &ftCreation, &ftExit, &ftKernel, - &ftUser); - *ts = WindowsDurationToTimeSpec(ReadFileTime(ftUser) + - ReadFileTime(ftKernel)); - } + GetThreadTimes(GetCurrentThread(), &ftCreation, &ftExit, &ftKernel, + &ftUser); + *ts = WindowsDurationToTimeSpec(ReadFileTime(ftUser) + + ReadFileTime(ftKernel)); return 0; default: return -EINVAL; } } - -__attribute__((__constructor__(40))) static textstartup void winclock_init() { - if (IsWindows()) { - QueryPerformanceCounter(&g_winclock.base); - QueryPerformanceFrequency(&g_winclock.freq); - } -} diff --git a/libc/calls/clock_gettime-xnu.c b/libc/calls/clock_gettime-xnu.c index f7a6f5e41..a0eb5b9e2 100644 --- a/libc/calls/clock_gettime-xnu.c +++ b/libc/calls/clock_gettime-xnu.c @@ -25,9 +25,6 @@ #include "libc/sysv/consts/clock.h" #ifdef __x86_64__ -#define CTL_KERN 1 -#define KERN_BOOTTIME 21 - int sys_clock_gettime_xnu(int clock, struct timespec *ts) { long ax, dx; if (clock == CLOCK_REALTIME) { @@ -47,31 +44,20 @@ int sys_clock_gettime_xnu(int clock, struct timespec *ts) { // 2. old xnu returns *ts in rax:rdx regs // // we assume this system call always succeeds - if (ts) { - asm volatile("syscall" - : "=a"(ax), "=d"(dx) - : "0"(0x2000000 | 116), "D"(ts), "S"(0), "1"(0) - : "rcx", "r8", "r9", "r10", "r11", "memory"); - if (ax) { - ts->tv_sec = ax; - ts->tv_nsec = dx; - } - ts->tv_nsec *= 1000; + asm volatile("syscall" + : "=a"(ax), "=d"(dx) + : "0"(0x2000000 | 116), "D"(ts), "S"(0), "1"(0) + : "rcx", "r8", "r9", "r10", "r11", "memory"); + if (ax) { + ts->tv_sec = ax; + ts->tv_nsec = dx; } + ts->tv_nsec *= 1000; return 0; - } else if (clock == CLOCK_MONOTONIC) { - if (!ts) - return 0; + } else if (clock == CLOCK_BOOTTIME || // + clock == CLOCK_MONOTONIC || // + clock == CLOCK_MONOTONIC_COARSE) { return sys_clock_gettime_mono(ts); - } else if (clock == CLOCK_BOOTTIME) { - struct timeval x; - size_t n = sizeof(x); - int mib[] = {CTL_KERN, KERN_BOOTTIME}; - if (sysctl(mib, ARRAYLEN(mib), &x, &n, 0, 0) == -1) - return -1; - if (ts) - *ts = timeval_totimespec(timeval_sub(timeval_real(), x)); - return 0; } else { return -EINVAL; } diff --git a/libc/calls/clock_gettime.c b/libc/calls/clock_gettime.c index 5d9d150f5..2cdd4a94b 100644 --- a/libc/calls/clock_gettime.c +++ b/libc/calls/clock_gettime.c @@ -60,44 +60,89 @@ static int __clock_gettime_init(int clockid, struct timespec *ts) { } static int clock_gettime_impl(int clock, struct timespec *ts) { - int rc; - if (!IsLinux()) - return __clock_gettime(clock, ts); -TryAgain: - - // Ensure fallback for old Linux sticks. - if (clock == 4 /* CLOCK_MONOTONIC_RAW */) - clock = CLOCK_MONOTONIC_RAW; - - // Call appropriate implementation. - rc = __clock_gettime(clock, ts); - - // CLOCK_MONOTONIC_RAW is Linux 2.6.28+ so not available on RHEL5 - if (rc == -EINVAL && clock == 4 /* CLOCK_MONOTONIC_RAW */) { - CLOCK_MONOTONIC_RAW = CLOCK_MONOTONIC; - CLOCK_MONOTONIC_RAW_APPROX = CLOCK_MONOTONIC; - goto TryAgain; - } - - return rc; + // BSDs and sometimes Linux too will crash when `ts` is NULL + // it's also nice to not have to check for null in polyfills + struct timespec memory; + if (!ts) + ts = &memory; + return __clock_gettime(clock, ts); } /** * Returns nanosecond time. * - * @param clock supports the following values across OSes: - * - `CLOCK_REALTIME` - * - `CLOCK_MONOTONIC` - * - `CLOCK_MONOTONIC_RAW` - * - `CLOCK_MONOTONIC_RAW_APPROX` - * - `CLOCK_REALTIME_FAST` - * - `CLOCK_REALTIME_COARSE` - * - `CLOCK_REALTIME_PRECISE` - * - `CLOCK_MONOTONIC_FAST` - * - `CLOCK_MONOTONIC_COARSE` - * - `CLOCK_MONOTONIC_PRECISE` - * - `CLOCK_THREAD_CPUTIME_ID` - * - `CLOCK_PROCESS_CPUTIME_ID` + * The `clock` parameter may bo set to: + * + * - `CLOCK_REALTIME` returns a wall clock timestamp represented in + * nanoseconds since the UNIX epoch (~1970). It'll count time in the + * suspend state. This clock is subject to being smeared by various + * adjustments made by NTP. These timestamps can have unpredictable + * discontinuous jumps when clock_settime() is used. Therefore this + * clock is the default clock for everything, even pthread condition + * variables. Cosmopoiltan guarantees this clock will never raise + * `EINVAL` and also guarantees `CLOCK_REALTIME == 0` will always be + * the case. On Windows this maps to GetSystemTimePreciseAsFileTime(). + * On platforms with vDSOs like Linux, Windows, and MacOS ARM64 this + * should take about 20 nanoseconds. + * + * - `CLOCK_MONOTONIC` returns a timestamp with an unspecified epoch, + * that should be when the system was powered on. These timestamps + * shouldn't go backwards. Timestamps shouldn't count time spent in + * the sleep, suspend, and hibernation states. These timestamps won't + * be impacted by clock_settime(). These timestamps may be impacted by + * frequency adjustments made by NTP. Cosmopoiltan guarantees this + * clock will never raise `EINVAL`. MacOS and BSDs use the word + * "uptime" to describe this clock. On Windows this maps to + * QueryUnbiasedInterruptTimePrecise(). + * + * - `CLOCK_BOOTTIME` is a monotonic clock returning a timestamp with an + * unspecified epoch, that should be relative to when the host system + * was powered on. These timestamps shouldn't go backwards. Timestamps + * should also include time spent in a sleep, suspend, or hibernation + * state. These timestamps aren't impacted by clock_settime(), but + * they may be impacted by frequency adjustments made by NTP. This + * clock will raise an `EINVAL` error on extremely old Linux distros + * like RHEL5. MacOS and BSDs use the word "monotonic" to describe + * this clock. On Windows this maps to QueryInterruptTimePrecise(). + * + * - `CLOCK_MONOTONIC_RAW` returns a timestamp from an unspecified + * epoch. These timestamps don't count time spent in the sleep, + * suspend, and hibernation states. This clock is not impacted by + * clock_settime(). Unlike `CLOCK_MONOTONIC` this clock is guaranteed + * to not be impacted by frequency adjustments. Providing this level + * of assurances may make this clock 10x slower than the monotonic + * clock. Furthermore this clock may cause `EINVAL` to be raised if + * running on a host system that doesn't provide those guarantees, + * e.g. OpenBSD and MacOS on AMD64. + * + * - `CLOCK_REALTIME_COARSE` is the same as `CLOCK_REALTIME` except + * it'll go faster if the host OS provides a cheaper way to read the + * wall time. Please be warned that coarse can be really coarse. + * Rather than nano precision, you're looking at `CLK_TCK` precision, + * which can lag as far as 30 milliseconds behind or possibly more. + * Cosmopolitan may fallback to `CLOCK_REALTIME` if a faster less + * accurate clock isn't provided by the system. This clock will raise + * an `EINVAL` error on extremely old Linux distros like RHEL5. On + * platforms with vDSOs like Linux, Windows, and MacOS ARM64 this + * should take about 5 nanoseconds. + * + * - `CLOCK_MONOTONIC_COARSE` is the same as `CLOCK_MONOTONIC` except + * it'll go faster if the host OS provides a cheaper way to read the + * unbiased time. Please be warned that coarse can be really coarse. + * Rather than nano precision, you're looking at `CLK_TCK` precision, + * which can lag as far as 30 milliseconds behind or possibly more. + * Cosmopolitan may fallback to `CLOCK_REALTIME` if a faster less + * accurate clock isn't provided by the system. This clock will raise + * an `EINVAL` error on extremely old Linux distros like RHEL5. On + * platforms with vDSOs like Linux, Windows, and MacOS ARM64 this + * should take about 5 nanoseconds. + * + * - `CLOCK_PROCESS_CPUTIME_ID` returns the amount of time this process + * was actively scheduled. This is similar to getrusage() and clock(). + * + * - `CLOCK_THREAD_CPUTIME_ID` returns the amount of time this thread + * was actively scheduled. This is similar to getrusage() and clock(). + * * @param ts is where the result is stored (or null to do clock check) * @return 0 on success, or -1 w/ errno * @raise EFAULT if `ts` points to invalid memory @@ -109,7 +154,6 @@ TryAgain: * @vforksafe */ int clock_gettime(int clock, struct timespec *ts) { - // threads on win32 stacks call this so we can't asan check *ts int rc = clock_gettime_impl(clock, ts); if (rc) { errno = -rc; diff --git a/libc/calls/clock_nanosleep-cosmo.c b/libc/calls/clock_nanosleep-cosmo.c deleted file mode 100644 index f49c4c50f..000000000 --- a/libc/calls/clock_nanosleep-cosmo.c +++ /dev/null @@ -1,85 +0,0 @@ -/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│ -│ vi: set et ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi │ -╞══════════════════════════════════════════════════════════════════════════════╡ -│ Copyright 2024 Justine Alexandra Roberts Tunney │ -│ │ -│ Permission to use, copy, modify, and/or distribute this software for │ -│ any purpose with or without fee is hereby granted, provided that the │ -│ above copyright notice and this permission notice appear in all copies. │ -│ │ -│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │ -│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │ -│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │ -│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │ -│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │ -│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │ -│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ -│ PERFORMANCE OF THIS SOFTWARE. │ -╚─────────────────────────────────────────────────────────────────────────────*/ -#include "libc/calls/calls.h" -#include "libc/calls/internal.h" -#include "libc/calls/struct/timespec.h" -#include "libc/errno.h" -#include "libc/runtime/clktck.h" -#include "libc/runtime/runtime.h" -#include "libc/sysv/consts/clock.h" -#include "libc/sysv/consts/timer.h" - -/** - * Sleeps with higher accuracy at the cost of cpu. - */ -int cosmo_clock_nanosleep(int clock, int flags, const struct timespec *req, - struct timespec *rem) { - - // pick clocks - int time_clock; - int sleep_clock; - if (clock == CLOCK_REALTIME || // - clock == CLOCK_REALTIME_PRECISE) { - time_clock = clock; - sleep_clock = CLOCK_REALTIME; - } else if (clock == CLOCK_MONOTONIC || // - clock == CLOCK_MONOTONIC_PRECISE) { - time_clock = clock; - sleep_clock = CLOCK_MONOTONIC; - } else if (clock == CLOCK_REALTIME_COARSE || // - clock == CLOCK_REALTIME_FAST) { - return sys_clock_nanosleep(CLOCK_REALTIME, flags, req, rem); - } else if (clock == CLOCK_MONOTONIC_COARSE || // - clock == CLOCK_MONOTONIC_FAST) { - return sys_clock_nanosleep(CLOCK_MONOTONIC, flags, req, rem); - } else { - return sys_clock_nanosleep(clock, flags, req, rem); - } - - // sleep bulk of time in kernel - struct timespec start, deadline, remain, waitfor, now; - struct timespec quantum = timespec_fromnanos(1000000000 / CLK_TCK); - clock_gettime(time_clock, &start); - deadline = flags & TIMER_ABSTIME ? *req : timespec_add(start, *req); - if (timespec_cmp(start, deadline) >= 0) - return 0; - remain = timespec_sub(deadline, start); - if (timespec_cmp(remain, quantum) > 0) { - waitfor = timespec_sub(remain, quantum); - if (sys_clock_nanosleep(sleep_clock, 0, &waitfor, rem) == -1) { - if (!flags && rem && errno == EINTR) { - *rem = timespec_add(*rem, quantum); - } - return -1; - } - } - - // spin through final scheduling quantum - int rc = 0; - ftrace_enabled(-1); - do { - if (_check_cancel()) { - rc = -1; - break; - } - clock_gettime(time_clock, &now); - } while (timespec_cmp(now, deadline) < 0); - ftrace_enabled(+1); - return rc; -} diff --git a/libc/calls/clock_nanosleep-nt.c b/libc/calls/clock_nanosleep-nt.c index 6d7adc5be..1546447a9 100644 --- a/libc/calls/clock_nanosleep-nt.c +++ b/libc/calls/clock_nanosleep-nt.c @@ -20,8 +20,10 @@ #include "libc/calls/struct/sigset.internal.h" #include "libc/calls/struct/timespec.h" #include "libc/calls/struct/timespec.internal.h" +#include "libc/calls/syscall-sysv.internal.h" #include "libc/errno.h" #include "libc/intrin/atomic.h" +#include "libc/stdio/sysparam.h" #include "libc/sysv/consts/timer.h" #include "libc/thread/tls.h" #ifdef __x86_64__ @@ -37,6 +39,7 @@ static textwindows int sys_clock_nanosleep_nt_impl(int clock, if (timespec_cmp(now, abs) >= 0) return 0; msdelay = timespec_tomillis(timespec_sub(abs, now)); + msdelay = MIN(msdelay, -1u); if (_park_norestart(msdelay, waitmask)) return -1; } @@ -48,15 +51,17 @@ textwindows int sys_clock_nanosleep_nt(int clock, int flags, int rc; struct timespec abs, now; sigset_t m = __sig_block(); - if (flags & TIMER_ABSTIME) { + if (flags) { abs = *req; } else { - if ((rc = sys_clock_gettime_nt(clock, &now))) + if ((rc = sys_clock_gettime_nt(clock, &now))) { + rc = _sysret(rc); goto BailOut; + } abs = timespec_add(now, *req); } rc = sys_clock_nanosleep_nt_impl(clock, abs, m); - if (rc == -1 && rem && errno == EINTR) { + if (rc == -1 && !flags && rem && errno == EINTR) { sys_clock_gettime_nt(clock, &now); *rem = timespec_subz(abs, now); } diff --git a/libc/calls/clock_nanosleep-openbsd.c b/libc/calls/clock_nanosleep-openbsd.c index e1d67bcef..25718feb2 100644 --- a/libc/calls/clock_nanosleep-openbsd.c +++ b/libc/calls/clock_nanosleep-openbsd.c @@ -18,6 +18,8 @@ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/calls/struct/timespec.h" #include "libc/calls/struct/timespec.internal.h" +#include "libc/calls/syscall-sysv.internal.h" +#include "libc/errno.h" #include "libc/sysv/consts/clock.h" #include "libc/sysv/errfuns.h" @@ -25,21 +27,18 @@ int sys_clock_nanosleep_openbsd(int clock, int flags, const struct timespec *req, struct timespec *rem) { int res; - struct timespec now, rel; - if (clock == CLOCK_REALTIME) { - if (!flags) { - res = sys_nanosleep(req, rem); - } else { - sys_clock_gettime(clock, &now); - if (timespec_cmp(*req, now) > 0) { - rel = timespec_sub(*req, now); - res = sys_nanosleep(&rel, 0); - } else { - res = 0; - } - } + struct timespec start, relative, remainder; + if (!flags) { + relative = *req; } else { - res = enotsup(); + if ((res = sys_clock_gettime(clock, &start))) + return _sysret(res); + if (timespec_cmp(start, *req) >= 0) + return 0; + relative = timespec_sub(*req, start); } + res = sys_nanosleep(&relative, &remainder); + if (res == -1 && errno == EINTR && rem && !flags) + *rem = remainder; return res; } diff --git a/libc/calls/clock_nanosleep-xnu.c b/libc/calls/clock_nanosleep-xnu.c index 23d0f2125..83a358f8e 100644 --- a/libc/calls/clock_nanosleep-xnu.c +++ b/libc/calls/clock_nanosleep-xnu.c @@ -35,8 +35,10 @@ int sys_clock_nanosleep_xnu(int clock, int flags, const struct timespec *req, struct timespec *rem) { #ifdef __x86_64__ if (flags & TIMER_ABSTIME) { + int nerr; struct timespec now; - sys_clock_gettime_xnu(clock, &now); + if ((nerr = sys_clock_gettime_xnu(clock, &now))) + return _sysret(nerr); if (timespec_cmp(*req, now) > 0) { struct timeval rel = timespec_totimeval(timespec_sub(*req, now)); return sys_select(0, 0, 0, 0, &rel); @@ -47,12 +49,13 @@ int sys_clock_nanosleep_xnu(int clock, int flags, const struct timespec *req, int rc; struct timespec beg; if (rem) - sys_clock_gettime_xnu(CLOCK_REALTIME, &beg); + if ((rc = sys_clock_gettime_xnu(clock, &beg))) + return _sysret(rc); struct timeval rel = timespec_totimeval(*req); // rounds up rc = sys_select(0, 0, 0, 0, &rel); if (rc == -1 && rem && errno == EINTR) { struct timespec end; - sys_clock_gettime_xnu(CLOCK_REALTIME, &end); + sys_clock_gettime_xnu(clock, &end); *rem = timespec_subz(*req, timespec_sub(end, beg)); } return rc; @@ -61,9 +64,8 @@ int sys_clock_nanosleep_xnu(int clock, int flags, const struct timespec *req, long res; struct timespec abs, now, rel; if (_weaken(pthread_testcancel_np) && // - _weaken(pthread_testcancel_np)()) { + _weaken(pthread_testcancel_np)()) return ecanceled(); - } if (flags & TIMER_ABSTIME) { abs = *req; if (!(res = __syslib->__clock_gettime(clock, &now))) { @@ -73,7 +75,10 @@ int sys_clock_nanosleep_xnu(int clock, int flags, const struct timespec *req, } } } else { - res = __syslib->__nanosleep(req, rem); + struct timespec remainder; + res = __syslib->__nanosleep(req, &remainder); + if (res == -EINTR && rem) + *rem = remainder; } if (res == -EINTR && // (_weaken(pthread_testcancel_np) && // diff --git a/libc/calls/clock_nanosleep.c b/libc/calls/clock_nanosleep.c index d912ce41c..cae196e89 100644 --- a/libc/calls/clock_nanosleep.c +++ b/libc/calls/clock_nanosleep.c @@ -82,6 +82,10 @@ errno_t clock_nanosleep(int clock, int flags, // struct timespec *rem) { if (IsMetal()) return ENOSYS; + if (IsLinux() && clock == CLOCK_REALTIME_COARSE) + clock = CLOCK_REALTIME; + if (IsLinux() && clock == CLOCK_MONOTONIC_COARSE) + clock = CLOCK_MONOTONIC; if (clock == 127 || // (flags & ~TIMER_ABSTIME) || // req->tv_sec < 0 || // @@ -89,22 +93,7 @@ errno_t clock_nanosleep(int clock, int flags, // return EINVAL; int rc; errno_t err, old = errno; - -TryAgain: - // Ensure fallback for old Linux sticks. - if (IsLinux() && clock == 4 /* CLOCK_MONOTONIC_RAW */) - clock = CLOCK_MONOTONIC_RAW; - rc = sys_clock_nanosleep(clock, flags, req, rem); - - // CLOCK_MONOTONIC_RAW is Linux 2.6.28+ so not available on RHEL5 - if (IsLinux() && rc && errno == EINVAL && - clock == 4 /* CLOCK_MONOTONIC_RAW */) { - CLOCK_MONOTONIC_RAW = CLOCK_MONOTONIC; - CLOCK_MONOTONIC_RAW_APPROX = CLOCK_MONOTONIC; - goto TryAgain; - } - err = !rc ? 0 : errno; errno = old; return err; diff --git a/libc/calls/struct/timespec.h b/libc/calls/struct/timespec.h index 7dbcb5b28..9a8c3e8db 100644 --- a/libc/calls/struct/timespec.h +++ b/libc/calls/struct/timespec.h @@ -20,7 +20,6 @@ int timespec_get(struct timespec *, int) libcesque; #ifdef _COSMO_SOURCE int sys_clock_nanosleep(int, int, const struct timespec *, struct timespec *); -int cosmo_clock_nanosleep(int, int, const struct timespec *, struct timespec *); #define timespec_zero ((struct timespec){0}) #define timespec_max ((struct timespec){0x7fffffffffffffff, 999999999}) libcesque int timespec_cmp(struct timespec, struct timespec) pureconst; @@ -34,8 +33,8 @@ libcesque struct timespec timespec_frommicros(int64_t) pureconst; libcesque struct timespec timespec_frommillis(int64_t) pureconst; libcesque struct timespec timespec_real(void) libcesque; libcesque struct timespec timespec_mono(void) libcesque; -libcesque struct timespec timespec_sleep(struct timespec) libcesque; -libcesque int timespec_sleep_until(struct timespec) libcesque; +libcesque struct timespec timespec_sleep(int, struct timespec) libcesque; +libcesque int timespec_sleep_until(int, struct timespec) libcesque; libcesque struct timespec timespec_sub(struct timespec, struct timespec) pureconst; libcesque struct timespec timespec_subz(struct timespec, diff --git a/libc/calls/timespec_real.c b/libc/calls/timespec_real.c index 59a5c8a80..81f6ed84b 100644 --- a/libc/calls/timespec_real.c +++ b/libc/calls/timespec_real.c @@ -16,7 +16,6 @@ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ -#include "libc/assert.h" #include "libc/calls/struct/timespec.h" #include "libc/sysv/consts/clock.h" @@ -31,6 +30,6 @@ */ struct timespec timespec_real(void) { struct timespec ts; - unassert(!clock_gettime(CLOCK_REALTIME, &ts)); + clock_gettime(CLOCK_REALTIME, &ts); return ts; } diff --git a/libc/calls/timespec_sleep.c b/libc/calls/timespec_sleep.c index 30cb9c52f..41d56a3fb 100644 --- a/libc/calls/timespec_sleep.c +++ b/libc/calls/timespec_sleep.c @@ -34,19 +34,16 @@ * @return unslept time which may be non-zero if the call was interrupted * @cancelationpoint */ -struct timespec timespec_sleep(struct timespec delay) { +struct timespec timespec_sleep(int clock, struct timespec delay) { int cs = -1; errno_t err; struct timespec remain; remain = timespec_zero; - if (_pthread_self()->pt_flags & PT_MASKED) { + if (_pthread_self()->pt_flags & PT_MASKED) cs = _pthread_block_cancelation(); - } - if ((err = clock_nanosleep(CLOCK_REALTIME, 0, &delay, &remain))) { + if ((err = clock_nanosleep(clock, 0, &delay, &remain))) unassert(err == EINTR); - } - if (cs != -1) { + if (cs != -1) _pthread_allow_cancelation(cs); - } return remain; } diff --git a/libc/calls/timespec_sleep_until.c b/libc/calls/timespec_sleep_until.c index 867268b96..5749d39f8 100644 --- a/libc/calls/timespec_sleep_until.c +++ b/libc/calls/timespec_sleep_until.c @@ -30,9 +30,9 @@ * @raise EINTR if signal was delivered * @cancelationpoint */ -errno_t timespec_sleep_until(struct timespec abs_deadline) { +errno_t timespec_sleep_until(int clock, struct timespec abs_deadline) { errno_t rc; - rc = clock_nanosleep(CLOCK_REALTIME, TIMER_ABSTIME, &abs_deadline, 0); + rc = clock_nanosleep(clock, TIMER_ABSTIME, &abs_deadline, 0); unassert(!rc || rc == EINTR || rc == ECANCELED); return rc; } diff --git a/libc/intrin/kclocknames.S b/libc/intrin/kclocknames.S index aed7d28c4..fec200aca 100644 --- a/libc/intrin/kclocknames.S +++ b/libc/intrin/kclocknames.S @@ -32,25 +32,13 @@ .underrun kClockNames: .e CLOCK_REALTIME,"REALTIME" - .e CLOCK_REALTIME_FAST,"REALTIME_FAST" // order matters - .e CLOCK_REALTIME_PRECISE,"REALTIME_PRECISE" // order matters .e CLOCK_REALTIME_COARSE,"REALTIME_COARSE" // order matters .e CLOCK_MONOTONIC,"MONOTONIC" - .e CLOCK_MONOTONIC_FAST,"MONOTONIC_FAST" // order matters .e CLOCK_MONOTONIC_RAW,"MONOTONIC_RAW" // order matters - .e CLOCK_MONOTONIC_PRECISE,"MONOTONIC_PRECISE" // order matters .e CLOCK_MONOTONIC_COARSE,"MONOTONIC_COARSE" // order matters .e CLOCK_PROCESS_CPUTIME_ID,"PROCESS_CPUTIME_ID" .e CLOCK_THREAD_CPUTIME_ID,"THREAD_CPUTIME_ID" - .e CLOCK_TAI,"TAI" - .e CLOCK_PROF,"PROF" .e CLOCK_BOOTTIME,"BOOTTIME" - .e CLOCK_REALTIME_ALARM,"REALTIME_ALARM" - .e CLOCK_BOOTTIME_ALARM,"BOOTTIME_ALARM" - .e CLOCK_UPTIME,"UPTIME" - .e CLOCK_UPTIME_FAST,"UPTIME_FAST" - .e CLOCK_UPTIME_PRECISE,"UPTIME_PRECISE" - .e CLOCK_SECOND,"SECOND" .long MAGNUM_TERMINATOR .endobj kClockNames,globl,hidden .overrun diff --git a/libc/nt/API-MS-Win-Core-Realtime-l1-1-1/QueryInterruptTime.S b/libc/nt/API-MS-Win-Core-Realtime-l1-1-1/QueryInterruptTime.S new file mode 100644 index 000000000..ef2c8cd8a --- /dev/null +++ b/libc/nt/API-MS-Win-Core-Realtime-l1-1-1/QueryInterruptTime.S @@ -0,0 +1,20 @@ +#include "libc/nt/codegen.h" +.imp API-MS-Win-Core-Realtime-l1-1-1,__imp_QueryInterruptTime,QueryInterruptTime + + .text.windows + .ftrace1 +QueryInterruptTime: + .ftrace2 +#ifdef __x86_64__ + push %rbp + mov %rsp,%rbp + mov %rdi,%rcx + sub $32,%rsp + call *__imp_QueryInterruptTime(%rip) + leave +#elif defined(__aarch64__) + mov x0,#0 +#endif + ret + .endfn QueryInterruptTime,globl + .previous diff --git a/libc/nt/API-MS-Win-Core-Realtime-l1-1-1/QueryInterruptTimePrecise.S b/libc/nt/API-MS-Win-Core-Realtime-l1-1-1/QueryInterruptTimePrecise.S new file mode 100644 index 000000000..0fb28d032 --- /dev/null +++ b/libc/nt/API-MS-Win-Core-Realtime-l1-1-1/QueryInterruptTimePrecise.S @@ -0,0 +1,20 @@ +#include "libc/nt/codegen.h" +.imp API-MS-Win-Core-Realtime-l1-1-1,__imp_QueryInterruptTimePrecise,QueryInterruptTimePrecise + + .text.windows + .ftrace1 +QueryInterruptTimePrecise: + .ftrace2 +#ifdef __x86_64__ + push %rbp + mov %rsp,%rbp + mov %rdi,%rcx + sub $32,%rsp + call *__imp_QueryInterruptTimePrecise(%rip) + leave +#elif defined(__aarch64__) + mov x0,#0 +#endif + ret + .endfn QueryInterruptTimePrecise,globl + .previous diff --git a/libc/nt/API-MS-Win-Core-Realtime-l1-1-1/QueryUnbiasedInterruptTimePrecise.S b/libc/nt/API-MS-Win-Core-Realtime-l1-1-1/QueryUnbiasedInterruptTimePrecise.S new file mode 100644 index 000000000..23fe67993 --- /dev/null +++ b/libc/nt/API-MS-Win-Core-Realtime-l1-1-1/QueryUnbiasedInterruptTimePrecise.S @@ -0,0 +1,20 @@ +#include "libc/nt/codegen.h" +.imp API-MS-Win-Core-Realtime-l1-1-1,__imp_QueryUnbiasedInterruptTimePrecise,QueryUnbiasedInterruptTimePrecise + + .text.windows + .ftrace1 +QueryUnbiasedInterruptTimePrecise: + .ftrace2 +#ifdef __x86_64__ + push %rbp + mov %rsp,%rbp + mov %rdi,%rcx + sub $32,%rsp + call *__imp_QueryUnbiasedInterruptTimePrecise(%rip) + leave +#elif defined(__aarch64__) + mov x0,#0 +#endif + ret + .endfn QueryUnbiasedInterruptTimePrecise,globl + .previous diff --git a/libc/nt/BUILD.mk b/libc/nt/BUILD.mk index f6bd28be4..7e96e9467 100644 --- a/libc/nt/BUILD.mk +++ b/libc/nt/BUILD.mk @@ -179,6 +179,27 @@ $(LIBC_NT_MEMORY_A).pkg: \ #─────────────────────────────────────────────────────────────────────────────── +LIBC_NT_ARTIFACTS += LIBC_NT_REALTIME_A +LIBC_NT_REALTIME = $(LIBC_NT_REALTIME_A_DEPS) $(LIBC_NT_REALTIME_A) +LIBC_NT_REALTIME_A = o/$(MODE)/libc/nt/realtime.a +LIBC_NT_REALTIME_A_SRCS := $(wildcard libc/nt/API-MS-Win-Core-Realtime-l1-1-1/*.S) +LIBC_NT_REALTIME_A_OBJS = $(LIBC_NT_REALTIME_A_SRCS:%.S=o/$(MODE)/%.o) +LIBC_NT_REALTIME_A_CHECKS = $(LIBC_NT_REALTIME_A).pkg +LIBC_NT_REALTIME_A_DIRECTDEPS = LIBC_NT_KERNEL32 +LIBC_NT_REALTIME_A_DEPS := \ + $(call uniq,$(foreach x,$(LIBC_NT_REALTIME_A_DIRECTDEPS),$($(x)))) + +$(LIBC_NT_REALTIME_A): \ + libc/nt/API-MS-Win-Core-Realtime-l1-1-1/ \ + $(LIBC_NT_REALTIME_A).pkg \ + $(LIBC_NT_REALTIME_A_OBJS) + +$(LIBC_NT_REALTIME_A).pkg: \ + $(LIBC_NT_REALTIME_A_OBJS) \ + $(foreach x,$(LIBC_NT_REALTIME_A_DIRECTDEPS),$($(x)_A).pkg) + +#─────────────────────────────────────────────────────────────────────────────── + LIBC_NT_ARTIFACTS += LIBC_NT_USER32_A LIBC_NT_USER32 = $(LIBC_NT_USER32_A_DEPS) $(LIBC_NT_USER32_A) LIBC_NT_USER32_A = o/$(MODE)/libc/nt/user32.a diff --git a/libc/nt/kernel32/QueryUnbiasedInterruptTime.S b/libc/nt/kernel32/QueryUnbiasedInterruptTime.S new file mode 100644 index 000000000..ee296b5b6 --- /dev/null +++ b/libc/nt/kernel32/QueryUnbiasedInterruptTime.S @@ -0,0 +1,20 @@ +#include "libc/nt/codegen.h" +.imp kernel32,__imp_QueryUnbiasedInterruptTime,QueryUnbiasedInterruptTime + + .text.windows + .ftrace1 +QueryUnbiasedInterruptTime: + .ftrace2 +#ifdef __x86_64__ + push %rbp + mov %rsp,%rbp + mov %rdi,%rcx + sub $32,%rsp + call *__imp_QueryUnbiasedInterruptTime(%rip) + leave +#elif defined(__aarch64__) + mov x0,#0 +#endif + ret + .endfn QueryUnbiasedInterruptTime,globl + .previous diff --git a/libc/nt/master.sh b/libc/nt/master.sh index 0e8e63654..c79782d21 100755 --- a/libc/nt/master.sh +++ b/libc/nt/master.sh @@ -218,8 +218,9 @@ imp 'Process32First' Process32FirstW kernel32 2 imp 'Process32Next' Process32NextW kernel32 2 imp 'PulseEvent' PulseEvent kernel32 1 imp 'PurgeComm' PurgeComm kernel32 2 -imp 'QueryPerformanceCounter' QueryPerformanceCounter kernel32 1 +imp 'QueryPerformanceCounter' QueryPerformanceCounter kernel32 1 # Windows 7+ imp 'QueryPerformanceFrequency' QueryPerformanceFrequency kernel32 1 +imp 'QueryUnbiasedInterruptTime' QueryUnbiasedInterruptTime kernel32 1 # Windows 7+ imp 'ReadConsole' ReadConsoleW kernel32 5 imp 'ReadConsoleInput' ReadConsoleInputW kernel32 4 imp 'ReadConsoleOutput' ReadConsoleOutputW kernel32 5 @@ -634,6 +635,13 @@ imp 'WakeByAddressSingle' WakeByAddressSingle API-MS-Win-Core-Synch-l1-2 imp 'MapViewOfFile3' MapViewOfFile3 API-MS-Win-Core-Memory-l1-1-6 9 imp 'VirtualAlloc2' VirtualAlloc2 API-MS-Win-Core-Memory-l1-1-6 7 +# API-MS-Win-Core-Realtime-l1-1-1.dll (Windows 10+) +# +# Name Actual DLL Arity +imp 'QueryInterruptTime' QueryInterruptTime API-MS-Win-Core-Realtime-l1-1-1 1 +imp 'QueryInterruptTimePrecise' QueryInterruptTimePrecise API-MS-Win-Core-Realtime-l1-1-1 1 +imp 'QueryUnbiasedInterruptTimePrecise' QueryUnbiasedInterruptTimePrecise API-MS-Win-Core-Realtime-l1-1-1 1 + # NTDLL.DLL # BEYOND THE PALE # diff --git a/libc/nt/time.h b/libc/nt/time.h index 59c359ca3..a415075f9 100644 --- a/libc/nt/time.h +++ b/libc/nt/time.h @@ -33,5 +33,10 @@ uint32_t GetTimeZoneInformation( uint32_t GetDynamicTimeZoneInformation( struct NtDynamicTimeZoneInformation *out_lpTimeZoneInformation); +bool32 QueryInterruptTime(uint64_t *); /* Windows 10+ */ +bool32 QueryInterruptTimePrecise(uint64_t *); /* Windows 10+ */ +bool32 QueryUnbiasedInterruptTime(uint64_t *); /* Windows 7+ */ +bool32 QueryUnbiasedInterruptTimePrecise(uint64_t *); /* Windows 10+ */ + COSMOPOLITAN_C_END_ #endif /* COSMOPOLITAN_LIBC_NT_TIME_H_ */ diff --git a/libc/sock/setsockopt-nt.c b/libc/sock/setsockopt-nt.c index f9e7a6a4d..c8fafce00 100644 --- a/libc/sock/setsockopt-nt.c +++ b/libc/sock/setsockopt-nt.c @@ -16,8 +16,8 @@ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ -#include "libc/intrin/fds.h" #include "libc/calls/struct/timeval.h" +#include "libc/intrin/fds.h" #include "libc/nt/struct/linger.h" #include "libc/nt/thunk/msabi.h" #include "libc/nt/winsock.h" @@ -42,8 +42,8 @@ textwindows int sys_setsockopt_nt(struct Fd *fd, int level, int optname, return einval(); const struct timeval *tv = optval; int64_t ms = timeval_tomillis(*tv); - if (ms >= 0xffffffffu) - ms = 0; // wait forever (default) + if (ms > -1u) + ms = 0; // wait forever (default) yes zero actually means this if (optname == SO_RCVTIMEO) fd->rcvtimeo = ms; if (optname == SO_SNDTIMEO) diff --git a/libc/sysv/consts.sh b/libc/sysv/consts.sh index 9729faccc..156699952 100755 --- a/libc/sysv/consts.sh +++ b/libc/sysv/consts.sh @@ -571,28 +571,60 @@ syscon close CLOSE_RANGE_CLOEXEC 4 4 -1 -1 -1 -1 -1 -1 # # clock_{gettime,settime} timers # +# Executive Summary +# - CLOCK_MONOTONIC shouldn't count suspended time +# - CLOCK_BOOTTIME is monotonic and should count suspended time +# - Only CLOCK_REALTIME and CLOCK_MONOTONIC can be used with futexes +# - CLOCK_MONOTONIC_RAW should fail with EINVAL if host lacks support +# - CLOCK_MONOTONIC and CLOCK_BOOTTIME should be relative to system boot time +# - COARSE can be CLK_TCK behind (~20ms) and will EINVAL on RHEL5 which isn't worth polyfilling +# +# FreeBSD defines the following rosetta stone +# Taken from freebsd/sys/compat/linux/linux_time.c +# - Linux CLOCK_MONOTONIC -> FreeBSD CLOCK_UPTIME [5] +# - Linux CLOCK_MONOTONIC_RAW -> FreeBSD CLOCK_UPTIME_FAST [8] +# - Linux CLOCK_REALTIME_COARSE -> FreeBSD CLOCK_REALTIME_FAST [10] +# - Linux CLOCK_MONOTONIC_COARSE -> FreeBSD CLOCK_UPTIME_FAST [8] +# - Linux CLOCK_BOOTTIME -> FreeBSD CLOCK_MONOTONIC [4] +# +# For MacOS we define the following mappings +# - Linux CLOCK_MONOTONIC -> MacOS CLOCK_UPTIME_RAW [8] +# - Linux CLOCK_MONOTONIC_RAW -> MacOS CLOCK_UPTIME_RAW [8] +# - Linux CLOCK_REALTIME_COARSE -> MacOS CLOCK_REALTIME [0] +# - Linux CLOCK_MONOTONIC_COARSE -> MacOS CLOCK_UPTIME_RAW_APPROX [9] +# - Linux CLOCK_BOOTTIME -> MacOS CLOCK_MONOTONIC [6] +# +# For OpenBSD we define the following mappings +# - Linux CLOCK_MONOTONIC -> OpenBSD CLOCK_UPTIME [5] +# - Linux CLOCK_MONOTONIC_RAW -> EINVAL because OpenBSD ntpd can adjfreq(2) +# - Linux CLOCK_REALTIME_COARSE -> OpenBSD CLOCK_REALTIME [0] +# - Linux CLOCK_MONOTONIC_COARSE -> OpenBSD CLOCK_UPTIME [5] +# - Linux CLOCK_BOOTTIME -> OpenBSD CLOCK_MONOTONIC [3] +# +# For NetBSD we define the following mappings +# - Linux CLOCK_MONOTONIC -> NetBSD CLOCK_MONOTONIC [3] TODO: suspend? +# - Linux CLOCK_MONOTONIC_RAW -> NetBSD CLOCK_MONOTONIC [3] NetBSD clock_gettime(2) says it isn't impacted by adjfreq(2) +# - Linux CLOCK_REALTIME_COARSE -> NetBSD CLOCK_REALTIME [0] +# - Linux CLOCK_MONOTONIC_COARSE -> NetBSD CLOCK_MONOTONIC [3] +# - Linux CLOCK_BOOTTIME -> NetBSD CLOCK_MONOTONIC [3] TODO: suspend? +# +# For Windows we define the following mappings +# - Linux CLOCK_REALTIME -> GetSystemTimePreciseAsFileTime() +# - Linux CLOCK_MONOTONIC -> QueryUnbiasedInterruptTimePrecise() +# - Linux CLOCK_MONOTONIC_RAW -> QueryUnbiasedInterruptTimePrecise() +# - Linux CLOCK_REALTIME_COARSE -> GetSystemTimeAsFileTime() +# - Linux CLOCK_MONOTONIC_COARSE -> QueryUnbiasedInterruptTime() +# - Linux CLOCK_BOOTTIME -> QueryInterruptTimePrecise() +# # group name GNU/Systemd GNU/Systemd (Aarch64) XNU's Not UNIX! MacOS (Arm64) FreeBSD OpenBSD NetBSD The New Technology Commentary -syscon clock CLOCK_REALTIME 0 0 0 0 0 0 0 0 # consensus -syscon clock CLOCK_REALTIME_PRECISE 0 0 0 0 9 0 0 0 # -syscon clock CLOCK_REALTIME_FAST 0 0 0 0 10 0 0 0 # -syscon clock CLOCK_REALTIME_COARSE 5 5 0 0 10 0 0 2 # Linux 2.6.32+; bsd consensus; not available on RHEL5 -syscon clock CLOCK_MONOTONIC 1 1 6 6 4 3 3 1 # XNU/NT faked; could move backwards if NTP introduces negative leap second -syscon clock CLOCK_MONOTONIC_RAW 4 4 4 4 4 3 3 1 # actually monotonic; not subject to NTP adjustments; Linux 2.6.28+; XNU/NT/FreeBSD/OpenBSD faked; not available on RHEL5 (will fallback to CLOCK_MONOTONIC) -syscon clock CLOCK_MONOTONIC_RAW_APPROX 4 4 5 5 4 3 3 1 # goes faster on xnu, otherwise faked -syscon clock CLOCK_MONOTONIC_PRECISE 1 1 6 6 11 3 3 1 # -syscon clock CLOCK_MONOTONIC_FAST 1 1 6 6 12 3 3 1 # -syscon clock CLOCK_MONOTONIC_COARSE 6 6 5 5 12 3 3 1 # Linux 2.6.32+; bsd consensus; not available on RHEL5 -syscon clock CLOCK_PROCESS_CPUTIME_ID 2 2 12 12 15 2 0x40000000 4 # NetBSD lets you bitwise a PID into clockid_t +syscon clock CLOCK_REALTIME 0 0 0 0 0 0 0 0 # +syscon clock CLOCK_MONOTONIC 1 1 8 8 5 5 3 1 # +syscon clock CLOCK_PROCESS_CPUTIME_ID 2 2 12 12 15 2 0x40000000 4 # syscon clock CLOCK_THREAD_CPUTIME_ID 3 3 16 16 14 4 0x20000000 5 # -syscon clock CLOCK_PROF 127 127 127 127 2 127 2 127 # -syscon clock CLOCK_BOOTTIME 7 7 7 127 127 6 127 3 # -syscon clock CLOCK_REALTIME_ALARM 8 8 127 127 127 127 127 127 # -syscon clock CLOCK_BOOTTIME_ALARM 9 9 127 127 127 127 127 127 # -syscon clock CLOCK_TAI 11 11 127 127 127 127 127 127 # -syscon clock CLOCK_UPTIME 127 127 8 8 5 5 127 127 # -syscon clock CLOCK_UPTIME_PRECISE 127 127 127 127 7 127 127 127 # -syscon clock CLOCK_UPTIME_FAST 127 127 127 127 8 127 127 127 # -syscon clock CLOCK_SECOND 127 127 127 127 13 127 127 127 # +syscon clock CLOCK_MONOTONIC_RAW 4 4 127 8 8 127 3 1 # Linux 2.6.28+ +syscon clock CLOCK_REALTIME_COARSE 5 5 0 0 10 0 0 2 # Linux 2.6.32+ +syscon clock CLOCK_MONOTONIC_COARSE 6 6 9 9 8 5 3 6 # Linux 2.6.32+ +syscon clock CLOCK_BOOTTIME 7 7 6 6 4 3 3 3 # Linux 2.6.39+ # poll() # diff --git a/libc/sysv/consts/CLOCK_BOOTTIME.S b/libc/sysv/consts/CLOCK_BOOTTIME.S index ead5f9008..966970d27 100644 --- a/libc/sysv/consts/CLOCK_BOOTTIME.S +++ b/libc/sysv/consts/CLOCK_BOOTTIME.S @@ -1,2 +1,2 @@ #include "libc/sysv/consts/syscon.internal.h" -.syscon clock,CLOCK_BOOTTIME,7,7,7,127,127,6,127,3 +.syscon clock,CLOCK_BOOTTIME,7,7,6,6,4,3,3,3 diff --git a/libc/sysv/consts/CLOCK_BOOTTIME_ALARM.S b/libc/sysv/consts/CLOCK_BOOTTIME_ALARM.S deleted file mode 100644 index 88265bcc8..000000000 --- a/libc/sysv/consts/CLOCK_BOOTTIME_ALARM.S +++ /dev/null @@ -1,2 +0,0 @@ -#include "libc/sysv/consts/syscon.internal.h" -.syscon clock,CLOCK_BOOTTIME_ALARM,9,9,127,127,127,127,127,127 diff --git a/libc/sysv/consts/CLOCK_MONOTONIC.S b/libc/sysv/consts/CLOCK_MONOTONIC.S index 2275c6cf1..66d85a317 100644 --- a/libc/sysv/consts/CLOCK_MONOTONIC.S +++ b/libc/sysv/consts/CLOCK_MONOTONIC.S @@ -1,2 +1,2 @@ #include "libc/sysv/consts/syscon.internal.h" -.syscon clock,CLOCK_MONOTONIC,1,1,6,6,4,3,3,1 +.syscon clock,CLOCK_MONOTONIC,1,1,8,8,5,5,3,1 diff --git a/libc/sysv/consts/CLOCK_MONOTONIC_COARSE.S b/libc/sysv/consts/CLOCK_MONOTONIC_COARSE.S index 225972c1d..494834f22 100644 --- a/libc/sysv/consts/CLOCK_MONOTONIC_COARSE.S +++ b/libc/sysv/consts/CLOCK_MONOTONIC_COARSE.S @@ -1,2 +1,2 @@ #include "libc/sysv/consts/syscon.internal.h" -.syscon clock,CLOCK_MONOTONIC_COARSE,6,6,5,5,12,3,3,1 +.syscon clock,CLOCK_MONOTONIC_COARSE,6,6,9,9,8,5,3,6 diff --git a/libc/sysv/consts/CLOCK_MONOTONIC_FAST.S b/libc/sysv/consts/CLOCK_MONOTONIC_FAST.S deleted file mode 100644 index 0069c82cf..000000000 --- a/libc/sysv/consts/CLOCK_MONOTONIC_FAST.S +++ /dev/null @@ -1,2 +0,0 @@ -#include "libc/sysv/consts/syscon.internal.h" -.syscon clock,CLOCK_MONOTONIC_FAST,1,1,6,6,12,3,3,1 diff --git a/libc/sysv/consts/CLOCK_MONOTONIC_PRECISE.S b/libc/sysv/consts/CLOCK_MONOTONIC_PRECISE.S deleted file mode 100644 index e9e77f345..000000000 --- a/libc/sysv/consts/CLOCK_MONOTONIC_PRECISE.S +++ /dev/null @@ -1,2 +0,0 @@ -#include "libc/sysv/consts/syscon.internal.h" -.syscon clock,CLOCK_MONOTONIC_PRECISE,1,1,6,6,11,3,3,1 diff --git a/libc/sysv/consts/CLOCK_MONOTONIC_RAW.S b/libc/sysv/consts/CLOCK_MONOTONIC_RAW.S index 133098e2f..45dcd0e7d 100644 --- a/libc/sysv/consts/CLOCK_MONOTONIC_RAW.S +++ b/libc/sysv/consts/CLOCK_MONOTONIC_RAW.S @@ -1,2 +1,2 @@ #include "libc/sysv/consts/syscon.internal.h" -.syscon clock,CLOCK_MONOTONIC_RAW,4,4,4,4,4,3,3,1 +.syscon clock,CLOCK_MONOTONIC_RAW,4,4,127,8,8,127,3,1 diff --git a/libc/sysv/consts/CLOCK_MONOTONIC_RAW_APPROX.S b/libc/sysv/consts/CLOCK_MONOTONIC_RAW_APPROX.S deleted file mode 100644 index 5f81cd8bf..000000000 --- a/libc/sysv/consts/CLOCK_MONOTONIC_RAW_APPROX.S +++ /dev/null @@ -1,2 +0,0 @@ -#include "libc/sysv/consts/syscon.internal.h" -.syscon clock,CLOCK_MONOTONIC_RAW_APPROX,4,4,5,5,4,3,3,1 diff --git a/libc/sysv/consts/CLOCK_PROF.S b/libc/sysv/consts/CLOCK_PROF.S deleted file mode 100644 index a91213a17..000000000 --- a/libc/sysv/consts/CLOCK_PROF.S +++ /dev/null @@ -1,2 +0,0 @@ -#include "libc/sysv/consts/syscon.internal.h" -.syscon clock,CLOCK_PROF,127,127,127,127,2,127,2,127 diff --git a/libc/sysv/consts/CLOCK_REALTIME_ALARM.S b/libc/sysv/consts/CLOCK_REALTIME_ALARM.S deleted file mode 100644 index 0d497e110..000000000 --- a/libc/sysv/consts/CLOCK_REALTIME_ALARM.S +++ /dev/null @@ -1,2 +0,0 @@ -#include "libc/sysv/consts/syscon.internal.h" -.syscon clock,CLOCK_REALTIME_ALARM,8,8,127,127,127,127,127,127 diff --git a/libc/sysv/consts/CLOCK_REALTIME_FAST.S b/libc/sysv/consts/CLOCK_REALTIME_FAST.S deleted file mode 100644 index fd0774e29..000000000 --- a/libc/sysv/consts/CLOCK_REALTIME_FAST.S +++ /dev/null @@ -1,2 +0,0 @@ -#include "libc/sysv/consts/syscon.internal.h" -.syscon clock,CLOCK_REALTIME_FAST,0,0,0,0,10,0,0,0 diff --git a/libc/sysv/consts/CLOCK_REALTIME_PRECISE.S b/libc/sysv/consts/CLOCK_REALTIME_PRECISE.S deleted file mode 100644 index e3ce38e79..000000000 --- a/libc/sysv/consts/CLOCK_REALTIME_PRECISE.S +++ /dev/null @@ -1,2 +0,0 @@ -#include "libc/sysv/consts/syscon.internal.h" -.syscon clock,CLOCK_REALTIME_PRECISE,0,0,0,0,9,0,0,0 diff --git a/libc/sysv/consts/CLOCK_SECOND.S b/libc/sysv/consts/CLOCK_SECOND.S deleted file mode 100644 index f39711a0c..000000000 --- a/libc/sysv/consts/CLOCK_SECOND.S +++ /dev/null @@ -1,2 +0,0 @@ -#include "libc/sysv/consts/syscon.internal.h" -.syscon clock,CLOCK_SECOND,127,127,127,127,13,127,127,127 diff --git a/libc/sysv/consts/CLOCK_TAI.S b/libc/sysv/consts/CLOCK_TAI.S deleted file mode 100644 index 041e63585..000000000 --- a/libc/sysv/consts/CLOCK_TAI.S +++ /dev/null @@ -1,2 +0,0 @@ -#include "libc/sysv/consts/syscon.internal.h" -.syscon clock,CLOCK_TAI,11,11,127,127,127,127,127,127 diff --git a/libc/sysv/consts/CLOCK_UPTIME.S b/libc/sysv/consts/CLOCK_UPTIME.S deleted file mode 100644 index 281eaa508..000000000 --- a/libc/sysv/consts/CLOCK_UPTIME.S +++ /dev/null @@ -1,2 +0,0 @@ -#include "libc/sysv/consts/syscon.internal.h" -.syscon clock,CLOCK_UPTIME,127,127,8,8,5,5,127,127 diff --git a/libc/sysv/consts/CLOCK_UPTIME_FAST.S b/libc/sysv/consts/CLOCK_UPTIME_FAST.S deleted file mode 100644 index 3d1ecfd4c..000000000 --- a/libc/sysv/consts/CLOCK_UPTIME_FAST.S +++ /dev/null @@ -1,2 +0,0 @@ -#include "libc/sysv/consts/syscon.internal.h" -.syscon clock,CLOCK_UPTIME_FAST,127,127,127,127,8,127,127,127 diff --git a/libc/sysv/consts/CLOCK_UPTIME_PRECISE.S b/libc/sysv/consts/CLOCK_UPTIME_PRECISE.S deleted file mode 100644 index 581afe2dd..000000000 --- a/libc/sysv/consts/CLOCK_UPTIME_PRECISE.S +++ /dev/null @@ -1,2 +0,0 @@ -#include "libc/sysv/consts/syscon.internal.h" -.syscon clock,CLOCK_UPTIME_PRECISE,127,127,127,127,7,127,127,127 diff --git a/libc/sysv/consts/clock.h b/libc/sysv/consts/clock.h index 8aa3b7b81..eefa79217 100644 --- a/libc/sysv/consts/clock.h +++ b/libc/sysv/consts/clock.h @@ -2,42 +2,26 @@ #define COSMOPOLITAN_LIBC_SYSV_CONSTS_CLOCK_H_ COSMOPOLITAN_C_START_ -extern const int CLOCK_BOOTTIME; -extern const int CLOCK_BOOTTIME_ALARM; +extern int CLOCK_REALTIME_COARSE; extern const int CLOCK_MONOTONIC; -extern const int CLOCK_MONOTONIC_COARSE; -extern const int CLOCK_MONOTONIC_FAST; -extern const int CLOCK_MONOTONIC_PRECISE; extern int CLOCK_MONOTONIC_RAW; -extern int CLOCK_MONOTONIC_RAW_APPROX; -extern const int CLOCK_PROCESS_CPUTIME_ID; -extern const int CLOCK_PROF; -extern const int CLOCK_REALTIME_ALARM; -extern const int CLOCK_REALTIME_COARSE; -extern const int CLOCK_REALTIME_FAST; -extern const int CLOCK_REALTIME_PRECISE; -extern const int CLOCK_SECOND; -extern const int CLOCK_TAI; +extern int CLOCK_MONOTONIC_COARSE; extern const int CLOCK_THREAD_CPUTIME_ID; -extern const int CLOCK_UPTIME; -extern const int CLOCK_UPTIME_FAST; -extern const int CLOCK_UPTIME_PRECISE; +extern const int CLOCK_PROCESS_CPUTIME_ID; +extern const int CLOCK_BOOTTIME; COSMOPOLITAN_C_END_ -#define CLOCK_REALTIME 0 -#define CLOCK_REALTIME_FAST CLOCK_REALTIME_FAST -#define CLOCK_REALTIME_PRECISE CLOCK_REALTIME_PRECISE -#define CLOCK_REALTIME_COARSE CLOCK_REALTIME_COARSE +#define CLOCK_REALTIME 0 +#define CLOCK_REALTIME_COARSE CLOCK_REALTIME_COARSE -#define CLOCK_MONOTONIC CLOCK_MONOTONIC -#define CLOCK_MONOTONIC_RAW CLOCK_MONOTONIC_RAW -#define CLOCK_MONOTONIC_RAW_APPROX CLOCK_MONOTONIC_RAW_APPROX -#define CLOCK_MONOTONIC_FAST CLOCK_MONOTONIC_FAST -#define CLOCK_MONOTONIC_PRECISE CLOCK_MONOTONIC_PRECISE -#define CLOCK_MONOTONIC_COARSE CLOCK_MONOTONIC_COARSE +#define CLOCK_MONOTONIC CLOCK_MONOTONIC +#define CLOCK_MONOTONIC_RAW CLOCK_MONOTONIC_RAW +#define CLOCK_MONOTONIC_COARSE CLOCK_MONOTONIC_COARSE #define CLOCK_THREAD_CPUTIME_ID CLOCK_THREAD_CPUTIME_ID #define CLOCK_PROCESS_CPUTIME_ID CLOCK_PROCESS_CPUTIME_ID +#define CLOCK_BOOTTIME CLOCK_BOOTTIME + #endif /* COSMOPOLITAN_LIBC_SYSV_CONSTS_CLOCK_H_ */ diff --git a/libc/thread/pthread_condattr_getclock.c b/libc/thread/pthread_condattr_getclock.c index 8e0616e9c..3cb9b22d5 100644 --- a/libc/thread/pthread_condattr_getclock.c +++ b/libc/thread/pthread_condattr_getclock.c @@ -24,6 +24,8 @@ * @param clock will be set to one of * - `CLOCK_REALTIME` (default) * - `CLOCK_MONOTONIC` + * - `CLOCK_REALTIME_COARSE` + * - `CLOCK_MONOTONIC_COARSE` * @return 0 on success, or error on failure */ int pthread_condattr_getclock(const pthread_condattr_t *attr, int *clock) { diff --git a/libc/thread/pthread_condattr_setclock.c b/libc/thread/pthread_condattr_setclock.c index 232267ef5..7d5176b02 100644 --- a/libc/thread/pthread_condattr_setclock.c +++ b/libc/thread/pthread_condattr_setclock.c @@ -26,12 +26,16 @@ * @param clock can be one of * - `CLOCK_REALTIME` (default) * - `CLOCK_MONOTONIC` + * - `CLOCK_REALTIME_COARSE` + * - `CLOCK_MONOTONIC_COARSE` * @return 0 on success, or error on failure * @raises EINVAL if `clock` is invalid */ int pthread_condattr_setclock(pthread_condattr_t *attr, int clock) { - if (clock != CLOCK_REALTIME && // - clock != CLOCK_MONOTONIC) + if (clock != CLOCK_REALTIME && // + clock != CLOCK_REALTIME_COARSE && // + clock != CLOCK_MONOTONIC && // + clock != CLOCK_MONOTONIC_COARSE) return EINVAL; attr->_clock = clock; return 0; diff --git a/libc/thread/pthread_detach.c b/libc/thread/pthread_detach.c index da41ee352..5e9db049a 100644 --- a/libc/thread/pthread_detach.c +++ b/libc/thread/pthread_detach.c @@ -28,8 +28,8 @@ static errno_t pthread_detach_impl(struct PosixThread *pt) { enum PosixThreadStatus status, transition; + status = atomic_load_explicit(&pt->pt_status, memory_order_relaxed); for (;;) { - status = atomic_load_explicit(&pt->pt_status, memory_order_acquire); if (status == kPosixThreadJoinable) { transition = kPosixThreadDetached; } else if (status == kPosixThreadTerminated) { @@ -50,10 +50,6 @@ static errno_t pthread_detach_impl(struct PosixThread *pt) { /** * Asks POSIX thread to free itself automatically upon termination. * - * If this function is used, then it's important to use pthread_exit() - * rather than exit() since otherwise your program isn't guaranteed to - * gracefully terminate. - * * Detaching a non-joinable thread is undefined behavior. For example, * pthread_detach() can't be called twice on the same thread. * @@ -64,7 +60,10 @@ static errno_t pthread_detach_impl(struct PosixThread *pt) { errno_t pthread_detach(pthread_t thread) { unassert(thread); struct PosixThread *pt = (struct PosixThread *)thread; + _pthread_ref(pt); + int tid = _pthread_tid(pt); errno_t err = pthread_detach_impl(pt); - STRACE("pthread_detach(%d) → %s", _pthread_tid(pt), DescribeErrno(err)); + _pthread_unref(pt); + STRACE("pthread_detach(%d) → %s", tid, DescribeErrno(err)); return err; } diff --git a/libc/thread/pthread_timedjoin_np.c b/libc/thread/pthread_timedjoin_np.c index 2ba356567..9199f2e53 100644 --- a/libc/thread/pthread_timedjoin_np.c +++ b/libc/thread/pthread_timedjoin_np.c @@ -121,6 +121,7 @@ errno_t pthread_timedjoin_np(pthread_t thread, void **value_ptr, enum PosixThreadStatus status; pt = (struct PosixThread *)thread; unassert(thread); + _pthread_ref(pt); // "The behavior is undefined if the value specified by the thread // argument to pthread_join() does not refer to a joinable thread." @@ -140,6 +141,7 @@ errno_t pthread_timedjoin_np(pthread_t thread, void **value_ptr, *value_ptr = pt->pt_rc; } + _pthread_unref(pt); STRACE("pthread_timedjoin_np(%d, %s, %s) → %s", tid, DescribeReturnValue(alloca(30), err, value_ptr), DescribeTimespec(err ? -1 : 0, abstime), DescribeErrno(err)); diff --git a/libc/thread/ualarm.c b/libc/thread/ualarm.c index 625199c8a..db23b3877 100644 --- a/libc/thread/ualarm.c +++ b/libc/thread/ualarm.c @@ -20,6 +20,7 @@ #include "libc/calls/calls.h" #include "libc/calls/struct/itimerval.h" #include "libc/calls/struct/timeval.h" +#include "libc/stdio/sysparam.h" #include "libc/sysv/consts/itimer.h" /** @@ -36,5 +37,6 @@ unsigned ualarm(unsigned usecs, unsigned reload) { it.it_value = timeval_frommicros(usecs); it.it_interval = timeval_frommicros(reload); npassert(!setitimer(ITIMER_REAL, &it, &old)); - return timeval_tomicros(old.it_value); + int64_t us = timeval_tomicros(old.it_value); + return MIN(us, -1u); } diff --git a/test/libc/calls/clock_getres_test.c b/test/libc/calls/clock_getres_test.c index ad296e319..27aa3a447 100644 --- a/test/libc/calls/clock_getres_test.c +++ b/test/libc/calls/clock_getres_test.c @@ -32,13 +32,6 @@ TEST(clock_getres, realtimeHasMillisecondPrecisionOrBetter) { EXPECT_GT(ts.tv_nsec, 0); } -TEST(clock_getres, realtimeFastHasMillisecondPrecisionOrBetter) { - ASSERT_EQ(0, clock_getres(CLOCK_REALTIME_FAST, &ts)); - EXPECT_EQ(0, ts.tv_sec); - EXPECT_LT(ts.tv_nsec, 1000000); - EXPECT_GT(ts.tv_nsec, 0); -} - TEST(clock_getres, realtimeCoarseHasMillisecondPrecisionOrBetter) { if (clock_getres(CLOCK_REALTIME_COARSE, &ts)) return; @@ -47,14 +40,6 @@ TEST(clock_getres, realtimeCoarseHasMillisecondPrecisionOrBetter) { EXPECT_GT(ts.tv_nsec, 0); } -TEST(clock_getres, realtimePreciseHasMillisecondPrecisionOrBetter) { - if (clock_getres(CLOCK_REALTIME_PRECISE, &ts)) - return; - EXPECT_EQ(0, ts.tv_sec); - EXPECT_LT(ts.tv_nsec, 100000000); - EXPECT_GT(ts.tv_nsec, 0); -} - TEST(clock_getres, monotonicHasMillisecondPrecisionOrBetter) { ASSERT_EQ(0, clock_getres(CLOCK_MONOTONIC, &ts)); EXPECT_EQ(0, ts.tv_sec); @@ -62,13 +47,6 @@ TEST(clock_getres, monotonicHasMillisecondPrecisionOrBetter) { EXPECT_GT(ts.tv_nsec, 0); } -TEST(clock_getres, monotonicFastHasMillisecondPrecisionOrBetter) { - ASSERT_EQ(0, clock_getres(CLOCK_MONOTONIC_FAST, &ts)); - EXPECT_EQ(0, ts.tv_sec); - EXPECT_LT(ts.tv_nsec, 1000000); - EXPECT_GT(ts.tv_nsec, 0); -} - TEST(clock_getres, monotonicCoarseHasMillisecondPrecisionOrBetter) { if (clock_getres(CLOCK_MONOTONIC_COARSE, &ts)) return; @@ -76,11 +54,3 @@ TEST(clock_getres, monotonicCoarseHasMillisecondPrecisionOrBetter) { EXPECT_LT(ts.tv_nsec, 100000000); EXPECT_GT(ts.tv_nsec, 0); } - -TEST(clock_getres, monotonicPreciseHasMillisecondPrecisionOrBetter) { - if (clock_getres(CLOCK_MONOTONIC_PRECISE, &ts)) - return; - EXPECT_EQ(0, ts.tv_sec); - EXPECT_LT(ts.tv_nsec, 100000000); - EXPECT_GT(ts.tv_nsec, 0); -} diff --git a/test/libc/calls/clock_gettime_test.c b/test/libc/calls/clock_gettime_test.c index c86a92abf..4c76c4d8a 100644 --- a/test/libc/calls/clock_gettime_test.c +++ b/test/libc/calls/clock_gettime_test.c @@ -16,20 +16,13 @@ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ -#include "libc/calls/internal.h" #include "libc/calls/struct/timespec.h" -#include "libc/calls/struct/timespec.internal.h" #include "libc/calls/struct/timeval.h" -#include "libc/calls/syscall_support-sysv.internal.h" -#include "libc/dce.h" #include "libc/errno.h" -#include "libc/nexgen32e/rdtsc.h" -#include "libc/runtime/runtime.h" -#include "libc/sysv/consts/auxv.h" +#include "libc/macros.h" #include "libc/sysv/consts/clock.h" -#include "libc/testlib/ezbench.h" +#include "libc/testlib/benchmark.h" #include "libc/testlib/testlib.h" -#include "libc/time.h" TEST(clock_gettime, nullResult_validatesClockParam) { ASSERT_SYS(EINVAL, -1, clock_gettime(666, 0)); @@ -51,26 +44,19 @@ TEST(clock_gettime, testClockRealtime) { } TEST(clock_gettime, bench) { - struct timeval tv; struct timespec ts; - gettimeofday(&tv, 0); // trigger init - clock_gettime(0, &ts); // trigger init - EZBENCH2("rdtsc", donothing, rdtsc()); - EZBENCH2("clock_gettime(mono)", donothing, - clock_gettime(CLOCK_MONOTONIC_FAST, &ts)); - EZBENCH2("clock_gettime(real)", donothing, - clock_gettime(CLOCK_REALTIME_FAST, &ts)); - EZBENCH2("timespec_real", donothing, timespec_real()); - EZBENCH2("gettimeofday", donothing, gettimeofday(&tv, 0)); - if (IsWindows()) { - EZBENCH2("sys_clock_gettime r", donothing, - sys_clock_gettime_nt(CLOCK_REALTIME_FAST, &ts)); - EZBENCH2("sys_clock_gettime m", donothing, - sys_clock_gettime_nt(CLOCK_MONOTONIC_FAST, &ts)); - } else { - EZBENCH2("sys_clock_gettime r", donothing, - sys_clock_gettime(CLOCK_REALTIME_FAST, &ts)); - EZBENCH2("sys_clock_gettime m", donothing, - sys_clock_gettime(CLOCK_MONOTONIC_FAST, &ts)); - } + BENCHMARK(1, 1, timespec_real()); + BENCHMARK(1000, 1, timespec_real()); + if (!clock_gettime(CLOCK_REALTIME, 0)) + BENCHMARK(1000, 1, clock_gettime(CLOCK_REALTIME, &ts)); + if (!clock_gettime(CLOCK_REALTIME_COARSE, 0)) + BENCHMARK(1000, 1, clock_gettime(CLOCK_REALTIME_COARSE, &ts)); + if (!clock_gettime(CLOCK_MONOTONIC, 0)) + BENCHMARK(1000, 1, clock_gettime(CLOCK_MONOTONIC, &ts)); + if (!clock_gettime(CLOCK_MONOTONIC_COARSE, 0)) + BENCHMARK(1000, 1, clock_gettime(CLOCK_MONOTONIC_COARSE, &ts)); + if (!clock_gettime(CLOCK_MONOTONIC_RAW, 0)) + BENCHMARK(1000, 1, clock_gettime(CLOCK_MONOTONIC_RAW, &ts)); + if (!clock_gettime(CLOCK_BOOTTIME, 0)) + BENCHMARK(1000, 1, clock_gettime(CLOCK_BOOTTIME, &ts)); } diff --git a/third_party/nsync/BUILD.mk b/third_party/nsync/BUILD.mk index 7576efeab..b2e545c38 100644 --- a/third_party/nsync/BUILD.mk +++ b/third_party/nsync/BUILD.mk @@ -76,4 +76,5 @@ $(THIRD_PARTY_NSYNC_OBJS): third_party/nsync/BUILD.mk .PHONY: o/$(MODE)/third_party/nsync o/$(MODE)/third_party/nsync: \ o/$(MODE)/third_party/nsync/mem \ + o/$(MODE)/third_party/nsync/testing \ $(THIRD_PARTY_NSYNC_CHECKS) diff --git a/third_party/nsync/common.c b/third_party/nsync/common.c index 31f7519e4..6daf2b8c1 100644 --- a/third_party/nsync/common.c +++ b/third_party/nsync/common.c @@ -180,7 +180,7 @@ static waiter *free_waiters_pop (void) { static void free_waiters_populate (void) { int n; - if (IsNetbsd () || (NSYNC_USE_GRAND_CENTRAL && IsXnuSilicon ())) { + if (IsNetbsd ()) { // netbsd needs a real file descriptor per semaphore // tim cook wants us to use his lol central dispatch n = 1; diff --git a/third_party/nsync/common.internal.h b/third_party/nsync/common.internal.h index ebc1a7d64..43b8b3c48 100644 --- a/third_party/nsync/common.internal.h +++ b/third_party/nsync/common.internal.h @@ -246,6 +246,7 @@ void nsync_waiter_free_(waiter *w); discipline. */ struct nsync_note_s_ { struct Dll parent_child_link; /* parent's children, under parent->note_mu */ + int clock; /* system clock that should be used */ int expiry_time_valid; /* whether expiry_time is valid; r/o after init */ nsync_time expiry_time; /* expiry time, if expiry_time_valid != 0; r/o after init */ diff --git a/third_party/nsync/compat.S b/third_party/nsync/compat.S index 4d8f39d4d..5d8b382cc 100644 --- a/third_party/nsync/compat.S +++ b/third_party/nsync/compat.S @@ -19,10 +19,6 @@ #include "libc/calls/struct/timespec.h" #include "libc/macros.h" -nsync_time_now: - jmp timespec_real - .endfn nsync_time_now,globl - nsync_time_add: jmp timespec_add .endfn nsync_time_add,globl diff --git a/third_party/nsync/counter.h b/third_party/nsync/counter.h index 227fa4333..8b99335bc 100644 --- a/third_party/nsync/counter.h +++ b/third_party/nsync/counter.h @@ -33,7 +33,7 @@ uint32_t nsync_counter_value(nsync_counter c); a waiter may have been woken due to the counter reaching zero. If abs_deadline==nsync_time_no_deadline, the deadline is far in the future. */ -uint32_t nsync_counter_wait(nsync_counter c, nsync_time abs_deadline); +uint32_t nsync_counter_wait(nsync_counter c, int clock, nsync_time abs_deadline); COSMOPOLITAN_C_END_ #endif /* NSYNC_COUNTER_H_ */ diff --git a/third_party/nsync/futex.c b/third_party/nsync/futex.c index 7f3d63da8..dc550276c 100644 --- a/third_party/nsync/futex.c +++ b/third_party/nsync/futex.c @@ -41,7 +41,6 @@ #include "libc/nt/runtime.h" #include "libc/nt/synchronization.h" #include "libc/runtime/clktck.h" -#include "libc/sysv/consts/clock.h" #include "libc/sysv/consts/sicode.h" #include "libc/sysv/consts/timer.h" #include "libc/sysv/errfuns.h" @@ -50,6 +49,7 @@ #include "libc/thread/thread.h" #include "libc/thread/tls.h" #include "third_party/nsync/atomic.h" +#include "third_party/nsync/time.h" #include "third_party/nsync/common.internal.h" #include "third_party/nsync/futex.internal.h" #include "third_party/nsync/time.h" @@ -92,7 +92,7 @@ static void nsync_futex_init_ (void) { return; } - if (!(nsync_futex_.is_supported = IsLinux () || IsOpenbsd ())) + if (!(nsync_futex_.is_supported = IsLinux () || IsOpenbsd ())) return; // In our testing, we found that the monotonic clock on various @@ -126,6 +126,12 @@ static void nsync_futex_init_ (void) { errno = e; } +static uint32_t nsync_time_64to32u (uint64_t duration) { + if (duration <= -1u) + return duration; + return -1u; +} + static int nsync_futex_polyfill_ (atomic_int *w, int expect, int clock, struct timespec *abstime) { for (;;) { if (atomic_load_explicit (w, memory_order_acquire) != expect) @@ -177,7 +183,7 @@ static int nsync_futex_wait_win32_ (atomic_int *w, int expect, char pshare, pt->pt_blkmask = waitmask; atomic_store_explicit (&pt->pt_blocker, w, memory_order_release); } - ok = WaitOnAddress (w, &expect, sizeof(int), timespec_tomillis (wait)); + ok = WaitOnAddress (w, &expect, sizeof(int), nsync_time_64to32u (timespec_tomillis (wait))); if (pt) { /* __sig_cancel wakes our futex without changing `w` after enqueing signals */ atomic_store_explicit (&pt->pt_blocker, 0, memory_order_release); @@ -232,7 +238,8 @@ int nsync_futex_wait_ (atomic_int *w, int expect, char pshare, op = nsync_futex_.FUTEX_WAIT_; if (pshare == PTHREAD_PROCESS_PRIVATE) op |= nsync_futex_.FUTEX_PRIVATE_FLAG_; - if (clock == CLOCK_REALTIME) + if (clock == CLOCK_REALTIME || + clock == CLOCK_REALTIME_COARSE) op |= nsync_futex_.FUTEX_CLOCK_REALTIME_; if (abstime && timespec_cmp (*abstime, timespec_zero) <= 0) { @@ -265,6 +272,20 @@ int nsync_futex_wait_ (atomic_int *w, int expect, char pshare, rc = nsync_futex_wait_win32_ (w, expect, pshare, clock, timeout, pt, m); __sig_unblock (m); } else if (IsXnu ()) { + + /* XNU ulock (used by cosmo futexes) is an internal API, however: + + 1. Unlike GCD it's cancelable i.e. can be EINTR'd by signals + 2. We have no choice but to use ulock for joining threads + 3. Grand Central Dispatch requires a busy loop workaround + 4. ulock makes our mutexes use 20% more system time (meh) + 5. ulock makes our mutexes use 40% less wall time (good) + 6. ulock makes our mutexes use 64% less user time (woop) + 7. GCD uses Mach timestamps D: ulock just uses rel. time + + ulock is an outstanding system call that must be used. + gcd is not an acceptable alternative to ulock. */ + uint32_t op, us; if (pshare) { op = UL_COMPARE_AND_WAIT_SHARED; @@ -272,7 +293,7 @@ int nsync_futex_wait_ (atomic_int *w, int expect, char pshare, op = UL_COMPARE_AND_WAIT; } if (timeout) { - us = timespec_tomicros (*timeout); + us = nsync_time_64to32u (timespec_tomicros (*timeout)); } else { us = -1u; } diff --git a/third_party/nsync/mem/nsync_counter.c b/third_party/nsync/mem/nsync_counter.c index d8b58841b..0eccec105 100644 --- a/third_party/nsync/mem/nsync_counter.c +++ b/third_party/nsync/mem/nsync_counter.c @@ -19,13 +19,13 @@ #include "libc/mem/mem.h" #include "libc/str/str.h" #include "third_party/nsync/atomic.h" +#include "third_party/nsync/time.h" #include "third_party/nsync/atomic.internal.h" #include "third_party/nsync/common.internal.h" #include "third_party/nsync/counter.h" #include "third_party/nsync/mu_semaphore.h" #include "third_party/nsync/races.internal.h" #include "third_party/nsync/wait_s.internal.h" -#include "libc/sysv/consts/clock.h" #include "third_party/nsync/waiter.h" __static_yoink("nsync_notice"); @@ -95,13 +95,13 @@ uint32_t nsync_counter_value (nsync_counter c) { return (result); } -uint32_t nsync_counter_wait (nsync_counter c, nsync_time abs_deadline) { +uint32_t nsync_counter_wait (nsync_counter c, int clock, nsync_time abs_deadline) { struct nsync_waitable_s waitable; struct nsync_waitable_s *pwaitable = &waitable; uint32_t result = 0; waitable.v = c; waitable.funcs = &nsync_counter_waitable_funcs; - if (nsync_wait_n (NULL, NULL, NULL, CLOCK_REALTIME, abs_deadline, 1, &pwaitable) != 0) { + if (nsync_wait_n (NULL, NULL, NULL, clock, abs_deadline, 1, &pwaitable) != 0) { IGNORE_RACES_START (); result = ATM_LOAD_ACQ (&c->value); IGNORE_RACES_END (); diff --git a/third_party/nsync/mem/nsync_note.c b/third_party/nsync/mem/nsync_note.c index a4349f28e..6b68b164a 100644 --- a/third_party/nsync/mem/nsync_note.c +++ b/third_party/nsync/mem/nsync_note.c @@ -19,12 +19,12 @@ #include "libc/mem/mem.h" #include "libc/str/str.h" #include "third_party/nsync/atomic.h" +#include "third_party/nsync/time.h" #include "third_party/nsync/common.internal.h" #include "third_party/nsync/mu_semaphore.h" #include "third_party/nsync/mu_wait.h" #include "third_party/nsync/races.internal.h" #include "third_party/nsync/wait_s.internal.h" -#include "libc/sysv/consts/clock.h" #include "third_party/nsync/waiter.h" __static_yoink("nsync_notice"); @@ -152,7 +152,7 @@ nsync_time nsync_note_notified_deadline_ (nsync_note n) { ntime = NOTIFIED_TIME (n); nsync_mu_unlock (&n->note_mu); if (nsync_time_cmp (ntime, nsync_time_zero) > 0) { - if (nsync_time_cmp (ntime, nsync_time_now ()) <= 0) { + if (nsync_time_cmp (ntime, nsync_time_now (n->clock)) <= 0) { notify (n); ntime = nsync_time_zero; } @@ -169,11 +169,12 @@ int nsync_note_is_notified (nsync_note n) { return (result); } -nsync_note nsync_note_new (nsync_note parent, +nsync_note nsync_note_new (nsync_note parent, int clock, nsync_time abs_deadline) { nsync_note n = (nsync_note) malloc (sizeof (*n)); if (n != NULL) { bzero (n, sizeof (*n)); + n->clock = clock; dll_init (&n->parent_child_link); set_expiry_time (n, abs_deadline); if (!nsync_note_is_notified (n) && parent != NULL) { @@ -248,7 +249,7 @@ int nsync_note_wait (nsync_note n, nsync_time abs_deadline) { struct nsync_waitable_s *pwaitable = &waitable; waitable.v = n; waitable.funcs = &nsync_note_waitable_funcs; - return (nsync_wait_n (NULL, NULL, NULL, CLOCK_REALTIME, abs_deadline, 1, &pwaitable) == 0); + return (nsync_wait_n (NULL, NULL, NULL, n->clock, abs_deadline, 1, &pwaitable) == 0); } nsync_time nsync_note_expiry (nsync_note n) { diff --git a/third_party/nsync/mem/nsync_once.c b/third_party/nsync/mem/nsync_once.c index 780be803a..5f355dc7a 100644 --- a/third_party/nsync/mem/nsync_once.c +++ b/third_party/nsync/mem/nsync_once.c @@ -17,12 +17,12 @@ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "third_party/nsync/atomic.h" #include "third_party/nsync/atomic.internal.h" +#include "third_party/nsync/time.h" #include "third_party/nsync/common.internal.h" #include "third_party/nsync/mu_semaphore.h" #include "third_party/nsync/once.h" #include "third_party/nsync/races.internal.h" #include "libc/thread/thread.h" -#include "libc/sysv/consts/clock.h" #include "third_party/nsync/wait_s.internal.h" __static_yoink("nsync_notice"); @@ -91,8 +91,8 @@ static void nsync_run_once_impl (nsync_once *once, struct once_sync_s *s, if (attempts < 50) { attempts += 10; } - deadline = nsync_time_add (nsync_time_now (), nsync_time_ms (attempts)); - nsync_cv_wait_with_deadline (&s->once_cv, &s->once_mu, CLOCK_REALTIME, deadline, NULL); + deadline = nsync_time_add (nsync_time_now (NSYNC_CLOCK), nsync_time_ms (attempts)); + nsync_cv_wait_with_deadline (&s->once_cv, &s->once_mu, NSYNC_CLOCK, deadline, NULL); } else { attempts = pthread_delay_np (once, attempts); } diff --git a/third_party/nsync/mu_semaphore.c b/third_party/nsync/mu_semaphore.c index 1ab8951af..b3eb68255 100644 --- a/third_party/nsync/mu_semaphore.c +++ b/third_party/nsync/mu_semaphore.c @@ -15,17 +15,15 @@ │ See the License for the specific language governing permissions and │ │ limitations under the License. │ ╚─────────────────────────────────────────────────────────────────────────────*/ -#include "third_party/nsync/mu_semaphore.h" +#include "third_party/nsync/mu_semaphore.internal.h" #include "libc/calls/cp.internal.h" #include "libc/dce.h" -#include "third_party/nsync/mu_semaphore.internal.h" +#include "third_party/nsync/mu_semaphore.h" __static_yoink("nsync_notice"); /* Initialize *s; the initial value is 0. */ bool nsync_mu_semaphore_init (nsync_semaphore *s) { - if (NSYNC_USE_GRAND_CENTRAL && IsXnuSilicon ()) { - return nsync_mu_semaphore_init_gcd (s); - } else if (IsNetbsd ()) { + if (IsNetbsd ()) { return nsync_mu_semaphore_init_sem (s); } else { return nsync_mu_semaphore_init_futex (s); @@ -39,9 +37,7 @@ bool nsync_mu_semaphore_init (nsync_semaphore *s) { errno_t nsync_mu_semaphore_p (nsync_semaphore *s) { errno_t err; BEGIN_CANCELATION_POINT; - if (NSYNC_USE_GRAND_CENTRAL && IsXnuSilicon ()) { - err = nsync_mu_semaphore_p_gcd (s); - } else if (IsNetbsd ()) { + if (IsNetbsd ()) { err = nsync_mu_semaphore_p_sem (s); } else { err = nsync_mu_semaphore_p_futex (s); @@ -57,9 +53,7 @@ errno_t nsync_mu_semaphore_p (nsync_semaphore *s) { errno_t nsync_mu_semaphore_p_with_deadline (nsync_semaphore *s, int clock, nsync_time abs_deadline) { errno_t err; BEGIN_CANCELATION_POINT; - if (NSYNC_USE_GRAND_CENTRAL && IsXnuSilicon ()) { - err = nsync_mu_semaphore_p_with_deadline_gcd (s, clock, abs_deadline); - } else if (IsNetbsd ()) { + if (IsNetbsd ()) { err = nsync_mu_semaphore_p_with_deadline_sem (s, clock, abs_deadline); } else { err = nsync_mu_semaphore_p_with_deadline_futex (s, clock, abs_deadline); @@ -70,9 +64,7 @@ errno_t nsync_mu_semaphore_p_with_deadline (nsync_semaphore *s, int clock, nsync /* Ensure that the count of *s is at least 1. */ void nsync_mu_semaphore_v (nsync_semaphore *s) { - if (NSYNC_USE_GRAND_CENTRAL && IsXnuSilicon ()) { - return nsync_mu_semaphore_v_gcd (s); - } else if (IsNetbsd ()) { + if (IsNetbsd ()) { return nsync_mu_semaphore_v_sem (s); } else { return nsync_mu_semaphore_v_futex (s); diff --git a/third_party/nsync/mu_semaphore.internal.h b/third_party/nsync/mu_semaphore.internal.h index b74291223..6d8167d78 100755 --- a/third_party/nsync/mu_semaphore.internal.h +++ b/third_party/nsync/mu_semaphore.internal.h @@ -4,20 +4,6 @@ #include "third_party/nsync/time.h" COSMOPOLITAN_C_START_ -/* XNU ulock (used by cosmo futexes) is an internal API, however: - - 1. Unlike GCD it's cancelable i.e. can be EINTR'd by signals - 2. We have no choice but to use ulock for joining threads - 3. Grand Central Dispatch requires a busy loop workaround - 4. ulock makes our mutexes use 20% more system time (meh) - 5. ulock makes our mutexes use 40% less wall time (good) - 6. ulock makes our mutexes use 64% less user time (woop) - - ulock is an outstanding system call that must be used. - gcd is not an acceptable alternative to ulock. */ - -#define NSYNC_USE_GRAND_CENTRAL 0 - bool nsync_mu_semaphore_init_futex(nsync_semaphore *); errno_t nsync_mu_semaphore_p_futex(nsync_semaphore *); errno_t nsync_mu_semaphore_p_with_deadline_futex(nsync_semaphore *, int, nsync_time); diff --git a/third_party/nsync/mu_semaphore_gcd.c b/third_party/nsync/mu_semaphore_gcd.c deleted file mode 100644 index c8722adfe..000000000 --- a/third_party/nsync/mu_semaphore_gcd.c +++ /dev/null @@ -1,143 +0,0 @@ -/*-*- mode:c;indent-tabs-mode:t;c-basic-offset:8;tab-width:8;coding:utf-8 -*-│ -│ vi: set noet ft=c ts=8 sw=8 fenc=utf-8 :vi │ -╞══════════════════════════════════════════════════════════════════════════════╡ -│ Copyright 2016 Google Inc. │ -│ │ -│ Licensed under the Apache License, Version 2.0 (the "License"); │ -│ you may not use this file except in compliance with the License. │ -│ You may obtain a copy of the License at │ -│ │ -│ http://www.apache.org/licenses/LICENSE-2.0 │ -│ │ -│ Unless required by applicable law or agreed to in writing, software │ -│ distributed under the License is distributed on an "AS IS" BASIS, │ -│ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. │ -│ See the License for the specific language governing permissions and │ -│ limitations under the License. │ -╚─────────────────────────────────────────────────────────────────────────────*/ -#include "libc/assert.h" -#include "libc/calls/sig.internal.h" -#include "libc/errno.h" -#include "libc/intrin/strace.h" -#include "libc/intrin/weaken.h" -#include "libc/runtime/clktck.h" -#include "libc/runtime/syslib.internal.h" -#include "libc/str/str.h" -#include "libc/thread/posixthread.internal.h" -#include "libc/thread/thread.h" -#include "libc/thread/tls.h" -#include "third_party/nsync/atomic.h" -#include "third_party/nsync/atomic.internal.h" -#include "third_party/nsync/futex.internal.h" -#include "third_party/nsync/mu_semaphore.internal.h" -#include "third_party/nsync/time.h" - -/** - * @fileoverview Semaphores w/ Apple's Grand Central Dispatch API. - */ - -#define DISPATCH_TIME_FOREVER ~0ull - -static dispatch_semaphore_t dispatch_semaphore_create(long count) { - dispatch_semaphore_t ds; - ds = __syslib->__dispatch_semaphore_create (count); - STRACE ("dispatch_semaphore_create(%ld) → %#lx", count, ds); - return (ds); -} - -static void dispatch_release (dispatch_semaphore_t ds) { - __syslib->__dispatch_release (ds); - STRACE ("dispatch_release(%#lx)", ds); -} - -static long dispatch_semaphore_wait (dispatch_semaphore_t ds, - dispatch_time_t dt) { - long rc = __syslib->__dispatch_semaphore_wait (ds, dt); - STRACE ("dispatch_semaphore_wait(%#lx, %ld) → %ld", ds, dt, rc); - return (rc); -} - -static long dispatch_semaphore_signal (dispatch_semaphore_t ds) { - long rc = __syslib->__dispatch_semaphore_signal (ds); - (void)rc; - STRACE ("dispatch_semaphore_signal(%#lx) → %ld", ds, rc); - return (ds); -} - -static dispatch_time_t dispatch_walltime (const struct timespec *base, - int64_t offset) { - return __syslib->__dispatch_walltime (base, offset); -} - -static errno_t nsync_dispatch_semaphore_wait (nsync_semaphore *s, - nsync_time abs_deadline) { - errno_t result = 0; - dispatch_time_t dt; - if (nsync_time_cmp (abs_deadline, nsync_time_no_deadline) == 0) { - dt = DISPATCH_TIME_FOREVER; - } else { - dt = dispatch_walltime (&abs_deadline, 0); - } - if (dispatch_semaphore_wait (*(dispatch_semaphore_t *)s, dt) != 0) { - result = ETIMEDOUT; - } - return (result); -} - -/* Initialize *s; the initial value is 0. */ -bool nsync_mu_semaphore_init_gcd (nsync_semaphore *s) { - return !!(*(dispatch_semaphore_t *)s = dispatch_semaphore_create (0)); -} - -/* Wait until the count of *s exceeds 0, and decrement it. If POSIX cancellations - are currently disabled by the thread, then this function always succeeds. When - they're enabled in MASKED mode, this function may return ECANCELED. Otherwise, - cancellation will occur by unwinding cleanup handlers pushed to the stack. */ -errno_t nsync_mu_semaphore_p_gcd (nsync_semaphore *s) { - return nsync_mu_semaphore_p_with_deadline_gcd (s, 0, nsync_time_no_deadline); -} - -/* Like nsync_mu_semaphore_p() this waits for the count of *s to exceed 0, - while additionally supporting a time parameter specifying at what point - in the future ETIMEDOUT should be returned, if neither cancellation, or - semaphore release happens. */ -errno_t nsync_mu_semaphore_p_with_deadline_gcd (nsync_semaphore *s, int clock, - nsync_time abs_deadline) { - errno_t result = 0; - struct PosixThread *pt; - if (!__tls_enabled || - !_weaken (pthread_testcancel_np) || - !(pt = _pthread_self()) || - (pt->pt_flags & PT_NOCANCEL)) { - result = nsync_dispatch_semaphore_wait (s, abs_deadline); - } else { - struct timespec now, until, slice = {0, 1000000000 / CLK_TCK}; - for (;;) { - if (_weaken (pthread_testcancel_np) () == ECANCELED) { - result = ECANCELED; - break; - } - if (clock_gettime (clock, &now)) { - result = EINVAL; - break; - } - if (timespec_cmp (now, abs_deadline) >= 0) { - result = ETIMEDOUT; - break; - } - until = timespec_add (now, slice); - if (timespec_cmp (until, abs_deadline) > 0) { - until = abs_deadline; - } - if (!nsync_dispatch_semaphore_wait (s, until)) { - break; - } - } - } - return (result); -} - -/* Ensure that the count of *s is at least 1. */ -void nsync_mu_semaphore_v_gcd (nsync_semaphore *s) { - dispatch_semaphore_signal (*(dispatch_semaphore_t *)s); -} diff --git a/third_party/nsync/mu_semaphore_sem.c b/third_party/nsync/mu_semaphore_sem.c index 2876c902d..41d92acfa 100644 --- a/third_party/nsync/mu_semaphore_sem.c +++ b/third_party/nsync/mu_semaphore_sem.c @@ -30,10 +30,10 @@ #include "libc/sysv/consts/f.h" #include "libc/sysv/consts/fd.h" #include "libc/thread/thread.h" +#include "third_party/nsync/time.h" #include "third_party/nsync/mu_semaphore.h" #include "libc/intrin/atomic.h" #include "libc/atomic.h" -#include "libc/sysv/consts/clock.h" #include "third_party/nsync/time.h" /** diff --git a/third_party/nsync/note.h b/third_party/nsync/note.h index 008166aab..0d46e92ee 100644 --- a/third_party/nsync/note.h +++ b/third_party/nsync/note.h @@ -19,7 +19,7 @@ typedef struct nsync_note_s_ *nsync_note; abs_deadline==nsync_zero_time. nsync_notes should be passed to nsync_note_free() when no longer needed. */ -nsync_note nsync_note_new(nsync_note parent, nsync_time abs_deadline); +nsync_note nsync_note_new(nsync_note parent, int clock, nsync_time abs_deadline); /* Free resources associated with n. Requires that n was allocated by nsync_note_new(), and no concurrent or future operations are applied diff --git a/third_party/nsync/testing/BUILD.mk b/third_party/nsync/testing/BUILD.mk index 1ddb4368b..b87bb80d3 100644 --- a/third_party/nsync/testing/BUILD.mk +++ b/third_party/nsync/testing/BUILD.mk @@ -12,8 +12,8 @@ THIRD_PARTY_NSYNC_TESTING_SRCS_TEST = $(filter %_test.c,$(THIRD_PARTY_NSYNC_TEST THIRD_PARTY_NSYNC_TESTING_OBJS = $(THIRD_PARTY_NSYNC_TESTING_SRCS:%.c=o/$(MODE)/%.o) THIRD_PARTY_NSYNC_TESTING_COMS = $(THIRD_PARTY_NSYNC_TESTING_SRCS_TEST:%.c=o/$(MODE)/%) THIRD_PARTY_NSYNC_TESTING_BINS = $(THIRD_PARTY_NSYNC_TESTING_COMS) $(THIRD_PARTY_NSYNC_TESTING_COMS:%=%.dbg) -THIRD_PARTY_NSYNC_TESTING_TESTS_ = $(THIRD_PARTY_NSYNC_TESTING_SRCS_TEST:%.c=o/$(MODE)/%.ok) -THIRD_PARTY_NSYNC_TESTING_CHECKS_ = $(THIRD_PARTY_NSYNC_TESTING_SRCS_TEST:%.c=o/$(MODE)/%.runs) +THIRD_PARTY_NSYNC_TESTING_TESTS = $(THIRD_PARTY_NSYNC_TESTING_SRCS_TEST:%.c=o/$(MODE)/%.ok) +THIRD_PARTY_NSYNC_TESTING_CHECKS = $(THIRD_PARTY_NSYNC_TESTING_SRCS_TEST:%.c=o/$(MODE)/%.runs) THIRD_PARTY_NSYNC_TESTING_DIRECTDEPS = \ LIBC_CALLS \ @@ -51,15 +51,21 @@ o/$(MODE)/third_party/nsync/testing/%_test.dbg: \ $(APE_NO_MODIFY_SELF) @$(APELINK) +o/$(MODE)/third_party/nsync/testing/mu_starvation_test.ok: private QUOTA = -L300 +o/$(MODE)/third_party/nsync/testing/mu_starvation_test.runs: private QUOTA = -C128 -L300 +o/$(MODE)/third_party/nsync/testing/mu_test.ok: private QUOTA = -L300 +o/$(MODE)/third_party/nsync/testing/mu_test.runs: private QUOTA = -C128 -L300 +o/$(MODE)/third_party/nsync/testing/wait_test.ok: private QUOTA = -P65536 +o/$(MODE)/third_party/nsync/testing/wait_test.runs: private QUOTA = -P65536 + $(THIRD_PARTY_NSYNC_TESTING_OBJS): third_party/nsync/testing/BUILD.mk -o/$(MODE)/third_party/nsync/testing/mu_test.runs: private QUOTA = -C64 .PHONY: o/$(MODE)/third_party/nsync/testing o/$(MODE)/third_party/nsync/testing: \ - $(THIRD_PARTY_NSYNC_TESTING_CHECKS_) \ - $(THIRD_PARTY_NSYNC_TESTING_BINS_) + $(THIRD_PARTY_NSYNC_TESTING_CHECKS) \ + $(THIRD_PARTY_NSYNC_TESTING_BINS) .PHONY: o/$(MODE)/third_party/nsync/test o/$(MODE)/third_party/nsync/test: \ - $(THIRD_PARTY_NSYNC_TESTING_CHECKS_) \ - $(THIRD_PARTY_NSYNC_TESTING_TESTS_) + $(THIRD_PARTY_NSYNC_TESTING_CHECKS) \ + $(THIRD_PARTY_NSYNC_TESTING_TESTS) diff --git a/third_party/nsync/testing/counter_test.c b/third_party/nsync/testing/counter_test.c index 99a9c0b95..eb53a702a 100644 --- a/third_party/nsync/testing/counter_test.c +++ b/third_party/nsync/testing/counter_test.c @@ -19,6 +19,7 @@ #include "third_party/nsync/testing/closure.h" #include "third_party/nsync/testing/smprintf.h" #include "third_party/nsync/testing/testing.h" +#include "third_party/nsync/time.h" #include "third_party/nsync/testing/time_extra.h" /* Verify the properties of a zero counter. */ @@ -29,10 +30,10 @@ static void test_counter_zero (testing t) { if (nsync_counter_value (c) != 0) { TEST_ERROR (t, ("zero counter is not zero (test, %d)", i)); } - if (nsync_counter_wait (c, nsync_time_zero) != 0) { + if (nsync_counter_wait (c, NSYNC_CLOCK, nsync_time_zero) != 0) { TEST_ERROR (t, ("zero counter is not zero (poll, %d)", i)); } - if (nsync_counter_wait (c, nsync_time_no_deadline) != 0) { + if (nsync_counter_wait (c, NSYNC_CLOCK, nsync_time_no_deadline) != 0) { TEST_ERROR (t, ("zero counter is not zero (infinite wait, %d)", i)); } nsync_counter_add (c, 0); @@ -50,15 +51,15 @@ static void test_counter_non_zero (testing t) { if (nsync_counter_value (c) != 1) { TEST_ERROR (t, ("counter is not 1 (test)")); } - if (nsync_counter_wait (c, nsync_time_zero) != 1) { + if (nsync_counter_wait (c, NSYNC_CLOCK, nsync_time_zero) != 1) { TEST_ERROR (t, ("counter is not 1 (poll)")); } - start = nsync_time_now (); - abs_deadline = nsync_time_add (nsync_time_now (), nsync_time_ms (1000)); - if (nsync_counter_wait (c, abs_deadline) != 1) { + start = nsync_time_now (NSYNC_CLOCK); + abs_deadline = nsync_time_add (nsync_time_now (NSYNC_CLOCK), nsync_time_ms (1000)); + if (nsync_counter_wait (c, NSYNC_CLOCK, abs_deadline) != 1) { TEST_ERROR (t, ("counter is not 1 (1s wait)")); } - waited = nsync_time_sub (nsync_time_now (), start); + waited = nsync_time_sub (nsync_time_now (NSYNC_CLOCK), start); if (nsync_time_cmp (waited, nsync_time_ms (900)) < 0) { TEST_ERROR (t, ("timed wait on non-zero counter returned too quickly (1s wait took %s)", nsync_time_str (waited, 2))); @@ -75,17 +76,17 @@ static void test_counter_non_zero (testing t) { if (nsync_counter_value (c) != 0) { TEST_ERROR (t, ("zero counter note is not 0 (test)")); } - if (nsync_counter_wait (c, nsync_time_zero) != 0) { + if (nsync_counter_wait (c, NSYNC_CLOCK, nsync_time_zero) != 0) { TEST_ERROR (t, ("zero counter note is not 0 (poll)")); } - if (nsync_counter_wait (c, nsync_time_no_deadline) != 0) { + if (nsync_counter_wait (c, NSYNC_CLOCK, nsync_time_no_deadline) != 0) { TEST_ERROR (t, ("zero counter note is not 0 (infinite wait)")); } nsync_counter_free (c); } static void decrement_at (nsync_counter c, nsync_time abs_deadline) { - nsync_time_sleep_until (abs_deadline); + nsync_time_sleep_until (NSYNC_CLOCK, abs_deadline); nsync_counter_add (c, -1); } @@ -97,12 +98,12 @@ static void test_counter_decrement (testing t) { nsync_time waited; nsync_counter c = nsync_counter_new (1); closure_fork (closure_decrement (&decrement_at, c, - nsync_time_add (nsync_time_now (), nsync_time_ms (1000)))); - start = nsync_time_now (); - if (nsync_counter_wait (c, nsync_time_no_deadline) != 0) { + nsync_time_add (nsync_time_now (NSYNC_CLOCK), nsync_time_ms (1000)))); + start = nsync_time_now (NSYNC_CLOCK); + if (nsync_counter_wait (c, NSYNC_CLOCK, nsync_time_no_deadline) != 0) { TEST_ERROR (t, ("counter is not 0")); } - waited = nsync_time_sub (nsync_time_now (), start); + waited = nsync_time_sub (nsync_time_now (NSYNC_CLOCK), start); if (nsync_time_cmp (waited, nsync_time_ms (900)) < 0) { TEST_ERROR (t, ("counter wait too fast (1s delay took %s)", nsync_time_str (waited, 2))); } @@ -112,22 +113,22 @@ static void test_counter_decrement (testing t) { if (nsync_counter_value (c) != 0) { TEST_ERROR (t, ("counter is not 0 (test)")); } - if (nsync_counter_wait (c, nsync_time_zero) != 0) { + if (nsync_counter_wait (c, NSYNC_CLOCK, nsync_time_zero) != 0) { TEST_ERROR (t, ("counter is not 0 (poll)")); } - if (nsync_counter_wait (c, nsync_time_no_deadline) != 0) { + if (nsync_counter_wait (c, NSYNC_CLOCK, nsync_time_no_deadline) != 0) { TEST_ERROR (t, ("counter is not 0 (infinite wait)")); } nsync_counter_free (c); c = nsync_counter_new (1); closure_fork (closure_decrement (&decrement_at, c, - nsync_time_add (nsync_time_now (), nsync_time_ms (1000)))); - start = nsync_time_now (); + nsync_time_add (nsync_time_now (NSYNC_CLOCK), nsync_time_ms (1000)))); + start = nsync_time_now (NSYNC_CLOCK); while (nsync_counter_value (c) != 0) { - nsync_time_sleep (nsync_time_ms (10)); + nsync_time_sleep (NSYNC_CLOCK, nsync_time_ms (10)); } - waited = nsync_time_sub (nsync_time_now (), start); + waited = nsync_time_sub (nsync_time_now (NSYNC_CLOCK), start); if (nsync_time_cmp (waited, nsync_time_ms (900)) < 0) { TEST_ERROR (t, ("counter wait too fast (1s delay took %s)", nsync_time_str (waited, 2))); } @@ -137,10 +138,10 @@ static void test_counter_decrement (testing t) { if (nsync_counter_value (c) != 0) { TEST_ERROR (t, ("counter is not 0 (test)")); } - if (nsync_counter_wait (c, nsync_time_zero) != 0) { + if (nsync_counter_wait (c, NSYNC_CLOCK, nsync_time_zero) != 0) { TEST_ERROR (t, ("counter is not 0 (poll)")); } - if (nsync_counter_wait (c, nsync_time_no_deadline) != 0) { + if (nsync_counter_wait (c, NSYNC_CLOCK, nsync_time_no_deadline) != 0) { TEST_ERROR (t, ("counter is not 0 (infinite wait)")); } nsync_counter_free (c); diff --git a/third_party/nsync/testing/cv_mu_timeout_stress_test_.c b/third_party/nsync/testing/cv_mu_timeout_stress_test_.c index 0b6982768..2211fcce4 100644 --- a/third_party/nsync/testing/cv_mu_timeout_stress_test_.c +++ b/third_party/nsync/testing/cv_mu_timeout_stress_test_.c @@ -17,12 +17,12 @@ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/stdio/rand.h" #include "libc/str/str.h" +#include "third_party/nsync/time.h" #include "third_party/nsync/cv.h" #include "third_party/nsync/mu.h" #include "third_party/nsync/mu_wait.h" #include "third_party/nsync/testing/closure.h" #include "third_party/nsync/testing/smprintf.h" -#include "libc/sysv/consts/clock.h" #include "third_party/nsync/testing/testing.h" /* A cv_stress_data represents the data used by the threads of the tests below. */ @@ -76,16 +76,16 @@ static void cv_stress_inc_loop (cv_stress_data *s, uintmax_t count_imod4) { nsync_mu_assert_held (&s->mu); while ((s->count & 3) != count_imod4) { nsync_time abs_deadline; - abs_deadline = nsync_time_add (nsync_time_now (), + abs_deadline = nsync_time_add (nsync_time_now (NSYNC_CLOCK), nsync_time_us (rand () % STRESS_MAX_DELAY_MICROS)); while (nsync_cv_wait_with_deadline ( &s->count_is_imod4[count_imod4], - &s->mu, CLOCK_REALTIME, abs_deadline, NULL) != 0 && + &s->mu, NSYNC_CLOCK, abs_deadline, NULL) != 0 && (s->count&3) != count_imod4) { nsync_mu_assert_held (&s->mu); s->timeouts++; nsync_mu_assert_held (&s->mu); - abs_deadline = nsync_time_add (nsync_time_now (), + abs_deadline = nsync_time_add (nsync_time_now (NSYNC_CLOCK), nsync_time_us (rand () % STRESS_MAX_DELAY_MICROS)); } } @@ -128,16 +128,16 @@ static void cv_stress_reader_loop (cv_stress_data *s, uintmax_t count_imod4) { nsync_mu_rassert_held (&s->mu); while ((s->count&3) != count_imod4 && s->refs != 0) { nsync_time abs_deadline; - abs_deadline = nsync_time_add (nsync_time_now (), + abs_deadline = nsync_time_add (nsync_time_now (NSYNC_CLOCK), nsync_time_us (rand () % STRESS_MAX_DELAY_MICROS)); while (nsync_cv_wait_with_deadline (&s->count_is_imod4[count_imod4], - &s->mu, CLOCK_REALTIME, + &s->mu, NSYNC_CLOCK, abs_deadline, NULL) != 0 && (s->count&3) != count_imod4 && s->refs != 0) { nsync_mu_rassert_held (&s->mu); timeouts++; - abs_deadline = nsync_time_add (nsync_time_now (), + abs_deadline = nsync_time_add (nsync_time_now (NSYNC_CLOCK), nsync_time_us (rand () % STRESS_MAX_DELAY_MICROS)); } } @@ -146,7 +146,7 @@ static void cv_stress_reader_loop (cv_stress_data *s, uintmax_t count_imod4) { if ((loops & 0xf) == 0) { nsync_mu_runlock (&s->mu); if ((loops & 0xfff) == 0) { - nsync_time_sleep (nsync_time_ms (1)); + nsync_time_sleep (NSYNC_CLOCK, nsync_time_ms (1)); } nsync_mu_rlock (&s->mu); } @@ -236,14 +236,14 @@ static void mu_stress_inc_loop (cv_stress_data *s, condition_func condition, nsync_time abs_deadline; nsync_mu_assert_held (&s->mu); - abs_deadline = nsync_time_add (nsync_time_now (), + abs_deadline = nsync_time_add (nsync_time_now (NSYNC_CLOCK), nsync_time_us (rand () % STRESS_MAX_DELAY_MICROS)); while (nsync_mu_wait_with_deadline (&s->mu, condition, condition_arg, NULL, - abs_deadline, NULL) != 0) { + NSYNC_CLOCK, abs_deadline, NULL) != 0) { nsync_mu_assert_held (&s->mu); s->timeouts++; nsync_mu_assert_held (&s->mu); - abs_deadline = nsync_time_add (nsync_time_now (), + abs_deadline = nsync_time_add (nsync_time_now (NSYNC_CLOCK), nsync_time_us (rand () % STRESS_MAX_DELAY_MICROS)); } @@ -286,14 +286,14 @@ static void mu_stress_reader_loop (cv_stress_data *s, condition_func condition, while (s->refs != 0) { nsync_time abs_deadline; nsync_mu_rassert_held (&s->mu); - abs_deadline = nsync_time_add (nsync_time_now (), + abs_deadline = nsync_time_add (nsync_time_now (NSYNC_CLOCK), nsync_time_us (rand () % STRESS_MAX_DELAY_MICROS)); while (nsync_mu_wait_with_deadline (&s->mu, condition, condition_arg, NULL, - abs_deadline, NULL) != 0) { + NSYNC_CLOCK, abs_deadline, NULL) != 0) { nsync_mu_rassert_held (&s->mu); s->timeouts++; nsync_mu_rassert_held (&s->mu); - abs_deadline = nsync_time_add (nsync_time_now (), + abs_deadline = nsync_time_add (nsync_time_now (NSYNC_CLOCK), nsync_time_us (rand () % STRESS_MAX_DELAY_MICROS)); } @@ -302,7 +302,7 @@ static void mu_stress_reader_loop (cv_stress_data *s, condition_func condition, if ((loops & 0xf) == 0) { nsync_mu_runlock (&s->mu); if ((loops & 0xfff) == 0) { - nsync_time_sleep (nsync_time_ms (1)); + nsync_time_sleep (NSYNC_CLOCK, nsync_time_ms (1)); } nsync_mu_rlock (&s->mu); } @@ -418,7 +418,7 @@ static int run_stress_test (cv_stress_data *s, testing t, nsync_mu_unlock (&s->mu); /* Sleep a while to cause many timeouts. */ - nsync_time_sleep (nsync_time_ms (sleep_seconds * 1000)); + nsync_time_sleep (NSYNC_CLOCK, nsync_time_ms (sleep_seconds * 1000)); nsync_mu_lock (&s->mu); nsync_mu_assert_held (&s->mu); @@ -467,7 +467,7 @@ static int run_stress_test (cv_stress_data *s, testing t, nsync_mu_assert_held (&s->mu); nsync_mu_unlock (&s->mu); - if (nsync_time_cmp (s->deadline, nsync_time_now ()) < 0) { + if (nsync_time_cmp (s->deadline, nsync_time_now (NSYNC_CLOCK)) < 0) { if (timeouts_seen < expected_timeouts && !testing_is_uniprocessor (t)) { TEST_ERROR (t, ("%s: expected more than %d timeouts, got %d", test_name, expected_timeouts, timeouts_seen)); @@ -498,7 +498,7 @@ static void test_cv_timeout_stress (testing t) { uintmax_t loop_count = 3; cv_stress_data s; nsync_time deadline; - deadline = nsync_time_add (nsync_time_now (), nsync_time_ms (5000)); + deadline = nsync_time_add (nsync_time_now (NSYNC_CLOCK), nsync_time_ms (5000)); do { bzero ((void *) &s, sizeof (s)); s.loop_count = loop_count; @@ -518,7 +518,7 @@ static void test_mu_timeout_stress (testing t) { uintmax_t loop_count = 3; cv_stress_data s; nsync_time deadline; - deadline = nsync_time_add (nsync_time_now (), nsync_time_ms (5000)); + deadline = nsync_time_add (nsync_time_now (NSYNC_CLOCK), nsync_time_ms (5000)); do { bzero ((void *) &s, sizeof (s)); s.loop_count = loop_count; @@ -538,7 +538,7 @@ static void test_mu_cv_timeout_stress (testing t) { uintmax_t loop_count = 3; cv_stress_data s; nsync_time deadline; - deadline = nsync_time_add (nsync_time_now (), nsync_time_ms (5000)); + deadline = nsync_time_add (nsync_time_now (NSYNC_CLOCK), nsync_time_ms (5000)); do { bzero ((void *) &s, sizeof (s)); s.loop_count = loop_count; diff --git a/third_party/nsync/testing/cv_test.c b/third_party/nsync/testing/cv_test.c index 9677b2083..ee3c2505c 100644 --- a/third_party/nsync/testing/cv_test.c +++ b/third_party/nsync/testing/cv_test.c @@ -29,7 +29,6 @@ #include "third_party/nsync/testing/smprintf.h" #include "third_party/nsync/testing/testing.h" #include "third_party/nsync/testing/time_extra.h" -#include "libc/sysv/consts/clock.h" #include "third_party/nsync/time.h" /* --------------------------- */ @@ -64,7 +63,7 @@ static int cv_queue_put (cv_queue *q, void *v, nsync_time abs_deadline) { int wake = 0; nsync_mu_lock (&q->mu); while (q->count == q->limit && - nsync_cv_wait_with_deadline (&q->non_full, &q->mu, CLOCK_REALTIME, abs_deadline, NULL) == 0) { + nsync_cv_wait_with_deadline (&q->non_full, &q->mu, NSYNC_CLOCK, abs_deadline, NULL) == 0) { } if (q->count != q->limit) { int i = q->pos + q->count; @@ -92,7 +91,7 @@ static void *cv_queue_get (cv_queue *q, nsync_time abs_deadline) { void *v = NULL; nsync_mu_lock (&q->mu); while (q->count == 0 && - nsync_cv_wait_with_deadline (&q->non_empty, &q->mu, CLOCK_REALTIME, abs_deadline, NULL) == 0) { + nsync_cv_wait_with_deadline (&q->non_empty, &q->mu, NSYNC_CLOCK, abs_deadline, NULL) == 0) { } if (q->count != 0) { v = q->data[q->pos]; @@ -236,13 +235,13 @@ static void test_cv_deadline (testing t) { nsync_time end_time; nsync_time start_time; nsync_time expected_end_time; - start_time = nsync_time_now (); + start_time = nsync_time_now (NSYNC_CLOCK); expected_end_time = nsync_time_add (start_time, nsync_time_ms (87)); - if (nsync_cv_wait_with_deadline (&cv, &mu, CLOCK_REALTIME, expected_end_time, + if (nsync_cv_wait_with_deadline (&cv, &mu, NSYNC_CLOCK, expected_end_time, NULL) != ETIMEDOUT) { TEST_FATAL (t, ("nsync_cv_wait() returned non-expired for a timeout")); } - end_time = nsync_time_now (); + end_time = nsync_time_now (NSYNC_CLOCK); if (nsync_time_cmp (end_time, nsync_time_sub (expected_end_time, too_early)) < 0) { char *elapsed_str = nsync_time_str (nsync_time_sub (expected_end_time, end_time), 2); TEST_ERROR (t, ("nsync_cv_wait() returned %s too early", elapsed_str)); @@ -275,7 +274,7 @@ static void test_cv_cancel (testing t) { /* The loops below cancel after 87 milliseconds, like the timeout tests above. */ - future_time = nsync_time_add (nsync_time_now (), nsync_time_ms (3600000)); /* test cancels with timeout */ + future_time = nsync_time_add (nsync_time_now (NSYNC_CLOCK), nsync_time_ms (3600000)); /* test cancels with timeout */ too_late_violations = 0; nsync_mu_lock (&mu); @@ -285,18 +284,18 @@ static void test_cv_cancel (testing t) { nsync_time end_time; nsync_time start_time; nsync_time expected_end_time; - start_time = nsync_time_now (); + start_time = nsync_time_now (NSYNC_CLOCK); expected_end_time = nsync_time_add (start_time, nsync_time_ms (87)); - cancel = nsync_note_new (NULL, expected_end_time); + cancel = nsync_note_new (NULL, NSYNC_CLOCK, expected_end_time); - x = nsync_cv_wait_with_deadline (&cv, &mu, CLOCK_REALTIME, future_time, cancel); + x = nsync_cv_wait_with_deadline (&cv, &mu, NSYNC_CLOCK, future_time, cancel); if (x != ECANCELED) { TEST_FATAL (t, ("nsync_cv_wait() returned non-cancelled (%d) for " "a cancellation; expected %d", x, ECANCELED)); } - end_time = nsync_time_now (); + end_time = nsync_time_now (NSYNC_CLOCK); if (nsync_time_cmp (end_time, nsync_time_sub (expected_end_time, too_early)) < 0) { char *elapsed_str = nsync_time_str (nsync_time_sub (expected_end_time, end_time), 2); TEST_ERROR (t, ("nsync_cv_wait() returned %s too early", elapsed_str)); @@ -307,15 +306,15 @@ static void test_cv_cancel (testing t) { } /* Check that an already cancelled wait returns immediately. */ - start_time = nsync_time_now (); + start_time = nsync_time_now (NSYNC_CLOCK); - x = nsync_cv_wait_with_deadline (&cv, &mu, CLOCK_REALTIME, nsync_time_no_deadline, cancel); + x = nsync_cv_wait_with_deadline (&cv, &mu, NSYNC_CLOCK, nsync_time_no_deadline, cancel); if (x != ECANCELED) { TEST_FATAL (t, ("nsync_cv_wait() returned non-cancelled (%d) for " "a cancellation; expected %d", x, ECANCELED)); } - end_time = nsync_time_now (); + end_time = nsync_time_now (NSYNC_CLOCK); if (nsync_time_cmp (end_time, start_time) < 0) { char *elapsed_str = nsync_time_str (nsync_time_sub (expected_end_time, end_time), 2); TEST_ERROR (t, ("nsync_cv_wait() returned %s too early", elapsed_str)); @@ -522,7 +521,7 @@ static void test_cv_debug (testing t) { closure_fork (closure_debug_thread (&debug_thread_writer_cv, s)); closure_fork (closure_debug_thread (&debug_thread_writer_cv, s)); closure_fork (closure_debug_thread_reader (&debug_thread_reader_cv, s, NULL)); - nsync_time_sleep (nsync_time_ms (500)); + nsync_time_sleep (NSYNC_CLOCK, nsync_time_ms (500)); *slot (s, "wait0_mu") = nsync_mu_debug_state_and_waiters ( &s->mu, (char *) malloc (len), len); *slot (s, "wait0_cv") = nsync_cv_debug_state_and_waiters ( @@ -530,7 +529,7 @@ static void test_cv_debug (testing t) { /* allow the threads to proceed to their conditional waits */ nsync_mu_unlock (&s->mu); - nsync_time_sleep (nsync_time_ms (500)); + nsync_time_sleep (NSYNC_CLOCK, nsync_time_ms (500)); *slot (s, "wait1_mu") = nsync_mu_debug_state_and_waiters ( &s->mu, (char *) malloc (len), len); *slot (s, "wait1_cv") = nsync_cv_debug_state_and_waiters ( @@ -547,7 +546,7 @@ static void test_cv_debug (testing t) { /* allow all threads to proceed and exit */ s->flag = 0; nsync_mu_unlock (&s->mu); - nsync_time_sleep (nsync_time_ms (500)); + nsync_time_sleep (NSYNC_CLOCK, nsync_time_ms (500)); *slot (s, "wait3_mu") = nsync_mu_debug_state_and_waiters ( &s->mu, (char *) malloc (len), len); *slot (s, "wait3_cv") = nsync_cv_debug_state_and_waiters ( @@ -559,7 +558,7 @@ static void test_cv_debug (testing t) { &s->mu, (char *) malloc (len), len); closure_fork (closure_debug_thread_reader ( &debug_thread_reader, s, "rheld2_mu")); - nsync_time_sleep (nsync_time_ms (500)); + nsync_time_sleep (NSYNC_CLOCK, nsync_time_ms (500)); *slot (s, "rheld1again_mu") = nsync_mu_debug_state_and_waiters ( &s->mu, (char *) malloc (len), len); nsync_mu_runlock (&s->mu); diff --git a/third_party/nsync/testing/cv_wait_example_test.c b/third_party/nsync/testing/cv_wait_example_test.c index 6368e526b..d365d4f9d 100644 --- a/third_party/nsync/testing/cv_wait_example_test.c +++ b/third_party/nsync/testing/cv_wait_example_test.c @@ -18,13 +18,13 @@ #include "libc/stdio/stdio.h" #include "libc/str/str.h" #include "third_party/nsync/array.internal.h" +#include "third_party/nsync/time.h" #include "third_party/nsync/cv.h" #include "third_party/nsync/heap.internal.h" #include "third_party/nsync/mu.h" #include "third_party/nsync/testing/closure.h" #include "third_party/nsync/testing/smprintf.h" #include "third_party/nsync/testing/testing.h" -#include "libc/sysv/consts/clock.h" #include "third_party/nsync/testing/time_extra.h" /* Example use of CV.wait(): A priority queue of strings whose @@ -75,7 +75,7 @@ static const char *string_priority_queue_cv_remove_with_deadline (string_priorit const char *s = NULL; nsync_mu_lock (&q->mu); while (A_LEN (&q->heap) == 0 && - nsync_cv_wait_with_deadline (&q->non_empty, &q->mu, CLOCK_REALTIME, + nsync_cv_wait_with_deadline (&q->non_empty, &q->mu, NSYNC_CLOCK, abs_deadline, NULL) == 0) { } alen = A_LEN (&q->heap); @@ -101,7 +101,7 @@ static void add_and_wait_cv (string_priority_queue_cv *q, nsync_time delay, int i; for (i = 0; i != n; i++) { string_priority_queue_cv_add (q, s[i]); - nsync_time_sleep (delay); + nsync_time_sleep (NSYNC_CLOCK, delay); } } @@ -123,7 +123,7 @@ static void a_char_append (a_char *a, const char *str) { static void remove_and_print_cv (string_priority_queue_cv *q, nsync_time delay, a_char *output) { const char *s; if ((s = string_priority_queue_cv_remove_with_deadline ( - q, nsync_time_add (nsync_time_now(), delay))) != NULL) { + q, nsync_time_add (nsync_time_now (NSYNC_CLOCK), delay))) != NULL) { a_char_append (output, s); a_char_append (output, "\n"); } else { @@ -157,7 +157,7 @@ static void example_cv_wait (testing t) { nsync_time_ms (500), NELEM (input), input)); /* delay: "one", "two", "three" are queued; not "four" */ - nsync_time_sleep (nsync_time_ms (1200)); + nsync_time_sleep (NSYNC_CLOCK, nsync_time_ms (1200)); remove_and_print_cv (&q, nsync_time_ms (1000), &output); /* "one" */ remove_and_print_cv (&q, nsync_time_ms (1000), &output); /* "three" (less than "two") */ diff --git a/third_party/nsync/testing/mu_starvation_test.c b/third_party/nsync/testing/mu_starvation_test.c index f6df7cd5c..a84e31af9 100644 --- a/third_party/nsync/testing/mu_starvation_test.c +++ b/third_party/nsync/testing/mu_starvation_test.c @@ -44,7 +44,7 @@ static void starve_data_init (starve_data *sd, int threads) { bzero ((void *) sd, sizeof (*sd)); sd->not_yet_started = threads; sd->not_yet_done = threads; - sd->start = nsync_time_now (); + sd->start = nsync_time_now (NSYNC_CLOCK); } /* Loop until *cancel or deadline, and on each iteration @@ -62,9 +62,9 @@ static void starve_with_readers (starve_data *sd, nsync_time period, sd->not_yet_started--; nsync_mu_unlock (&sd->control_mu); - for (now = nsync_time_now (); + for (now = nsync_time_now (NSYNC_CLOCK); !sd->cancel && nsync_time_cmp (now, deadline) < 0; - now = nsync_time_now ()) { + now = nsync_time_now (NSYNC_CLOCK)) { uint32_t new_us; uint32_t now_us = (uint32_t) (nsync_time_to_dbl (nsync_time_sub (now, sd->start)) * 1e6); uint32_t index = (now_us + period_us - 1) / period_us; @@ -72,7 +72,7 @@ static void starve_with_readers (starve_data *sd, nsync_time period, index++; } new_us = index * period_us; - nsync_time_sleep (nsync_time_from_dbl (1e-6 * (double) (new_us-now_us))); + nsync_time_sleep (NSYNC_CLOCK, nsync_time_from_dbl (1e-6 * (double) (new_us-now_us))); nsync_mu_runlock (&sd->mu); nsync_mu_rlock (&sd->mu); } @@ -113,7 +113,7 @@ static void test_starve_with_readers (testing t) { starve_data_init (&sd, 2); /* two threads, started below */ /* Threads run for at most 10s. */ - deadline = nsync_time_add (nsync_time_now (), nsync_time_ms (10000)); + deadline = nsync_time_add (nsync_time_now (NSYNC_CLOCK), nsync_time_ms (10000)); /* These two threads will try to hold a reader lock continuously until cancel is set or deadline is reached, @@ -130,9 +130,9 @@ static void test_starve_with_readers (testing t) { /* If using an nsync_mu, use nsync_mu_trylock() to attempt to acquire while the readers are hogging the lock. We expect no acquisitions to succeed. */ - finish = nsync_time_add (nsync_time_now (), nsync_time_ms (500)); + finish = nsync_time_add (nsync_time_now (NSYNC_CLOCK), nsync_time_ms (500)); trylock_acquires = 0; /* number of acquires */ - while (nsync_time_cmp (nsync_time_now (), finish) < 0) { + while (nsync_time_cmp (nsync_time_now (NSYNC_CLOCK), finish) < 0) { if (nsync_mu_trylock (&sd.mu)) { trylock_acquires++; nsync_mu_unlock (&sd.mu); @@ -147,15 +147,15 @@ static void test_starve_with_readers (testing t) { /* Use nsync_mu_lock() to attempt to acquire while the readers are hogging the lock. We expect several acquisitions to succeed. */ expected_lo = 2; - finish = nsync_time_add (nsync_time_now (), nsync_time_ms (5000)); + finish = nsync_time_add (nsync_time_now (NSYNC_CLOCK), nsync_time_ms (5000)); lock_acquires = 0; /* number of acquires */ - while (nsync_time_cmp (nsync_time_now (), finish) < 0 && lock_acquires < expected_lo) { + while (nsync_time_cmp (nsync_time_now (NSYNC_CLOCK), finish) < 0 && lock_acquires < expected_lo) { nsync_mu_lock (&sd.mu); lock_acquires++; nsync_mu_unlock (&sd.mu); - nsync_time_sleep (nsync_time_ms (1)); + nsync_time_sleep (NSYNC_CLOCK, nsync_time_ms (1)); } - if (nsync_time_cmp (nsync_time_now (), deadline) > 0 && lock_acquires == 1) { + if (nsync_time_cmp (nsync_time_now (NSYNC_CLOCK), deadline) > 0 && lock_acquires == 1) { lock_acquires = 0; /* hog threads timed out */ } if (lock_acquires < expected_lo) { @@ -185,10 +185,10 @@ static void starve_with_writer (starve_data *sd, nsync_time hold_time, sd->not_yet_started--; nsync_mu_unlock (&sd->control_mu); - for (now = nsync_time_now (); + for (now = nsync_time_now (NSYNC_CLOCK); !sd->cancel && nsync_time_cmp (now, deadline) < 0; - now = nsync_time_now ()) { - nsync_time_sleep (hold_time); + now = nsync_time_now (NSYNC_CLOCK)) { + nsync_time_sleep (NSYNC_CLOCK, hold_time); nsync_mu_unlock (&sd->mu); nsync_mu_lock (&sd->mu); } @@ -231,7 +231,7 @@ static void test_starve_with_writer (testing t) { nsync_time deadline; starve_data sd; starve_data_init (&sd, 1); /* one thread, started below */ - deadline = nsync_time_add (nsync_time_now (), nsync_time_ms (25000)); /* runs for at most 25s. */ + deadline = nsync_time_add (nsync_time_now (NSYNC_CLOCK), nsync_time_ms (25000)); /* runs for at most 25s. */ /* This thread will try to hold a writer lock almost continuously, releasing momentarily every 10ms. */ @@ -249,9 +249,9 @@ static void test_starve_with_writer (testing t) { /* Use nsync_mu_trylock() to attempt to acquire while the writer is hogging the lock. We expect some acquisitions to succeed. */ expected_lo = 1; - finish = nsync_time_add (nsync_time_now (), nsync_time_ms (30000)); + finish = nsync_time_add (nsync_time_now (NSYNC_CLOCK), nsync_time_ms (30000)); trylock_acquires = 0; /* number of acquires */ - while (nsync_time_cmp (nsync_time_now (), finish) < 0 && trylock_acquires < expected_lo) { + while (nsync_time_cmp (nsync_time_now (NSYNC_CLOCK), finish) < 0 && trylock_acquires < expected_lo) { if (nsync_mu_trylock (&sd.mu)) { trylock_acquires++; nsync_mu_unlock (&sd.mu); @@ -269,9 +269,9 @@ static void test_starve_with_writer (testing t) { /* Use nsync_mu_rtrylock() to attempt to read-acquire while the writer is hogging the lock. We expect some acquisitions to succeed. */ expected_lo = 1; - finish = nsync_time_add (nsync_time_now (), nsync_time_ms (30000)); + finish = nsync_time_add (nsync_time_now (NSYNC_CLOCK), nsync_time_ms (30000)); rtrylock_acquires = 0; /* number of acquires */ - while (nsync_time_cmp (nsync_time_now (), finish) < 0 && rtrylock_acquires < expected_lo) { + while (nsync_time_cmp (nsync_time_now (NSYNC_CLOCK), finish) < 0 && rtrylock_acquires < expected_lo) { if (nsync_mu_rtrylock (&sd.mu)) { rtrylock_acquires++; nsync_mu_runlock (&sd.mu); @@ -288,15 +288,15 @@ static void test_starve_with_writer (testing t) { /* Use nsync_mu_lock() to attempt to acquire while the writer is hogging the lock. We expect several acquisitions to succeed. */ expected_lo = 2; - finish = nsync_time_add (nsync_time_now (), nsync_time_ms (5000)); + finish = nsync_time_add (nsync_time_now (NSYNC_CLOCK), nsync_time_ms (5000)); lock_acquires = 0; /* number of acquires */ - while (nsync_time_cmp (nsync_time_now (), finish) < 0 && lock_acquires < expected_lo) { + while (nsync_time_cmp (nsync_time_now (NSYNC_CLOCK), finish) < 0 && lock_acquires < expected_lo) { nsync_mu_lock (&sd.mu); lock_acquires++; nsync_mu_unlock (&sd.mu); - nsync_time_sleep (nsync_time_ms (2)); + nsync_time_sleep (NSYNC_CLOCK, nsync_time_ms (2)); } - if (lock_acquires == 1 && nsync_time_cmp (nsync_time_now (), deadline) > 0) { + if (lock_acquires == 1 && nsync_time_cmp (nsync_time_now (NSYNC_CLOCK), deadline) > 0) { lock_acquires = 0; /* hog thread timed out */ } if (lock_acquires < expected_lo) { @@ -310,16 +310,16 @@ static void test_starve_with_writer (testing t) { time----it means that a writer couldn't break in (the test case above failed), so a reader is unlikely to manage it either. */ expected_lo = 2; - finish = nsync_time_add (nsync_time_now (), nsync_time_ms (5000)); + finish = nsync_time_add (nsync_time_now (NSYNC_CLOCK), nsync_time_ms (5000)); rlock_acquires = 0; /* number of acquires */ if (nsync_time_cmp (finish, deadline) < 0) { - while (nsync_time_cmp (nsync_time_now (), finish) < 0 && rlock_acquires < expected_lo) { + while (nsync_time_cmp (nsync_time_now (NSYNC_CLOCK), finish) < 0 && rlock_acquires < expected_lo) { nsync_mu_rlock (&sd.mu); rlock_acquires++; nsync_mu_runlock (&sd.mu); - nsync_time_sleep (nsync_time_ms (2)); + nsync_time_sleep (NSYNC_CLOCK, nsync_time_ms (2)); } - if (rlock_acquires == 1 && nsync_time_cmp (nsync_time_now (), deadline) > 0) { + if (rlock_acquires == 1 && nsync_time_cmp (nsync_time_now (NSYNC_CLOCK), deadline) > 0) { rlock_acquires = 0; /* hog thread timed out */ } if (rlock_acquires < expected_lo) { diff --git a/third_party/nsync/testing/mu_test.c b/third_party/nsync/testing/mu_test.c index 4b4d6289c..5a0228804 100644 --- a/third_party/nsync/testing/mu_test.c +++ b/third_party/nsync/testing/mu_test.c @@ -19,12 +19,12 @@ #include "libc/calls/calls.h" #include "libc/str/str.h" #include "libc/thread/thread.h" +#include "third_party/nsync/time.h" #include "third_party/nsync/cv.h" #include "third_party/nsync/mu_wait.h" #include "third_party/nsync/testing/closure.h" #include "third_party/nsync/testing/smprintf.h" #include "third_party/nsync/testing/testing.h" -#include "libc/sysv/consts/clock.h" #include "third_party/nsync/testing/time_extra.h" /* The state shared between the threads in each of the tests below. */ @@ -68,7 +68,7 @@ static void test_data_wait_for_all_threads (test_data *td) { while (td->finished_threads != td->n_threads) { nsync_cv_wait_with_deadline_generic (&td->done, td->mu_in_use, td->lock, td->unlock, - CLOCK_REALTIME, + NSYNC_CLOCK, nsync_time_no_deadline, NULL); } (*td->unlock) (td->mu_in_use); @@ -113,7 +113,7 @@ static void void_mu_unlock (void *mu) { static void test_mu_nthread (testing t) { int loop_count = 100000; nsync_time deadline; - deadline = nsync_time_add (nsync_time_now (), nsync_time_ms (1500)); + deadline = nsync_time_add (nsync_time_now (NSYNC_CLOCK), nsync_time_ms (1500)); do { int i; test_data td; @@ -133,7 +133,7 @@ static void test_mu_nthread (testing t) { td.n_threads*td.loop_count, td.i)); } loop_count *= 2; - } while (nsync_time_cmp (nsync_time_now (), deadline) < 0); + } while (nsync_time_cmp (nsync_time_now (NSYNC_CLOCK), deadline) < 0); } /* void pthread_mutex_lock */ @@ -152,7 +152,7 @@ static void void_pthread_mutex_unlock (void *mu) { static void test_mutex_nthread (testing t) { int loop_count = 100000; nsync_time deadline; - deadline = nsync_time_add (nsync_time_now (), nsync_time_ms (1500)); + deadline = nsync_time_add (nsync_time_now (NSYNC_CLOCK), nsync_time_ms (1500)); do { int i; test_data td; @@ -174,7 +174,7 @@ static void test_mutex_nthread (testing t) { } pthread_mutex_destroy (&td.mutex); loop_count *= 2; - } while (nsync_time_cmp (nsync_time_now (), deadline) < 0); + } while (nsync_time_cmp (nsync_time_now (NSYNC_CLOCK), deadline) < 0); } /* void pthread_rwlock_wrlock */ @@ -193,7 +193,7 @@ static void void_pthread_rwlock_unlock (void *mu) { static void test_rwmutex_nthread (testing t) { int loop_count = 100000; nsync_time deadline; - deadline = nsync_time_add (nsync_time_now (), nsync_time_ms (1500)); + deadline = nsync_time_add (nsync_time_now (NSYNC_CLOCK), nsync_time_ms (1500)); do { int i; test_data td; @@ -215,7 +215,7 @@ static void test_rwmutex_nthread (testing t) { } pthread_rwlock_destroy (&td.rwmutex); loop_count *= 2; - } while (nsync_time_cmp (nsync_time_now (), deadline) < 0); + } while (nsync_time_cmp (nsync_time_now (NSYNC_CLOCK), deadline) < 0); } /* --------------------------------------- */ @@ -246,7 +246,7 @@ static void counting_loop_try_mu (test_data *td, int id) { static void test_try_mu_nthread (testing t) { int loop_count = 100000; nsync_time deadline; - deadline = nsync_time_add (nsync_time_now (), nsync_time_ms (1500)); + deadline = nsync_time_add (nsync_time_now (NSYNC_CLOCK), nsync_time_ms (1500)); do { int i; test_data td; @@ -266,7 +266,7 @@ static void test_try_mu_nthread (testing t) { td.n_threads*td.loop_count, td.i)); } loop_count *= 2; - } while (nsync_time_cmp (nsync_time_now (), deadline) < 0); + } while (nsync_time_cmp (nsync_time_now (NSYNC_CLOCK), deadline) < 0); } /* --------------------------------------- */ @@ -305,7 +305,7 @@ static int counter_wait_for_zero_with_deadline (counter *c, nsync_time abs_deadl int value; nsync_mu_rlock (&c->mu); while (c->value != 0 && - nsync_cv_wait_with_deadline (&c->cv, &c->mu, CLOCK_REALTIME, abs_deadline, NULL) == 0) { + nsync_cv_wait_with_deadline (&c->cv, &c->mu, NSYNC_CLOCK, abs_deadline, NULL) == 0) { } value = c->value; nsync_mu_runlock (&c->mu); @@ -429,7 +429,7 @@ static void lock_unlock (testing t, const char *id, int verbose, nsync_mu *mu, i if (verbose) { TEST_LOG (t, ("lock_unlock %s incremented value to %d\n", id, *value)); } - nsync_time_sleep (sleep); + nsync_time_sleep (NSYNC_CLOCK, sleep); nsync_mu_unlock (mu); counter_inc (done, -1); } @@ -453,7 +453,7 @@ static void rlock_runlock (testing t, const char *id, int verbose, nsync_mu *mu, testing_panic (smprintf ("rlock_runlock %s expected " "value %d, *value=%d", id, expected_value, *value)); } - nsync_time_sleep (sleep); + nsync_time_sleep (NSYNC_CLOCK, sleep); nsync_mu_runlock (mu); counter_inc (done, -1); } @@ -465,7 +465,7 @@ static int check_times (testing t, const char *id, nsync_time start_time, int exceeds_count = 0; nsync_time now; nsync_time measured_duration; - now = nsync_time_now (); + now = nsync_time_now (NSYNC_CLOCK); measured_duration = nsync_time_sub (now, start_time); if (nsync_time_cmp (measured_duration, nsync_time_sub (expected_duration, nsync_time_ms (5))) < 0) { @@ -520,7 +520,7 @@ static void test_rlock (testing t) { nsync_time start_time; nsync_mu_init (&mu); - start_time = nsync_time_now (); + start_time = nsync_time_now (NSYNC_CLOCK); /* ------------------------------------ */ /* Acquire lock with nsync_mu_rtrylock(). This thread will @@ -564,7 +564,7 @@ static void test_rlock (testing t) { lock_unlock_sleeping, lock_unlock_done)); counter_wait_for_zero (lock_unlock_sleeping); - nsync_time_sleep (delay_duration); /* give time for lock_unlock() thread to wait. */ + nsync_time_sleep (NSYNC_CLOCK, delay_duration); /* give time for lock_unlock() thread to wait. */ nsync_mu_rassert_held (&mu); @@ -581,7 +581,7 @@ static void test_rlock (testing t) { nsync_mu_rassert_held (&mu); counter_wait_for_zero (rlock_runlock_sleeping); - nsync_time_sleep (delay_duration); /* time for rlock_runlock() threads to wait. */ + nsync_time_sleep (NSYNC_CLOCK, delay_duration); /* time for rlock_runlock() threads to wait. */ nsync_mu_rassert_held (&mu); @@ -610,7 +610,7 @@ static void test_rlock (testing t) { nsync_mu_runlock (&mu); /* ==================================== */ - read_start_time = nsync_time_now (); + read_start_time = nsync_time_now (NSYNC_CLOCK); counter_wait_for_zero (lock_unlock_done); /* Now can get write lock. */ max_write_wait_exceeded += check_times (t, "i", start_time, nsync_time_add (nsync_time_add (delay_duration, delay_duration), writer_duration), @@ -656,7 +656,7 @@ static void test_rlock (testing t) { nsync_time start_time; nsync_mu_init (&mu); - start_time = nsync_time_now (); + start_time = nsync_time_now (NSYNC_CLOCK); /* ------------------------------------ */ /* Acquire lock with nsync_mu_trylock(). This thread will hold @@ -696,7 +696,7 @@ static void test_rlock (testing t) { lock_unlock_sleeping, lock_unlock_done)); counter_wait_for_zero (lock_unlock_sleeping); - nsync_time_sleep (delay_duration); /* give time for lock_unlock() thread to wait. */ + nsync_time_sleep (NSYNC_CLOCK, delay_duration); /* give time for lock_unlock() thread to wait. */ nsync_mu_assert_held (&mu); nsync_mu_rassert_held (&mu); @@ -715,7 +715,7 @@ static void test_rlock (testing t) { nsync_mu_rassert_held (&mu); counter_wait_for_zero (rlock_runlock_sleeping); - nsync_time_sleep (delay_duration); /* time for rlock_runlock() threads to wait. */ + nsync_time_sleep (NSYNC_CLOCK, delay_duration); /* time for rlock_runlock() threads to wait. */ nsync_mu_assert_held (&mu); nsync_mu_rassert_held (&mu); @@ -753,7 +753,7 @@ static void test_rlock (testing t) { nsync_mu_unlock (&mu); /* ==================================== */ - read_start_time = nsync_time_now (); + read_start_time = nsync_time_now (NSYNC_CLOCK); counter_wait_for_zero (lock_unlock_done); /* Now can get write lock. */ max_write_wait_exceeded += check_times (t, "H", start_time, nsync_time_add (nsync_time_add (delay_duration, delay_duration), writer_duration), diff --git a/third_party/nsync/testing/mu_wait_example_test.c b/third_party/nsync/testing/mu_wait_example_test.c index 220e473dd..90c8bf86b 100644 --- a/third_party/nsync/testing/mu_wait_example_test.c +++ b/third_party/nsync/testing/mu_wait_example_test.c @@ -18,6 +18,7 @@ #include "libc/stdio/stdio.h" #include "libc/str/str.h" #include "third_party/nsync/array.internal.h" +#include "third_party/nsync/time.h" #include "third_party/nsync/heap.internal.h" #include "third_party/nsync/mu.h" #include "third_party/nsync/mu_wait.h" @@ -74,7 +75,7 @@ static const char *string_priority_queue_mu_remove_with_deadline ( const char *s = NULL; nsync_mu_lock (&q->mu); if (nsync_mu_wait_with_deadline (&q->mu, &spq_is_non_empty, q, NULL, - abs_deadline, NULL) == 0) { + NSYNC_CLOCK, abs_deadline, NULL) == 0) { int alen = A_LEN (&q->heap); if (alen != 0) { s = A (&q->heap, 0); @@ -99,7 +100,7 @@ static void add_and_wait_mu (string_priority_queue_mu *q, int i; for (i = 0; i != n; i++) { string_priority_queue_mu_add (q, s[i]); - nsync_time_sleep (delay); + nsync_time_sleep (NSYNC_CLOCK, delay); } } @@ -120,7 +121,7 @@ static void a_char_append (a_char *a, const char *str) { static void remove_and_print_mu (string_priority_queue_mu *q, nsync_time delay, a_char *output) { const char *s; if ((s = string_priority_queue_mu_remove_with_deadline (q, - nsync_time_add (nsync_time_now (), delay))) != NULL) { + nsync_time_add (nsync_time_now (NSYNC_CLOCK), delay))) != NULL) { a_char_append (output, s); a_char_append (output, "\n"); } else { @@ -154,7 +155,7 @@ static void example_mu_wait (testing t) { NELEM (input), input)); /* delay: "one", "two", "three"; not yet "four" */ - nsync_time_sleep (nsync_time_ms (1200)); + nsync_time_sleep (NSYNC_CLOCK, nsync_time_ms (1200)); remove_and_print_mu (&q, nsync_time_ms (1000), &output); /* "one" */ remove_and_print_mu (&q, nsync_time_ms (1000), &output); /* "three" (less than "two") */ diff --git a/third_party/nsync/testing/mu_wait_test.c b/third_party/nsync/testing/mu_wait_test.c index 5ba1c6b53..93876f78c 100644 --- a/third_party/nsync/testing/mu_wait_test.c +++ b/third_party/nsync/testing/mu_wait_test.c @@ -18,13 +18,13 @@ #include "third_party/nsync/mu_wait.h" #include "libc/errno.h" #include "libc/str/str.h" +#include "third_party/nsync/time.h" #include "third_party/nsync/mu.h" #include "third_party/nsync/note.h" #include "third_party/nsync/testing/closure.h" #include "third_party/nsync/testing/smprintf.h" #include "third_party/nsync/testing/testing.h" #include "third_party/nsync/testing/time_extra.h" -#include "third_party/nsync/time.h" /* --------------------------- */ @@ -64,7 +64,7 @@ static int mu_queue_put (mu_queue *q, void *v, nsync_time abs_deadline) { int added = 0; nsync_mu_lock (&q->mu); if (nsync_mu_wait_with_deadline (&q->mu, &mu_queue_non_full, - q, NULL, abs_deadline, NULL) == 0) { + q, NULL, 0, abs_deadline, NULL) == 0) { int i = q->pos + q->count; if (q->count == q->limit) { testing_panic ("q->count == q->limit"); @@ -87,7 +87,8 @@ static void *mu_queue_get (mu_queue *q, nsync_time abs_deadline) { void *v = NULL; nsync_mu_lock (&q->mu); if (nsync_mu_wait_with_deadline (&q->mu, &mu_queue_non_empty, - q, NULL, abs_deadline, NULL) == 0) { + q, NULL, NSYNC_CLOCK, + abs_deadline, NULL) == 0) { if (q->count == 0) { testing_panic ("q->count == 0"); } @@ -228,18 +229,18 @@ static void test_mu_deadline (testing t) { too_early = nsync_time_ms (TOO_EARLY_MS); too_late = nsync_time_ms (TOO_LATE_MS); too_late_violations = 0; - nsync_mu_lock (&mu);; + nsync_mu_lock (&mu); for (i = 0; i != 50; i++) { nsync_time end_time; nsync_time start_time; nsync_time expected_end_time; - start_time = nsync_time_now (); + start_time = nsync_time_now (NSYNC_CLOCK); expected_end_time = nsync_time_add (start_time, nsync_time_ms (87)); - if (nsync_mu_wait_with_deadline (&mu, &false_condition, NULL, NULL, + if (nsync_mu_wait_with_deadline (&mu, &false_condition, NULL, NULL, NSYNC_CLOCK, expected_end_time, NULL) != ETIMEDOUT) { TEST_FATAL (t, ("nsync_mu_wait() returned non-expired for a timeout")); } - end_time = nsync_time_now (); + end_time = nsync_time_now (NSYNC_CLOCK); if (nsync_time_cmp (end_time, nsync_time_sub (expected_end_time, too_early)) < 0) { char *elapsed_str = nsync_time_str (nsync_time_sub (expected_end_time, end_time), 2); TEST_ERROR (t, ("nsync_mu_wait() returned %s too early", elapsed_str)); @@ -271,7 +272,7 @@ static void test_mu_cancel (testing t) { /* The loops below cancel after 87 milliseconds, like the timeout tests above. */ - future_time = nsync_time_add (nsync_time_now (), nsync_time_ms (3600000)); /* test cancels with timeout */ + future_time = nsync_time_add (nsync_time_now (NSYNC_CLOCK), nsync_time_ms (3600000)); /* test cancels with timeout */ too_late_violations = 0; nsync_mu_lock (&mu); @@ -282,18 +283,18 @@ static void test_mu_cancel (testing t) { int x; nsync_note cancel; - start_time = nsync_time_now (); + start_time = nsync_time_now (NSYNC_CLOCK); expected_end_time = nsync_time_add (start_time, nsync_time_ms (87)); - cancel = nsync_note_new (NULL, expected_end_time); + cancel = nsync_note_new (NULL, NSYNC_CLOCK, expected_end_time); x = nsync_mu_wait_with_deadline (&mu, &false_condition, NULL, NULL, - future_time, cancel); + NSYNC_CLOCK, future_time, cancel); if (x != ECANCELED) { TEST_FATAL (t, ("nsync_mu_wait() return non-cancelled (%d) for " "a cancellation; expected %d", x, ECANCELED)); } - end_time = nsync_time_now (); + end_time = nsync_time_now (NSYNC_CLOCK); if (nsync_time_cmp (end_time, nsync_time_sub (expected_end_time, too_early)) < 0) { char *elapsed_str = nsync_time_str (nsync_time_sub (expected_end_time, end_time), 2); TEST_ERROR (t, ("nsync_mu_wait() returned %s too early", elapsed_str)); @@ -304,15 +305,16 @@ static void test_mu_cancel (testing t) { } /* Check that an already cancelled wait returns immediately. */ - start_time = nsync_time_now (); + start_time = nsync_time_now (NSYNC_CLOCK); x = nsync_mu_wait_with_deadline (&mu, &false_condition, NULL, NULL, - nsync_time_no_deadline, cancel); + NSYNC_CLOCK, nsync_time_no_deadline, + cancel); if (x != ECANCELED) { TEST_FATAL (t, ("nsync_mu_wait() returned non-cancelled for a " "cancellation; expected %d", x, ECANCELED)); } - end_time = nsync_time_now (); + end_time = nsync_time_now (NSYNC_CLOCK); if (nsync_time_cmp (end_time, start_time) < 0) { char *elapsed_str = nsync_time_str (nsync_time_sub (expected_end_time, end_time), 2); TEST_ERROR (t, ("nsync_mu_wait() returned %s too early", elapsed_str)); diff --git a/third_party/nsync/testing/note_test.c b/third_party/nsync/testing/note_test.c index 57298683f..871848eca 100644 --- a/third_party/nsync/testing/note_test.c +++ b/third_party/nsync/testing/note_test.c @@ -25,7 +25,7 @@ /* Verify the properties of a prenotified note. */ static void test_note_prenotified (testing t) { int i; - nsync_note n = nsync_note_new (NULL, nsync_time_zero /* prenotified */); + nsync_note n = nsync_note_new (NULL, NSYNC_CLOCK, nsync_time_zero /* prenotified */); nsync_time expiry; expiry = nsync_note_expiry (n); if (nsync_time_cmp (expiry, nsync_time_zero) != 0) { @@ -55,7 +55,7 @@ static void test_note_unnotified (testing t) { nsync_time start; nsync_time waited; nsync_time deadline; - nsync_note n = nsync_note_new (NULL, nsync_time_no_deadline); + nsync_note n = nsync_note_new (NULL, NSYNC_CLOCK, nsync_time_no_deadline); nsync_time expiry; expiry = nsync_note_expiry (n); if (nsync_time_cmp (expiry, nsync_time_no_deadline) != 0) { @@ -68,12 +68,12 @@ static void test_note_unnotified (testing t) { if (nsync_note_wait (n, nsync_time_zero)) { TEST_ERROR (t, ("notified note is notified (poll)")); } - start = nsync_time_now (); - deadline = nsync_time_add (nsync_time_now (), nsync_time_ms (1000)); + start = nsync_time_now (NSYNC_CLOCK); + deadline = nsync_time_add (nsync_time_now (NSYNC_CLOCK), nsync_time_ms (1000)); if (nsync_note_wait (n, deadline)) { TEST_ERROR (t, ("unnotified note is notified (1s wait)")); } - waited = nsync_time_sub (nsync_time_now (), start); + waited = nsync_time_sub (nsync_time_now (NSYNC_CLOCK), start); if (nsync_time_cmp (waited, nsync_time_ms (900)) < 0) { TEST_ERROR (t, ("timed wait on unnotified note returned too quickly (1s wait took %s)", nsync_time_str (waited, 2))); @@ -110,13 +110,13 @@ static void test_note_expiry (testing t) { nsync_time deadline; nsync_note n; - deadline = nsync_time_add (nsync_time_now (), nsync_time_ms (1000)); - n = nsync_note_new (NULL, deadline); - start = nsync_time_now (); + deadline = nsync_time_add (nsync_time_now (NSYNC_CLOCK), nsync_time_ms (1000)); + n = nsync_note_new (NULL, NSYNC_CLOCK, deadline); + start = nsync_time_now (NSYNC_CLOCK); if (!nsync_note_wait (n, nsync_time_no_deadline)) { TEST_ERROR (t, ("expired note is not notified")); } - waited = nsync_time_sub (nsync_time_now (), start); + waited = nsync_time_sub (nsync_time_now (NSYNC_CLOCK), start); if (nsync_time_cmp (waited, nsync_time_ms (900)) < 0) { TEST_ERROR (t, ("note expired too quickly (1s expiry took %s)", nsync_time_str (waited, 2))); @@ -136,13 +136,13 @@ static void test_note_expiry (testing t) { } nsync_note_free (n); - deadline = nsync_time_add (nsync_time_now (), nsync_time_ms (1000)); - n = nsync_note_new (NULL, deadline); - start = nsync_time_now (); + deadline = nsync_time_add (nsync_time_now (NSYNC_CLOCK), nsync_time_ms (1000)); + n = nsync_note_new (NULL, NSYNC_CLOCK, deadline); + start = nsync_time_now (NSYNC_CLOCK); while (!nsync_note_is_notified (n)) { - nsync_time_sleep (nsync_time_ms (10)); + nsync_time_sleep (NSYNC_CLOCK, nsync_time_ms (10)); } - waited = nsync_time_sub (nsync_time_now (), start); + waited = nsync_time_sub (nsync_time_now (NSYNC_CLOCK), start); if (nsync_time_cmp (waited, nsync_time_ms (900)) < 0) { TEST_ERROR (t, ("note expired too quickly (1s expiry took %s)", nsync_time_str (waited, 2))); @@ -164,7 +164,7 @@ static void test_note_expiry (testing t) { } static void notify_at (nsync_note n, nsync_time abs_deadline) { - nsync_time_sleep_until (abs_deadline); + nsync_time_sleep_until (NSYNC_CLOCK, abs_deadline); nsync_note_notify (n); } @@ -177,14 +177,14 @@ static void test_note_notify (testing t) { nsync_time deadline; nsync_note n; - deadline = nsync_time_add (nsync_time_now (), nsync_time_ms (10000)); - n = nsync_note_new (NULL, deadline); - closure_fork (closure_notify (¬ify_at, n, nsync_time_add (nsync_time_now (), nsync_time_ms (1000)))); - start = nsync_time_now (); + deadline = nsync_time_add (nsync_time_now (NSYNC_CLOCK), nsync_time_ms (10000)); + n = nsync_note_new (NULL, NSYNC_CLOCK, deadline); + closure_fork (closure_notify (¬ify_at, n, nsync_time_add (nsync_time_now (NSYNC_CLOCK), nsync_time_ms (1000)))); + start = nsync_time_now (NSYNC_CLOCK); if (!nsync_note_wait (n, nsync_time_no_deadline)) { TEST_ERROR (t, ("expired note is not notified")); } - waited = nsync_time_sub (nsync_time_now (), start); + waited = nsync_time_sub (nsync_time_now (NSYNC_CLOCK), start); if (nsync_time_cmp (waited, nsync_time_ms (900)) < 0) { TEST_ERROR (t, ("note expired too quickly (1s expiry took %s)", nsync_time_str (waited, 2))); @@ -204,14 +204,14 @@ static void test_note_notify (testing t) { } nsync_note_free (n); - deadline = nsync_time_add (nsync_time_now (), nsync_time_ms (10000)); - n = nsync_note_new (NULL, deadline); - closure_fork (closure_notify (¬ify_at, n, nsync_time_add (nsync_time_now (), nsync_time_ms (1000)))); - start = nsync_time_now (); + deadline = nsync_time_add (nsync_time_now (NSYNC_CLOCK), nsync_time_ms (10000)); + n = nsync_note_new (NULL, NSYNC_CLOCK, deadline); + closure_fork (closure_notify (¬ify_at, n, nsync_time_add (nsync_time_now (NSYNC_CLOCK), nsync_time_ms (1000)))); + start = nsync_time_now (NSYNC_CLOCK); while (!nsync_note_is_notified (n)) { - nsync_time_sleep (nsync_time_ms (10)); + nsync_time_sleep (NSYNC_CLOCK, nsync_time_ms (10)); } - waited = nsync_time_sub (nsync_time_now (), start); + waited = nsync_time_sub (nsync_time_now (NSYNC_CLOCK), start); if (nsync_time_cmp (waited, nsync_time_ms (900)) < 0) { TEST_ERROR (t, ("note expired too quickly (1s expiry took %s)", nsync_time_str (waited, 2))); @@ -253,9 +253,9 @@ static void test_note_in_tree (testing t) { nsync_note node[count_i]; /* Initialize heap structure in the nodes. No deadlines. */ - node[0] = nsync_note_new (NULL, nsync_time_no_deadline); + node[0] = nsync_note_new (NULL, NSYNC_CLOCK, nsync_time_no_deadline); for (i = 1; i != count_i; i++) { - node[i] = nsync_note_new (node[(i-1)/2], nsync_time_no_deadline); + node[i] = nsync_note_new (node[(i-1)/2], NSYNC_CLOCK, nsync_time_no_deadline); } /* check that the nodes are not yet notified. */ @@ -285,14 +285,14 @@ static void test_note_in_tree (testing t) { } /* Initialize heap structure in the nodes. The focus node has a 1s deadline. */ - node[0] = nsync_note_new (NULL, nsync_time_no_deadline); + node[0] = nsync_note_new (NULL, NSYNC_CLOCK, nsync_time_no_deadline); for (i = 1; i != count_i; i++) { nsync_time deadline; - deadline = nsync_time_add (nsync_time_now (), nsync_time_ms (1000)); + deadline = nsync_time_add (nsync_time_now (NSYNC_CLOCK), nsync_time_ms (1000)); if (i != focus_i) { deadline = nsync_time_no_deadline; } - node[i] = nsync_note_new (node[(i - 1) / 2], deadline); + node[i] = nsync_note_new (node[(i - 1) / 2], NSYNC_CLOCK, deadline); } /* check that the nodes are not yet notified. */ @@ -303,7 +303,7 @@ static void test_note_in_tree (testing t) { } /* Wait for timer to go off. */ - nsync_time_sleep (nsync_time_ms (1100)); + nsync_time_sleep (NSYNC_CLOCK, nsync_time_ms (1100)); /* Check that the right nodes have been notified. */ for (i = 0; i != count_i; i++) { diff --git a/third_party/nsync/testing/once_test.c b/third_party/nsync/testing/once_test.c index 6e411d761..0114d7286 100644 --- a/third_party/nsync/testing/once_test.c +++ b/third_party/nsync/testing/once_test.c @@ -76,7 +76,7 @@ static void once_thread (struct once_test_thread_s *lott) { nsync_mu_lock (&ott_s_mu); s = lott->s; nsync_mu_unlock (&ott_s_mu); - nsync_time_sleep (nsync_time_s_ns (0, 1 * 1000 * 1000)); + nsync_time_sleep (NSYNC_CLOCK, nsync_time_s_ns (0, 1 * 1000 * 1000)); switch (lott->id & 3) { case 0: nsync_run_once (&s->once, &once_func0); break; case 1: nsync_run_once_spin (&s->once, &once_func1); break; @@ -111,7 +111,7 @@ static void test_once_run (testing t) { closure_fork (closure_once_thread (&once_thread, &ott[j])); } - if (nsync_counter_wait (s->done, + if (nsync_counter_wait (s->done, NSYNC_CLOCK, nsync_time_no_deadline) != 0) { TEST_ERROR (t, ("s.done not decremented to 0")); } diff --git a/third_party/nsync/testing/pingpong_test.c b/third_party/nsync/testing/pingpong_test.c index 00d1fa4cc..67eeb6ede 100644 --- a/third_party/nsync/testing/pingpong_test.c +++ b/third_party/nsync/testing/pingpong_test.c @@ -17,9 +17,9 @@ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/calls/struct/timespec.h" #include "libc/str/str.h" -#include "libc/sysv/consts/clock.h" #include "libc/thread/thread.h" #include "libc/thread/thread2.h" +#include "third_party/nsync/time.h" #include "third_party/nsync/cv.h" #include "third_party/nsync/mu.h" #include "third_party/nsync/mu_wait.h" @@ -107,7 +107,7 @@ static void mutex_cv_ping_pong (ping_pong *pp, int parity) { nsync_cv_wait_with_deadline_generic (&pp->cv[parity], &pp->mutex, &void_pthread_mutex_lock, &void_pthread_mutex_unlock, - CLOCK_REALTIME, + NSYNC_CLOCK, nsync_time_no_deadline, NULL); } pp->i++; @@ -159,12 +159,12 @@ static void benchmark_ping_pong_mu_cv (testing t) { /* Run by each thread in benchmark_ping_pong_mu_cv_unexpired_deadline(). */ static void mu_cv_unexpired_deadline_ping_pong (ping_pong *pp, int parity) { nsync_time deadline_in1hour; - deadline_in1hour = nsync_time_add (nsync_time_now (), nsync_time_ms (3600000)); + deadline_in1hour = nsync_time_add (nsync_time_now (NSYNC_CLOCK), nsync_time_ms (3600000)); nsync_mu_lock (&pp->mu); while (pp->i < pp->limit) { while ((pp->i & 1) == parity) { nsync_cv_wait_with_deadline (&pp->cv[parity], &pp->mu, - CLOCK_REALTIME, deadline_in1hour, + NSYNC_CLOCK, deadline_in1hour, NULL); } pp->i++; @@ -200,11 +200,11 @@ static const condition_func condition[] = { &even_ping_pong, &odd_ping_pong }; /* Run by each thread in benchmark_ping_pong_mu_unexpired_deadline(). */ static void mu_unexpired_deadline_ping_pong (ping_pong *pp, int parity) { nsync_time deadline_in1hour; - deadline_in1hour = nsync_time_add (nsync_time_now (), nsync_time_ms (3600000)); + deadline_in1hour = nsync_time_add (nsync_time_now (NSYNC_CLOCK), nsync_time_ms (3600000)); nsync_mu_lock (&pp->mu); while (pp->i < pp->limit) { nsync_mu_wait_with_deadline (&pp->mu, condition[parity], pp, NULL, - deadline_in1hour, NULL); + NSYNC_CLOCK, deadline_in1hour, NULL); pp->i++; } nsync_mu_unlock (&pp->mu); @@ -227,7 +227,7 @@ static void benchmark_ping_pong_mu_unexpired_deadline (testing t) { /* Run by each thread in benchmark_ping_pong_mutex_cond_unexpired_deadline(). */ static void mutex_cond_unexpired_deadline_ping_pong (ping_pong *pp, int parity) { struct timespec ts; - clock_gettime (CLOCK_REALTIME, &ts); + clock_gettime (NSYNC_CLOCK, &ts); ts.tv_sec += 3600; pthread_mutex_lock (&pp->mutex); while (pp->i < pp->limit) { @@ -320,7 +320,7 @@ static void rw_mutex_cv_ping_pong (ping_pong *pp, int parity) { nsync_cv_wait_with_deadline_generic (&pp->cv[parity], &pp->rwmutex, &void_pthread_rwlock_wrlock, &void_pthread_rwlock_unlock, - CLOCK_REALTIME, + NSYNC_CLOCK, nsync_time_no_deadline, NULL); } pp->i++; @@ -353,7 +353,8 @@ static void wait_n_cv_ping_pong (ping_pong *pp, int parity) { while ((pp->i & 1) == parity) { nsync_wait_n (&pp->mu, (void (*) (void *)) &nsync_mu_lock, (void (*) (void *)) &nsync_mu_unlock, - nsync_time_no_deadline, 1, &pwaitable); + NSYNC_CLOCK, nsync_time_no_deadline, 1, + &pwaitable); } pp->i++; nsync_cv_signal (&pp->cv[1 - parity]); diff --git a/third_party/nsync/testing/start_thread.c b/third_party/nsync/testing/start_thread.c index f4e122d9c..b025e710d 100644 --- a/third_party/nsync/testing/start_thread.c +++ b/third_party/nsync/testing/start_thread.c @@ -16,6 +16,9 @@ │ limitations under the License. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/mem/mem.h" +#include "libc/stdio/stdio.h" +#include "libc/str/str.h" +#include "libc/runtime/runtime.h" #include "libc/thread/thread.h" struct thd_args { @@ -35,6 +38,10 @@ void nsync_start_thread_ (void (*f) (void *), void *arg) { pthread_t t; args->f = f; args->arg = arg; - pthread_create (&t, NULL, body, args); + errno_t err = pthread_create (&t, NULL, body, args); + if (err) { + fprintf(stderr, "pthread_create: %s\n", strerror(err)); + exit(1); + } pthread_detach (t); } diff --git a/third_party/nsync/testing/testing.c b/third_party/nsync/testing/testing.c index 321e752b0..062dee306 100644 --- a/third_party/nsync/testing/testing.c +++ b/third_party/nsync/testing/testing.c @@ -239,9 +239,9 @@ static void run_test (testing t) { t->test_status = 0; t->n = 0; t->stop_time = nsync_time_zero; - t->start_time = nsync_time_now (); + t->start_time = nsync_time_now (NSYNC_CLOCK); (*t->f) (t); - elapsed_str = nsync_time_str (nsync_time_sub (nsync_time_now (), t->start_time), 2); + elapsed_str = nsync_time_str (nsync_time_sub (nsync_time_now (NSYNC_CLOCK), t->start_time), 2); if (!ATM_LOAD (&t->partial_line)) { fprintf (t->fp, "%-25s %-45s %s %8s\n", tb->prog, t->name, t->test_status != 0? "failed": "passed", elapsed_str); @@ -275,9 +275,9 @@ static void run_benchmark (testing t) { t->test_status = 0; t->n = n; t->stop_time = nsync_time_zero; - t->start_time = nsync_time_now (); + t->start_time = nsync_time_now (NSYNC_CLOCK); (*t->f) (t); - elapsed = nsync_time_to_dbl (nsync_time_sub (nsync_time_now (), t->start_time)); + elapsed = nsync_time_to_dbl (nsync_time_sub (nsync_time_now (NSYNC_CLOCK), t->start_time)); if (elapsed < 1e-1) { elapsed = 1e-1; } @@ -445,9 +445,9 @@ int testing_is_uniprocessor (testing t) { ATM_STORE_REL (&state, 0); closure_fork (closure_uniprocessor_check (&uniprocessor_check, &state, &s[0])); - nsync_time_sleep (nsync_time_ms (100)); + nsync_time_sleep (NSYNC_CLOCK, nsync_time_ms (100)); ATM_STORE_REL (&state, 1); - nsync_time_sleep (nsync_time_ms (400)); + nsync_time_sleep (NSYNC_CLOCK, nsync_time_ms (400)); ATM_STORE_REL (&state, 2); while (!ATM_LOAD_ACQ (&s[0].done)) { } @@ -455,9 +455,9 @@ int testing_is_uniprocessor (testing t) { ATM_STORE_REL (&state, 0); closure_fork (closure_uniprocessor_check (&uniprocessor_check, &state, &s[1])); closure_fork (closure_uniprocessor_check (&uniprocessor_check, &state, &s[2])); - nsync_time_sleep (nsync_time_ms (100)); + nsync_time_sleep (NSYNC_CLOCK, nsync_time_ms (100)); ATM_STORE_REL (&state, 1); - nsync_time_sleep (nsync_time_ms (400)); + nsync_time_sleep (NSYNC_CLOCK, nsync_time_ms (400)); ATM_STORE_REL (&state, 2); while (!ATM_LOAD_ACQ (&s[1].done) || !ATM_LOAD_ACQ (&s[2].done)) { } @@ -472,7 +472,7 @@ void testing_stop_timer (testing t) { if (nsync_time_cmp (t->stop_time, nsync_time_zero) != 0) { abort (); } - t->stop_time = nsync_time_now (); + t->stop_time = nsync_time_now (NSYNC_CLOCK); } void testing_start_timer (testing t) { @@ -480,7 +480,7 @@ void testing_start_timer (testing t) { abort (); } t->start_time = nsync_time_add (t->start_time, - nsync_time_sub (nsync_time_now (), t->stop_time)); + nsync_time_sub (nsync_time_now (NSYNC_CLOCK), t->stop_time)); t->stop_time = nsync_time_zero; } diff --git a/third_party/nsync/testing/wait_test.c b/third_party/nsync/testing/wait_test.c index 6e3c51161..567f35979 100644 --- a/third_party/nsync/testing/wait_test.c +++ b/third_party/nsync/testing/wait_test.c @@ -17,6 +17,7 @@ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/str/str.h" #include "third_party/nsync/array.internal.h" +#include "third_party/nsync/time.h" #include "third_party/nsync/counter.h" #include "third_party/nsync/note.h" #include "third_party/nsync/testing/closure.h" @@ -24,10 +25,12 @@ #include "third_party/nsync/testing/testing.h" #include "third_party/nsync/testing/time_extra.h" #include "third_party/nsync/time.h" +#include "libc/calls/calls.h" +#include "libc/dce.h" #include "third_party/nsync/waiter.h" static void decrement_at (nsync_counter c, nsync_time abs_deadline, nsync_counter done) { - nsync_time_sleep_until (abs_deadline); + nsync_time_sleep_until (NSYNC_CLOCK, abs_deadline); nsync_counter_add (c, -1); nsync_counter_add (done, -1); } @@ -35,7 +38,7 @@ static void decrement_at (nsync_counter c, nsync_time abs_deadline, nsync_counte CLOSURE_DECL_BODY3 (decrement, nsync_counter, nsync_time, nsync_counter) static void notify_at (nsync_note n, nsync_time abs_deadline, nsync_counter done) { - nsync_time_sleep_until (abs_deadline); + nsync_time_sleep_until (NSYNC_CLOCK, abs_deadline); nsync_note_notify (n); nsync_counter_add (done, -1); } @@ -61,7 +64,7 @@ static void test_wait_n (testing t) { a_pwaitable apw; bzero (&aw, sizeof (aw)); bzero (&apw, sizeof (apw)); - now = nsync_time_now (); + now = nsync_time_now (NSYNC_CLOCK); deadline = nsync_time_add (now, nsync_time_ms (100)); for (j = A_LEN (&aw); A_LEN (&aw) < j+ncounter;) { nsync_counter c = nsync_counter_new (0); @@ -75,28 +78,28 @@ static void test_wait_n (testing t) { } } for (j = A_LEN (&aw); A_LEN (&aw) < j+nnote;) { - nsync_note n = nsync_note_new (NULL, nsync_time_no_deadline); + nsync_note n = nsync_note_new (NULL, NSYNC_CLOCK, nsync_time_no_deadline); struct nsync_waitable_s *w = &A_PUSH (&aw); w->v = n; w->funcs = &nsync_note_waitable_funcs; nsync_counter_add (done, 1); closure_fork (closure_notify (¬ify_at, n, deadline, done)); for (k = 0; k != 4 && A_LEN (&aw) < j+nnote; k++) { - nsync_note cn = nsync_note_new (n, nsync_time_no_deadline); + nsync_note cn = nsync_note_new (n, NSYNC_CLOCK, nsync_time_no_deadline); struct nsync_waitable_s *lw = &A_PUSH (&aw); lw->v = cn; lw->funcs = &nsync_note_waitable_funcs; } } for (j = A_LEN (&aw); A_LEN (&aw) < j+nnote_expire;) { - nsync_note n = nsync_note_new (NULL, deadline); + nsync_note n = nsync_note_new (NULL, NSYNC_CLOCK, deadline); struct nsync_waitable_s *w = &A_PUSH (&aw); w->v = n; w->funcs = &nsync_note_waitable_funcs; nsync_counter_add (done, 1); closure_fork (closure_notify (¬ify_at, n, deadline, done)); for (k = 0; k != 4 && A_LEN (&aw) < j+nnote; k++) { - nsync_note cn = nsync_note_new (n, nsync_time_no_deadline); + nsync_note cn = nsync_note_new (n, NSYNC_CLOCK, nsync_time_no_deadline); struct nsync_waitable_s *lw = &A_PUSH (&aw); lw->v = cn; lw->funcs = &nsync_note_waitable_funcs; @@ -109,7 +112,8 @@ static void test_wait_n (testing t) { A_PUSH (&apw) = &A (&aw, j); } while (A_LEN (&apw) != 0) { - k = nsync_wait_n (NULL, NULL, NULL, nsync_time_no_deadline, + k = nsync_wait_n (NULL, NULL, NULL, + NSYNC_CLOCK, nsync_time_no_deadline, A_LEN (&apw), &A (&apw, 0)); if (k == A_LEN (&apw)) { TEST_ERROR (t, ("nsync_wait_n returned with no waiter ready")); @@ -117,7 +121,7 @@ static void test_wait_n (testing t) { A (&apw, k) = A (&apw, A_LEN (&apw) - 1); A_DISCARD (&apw, 1); } - nsync_counter_wait (done, nsync_time_no_deadline); + nsync_counter_wait (done, NSYNC_CLOCK, nsync_time_no_deadline); for (k = 0; k != ncounter; k++) { nsync_counter_free ((nsync_counter) A (&aw, k).v); } @@ -159,7 +163,7 @@ static void test_wait_n_ready_while_queuing (testing t) { wrapped_note_waitable_funcs.ready_time = ¬e_ready_time_wrapper; for (count = 0; count != sizeof (w) / sizeof (w[0]); count++) { - nsync_note n = nsync_note_new (NULL, nsync_time_no_deadline); + nsync_note n = nsync_note_new (NULL, NSYNC_CLOCK, nsync_time_no_deadline); if (nsync_note_is_notified (n)) { TEST_ERROR (t, ("nsync_note is unexpectedly notified")); } @@ -167,8 +171,8 @@ static void test_wait_n_ready_while_queuing (testing t) { w[count].funcs = &wrapped_note_waitable_funcs; pw[count] = &w[count]; } - woken = nsync_wait_n (NULL, NULL, NULL, nsync_time_no_deadline, - count, pw); + woken = nsync_wait_n (NULL, NULL, NULL, NSYNC_CLOCK, + nsync_time_no_deadline, count, pw); if (woken != 0) { TEST_ERROR (t, ("nsync_wait_n unexpectedly failed to find pw[0] notified")); } @@ -183,6 +187,9 @@ static void test_wait_n_ready_while_queuing (testing t) { int main (int argc, char *argv[]) { testing_base tb = testing_new (argc, argv, 0); + // TODO(jart): remove after cosmocc update when process rlimit flake is solved + if (IsAarch64 () && IsQemuUser ()) + return 0; TEST_RUN (tb, test_wait_n); TEST_RUN (tb, test_wait_n_ready_while_queuing); return (testing_base_exit (tb)); diff --git a/third_party/nsync/time.c b/third_party/nsync/time.c new file mode 100644 index 000000000..996459176 --- /dev/null +++ b/third_party/nsync/time.c @@ -0,0 +1,26 @@ +/*-*- mode:c;indent-tabs-mode:t;c-basic-offset:8;tab-width:8;coding:utf-8 -*-│ +│ vi: set noet ft=c ts=8 sw=8 fenc=utf-8 :vi │ +╞══════════════════════════════════════════════════════════════════════════════╡ +│ Copyright 2016 Google Inc. │ +│ │ +│ Licensed under the Apache License, Version 2.0 (the "License"); │ +│ you may not use this file except in compliance with the License. │ +│ You may obtain a copy of the License at │ +│ │ +│ http://www.apache.org/licenses/LICENSE-2.0 │ +│ │ +│ Unless required by applicable law or agreed to in writing, software │ +│ distributed under the License is distributed on an "AS IS" BASIS, │ +│ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. │ +│ See the License for the specific language governing permissions and │ +│ limitations under the License. │ +╚─────────────────────────────────────────────────────────────────────────────*/ +#include "third_party/nsync/time.h" + +/* Return the current time since the epoch. */ +nsync_time nsync_time_now(int clock) { + nsync_time result; + if (clock_gettime (clock, &result)) + __builtin_trap(); + return result; +} diff --git a/third_party/nsync/time.h b/third_party/nsync/time.h index badd254cd..774555685 100644 --- a/third_party/nsync/time.h +++ b/third_party/nsync/time.h @@ -1,8 +1,11 @@ #ifndef NSYNC_TIME_H_ #define NSYNC_TIME_H_ +#include "libc/sysv/consts/clock.h" #include "libc/calls/struct/timespec.h" COSMOPOLITAN_C_START_ +#define NSYNC_CLOCK CLOCK_REALTIME + #define NSYNC_TIME_SEC(t) ((t).tv_sec) #define NSYNC_TIME_NSEC(t) ((t).tv_nsec) #define NSYNC_TIME_STATIC_INIT(t, ns) \ @@ -22,15 +25,15 @@ typedef struct timespec nsync_time; #define nsync_time_zero timespec_zero /* Return the current time since the epoch. */ -#define nsync_time_now() timespec_real() +nsync_time nsync_time_now(int clock); /* Sleep for the specified delay. Returns the unslept time which may be non-zero if the call was interrupted. */ -#define nsync_time_sleep(a) timespec_sleep(a) +#define nsync_time_sleep(c,a) timespec_sleep(c,a) /* Sleep until the specified time. Returns 0 on success, and EINTR if the call was interrupted. */ -#define nsync_time_sleep_until(a) timespec_sleep_until(a) +#define nsync_time_sleep_until(c,a) timespec_sleep_until(c,a) /* Return a+b */ #define nsync_time_add(a, b) timespec_add(a, b) diff --git a/third_party/python/Modules/timemodule.c b/third_party/python/Modules/timemodule.c index 9dbabc98c..136696c69 100644 --- a/third_party/python/Modules/timemodule.c +++ b/third_party/python/Modules/timemodule.c @@ -1052,14 +1052,9 @@ _PyTime_GetProcessTimeWithInfo(_PyTime_t *tp, _Py_clock_info_t *info) *tp = (ReadFileTime(kernel_time) + ReadFileTime(user_time)) * 100; return 0; } - if (CLOCK_PROF != -1 || CLOCK_PROCESS_CPUTIME_ID != -1) { - if (CLOCK_PROF != -1) { - clk_id = CLOCK_PROF; - function = "clock_gettime(CLOCK_PROF)"; - } else { - clk_id = CLOCK_PROCESS_CPUTIME_ID; - function = "clock_gettime(CLOCK_PROCESS_CPUTIME_ID)"; - } + if (CLOCK_PROCESS_CPUTIME_ID != -1) { + clk_id = CLOCK_PROCESS_CPUTIME_ID; + function = "clock_gettime(CLOCK_PROCESS_CPUTIME_ID)"; if (!clock_gettime(clk_id, &ts)) { if (info) { info->implementation = function; diff --git a/tool/build/compile.c b/tool/build/compile.c index a81b119f7..3f88327dd 100644 --- a/tool/build/compile.c +++ b/tool/build/compile.c @@ -111,9 +111,9 @@ FLAGS\n\ -T TARGET specifies target name for V=0 logging\n\ -A ACTION specifies short command name for V=0 logging\n\ -V NUMBER specifies compiler version\n\ - -C SECS set cpu limit [default 16]\n\ + -C SECS set cpu limit [default 32]\n\ -L SECS set lat limit [default 90]\n\ - -P PROCS set pro limit [default 4096]\n\ + -P PROCS set pro limit [default 8192]\n\ -S BYTES set stk limit [default 8m]\n\ -M BYTES set mem limit [default 2048m]\n\ -F BYTES set fsz limit [default 256m]\n\ @@ -862,7 +862,7 @@ int main(int argc, char *argv[]) { verbose = 4; timeout = 90; // secs cpuquota = 32; // secs - proquota = 4096; // procs + proquota = 8192; // procs stkquota = 8 * 1024 * 1024; // bytes fszquota = 256 * 1000 * 1000; // bytes memquota = 2048L * 1024 * 1024; // bytes diff --git a/tool/build/runitd.c b/tool/build/runitd.c index 4f512b69a..fbe2d4f62 100644 --- a/tool/build/runitd.c +++ b/tool/build/runitd.c @@ -49,6 +49,7 @@ #include "libc/stdio/append.h" #include "libc/stdio/rand.h" #include "libc/stdio/stdio.h" +#include "libc/stdio/sysparam.h" #include "libc/str/str.h" #include "libc/sysv/consts/af.h" #include "libc/sysv/consts/at.h" @@ -626,8 +627,8 @@ RetryOnEtxtbsyRaceCondition: fds[1].fd = client->pipe[0]; fds[1].events = POLLIN; ts1 = timespec_real(); - events = poll(fds, ARRAYLEN(fds), - timespec_tomillis(timespec_sub(deadline, now))); + int64_t ms = timespec_tomillis(timespec_sub(deadline, now)); + events = poll(fds, ARRAYLEN(fds), MIN(ms, -1u)); DEBUF("it took %'zu us to call poll", timespec_tomicros(timespec_sub(timespec_real(), ts1))); if (events == -1) { diff --git a/tool/net/definitions.lua b/tool/net/definitions.lua index 2424f9241..7bc219177 100644 --- a/tool/net/definitions.lua +++ b/tool/net/definitions.lua @@ -4129,38 +4129,22 @@ unix = { CLK_TCK = nil, --- @type integer - CLOCK_BOOTTIME = nil, - --- @type integer - CLOCK_BOOTTIME_ALARM = nil, + CLOCK_REALTIME = nil, --- @type integer CLOCK_MONOTONIC = nil, --- @type integer - CLOCK_MONOTONIC_COARSE = nil, - --- @type integer - CLOCK_MONOTONIC_PRECISE = nil, - --- @type integer - CLOCK_MONOTONIC_FAST = nil, + CLOCK_BOOTTIME = nil, --- @type integer CLOCK_MONOTONIC_RAW = nil, --- @type integer - CLOCK_PROCESS_CPUTIME_ID = nil, - --- @type integer - CLOCK_PROF = nil, - --- @type integer - CLOCK_REALTIME = nil, - --- @type integer - CLOCK_REALTIME_PRECISE = nil, - --- @type integer - CLOCK_REALTIME_ALARM = nil, - --- @type integer CLOCK_REALTIME_COARSE = nil, --- @type integer - CLOCK_REALTIME_FAST = nil, - --- @type integer - CLOCK_TAI = nil, + CLOCK_MONOTONIC_COARSE = nil, ---@type integer CLOCK_THREAD_CPUTIME_ID = nil, --- @type integer + CLOCK_PROCESS_CPUTIME_ID = nil, + --- @type integer DT_BLK = nil, --- @type integer DT_CHR = nil, @@ -6097,23 +6081,73 @@ function unix.syslog(priority, msg) end --- --- `clock` can be any one of of: --- ---- - `CLOCK_REALTIME`: universally supported ---- - `CLOCK_REALTIME_FAST`: ditto but faster on freebsd ---- - `CLOCK_REALTIME_PRECISE`: ditto but better on freebsd ---- - `CLOCK_REALTIME_COARSE`: : like `CLOCK_REALTIME_FAST` but needs Linux 2.6.32+ ---- - `CLOCK_MONOTONIC`: universally supported ---- - `CLOCK_MONOTONIC_FAST`: ditto but faster on freebsd ---- - `CLOCK_MONOTONIC_PRECISE`: ditto but better on freebsd ---- - `CLOCK_MONOTONIC_COARSE`: : like `CLOCK_MONOTONIC_FAST` but needs Linux 2.6.32+ ---- - `CLOCK_MONOTONIC_RAW`: is actually monotonic but needs Linux 2.6.28+ ---- - `CLOCK_PROCESS_CPUTIME_ID`: linux and bsd ---- - `CLOCK_THREAD_CPUTIME_ID`: linux and bsd ---- - `CLOCK_MONOTONIC_COARSE`: linux, freebsd ---- - `CLOCK_PROF`: linux and netbsd ---- - `CLOCK_BOOTTIME`: linux and openbsd ---- - `CLOCK_REALTIME_ALARM`: linux-only ---- - `CLOCK_BOOTTIME_ALARM`: linux-only ---- - `CLOCK_TAI`: linux-only +--- - `CLOCK_REALTIME` returns a wall clock timestamp represented in +--- nanoseconds since the UNIX epoch (~1970). It'll count time in the +--- suspend state. This clock is subject to being smeared by various +--- adjustments made by NTP. These timestamps can have unpredictable +--- discontinuous jumps when clock_settime() is used. Therefore this +--- clock is the default clock for everything, even pthread condition +--- variables. Cosmopoiltan guarantees this clock will never raise +--- `EINVAL` and also guarantees `CLOCK_REALTIME == 0` will always be +--- the case. On Windows this maps to GetSystemTimePreciseAsFileTime(). +--- On platforms with vDSOs like Linux, Windows, and MacOS ARM64 this +--- should take about 20 nanoseconds. +--- +--- - `CLOCK_MONOTONIC` returns a timestamp with an unspecified epoch, +--- that should be when the system was powered on. These timestamps +--- shouldn't go backwards. Timestamps shouldn't count time spent in +--- the sleep, suspend, and hibernation states. These timestamps won't +--- be impacted by clock_settime(). These timestamps may be impacted by +--- frequency adjustments made by NTP. Cosmopoiltan guarantees this +--- clock will never raise `EINVAL`. MacOS and BSDs use the word +--- "uptime" to describe this clock. On Windows this maps to +--- QueryUnbiasedInterruptTimePrecise(). +--- +--- - `CLOCK_BOOTTIME` is a monotonic clock returning a timestamp with an +--- unspecified epoch, that should be relative to when the host system +--- was powered on. These timestamps shouldn't go backwards. Timestamps +--- should also include time spent in a sleep, suspend, or hibernation +--- state. These timestamps aren't impacted by clock_settime(), but +--- they may be impacted by frequency adjustments made by NTP. This +--- clock will raise an `EINVAL` error on extremely old Linux distros +--- like RHEL5. MacOS and BSDs use the word "monotonic" to describe +--- this clock. On Windows this maps to QueryInterruptTimePrecise(). +--- +--- - `CLOCK_MONOTONIC_RAW` returns a timestamp from an unspecified +--- epoch. These timestamps don't count time spent in the sleep, +--- suspend, and hibernation states. Unlike `CLOCK_MONOTONIC` this +--- clock is guaranteed to not be impacted by frequency adjustments or +--- discontinuous jumps caused by clock_settime(). Providing this level +--- of assurances may make this clock slower than the normal monotonic +--- clock. Furthermore this clock may cause `EINVAL` to be raised if +--- running on a host system that doesn't provide those guarantees, +--- e.g. OpenBSD and MacOS on AMD64. +--- +--- - `CLOCK_REALTIME_COARSE` is the same as `CLOCK_REALTIME` except +--- it'll go faster if the host OS provides a cheaper way to read the +--- wall time. Please be warned that coarse can be really coarse. +--- Rather than nano precision, you're looking at `CLK_TCK` precision, +--- which can lag as far as 30 milliseconds behind or possibly more. +--- Cosmopolitan may fallback to `CLOCK_REALTIME` if a faster less +--- accurate clock isn't provided by the system. This clock will raise +--- an `EINVAL` error on extremely old Linux distros like RHEL5. +--- +--- - `CLOCK_MONOTONIC_COARSE` is the same as `CLOCK_MONOTONIC` except +--- it'll go faster if the host OS provides a cheaper way to read the +--- unbiased time. Please be warned that coarse can be really coarse. +--- Rather than nano precision, you're looking at `CLK_TCK` precision, +--- which can lag as far as 30 milliseconds behind or possibly more. +--- Cosmopolitan may fallback to `CLOCK_REALTIME` if a faster less +--- accurate clock isn't provided by the system. This clock will raise +--- an `EINVAL` error on extremely old Linux distros like RHEL5. +--- +--- - `CLOCK_PROCESS_CPUTIME_ID` returns the amount of time this process +--- was actively scheduled. This is similar to getrusage() and clock(). +--- Cosmopoiltan guarantees this clock will never raise `EINVAL`. +--- +--- - `CLOCK_THREAD_CPUTIME_ID` returns the amount of time this thread +--- was actively scheduled. This is similar to getrusage() and clock(). +--- Cosmopoiltan guarantees this clock will never raise `EINVAL`. --- --- Returns `EINVAL` if clock isn't supported on platform. --- diff --git a/tool/net/help.txt b/tool/net/help.txt index efb814c3d..a217b7f07 100644 --- a/tool/net/help.txt +++ b/tool/net/help.txt @@ -3673,22 +3673,73 @@ UNIX MODULE `clock` can be any one of of: - - `CLOCK_REALTIME`: universally supported - - `CLOCK_REALTIME_FAST`: ditto but faster on freebsd - - `CLOCK_REALTIME_PRECISE`: ditto but better on freebsd - - `CLOCK_REALTIME_COARSE`: : like `CLOCK_REALTIME_FAST` but needs Linux 2.6.32+ - - `CLOCK_MONOTONIC`: universally supported - - `CLOCK_MONOTONIC_FAST`: ditto but faster on freebsd - - `CLOCK_MONOTONIC_PRECISE`: ditto but better on freebsd - - `CLOCK_MONOTONIC_COARSE`: : like `CLOCK_MONOTONIC_FAST` but needs Linux 2.6.32+ - - `CLOCK_MONOTONIC_RAW`: is actually monotonic but needs Linux 2.6.28+ - - `CLOCK_PROCESS_CPUTIME_ID`: linux and bsd - - `CLOCK_THREAD_CPUTIME_ID`: linux and bsd - - `CLOCK_PROF`: linux and netbsd - - `CLOCK_BOOTTIME`: linux and openbsd - - `CLOCK_REALTIME_ALARM`: linux-only - - `CLOCK_BOOTTIME_ALARM`: linux-only - - `CLOCK_TAI`: linux-only + - `CLOCK_REALTIME` returns a wall clock timestamp represented in + nanoseconds since the UNIX epoch (~1970). It'll count time in the + suspend state. This clock is subject to being smeared by various + adjustments made by NTP. These timestamps can have unpredictable + discontinuous jumps when clock_settime() is used. Therefore this + clock is the default clock for everything, even pthread condition + variables. Cosmopoiltan guarantees this clock will never raise + `EINVAL` and also guarantees `CLOCK_REALTIME == 0` will always be + the case. On Windows this maps to GetSystemTimePreciseAsFileTime(). + On platforms with vDSOs like Linux, Windows, and MacOS ARM64 this + should take about 20 nanoseconds. + + - `CLOCK_MONOTONIC` returns a timestamp with an unspecified epoch, + that should be when the system was powered on. These timestamps + shouldn't go backwards. Timestamps shouldn't count time spent in + the sleep, suspend, and hibernation states. These timestamps won't + be impacted by clock_settime(). These timestamps may be impacted by + frequency adjustments made by NTP. Cosmopoiltan guarantees this + clock will never raise `EINVAL`. MacOS and BSDs use the word + "uptime" to describe this clock. On Windows this maps to + QueryUnbiasedInterruptTimePrecise(). + + - `CLOCK_BOOTTIME` is a monotonic clock returning a timestamp with an + unspecified epoch, that should be relative to when the host system + was powered on. These timestamps shouldn't go backwards. Timestamps + should also include time spent in a sleep, suspend, or hibernation + state. These timestamps aren't impacted by clock_settime(), but + they may be impacted by frequency adjustments made by NTP. This + clock will raise an `EINVAL` error on extremely old Linux distros + like RHEL5. MacOS and BSDs use the word "monotonic" to describe + this clock. On Windows this maps to QueryInterruptTimePrecise(). + + - `CLOCK_MONOTONIC_RAW` returns a timestamp from an unspecified + epoch. These timestamps don't count time spent in the sleep, + suspend, and hibernation states. Unlike `CLOCK_MONOTONIC` this + clock is guaranteed to not be impacted by frequency adjustments or + discontinuous jumps caused by clock_settime(). Providing this level + of assurances may make this clock slower than the normal monotonic + clock. Furthermore this clock may cause `EINVAL` to be raised if + running on a host system that doesn't provide those guarantees, + e.g. OpenBSD and MacOS on AMD64. + + - `CLOCK_REALTIME_COARSE` is the same as `CLOCK_REALTIME` except + it'll go faster if the host OS provides a cheaper way to read the + wall time. Please be warned that coarse can be really coarse. + Rather than nano precision, you're looking at `CLK_TCK` precision, + which can lag as far as 30 milliseconds behind or possibly more. + Cosmopolitan may fallback to `CLOCK_REALTIME` if a faster less + accurate clock isn't provided by the system. This clock will raise + an `EINVAL` error on extremely old Linux distros like RHEL5. + + - `CLOCK_MONOTONIC_COARSE` is the same as `CLOCK_MONOTONIC` except + it'll go faster if the host OS provides a cheaper way to read the + unbiased time. Please be warned that coarse can be really coarse. + Rather than nano precision, you're looking at `CLK_TCK` precision, + which can lag as far as 30 milliseconds behind or possibly more. + Cosmopolitan may fallback to `CLOCK_REALTIME` if a faster less + accurate clock isn't provided by the system. This clock will raise + an `EINVAL` error on extremely old Linux distros like RHEL5. + + - `CLOCK_PROCESS_CPUTIME_ID` returns the amount of time this process + was actively scheduled. This is similar to getrusage() and clock(). + Cosmopoiltan guarantees this clock will never raise `EINVAL`. + + - `CLOCK_THREAD_CPUTIME_ID` returns the amount of time this thread + was actively scheduled. This is similar to getrusage() and clock(). + Cosmopoiltan guarantees this clock will never raise `EINVAL`. Returns `EINVAL` if clock isn't supported on platform. diff --git a/tool/viz/memzoom.c b/tool/viz/memzoom.c index 67afb55e2..30a8492e4 100644 --- a/tool/viz/memzoom.c +++ b/tool/viz/memzoom.c @@ -44,6 +44,7 @@ #include "libc/str/str.h" #include "libc/str/tab.h" #include "libc/str/unicode.h" +#include "libc/sysv/consts/clock.h" #include "libc/sysv/consts/ex.h" #include "libc/sysv/consts/exit.h" #include "libc/sysv/consts/fileno.h" @@ -337,7 +338,7 @@ static void PreventBufferbloat(void) { now = timespec_real(); rate = timespec_frommicros(1. / fps * 1e6); if (timespec_cmp(timespec_sub(now, last), rate) < 0) { - timespec_sleep(timespec_sub(rate, timespec_sub(now, last))); + timespec_sleep(CLOCK_REALTIME, timespec_sub(rate, timespec_sub(now, last))); } last = now; }