/* * Copyright (C) 2018 Ruby hackers * License: LGPL-2.1+ */ #include #include #include static VALUE eUncaughtThrow; static void * rb_timers_create(void) { struct timers *t = ALLOC(struct timers); timers_init(t, time_mono()); return t; } static void rb_timer_add(struct timers *timers, struct timer *t, struct timespec *ts) { struct timerel rel; rel.ts = *ts; timer_init(t); timer_addrel(timers, t, rel); } static void * rb_timers_expire(struct timers *timers) { return timers_expire(timers, time_mono()); } static void * rb_timers_earliest(struct timers *timers, struct timespec *rel) { struct timemono now; struct timemono first; if (!timer_earliest(timers, &first)) return 0; now = time_mono(); if (time_greater_(first.ts, now.ts)) { struct timerel ret = timemono_between(first, now); *rel = ret.ts; } else { rel->tv_sec = 0; rel->tv_nsec = 0; } return rel; } void rb_timers_destroy(void *p) { struct timers *timers = p; timers_cleanup(timers); xfree(timers); } static struct rb_timers_type0 ccan_timers = { /* .create = */ rb_timers_create, /* .add = */ rb_timer_add, /* .expire = */ rb_timers_expire, /* .earliest = */ rb_timers_earliest, /* .destroy = */ rb_timers_destroy }; static VALUE begin_throw(VALUE self) { rb_throw_obj(self, self); return self; } static VALUE rescue_throw(VALUE ignore, VALUE err) { return Qfalse; } /* * We don't want to generate a backtrace like the version * in timeout.rb does. We also want to raise the same * exception object so rb_s_timeout (in core) can match * against it without relying on an extra proc for: * * proc { |exception| return yield(sec) } */ static VALUE rb_timeout_error_exception(int argc, VALUE *argv, VALUE self) { if (rb_attr_get(self, rb_intern("@thread")) == rb_thread_current()) { rb_rescue2(begin_throw, self, rescue_throw, Qfalse, eUncaughtThrow, 0); } return self; } void Init_timeout_ext(void) { #undef rb_intern VALUE mTimeout = rb_const_get(rb_cObject, rb_intern("Timeout")); VALUE cError = rb_const_get(mTimeout, rb_intern("Error")); eUncaughtThrow = rb_const_get(rb_cObject, rb_intern("UncaughtThrowError")); rb_timers = &ccan_timers; rb_define_method(mTimeout, "timeout", rb_s_timeout, -1); rb_define_singleton_method(mTimeout, "timeout", rb_s_timeout, -1); rb_undef_method(cError, "exception"); rb_define_method(cError, "exception", rb_timeout_error_exception, -1); }