mirror of
https://github.com/jart/cosmopolitan.git
synced 2025-05-28 00:02:28 +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
|
@ -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();
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue