#include #include #include "sidetiq_ext.h" #ifdef __APPLE__ #include #include #include #include #include #include #include #include #else #include #endif VALUE msidetiq; VALUE esidetiq_error; VALUE csidetiq_clock; #ifdef __APPLE__ static mach_timebase_info_data_t clock_gettime_inf; typedef enum { CLOCK_REALTIME, CLOCK_MONOTONIC, CLOCK_PROCESS_CPUTIME_ID, CLOCK_THREAD_CPUTIME_ID } clockid_t; int clock_gettime(clockid_t clk_id, struct timespec *tp) { kern_return_t ret; clock_serv_t clk; clock_id_t clk_serv_id; mach_timespec_t tm; uint64_t start, end, delta, nano; int retval = -1; switch (clk_id) { case CLOCK_REALTIME: case CLOCK_MONOTONIC: clk_serv_id = clk_id == CLOCK_REALTIME ? CALENDAR_CLOCK : SYSTEM_CLOCK; if (KERN_SUCCESS == (ret = host_get_clock_service(mach_host_self(), clk_serv_id, &clk))) { if (KERN_SUCCESS == (ret = clock_get_time(clk, &tm))) { tp->tv_sec = tm.tv_sec; tp->tv_nsec = tm.tv_nsec; retval = 0; } } if (KERN_SUCCESS != ret) { errno = EINVAL; retval = -1; } break; case CLOCK_PROCESS_CPUTIME_ID: case CLOCK_THREAD_CPUTIME_ID: start = mach_absolute_time(); if (clk_id == CLOCK_PROCESS_CPUTIME_ID) { getpid(); } else { sched_yield(); } end = mach_absolute_time(); delta = end - start; if (0 == clock_gettime_inf.denom) { mach_timebase_info(&clock_gettime_inf); } nano = delta * clock_gettime_inf.numer / clock_gettime_inf.denom; tp->tv_sec = nano * 1e-9; tp->tv_nsec = nano - (tp->tv_sec * 1e9); retval = 0; break; default: errno = EINVAL; retval = -1; } return retval; } #endif static VALUE sidetiq_gettime(VALUE self) { struct timespec time; assert(clock_gettime(CLOCK_REALTIME, &time) == 0); return rb_time_nano_new(time.tv_sec, time.tv_nsec); } void Init_sidetiq_ext() { msidetiq = rb_define_module("Sidetiq"); esidetiq_error = rb_define_class_under(msidetiq, "Error", rb_eStandardError); csidetiq_clock = rb_define_class_under(msidetiq, "Clock", rb_cObject); rb_define_private_method(csidetiq_clock, "clock_gettime", sidetiq_gettime, 0); }