From cc43cfbb418ab7b4b2786123d33ede23b3cb5ea3 Mon Sep 17 00:00:00 2001 From: Eric Wong Date: Fri, 14 Jan 2011 09:07:57 +0000 Subject: another workaround for systems with broken CLOCK_MONOTONIC This should also detect cases where CLOCK_MONOTONIC is available at build but not at runtime. --- ext/clogger_ext/broken_system_compat.h | 17 +++++++++++---- ext/clogger_ext/clogger.c | 38 ++++++++++++++++++++++++++++------ ext/clogger_ext/extconf.rb | 5 +++-- 3 files changed, 48 insertions(+), 12 deletions(-) diff --git a/ext/clogger_ext/broken_system_compat.h b/ext/clogger_ext/broken_system_compat.h index f58307e..ec635b1 100644 --- a/ext/clogger_ext/broken_system_compat.h +++ b/ext/clogger_ext/broken_system_compat.h @@ -3,11 +3,15 @@ * without clock_gettime() or CLOCK_MONOTONIC */ +#ifndef HAVE_TYPE_CLOCKID_T +typedef clockid_t int; +#endif + #ifndef HAVE_CLOCK_GETTIME # ifndef CLOCK_REALTIME # define CLOCK_REALTIME 0 /* whatever */ # endif -static int fake_clock_gettime(int clk_id, struct timespec *res) +static int fake_clock_gettime(clockid_t clk_id, struct timespec *res) { struct timeval tv; int r = gettimeofday(&tv, NULL); @@ -21,7 +25,12 @@ static int fake_clock_gettime(int clk_id, struct timespec *res) # define clock_gettime fake_clock_gettime #endif /* broken systems w/o clock_gettime() */ -/* UGH */ -#ifndef _POSIX_MONOTONIC_CLOCK -# define CLOCK_MONOTONIC CLOCK_REALTIME +/* + * UGH + * CLOCK_MONOTONIC is not guaranteed to be a macro, either + */ +#ifndef CLOCK_MONOTONIC +# if (!defined(_POSIX_MONOTONIC_CLOCK) || !defined(HAVE_CLOCK_MONOTONIC)) +# define CLOCK_MONOTONIC CLOCK_REALTIME +# endif #endif diff --git a/ext/clogger_ext/clogger.c b/ext/clogger_ext/clogger.c index 7e01e6d..604b9b6 100644 --- a/ext/clogger_ext/clogger.c +++ b/ext/clogger_ext/clogger.c @@ -13,11 +13,38 @@ #ifdef HAVE_FCNTL_H # include #endif -#define _POSIX_C_SOURCE 200112L +#ifndef _POSIX_C_SOURCE +# define _POSIX_C_SOURCE 200112L +#endif #include #include "ruby_1_9_compat.h" #include "broken_system_compat.h" +/* + * Availability of a monotonic clock needs to be detected at runtime + * since we could've been built on a different system than we're run + * under. + */ +static clockid_t hopefully_CLOCK_MONOTONIC = CLOCK_MONOTONIC; + +static void check_clock(void) +{ + struct timespec now; + + /* we can't check this reliably at compile time */ + if (clock_gettime(CLOCK_MONOTONIC, &now) == 0) + return; + + if (clock_gettime(CLOCK_REALTIME, &now) == 0) { + hopefully_CLOCK_MONOTONIC = CLOCK_REALTIME; + rb_warn("CLOCK_MONOTONIC not available, " + "falling back to CLOCK_REALTIME"); + } + rb_warn("clock_gettime() totally broken, " \ + "falling back to pure Ruby Clogger"); + rb_raise(rb_eLoadError, "clock_gettime() broken"); +} + static void clock_diff(struct timespec *a, const struct timespec *b) { a->tv_sec -= b->tv_sec; @@ -346,11 +373,8 @@ static void append_ts(struct clogger *c, const VALUE *op, struct timespec *ts) static void append_request_time_fmt(struct clogger *c, const VALUE *op) { struct timespec now; - int r = clock_gettime(CLOCK_MONOTONIC, &now); - - if (unlikely(r != 0)) - rb_sys_fail("clock_gettime(CLOCK_MONONTONIC)"); + clock_gettime(hopefully_CLOCK_MONOTONIC, &now); clock_diff(&now, &c->ts_start); append_ts(c, op, &now); } @@ -724,7 +748,7 @@ static VALUE ccall(struct clogger *c, VALUE env) { VALUE rv; - clock_gettime(CLOCK_MONOTONIC, &c->ts_start); + clock_gettime(hopefully_CLOCK_MONOTONIC, &c->ts_start); c->env = env; c->cookies = Qfalse; rv = rb_funcall(c->app, call_id, 1, env); @@ -859,6 +883,8 @@ void Init_clogger_ext(void) { VALUE tmp; + check_clock(); + ltlt_id = rb_intern("<<"); call_id = rb_intern("call"); each_id = rb_intern("each"); diff --git a/ext/clogger_ext/extconf.rb b/ext/clogger_ext/extconf.rb index d87d8c2..85f2d30 100644 --- a/ext/clogger_ext/extconf.rb +++ b/ext/clogger_ext/extconf.rb @@ -13,10 +13,11 @@ begin have_macro('O_NONBLOCK', %w(unistd.h fcntl.h)) end - unless have_macro('CLOCK_MONOTONIC', 'time.h', '-D_POSIX_C_SOURCE=200112L') - $CPPFLAGS += '-D_POSIX_SOURCE_200112L' + $CPPFLAGS += '-D_POSIX_C_SOURCE=200112L' + unless have_macro('CLOCK_MONOTONIC', 'time.h') have_func('CLOCK_MONOTONIC', 'time.h') end + have_type('clockid_t', 'time.h') have_func('clock_gettime', 'time.h') have_func('localtime_r', 'time.h') or raise "localtime_r needed" have_func('gmtime_r', 'time.h') or raise "gmtime_r needed" -- cgit v1.2.3-24-ge0c7