Refactor gettimeofday()

This commit is contained in:
Justine Tunney 2022-08-05 02:13:41 -07:00
parent 4238e4def9
commit af3df0893b
11 changed files with 195 additions and 36 deletions

View file

@ -18,52 +18,86 @@
*/
#include "libc/assert.h"
#include "libc/calls/internal.h"
#include "libc/calls/state.internal.h"
#include "libc/calls/strace.internal.h"
#include "libc/calls/struct/timeval.h"
#include "libc/calls/syscall_support-sysv.internal.h"
#include "libc/dce.h"
#include "libc/intrin/asan.internal.h"
#include "libc/intrin/describeflags.internal.h"
#include "libc/sysv/errfuns.h"
#include "libc/time/struct/timezone.h"
#include "libc/time/time.h"
static typeof(sys_gettimeofday) *__gettimeofday = sys_gettimeofday;
typedef axdx_t gettimeofday_f(struct timeval *, struct timezone *, void *);
extern gettimeofday_f *__gettimeofday;
/**
* Returns system wall time in microseconds.
* Returns system wall time in microseconds, e.g.
*
* int64_t t;
* char p[30];
* struct tm tm;
* struct timeval tv;
* gettimeofday(&tv, 0);
* t = tv.tv_sec;
* gmtime_r(&t, &tm);
* FormatHttpDateTime(p, &tm);
* printf("%s\n", p);
*
* @param tv points to timeval that receives result if non-NULL
* @param tz receives UTC timezone if non-NULL
* @error EFAULT if `tv` or `tz` isn't valid memory
* @see clock_gettime() for nanosecond precision
* @see strftime() for string formatting
*/
int gettimeofday(struct timeval *tv, struct timezone *tz) {
int rc;
axdx_t ad;
if (IsAsan() && ((tv && !__asan_is_valid(tv, sizeof(*tv))) ||
(tz && !__asan_is_valid(tz, sizeof(*tz))))) {
return efault();
}
if (!IsWindows() && !IsMetal()) {
ad = __gettimeofday(tv, tz, NULL);
assert(ad.ax != -1);
if (SupportsXnu() && ad.ax && tv) {
tv->tv_sec = ad.ax;
tv->tv_usec = ad.dx;
}
return 0;
} else if (IsMetal()) {
return enosys();
rc = efault();
} else {
return sys_gettimeofday_nt(tv, tz);
rc = __gettimeofday(tv, tz, 0).ax;
}
#if SYSDEBUG
if (!__time_critical) {
STRACE("gettimeofday([%s], %p) → %d% m", DescribeTimeval(rc, tv), tz, rc);
}
#endif
return rc;
}
static textstartup void __gettimeofday_init(void) {
void *vdso;
if ((vdso = __vdsosym("LINUX_2.6", "__vdso_gettimeofday"))) {
__gettimeofday = vdso;
/**
* Returns pointer to fastest gettimeofday().
*/
gettimeofday_f *__gettimeofday_get(bool *opt_out_isfast) {
bool isfast;
gettimeofday_f *res;
if (IsLinux() && (res = __vdsosym("LINUX_2.6", "__vdso_gettimeofday"))) {
isfast = true;
} else if (IsWindows()) {
isfast = true;
res = sys_gettimeofday_nt;
} else if (IsXnu()) {
isfast = false;
res = sys_gettimeofday_xnu;
} else if (IsMetal()) {
isfast = false;
res = sys_gettimeofday_metal;
} else {
isfast = false;
res = sys_gettimeofday;
}
if (opt_out_isfast) {
*opt_out_isfast = isfast;
}
return res;
}
const void *const __gettimeofday_ctor[] initarray = {
__gettimeofday_init,
};
hidden int __gettimeofday_init(struct timeval *tv, struct timezone *tz) {
gettimeofday_f *gettime;
__gettimeofday = gettime = __gettimeofday_get(0);
return gettime(tv, tz, 0).ax;
}