mirror of
https://github.com/jart/cosmopolitan.git
synced 2025-05-23 05:42:29 +00:00
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
This commit is contained in:
parent
7ff0ea8c13
commit
12d9e1e128
24 changed files with 254 additions and 76 deletions
41
examples/clock.c
Normal file
41
examples/clock.c
Normal file
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
|
@ -8,14 +8,14 @@
|
||||||
╚─────────────────────────────────────────────────────────────────*/
|
╚─────────────────────────────────────────────────────────────────*/
|
||||||
#endif
|
#endif
|
||||||
#include "libc/calls/calls.h"
|
#include "libc/calls/calls.h"
|
||||||
|
#include "libc/intrin/kprintf.h"
|
||||||
#include "libc/log/check.h"
|
#include "libc/log/check.h"
|
||||||
#include "libc/stdio/stdio.h"
|
|
||||||
|
|
||||||
int main(int argc, char *argv[]) {
|
int main(int argc, char *argv[]) {
|
||||||
char name[254];
|
char name[254];
|
||||||
CHECK_NE(-1, gethostname(name, sizeof(name)));
|
gethostname(name, sizeof(name));
|
||||||
printf("gethostname() → %`'s\n", name);
|
kprintf("gethostname() → %#s\n", name);
|
||||||
CHECK_NE(-1, getdomainname(name, sizeof(name)));
|
getdomainname(name, sizeof(name));
|
||||||
printf("getdomainname() → %`'s\n", name);
|
kprintf("getdomainname() → %#s\n", name);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
29
libc/calls/_timespec_fromnanos.c
Normal file
29
libc/calls/_timespec_fromnanos.c
Normal file
|
@ -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;
|
||||||
|
}
|
|
@ -184,9 +184,11 @@ o//libc/calls/statfs2cosmo.o: private \
|
||||||
|
|
||||||
# we always want -O2 because:
|
# we always want -O2 because:
|
||||||
# division is expensive if not optimized
|
# division is expensive if not optimized
|
||||||
|
o/$(MODE)/libc/calls/clock.o \
|
||||||
o/$(MODE)/libc/calls/_timespec_tomillis.o \
|
o/$(MODE)/libc/calls/_timespec_tomillis.o \
|
||||||
o/$(MODE)/libc/calls/_timespec_tomicros.o \
|
o/$(MODE)/libc/calls/_timespec_tomicros.o \
|
||||||
o/$(MODE)/libc/calls/_timespec_totimeval.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_frommillis.o \
|
||||||
o/$(MODE)/libc/calls/_timespec_frommicros.o: private \
|
o/$(MODE)/libc/calls/_timespec_frommicros.o: private \
|
||||||
OVERRIDE_CFLAGS += \
|
OVERRIDE_CFLAGS += \
|
||||||
|
|
|
@ -16,36 +16,51 @@
|
||||||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||||
|
#include "libc/calls/struct/rusage.h"
|
||||||
#include "libc/calls/struct/timespec.h"
|
#include "libc/calls/struct/timespec.h"
|
||||||
#include "libc/dce.h"
|
#include "libc/calls/struct/timeval.h"
|
||||||
#include "libc/fmt/conv.h"
|
#include "libc/errno.h"
|
||||||
#include "libc/nt/accounting.h"
|
|
||||||
#include "libc/nt/runtime.h"
|
|
||||||
#include "libc/nt/synchronization.h"
|
|
||||||
#include "libc/sysv/consts/clock.h"
|
#include "libc/sysv/consts/clock.h"
|
||||||
|
#include "libc/sysv/consts/rusage.h"
|
||||||
#include "libc/time/time.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
|
* This function provides a basic idea of how computationally expensive
|
||||||
* @see clock_gettime()
|
* 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) {
|
int64_t clock(void) {
|
||||||
|
int e;
|
||||||
|
struct rusage ru;
|
||||||
struct timespec ts;
|
struct timespec ts;
|
||||||
struct NtFileTime creation_time, exit_time, kernel_time, user_time;
|
e = errno;
|
||||||
int64_t proc, total;
|
if (clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &ts) == -1) {
|
||||||
// polyfill on Windows where CLOCK_PROCESS_CPUTIME_ID may be not available
|
errno = e;
|
||||||
if (IsWindows() && CLOCK_PROCESS_CPUTIME_ID == -1) {
|
if (getrusage(RUSAGE_SELF, &ru) != -1) {
|
||||||
proc = GetCurrentProcess();
|
ts = _timeval_totimespec(_timeval_add(ru.ru_utime, ru.ru_stime));
|
||||||
if (!GetProcessTimes(proc, &creation_time, &exit_time, &kernel_time,
|
} else {
|
||||||
&user_time))
|
|
||||||
return -1;
|
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 +
|
// convert nanoseconds to microseconds w/ ceil rounding
|
||||||
ts.tv_nsec / (1000000000 / CLOCKS_PER_SEC);
|
// this would need roughly ~7,019,309 years to overflow
|
||||||
|
return ts.tv_sec * 1000000 + (ts.tv_nsec + 999) / 1000;
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,8 +25,6 @@
|
||||||
#include "libc/sysv/errfuns.h"
|
#include "libc/sysv/errfuns.h"
|
||||||
#include "libc/time/time.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) {
|
static int sys_clock_getres_poly(int clock, struct timespec *ts, int64_t real) {
|
||||||
if (clock == CLOCK_REALTIME) {
|
if (clock == CLOCK_REALTIME) {
|
||||||
ts->tv_sec = 0;
|
ts->tv_sec = 0;
|
||||||
|
@ -65,6 +63,7 @@ int clock_getres(int clock, struct timespec *ts) {
|
||||||
} else {
|
} else {
|
||||||
rc = sys_clock_getres(clock, ts);
|
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;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,38 +16,33 @@
|
||||||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||||
#include "libc/calls/clock_gettime.internal.h"
|
|
||||||
#include "libc/calls/struct/timespec.h"
|
#include "libc/calls/struct/timespec.h"
|
||||||
#include "libc/intrin/pthread.h"
|
#include "libc/intrin/pthread.h"
|
||||||
#include "libc/nexgen32e/rdtsc.h"
|
#include "libc/nexgen32e/rdtsc.h"
|
||||||
#include "libc/nexgen32e/x86feature.h"
|
#include "libc/nexgen32e/x86feature.h"
|
||||||
#include "libc/sysv/consts/clock.h"
|
#include "libc/sysv/consts/clock.h"
|
||||||
#include "libc/sysv/errfuns.h"
|
#include "libc/sysv/errfuns.h"
|
||||||
#include "libc/time/clockstonanos.internal.h"
|
|
||||||
|
|
||||||
static struct {
|
static struct {
|
||||||
pthread_once_t once;
|
pthread_once_t once;
|
||||||
uint64_t base;
|
struct timespec base_wall;
|
||||||
struct timespec mono;
|
uint64_t base_tick;
|
||||||
} g_mono;
|
} g_mono;
|
||||||
|
|
||||||
static void sys_clock_gettime_mono_init(void) {
|
static void sys_clock_gettime_mono_init(void) {
|
||||||
clock_gettime(CLOCK_REALTIME, &g_mono.mono);
|
g_mono.base_wall = _timespec_real();
|
||||||
g_mono.base = rdtsc();
|
g_mono.base_tick = rdtsc();
|
||||||
g_mono.once = true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int sys_clock_gettime_mono(struct timespec *ts) {
|
int sys_clock_gettime_mono(struct timespec *time) {
|
||||||
// this routine stops being monotonic after 194 years of uptime
|
|
||||||
uint64_t nanos;
|
uint64_t nanos;
|
||||||
|
uint64_t cycles;
|
||||||
struct timespec res;
|
struct timespec res;
|
||||||
if (X86_HAVE(INVTSC)) {
|
if (X86_HAVE(INVTSC)) {
|
||||||
pthread_once(&g_mono.once, sys_clock_gettime_mono_init);
|
pthread_once(&g_mono.once, sys_clock_gettime_mono_init);
|
||||||
nanos = ClocksToNanos(rdtsc(), g_mono.base);
|
cycles = rdtsc() - g_mono.base_tick;
|
||||||
res = g_mono.mono;
|
nanos = cycles / 3;
|
||||||
res.tv_sec += nanos / 1000000000;
|
*time = _timespec_add(g_mono.base_wall, _timespec_fromnanos(nanos));
|
||||||
res.tv_nsec += nanos % 1000000000;
|
|
||||||
*ts = res;
|
|
||||||
return 0;
|
return 0;
|
||||||
} else {
|
} else {
|
||||||
return einval();
|
return einval();
|
||||||
|
|
|
@ -66,8 +66,8 @@ int clock_gettime(int clock, struct timespec *ts) {
|
||||||
}
|
}
|
||||||
#if SYSDEBUG
|
#if SYSDEBUG
|
||||||
if (!__time_critical) {
|
if (!__time_critical) {
|
||||||
STRACE("clock_gettime(%d, [%s]) → %d% m", clock, DescribeTimespec(rc, ts),
|
STRACE("clock_gettime(%s, [%s]) → %d% m", DescribeClockName(clock),
|
||||||
rc);
|
DescribeTimespec(rc, ts), rc);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
return rc;
|
return rc;
|
||||||
|
|
|
@ -14,6 +14,8 @@ int futimens(int, const struct timespec[2]);
|
||||||
int nanosleep(const struct timespec *, struct timespec *);
|
int nanosleep(const struct timespec *, struct timespec *);
|
||||||
int sys_futex(int *, int, int, const struct timespec *, int *);
|
int sys_futex(int *, int, int, const struct timespec *, int *);
|
||||||
int utimensat(int, const char *, const struct timespec[2], 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_eq(struct timespec, struct timespec) pureconst;
|
||||||
bool _timespec_gte(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_tomillis(struct timespec) pureconst;
|
||||||
int64_t _timespec_tonanos(struct timespec) pureconst;
|
int64_t _timespec_tonanos(struct timespec) pureconst;
|
||||||
struct timespec _timespec_add(struct timespec, 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_frommicros(int64_t) pureconst;
|
||||||
struct timespec _timespec_frommillis(int64_t) pureconst;
|
struct timespec _timespec_frommillis(int64_t) pureconst;
|
||||||
struct timespec _timespec_mono(void);
|
struct timespec _timespec_mono(void);
|
||||||
|
|
|
@ -6,14 +6,15 @@
|
||||||
COSMOPOLITAN_C_START_
|
COSMOPOLITAN_C_START_
|
||||||
|
|
||||||
int __sys_utimensat(int, const char *, const struct timespec *, int) hidden;
|
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(int, struct timespec *) hidden;
|
||||||
|
int sys_clock_gettime_nt(int, struct timespec *) hidden;
|
||||||
int sys_clock_gettime_xnu(int, struct timespec *) hidden;
|
int sys_clock_gettime_xnu(int, struct timespec *) hidden;
|
||||||
int sys_futimens(int, const struct timespec *) hidden;
|
int sys_futimens(int, const struct timespec *) hidden;
|
||||||
int sys_nanosleep(const struct timespec *, 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_nt(const struct timespec *, struct timespec *) hidden;
|
||||||
int sys_nanosleep_xnu(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_nt(int, const char *, const struct timespec *, int) hidden;
|
||||||
int sys_utimensat_xnu(int, const char *, const struct timespec *, int) hidden;
|
int sys_utimensat_xnu(int, const char *, const struct timespec *, int) hidden;
|
||||||
|
|
||||||
|
|
36
libc/calls/timespec_get.c
Normal file
36
libc/calls/timespec_get.c
Normal file
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
36
libc/calls/timespec_getres.c
Normal file
36
libc/calls/timespec_getres.c
Normal file
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
|
@ -158,6 +158,9 @@ struct thatispacked mayalias __usi128ma {
|
||||||
#define _mm_srli_si128(M128I, IMM) \
|
#define _mm_srli_si128(M128I, IMM) \
|
||||||
((__m128i)__builtin_ia32_psrldqi128((__v2di)(__m128i)(M128I), (int)(IMM)*8))
|
((__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 ─╬─│┼
|
│ cosmopolitan § it's a trap! » sse2 » scalar ops ─╬─│┼
|
||||||
╚────────────────────────────────────────────────────────────────────────────│*/
|
╚────────────────────────────────────────────────────────────────────────────│*/
|
||||||
|
@ -218,19 +221,18 @@ struct thatispacked mayalias __usi128ma {
|
||||||
#define _mm_cmpunord_sd(M128D_0, M128D_1) \
|
#define _mm_cmpunord_sd(M128D_0, M128D_1) \
|
||||||
__builtin_ia32_cmpunordsd((__v2df)(M128D_0), (__v2df)(M128D_1))
|
__builtin_ia32_cmpunordsd((__v2df)(M128D_0), (__v2df)(M128D_1))
|
||||||
|
|
||||||
#define _mm_SSE2(op, A, B) \
|
#define _mm_SSE2(op, A, B) \
|
||||||
({ \
|
({ \
|
||||||
__m128i R = A; \
|
__m128i R = A; \
|
||||||
asm(#op " %1, %0" \
|
asm(#op " %1, %0" : "+x"(R) : "xm"(B)); \
|
||||||
: "+x"(R) : "xm"(B)); \
|
R; \
|
||||||
R; \
|
|
||||||
})
|
})
|
||||||
#define _mm_mul_epu32(A, B) _mm_SSE2(pmuludq, 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_add_epi64(A, B) _mm_SSE2(paddq, A, B)
|
||||||
#define _mm_srli_epi64(A, B) _mm_SSE2(psrlq, 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_slli_epi64(A, B) _mm_SSE2(psllq, A, B)
|
||||||
#define _mm_unpacklo_epi64(A, B) _mm_SSE2(punpcklqdq, 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_unpackhi_epi64(A, B) _mm_SSE2(punpckhqdq, A, B)
|
||||||
|
|
||||||
/*───────────────────────────────────────────────────────────────────────────│─╗
|
/*───────────────────────────────────────────────────────────────────────────│─╗
|
||||||
│ cosmopolitan § it's a trap! » sse2 » miscellaneous ─╬─│┼
|
│ cosmopolitan § it's a trap! » sse2 » miscellaneous ─╬─│┼
|
||||||
|
|
|
@ -17,10 +17,6 @@
|
||||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||||
#define ShouldUseMsabiAttribute() 1
|
#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/calls.h"
|
||||||
#include "libc/calls/state.internal.h"
|
#include "libc/calls/state.internal.h"
|
||||||
#include "libc/calls/syscall-sysv.internal.h"
|
#include "libc/calls/syscall-sysv.internal.h"
|
||||||
|
@ -28,11 +24,15 @@
|
||||||
#include "libc/errno.h"
|
#include "libc/errno.h"
|
||||||
#include "libc/fmt/divmod10.internal.h"
|
#include "libc/fmt/divmod10.internal.h"
|
||||||
#include "libc/fmt/fmt.h"
|
#include "libc/fmt/fmt.h"
|
||||||
|
#include "libc/intrin/bits.h"
|
||||||
#include "libc/intrin/cmpxchg.h"
|
#include "libc/intrin/cmpxchg.h"
|
||||||
#include "libc/intrin/kprintf.h"
|
#include "libc/intrin/kprintf.h"
|
||||||
|
#include "libc/intrin/likely.h"
|
||||||
#include "libc/intrin/lockcmpxchg.h"
|
#include "libc/intrin/lockcmpxchg.h"
|
||||||
#include "libc/intrin/nomultics.internal.h"
|
#include "libc/intrin/nomultics.internal.h"
|
||||||
|
#include "libc/intrin/safemacros.internal.h"
|
||||||
#include "libc/intrin/spinlock.h"
|
#include "libc/intrin/spinlock.h"
|
||||||
|
#include "libc/intrin/weaken.h"
|
||||||
#include "libc/limits.h"
|
#include "libc/limits.h"
|
||||||
#include "libc/log/internal.h"
|
#include "libc/log/internal.h"
|
||||||
#include "libc/macros.internal.h"
|
#include "libc/macros.internal.h"
|
||||||
|
@ -53,7 +53,6 @@
|
||||||
#include "libc/str/utf16.h"
|
#include "libc/str/utf16.h"
|
||||||
#include "libc/sysv/consts/nr.h"
|
#include "libc/sysv/consts/nr.h"
|
||||||
#include "libc/sysv/consts/prot.h"
|
#include "libc/sysv/consts/prot.h"
|
||||||
#include "libc/time/clockstonanos.internal.h"
|
|
||||||
|
|
||||||
extern hidden struct SymbolTable *__symtab;
|
extern hidden struct SymbolTable *__symtab;
|
||||||
|
|
||||||
|
@ -306,7 +305,7 @@ privileged static size_t kformat(char *b, size_t n, const char *fmt,
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
case 'T':
|
case 'T':
|
||||||
x = ClocksToNanos(rdtsc(), kStartTsc) % 86400000000000;
|
x = (rdtsc() - kStartTsc) / 3 % 86400000000000;
|
||||||
goto FormatUnsigned;
|
goto FormatUnsigned;
|
||||||
|
|
||||||
case 'P':
|
case 'P':
|
||||||
|
|
|
@ -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_PORTSEL 0x2000 0 0 0 0 0
|
||||||
syscon iff IFF_SLAVE 0x0800 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_STREAM 1 1 1 1 1 1 # consensus
|
||||||
syscon sock SOCK_DGRAM 2 2 2 2 2 2 # consensus
|
syscon sock SOCK_DGRAM 2 2 2 2 2 2 # consensus
|
||||||
syscon sock SOCK_RAW 3 3 3 3 3 3 # consensus
|
syscon sock SOCK_RAW 3 3 3 3 3 3 # consensus
|
||||||
|
|
|
@ -1,2 +0,0 @@
|
||||||
.include "o/libc/sysv/consts/syscon.internal.inc"
|
|
||||||
.syscon misc,CLOCKS_PER_SEC,1000000,1000000,0x80,100,100,10000000
|
|
|
@ -1,2 +1,2 @@
|
||||||
.include "o/libc/sysv/consts/syscon.internal.inc"
|
.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
|
||||||
|
|
|
@ -5,6 +5,10 @@
|
||||||
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||||
COSMOPOLITAN_C_START_
|
COSMOPOLITAN_C_START_
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @fileoverview Cosmopolitan POSIX Thread Internals
|
||||||
|
*/
|
||||||
|
|
||||||
enum PosixThreadStatus {
|
enum PosixThreadStatus {
|
||||||
kPosixThreadStarted,
|
kPosixThreadStarted,
|
||||||
kPosixThreadDetached,
|
kPosixThreadDetached,
|
||||||
|
|
|
@ -33,13 +33,13 @@ static int PosixThread(void *arg, int tid) {
|
||||||
((cthread_t)__get_tls())->pthread = pt;
|
((cthread_t)__get_tls())->pthread = pt;
|
||||||
pt->rc = pt->start_routine(pt->arg);
|
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) {
|
kPosixThreadDetached) {
|
||||||
atomic_store_explicit(&pt->status, kPosixThreadZombie,
|
atomic_store_explicit(&pt->status, kPosixThreadZombie,
|
||||||
memory_order_relaxed);
|
memory_order_release);
|
||||||
} else {
|
} else {
|
||||||
atomic_store_explicit(&pt->status, kPosixThreadTerminated,
|
atomic_store_explicit(&pt->status, kPosixThreadTerminated,
|
||||||
memory_order_relaxed);
|
memory_order_release);
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -47,6 +47,25 @@ static int PosixThread(void *arg, int tid) {
|
||||||
/**
|
/**
|
||||||
* Creates thread.
|
* 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
|
* @return 0 on success, or errno on error
|
||||||
*/
|
*/
|
||||||
int pthread_create(pthread_t *thread, const pthread_attr_t *attr,
|
int pthread_create(pthread_t *thread, const pthread_attr_t *attr,
|
||||||
|
|
|
@ -16,7 +16,6 @@
|
||||||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||||
#include "libc/bits/atomic.h"
|
|
||||||
#include "libc/intrin/atomic.h"
|
#include "libc/intrin/atomic.h"
|
||||||
#include "libc/mem/mem.h"
|
#include "libc/mem/mem.h"
|
||||||
#include "libc/runtime/runtime.h"
|
#include "libc/runtime/runtime.h"
|
||||||
|
|
|
@ -1,5 +1,9 @@
|
||||||
#ifndef COSMOPOLITAN_LIBC_TIME_TIME_H_
|
#ifndef COSMOPOLITAN_LIBC_TIME_TIME_H_
|
||||||
#define COSMOPOLITAN_LIBC_TIME_TIME_H_
|
#define COSMOPOLITAN_LIBC_TIME_TIME_H_
|
||||||
|
|
||||||
|
#define TIME_UTC 1
|
||||||
|
#define CLOCKS_PER_SEC 1000000L
|
||||||
|
|
||||||
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||||
COSMOPOLITAN_C_START_
|
COSMOPOLITAN_C_START_
|
||||||
|
|
||||||
|
@ -10,7 +14,6 @@ hidden extern const char kMonthName[12][10];
|
||||||
hidden extern const unsigned short kMonthYearDay[2][12];
|
hidden extern const unsigned short kMonthYearDay[2][12];
|
||||||
|
|
||||||
extern char *tzname[2];
|
extern char *tzname[2];
|
||||||
extern long CLOCKS_PER_SEC;
|
|
||||||
extern long timezone;
|
extern long timezone;
|
||||||
extern int daylight;
|
extern int daylight;
|
||||||
|
|
||||||
|
|
1
third_party/python/Modules/timemodule.c
vendored
1
third_party/python/Modules/timemodule.c
vendored
|
@ -110,7 +110,6 @@ PyDoc_STRVAR(time_ns_doc,
|
||||||
Return the current time in nanoseconds since the Epoch.");
|
Return the current time in nanoseconds since the Epoch.");
|
||||||
|
|
||||||
#ifdef HAVE_CLOCK
|
#ifdef HAVE_CLOCK
|
||||||
#define CLOCKS_PER_SEC CLK_TCK
|
|
||||||
static PyObject *
|
static PyObject *
|
||||||
floatclock(_Py_clock_info_t *info)
|
floatclock(_Py_clock_info_t *info)
|
||||||
{
|
{
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue