summaryrefslogtreecommitdiff
path: root/eval_load.c
diff options
context:
space:
mode:
authornobu <nobu@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2007-05-03 13:19:11 +0000
committernobu <nobu@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2007-05-03 13:19:11 +0000
commit1a89cc308d823033715131c2709a009ee971eb28 (patch)
tree1b7449c06b8a8ca3a73d629083810fb85857673d /eval_load.c
parent5bfe949dd543199a1776f1f816d47217837b896d (diff)
* configure.in, defines.h, eval_load.c (rb_feature_p, rb_provided,
search_required, rb_require_safe), ext/extmk.rb: Fix a bug where a statically linked extension cannot be autoloaded. [ruby-dev:30023] / [ruby-dev:30239] * thread.c: added an internal class, Barrier. * yarvcore.h (struct rb_vm_struct): moved loading_table from global. git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@12246 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
Diffstat (limited to 'eval_load.c')
-rw-r--r--eval_load.c184
1 files changed, 113 insertions, 71 deletions
diff --git a/eval_load.c b/eval_load.c
index 3210422bc4..f7375381ec 100644
--- a/eval_load.c
+++ b/eval_load.c
@@ -7,7 +7,6 @@
extern VALUE ruby_top_self;
VALUE ruby_dln_librefs;
-static st_table *loading_tbl;
#define IS_SOEXT(e) (strcmp(e, ".so") == 0 || strcmp(e, ".o") == 0)
#ifdef DLEXT2
@@ -16,18 +15,34 @@ static st_table *loading_tbl;
#define IS_DLEXT(e) (strcmp(e, DLEXT) == 0)
#endif
+
+static const char *const loadable_ext[] = {
+ ".rb", DLEXT,
+#ifdef DLEXT2
+ DLEXT2,
+#endif
+ 0
+};
+
static VALUE
get_loaded_features(void)
{
return GET_VM()->loaded_features;
}
+static st_table *
+get_loading_table(void)
+{
+ return GET_VM()->loading_table;
+}
+
static int
rb_feature_p(const char *feature, const char *ext, int rb)
{
- VALUE v;
- char *f, *e;
+ VALUE v, features;
+ const char *f, *e;
long i, len, elen;
+ st_table *loading_tbl;
if (ext) {
len = ext - feature;
@@ -37,18 +52,17 @@ rb_feature_p(const char *feature, const char *ext, int rb)
len = strlen(feature);
elen = 0;
}
- for (i = 0; i < RARRAY_LEN(get_loaded_features()); ++i) {
- v = RARRAY_PTR(get_loaded_features())[i];
+ features = get_loaded_features();
+ for (i = 0; i < RARRAY_LEN(features); ++i) {
+ v = RARRAY_PTR(features)[i];
f = StringValuePtr(v);
- if (strncmp(f, feature, len) != 0)
+ if (RSTRING_LEN(v) < len || strncmp(f, feature, len) != 0)
continue;
if (!*(e = f + len)) {
- if (ext)
- continue;
+ if (ext) continue;
return 'u';
}
- if (*e != '.')
- continue;
+ if (*e != '.') continue;
if ((!rb || !ext) && (IS_SOEXT(e) || IS_DLEXT(e))) {
return 's';
}
@@ -56,46 +70,47 @@ rb_feature_p(const char *feature, const char *ext, int rb)
return 'r';
}
}
+ loading_tbl = get_loading_table();
+ if (loading_tbl) {
+ if (st_lookup(loading_tbl, (st_data_t)feature, 0)) {
+ if (!ext) return 'u';
+ return strcmp(ext, ".rb") ? 's' : 'r';
+ }
+ else {
+ char *buf;
+
+ if (ext && *ext) return 0;
+ buf = ALLOCA_N(char, len + DLEXT_MAXLEN + 1);
+ MEMCPY(buf, feature, char, len);
+ for (i = 0; (e = loadable_ext[i]) != 0; i++) {
+ strncpy(buf + len, e, DLEXT_MAXLEN + 1);
+ if (st_lookup(loading_tbl, (st_data_t)buf, 0)) {
+ return i ? 's' : 'r';
+ }
+ }
+ }
+ }
return 0;
}
-static const char *const loadable_ext[] = {
- ".rb", DLEXT,
-#ifdef DLEXT2
- DLEXT2,
-#endif
- 0
-};
-
-static int search_required _((VALUE, VALUE *));
-
int
rb_provided(const char *feature)
{
- int i;
- char *buf;
- VALUE fname;
+ const char *ext = strrchr(feature, '.');
- if (rb_feature_p(feature, 0, Qfalse))
- return Qtrue;
- if (loading_tbl) {
- if (st_lookup(loading_tbl, (st_data_t) feature, 0))
- return Qtrue;
- buf = ALLOCA_N(char, strlen(feature) + 8);
- strcpy(buf, feature);
- for (i = 0; loadable_ext[i]; i++) {
- strcpy(buf + strlen(feature), loadable_ext[i]);
- if (st_lookup(loading_tbl, (st_data_t) buf, 0))
- return Qtrue;
+ if (ext && !strchr(ext, '/')) {
+ if (strcmp(".rb", ext) == 0) {
+ if (rb_feature_p(feature, ext, Qtrue)) return Qtrue;
+ return Qfalse;
+ }
+ else if (IS_SOEXT(ext) || IS_DLEXT(ext)) {
+ if (rb_feature_p(feature, ext, Qfalse)) return Qtrue;
+ return Qfalse;
}
}
- if (search_required(rb_str_new2(feature), &fname)) {
- feature = RSTRING_PTR(fname);
- if (rb_feature_p(feature, 0, Qfalse))
- return Qtrue;
- if (loading_tbl && st_lookup(loading_tbl, (st_data_t) feature, 0))
- return Qtrue;
- }
+ if (rb_feature_p(feature, feature + strlen(feature), Qtrue))
+ return Qtrue;
+
return Qfalse;
}
@@ -237,21 +252,43 @@ rb_f_load(argc, argv)
return Qtrue;
}
-static int
-load_wait(char *ftptr)
+static char *
+load_lock(const char *ftptr)
{
- st_data_t th;
- if (!loading_tbl) {
- return Qfalse;
- }
- if (!st_lookup(loading_tbl, (st_data_t) ftptr, &th)) {
- return Qfalse;
+ st_data_t data;
+ st_table *loading_tbl = get_loading_table();
+
+ if (!loading_tbl || !st_lookup(loading_tbl, (st_data_t)ftptr, &data)) {
+ /* loading ruby library should be serialized. */
+ if (!loading_tbl) {
+ GET_VM()->loading_table = loading_tbl = st_init_strtable();
+ }
+ /* partial state */
+ ftptr = ruby_strdup(ftptr);
+ data = (st_data_t)rb_barrier_new();
+ st_insert(loading_tbl, (st_data_t)ftptr, data);
+ return (char *)ftptr;
}
+ rb_barrier_wait((VALUE)data);
+ return 0;
+}
- /* TODO: write wait routine */
- return Qtrue;
+static void
+load_unlock(const char *ftptr)
+{
+ if (ftptr) {
+ st_data_t key = (st_data_t)ftptr;
+ st_data_t data;
+ st_table *loading_tbl = get_loading_table();
+
+ if (st_delete(loading_tbl, &key, &data)) {
+ free((char *)key);
+ rb_barrier_release((VALUE)data);
+ }
+ }
}
+
/*
* call-seq:
* require(string) => true or false
@@ -346,16 +383,16 @@ search_required(VALUE fname, VALUE *path)
type = rb_find_file_ext(&tmp, loadable_ext);
tmp = rb_file_expand_path(tmp, Qnil);
switch (type) {
- case 0:
+ case 0:
ftptr = RSTRING_PTR(tmp);
if (ft)
break;
return rb_feature_p(ftptr, 0, Qfalse);
- default:
+ default:
if (ft)
break;
- case 1:
+ case 1:
ext = strrchr(ftptr = RSTRING_PTR(tmp), '.');
if (rb_feature_p(ftptr, ext, !--type))
break;
@@ -375,8 +412,8 @@ VALUE
rb_require_safe(VALUE fname, int safe)
{
VALUE result = Qnil;
- volatile VALUE errinfo = GET_THREAD()->errinfo;
rb_thread_t *th = GET_THREAD();
+ volatile VALUE errinfo = th->errinfo;
int state;
struct {
NODE *node;
@@ -397,25 +434,17 @@ rb_require_safe(VALUE fname, int safe)
*(volatile VALUE *)&fname = rb_str_new4(fname);
found = search_required(fname, &path);
if (found) {
- if (!path || load_wait(RSTRING_PTR(path))) {
+ if (!path || !(ftptr = load_lock(RSTRING_PTR(path)))) {
result = Qfalse;
}
else {
rb_set_safe_level_force(0);
switch (found) {
- case 'r':
- /* loading ruby library should be serialized. */
- if (!loading_tbl) {
- loading_tbl = st_init_strtable();
- }
- /* partial state */
- ftptr = ruby_strdup(RSTRING_PTR(path));
- st_insert(loading_tbl, (st_data_t) ftptr,
- (st_data_t) GET_THREAD()->self);
+ case 'r':
rb_load(path, 0);
break;
- case 's':
+ case 's':
ruby_current_node = 0;
ruby_sourcefile = rb_source_filename(RSTRING_PTR(path));
ruby_sourceline = 0;
@@ -430,12 +459,8 @@ rb_require_safe(VALUE fname, int safe)
}
}
POP_TAG();
+ load_unlock(ftptr);
- if (ftptr) {
- if (st_delete(loading_tbl, (st_data_t *) & ftptr, 0)) { /* loading done */
- free(ftptr);
- }
- }
ruby_current_node = saved.node;
rb_set_safe_level_force(saved.safe);
if (state) {
@@ -459,6 +484,23 @@ rb_require(const char *fname)
return rb_require_safe(fn, rb_safe_level());
}
+void
+ruby_init_ext(const char *name, void (*init)(void))
+{
+ rb_control_frame_t *frame = GET_THREAD()->cfp;
+
+ ruby_current_node = 0;
+ ruby_sourcefile = rb_source_filename(name);
+ ruby_sourceline = 0;
+ frame->method_id = 0;
+ SCOPE_SET(NOEX_PUBLIC);
+ if (load_lock(name)) {
+ (*init)();
+ rb_provide(name);
+ load_unlock(name);
+ }
+}
+
/*
* call-seq:
* mod.autoload(name, filename) => nil