summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog35
-rw-r--r--variable.c59
-rw-r--r--version.h2
3 files changed, 87 insertions, 9 deletions
diff --git a/ChangeLog b/ChangeLog
index 95aeda318e..92b1334eb7 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -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",
diff --git a/version.h b/version.h
index 78bd05115f..deec715ef6 100644
--- a/version.h
+++ b/version.h
@@ -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