static char * load_lock(const char *ftptr) { st_data_t data; st_table *loading_tbl = get_loading_table(); if (!st_lookup(loading_tbl, (st_data_t)ftptr, &data)) { /* partial state */ ftptr = ruby_strdup(ftptr); data = (st_data_t)rb_thread_shield_new(); st_insert(loading_tbl, (st_data_t)ftptr, data); return (char *)ftptr; } else if (RB_TYPE_P((VALUE)data, T_IMEMO) && imemo_type((VALUE)data) == imemo_memo) { struct MEMO *memo = MEMO_CAST(data); void (*init)(void) = (void (*)(void))memo->u3.func; data = (st_data_t)rb_thread_shield_new(); st_insert(loading_tbl, (st_data_t)ftptr, data); (*init)(); return (char *)""; } if (RTEST(ruby_verbose)) { rb_warning("loading in progress, circular require considered harmful - %s", ftptr); rb_backtrace_print_to(rb_stderr); } switch (rb_thread_shield_wait((VALUE)data)) { case Qfalse: data = (st_data_t)ftptr; st_insert(loading_tbl, data, (st_data_t)rb_thread_shield_new()); return 0; case Qnil: return 0; } return (char *)ftptr; }
RUBY_FUNC_EXPORTED void ruby_init_ext(const char *name, void (*init)(void)) { st_table *loading_tbl = get_loading_table(); if (rb_provided(name)) return; st_update(loading_tbl, (st_data_t)name, register_init_ext, (st_data_t)init); }
static void load_unlock(const char *ftptr, int done) { if (ftptr) { st_data_t key = (st_data_t)ftptr; st_table *loading_tbl = get_loading_table(); st_update(loading_tbl, key, release_thread_shield, done); } }
static void load_unlock(const char *ftptr, int done) { 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)) { VALUE barrier = (VALUE)data; xfree((char *)key); if (done) rb_barrier_destroy(barrier); else rb_barrier_release(barrier); } } }
static char * load_lock(const char *ftptr) { 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_thread_shield_new(); st_insert(loading_tbl, (st_data_t)ftptr, data); return (char *)ftptr; } else if (RB_TYPE_P((VALUE)data, T_NODE) && nd_type((VALUE)data) == NODE_MEMO) { NODE *memo = RNODE(data); void (*init)(void) = (void (*)(void))memo->nd_cfnc; data = (st_data_t)rb_thread_shield_new(); st_insert(loading_tbl, (st_data_t)ftptr, data); (*init)(); return (char *)""; } if (RTEST(ruby_verbose)) { rb_warning("loading in progress, circular require considered harmful - %s", ftptr); rb_backtrace_print_to(rb_stderr); } switch (rb_thread_shield_wait((VALUE)data)) { case Qfalse: data = (st_data_t)ftptr; st_insert(loading_tbl, data, (st_data_t)rb_thread_shield_new()); return 0; case Qnil: return 0; } return (char *)ftptr; }
static char * load_lock(const char *ftptr) { 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; } if (RTEST(ruby_verbose)) { rb_warning("loading in progress, circular require considered harmful - %s", ftptr); rb_backtrace(); } return RTEST(rb_barrier_wait((VALUE)data)) ? (char *)ftptr : 0; }
static int rb_feature_p(const char *feature, const char *ext, int rb, int expanded, const char **fn) { VALUE features, this_feature_index = Qnil, v, p, load_path = 0; const char *f, *e; long i, len, elen, n; st_table *loading_tbl, *features_index; st_data_t data; int type; if (fn) *fn = 0; if (ext) { elen = strlen(ext); len = strlen(feature) - elen; type = rb ? 'r' : 's'; } else { len = strlen(feature); elen = 0; type = 0; } features = get_loaded_features(); features_index = get_loaded_features_index(); st_lookup(features_index, (st_data_t)feature, (st_data_t *)&this_feature_index); /* We search `features` for an entry such that either "#{features[i]}" == "#{load_path[j]}/#{feature}#{e}" for some j, or "#{features[i]}" == "#{feature}#{e}" Here `e` is an "allowed" extension -- either empty or one of the extensions accepted by IS_RBEXT, IS_SOEXT, or IS_DLEXT. Further, if `ext && rb` then `IS_RBEXT(e)`, and if `ext && !rb` then `IS_SOEXT(e) || IS_DLEXT(e)`. If `expanded`, then only the latter form (without load_path[j]) is accepted. Otherwise either form is accepted, *unless* `ext` is false and an otherwise-matching entry of the first form is preceded by an entry of the form "#{features[i2]}" == "#{load_path[j2]}/#{feature}#{e2}" where `e2` matches %r{^\.[^./]*$} but is not an allowed extension. After a "distractor" entry of this form, only entries of the form "#{feature}#{e}" are accepted. In `rb_provide_feature()` and `get_loaded_features_index()` we maintain an invariant that the array `this_feature_index` will point to every entry in `features` which has the form "#{prefix}#{feature}#{e}" where `e` is empty or matches %r{^\.[^./]*$}, and `prefix` is empty or ends in '/'. This includes both match forms above, as well as any distractors, so we may ignore all other entries in `features`. */ if (!NIL_P(this_feature_index)) { for (i = 0; ; i++) { VALUE entry; long index; if (RB_TYPE_P(this_feature_index, T_ARRAY)) { if (i >= RARRAY_LEN(this_feature_index)) break; entry = RARRAY_AREF(this_feature_index, i); } else { if (i > 0) break; entry = this_feature_index; } index = FIX2LONG(entry); v = RARRAY_AREF(features, index); f = StringValuePtr(v); if ((n = RSTRING_LEN(v)) < len) continue; if (strncmp(f, feature, len) != 0) { if (expanded) continue; if (!load_path) load_path = rb_get_expanded_load_path(); if (!(p = loaded_feature_path(f, n, feature, len, type, load_path))) continue; expanded = 1; f += RSTRING_LEN(p) + 1; } if (!*(e = f + len)) { if (ext) continue; return 'u'; } if (*e != '.') continue; if ((!rb || !ext) && (IS_SOEXT(e) || IS_DLEXT(e))) { return 's'; } if ((rb || !ext) && (IS_RBEXT(e))) { return 'r'; } } } loading_tbl = get_loading_table(); f = 0; if (!expanded) { struct loaded_feature_searching fs; fs.name = feature; fs.len = len; fs.type = type; fs.load_path = load_path ? load_path : rb_get_expanded_load_path(); fs.result = 0; st_foreach(loading_tbl, loaded_feature_path_i, (st_data_t)&fs); if ((f = fs.result) != 0) { if (fn) *fn = f; goto loading; } } if (st_get_key(loading_tbl, (st_data_t)feature, &data)) { if (fn) *fn = (const char*)data; loading: if (!ext) return 'u'; return !IS_RBEXT(ext) ? 's' : 'r'; } else { VALUE bufstr; char *buf; static const char so_ext[][4] = { ".so", ".o", }; if (ext && *ext) return 0; bufstr = rb_str_tmp_new(len + DLEXT_MAXLEN); buf = RSTRING_PTR(bufstr); MEMCPY(buf, feature, char, len); for (i = 0; (e = loadable_ext[i]) != 0; i++) { strlcpy(buf + len, e, DLEXT_MAXLEN + 1); if (st_get_key(loading_tbl, (st_data_t)buf, &data)) { rb_str_resize(bufstr, 0); if (fn) *fn = (const char*)data; return i ? 's' : 'r'; } } for (i = 0; i < numberof(so_ext); i++) { strlcpy(buf + len, so_ext[i], DLEXT_MAXLEN + 1); if (st_get_key(loading_tbl, (st_data_t)buf, &data)) { rb_str_resize(bufstr, 0); if (fn) *fn = (const char*)data; return 's'; } } rb_str_resize(bufstr, 0); } return 0; }
static int rb_feature_p(const char *feature, const char *ext, int rb, int expanded, const char **fn) { VALUE v, features, p, load_path = 0; const char *f, *e; long i, len, elen, n; st_table *loading_tbl; st_data_t data; int type; if (fn) *fn = 0; if (ext) { elen = strlen(ext); len = strlen(feature) - elen; type = rb ? 'r' : 's'; } else { len = strlen(feature); elen = 0; type = 0; } features = get_loaded_features(); for (i = 0; i < RARRAY_LEN(features); ++i) { v = RARRAY_PTR(features)[i]; f = StringValuePtr(v); if ((n = RSTRING_LEN(v)) < len) continue; if (strncmp(f, feature, len) != 0) { if (expanded) continue; if (!load_path) load_path = rb_get_expanded_load_path(); if (!(p = loaded_feature_path(f, n, feature, len, type, load_path))) continue; expanded = 1; f += RSTRING_LEN(p) + 1; } if (!*(e = f + len)) { if (ext) continue; return 'u'; } if (*e != '.') continue; if ((!rb || !ext) && (IS_SOEXT(e) || IS_DLEXT(e))) { return 's'; } if ((rb || !ext) && (IS_RBEXT(e))) { return 'r'; } } loading_tbl = get_loading_table(); if (loading_tbl) { f = 0; if (!expanded) { struct loaded_feature_searching fs; fs.name = feature; fs.len = len; fs.type = type; fs.load_path = load_path ? load_path : rb_get_load_path(); fs.result = 0; st_foreach(loading_tbl, loaded_feature_path_i, (st_data_t)&fs); if ((f = fs.result) != 0) { if (fn) *fn = f; goto loading; } } if (st_get_key(loading_tbl, (st_data_t)feature, &data)) { if (fn) *fn = (const char*)data; loading: if (!ext) return 'u'; return !IS_RBEXT(ext) ? 's' : 'r'; } else { VALUE bufstr; char *buf; if (ext && *ext) return 0; bufstr = rb_str_tmp_new(len + DLEXT_MAXLEN); buf = RSTRING_PTR(bufstr); MEMCPY(buf, feature, char, len); for (i = 0; (e = loadable_ext[i]) != 0; i++) { strlcpy(buf + len, e, DLEXT_MAXLEN + 1); if (st_get_key(loading_tbl, (st_data_t)buf, &data)) { rb_str_resize(bufstr, 0); if (fn) *fn = (const char*)data; return i ? 's' : 'r'; } } rb_str_resize(bufstr, 0); } } return 0; }