#ifndef RB_HRTIME_H
#define RB_HRTIME_H
#include "ruby/ruby.h"
#include <time.h>
#if defined(HAVE_SYS_TIME_H)
# include <sys/time.h>
#endif
#define RB_HRTIME_PER_USEC ((rb_hrtime_t)1000)
#define RB_HRTIME_PER_MSEC (RB_HRTIME_PER_USEC * (rb_hrtime_t)1000)
#define RB_HRTIME_PER_SEC (RB_HRTIME_PER_MSEC * (rb_hrtime_t)1000)
#define RB_HRTIME_MAX UINT64_MAX
#ifdef MY_RUBY_BUILD_MAY_TIME_TRAVEL
typedef int128_t rb_hrtime_t;
#else
typedef uint64_t rb_hrtime_t;
#endif
rb_hrtime_t rb_hrtime_now(void);
static inline rb_hrtime_t
rb_hrtime_mul(rb_hrtime_t a, rb_hrtime_t b)
{
rb_hrtime_t c;
#ifdef HAVE_BUILTIN___BUILTIN_MUL_OVERFLOW
if (__builtin_mul_overflow(a, b, &c))
return RB_HRTIME_MAX;
#else
if (b != 0 && a > RB_HRTIME_MAX / b)
return RB_HRTIME_MAX;
c = a * b;
#endif
return c;
}
static inline rb_hrtime_t
rb_hrtime_add(rb_hrtime_t a, rb_hrtime_t b)
{
rb_hrtime_t c;
#ifdef HAVE_BUILTIN___BUILTIN_ADD_OVERFLOW
if (__builtin_add_overflow(a, b, &c))
return RB_HRTIME_MAX;
#else
c = a + b;
if (c < a)
return RB_HRTIME_MAX;
#endif
return c;
}
static inline rb_hrtime_t
rb_timeval2hrtime(const struct timeval *tv)
{
rb_hrtime_t s = rb_hrtime_mul((rb_hrtime_t)tv->tv_sec, RB_HRTIME_PER_SEC);
rb_hrtime_t u = rb_hrtime_mul((rb_hrtime_t)tv->tv_usec, RB_HRTIME_PER_USEC);
return rb_hrtime_add(s, u);
}
static inline rb_hrtime_t
rb_timespec2hrtime(const struct timespec *ts)
{
rb_hrtime_t s = rb_hrtime_mul((rb_hrtime_t)ts->tv_sec, RB_HRTIME_PER_SEC);
return rb_hrtime_add(s, (rb_hrtime_t)ts->tv_nsec);
}
static inline rb_hrtime_t
rb_msec2hrtime(unsigned long msec)
{
return rb_hrtime_mul((rb_hrtime_t)msec, RB_HRTIME_PER_MSEC);
}
static inline rb_hrtime_t
rb_sec2hrtime(time_t sec)
{
if (sec <= 0) return 0;
return rb_hrtime_mul((rb_hrtime_t)sec, RB_HRTIME_PER_SEC);
}
static inline struct timespec *
rb_hrtime2timespec(struct timespec *ts, const rb_hrtime_t *hrt)
{
if (hrt) {
ts->tv_sec = (time_t)(*hrt / RB_HRTIME_PER_SEC);
ts->tv_nsec = (int32_t)(*hrt % RB_HRTIME_PER_SEC);
return ts;
}
return 0;
}
static inline struct timeval *
rb_hrtime2timeval(struct timeval *tv, const rb_hrtime_t *hrt)
{
if (hrt) {
tv->tv_sec = (time_t)(*hrt / RB_HRTIME_PER_SEC);
tv->tv_usec = (int32_t)((*hrt % RB_HRTIME_PER_SEC)/RB_HRTIME_PER_USEC);
return tv;
}
return 0;
}
#endif