From: Nobuyoshi Nakada Date: 2006-12-20T01:07:11+09:00 Subject: [ruby-dev:30037] Re: autoloading static linked extension なかだです。 At Tue, 19 Dec 2006 07:43:02 +0900, Akinori MUSHA wrote in [ruby-dev:30027]: >  rb_provided() の if ブロックは括弧が抜けていますか? すいません、抜けてるというか、直しかけだったようです。 >  1.8 については手元でテストしたいので別途ッチをお願いします。 これでどうでしょうか。 Index: eval.c =================================================================== RCS file: /pub/cvs/ruby/src/ruby/eval.c,v retrieving revision 1.616.2.200 diff -U 2 -p -r1.616.2.200 eval.c --- eval.c 9 Dec 2006 12:40:17 -0000 1.616.2.200 +++ eval.c 19 Dec 2006 15:51:06 -0000 @@ -6930,5 +6930,14 @@ static st_table *loading_tbl; #endif -static char * + +static const char *const loadable_ext[] = { + ".rb", DLEXT, +#ifdef DLEXT2 + DLEXT2, +#endif + 0 +}; + +static int rb_feature_p(feature, ext, rb) const char *feature, *ext; @@ -6936,5 +6945,5 @@ rb_feature_p(feature, ext, rb) { VALUE v; - char *f, *e; + const char *f, *e; long i, len, elen; @@ -6947,30 +6956,42 @@ rb_feature_p(feature, ext, rb) elen = 0; } - for (i = 0; i < RARRAY(rb_features)->len; ++i) { - v = RARRAY(rb_features)->ptr[i]; + for (i = 0; i < RARRAY_LEN(rb_features); ++i) { + v = RARRAY_PTR(rb_features)[i]; f = StringValuePtr(v); - if (strncmp(f, feature, len) != 0) continue; + if (RSTRING_LEN(v) < len || strncmp(f, feature, len) != 0) + continue; if (!*(e = f + len)) { if (ext) continue; - return e; + return 'u'; } if (*e != '.') continue; if ((!rb || !ext) && (IS_SOEXT(e) || IS_DLEXT(e))) { - return e; + return 's'; } if ((rb || !ext) && (strcmp(e, ".rb") == 0)) { - return e; + return 'r'; + } + } + if (loading_tbl) { + e = ext; + if (!st_lookup(loading_tbl, (st_data_t)feature, 0)) { + char *buf; + + if (ext) return 0; + buf = ALLOCA_N(char, len+8); + strcpy(buf, feature); + for (i = 0; (e = loadable_ext[i]) != 0; i++) { + strcpy(buf + len, loadable_ext[i]); + if (st_lookup(loading_tbl, (st_data_t)buf, 0)) { + break; + } + } } + return !e ? 'u' : strcmp(e, ".rb") ? 's' : 'r'; } return 0; } -static const char *const loadable_ext[] = { - ".rb", DLEXT, -#ifdef DLEXT2 - DLEXT2, -#endif - 0 -}; +static int search_required(VALUE, VALUE *, VALUE *); int @@ -6978,17 +6999,12 @@ rb_provided(feature) const char *feature; { - int i; - char *buf; + VALUE fname, path; if (rb_feature_p(feature, 0, Qfalse)) return Qtrue; - if (!loading_tbl) return Qfalse; - 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; ; i++) { - if (!loadable_ext[i]) break; - strcpy(buf+strlen(feature), loadable_ext[i]); - if (st_lookup(loading_tbl, (st_data_t)buf, 0)) return Qtrue; + if (search_required(rb_str_new2(feature), &fname, &path) != 0) { + feature = RSTRING_PTR(fname); + if (rb_feature_p(feature, strrchr(feature, '.'), Qfalse)) + return Qtrue; } return Qfalse; @@ -7009,17 +7025,39 @@ rb_provide(feature) } -static int -load_wait(ftptr) - char *ftptr; +static char * +load_lock(ftptr) + const char *ftptr; { st_data_t th; - if (!loading_tbl) return Qfalse; - if (!st_lookup(loading_tbl, (st_data_t)ftptr, &th)) return Qfalse; + if (!loading_tbl || + !st_lookup(loading_tbl, (st_data_t)ftptr, &th)) + { + /* loading ruby library should be serialized. */ + if (!loading_tbl) { + loading_tbl = st_init_strtable(); + } + /* partial state */ + ftptr = ruby_strdup(ftptr); + st_insert(loading_tbl, (st_data_t)ftptr, (st_data_t)curr_thread); + return (char *)ftptr; + } do { - if ((rb_thread_t)th == curr_thread) return Qtrue; + if ((rb_thread_t)th == curr_thread) return 0; CHECK_INTS; } while (st_lookup(loading_tbl, (st_data_t)ftptr, &th)); - return Qtrue; + return 0; +} + +static void +load_unlock(const char *ftptr) +{ + if (ftptr) { + st_data_t key = (st_data_t)ftptr; + + if (st_delete(loading_tbl, &key, 0)) { + free((char *)key); + } + } } @@ -7063,14 +7101,14 @@ search_required(fname, featurep, path) *featurep = fname; *path = 0; - ext = strrchr(ftptr = RSTRING(fname)->ptr, '.'); + ext = strrchr(ftptr = RSTRING_PTR(fname), '.'); if (ext && !strchr(ext, '/')) { if (strcmp(".rb", ext) == 0) { if (rb_feature_p(ftptr, ext, Qtrue)) return 'r'; - if (*path = rb_find_file(fname)) return 'r'; + if ((*path = rb_find_file(fname)) != 0) return 'r'; return 0; } else if (IS_SOEXT(ext)) { if (rb_feature_p(ftptr, ext, Qfalse)) return 's'; - tmp = rb_str_new(RSTRING(fname)->ptr, ext-RSTRING(fname)->ptr); + tmp = rb_str_new(RSTRING_PTR(fname), ext-RSTRING_PTR(fname)); *featurep = tmp; #ifdef DLEXT2 @@ -7091,18 +7129,16 @@ search_required(fname, featurep, path) else if (IS_DLEXT(ext)) { if (rb_feature_p(ftptr, ext, Qfalse)) return 's'; - if (*path = rb_find_file(fname)) return 's'; + if ((*path = rb_find_file(fname)) != 0) return 's'; } } tmp = fname; - switch (type = rb_find_file_ext(&tmp, loadable_ext)) { + type = rb_find_file_ext(&tmp, loadable_ext); + *featurep = tmp; + switch (type) { case 0: - if ((ext = rb_feature_p(ftptr, 0, Qfalse))) { - type = strcmp(".rb", ext); - break; - } - return 0; + ftptr = RSTRING_PTR(tmp); + return rb_feature_p(ftptr, 0, Qfalse); default: - *featurep = tmp; ext = strrchr(ftptr = RSTRING(tmp)->ptr, '.'); if (rb_feature_p(ftptr, ext, !--type)) break; @@ -7152,16 +7188,9 @@ rb_require_safe(fname, safe) found = search_required(fname, &feature, &path); if (found) { - if (!path || load_wait(RSTRING(feature)->ptr)) { + if (!path || !(ftptr = load_lock(RSTRING_PTR(feature)))) { result = Qfalse; } else { ruby_safe_level = 0; - /* loading ruby library should be serialized. */ - if (!loading_tbl) { - loading_tbl = st_init_strtable(); - } - /* partial state */ - ftptr = ruby_strdup(RSTRING_PTR(feature)); - st_insert(loading_tbl, (st_data_t)ftptr, (st_data_t)curr_thread); switch (found) { case 'r': @@ -7190,9 +7219,5 @@ rb_require_safe(fname, safe) SCOPE_SET(saved.vmode); ruby_safe_level = saved.safe; - if (ftptr) { - if (st_delete(loading_tbl, (st_data_t *)&ftptr, 0)) { /* loading done */ - free(ftptr); - } - } + load_unlock(ftptr); if (state) JUMP_TAG(state); if (NIL_P(result)) { @@ -7213,4 +7238,22 @@ rb_require(fname) } +void +ruby_init_ext(name, init) + const char *name; + void (*init) _((void)); +{ + ruby_current_node = 0; + ruby_sourcefile = rb_source_filename(name); + ruby_sourceline = 0; + ruby_frame->last_func = 0; + ruby_frame->orig_func = 0; + SCOPE_SET(SCOPE_PUBLIC); + if (load_lock(name)) { + (*init)(); + rb_provide(name); + load_unlock(name); + } +} + static void secure_visibility(self) Index: ext/extmk.rb =================================================================== RCS file: /pub/cvs/ruby/src/ruby/ext/extmk.rb,v retrieving revision 1.44.2.37 diff -U 2 -p -r1.44.2.37 extmk.rb --- ext/extmk.rb 19 Oct 2006 16:03:45 -0000 1.44.2.37 +++ ext/extmk.rb 19 Dec 2006 15:54:28 -0000 @@ -452,12 +452,9 @@ unless $extlist.empty? #include "ruby.h" -#define init(func, name) { \ - void func _((void)); \ - ruby_sourcefile = src = rb_source_filename(name); \ - func(); \ - rb_provide(src); \ -} +#define init(func, name) {void func _((void)); ruby_init_ext(name, func);} + +void ruby_init_ext _((const char *name, void (*init)(void))); -void Init_ext _((void))\n{\n char *src;#$extinit} +void Init_ext _((void))\n{\n#$extinit} } if !modified?(extinit.c, MTIMES) || IO.read(extinit.c) != src -- --- 僕の前にBugはない。 --- 僕の後ろにBugはできる。 中田 伸悦