diff options
-rw-r--r-- | ChangeLog | 35 | ||||
-rw-r--r-- | variable.c | 59 | ||||
-rw-r--r-- | version.h | 2 |
3 files changed, 87 insertions, 9 deletions
@@ -1,3 +1,38 @@ +Thu Jun 2 18:33:51 2011 URABE Shyouhei <shyouhei@ruby-lang.org> + + * variable.c (rb_const_get_0): Fix previous change. There were + possibilities when an autoload-specified library lacks + definition of the constant it was bound to. Once after such + library had already beed loaded, the autoload engine shall not + reload it. Instead the interpreter have to consider such + constant nonexistent. It results in a const_missing situation. + + * variable.c (rb_autoload_load): ditto. + + * variable.c (autoload_node): ditto. + +Thu Jun 2 18:28:58 2011 URABE Shyouhei <shyouhei@ruby-lang.org> + + * variable.c (rb_autoload_load): There is a race condition while + autoloading. When two or more threads touch a single autoloaded + constant at a time, one of them does the require, but others + behave oddly. To fix this situation we now refrain from + deleting the autoload table while someone is doing the autoload. + That deletion is deferred to a point where a require ended + successfully. Doing so make it possible for multiple threads to + enter autoloading at the same time but the require is protected + against multiple simultaneous entrance anyway so all but one + thread gets blocked at that point. So with it, touching a + constant that gets autoloaded cause those threads to block until + there is another one that does the same thing. + [ruby-core:36308] (#921) + + * variable.c (rb_const_get_0): ditto. + + * variable.c (autoload_node): ditto. + + * variable.c (autoload_delete): ditto. + Mon May 30 10:58:17 2011 Hiroshi Nakamura <nahi@ruby-lang.org> * lib/logger.rb (Logger::ProgName): do not depend on subversion diff --git a/variable.c b/variable.c index 53143ca190..98c3940a16 100644 --- a/variable.c +++ b/variable.c @@ -1331,7 +1331,6 @@ autoload_delete(mod, id) VALUE val; st_data_t load = 0; - st_delete(RCLASS(mod)->iv_tbl, (st_data_t*)&id, 0); if (st_lookup(RCLASS(mod)->iv_tbl, autoload, &val)) { struct st_table *tbl = check_autoload_table(val); @@ -1346,18 +1345,55 @@ autoload_delete(mod, id) return (NODE *)load; } +static NODE * +autoload_node(mod, id) + VALUE mod; + ID id; +{ + st_data_t val, load, n = id; + struct st_table *p, *q; + + if ((p = RCLASS(mod)->iv_tbl) == 0) { + return 0; + } + else if (!st_lookup(p, n, &val)) { + return 0; + } + else if (val != Qundef) { + return 0; + } + else if (!st_lookup(p, autoload, &val)) { + return 0; + } + else if ((q = check_autoload_table((VALUE)val)) == 0) { + return 0; + } + else if (!st_lookup(q, n, &load)) { + return 0; + } + else { + return (NODE *)load; + } +} + VALUE rb_autoload_load(klass, id) VALUE klass; ID id; { - VALUE file; - NODE *load = autoload_delete(klass, id); + NODE *load = 0; + VALUE ret = 0; - if (!load || !(file = load->nd_lit) || rb_provided(RSTRING(file)->ptr)) { - return Qfalse; + if ((load = autoload_node(klass, id)) == 0) { + return 0; + } + else if ((ret = rb_require_safe(load->nd_lit, load->nd_nth)) == Qfalse) { + return 0; + } + else { + (void) autoload_delete(klass, id); + return ret; } - return rb_require_safe(file, load->nd_nth); } static VALUE @@ -1419,8 +1455,15 @@ rb_const_get_0(klass, id, exclude, recurse) while (tmp) { while (RCLASS(tmp)->iv_tbl && st_lookup(RCLASS(tmp)->iv_tbl,id,&value)) { if (value == Qundef) { - if (!RTEST(rb_autoload_load(tmp, id))) break; - continue; + rb_autoload_load(tmp, id); + st_lookup(RCLASS(tmp)->iv_tbl, id, &value); + if (value == Qundef) { + /* the autoload above did not assign a constant */ + break; + } + else { + continue; + } } if (exclude && tmp == rb_cObject && klass != rb_cObject) { rb_warn("toplevel constant %s referenced by %s::%s", @@ -2,7 +2,7 @@ #define RUBY_RELEASE_DATE "2011-06-02" #define RUBY_VERSION_CODE 187 #define RUBY_RELEASE_CODE 20110602 -#define RUBY_PATCHLEVEL 347 +#define RUBY_PATCHLEVEL 348 #define RUBY_VERSION_MAJOR 1 #define RUBY_VERSION_MINOR 8 |