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:
Justine Tunney 2022-09-05 21:43:49 -07:00
parent 7ff0ea8c13
commit 12d9e1e128
No known key found for this signature in database
GPG key ID: BE714B4575D6E328
24 changed files with 254 additions and 76 deletions

View file

@ -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();