From 12d9e1e12859398c1698fcf073aa0d3c67f31a0c Mon Sep 17 00:00:00 2001 From: Justine Tunney Date: Mon, 5 Sep 2022 21:43:49 -0700 Subject: [PATCH] Improve quality of our ANSI C clock() function It now works most excellently across all supported operating sytsems (earlier it didn't work on NT and XNU). Demo code is available in examples/clock.c and this change also adds some of the newer ANSI C time functions like timespec_get(), plus timespec_getres() which hasn't even come out yet as it's C23 --- examples/clock.c | 41 +++++++++++++++ examples/hostname.c | 10 ++-- libc/bits/atomic.h | 0 libc/calls/_timespec_fromnanos.c | 29 +++++++++++ libc/calls/{addtimeval.c => _timeval_add.c} | 0 libc/calls/calls.mk | 2 + libc/calls/clock.c | 57 +++++++++++++-------- libc/calls/clock_getres.c | 5 +- libc/calls/clock_gettime-mono.c | 23 ++++----- libc/calls/clock_gettime.c | 4 +- libc/calls/struct/timespec.h | 3 ++ libc/calls/struct/timespec.internal.h | 5 +- libc/calls/timespec_get.c | 36 +++++++++++++ libc/calls/timespec_getres.c | 36 +++++++++++++ libc/intrin/emmintrin.internal.h | 26 +++++----- libc/intrin/kprintf.greg.c | 11 ++-- libc/sysv/consts.sh | 2 - libc/sysv/consts/CLOCKS_PER_SEC.s | 2 - libc/sysv/consts/SI_KERNEL.s | 2 +- libc/thread/posixthread.internal.h | 4 ++ libc/thread/pthread_create.c | 25 +++++++-- libc/thread/zombie.c | 1 - libc/time/time.h | 5 +- third_party/python/Modules/timemodule.c | 1 - 24 files changed, 254 insertions(+), 76 deletions(-) create mode 100644 examples/clock.c delete mode 100755 libc/bits/atomic.h create mode 100644 libc/calls/_timespec_fromnanos.c rename libc/calls/{addtimeval.c => _timeval_add.c} (100%) create mode 100644 libc/calls/timespec_get.c create mode 100644 libc/calls/timespec_getres.c delete mode 100644 libc/sysv/consts/CLOCKS_PER_SEC.s diff --git a/examples/clock.c b/examples/clock.c new file mode 100644 index 000000000..a2eed57c9 --- /dev/null +++ b/examples/clock.c @@ -0,0 +1,41 @@ +#if 0 +/*─────────────────────────────────────────────────────────────────╗ +│ To the extent possible under law, Justine Tunney has waived │ +│ all copyright and related or neighboring rights to this file, │ +│ as it is written in the following disclaimers: │ +│ • http://unlicense.org/ │ +│ • http://creativecommons.org/publicdomain/zero/1.0/ │ +╚─────────────────────────────────────────────────────────────────*/ +#endif +#include "libc/calls/struct/timespec.h" +#include "libc/stdio/stdio.h" +#include "libc/time/time.h" + +/** + * @fileoverview clock() function demo + */ + +int main(int argc, char *argv[]) { + unsigned long i; + volatile unsigned long x; + struct timespec now, start, next, interval; + printf("hammering the cpu...\n"); + next = start = _timespec_mono(); + interval = _timespec_frommillis(500); + next = _timespec_add(next, interval); + for (;;) { + for (i = 0;; ++i) { + x *= 7; + if (!(i % 256)) { + now = _timespec_mono(); + if (_timespec_gte(now, next)) { + break; + } + } + } + next = _timespec_add(next, interval); + printf("consumed %10g seconds monotonic time and %10g seconds cpu time\n", + _timespec_tonanos(_timespec_sub(now, start)) / 1000000000., + (double)clock() / CLOCKS_PER_SEC); + } +} diff --git a/examples/hostname.c b/examples/hostname.c index 6d076293d..ba276eff2 100644 --- a/examples/hostname.c +++ b/examples/hostname.c @@ -8,14 +8,14 @@ ╚─────────────────────────────────────────────────────────────────*/ #endif #include "libc/calls/calls.h" +#include "libc/intrin/kprintf.h" #include "libc/log/check.h" -#include "libc/stdio/stdio.h" int main(int argc, char *argv[]) { char name[254]; - CHECK_NE(-1, gethostname(name, sizeof(name))); - printf("gethostname() → %`'s\n", name); - CHECK_NE(-1, getdomainname(name, sizeof(name))); - printf("getdomainname() → %`'s\n", name); + gethostname(name, sizeof(name)); + kprintf("gethostname() → %#s\n", name); + getdomainname(name, sizeof(name)); + kprintf("getdomainname() → %#s\n", name); return 0; } diff --git a/libc/bits/atomic.h b/libc/bits/atomic.h deleted file mode 100755 index e69de29bb..000000000 diff --git a/libc/calls/_timespec_fromnanos.c b/libc/calls/_timespec_fromnanos.c new file mode 100644 index 000000000..7e4948b9b --- /dev/null +++ b/libc/calls/_timespec_fromnanos.c @@ -0,0 +1,29 @@ +/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│ +│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│ +╞══════════════════════════════════════════════════════════════════════════════╡ +│ Copyright 2022 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/struct/timespec.h" + +/** + * Converts timespec interval from nanoseconds. + */ +struct timespec _timespec_fromnanos(int64_t x) { + struct timespec ts; + ts.tv_sec = x / 1000000000; + ts.tv_nsec = x % 1000000000; + return ts; +} diff --git a/libc/calls/addtimeval.c b/libc/calls/_timeval_add.c similarity index 100% rename from libc/calls/addtimeval.c rename to libc/calls/_timeval_add.c diff --git a/libc/calls/calls.mk b/libc/calls/calls.mk index 2708a40bd..bab0d35be 100644 --- a/libc/calls/calls.mk +++ b/libc/calls/calls.mk @@ -184,9 +184,11 @@ o//libc/calls/statfs2cosmo.o: private \ # we always want -O2 because: # division is expensive if not optimized +o/$(MODE)/libc/calls/clock.o \ o/$(MODE)/libc/calls/_timespec_tomillis.o \ o/$(MODE)/libc/calls/_timespec_tomicros.o \ o/$(MODE)/libc/calls/_timespec_totimeval.o \ +o/$(MODE)/libc/calls/_timespec_fromnanos.o \ o/$(MODE)/libc/calls/_timespec_frommillis.o \ o/$(MODE)/libc/calls/_timespec_frommicros.o: private \ OVERRIDE_CFLAGS += \ diff --git a/libc/calls/clock.c b/libc/calls/clock.c index 9fcec2fa8..5ac525e0c 100644 --- a/libc/calls/clock.c +++ b/libc/calls/clock.c @@ -16,36 +16,51 @@ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ +#include "libc/calls/struct/rusage.h" #include "libc/calls/struct/timespec.h" -#include "libc/dce.h" -#include "libc/fmt/conv.h" -#include "libc/nt/accounting.h" -#include "libc/nt/runtime.h" -#include "libc/nt/synchronization.h" +#include "libc/calls/struct/timeval.h" +#include "libc/errno.h" #include "libc/sysv/consts/clock.h" +#include "libc/sysv/consts/rusage.h" #include "libc/time/time.h" /** - * Returns how much CPU program has consumed on time-sharing system. + * Returns sum of CPU time consumed by current process since birth. * - * @return value that can be divided by CLOCKS_PER_SEC, or -1 w/ errno - * @see clock_gettime() + * This function provides a basic idea of how computationally expensive + * your program is, in terms of both the userspace and kernel processor + * resources it's hitherto consumed. Here's an example of how you might + * display this information: + * + * printf("consumed %g seconds of cpu time\n", + * (double)clock() / CLOCKS_PER_SEC); + * + * This function offers at best microsecond accuracy on all supported + * platforms. Please note the reported values might be a bit chunkier + * depending on the kernel scheduler sampling interval see `CLK_TCK`. + * + * @return units of CPU time consumed, where each unit's time length + * should be `1./CLOCKS_PER_SEC` seconds; Cosmopolitan currently + * returns the unit count in microseconds, i.e. `CLOCKS_PER_SEC` + * is hard-coded as 1000000. On failure this returns -1 / errno. + * @raise ENOSYS should be returned currently if run on Bare Metal + * @see clock_gettime() which polyfills this on Linux and BSDs + * @see getrusage() which polyfills this on XNU and NT */ int64_t clock(void) { + int e; + struct rusage ru; struct timespec ts; - struct NtFileTime creation_time, exit_time, kernel_time, user_time; - int64_t proc, total; - // polyfill on Windows where CLOCK_PROCESS_CPUTIME_ID may be not available - if (IsWindows() && CLOCK_PROCESS_CPUTIME_ID == -1) { - proc = GetCurrentProcess(); - if (!GetProcessTimes(proc, &creation_time, &exit_time, &kernel_time, - &user_time)) + e = errno; + if (clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &ts) == -1) { + errno = e; + if (getrusage(RUSAGE_SELF, &ru) != -1) { + ts = _timeval_totimespec(_timeval_add(ru.ru_utime, ru.ru_stime)); + } else { return -1; - total = ReadFileTime(kernel_time) + ReadFileTime(user_time); - ts = WindowsDurationToTimeSpec(total); - } else if (clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &ts) == -1) { - return -1; + } } - return ts.tv_sec * CLOCKS_PER_SEC + - ts.tv_nsec / (1000000000 / CLOCKS_PER_SEC); + // convert nanoseconds to microseconds w/ ceil rounding + // this would need roughly ~7,019,309 years to overflow + return ts.tv_sec * 1000000 + (ts.tv_nsec + 999) / 1000; } diff --git a/libc/calls/clock_getres.c b/libc/calls/clock_getres.c index 9794258a7..31d5709e4 100644 --- a/libc/calls/clock_getres.c +++ b/libc/calls/clock_getres.c @@ -25,8 +25,6 @@ #include "libc/sysv/errfuns.h" #include "libc/time/time.h" -int sys_clock_getres(int, struct timespec *) hidden; - static int sys_clock_getres_poly(int clock, struct timespec *ts, int64_t real) { if (clock == CLOCK_REALTIME) { ts->tv_sec = 0; @@ -65,6 +63,7 @@ int clock_getres(int clock, struct timespec *ts) { } else { rc = sys_clock_getres(clock, ts); } - STRACE("clock_getres(%d, [%s]) → %d% m", clock, DescribeTimespec(rc, ts), rc); + STRACE("clock_getres(%s, [%s]) → %d% m", DescribeClockName(clock), + DescribeTimespec(rc, ts), rc); return rc; } diff --git a/libc/calls/clock_gettime-mono.c b/libc/calls/clock_gettime-mono.c index fb937604b..42a88162e 100644 --- a/libc/calls/clock_gettime-mono.c +++ b/libc/calls/clock_gettime-mono.c @@ -16,38 +16,33 @@ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ -#include "libc/calls/clock_gettime.internal.h" #include "libc/calls/struct/timespec.h" #include "libc/intrin/pthread.h" #include "libc/nexgen32e/rdtsc.h" #include "libc/nexgen32e/x86feature.h" #include "libc/sysv/consts/clock.h" #include "libc/sysv/errfuns.h" -#include "libc/time/clockstonanos.internal.h" static struct { pthread_once_t once; - uint64_t base; - struct timespec mono; + struct timespec base_wall; + uint64_t base_tick; } g_mono; static void sys_clock_gettime_mono_init(void) { - clock_gettime(CLOCK_REALTIME, &g_mono.mono); - g_mono.base = rdtsc(); - g_mono.once = true; + g_mono.base_wall = _timespec_real(); + g_mono.base_tick = rdtsc(); } -int sys_clock_gettime_mono(struct timespec *ts) { - // this routine stops being monotonic after 194 years of uptime +int sys_clock_gettime_mono(struct timespec *time) { uint64_t nanos; + uint64_t cycles; struct timespec res; if (X86_HAVE(INVTSC)) { pthread_once(&g_mono.once, sys_clock_gettime_mono_init); - nanos = ClocksToNanos(rdtsc(), g_mono.base); - res = g_mono.mono; - res.tv_sec += nanos / 1000000000; - res.tv_nsec += nanos % 1000000000; - *ts = res; + cycles = rdtsc() - g_mono.base_tick; + nanos = cycles / 3; + *time = _timespec_add(g_mono.base_wall, _timespec_fromnanos(nanos)); return 0; } else { return einval(); diff --git a/libc/calls/clock_gettime.c b/libc/calls/clock_gettime.c index 7a2431914..ea5b79d6f 100644 --- a/libc/calls/clock_gettime.c +++ b/libc/calls/clock_gettime.c @@ -66,8 +66,8 @@ int clock_gettime(int clock, struct timespec *ts) { } #if SYSDEBUG if (!__time_critical) { - STRACE("clock_gettime(%d, [%s]) → %d% m", clock, DescribeTimespec(rc, ts), - rc); + STRACE("clock_gettime(%s, [%s]) → %d% m", DescribeClockName(clock), + DescribeTimespec(rc, ts), rc); } #endif return rc; diff --git a/libc/calls/struct/timespec.h b/libc/calls/struct/timespec.h index 77c892579..4c555e637 100644 --- a/libc/calls/struct/timespec.h +++ b/libc/calls/struct/timespec.h @@ -14,6 +14,8 @@ int futimens(int, const struct timespec[2]); int nanosleep(const struct timespec *, struct timespec *); int sys_futex(int *, int, int, const struct timespec *, int *); int utimensat(int, const char *, const struct timespec[2], int); +int timespec_get(struct timespec *, int); +int timespec_getres(struct timespec *, int); bool _timespec_eq(struct timespec, struct timespec) pureconst; bool _timespec_gte(struct timespec, struct timespec) pureconst; @@ -21,6 +23,7 @@ int64_t _timespec_tomicros(struct timespec) pureconst; int64_t _timespec_tomillis(struct timespec) pureconst; int64_t _timespec_tonanos(struct timespec) pureconst; struct timespec _timespec_add(struct timespec, struct timespec) pureconst; +struct timespec _timespec_fromnanos(int64_t) pureconst; struct timespec _timespec_frommicros(int64_t) pureconst; struct timespec _timespec_frommillis(int64_t) pureconst; struct timespec _timespec_mono(void); diff --git a/libc/calls/struct/timespec.internal.h b/libc/calls/struct/timespec.internal.h index 329d71c97..c21a285b6 100644 --- a/libc/calls/struct/timespec.internal.h +++ b/libc/calls/struct/timespec.internal.h @@ -6,14 +6,15 @@ COSMOPOLITAN_C_START_ int __sys_utimensat(int, const char *, const struct timespec *, int) hidden; +int sys_clock_getres(int, struct timespec *) hidden; int sys_clock_gettime(int, struct timespec *) hidden; +int sys_clock_gettime_nt(int, struct timespec *) hidden; int sys_clock_gettime_xnu(int, struct timespec *) hidden; int sys_futimens(int, const struct timespec *) hidden; int sys_nanosleep(const struct timespec *, struct timespec *) hidden; -int sys_utimensat(int, const char *, const struct timespec *, int) hidden; -int sys_clock_gettime_nt(int, struct timespec *) hidden; int sys_nanosleep_nt(const struct timespec *, struct timespec *) hidden; int sys_nanosleep_xnu(const struct timespec *, struct timespec *) hidden; +int sys_utimensat(int, const char *, const struct timespec *, int) hidden; int sys_utimensat_nt(int, const char *, const struct timespec *, int) hidden; int sys_utimensat_xnu(int, const char *, const struct timespec *, int) hidden; diff --git a/libc/calls/timespec_get.c b/libc/calls/timespec_get.c new file mode 100644 index 000000000..a7b433347 --- /dev/null +++ b/libc/calls/timespec_get.c @@ -0,0 +1,36 @@ +/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│ +│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│ +╞══════════════════════════════════════════════════════════════════════════════╡ +│ Copyright 2022 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/struct/timespec.h" +#include "libc/sysv/consts/clock.h" +#include "libc/time/time.h" + +/** + * Returns high-precision timestamp, the C11 way. + * + * @param ts receives `CLOCK_REALTIME` timestamp + * @param base must be `TIME_UTC` + * @return `base` on success, or `0` on failure + */ +int timespec_get(struct timespec *ts, int base) { + if (base == TIME_UTC && !clock_gettime(CLOCK_REALTIME, ts)) { + return base; + } else { + return 0; + } +} diff --git a/libc/calls/timespec_getres.c b/libc/calls/timespec_getres.c new file mode 100644 index 000000000..79a854072 --- /dev/null +++ b/libc/calls/timespec_getres.c @@ -0,0 +1,36 @@ +/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│ +│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│ +╞══════════════════════════════════════════════════════════════════════════════╡ +│ Copyright 2022 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/struct/timespec.h" +#include "libc/sysv/consts/clock.h" +#include "libc/time/time.h" + +/** + * Returns high-precision timestamp granularity, the C23 way. + * + * @param ts receives granularity as a relative timestamp + * @param base must be `TIME_UTC` + * @return `base` on success, or `0` on failure + */ +int timespec_getres(struct timespec *ts, int base) { + if (base == TIME_UTC && !clock_getres(CLOCK_REALTIME, ts)) { + return base; + } else { + return 0; + } +} diff --git a/libc/intrin/emmintrin.internal.h b/libc/intrin/emmintrin.internal.h index abd28478d..75e25b045 100644 --- a/libc/intrin/emmintrin.internal.h +++ b/libc/intrin/emmintrin.internal.h @@ -158,6 +158,9 @@ struct thatispacked mayalias __usi128ma { #define _mm_srli_si128(M128I, IMM) \ ((__m128i)__builtin_ia32_psrldqi128((__v2di)(__m128i)(M128I), (int)(IMM)*8)) +#define _mm_cmpeq_epi8(a, b) ((__m128i)((__v16qi)(a) == (__v16qi)(b))) +#define _mm_movemask_epi8(a) __builtin_ia32_pmovmskb128((__v16qi)(a)) + /*───────────────────────────────────────────────────────────────────────────│─╗ │ cosmopolitan § it's a trap! » sse2 » scalar ops ─╬─│┼ ╚────────────────────────────────────────────────────────────────────────────│*/ @@ -218,19 +221,18 @@ struct thatispacked mayalias __usi128ma { #define _mm_cmpunord_sd(M128D_0, M128D_1) \ __builtin_ia32_cmpunordsd((__v2df)(M128D_0), (__v2df)(M128D_1)) -#define _mm_SSE2(op, A, B) \ - ({ \ - __m128i R = A; \ - asm(#op " %1, %0" \ - : "+x"(R) : "xm"(B)); \ - R; \ +#define _mm_SSE2(op, A, B) \ + ({ \ + __m128i R = A; \ + asm(#op " %1, %0" : "+x"(R) : "xm"(B)); \ + R; \ }) -#define _mm_mul_epu32(A, B) _mm_SSE2(pmuludq, A, B) -#define _mm_add_epi64(A, B) _mm_SSE2(paddq, A, B) -#define _mm_srli_epi64(A, B) _mm_SSE2(psrlq, A, B) -#define _mm_slli_epi64(A, B) _mm_SSE2(psllq, A, B) -#define _mm_unpacklo_epi64(A, B) _mm_SSE2(punpcklqdq, A, B) -#define _mm_unpackhi_epi64(A, B) _mm_SSE2(punpckhqdq, A, B) +#define _mm_mul_epu32(A, B) _mm_SSE2(pmuludq, A, B) +#define _mm_add_epi64(A, B) _mm_SSE2(paddq, A, B) +#define _mm_srli_epi64(A, B) _mm_SSE2(psrlq, A, B) +#define _mm_slli_epi64(A, B) _mm_SSE2(psllq, A, B) +#define _mm_unpacklo_epi64(A, B) _mm_SSE2(punpcklqdq, A, B) +#define _mm_unpackhi_epi64(A, B) _mm_SSE2(punpckhqdq, A, B) /*───────────────────────────────────────────────────────────────────────────│─╗ │ cosmopolitan § it's a trap! » sse2 » miscellaneous ─╬─│┼ diff --git a/libc/intrin/kprintf.greg.c b/libc/intrin/kprintf.greg.c index f34340278..1ae95aecd 100644 --- a/libc/intrin/kprintf.greg.c +++ b/libc/intrin/kprintf.greg.c @@ -17,10 +17,6 @@ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #define ShouldUseMsabiAttribute() 1 -#include "libc/intrin/bits.h" -#include "libc/intrin/likely.h" -#include "libc/intrin/safemacros.internal.h" -#include "libc/intrin/weaken.h" #include "libc/calls/calls.h" #include "libc/calls/state.internal.h" #include "libc/calls/syscall-sysv.internal.h" @@ -28,11 +24,15 @@ #include "libc/errno.h" #include "libc/fmt/divmod10.internal.h" #include "libc/fmt/fmt.h" +#include "libc/intrin/bits.h" #include "libc/intrin/cmpxchg.h" #include "libc/intrin/kprintf.h" +#include "libc/intrin/likely.h" #include "libc/intrin/lockcmpxchg.h" #include "libc/intrin/nomultics.internal.h" +#include "libc/intrin/safemacros.internal.h" #include "libc/intrin/spinlock.h" +#include "libc/intrin/weaken.h" #include "libc/limits.h" #include "libc/log/internal.h" #include "libc/macros.internal.h" @@ -53,7 +53,6 @@ #include "libc/str/utf16.h" #include "libc/sysv/consts/nr.h" #include "libc/sysv/consts/prot.h" -#include "libc/time/clockstonanos.internal.h" extern hidden struct SymbolTable *__symtab; @@ -306,7 +305,7 @@ privileged static size_t kformat(char *b, size_t n, const char *fmt, continue; case 'T': - x = ClocksToNanos(rdtsc(), kStartTsc) % 86400000000000; + x = (rdtsc() - kStartTsc) / 3 % 86400000000000; goto FormatUnsigned; case 'P': diff --git a/libc/sysv/consts.sh b/libc/sysv/consts.sh index 55e17602a..03a6ec850 100755 --- a/libc/sysv/consts.sh +++ b/libc/sysv/consts.sh @@ -1615,8 +1615,6 @@ syscon iff IFF_MASTER 0x0400 0 0 0 0 0 syscon iff IFF_PORTSEL 0x2000 0 0 0 0 0 syscon iff IFF_SLAVE 0x0800 0 0 0 0 0 -syscon misc CLOCKS_PER_SEC 1000000 1000000 0x80 100 100 10000000 - syscon sock SOCK_STREAM 1 1 1 1 1 1 # consensus syscon sock SOCK_DGRAM 2 2 2 2 2 2 # consensus syscon sock SOCK_RAW 3 3 3 3 3 3 # consensus diff --git a/libc/sysv/consts/CLOCKS_PER_SEC.s b/libc/sysv/consts/CLOCKS_PER_SEC.s deleted file mode 100644 index 6871299f8..000000000 --- a/libc/sysv/consts/CLOCKS_PER_SEC.s +++ /dev/null @@ -1,2 +0,0 @@ -.include "o/libc/sysv/consts/syscon.internal.inc" -.syscon misc,CLOCKS_PER_SEC,1000000,1000000,0x80,100,100,10000000 diff --git a/libc/sysv/consts/SI_KERNEL.s b/libc/sysv/consts/SI_KERNEL.s index e7a6d02e7..13360434e 100644 --- a/libc/sysv/consts/SI_KERNEL.s +++ b/libc/sysv/consts/SI_KERNEL.s @@ -1,2 +1,2 @@ .include "o/libc/sysv/consts/syscon.internal.inc" -.syscon sicode,SI_KERNEL,0x80,0x80000000,0x010006,0x80000000,0x80000000,0x80 +.syscon sicode,SI_KERNEL,128,0x80000000,0x010006,0x80000000,0x80000000,0x80 diff --git a/libc/thread/posixthread.internal.h b/libc/thread/posixthread.internal.h index e5030a99f..9fe68e47c 100644 --- a/libc/thread/posixthread.internal.h +++ b/libc/thread/posixthread.internal.h @@ -5,6 +5,10 @@ #if !(__ASSEMBLER__ + __LINKER__ + 0) COSMOPOLITAN_C_START_ +/** + * @fileoverview Cosmopolitan POSIX Thread Internals + */ + enum PosixThreadStatus { kPosixThreadStarted, kPosixThreadDetached, diff --git a/libc/thread/pthread_create.c b/libc/thread/pthread_create.c index 7659327f2..e1dd14eff 100644 --- a/libc/thread/pthread_create.c +++ b/libc/thread/pthread_create.c @@ -33,13 +33,13 @@ static int PosixThread(void *arg, int tid) { ((cthread_t)__get_tls())->pthread = pt; pt->rc = pt->start_routine(pt->arg); } - if (atomic_load_explicit(&pt->status, memory_order_relaxed) == + if (atomic_load_explicit(&pt->status, memory_order_acquire) == kPosixThreadDetached) { atomic_store_explicit(&pt->status, kPosixThreadZombie, - memory_order_relaxed); + memory_order_release); } else { atomic_store_explicit(&pt->status, kPosixThreadTerminated, - memory_order_relaxed); + memory_order_release); } return 0; } @@ -47,6 +47,25 @@ static int PosixThread(void *arg, int tid) { /** * Creates thread. * + * Here's the OSI model of threads in Cosmopolitan: + * + * ┌──────────────────┐ + * │ pthread_create() │ - Standard + * └─────────┬────────┘ Abstraction + * ┌─────────┴────────┐ + * │ _spawn() │ - Cosmopolitan + * └─────────┬────────┘ Abstraction + * ┌─────────┴────────┐ + * │ clone() │ - Polyfill + * └─────────┬────────┘ + * ┌────────┬──┴──┬─┬─────────┐ - Kernel + * ┌─────┴─────┐ │ │┌┴──────┐ │ Interfaces + * │ sys_clone │ │ ││ tfork │ │ + * └───────────┘ │ │└───────┘ ┌┴─────────────┐ + * ┌───────────────┴──┐ ┌┴────────┐ │ CreateThread │ + * │ bsdthread_create │ │ thr_new │ └──────────────┘ + * └──────────────────┘ └─────────┘ + * * @return 0 on success, or errno on error */ int pthread_create(pthread_t *thread, const pthread_attr_t *attr, diff --git a/libc/thread/zombie.c b/libc/thread/zombie.c index 0203e547f..ea5d78ad8 100644 --- a/libc/thread/zombie.c +++ b/libc/thread/zombie.c @@ -16,7 +16,6 @@ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ -#include "libc/bits/atomic.h" #include "libc/intrin/atomic.h" #include "libc/mem/mem.h" #include "libc/runtime/runtime.h" diff --git a/libc/time/time.h b/libc/time/time.h index 5d21850dc..d44b08b31 100644 --- a/libc/time/time.h +++ b/libc/time/time.h @@ -1,5 +1,9 @@ #ifndef COSMOPOLITAN_LIBC_TIME_TIME_H_ #define COSMOPOLITAN_LIBC_TIME_TIME_H_ + +#define TIME_UTC 1 +#define CLOCKS_PER_SEC 1000000L + #if !(__ASSEMBLER__ + __LINKER__ + 0) COSMOPOLITAN_C_START_ @@ -10,7 +14,6 @@ hidden extern const char kMonthName[12][10]; hidden extern const unsigned short kMonthYearDay[2][12]; extern char *tzname[2]; -extern long CLOCKS_PER_SEC; extern long timezone; extern int daylight; diff --git a/third_party/python/Modules/timemodule.c b/third_party/python/Modules/timemodule.c index 15051d8c6..0ccb89d22 100644 --- a/third_party/python/Modules/timemodule.c +++ b/third_party/python/Modules/timemodule.c @@ -110,7 +110,6 @@ PyDoc_STRVAR(time_ns_doc, Return the current time in nanoseconds since the Epoch."); #ifdef HAVE_CLOCK -#define CLOCKS_PER_SEC CLK_TCK static PyObject * floatclock(_Py_clock_info_t *info) {