From: Eric Wong Date: 2010-09-23T09:27:17+09:00 Subject: [ruby-core:32508] Re: non-blocking I/O (still) clearing cache (ref: ) Eric Wong wrote: > Tanaka Akira wrote: > > * create and cache a subclass of Errno::EAGAIN which includes IO::WaitReadable. > > I think caching the subclass is still needed. Here's my attempt to add caching, test/socket/test_nonblock.rb passes From f0c274e9e87634f47515a68bb18693d9d8423bc8 Mon Sep 17 00:00:00 2001 From: Eric Wong Date: Wed, 22 Sep 2010 17:20:28 -0700 Subject: [PATCH] error.c (rb_mod_sys_fail): use subclass and cache While r28813 avoids clearing the method cache upon extending with IO::Wait{Read,Writ}able modules, the method cache still gets scanned and partially cleared when the exceptions are garbage collected. Reusing the same subclass now prevents rb_clear_cache_by_class() from showing up at/near the top of profiler output. --- error.c | 40 ++++++++++++++++++++++++++++++++++++++-- 1 files changed, 38 insertions(+), 2 deletions(-) diff --git a/error.c b/error.c index 479caff..bc7edef 100644 --- a/error.c +++ b/error.c @@ -27,6 +27,8 @@ extern const char ruby_description[]; +static VALUE mod_sys_fail_cache; + static const char * rb_strerrno(int err) { @@ -1541,8 +1543,42 @@ rb_sys_fail(const char *mesg) void rb_mod_sys_fail(VALUE mod, const char *mesg) { - VALUE exc = make_errno_exc(mesg); - rb_extend_object(exc, mod); + int n = errno; + int need_aset_tmp = 0; + VALUE super_class; + VALUE cached_class; + VALUE per_class; + VALUE exc; + VALUE arg; + + errno = 0; + if (n == 0) { + rb_bug("rb_mod_sys_fail(%s) - errno == 0", mesg ? mesg : ""); + } + super_class = get_syserr(n); + + if (! mod_sys_fail_cache) { + mod_sys_fail_cache = rb_hash_new(); + rb_global_variable(&mod_sys_fail_cache); + } + per_class = rb_hash_aref(mod_sys_fail_cache, super_class); + + if (NIL_P(per_class)) { + need_aset_tmp = 1; + per_class = rb_hash_new(); + } + + cached_class = rb_hash_aref(per_class, mod); + if (NIL_P(cached_class)) { + cached_class = rb_obj_dup(super_class); + rb_include_module(cached_class, mod); + rb_hash_aset(per_class, mod, cached_class); + if (need_aset_tmp) + rb_hash_aset(mod_sys_fail_cache, super_class, per_class); + } + + arg = mesg ? rb_str_new2(mesg) : Qnil; + exc = rb_class_new_instance(1, &arg, cached_class); rb_exc_raise(exc); } -- Eric Wong