From 166032bddf9a14f3ea6252724532039a1113612d Mon Sep 17 00:00:00 2001 From: Sverker Eriksson Date: Wed, 11 Jan 2012 21:01:49 +0100 Subject: erts: Refactor Module struct --- erts/emulator/beam/beam_bif_load.c | 103 ++++++++++++++++++------------------- erts/emulator/beam/beam_bp.c | 14 ++--- erts/emulator/beam/beam_debug.c | 2 +- erts/emulator/beam/beam_emu.c | 2 +- erts/emulator/beam/beam_load.c | 16 +++--- erts/emulator/beam/break.c | 38 +++++++------- erts/emulator/beam/erl_nif.c | 32 ++++++------ erts/emulator/beam/module.c | 12 ++--- erts/emulator/beam/module.h | 15 +++--- erts/emulator/hipe/hipe_bif0.c | 2 +- 10 files changed, 117 insertions(+), 119 deletions(-) diff --git a/erts/emulator/beam/beam_bif_load.c b/erts/emulator/beam/beam_bif_load.c index 78a9d76a20..90baa6178e 100644 --- a/erts/emulator/beam/beam_bif_load.c +++ b/erts/emulator/beam/beam_bif_load.c @@ -132,8 +132,8 @@ BIF_RETTYPE code_is_module_native_1(BIF_ALIST_1) if ((modp = erts_get_module(BIF_ARG_1)) == NULL) { return am_undefined; } - return ((modp->code && is_native(modp->code)) || - (modp->old_code != 0 && is_native(modp->old_code))) ? + return ((modp->curr.code && is_native(modp->curr.code)) || + (modp->old.code != 0 && is_native(modp->old.code))) ? am_true : am_false; } @@ -163,7 +163,7 @@ check_old_code_1(BIF_ALIST_1) modp = erts_get_module(BIF_ARG_1); if (modp == NULL) { /* Doesn't exist. */ BIF_RET(am_false); - } else if (modp->old_code == NULL) { /* No old code. */ + } else if (modp->old.code == NULL) { /* No old code. */ BIF_RET(am_false); } BIF_RET(am_true); @@ -185,7 +185,7 @@ check_process_code_2(BIF_ALIST_2) modp = erts_get_module(BIF_ARG_2); if (modp == NULL) { /* Doesn't exist. */ return am_false; - } else if (modp->old_code == NULL) { /* No old code. */ + } else if (modp->old.code == NULL) { /* No old code. */ return am_false; } @@ -236,7 +236,7 @@ BIF_RETTYPE delete_module_1(BIF_ALIST_1) if (!modp) { res = am_undefined; } - else if (modp->old_code != 0) { + else if (modp->old.code != 0) { erts_dsprintf_buf_t *dsbufp = erts_create_logger_dsbuf(); erts_dsprintf(dsbufp, "Module %T must be purged before loading\n", BIF_ARG_1); @@ -268,8 +268,8 @@ BIF_RETTYPE module_loaded_1(BIF_ALIST_1) BIF_ERROR(BIF_P, BADARG); } if ((modp = erts_get_module(BIF_ARG_1)) == NULL || - modp->code == NULL || - modp->code[MI_ON_LOAD_FUNCTION_PTR] != 0) { + modp->curr.code == NULL || + modp->curr.code[MI_ON_LOAD_FUNCTION_PTR] != 0) { BIF_RET(am_false); } BIF_RET(am_true); @@ -289,8 +289,8 @@ BIF_RETTYPE loaded_0(BIF_ALIST_0) for (i = 0; i < module_code_size(); i++) { if (module_code(i) != NULL && - ((module_code(i)->code_length != 0) || - (module_code(i)->old_code_length != 0))) { + ((module_code(i)->curr.code_length != 0) || + (module_code(i)->old.code_length != 0))) { j++; } } @@ -299,8 +299,8 @@ BIF_RETTYPE loaded_0(BIF_ALIST_0) for (i = 0; i < module_code_size(); i++) { if (module_code(i) != NULL && - ((module_code(i)->code_length != 0) || - (module_code(i)->old_code_length != 0))) { + ((module_code(i)->curr.code_length != 0) || + (module_code(i)->old.code_length != 0))) { previous = CONS(hp, make_atom(module_code(i)->module), previous); hp += 2; @@ -315,11 +315,11 @@ BIF_RETTYPE call_on_load_function_1(BIF_ALIST_1) Module* modp = erts_get_module(BIF_ARG_1); Eterm on_load; - if (!modp || modp->code == 0) { + if (!modp || modp->curr.code == 0) { error: BIF_ERROR(BIF_P, BADARG); } - if ((on_load = modp->code[MI_ON_LOAD_FUNCTION_PTR]) == 0) { + if ((on_load = modp->curr.code[MI_ON_LOAD_FUNCTION_PTR]) == 0) { goto error; } BIF_TRAP_CODE_PTR_0(BIF_P, on_load); @@ -330,11 +330,11 @@ BIF_RETTYPE finish_after_on_load_2(BIF_ALIST_2) Module* modp = erts_get_module(BIF_ARG_1); Eterm on_load; - if (!modp || modp->code == 0) { + if (!modp || modp->curr.code == 0) { error: BIF_ERROR(BIF_P, BADARG); } - if ((on_load = modp->code[MI_ON_LOAD_FUNCTION_PTR]) == 0) { + if ((on_load = modp->curr.code[MI_ON_LOAD_FUNCTION_PTR]) == 0) { goto error; } if (BIF_ARG_2 != am_false && BIF_ARG_2 != am_true) { @@ -359,7 +359,7 @@ BIF_RETTYPE finish_after_on_load_2(BIF_ALIST_2) ep->code[4] = 0; } } - modp->code[MI_ON_LOAD_FUNCTION_PTR] = 0; + modp->curr.code[MI_ON_LOAD_FUNCTION_PTR] = 0; set_default_trace_pattern(BIF_ARG_1); } else if (BIF_ARG_2 == am_false) { BeamInstr* code; @@ -370,15 +370,15 @@ BIF_RETTYPE finish_after_on_load_2(BIF_ALIST_2) * This is an combination of delete and purge. We purge * the current code; the old code is not touched. */ - erts_total_code_size -= modp->code_length; - code = modp->code; - end = (BeamInstr *)((char *)code + modp->code_length); + erts_total_code_size -= modp->curr.code_length; + code = modp->curr.code; + end = (BeamInstr *)((char *)code + modp->curr.code_length); erts_cleanup_funs_on_purge(code, end); - beam_catches_delmod(modp->catches, code, modp->code_length); + beam_catches_delmod(modp->curr.catches, code, modp->curr.code_length); erts_free(ERTS_ALC_T_CODE, (void *) code); - modp->code = NULL; - modp->code_length = 0; - modp->catches = BEAM_CATCHES_NIL; + modp->curr.code = NULL; + modp->curr.code_length = 0; + modp->curr.catches = BEAM_CATCHES_NIL; remove_from_address_table(code); } erts_smp_thr_progress_unblock(); @@ -429,10 +429,10 @@ check_process_code(Process* rp, Module* modp) /* * Pick up limits for the module. */ - start = modp->old_code; - end = (BeamInstr *)((char *)start + modp->old_code_length); + start = modp->old.code; + end = (BeamInstr *)((char *)start + modp->old.code_length); mod_start = (char *) start; - mod_size = modp->old_code_length; + mod_size = modp->old.code_length; /* * Check if current instruction or continuation pointer points into module. @@ -566,10 +566,10 @@ check_process_code(Process* rp, Module* modp) done_gc = 1; FLAGS(rp) |= F_NEED_FULLSWEEP; (void) erts_garbage_collect(rp, 0, rp->arg_reg, rp->arity); - literals = (Eterm *) modp->old_code[MI_LITERALS_START]; - lit_size = (Eterm *) modp->old_code[MI_LITERALS_END] - literals; + literals = (Eterm *) modp->old.code[MI_LITERALS_START]; + lit_size = (Eterm *) modp->old.code[MI_LITERALS_END] - literals; oh = (struct erl_off_heap_header *) - modp->old_code[MI_LITERALS_OFF_HEAP]; + modp->old.code[MI_LITERALS_OFF_HEAP]; erts_garbage_collect_literals(rp, literals, lit_size, oh); } } @@ -647,32 +647,32 @@ purge_module(int module) /* * Any code to purge? */ - if (modp->old_code == 0) { + if (modp->old.code == 0) { return -1; } /* * Unload any NIF library */ - if (modp->old_nif != NULL) { - erts_unload_nif(modp->old_nif); - modp->old_nif = NULL; + if (modp->old.nif != NULL) { + erts_unload_nif(modp->old.nif); + modp->old.nif = NULL; } /* * Remove the old code. */ - ASSERT(erts_total_code_size >= modp->old_code_length); - erts_total_code_size -= modp->old_code_length; - code = modp->old_code; - end = (BeamInstr *)((char *)code + modp->old_code_length); + ASSERT(erts_total_code_size >= modp->old.code_length); + erts_total_code_size -= modp->old.code_length; + code = modp->old.code; + end = (BeamInstr *)((char *)code + modp->old.code_length); erts_cleanup_funs_on_purge(code, end); - beam_catches_delmod(modp->old_catches, code, modp->old_code_length); + beam_catches_delmod(modp->old.catches, code, modp->old.code_length); decrement_refc(code); erts_free(ERTS_ALC_T_CODE, (void *) code); - modp->old_code = NULL; - modp->old_code_length = 0; - modp->old_catches = BEAM_CATCHES_NIL; + modp->old.code = NULL; + modp->old.code_length = 0; + modp->old.catches = BEAM_CATCHES_NIL; remove_from_address_table(code); return 0; } @@ -733,24 +733,21 @@ delete_code(Process *c_p, ErtsProcLocks c_p_locks, Module* modp) /* * Clear breakpoints if any */ - if (modp->code != NULL && modp->code[MI_NUM_BREAKPOINTS] > 0) { + if (modp->curr.code != NULL && modp->curr.code[MI_NUM_BREAKPOINTS] > 0) { if (c_p && c_p_locks) erts_smp_proc_unlock(c_p, ERTS_PROC_LOCK_MAIN); erts_smp_thr_progress_block(); erts_clear_module_break(modp); - modp->code[MI_NUM_BREAKPOINTS] = 0; + modp->curr.code[MI_NUM_BREAKPOINTS] = 0; erts_smp_thr_progress_unblock(); if (c_p && c_p_locks) erts_smp_proc_lock(c_p, ERTS_PROC_LOCK_MAIN); } - modp->old_code = modp->code; - modp->old_code_length = modp->code_length; - modp->old_catches = modp->catches; - modp->old_nif = modp->nif; - modp->code = NULL; - modp->code_length = 0; - modp->catches = BEAM_CATCHES_NIL; - modp->nif = NULL; + modp->old = modp->curr; + modp->curr.code = NULL; + modp->curr.code_length = 0; + modp->curr.catches = BEAM_CATCHES_NIL; + modp->curr.nif = NULL; } @@ -791,9 +788,9 @@ beam_make_current_old(Process *c_p, ErtsProcLocks c_p_locks, Eterm module) * if not, delete old code; error if old code already exists. */ - if (modp->code != NULL && modp->old_code != NULL) { + if (modp->curr.code != NULL && modp->old.code != NULL) { return am_not_purged; - } else if (modp->old_code == NULL) { /* Make the current version old. */ + } else if (modp->old.code == NULL) { /* Make the current version old. */ delete_code(c_p, c_p_locks, modp); delete_export_references(module); } diff --git a/erts/emulator/beam/beam_bp.c b/erts/emulator/beam/beam_bp.c index 53f283ba39..872907e232 100644 --- a/erts/emulator/beam/beam_bp.c +++ b/erts/emulator/beam/beam_bp.c @@ -480,7 +480,7 @@ erts_find_local_func(Eterm mfa[3]) { if ((modp = erts_get_module(mfa[0])) == NULL) return NULL; - if ((code_base = (BeamInstr **) modp->code) == NULL) + if ((code_base = (BeamInstr **) modp->curr.code) == NULL) return NULL; n = (BeamInstr) code_base[MI_NUM_FUNCTIONS]; for (i = 0; i < n; ++i) { @@ -884,7 +884,7 @@ static int set_module_break(Module *modp, Eterm mfa[3], int specified, ASSERT(break_op); ASSERT(modp); - code_base = (BeamInstr **) modp->code; + code_base = (BeamInstr **) modp->curr.code; if (code_base == NULL) { return 0; } @@ -914,10 +914,10 @@ static int set_function_break(Module *modp, BeamInstr *pc, int bif, Uint ix = 0; if (bif == BREAK_IS_ERL) { - code_base = (BeamInstr **)modp->code; + code_base = (BeamInstr **)modp->curr.code; ASSERT(code_base); ASSERT(code_base <= (BeamInstr **)pc); - ASSERT((BeamInstr **)pc < code_base + (modp->code_length/sizeof(BeamInstr *))); + ASSERT((BeamInstr **)pc < code_base + (modp->curr.code_length/sizeof(BeamInstr *))); } else { ASSERT(*pc == (BeamInstr) em_apply_bif); ASSERT(modp == NULL); @@ -1137,7 +1137,7 @@ static int clear_module_break(Module *m, Eterm mfa[3], int specified, BeamInstr n; ASSERT(m); - code_base = (BeamInstr **) m->code; + code_base = (BeamInstr **) m->curr.code; if (code_base == NULL) { return 0; } @@ -1161,10 +1161,10 @@ static int clear_function_break(Module *m, BeamInstr *pc, int bif, BeamInstr bre BeamInstr **code_base = NULL; if (bif == BREAK_IS_ERL) { - code_base = (BeamInstr **)m->code; + code_base = (BeamInstr **)m->curr.code; ASSERT(code_base); ASSERT(code_base <= (BeamInstr **)pc); - ASSERT((BeamInstr **)pc < code_base + (m->code_length/sizeof(BeamInstr *))); + ASSERT((BeamInstr **)pc < code_base + (m->curr.code_length/sizeof(BeamInstr *))); } else { ASSERT(*pc == (BeamInstr) em_apply_bif); ASSERT(m == NULL); diff --git a/erts/emulator/beam/beam_debug.c b/erts/emulator/beam/beam_debug.c index 8041c92162..4bef59dd66 100644 --- a/erts/emulator/beam/beam_debug.c +++ b/erts/emulator/beam/beam_debug.c @@ -243,7 +243,7 @@ erts_debug_disassemble_1(BIF_ALIST_1) */ code_ptr = ((BeamInstr *) ep->address) - 5; funcinfo = code_ptr+2; - } else if (modp == NULL || (code_base = modp->code) == NULL) { + } else if (modp == NULL || (code_base = modp->curr.code) == NULL) { BIF_RET(am_undef); } else { n = code_base[MI_NUM_FUNCTIONS]; diff --git a/erts/emulator/beam/beam_emu.c b/erts/emulator/beam/beam_emu.c index c65b2be106..97eb4f1edc 100644 --- a/erts/emulator/beam/beam_emu.c +++ b/erts/emulator/beam/beam_emu.c @@ -6128,7 +6128,7 @@ call_fun(Process* p, /* Current process. */ */ module = fe->module; - if ((modp = erts_get_module(module)) != NULL && modp->code != NULL) { + if ((modp = erts_get_module(module)) != NULL && modp->curr.code != NULL) { /* * There is a module loaded, but obviously the fun is not * defined in it. We must not call the error_handler diff --git a/erts/emulator/beam/beam_load.c b/erts/emulator/beam/beam_load.c index d54fe603d8..3040a2b7cd 100644 --- a/erts/emulator/beam/beam_load.c +++ b/erts/emulator/beam/beam_load.c @@ -972,9 +972,9 @@ insert_new_code(Process *c_p, ErtsProcLocks c_p_locks, erts_total_code_size += size; modp = erts_put_module(module); - modp->code = code; - modp->code_length = size; - modp->catches = BEAM_CATCHES_NIL; /* Will be filled in later. */ + modp->curr.code = code; + modp->curr.code_length = size; + modp->curr.catches = BEAM_CATCHES_NIL; /* Will be filled in later. */ /* * Update address table (used for finding a function from a PC value). @@ -4283,7 +4283,7 @@ final_touch(LoaderState* stp) index = next; } modp = erts_put_module(stp->module); - modp->catches = catches; + modp->curr.catches = catches; /* * Export functions. @@ -5092,7 +5092,7 @@ functions_in_module(Process* p, /* Process whose heap to use. */ if (modp == NULL) { return THE_NON_VALUE; } - code = modp->code; + code = modp->curr.code; num_functions = code[MI_NUM_FUNCTIONS]; need = 5*num_functions; hp = HAlloc(p, need); @@ -5147,7 +5147,7 @@ native_addresses(Process* p, Eterm mod) return THE_NON_VALUE; } - code = modp->code; + code = modp->curr.code; num_functions = code[MI_NUM_FUNCTIONS]; need = (6+BIG_UINT_HEAP_SIZE)*num_functions; hp = HAlloc(p, need); @@ -5246,7 +5246,7 @@ attributes_for_module(Process* p, /* Process whose heap to use. */ if (modp == NULL) { return THE_NON_VALUE; } - code = modp->code; + code = modp->curr.code; ext = (byte *) code[MI_ATTR_PTR]; if (ext != NULL) { hp = HAlloc(p, code[MI_ATTR_SIZE_ON_HEAP]); @@ -5286,7 +5286,7 @@ compilation_info_for_module(Process* p, /* Process whose heap to use. */ if (modp == NULL) { return THE_NON_VALUE; } - code = modp->code; + code = modp->curr.code; ext = (byte *) code[MI_COMPILE_PTR]; if (ext != NULL) { hp = HAlloc(p, code[MI_COMPILE_SIZE_ON_HEAP]); diff --git a/erts/emulator/beam/break.c b/erts/emulator/beam/break.c index 6f5020dc14..d769957210 100644 --- a/erts/emulator/beam/break.c +++ b/erts/emulator/beam/break.c @@ -383,11 +383,11 @@ loaded(int to, void *to_arg) */ for (i = 0; i < module_code_size(); i++) { if (module_code(i) != NULL && - ((module_code(i)->code_length != 0) || - (module_code(i)->old_code_length != 0))) { - cur += module_code(i)->code_length; - if (module_code(i)->old_code_length != 0) { - old += module_code(i)->old_code_length; + ((module_code(i)->curr.code_length != 0) || + (module_code(i)->old.code_length != 0))) { + cur += module_code(i)->curr.code_length; + if (module_code(i)->old.code_length != 0) { + old += module_code(i)->old.code_length; } } } @@ -404,15 +404,15 @@ loaded(int to, void *to_arg) * Interactive dump; keep it brief. */ if (module_code(i) != NULL && - ((module_code(i)->code_length != 0) || - (module_code(i)->old_code_length != 0))) { + ((module_code(i)->curr.code_length != 0) || + (module_code(i)->old.code_length != 0))) { erts_print(to, to_arg, "%T", make_atom(module_code(i)->module)); - cur += module_code(i)->code_length; - erts_print(to, to_arg, " %d", module_code(i)->code_length ); - if (module_code(i)->old_code_length != 0) { + cur += module_code(i)->curr.code_length; + erts_print(to, to_arg, " %d", module_code(i)->curr.code_length ); + if (module_code(i)->old.code_length != 0) { erts_print(to, to_arg, " (%d old)", - module_code(i)->old_code_length ); - old += module_code(i)->old_code_length; + module_code(i)->old.code_length ); + old += module_code(i)->old.code_length; } erts_print(to, to_arg, "\n"); } @@ -421,14 +421,14 @@ loaded(int to, void *to_arg) * To crash dump; make it parseable. */ if (module_code(i) != NULL && - ((module_code(i)->code_length != 0) || - (module_code(i)->old_code_length != 0))) { + ((module_code(i)->curr.code_length != 0) || + (module_code(i)->old.code_length != 0))) { erts_print(to, to_arg, "=mod:"); erts_print(to, to_arg, "%T", make_atom(module_code(i)->module)); erts_print(to, to_arg, "\n"); erts_print(to, to_arg, "Current size: %d\n", - module_code(i)->code_length); - code = module_code(i)->code; + module_code(i)->curr.code_length); + code = module_code(i)->curr.code; if (code != NULL && code[MI_ATTR_PTR]) { erts_print(to, to_arg, "Current attributes: "); dump_attributes(to, to_arg, (byte *) code[MI_ATTR_PTR], @@ -440,9 +440,9 @@ loaded(int to, void *to_arg) code[MI_COMPILE_SIZE]); } - if (module_code(i)->old_code_length != 0) { - erts_print(to, to_arg, "Old size: %d\n", module_code(i)->old_code_length); - code = module_code(i)->old_code; + if (module_code(i)->old.code_length != 0) { + erts_print(to, to_arg, "Old size: %d\n", module_code(i)->old.code_length); + code = module_code(i)->old.code; if (code[MI_ATTR_PTR]) { erts_print(to, to_arg, "Old attributes: "); dump_attributes(to, to_arg, (byte *) code[MI_ATTR_PTR], diff --git a/erts/emulator/beam/erl_nif.c b/erts/emulator/beam/erl_nif.c index 58a09986d2..f6082c09f2 100644 --- a/erts/emulator/beam/erl_nif.c +++ b/erts/emulator/beam/erl_nif.c @@ -1537,8 +1537,8 @@ BIF_RETTYPE load_nif_2(BIF_ALIST_2) mod=erts_get_module(mod_atom); ASSERT(mod != NULL); - if (!in_area(caller, mod->code, mod->code_length)) { - ASSERT(in_area(caller, mod->old_code, mod->old_code_length)); + if (!in_area(caller, mod->curr.code, mod->curr.code_length)) { + ASSERT(in_area(caller, mod->old.code, mod->old.code_length)); ret = load_nif_error(BIF_P, "old_code", "Calling load_nif from old " "module '%T' not allowed", mod_atom); @@ -1584,7 +1584,7 @@ BIF_RETTYPE load_nif_2(BIF_ALIST_2) BeamInstr** code_pp; ErlNifFunc* f = &entry->funcs[i]; if (!erts_atom_get(f->name, sys_strlen(f->name), &f_atom) - || (code_pp = get_func_pp(mod->code, f_atom, f->arity))==NULL) { + || (code_pp = get_func_pp(mod->curr.code, f_atom, f->arity))==NULL) { ret = load_nif_error(BIF_P,bad_lib,"Function not found %T:%s/%u", mod_atom, f->name, f->arity); } @@ -1613,18 +1613,18 @@ BIF_RETTYPE load_nif_2(BIF_ALIST_2) erts_refc_init(&lib->rt_dtor_cnt, 0); lib->mod = mod; env.mod_nif = lib; - if (mod->nif != NULL) { /* Reload */ + if (mod->curr.nif != NULL) { /* Reload */ int k; - lib->priv_data = mod->nif->priv_data; + lib->priv_data = mod->curr.nif->priv_data; - ASSERT(mod->nif->entry != NULL); + ASSERT(mod->curr.nif->entry != NULL); if (entry->reload == NULL) { ret = load_nif_error(BIF_P,reload,"Reload not supported by this NIF library."); goto error; } /* Check that no NIF is removed */ - for (k=0; k < mod->nif->entry->num_of_funcs; k++) { - ErlNifFunc* old_func = &mod->nif->entry->funcs[k]; + for (k=0; k < mod->curr.nif->entry->num_of_funcs; k++) { + ErlNifFunc* old_func = &mod->curr.nif->entry->funcs[k]; for (i=0; i < entry->num_of_funcs; i++) { if (old_func->arity == entry->funcs[i].arity && sys_strcmp(old_func->name, entry->funcs[i].name) == 0) { @@ -1645,24 +1645,24 @@ BIF_RETTYPE load_nif_2(BIF_ALIST_2) ret = load_nif_error(BIF_P, reload, "Library reload-call unsuccessful."); } else { - mod->nif->entry = NULL; /* to prevent 'unload' callback */ - erts_unload_nif(mod->nif); + mod->curr.nif->entry = NULL; /* to prevent 'unload' callback */ + erts_unload_nif(mod->curr.nif); reload_warning = 1; } } else { lib->priv_data = NULL; - if (mod->old_nif != NULL) { /* Upgrade */ - void* prev_old_data = mod->old_nif->priv_data; + if (mod->old.nif != NULL) { /* Upgrade */ + void* prev_old_data = mod->old.nif->priv_data; if (entry->upgrade == NULL) { ret = load_nif_error(BIF_P, upgrade, "Upgrade not supported by this NIF library."); goto error; } erts_pre_nif(&env, BIF_P, lib); - veto = entry->upgrade(&env, &lib->priv_data, &mod->old_nif->priv_data, BIF_ARG_2); + veto = entry->upgrade(&env, &lib->priv_data, &mod->old.nif->priv_data, BIF_ARG_2); erts_post_nif(&env); if (veto) { - mod->old_nif->priv_data = prev_old_data; + mod->old.nif->priv_data = prev_old_data; ret = load_nif_error(BIF_P, upgrade, "Library upgrade-call unsuccessful."); } /*else if (mod->old_nif->priv_data != prev_old_data) { @@ -1682,12 +1682,12 @@ BIF_RETTYPE load_nif_2(BIF_ALIST_2) /* ** Everything ok, patch the beam code with op_call_nif */ - mod->nif = lib; + mod->curr.nif = lib; for (i=0; i < entry->num_of_funcs; i++) { BeamInstr* code_ptr; erts_atom_get(entry->funcs[i].name, sys_strlen(entry->funcs[i].name), &f_atom); - code_ptr = *get_func_pp(mod->code, f_atom, entry->funcs[i].arity); + code_ptr = *get_func_pp(mod->curr.code, f_atom, entry->funcs[i].arity); if (code_ptr[1] == 0) { code_ptr[5+0] = (BeamInstr) BeamOp(op_call_nif); diff --git a/erts/emulator/beam/module.c b/erts/emulator/beam/module.c index b93b1ad09a..39baabdf54 100644 --- a/erts/emulator/beam/module.c +++ b/erts/emulator/beam/module.c @@ -61,13 +61,13 @@ static Module* module_alloc(Module* tmpl) Module* obj = (Module*) erts_alloc(ERTS_ALC_T_MODULE, sizeof(Module)); obj->module = tmpl->module; - obj->code = 0; - obj->old_code = 0; - obj->code_length = 0; - obj->old_code_length = 0; + obj->curr.code = 0; + obj->old.code = 0; + obj->curr.code_length = 0; + obj->old.code_length = 0; obj->slot.index = -1; - obj->nif = NULL; - obj->old_nif = NULL; + obj->curr.nif = NULL; + obj->old.nif = NULL; return obj; } diff --git a/erts/emulator/beam/module.h b/erts/emulator/beam/module.h index 694e4ab72f..4a2c92c0f7 100644 --- a/erts/emulator/beam/module.h +++ b/erts/emulator/beam/module.h @@ -24,18 +24,19 @@ #include "index.h" #endif +struct erl_module_instance { + BeamInstr* code; + int code_length; /* Length of loaded code in bytes. */ + unsigned catches; + struct erl_module_nif* nif; +}; typedef struct erl_module { IndexSlot slot; /* Must be located at top of struct! */ int module; /* Atom index for module (not tagged). */ - BeamInstr* code; - BeamInstr* old_code; - int code_length; /* Length of loaded code in bytes. */ - int old_code_length; /* Length of old loaded code in bytes */ - unsigned catches, old_catches; - struct erl_module_nif* nif; - struct erl_module_nif* old_nif; + struct erl_module_instance curr; + struct erl_module_instance old; } Module; Module* erts_get_module(Eterm mod); diff --git a/erts/emulator/hipe/hipe_bif0.c b/erts/emulator/hipe/hipe_bif0.c index 28e4382835..d81c50b4ae 100644 --- a/erts/emulator/hipe/hipe_bif0.c +++ b/erts/emulator/hipe/hipe_bif0.c @@ -610,7 +610,7 @@ static Uint *hipe_find_emu_address(Eterm mod, Eterm name, unsigned int arity) int i, n; modp = erts_get_module(mod); - if (modp == NULL || (code_base = modp->code) == NULL) + if (modp == NULL || (code_base = modp->curr.code) == NULL) return NULL; n = code_base[MI_NUM_FUNCTIONS]; for (i = 0; i < n; ++i) { -- cgit v1.2.3 From 272a61ce4cfa7e92a037fbf71bc79ec0456f8b2b Mon Sep 17 00:00:00 2001 From: Sverker Eriksson Date: Wed, 18 Jan 2012 17:07:35 +0100 Subject: erts: Refactor new helper function erts_init_trap_export --- erts/emulator/beam/bif.c | 24 +++++++---- erts/emulator/beam/erl_bif_binary.c | 69 +++++++++++--------------------- erts/emulator/beam/erl_bif_chksum.c | 13 ++---- erts/emulator/beam/erl_bif_re.c | 11 ++---- erts/emulator/beam/erl_db.c | 50 ++++++----------------- erts/emulator/beam/erl_db_tree.c | 12 +----- erts/emulator/beam/erl_process.c | 9 +---- erts/emulator/beam/erl_unicode.c | 79 +++++++++---------------------------- erts/emulator/beam/global.h | 2 + 9 files changed, 82 insertions(+), 187 deletions(-) diff --git a/erts/emulator/beam/bif.c b/erts/emulator/beam/bif.c index f8305944a4..9512aa1558 100644 --- a/erts/emulator/beam/bif.c +++ b/erts/emulator/beam/bif.c @@ -4434,6 +4434,18 @@ erts_bif_prep_await_proc_exit_apply_trap(Process *c_p, Export bif_return_trap_export; +void erts_init_trap_export(Export* ep, Eterm m, Eterm f, Uint a, + Eterm (*bif)(BIF_ALIST_0)) +{ + sys_memset((void *) ep, 0, sizeof(Export)); + ep->address = &ep->code[3]; + ep->code[0] = m; + ep->code[1] = f; + ep->code[2] = a; + ep->code[3] = (BeamInstr) em_apply_bif; + ep->code[4] = (BeamInstr) bif; +} + void erts_init_bif(void) { reference0 = 0; @@ -4449,17 +4461,13 @@ void erts_init_bif(void) * yield the calling process traps to. The only thing it does: * return the value passed as argument. */ - sys_memset((void *) &bif_return_trap_export, 0, sizeof(Export)); - bif_return_trap_export.address = &bif_return_trap_export.code[3]; - bif_return_trap_export.code[0] = am_erlang; - bif_return_trap_export.code[1] = am_bif_return_trap; + erts_init_trap_export(&bif_return_trap_export, am_erlang, am_bif_return_trap, #ifdef DEBUG - bif_return_trap_export.code[2] = 2; + 2 #else - bif_return_trap_export.code[2] = 1; + 1 #endif - bif_return_trap_export.code[3] = (BeamInstr) em_apply_bif; - bif_return_trap_export.code[4] = (BeamInstr) &bif_return_trap; + , &bif_return_trap); flush_monitor_message_trap = erts_export_put(am_erlang, am_flush_monitor_message, diff --git a/erts/emulator/beam/erl_bif_binary.c b/erts/emulator/beam/erl_bif_binary.c index cc4f2be8eb..474151d454 100644 --- a/erts/emulator/beam/erl_bif_binary.c +++ b/erts/emulator/beam/erl_bif_binary.c @@ -72,52 +72,29 @@ binary_matches(Process *p, Eterm arg1, Eterm arg2, Eterm arg3); void erts_init_bif_binary(void) { - sys_memset((void *) &binary_match_trap_export, 0, sizeof(Export)); - binary_match_trap_export.address = &binary_match_trap_export.code[3]; - binary_match_trap_export.code[0] = am_erlang; - binary_match_trap_export.code[1] = am_binary_match_trap; - binary_match_trap_export.code[2] = 3; - binary_match_trap_export.code[3] = (BeamInstr) em_apply_bif; - binary_match_trap_export.code[4] = (BeamInstr) &binary_match_trap; - - sys_memset((void *) &binary_matches_trap_export, 0, sizeof(Export)); - binary_matches_trap_export.address = &binary_matches_trap_export.code[3]; - binary_matches_trap_export.code[0] = am_erlang; - binary_matches_trap_export.code[1] = am_binary_matches_trap; - binary_matches_trap_export.code[2] = 3; - binary_matches_trap_export.code[3] = (BeamInstr) em_apply_bif; - binary_matches_trap_export.code[4] = (BeamInstr) &binary_matches_trap; - - sys_memset((void *) &binary_longest_prefix_trap_export, 0, sizeof(Export)); - binary_longest_prefix_trap_export.address = &binary_longest_prefix_trap_export.code[3]; - binary_longest_prefix_trap_export.code[0] = am_erlang; - binary_longest_prefix_trap_export.code[1] = am_binary_longest_prefix_trap; - binary_longest_prefix_trap_export.code[2] = 3; - binary_longest_prefix_trap_export.code[3] = (BeamInstr) em_apply_bif; - binary_longest_prefix_trap_export.code[4] = (BeamInstr) &binary_longest_prefix_trap; - - sys_memset((void *) &binary_longest_suffix_trap_export, 0, sizeof(Export)); - binary_longest_suffix_trap_export.address = &binary_longest_suffix_trap_export.code[3]; - binary_longest_suffix_trap_export.code[0] = am_erlang; - binary_longest_suffix_trap_export.code[1] = am_binary_longest_suffix_trap; - binary_longest_suffix_trap_export.code[2] = 3; - binary_longest_suffix_trap_export.code[3] = (BeamInstr) em_apply_bif; - binary_longest_suffix_trap_export.code[4] = (BeamInstr) &binary_longest_suffix_trap; - - sys_memset((void *) &binary_bin_to_list_trap_export, 0, sizeof(Export)); - binary_bin_to_list_trap_export.address = &binary_bin_to_list_trap_export.code[3]; - binary_bin_to_list_trap_export.code[0] = am_erlang; - binary_bin_to_list_trap_export.code[1] = am_binary_bin_to_list_trap; - binary_bin_to_list_trap_export.code[2] = 3; - binary_bin_to_list_trap_export.code[3] = (BeamInstr) em_apply_bif; - binary_bin_to_list_trap_export.code[4] = (BeamInstr) &binary_bin_to_list_trap; - sys_memset((void *) &binary_copy_trap_export, 0, sizeof(Export)); - binary_copy_trap_export.address = &binary_copy_trap_export.code[3]; - binary_copy_trap_export.code[0] = am_erlang; - binary_copy_trap_export.code[1] = am_binary_copy_trap; - binary_copy_trap_export.code[2] = 2; - binary_copy_trap_export.code[3] = (BeamInstr) em_apply_bif; - binary_copy_trap_export.code[4] = (BeamInstr) &binary_copy_trap; + erts_init_trap_export(&binary_match_trap_export, + am_erlang, am_binary_match_trap, 3, + &binary_match_trap); + + erts_init_trap_export(&binary_matches_trap_export, + am_erlang, am_binary_matches_trap, 3, + &binary_matches_trap); + + erts_init_trap_export(&binary_longest_prefix_trap_export, + am_erlang, am_binary_longest_prefix_trap, 3, + &binary_longest_prefix_trap); + + erts_init_trap_export(&binary_longest_suffix_trap_export, + am_erlang, am_binary_longest_suffix_trap, 3, + &binary_longest_suffix_trap); + + erts_init_trap_export(&binary_bin_to_list_trap_export, + am_erlang, am_binary_bin_to_list_trap, 3, + &binary_bin_to_list_trap); + + erts_init_trap_export(&binary_copy_trap_export, + am_erlang, am_binary_copy_trap, 2, + &binary_copy_trap); max_loop_limit = 0; return; diff --git a/erts/emulator/beam/erl_bif_chksum.c b/erts/emulator/beam/erl_bif_chksum.c index 06b7ffdf32..ff5ce3cc7a 100644 --- a/erts/emulator/beam/erl_bif_chksum.c +++ b/erts/emulator/beam/erl_bif_chksum.c @@ -42,16 +42,9 @@ static Export chksum_md5_2_exp; void erts_init_bif_chksum(void) { /* Non visual BIF to trap to. */ - memset(&chksum_md5_2_exp, 0, sizeof(Export)); - chksum_md5_2_exp.address = - &chksum_md5_2_exp.code[3]; - chksum_md5_2_exp.code[0] = am_erlang; - chksum_md5_2_exp.code[1] = am_atom_put("md5_trap",8); - chksum_md5_2_exp.code[2] = 2; - chksum_md5_2_exp.code[3] = - (BeamInstr) em_apply_bif; - chksum_md5_2_exp.code[4] = - (BeamInstr) &md5_2; + erts_init_trap_export(&chksum_md5_2_exp, + am_erlang, am_atom_put("md5_trap",8), 2, + &md5_2); } diff --git a/erts/emulator/beam/erl_bif_re.c b/erts/emulator/beam/erl_bif_re.c index 6b843d2e08..b036c5ef5c 100644 --- a/erts/emulator/beam/erl_bif_re.c +++ b/erts/emulator/beam/erl_bif_re.c @@ -71,14 +71,9 @@ void erts_init_bif_re(void) erts_pcre_stack_free = &erts_erts_pcre_stack_free; default_table = NULL; /* ISO8859-1 default, forced into pcre */ max_loop_limit = CONTEXT_REDS * LOOP_FACTOR; - - sys_memset((void *) &re_exec_trap_export, 0, sizeof(Export)); - re_exec_trap_export.address = &re_exec_trap_export.code[3]; - re_exec_trap_export.code[0] = am_erlang; - re_exec_trap_export.code[1] = am_re_run_trap; - re_exec_trap_export.code[2] = 3; - re_exec_trap_export.code[3] = (BeamInstr) em_apply_bif; - re_exec_trap_export.code[4] = (BeamInstr) &re_exec_trap; + + erts_init_trap_export(&re_exec_trap_export, am_erlang, am_re_run_trap, 3, + &re_exec_trap); grun_trap_exportp = erts_export_put(am_re,am_grun,3); urun_trap_exportp = erts_export_put(am_re,am_urun,3); diff --git a/erts/emulator/beam/erl_db.c b/erts/emulator/beam/erl_db.c index 51bdf53823..5cbfa65378 100644 --- a/erts/emulator/beam/erl_db.c +++ b/erts/emulator/beam/erl_db.c @@ -2816,7 +2816,6 @@ void init_db(void) { DbTable init_tb; int i; - extern BeamInstr* em_apply_bif; Eterm *hp; unsigned bits; size_t size; @@ -2949,49 +2948,24 @@ void init_db(void) } /* Non visual BIF to trap to. */ - memset(&ets_select_delete_continue_exp, 0, sizeof(Export)); - ets_select_delete_continue_exp.address = - &ets_select_delete_continue_exp.code[3]; - ets_select_delete_continue_exp.code[0] = am_ets; - ets_select_delete_continue_exp.code[1] = am_atom_put("delete_trap",11); - ets_select_delete_continue_exp.code[2] = 1; - ets_select_delete_continue_exp.code[3] = - (BeamInstr) em_apply_bif; - ets_select_delete_continue_exp.code[4] = - (BeamInstr) &ets_select_delete_1; + erts_init_trap_export(&ets_select_delete_continue_exp, + am_ets, am_atom_put("delete_trap",11), 1, + &ets_select_delete_1); /* Non visual BIF to trap to. */ - memset(&ets_select_count_continue_exp, 0, sizeof(Export)); - ets_select_count_continue_exp.address = - &ets_select_count_continue_exp.code[3]; - ets_select_count_continue_exp.code[0] = am_ets; - ets_select_count_continue_exp.code[1] = am_atom_put("count_trap",11); - ets_select_count_continue_exp.code[2] = 1; - ets_select_count_continue_exp.code[3] = - (BeamInstr) em_apply_bif; - ets_select_count_continue_exp.code[4] = - (BeamInstr) &ets_select_count_1; + erts_init_trap_export(&ets_select_count_continue_exp, + am_ets, am_atom_put("count_trap",11), 1, + &ets_select_count_1); /* Non visual BIF to trap to. */ - memset(&ets_select_continue_exp, 0, sizeof(Export)); - ets_select_continue_exp.address = - &ets_select_continue_exp.code[3]; - ets_select_continue_exp.code[0] = am_ets; - ets_select_continue_exp.code[1] = am_atom_put("select_trap",11); - ets_select_continue_exp.code[2] = 1; - ets_select_continue_exp.code[3] = - (BeamInstr) em_apply_bif; - ets_select_continue_exp.code[4] = - (BeamInstr) &ets_select_trap_1; + erts_init_trap_export(&ets_select_continue_exp, + am_ets, am_atom_put("select_trap",11), 1, + &ets_select_trap_1); /* Non visual BIF to trap to. */ - memset(&ets_delete_continue_exp, 0, sizeof(Export)); - ets_delete_continue_exp.address = &ets_delete_continue_exp.code[3]; - ets_delete_continue_exp.code[0] = am_ets; - ets_delete_continue_exp.code[1] = am_atom_put("delete_trap",11); - ets_delete_continue_exp.code[2] = 1; - ets_delete_continue_exp.code[3] = (BeamInstr) em_apply_bif; - ets_delete_continue_exp.code[4] = (BeamInstr) &ets_delete_trap; + erts_init_trap_export(&ets_delete_continue_exp, + am_ets, am_atom_put("delete_trap",11), 1, + &ets_delete_trap); hp = ms_delete_all_buff; ms_delete_all = CONS(hp, am_true, NIL); diff --git a/erts/emulator/beam/erl_db_tree.c b/erts/emulator/beam/erl_db_tree.c index 312050b931..faa7f31d99 100644 --- a/erts/emulator/beam/erl_db_tree.c +++ b/erts/emulator/beam/erl_db_tree.c @@ -452,16 +452,8 @@ DbTableMethod db_tree = void db_initialize_tree(void) { - memset(&ets_select_reverse_exp, 0, sizeof(Export)); - ets_select_reverse_exp.address = - &ets_select_reverse_exp.code[3]; - ets_select_reverse_exp.code[0] = am_ets; - ets_select_reverse_exp.code[1] = am_reverse; - ets_select_reverse_exp.code[2] = 3; - ets_select_reverse_exp.code[3] = - (BeamInstr) em_apply_bif; - ets_select_reverse_exp.code[4] = - (BeamInstr) &ets_select_reverse; + erts_init_trap_export(&ets_select_reverse_exp, am_ets, am_reverse, 3, + &ets_select_reverse); return; }; diff --git a/erts/emulator/beam/erl_process.c b/erts/emulator/beam/erl_process.c index 138acfeb2c..44a99e1f84 100644 --- a/erts/emulator/beam/erl_process.c +++ b/erts/emulator/beam/erl_process.c @@ -9599,13 +9599,8 @@ init_processes_bif(void) + 1); /* processes_trap/2 is a hidden BIF that the processes/0 BIF traps to. */ - sys_memset((void *) &processes_trap_export, 0, sizeof(Export)); - processes_trap_export.address = &processes_trap_export.code[3]; - processes_trap_export.code[0] = am_erlang; - processes_trap_export.code[1] = am_processes_trap; - processes_trap_export.code[2] = 2; - processes_trap_export.code[3] = (BeamInstr) em_apply_bif; - processes_trap_export.code[4] = (BeamInstr) &processes_trap; + erts_init_trap_export(&processes_trap_export, am_erlang, am_processes_trap, 2, + &processes_trap); #if ERTS_PROCESSES_BIF_DEBUGLEVEL >= ERTS_PROCS_DBGLVL_CHK_TERM_PROC_LIST erts_get_emu_time(&debug_tv_start); diff --git a/erts/emulator/beam/erl_unicode.c b/erts/emulator/beam/erl_unicode.c index 6d5eae73b0..049226ab7d 100644 --- a/erts/emulator/beam/erl_unicode.c +++ b/erts/emulator/beam/erl_unicode.c @@ -77,66 +77,25 @@ void erts_init_unicode(void) { max_loop_limit = CONTEXT_REDS * LOOP_FACTOR; /* Non visual BIFs to trap to. */ - memset(&characters_to_utf8_trap_exp, 0, sizeof(Export)); - characters_to_utf8_trap_exp.address = - &characters_to_utf8_trap_exp.code[3]; - characters_to_utf8_trap_exp.code[0] = am_erlang; - characters_to_utf8_trap_exp.code[1] = - am_atom_put("characters_to_utf8_trap",23); - characters_to_utf8_trap_exp.code[2] = 3; - characters_to_utf8_trap_exp.code[3] = - (BeamInstr) em_apply_bif; - characters_to_utf8_trap_exp.code[4] = - (BeamInstr) &characters_to_utf8_trap; - - memset(&characters_to_list_trap_1_exp, 0, sizeof(Export)); - characters_to_list_trap_1_exp.address = - &characters_to_list_trap_1_exp.code[3]; - characters_to_list_trap_1_exp.code[0] = am_erlang; - characters_to_list_trap_1_exp.code[1] = - am_atom_put("characters_to_list_trap_1",25); - characters_to_list_trap_1_exp.code[2] = 3; - characters_to_list_trap_1_exp.code[3] = - (BeamInstr) em_apply_bif; - characters_to_list_trap_1_exp.code[4] = - (BeamInstr) &characters_to_list_trap_1; - - memset(&characters_to_list_trap_2_exp, 0, sizeof(Export)); - characters_to_list_trap_2_exp.address = - &characters_to_list_trap_2_exp.code[3]; - characters_to_list_trap_2_exp.code[0] = am_erlang; - characters_to_list_trap_2_exp.code[1] = - am_atom_put("characters_to_list_trap_2",25); - characters_to_list_trap_2_exp.code[2] = 3; - characters_to_list_trap_2_exp.code[3] = - (BeamInstr) em_apply_bif; - characters_to_list_trap_2_exp.code[4] = - (BeamInstr) &characters_to_list_trap_2; - - - memset(&characters_to_list_trap_3_exp, 0, sizeof(Export)); - characters_to_list_trap_3_exp.address = - &characters_to_list_trap_3_exp.code[3]; - characters_to_list_trap_3_exp.code[0] = am_erlang; - characters_to_list_trap_3_exp.code[1] = - am_atom_put("characters_to_list_trap_3",25); - characters_to_list_trap_3_exp.code[2] = 3; - characters_to_list_trap_3_exp.code[3] = - (BeamInstr) em_apply_bif; - characters_to_list_trap_3_exp.code[4] = - (BeamInstr) &characters_to_list_trap_3; - - memset(&characters_to_list_trap_4_exp, 0, sizeof(Export)); - characters_to_list_trap_4_exp.address = - &characters_to_list_trap_4_exp.code[3]; - characters_to_list_trap_4_exp.code[0] = am_erlang; - characters_to_list_trap_4_exp.code[1] = - am_atom_put("characters_to_list_trap_4",25); - characters_to_list_trap_4_exp.code[2] = 1; - characters_to_list_trap_4_exp.code[3] = - (BeamInstr) em_apply_bif; - characters_to_list_trap_4_exp.code[4] = - (BeamInstr) &characters_to_list_trap_4; + erts_init_trap_export(&characters_to_utf8_trap_exp, + am_erlang, am_atom_put("characters_to_utf8_trap",23), 3, + &characters_to_utf8_trap); + + erts_init_trap_export(&characters_to_list_trap_1_exp, + am_erlang, am_atom_put("characters_to_list_trap_1",25), 3, + &characters_to_list_trap_1); + + erts_init_trap_export(&characters_to_list_trap_2_exp, + am_erlang, am_atom_put("characters_to_list_trap_2",25), 3, + &characters_to_list_trap_2); + + erts_init_trap_export(&characters_to_list_trap_3_exp, + am_erlang, am_atom_put("characters_to_list_trap_3",25), 3, + &characters_to_list_trap_3); + + erts_init_trap_export(&characters_to_list_trap_4_exp, + am_erlang, am_atom_put("characters_to_list_trap_4",25), 1, + &characters_to_list_trap_4); c_to_b_int_trap_exportp = erts_export_put(am_unicode,am_characters_to_binary_int,2); c_to_l_int_trap_exportp = erts_export_put(am_unicode,am_characters_to_list_int,2); diff --git a/erts/emulator/beam/global.h b/erts/emulator/beam/global.h index f1335f600d..46bc58891b 100644 --- a/erts/emulator/beam/global.h +++ b/erts/emulator/beam/global.h @@ -847,6 +847,8 @@ void erts_queue_monitor_message(Process *, Eterm, Eterm, Eterm); +void erts_init_trap_export(Export* ep, Eterm m, Eterm f, Uint a, + Eterm (*bif)(Process*,Eterm*)); void erts_init_bif(void); Eterm erl_send(Process *p, Eterm to, Eterm msg); -- cgit v1.2.3 From 9df5bbccee7f50e11969ed41035ee8bc4bf5f42a Mon Sep 17 00:00:00 2001 From: Sverker Eriksson Date: Wed, 11 Jan 2012 21:15:39 +0100 Subject: erts: Make use of def_lambdas optimization during loading The default array was defined but not used. --- erts/emulator/beam/beam_load.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/erts/emulator/beam/beam_load.c b/erts/emulator/beam/beam_load.c index 3040a2b7cd..27a5e72113 100644 --- a/erts/emulator/beam/beam_load.c +++ b/erts/emulator/beam/beam_load.c @@ -1409,9 +1409,12 @@ read_lambda_table(LoaderState* stp) int i; GetInt(stp, 4, stp->num_lambdas); - stp->lambdas_allocated = stp->num_lambdas; - stp->lambdas = (Lambda *) erts_alloc(ERTS_ALC_T_LOADER_TMP, - stp->num_lambdas * sizeof(Lambda)); + if (stp->num_lambdas > stp->lambdas_allocated) { + ASSERT(stp->lambdas == stp->def_lambdas); + stp->lambdas_allocated = stp->num_lambdas; + stp->lambdas = (Lambda *) erts_alloc(ERTS_ALC_T_LOADER_TMP, + stp->num_lambdas * sizeof(Lambda)); + } for (i = 0; i < stp->num_lambdas; i++) { Uint n; Uint32 Index; -- cgit v1.2.3 From 587e7c4a43e5650637390719dc9df2586368d60b Mon Sep 17 00:00:00 2001 From: Sverker Eriksson Date: Fri, 13 Jan 2012 21:29:49 +0100 Subject: erts: First refactor step of export table --- erts/emulator/beam/export.c | 106 ++++++++++++++++++++++++++++---------------- erts/emulator/beam/export.h | 2 +- 2 files changed, 69 insertions(+), 39 deletions(-) diff --git a/erts/emulator/beam/export.c b/erts/emulator/beam/export.c index fb0ee99119..82636526bf 100644 --- a/erts/emulator/beam/export.c +++ b/erts/emulator/beam/export.c @@ -47,6 +47,20 @@ static erts_smp_rwmtx_t export_table_lock; /* Locks the secondary export table. extern BeamInstr* em_call_error_handler; extern BeamInstr* em_call_traced_function; +struct export_entry +{ + IndexSlot slot; /* MUST BE LOCATED AT TOP OF STRUCT!!! */ + Export* ep; +}; + +/* Helper struct that brings things together in one allocation +*/ +struct export_blob +{ + Export exp; + struct export_entry entry; +}; + void export_info(int to, void *to_arg) { @@ -65,45 +79,54 @@ export_info(int to, void *to_arg) static HashValue -export_hash(Export* x) +export_hash(struct export_entry* ee) { + Export* x = ee->ep; return EXPORT_HASH(x->code[0], x->code[1], x->code[2]); } static int -export_cmp(Export* tmpl, Export* obj) +export_cmp(struct export_entry* tmpl_e, struct export_entry* obj_e) { + Export* tmpl = tmpl_e->ep; + Export* obj = obj_e->ep; return !(tmpl->code[0] == obj->code[0] && tmpl->code[1] == obj->code[1] && tmpl->code[2] == obj->code[2]); } -static Export* -export_alloc(Export* tmpl) +static struct export_entry* +export_alloc(struct export_entry* tmpl_e) { - Export* obj = (Export*) erts_alloc(ERTS_ALC_T_EXPORT, sizeof(Export)); + + Export* tmpl = tmpl_e->ep; + struct export_blob* blob = + (struct export_blob*) erts_alloc(ERTS_ALC_T_EXPORT, sizeof(*blob)); + Export* obj = &blob->exp; obj->fake_op_func_info_for_hipe[0] = 0; obj->fake_op_func_info_for_hipe[1] = 0; obj->code[0] = tmpl->code[0]; obj->code[1] = tmpl->code[1]; obj->code[2] = tmpl->code[2]; - obj->slot.index = -1; + blob->entry.slot.index = -1; obj->address = obj->code+3; obj->code[3] = (BeamInstr) em_call_error_handler; obj->code[4] = 0; obj->match_prog_set = NULL; - return obj; -} + blob->entry.ep = &blob->exp; + return &blob->entry; +} +/*SVERK static void -export_free(Export* obj) +export_free(struct export_entry* obj) { erts_free(ERTS_ALC_T_EXPORT, (void*) obj); } - +*/ void init_export_table(void) @@ -118,7 +141,7 @@ init_export_table(void) f.hash = (H_FUN) export_hash; f.cmp = (HCMP_FUN) export_cmp; f.alloc = (HALLOC_FUN) export_alloc; - f.free = (HFREE_FUN) export_free; + f.free = (HFREE_FUN) NULL; /*SVERK export_free;*/ erts_index_init(ERTS_ALC_T_EXPORT_TABLE, &export_table, "export_list", EXPORT_INITIAL_SIZE, EXPORT_LIMIT, f); @@ -154,13 +177,23 @@ erts_find_export_entry(Eterm m, Eterm f, unsigned int a) */ while (b != (HashBucket*) 0) { - Export* ep = (Export *) b; + Export* ep = ((struct export_entry*) b)->ep; if (ep->code[0] == m && ep->code[1] == f && ep->code[2] == a) { - break; + return ep; } b = b->next; } - return (Export*)b; + return NULL; +} + +static struct export_entry* init_template(struct export_blob* blob, + Eterm m, Eterm f, unsigned a) +{ + blob->entry.ep = &blob->exp; + blob->exp.code[0] = m; + blob->exp.code[1] = f; + blob->exp.code[2] = a; + return &blob->entry; } @@ -178,19 +211,15 @@ erts_find_export_entry(Eterm m, Eterm f, unsigned int a) Export* erts_find_function(Eterm m, Eterm f, unsigned int a) { - Export e; - Export* ep; - - e.code[0] = m; - e.code[1] = f; - e.code[2] = a; + struct export_blob blob; + struct export_entry* ee; - ep = hash_get(&export_table.htable, (void*) &e); - if (ep != NULL && ep->address == ep->code+3 && - ep->code[3] != (BeamInstr) em_call_traced_function) { - ep = NULL; + ee = hash_get(&export_table.htable, init_template(&blob, m, f, a)); + if (ee == NULL || (ee->ep->address == ee->ep->code+3 && + ee->ep->code[3] != (BeamInstr) em_call_traced_function)) { + return NULL; } - return ep; + return ee->ep; } /* @@ -205,18 +234,15 @@ erts_find_function(Eterm m, Eterm f, unsigned int a) Export* erts_export_put(Eterm mod, Eterm func, unsigned int arity) { - Export e; + struct export_blob blob; int ix; ERTS_SMP_LC_ASSERT(erts_initialized == 0 || erts_smp_thr_progress_is_blocking()); ASSERT(is_atom(mod)); ASSERT(is_atom(func)); - e.code[0] = mod; - e.code[1] = func; - e.code[2] = arity; - ix = index_put(&export_table, (void*) &e); - return (Export*) erts_index_lookup(&export_table, ix); + ix = index_put(&export_table, init_template(&blob, mod, func, arity)); + return ((struct export_entry*) erts_index_lookup(&export_table, ix))->ep; } /* @@ -232,24 +258,24 @@ erts_export_put(Eterm mod, Eterm func, unsigned int arity) Export* erts_export_get_or_make_stub(Eterm mod, Eterm func, unsigned int arity) { - Export e; + struct export_blob blob; Export* ep; ASSERT(is_atom(mod)); ASSERT(is_atom(func)); - e.code[0] = mod; - e.code[1] = func; - e.code[2] = arity; ep = erts_find_export_entry(mod, func, arity); if (ep == 0) { + struct export_entry* entry; /* * The code is not loaded (yet). Put the export in the secondary * export table, to avoid having to lock the main export table. */ export_write_lock(); - ep = (Export *) hash_put(&secondary_export_table, (void*) &e); + entry = (struct export_entry *) hash_put(&secondary_export_table, + init_template(&blob, mod, func, arity)); export_write_unlock(); + ep = entry->ep; } return ep; } @@ -281,7 +307,7 @@ erts_export_consolidate(void) Export *export_list(int i) { - return (Export*) erts_index_lookup(&export_table, i); + return ((struct export_entry*) erts_index_lookup(&export_table, i))->ep; } int export_list_size(void) @@ -296,5 +322,9 @@ int export_table_sz(void) Export *export_get(Export *e) { - return hash_get(&export_table.htable, e); + struct export_entry ee; + struct export_entry* entry; + ee.ep = e; + entry = (struct export_entry*)hash_get(&export_table.htable, &ee); + return entry ? entry->ep : NULL; } diff --git a/erts/emulator/beam/export.h b/erts/emulator/beam/export.h index c604fdf7c3..47e5a2c1d1 100644 --- a/erts/emulator/beam/export.h +++ b/erts/emulator/beam/export.h @@ -31,9 +31,9 @@ /* ** Export entry */ + typedef struct export { - IndexSlot slot; /* MUST BE LOCATED AT TOP OF STRUCT!!! */ void* address; /* Pointer to code for function. */ struct binary* match_prog_set; /* Match program for tracing. */ -- cgit v1.2.3 From 41cf0cb977472a15527b6ac693883daaa84faa5a Mon Sep 17 00:00:00 2001 From: Sverker Eriksson Date: Tue, 17 Jan 2012 11:18:26 +0100 Subject: erts: First stab at code_ix interface and beam_catches using it Code loading still blocking --- erts/emulator/beam/beam_bif_load.c | 10 ++- erts/emulator/beam/beam_catches.c | 128 +++++++++++++++++++++++++++---------- erts/emulator/beam/beam_catches.h | 7 +- erts/emulator/beam/beam_load.c | 92 ++++++++++++++++++++++++++ erts/emulator/beam/erl_init.c | 4 +- erts/emulator/beam/global.h | 44 +++++++++++++ 6 files changed, 249 insertions(+), 36 deletions(-) diff --git a/erts/emulator/beam/beam_bif_load.c b/erts/emulator/beam/beam_bif_load.c index 90baa6178e..a8ef198be5 100644 --- a/erts/emulator/beam/beam_bif_load.c +++ b/erts/emulator/beam/beam_bif_load.c @@ -86,11 +86,15 @@ load_module_2(BIF_ALIST_2) erts_smp_proc_unlock(BIF_P, ERTS_PROC_LOCK_MAIN); erts_smp_thr_progress_block(); + erts_start_loader_code_ix(); + reason = erts_finish_loading(stp, BIF_P, 0, &BIF_ARG_1); if (reason != NIL) { + erts_abort_loader_code_ix(); res = TUPLE2(hp, am_error, reason); } else { set_default_trace_pattern(BIF_ARG_1); + erts_commit_loader_code_ix(); res = TUPLE2(hp, am_module, BIF_ARG_1); } @@ -374,7 +378,8 @@ BIF_RETTYPE finish_after_on_load_2(BIF_ALIST_2) code = modp->curr.code; end = (BeamInstr *)((char *)code + modp->curr.code_length); erts_cleanup_funs_on_purge(code, end); - beam_catches_delmod(modp->curr.catches, code, modp->curr.code_length); + beam_catches_delmod(modp->curr.catches, code, modp->curr.code_length, + erts_active_code_ix()); erts_free(ERTS_ALC_T_CODE, (void *) code); modp->curr.code = NULL; modp->curr.code_length = 0; @@ -667,7 +672,8 @@ purge_module(int module) code = modp->old.code; end = (BeamInstr *)((char *)code + modp->old.code_length); erts_cleanup_funs_on_purge(code, end); - beam_catches_delmod(modp->old.catches, code, modp->old.code_length); + beam_catches_delmod(modp->old.catches, code, modp->old.code_length, + erts_active_code_ix()); decrement_refc(code); erts_free(ERTS_ALC_T_CODE, (void *) code); modp->old.code = NULL; diff --git a/erts/emulator/beam/beam_catches.c b/erts/emulator/beam/beam_catches.c index 406ef1db5f..72bd3583e1 100644 --- a/erts/emulator/beam/beam_catches.c +++ b/erts/emulator/beam/beam_catches.c @@ -31,24 +31,77 @@ typedef struct { unsigned cdr; } beam_catch_t; -static int free_list; -static unsigned high_mark; -static unsigned tabsize; -static beam_catch_t *beam_catches; +#ifdef DEBUG +# define IF_DEBUG(x) x +#else +# define IF_DEBUG(x) +#endif + +struct bc_code_ix { /*SVERK A better name maybe... */ + int free_list; + unsigned high_mark; + unsigned tabsize; + beam_catch_t *beam_catches; + + IF_DEBUG(int is_prepared;) +}; + +static struct bc_code_ix bccix[ERTS_NUM_CODE_IX]; void beam_catches_init(void) { - tabsize = DEFAULT_TABSIZE; - free_list = -1; - high_mark = 0; + int i; + + bccix[0].tabsize = DEFAULT_TABSIZE; + bccix[0].free_list = -1; + bccix[0].high_mark = 0; + bccix[0].beam_catches = erts_alloc(ERTS_ALC_T_CODE, + sizeof(beam_catch_t)*DEFAULT_TABSIZE); + IF_DEBUG(bccix[0].is_prepared = 0); + for (i=1; iis_prepared); /* * Allocate from free_list while it is non-empty. * If free_list is empty, allocate at high_mark. @@ -56,53 +109,64 @@ unsigned beam_catches_cons(BeamInstr *cp, unsigned cdr) * This avoids the need to initialise the free list in * beam_catches_init(), which would cost O(TABSIZ) time. */ - if( free_list >= 0 ) { - i = free_list; - free_list = beam_catches[i].cdr; - } else if( high_mark < tabsize ) { - i = high_mark; - high_mark++; - } else { - /* No free slots and table is full: realloc table */ - tabsize = 2*tabsize; - beam_catches = erts_realloc(ERTS_ALC_T_CODE, beam_catches, sizeof(beam_catch_t)*tabsize); - i = high_mark; - high_mark++; + if (p->free_list >= 0) { + i = p->free_list; + p->free_list = p->beam_catches[i].cdr; + } + else { + if (p->high_mark >= p->tabsize) { + /* No free slots and table is full: realloc table */ + beam_catch_t* prev_vec = p->beam_catches; + unsigned newsize = p->tabsize*2; + + p->beam_catches = erts_alloc(ERTS_ALC_T_CODE, + newsize*sizeof(beam_catch_t)); + sys_memcpy(p->beam_catches, prev_vec, + p->tabsize*sizeof(beam_catch_t)); + gc_old_vec(prev_vec); + p->tabsize = newsize; + } + i = p->high_mark++; } - beam_catches[i].cp = cp; - beam_catches[i].cdr = cdr; + p->beam_catches[i].cp = cp; + p->beam_catches[i].cdr = cdr; return i; } BeamInstr *beam_catches_car(unsigned i) { - if( i >= tabsize ) { + struct bc_code_ix* p = &bccix[erts_active_code_ix()]; + + if (i >= p->tabsize ) { erl_exit(1, "beam_catches_delmod: index %#x is out of range\r\n", i); } - return beam_catches[i].cp; + return p->beam_catches[i].cp; } -void beam_catches_delmod(unsigned head, BeamInstr *code, unsigned code_bytes) +void beam_catches_delmod(unsigned head, BeamInstr *code, unsigned code_bytes, + ErtsCodeIndex code_ix) { + struct bc_code_ix* p = &bccix[code_ix]; unsigned i, cdr; + ASSERT((code_ix == erts_active_code_ix()) != bccix[erts_loader_code_ix()].is_prepared); for(i = head; i != (unsigned)-1;) { - if( i >= tabsize ) { + if (i >= p->tabsize) { erl_exit(1, "beam_catches_delmod: index %#x is out of range\r\n", i); } - if( (char*)beam_catches[i].cp - (char*)code >= code_bytes ) { + if( (char*)p->beam_catches[i].cp - (char*)code >= code_bytes ) { erl_exit(1, "beam_catches_delmod: item %#x has cp %#lx which is not " "in module's range [%#lx,%#lx[\r\n", - i, (long)beam_catches[i].cp, + i, (long)p->beam_catches[i].cp, (long)code, (long)((char*)code + code_bytes)); } - beam_catches[i].cp = 0; - cdr = beam_catches[i].cdr; - beam_catches[i].cdr = free_list; - free_list = i; + p->beam_catches[i].cp = 0; + cdr = p->beam_catches[i].cdr; + p->beam_catches[i].cdr = p->free_list; + p->free_list = i; i = cdr; } } diff --git a/erts/emulator/beam/beam_catches.h b/erts/emulator/beam/beam_catches.h index 6223427f0d..970772806b 100644 --- a/erts/emulator/beam/beam_catches.h +++ b/erts/emulator/beam/beam_catches.h @@ -20,12 +20,17 @@ #ifndef __BEAM_CATCHES_H #define __BEAM_CATCHES_H +#include "global.h" /*SVERK the code_ix stuff */ + #define BEAM_CATCHES_NIL (-1) void beam_catches_init(void); +void beam_catches_start_load(void); +void beam_catches_end_load(int commit); unsigned beam_catches_cons(BeamInstr* cp, unsigned cdr); BeamInstr *beam_catches_car(unsigned i); -void beam_catches_delmod(unsigned head, BeamInstr* code, unsigned code_bytes); +void beam_catches_delmod(unsigned head, BeamInstr* code, unsigned code_bytes, + ErtsCodeIndex); #define catch_pc(x) beam_catches_car(catch_val((x))) diff --git a/erts/emulator/beam/beam_load.c b/erts/emulator/beam/beam_load.c index 27a5e72113..f7c8395cb6 100644 --- a/erts/emulator/beam/beam_load.c +++ b/erts/emulator/beam/beam_load.c @@ -6101,3 +6101,95 @@ static int safe_mul(UWord a, UWord b, UWord* resp) return (res / b) == a; } } + + +/*SVERK Do these deserve a file of their own maybe? */ + +static erts_smp_atomic32_t the_active_code_index; +static erts_smp_atomic32_t the_loader_code_index; + +#ifdef DEBUG +# define CIX_TRACE(text) erts_fprintf(stderr, "CIX_TRACE: " text " act=%u load=%u\r\n", erts_active_code_ix(), erts_loader_code_ix()) +#else +# define CIX_TRACE(text) +#endif + +void erts_code_ix_init(void) +{ + erts_smp_atomic32_init_nob(&the_active_code_index, 0); + erts_smp_atomic32_init_nob(&the_loader_code_index, 0); + CIX_TRACE("init"); +} +ErtsCodeIndex erts_active_code_ix(void) +{ + return erts_smp_atomic32_read_nob(&the_active_code_index); +} +ErtsCodeIndex erts_loader_code_ix(void) +{ + return erts_smp_atomic32_read_nob(&the_loader_code_index); +} + +/* Lock code_ix (enqueue and suspend until we get it) +*/ +void erts_lock_code_ix(void) +{ +} + +/* Unlock code_ix (resume first waiter) +*/ +void erts_unlock_code_ix(void) +{ +} + +void erts_start_loader_code_ix(void) +{ + beam_catches_start_load(); + /*SVERK and more to come I guess... + : + */ + CIX_TRACE("start"); +} + + +void erts_commit_loader_code_ix(void) +{ + beam_catches_end_load(1); + { + ErtsCodeIndex ix = erts_loader_code_ix(); + erts_smp_atomic32_set_nob(&the_active_code_index, ix); + ix = (ix + 1) % ERTS_NUM_CODE_IX; + erts_smp_atomic32_set_nob(&the_loader_code_index, ix); + } + CIX_TRACE("commit"); +} + +void erts_abort_loader_code_ix(void) +{ + beam_catches_end_load(0); + CIX_TRACE("abort"); +} + +/*SVERK old_code lock should maybe be part of module.c */ +void erts_rwlock_old_code(void) +{ +} +void erts_rwunlock_old_code(void) +{ +} +void erts_rlock_old_code(void) +{ +} +void erts_runlock_old_code(void) +{ +} + +#ifdef ERTS_ENABLE_LOCK_CHECK +int erts_is_old_code_rlocked(void) +{ + return 1; +} +int erts_is_code_ix_locked(void) +{ + return 1; +} +#endif diff --git a/erts/emulator/beam/erl_init.c b/erts/emulator/beam/erl_init.c index 717315d8bd..8d382057dc 100644 --- a/erts/emulator/beam/erl_init.c +++ b/erts/emulator/beam/erl_init.c @@ -236,7 +236,7 @@ void erl_error(char *fmt, va_list args) static int early_init(int *argc, char **argv); void -erts_short_init(void) +erts_short_init_SVERK_SAYS_NOT_USED(void) { int ncpu = early_init(NULL, NULL); erl_init(ncpu); @@ -264,6 +264,7 @@ erl_init(int ncpu) erts_init_trace(); erts_init_binary(); erts_init_bits(); + erts_code_ix_init(); erts_init_fun_table(); init_atom_table(); init_export_table(); @@ -1471,6 +1472,7 @@ erl_start(int argc, char **argv) init_shared_memory(boot_argc, boot_argv); load_preloaded(); + erts_commit_loader_code_ix(); erts_initialized = 1; diff --git a/erts/emulator/beam/global.h b/erts/emulator/beam/global.h index 46bc58891b..8745ca610b 100644 --- a/erts/emulator/beam/global.h +++ b/erts/emulator/beam/global.h @@ -28,6 +28,50 @@ #include "hash.h" #include "index.h" #include "atom.h" + +/*SVERK maybe put this is some other header, must be before module.h and export.h */ +#define ERTS_NUM_CODE_IX 3 +typedef unsigned ErtsCodeIndex; + +void erts_code_ix_init(void); +ErtsCodeIndex erts_active_code_ix(void); +ErtsCodeIndex erts_loader_code_ix(void); + +/* Lock code_ix (enqueue and suspend until we get it) +*/ +void erts_lock_code_ix(void); + +/*SVERK + erts_lock_code_ix(); + wait for thread progress + (we don't want any retarded threads with pointers to inactive Module) + Copy active -> loader + rlock old_code while copying Modules + Update loader + wait for thread progress + (we need a membarrier for everybody to "see" the new code) + Set loader as new active + erts_unlock_code_ix(); +}*/ + + +/* Unlock code_ix (resume first waiter) +*/ +void erts_unlock_code_ix(void); +void erts_start_loader_code_ix(void); +void erts_commit_loader_code_ix(void); +void erts_abort_loader_code_ix(void); + +void erts_rwlock_old_code(void); +void erts_rwunlock_old_code(void); +void erts_rlock_old_code(void); +void erts_runlock_old_code(void); + +#ifdef ERTS_ENABLE_LOCK_CHECK +int erts_is_old_code_rlocked(void); +int erts_is_code_ix_locked(void); +#endif + #include "export.h" #include "module.h" #include "register.h" -- cgit v1.2.3 From 90209e4d57dd9b5ff27729b582f02c3d9e383f72 Mon Sep 17 00:00:00 2001 From: Sverker Eriksson Date: Tue, 17 Jan 2012 12:16:39 +0100 Subject: erts: Multiple export tab's using code_ix Still blocking code loading --- erts/emulator/beam/beam_bif_load.c | 33 ++++--- erts/emulator/beam/beam_debug.c | 5 +- erts/emulator/beam/beam_emu.c | 17 ++-- erts/emulator/beam/beam_load.c | 15 ++-- erts/emulator/beam/bif.c | 3 +- erts/emulator/beam/code_ix.h | 65 ++++++++++++++ erts/emulator/beam/erl_alloc.c | 4 +- erts/emulator/beam/erl_bif_trace.c | 10 ++- erts/emulator/beam/erl_init.c | 3 +- erts/emulator/beam/export.c | 176 ++++++++++++++++++++++++++++--------- erts/emulator/beam/export.h | 13 ++- erts/emulator/beam/external.c | 2 +- erts/emulator/beam/global.h | 50 +---------- erts/emulator/hipe/hipe_bif0.c | 2 +- 14 files changed, 271 insertions(+), 127 deletions(-) create mode 100644 erts/emulator/beam/code_ix.h diff --git a/erts/emulator/beam/beam_bif_load.c b/erts/emulator/beam/beam_bif_load.c index a8ef198be5..4858859c2d 100644 --- a/erts/emulator/beam/beam_bif_load.c +++ b/erts/emulator/beam/beam_bif_load.c @@ -35,7 +35,7 @@ #include "erl_nif.h" #include "erl_thr_progress.h" -static void set_default_trace_pattern(Eterm module); +static void set_default_trace_pattern(Eterm module, ErtsCodeIndex); static Eterm check_process_code(Process* rp, Module* modp); static void delete_code(Process *c_p, ErtsProcLocks c_p_locks, Module* modp); static void delete_export_references(Eterm module); @@ -90,10 +90,15 @@ load_module_2(BIF_ALIST_2) reason = erts_finish_loading(stp, BIF_P, 0, &BIF_ARG_1); if (reason != NIL) { - erts_abort_loader_code_ix(); + if (reason == am_on_load) { + erts_commit_loader_code_ix(); + } + else { + erts_abort_loader_code_ix(); + } res = TUPLE2(hp, am_error, reason); } else { - set_default_trace_pattern(BIF_ARG_1); + set_default_trace_pattern(BIF_ARG_1, erts_loader_code_ix()); erts_commit_loader_code_ix(); res = TUPLE2(hp, am_module, BIF_ARG_1); } @@ -114,7 +119,7 @@ BIF_RETTYPE purge_module_1(BIF_ALIST_1) erts_smp_proc_unlock(BIF_P, ERTS_PROC_LOCK_MAIN); erts_smp_thr_progress_block(); - erts_export_consolidate(); + erts_export_consolidate(erts_active_code_ix()); purge_res = purge_module(atom_val(BIF_ARG_1)); erts_smp_thr_progress_unblock(); @@ -148,7 +153,7 @@ BIF_RETTYPE code_make_stub_module_3(BIF_ALIST_3) erts_smp_proc_unlock(BIF_P, ERTS_PROC_LOCK_MAIN); erts_smp_thr_progress_block(); - erts_export_consolidate(); + erts_export_consolidate(erts_active_code_ix()); res = erts_make_stub_module(BIF_P, BIF_ARG_1, BIF_ARG_2, BIF_ARG_3); erts_smp_thr_progress_unblock(); @@ -331,8 +336,10 @@ BIF_RETTYPE call_on_load_function_1(BIF_ALIST_1) BIF_RETTYPE finish_after_on_load_2(BIF_ALIST_2) { + ErtsCodeIndex code_ix; Module* modp = erts_get_module(BIF_ARG_1); Eterm on_load; + code_ix = erts_active_code_ix(); if (!modp || modp->curr.code == 0) { error: @@ -354,8 +361,8 @@ BIF_RETTYPE finish_after_on_load_2(BIF_ALIST_2) /* * The on_load function succeded. Fix up export entries. */ - for (i = 0; i < export_list_size(); i++) { - Export *ep = export_list(i); + for (i = 0; i < export_list_size(code_ix); i++) { + Export *ep = export_list(i,code_ix); if (ep != NULL && ep->code[0] == BIF_ARG_1 && ep->code[4] != 0) { @@ -364,7 +371,7 @@ BIF_RETTYPE finish_after_on_load_2(BIF_ALIST_2) } } modp->curr.code[MI_ON_LOAD_FUNCTION_PTR] = 0; - set_default_trace_pattern(BIF_ARG_1); + set_default_trace_pattern(BIF_ARG_1, erts_active_code_ix ()); } else if (BIF_ARG_2 == am_false) { BeamInstr* code; BeamInstr* end; @@ -392,7 +399,7 @@ BIF_RETTYPE finish_after_on_load_2(BIF_ALIST_2) } static void -set_default_trace_pattern(Eterm module) +set_default_trace_pattern(Eterm module, ErtsCodeIndex code_ix) { int trace_pattern_is_on; Binary *match_spec; @@ -412,7 +419,8 @@ set_default_trace_pattern(Eterm module) match_spec, meta_match_spec, 1, trace_pattern_flags, - meta_tracer_pid); + meta_tracer_pid, + code_ix); } } @@ -763,12 +771,13 @@ delete_code(Process *c_p, ErtsProcLocks c_p_locks, Module* modp) static void delete_export_references(Eterm module) { + ErtsCodeIndex code_ix = erts_loader_code_ix(); int i; ASSERT(is_atom(module)); - for (i = 0; i < export_list_size(); i++) { - Export *ep = export_list(i); + for (i = 0; i < export_list_size(code_ix); i++) { + Export *ep = export_list(i, code_ix); if (ep != NULL && (ep->code[0] == module)) { if (ep->address == ep->code+3 && (ep->code[3] == (BeamInstr) em_apply_bif)) { diff --git a/erts/emulator/beam/beam_debug.c b/erts/emulator/beam/beam_debug.c index 4bef59dd66..ff47b26e13 100644 --- a/erts/emulator/beam/beam_debug.c +++ b/erts/emulator/beam/beam_debug.c @@ -207,6 +207,7 @@ erts_debug_disassemble_1(BIF_ALIST_1) BIF_RET(am_false); } } else if (is_tuple(addr)) { + ErtsCodeIndex code_ix; Module* modp; Eterm mod; Eterm name; @@ -231,8 +232,8 @@ erts_debug_disassemble_1(BIF_ALIST_1) * Try the export entry first to allow disassembly of special functions * such as erts_debug:apply/4. Then search for it in the module. */ - - if ((ep = erts_find_function(mod, name, arity)) != NULL) { + code_ix = erts_active_code_ix(); + if ((ep = erts_find_function(mod, name, arity, code_ix)) != NULL) { /* XXX: add "&& ep->address != ep->code+3" condition? * Consider a traced function. * Its ep will have ep->address == ep->code+3. diff --git a/erts/emulator/beam/beam_emu.c b/erts/emulator/beam/beam_emu.c index 97eb4f1edc..177dd397f1 100644 --- a/erts/emulator/beam/beam_emu.c +++ b/erts/emulator/beam/beam_emu.c @@ -5742,7 +5742,8 @@ call_error_handler(Process* p, BeamInstr* fi, Eterm* reg, Eterm func) /* * Search for the error_handler module. */ - ep = erts_find_function(erts_proc_get_error_handler(p), func, 3); + ep = erts_find_function(erts_proc_get_error_handler(p), func, 3, + erts_active_code_ix()); if (ep == NULL) { /* No error handler */ p->current = fi; p->freason = EXC_UNDEF; @@ -5786,7 +5787,7 @@ apply_setup_error_handler(Process* p, Eterm module, Eterm function, Uint arity, * there is no error handler module. */ - if ((ep = erts_find_export_entry(erts_proc_get_error_handler(p), + if ((ep = erts_active_export_entry(erts_proc_get_error_handler(p), am_undefined_function, 3)) == NULL) { return NULL; } else { @@ -5893,7 +5894,7 @@ apply(Process* p, Eterm module, Eterm function, Eterm args, Eterm* reg) * Note: All BIFs have export entries; thus, no special case is needed. */ - if ((ep = erts_find_export_entry(module, function, arity)) == NULL) { + if ((ep = erts_active_export_entry(module, function, arity)) == NULL) { if ((ep = apply_setup_error_handler(p, module, function, arity, reg)) == NULL) goto error; } else if (ERTS_PROC_GET_SAVED_CALLS_BUF(p)) { save_calls(p, ep); @@ -5941,7 +5942,7 @@ fixed_apply(Process* p, Eterm* reg, Uint arity) * Note: All BIFs have export entries; thus, no special case is needed. */ - if ((ep = erts_find_export_entry(module, function, arity)) == NULL) { + if ((ep = erts_active_export_entry(module, function, arity)) == NULL) { if ((ep = apply_setup_error_handler(p, module, function, arity, reg)) == NULL) goto error; } else if (ERTS_PROC_GET_SAVED_CALLS_BUF(p)) { @@ -6118,7 +6119,7 @@ call_fun(Process* p, /* Current process. */ Export* ep; Module* modp; Eterm module; - + ErtsCodeIndex code_ix = erts_active_code_ix(); /* * No arity. There is no module loaded that defines the fun, @@ -6143,7 +6144,7 @@ call_fun(Process* p, /* Current process. */ */ ep = erts_find_function(erts_proc_get_error_handler(p), - am_undefined_lambda, 3); + am_undefined_lambda, 3, code_ix); if (ep == NULL) { /* No error handler */ p->current = NULL; p->freason = EXC_UNDEF; @@ -6215,8 +6216,8 @@ call_fun(Process* p, /* Current process. */ erts_send_warning_to_logger(p->group_leader, dsbufp); } - if ((ep = erts_find_export_entry(module, function, arity)) == NULL) { - ep = erts_find_export_entry(erts_proc_get_error_handler(p), + if ((ep = erts_active_export_entry(module, function, arity)) == NULL) { + ep = erts_active_export_entry(erts_proc_get_error_handler(p), am_undefined_function, 3); if (ep == NULL) { p->freason = EXC_UNDEF; diff --git a/erts/emulator/beam/beam_load.c b/erts/emulator/beam/beam_load.c index f7c8395cb6..7768438dd0 100644 --- a/erts/emulator/beam/beam_load.c +++ b/erts/emulator/beam/beam_load.c @@ -812,7 +812,7 @@ erts_finish_loading(LoaderState* stp, Process* c_p, * exported and imported functions. This can't fail. */ - erts_export_consolidate(); + erts_export_consolidate(erts_loader_code_ix()); CHKBLK(ERTS_ALC_T_CODE,stp->code); final_touch(stp); @@ -1294,7 +1294,7 @@ load_import_table(LoaderState* stp) * If the export entry refers to a BIF, get the pointer to * the BIF function. */ - if ((e = erts_find_export_entry(mod, func, arity)) != NULL) { + if ((e = erts_active_export_entry(mod, func, arity)) != NULL) { /*SVERK does it matter which one we use? */ if (e->code[3] == (BeamInstr) em_apply_bif) { stp->import[i].bf = (BifFunction) e->code[4]; if (func == am_load_nif && mod == am_erlang && arity == 2) { @@ -1386,7 +1386,7 @@ read_export_table(LoaderState* stp) static int is_bif(Eterm mod, Eterm func, unsigned arity) { - Export* e = erts_find_export_entry(mod, func, arity); + Export* e = erts_active_export_entry(mod, func, arity); if (e == NULL) { return 0; } @@ -5190,13 +5190,15 @@ exported_from_module(Process* p, /* Process whose heap to use. */ Eterm* hp = NULL; Eterm* hend = NULL; Eterm result = NIL; + ErtsCodeIndex code_ix; if (is_not_atom(mod)) { return THE_NON_VALUE; } - for (i = 0; i < export_list_size(); i++) { - Export* ep = export_list(i); + code_ix = erts_active_code_ix(); + for (i = 0; i < export_list_size(code_ix); i++) { + Export* ep = export_list(i,code_ix); if (ep->code[0] == mod) { Eterm tuple; @@ -6144,6 +6146,7 @@ void erts_unlock_code_ix(void) void erts_start_loader_code_ix(void) { beam_catches_start_load(); + export_start_load(); /*SVERK and more to come I guess... : */ @@ -6154,6 +6157,7 @@ void erts_start_loader_code_ix(void) void erts_commit_loader_code_ix(void) { beam_catches_end_load(1); + export_end_load(1); { ErtsCodeIndex ix = erts_loader_code_ix(); erts_smp_atomic32_set_nob(&the_active_code_index, ix); @@ -6166,6 +6170,7 @@ void erts_commit_loader_code_ix(void) void erts_abort_loader_code_ix(void) { beam_catches_end_load(0); + export_end_load(0); CIX_TRACE("abort"); } diff --git a/erts/emulator/beam/bif.c b/erts/emulator/beam/bif.c index 9512aa1558..cb99c1381c 100644 --- a/erts/emulator/beam/bif.c +++ b/erts/emulator/beam/bif.c @@ -3709,7 +3709,8 @@ BIF_RETTYPE function_exported_3(BIF_ALIST_3) is_not_small(BIF_ARG_3)) { BIF_ERROR(BIF_P, BADARG); } - if (erts_find_function(BIF_ARG_1, BIF_ARG_2, signed_val(BIF_ARG_3)) == NULL) { + if (erts_find_function(BIF_ARG_1, BIF_ARG_2, signed_val(BIF_ARG_3), + erts_active_code_ix()) == NULL) { BIF_RET(am_false); } BIF_RET(am_true); diff --git a/erts/emulator/beam/code_ix.h b/erts/emulator/beam/code_ix.h new file mode 100644 index 0000000000..6b81102269 --- /dev/null +++ b/erts/emulator/beam/code_ix.h @@ -0,0 +1,65 @@ +/* + * %CopyrightBegin% + * + * Copyright Ericsson AB 2012-2012. All Rights Reserved. + * + * The contents of this file are subject to the Erlang Public License, + * Version 1.1, (the "License"); you may not use this file except in + * compliance with the License. You should have received a copy of the + * Erlang Public License along with this software. If not, it can be + * retrieved online at http://www.erlang.org/. + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and limitations + * under the License. + * + * %CopyrightEnd% + */ +#ifndef __CODE_IX_H__ +#define __CODE_IX_H__ + + +#define ERTS_NUM_CODE_IX 3 +typedef unsigned ErtsCodeIndex; + +void erts_code_ix_init(void); +ErtsCodeIndex erts_active_code_ix(void); +ErtsCodeIndex erts_loader_code_ix(void); + +/* Lock code_ix (enqueue and suspend until we get it) +*/ +void erts_lock_code_ix(void); + +/*SVERK + erts_lock_code_ix(); + wait for thread progress + (we don't want any retarded threads with pointers to inactive Module) + Copy active -> loader + rlock old_code while copying Modules + Update loader + wait for thread progress + (we need a membarrier for everybody to "see" the new code) + Set loader as new active + erts_unlock_code_ix(); +}*/ + + +/* Unlock code_ix (resume first waiter) +*/ +void erts_unlock_code_ix(void); +void erts_start_loader_code_ix(void); +void erts_commit_loader_code_ix(void); +void erts_abort_loader_code_ix(void); + +void erts_rwlock_old_code(void); +void erts_rwunlock_old_code(void); +void erts_rlock_old_code(void); +void erts_runlock_old_code(void); + +#ifdef ERTS_ENABLE_LOCK_CHECK +int erts_is_old_code_rlocked(void); +int erts_is_code_ix_locked(void); +#endif + +#endif /* !__CODE_IX_H__ */ diff --git a/erts/emulator/beam/erl_alloc.c b/erts/emulator/beam/erl_alloc.c index df27186680..07a2539367 100644 --- a/erts/emulator/beam/erl_alloc.c +++ b/erts/emulator/beam/erl_alloc.c @@ -2185,7 +2185,7 @@ erts_memory(int *print_to_p, void *print_to_arg, void *proc, Eterm earg) if (want.code) { size.code = module_table_sz(); size.code += export_table_sz(); - size.code += export_list_size() * sizeof(Export); + size.code += export_list_size(erts_active_code_ix()) * sizeof(Export); size.code += erts_fun_table_sz(); size.code += allocated_modules*sizeof(Range); size.code += erts_total_code_size; @@ -2335,7 +2335,7 @@ erts_allocated_areas(int *print_to_p, void *print_to_arg, void *proc) values[i].arity = 2; values[i].name = "export_list"; - values[i].ui[0] = export_list_size() * sizeof(Export); + values[i].ui[0] = export_list_size(erts_active_code_ix ()) * sizeof(Export); i++; values[i].arity = 2; diff --git a/erts/emulator/beam/erl_bif_trace.c b/erts/emulator/beam/erl_bif_trace.c index b0a58c80ea..7db764280a 100644 --- a/erts/emulator/beam/erl_bif_trace.c +++ b/erts/emulator/beam/erl_bif_trace.c @@ -333,7 +333,8 @@ trace_pattern(Process* p, Eterm MFA, Eterm Pattern, Eterm flaglist) matches = erts_set_trace_pattern(mfa, specified, match_prog_set, match_prog_set, - on, flags, meta_tracer_pid); + on, flags, meta_tracer_pid, + erts_active_code_ix()); MatchSetUnref(match_prog_set); done: @@ -1331,7 +1332,8 @@ int erts_set_trace_pattern(Eterm* mfa, int specified, Binary* match_prog_set, Binary *meta_match_prog_set, int on, struct trace_pattern_flags flags, - Eterm meta_tracer_pid) + Eterm meta_tracer_pid, + ErtsCodeIndex code_ix) { int matches = 0; int i; @@ -1340,8 +1342,8 @@ erts_set_trace_pattern(Eterm* mfa, int specified, * First work on normal functions (not real BIFs). */ - for (i = 0; i < export_list_size(); i++) { - Export* ep = export_list(i); + for (i = 0; i < export_list_size(code_ix); i++) { + Export* ep = export_list(i, code_ix); int j; if (ExportIsBuiltIn(ep)) { diff --git a/erts/emulator/beam/erl_init.c b/erts/emulator/beam/erl_init.c index 8d382057dc..54b3c19616 100644 --- a/erts/emulator/beam/erl_init.c +++ b/erts/emulator/beam/erl_init.c @@ -353,7 +353,8 @@ erl_first_process_otp(char* modname, void* code, unsigned size, int argc, char** Eterm env; start_mod = am_atom_put(modname, sys_strlen(modname)); - if (erts_find_function(start_mod, am_start, 2) == NULL) { + if (erts_find_function(start_mod, am_start, 2, + erts_active_code_ix()) == NULL) { erl_exit(5, "No function %s:start/2\n", modname); } diff --git a/erts/emulator/beam/export.c b/erts/emulator/beam/export.c index 82636526bf..6a71b09472 100644 --- a/erts/emulator/beam/export.c +++ b/erts/emulator/beam/export.c @@ -32,7 +32,13 @@ #define EXPORT_HASH(m,f,a) ((m)*(f)+(a)) -static IndexTable export_table; /* Not locked. */ +#ifdef DEBUG +# define IF_DEBUG(x) x +#else +# define IF_DEBUG(x) +#endif + +static IndexTable export_tables[ERTS_NUM_CODE_IX]; /* Active not locked */ static Hash secondary_export_table; /* Locked. */ #include "erl_smp.h" @@ -58,9 +64,19 @@ struct export_entry struct export_blob { Export exp; + unsigned top_ix; /*SVERK atomic? */ + struct export_entry entryv[ERTS_NUM_CODE_IX]; +}; + +/* Helper struct only used as template +*/ +struct export_templ +{ struct export_entry entry; + Export exp; }; + void export_info(int to, void *to_arg) { @@ -69,7 +85,7 @@ export_info(int to, void *to_arg) if (lock) export_read_lock(); #endif - index_info(to, to_arg, &export_table); + index_info(to, to_arg, &export_tables[erts_active_code_ix()]); hash_info(to, to_arg, &secondary_export_table); #ifdef ERTS_SMP if (lock) @@ -104,20 +120,24 @@ export_alloc(struct export_entry* tmpl_e) struct export_blob* blob = (struct export_blob*) erts_alloc(ERTS_ALC_T_EXPORT, sizeof(*blob)); Export* obj = &blob->exp; - + int i; + obj->fake_op_func_info_for_hipe[0] = 0; obj->fake_op_func_info_for_hipe[1] = 0; obj->code[0] = tmpl->code[0]; obj->code[1] = tmpl->code[1]; obj->code[2] = tmpl->code[2]; - blob->entry.slot.index = -1; obj->address = obj->code+3; obj->code[3] = (BeamInstr) em_call_error_handler; obj->code[4] = 0; obj->match_prog_set = NULL; - blob->entry.ep = &blob->exp; - return &blob->entry; + for (i=0; ientryv[i].slot.index = -1; + blob->entryv[i].ep = &blob->exp; + } + blob->top_ix = 0; + return &blob->entryv[blob->top_ix]; } /*SVERK @@ -133,6 +153,7 @@ init_export_table(void) { HashFunctions f; erts_smp_rwmtx_opt_t rwmtx_opt = ERTS_SMP_RWMTX_OPT_DEFAULT_INITER; + int i; rwmtx_opt.type = ERTS_SMP_RWMTX_TYPE_FREQUENT_READ; rwmtx_opt.lived = ERTS_SMP_RWMTX_LONG_LIVED; @@ -143,8 +164,10 @@ init_export_table(void) f.alloc = (HALLOC_FUN) export_alloc; f.free = (HFREE_FUN) NULL; /*SVERK export_free;*/ - erts_index_init(ERTS_ALC_T_EXPORT_TABLE, &export_table, "export_list", - EXPORT_INITIAL_SIZE, EXPORT_LIMIT, f); + for (i=0; ientry.ep = &blob->exp; - blob->exp.code[0] = m; - blob->exp.code[1] = f; - blob->exp.code[2] = a; - return &blob->entry; + templ->entry.ep = &templ->exp; + templ->entry.slot.index = -1; + templ->exp.code[0] = m; + templ->exp.code[1] = f; + templ->exp.code[2] = a; + return &templ->entry; } @@ -209,12 +241,12 @@ static struct export_entry* init_template(struct export_blob* blob, */ Export* -erts_find_function(Eterm m, Eterm f, unsigned int a) +erts_find_function(Eterm m, Eterm f, unsigned int a, ErtsCodeIndex code_ix) { - struct export_blob blob; + struct export_templ templ; struct export_entry* ee; - ee = hash_get(&export_table.htable, init_template(&blob, m, f, a)); + ee = hash_get(&export_tables[code_ix].htable, init_template(&templ, m, f, a)); if (ee == NULL || (ee->ep->address == ee->ep->code+3 && ee->ep->code[3] != (BeamInstr) em_call_traced_function)) { return NULL; @@ -234,15 +266,14 @@ erts_find_function(Eterm m, Eterm f, unsigned int a) Export* erts_export_put(Eterm mod, Eterm func, unsigned int arity) { - struct export_blob blob; + ErtsCodeIndex code_ix = erts_loader_code_ix(); + struct export_templ templ; int ix; - ERTS_SMP_LC_ASSERT(erts_initialized == 0 - || erts_smp_thr_progress_is_blocking()); ASSERT(is_atom(mod)); ASSERT(is_atom(func)); - ix = index_put(&export_table, init_template(&blob, mod, func, arity)); - return ((struct export_entry*) erts_index_lookup(&export_table, ix))->ep; + ix = index_put(&export_tables[code_ix], init_template(&templ, mod, func, arity)); + return ((struct export_entry*) erts_index_lookup(&export_tables[code_ix], ix))->ep; } /* @@ -258,14 +289,14 @@ erts_export_put(Eterm mod, Eterm func, unsigned int arity) Export* erts_export_get_or_make_stub(Eterm mod, Eterm func, unsigned int arity) { - struct export_blob blob; Export* ep; ASSERT(is_atom(mod)); ASSERT(is_atom(func)); - ep = erts_find_export_entry(mod, func, arity); + ep = erts_active_export_entry(mod, func, arity); if (ep == 0) { + struct export_templ templ; struct export_entry* entry; /* * The code is not loaded (yet). Put the export in the secondary @@ -273,7 +304,7 @@ erts_export_get_or_make_stub(Eterm mod, Eterm func, unsigned int arity) */ export_write_lock(); entry = (struct export_entry *) hash_put(&secondary_export_table, - init_template(&blob, mod, func, arity)); + init_template(&templ, mod, func, arity)); export_write_unlock(); ep = entry->ep; } @@ -286,38 +317,44 @@ erts_export_get_or_make_stub(Eterm mod, Eterm func, unsigned int arity) * export table into the primary. */ void -erts_export_consolidate(void) +erts_export_consolidate(ErtsCodeIndex code_ix) { #ifdef DEBUG HashInfo hi; #endif - ERTS_SMP_LC_ASSERT(erts_initialized == 0 + /*SVERK: Not sure if this is the way to go. + Maye we should always merge into loader ix, + or can loader table act as secondary_export_table?*/ + + ERTS_SMP_LC_ASSERT((erts_is_code_ix_locked() + && code_ix == erts_loader_code_ix()) + || erts_initialized == 0 || erts_smp_thr_progress_is_blocking()); export_write_lock(); - erts_index_merge(&secondary_export_table, &export_table); - erts_hash_merge(&secondary_export_table, &export_table.htable); + erts_index_merge(&secondary_export_table, &export_tables[code_ix]); + erts_hash_merge(&secondary_export_table, &export_tables[code_ix].htable); export_write_unlock(); #ifdef DEBUG - hash_get_info(&hi, &export_table.htable); - ASSERT(export_table.entries == hi.objs); + hash_get_info(&hi, &export_tables[code_ix].htable); + ASSERT(export_tables[code_ix].entries == hi.objs); #endif } -Export *export_list(int i) +Export *export_list(int i, ErtsCodeIndex code_ix) { - return ((struct export_entry*) erts_index_lookup(&export_table, i))->ep; + return ((struct export_entry*) erts_index_lookup(&export_tables[code_ix], i))->ep; } -int export_list_size(void) +int export_list_size(ErtsCodeIndex code_ix) { - return export_table.entries; + return export_tables[code_ix].entries; } int export_table_sz(void) { - return index_table_sz(&export_table); + return index_table_sz(&export_tables[erts_active_code_ix()]); } Export *export_get(Export *e) @@ -325,6 +362,65 @@ Export *export_get(Export *e) struct export_entry ee; struct export_entry* entry; ee.ep = e; - entry = (struct export_entry*)hash_get(&export_table.htable, &ee); + entry = (struct export_entry*)hash_get(&export_tables[erts_active_code_ix()].htable, &ee); return entry ? entry->ep : NULL; } + +static struct export_entry* +export_dummy_alloc(struct export_entry* entry) +{ + return entry; +} + +static struct export_blob* entry_to_blob(struct export_entry* ee) +{ + return (struct export_blob*) + ((char*)ee->ep - offsetof(struct export_blob,exp)); +} + +IF_DEBUG(static ErtsCodeIndex debug_start_load_ix = 0;) + +void export_start_load(void) +{ + ErtsCodeIndex dst_ix = erts_loader_code_ix(); + ErtsCodeIndex src_ix = erts_active_code_ix(); + IndexTable* dst = &export_tables[dst_ix]; + IndexTable* src = &export_tables[src_ix]; + int i; + + ASSERT(dst_ix != src_ix); + ASSERT(debug_start_load_ix == -1); + + /* Trick hash_put (called by index_put below) + * to insert an already allocated entry. */ + dst->htable.fun.alloc = (HALLOC_FUN) &export_dummy_alloc; + + for (i = dst->entries; i < src->entries; i++) { + struct export_entry* src_entry; + struct export_entry* dst_entry; + struct export_blob* blob; + + src_entry = (struct export_entry*) erts_index_lookup(src, i); + blob = entry_to_blob(src_entry); + dst_entry = &blob->entryv[++blob->top_ix]; + ASSERT(blob->top_ix < ERTS_NUM_CODE_IX); + ASSERT(dst_entry->ep == &blob->exp); + ASSERT(dst_entry->slot.index == -1); + index_put(dst, dst_entry); + } + + dst->htable.fun.alloc = (HALLOC_FUN) &export_alloc; /* restore */ + + /*SVERK Remember dst->entries in order to purge on abort */ + + IF_DEBUG(debug_start_load_ix = dst_ix); +} + +void export_end_load(int commit) +{ + ASSERT(debug_start_load_ix == erts_loader_code_ix()); + + /*SVERK Purge if abort */ + + IF_DEBUG(debug_start_load_ix = -1); +} diff --git a/erts/emulator/beam/export.h b/erts/emulator/beam/export.h index 47e5a2c1d1..0aad921b2d 100644 --- a/erts/emulator/beam/export.h +++ b/erts/emulator/beam/export.h @@ -28,6 +28,8 @@ #include "index.h" #endif +#include "code_ix.h" + /* ** Export entry */ @@ -59,17 +61,20 @@ typedef struct export void init_export_table(void); void export_info(int, void *); -Export* erts_find_export_entry(Eterm m, Eterm f, unsigned int a); +Export* erts_find_export_entry(Eterm m, Eterm f, unsigned int a, ErtsCodeIndex); +Export* erts_active_export_entry(Eterm m, Eterm f, unsigned int a); /*SVERK inline? */ Export* erts_export_put(Eterm mod, Eterm func, unsigned int arity); Export* erts_export_get_or_make_stub(Eterm, Eterm, unsigned); -void erts_export_consolidate(void); +void erts_export_consolidate(ErtsCodeIndex); -Export *export_list(int); -int export_list_size(void); +Export *export_list(int,ErtsCodeIndex); +int export_list_size(ErtsCodeIndex); int export_table_sz(void); Export *export_get(Export*); +void export_start_load(void); +void export_end_load(int commit); #include "beam_load.h" /* For em_* extern declarations */ #define ExportIsBuiltIn(EntryPtr) \ diff --git a/erts/emulator/beam/external.c b/erts/emulator/beam/external.c index 152dbcf085..792bf66487 100644 --- a/erts/emulator/beam/external.c +++ b/erts/emulator/beam/external.c @@ -2562,7 +2562,7 @@ dec_term_atom_common: goto error; } if (edep && (edep->flags & ERTS_DIST_EXT_BTT_SAFE)) { - if (!erts_find_export_entry(mod, name, arity)) + if (!erts_active_export_entry(mod, name, arity)) goto error; } *objp = make_export(hp); diff --git a/erts/emulator/beam/global.h b/erts/emulator/beam/global.h index 8745ca610b..4ce6ed5280 100644 --- a/erts/emulator/beam/global.h +++ b/erts/emulator/beam/global.h @@ -28,50 +28,7 @@ #include "hash.h" #include "index.h" #include "atom.h" - -/*SVERK maybe put this is some other header, must be before module.h and export.h */ -#define ERTS_NUM_CODE_IX 3 -typedef unsigned ErtsCodeIndex; - -void erts_code_ix_init(void); -ErtsCodeIndex erts_active_code_ix(void); -ErtsCodeIndex erts_loader_code_ix(void); - -/* Lock code_ix (enqueue and suspend until we get it) -*/ -void erts_lock_code_ix(void); - -/*SVERK - erts_lock_code_ix(); - wait for thread progress - (we don't want any retarded threads with pointers to inactive Module) - Copy active -> loader - rlock old_code while copying Modules - Update loader - wait for thread progress - (we need a membarrier for everybody to "see" the new code) - Set loader as new active - erts_unlock_code_ix(); -}*/ - - -/* Unlock code_ix (resume first waiter) -*/ -void erts_unlock_code_ix(void); -void erts_start_loader_code_ix(void); -void erts_commit_loader_code_ix(void); -void erts_abort_loader_code_ix(void); - -void erts_rwlock_old_code(void); -void erts_rwunlock_old_code(void); -void erts_rlock_old_code(void); -void erts_runlock_old_code(void); - -#ifdef ERTS_ENABLE_LOCK_CHECK -int erts_is_old_code_rlocked(void); -int erts_is_code_ix_locked(void); -#endif - +#include "code_ix.h" #include "export.h" #include "module.h" #include "register.h" @@ -1529,7 +1486,7 @@ void erts_cleanup_offheap(ErlOffHeap *offheap); Uint erts_fit_in_bits(Uint); int list_length(Eterm); -Export* erts_find_function(Eterm, Eterm, unsigned int); +Export* erts_find_function(Eterm, Eterm, unsigned int, ErtsCodeIndex); int erts_is_builtin(Eterm, Eterm, int); Uint32 make_broken_hash(Eterm); Uint32 block_hash(byte *, unsigned, Uint32); @@ -1800,7 +1757,8 @@ extern int erts_call_time_breakpoint_tracing; int erts_set_trace_pattern(Eterm* mfa, int specified, Binary* match_prog_set, Binary *meta_match_prog_set, int on, struct trace_pattern_flags, - Eterm meta_tracer_pid); + Eterm meta_tracer_pid, + ErtsCodeIndex); void erts_get_default_trace_pattern(int *trace_pattern_is_on, Binary **match_spec, diff --git a/erts/emulator/hipe/hipe_bif0.c b/erts/emulator/hipe/hipe_bif0.c index d81c50b4ae..34f58378c7 100644 --- a/erts/emulator/hipe/hipe_bif0.c +++ b/erts/emulator/hipe/hipe_bif0.c @@ -1591,7 +1591,7 @@ BIF_RETTYPE hipe_nonclosure_address(BIF_ALIST_2) f = tp[2]; if (is_not_atom(m) || is_not_atom(f)) goto badfun; - if (!erts_find_export_entry(m, f, BIF_ARG_2)) + if (!erts_active_export_entry(m, f, BIF_ARG_2)) /*SVERK active? */ goto badfun; } else goto badfun; -- cgit v1.2.3 From 5ed73504d7409a449ec4e0c0de421a93c4570e3b Mon Sep 17 00:00:00 2001 From: Sverker Eriksson Date: Wed, 18 Jan 2012 17:23:52 +0100 Subject: erts: Use several addresses in each Export --- erts/emulator/beam/beam_bif_load.c | 6 ++--- erts/emulator/beam/beam_debug.c | 2 +- erts/emulator/beam/beam_emu.c | 21 ++++++++-------- erts/emulator/beam/beam_load.c | 8 +++---- erts/emulator/beam/bif.c | 5 +++- erts/emulator/beam/bif.h | 18 +++++++------- erts/emulator/beam/dist.c | 16 ++++++------- erts/emulator/beam/erl_bif_trace.c | 30 +++++++++++------------ erts/emulator/beam/export.c | 49 +++++++++++++++++++++++++++++++------- erts/emulator/beam/export.h | 4 ++-- erts/emulator/hipe/hipe_bif0.c | 2 +- 11 files changed, 99 insertions(+), 62 deletions(-) diff --git a/erts/emulator/beam/beam_bif_load.c b/erts/emulator/beam/beam_bif_load.c index 4858859c2d..346b64033b 100644 --- a/erts/emulator/beam/beam_bif_load.c +++ b/erts/emulator/beam/beam_bif_load.c @@ -366,7 +366,7 @@ BIF_RETTYPE finish_after_on_load_2(BIF_ALIST_2) if (ep != NULL && ep->code[0] == BIF_ARG_1 && ep->code[4] != 0) { - ep->address = (void *) ep->code[4]; + ep->addressv[code_ix] = (void *) ep->code[4]; ep->code[4] = 0; } } @@ -779,11 +779,11 @@ delete_export_references(Eterm module) for (i = 0; i < export_list_size(code_ix); i++) { Export *ep = export_list(i, code_ix); if (ep != NULL && (ep->code[0] == module)) { - if (ep->address == ep->code+3 && + if (ep->addressv[code_ix] == ep->code+3 && (ep->code[3] == (BeamInstr) em_apply_bif)) { continue; } - ep->address = ep->code+3; + ep->addressv[code_ix] = ep->code+3; ep->code[3] = (BeamInstr) em_call_error_handler; ep->code[4] = 0; MatchSetUnref(ep->match_prog_set); diff --git a/erts/emulator/beam/beam_debug.c b/erts/emulator/beam/beam_debug.c index ff47b26e13..608303cf4b 100644 --- a/erts/emulator/beam/beam_debug.c +++ b/erts/emulator/beam/beam_debug.c @@ -242,7 +242,7 @@ erts_debug_disassemble_1(BIF_ALIST_1) * But this code_ptr will point to the start of the Export, * not the function's func_info instruction. BOOM !? */ - code_ptr = ((BeamInstr *) ep->address) - 5; + code_ptr = ((BeamInstr *) ep->addressv[code_ix]) - 5; funcinfo = code_ptr+2; } else if (modp == NULL || (code_base = modp->curr.code) == NULL) { BIF_RET(am_undef); diff --git a/erts/emulator/beam/beam_emu.c b/erts/emulator/beam/beam_emu.c index 177dd397f1..4bb4885cbb 100644 --- a/erts/emulator/beam/beam_emu.c +++ b/erts/emulator/beam/beam_emu.c @@ -541,7 +541,7 @@ extern int count_instructions; do { \ if (FCALLS > 0) { \ Eterm* dis_next; \ - SET_I(((Export *) Arg(0))->address); \ + SET_I(((Export *) Arg(0))->addressv[erts_active_code_ix()]); \ dis_next = (Eterm *) *I; \ FCALLS--; \ CHECK_ARGS(I); \ @@ -550,7 +550,7 @@ extern int count_instructions; && FCALLS > neg_o_reds) { \ goto save_calls1; \ } else { \ - SET_I(((Export *) Arg(0))->address); \ + SET_I(((Export *) Arg(0))->addressv[erts_active_code_ix()]); \ CHECK_ARGS(I); \ goto context_switch; \ } \ @@ -5065,7 +5065,7 @@ void process_main(void) save_calls(c_p, (Export *) Arg(0)); - SET_I(((Export *) Arg(0))->address); + SET_I(((Export *) Arg(0))->addressv[erts_active_code_ix()]); dis_next = (Eterm *) *I; FCALLS--; @@ -5773,7 +5773,7 @@ call_error_handler(Process* p, BeamInstr* fi, Eterm* reg, Eterm func) reg[0] = fi[0]; reg[1] = fi[1]; reg[2] = args; - return ep->address; + return ep->addressv[erts_active_code_ix()]; } @@ -5900,7 +5900,7 @@ apply(Process* p, Eterm module, Eterm function, Eterm args, Eterm* reg) save_calls(p, ep); } - return ep->address; + return ep->addressv[erts_active_code_ix()]; } static BeamInstr* @@ -5949,7 +5949,7 @@ fixed_apply(Process* p, Eterm* reg, Uint arity) save_calls(p, ep); } - return ep->address; + return ep->addressv[erts_active_code_ix()]; } int @@ -6154,7 +6154,7 @@ call_fun(Process* p, /* Current process. */ reg[1] = fun; reg[2] = args; reg[3] = NIL; - return ep->address; + return ep->addressv[erts_active_code_ix()]; } } } else if (is_export_header(hdr)) { @@ -6165,7 +6165,7 @@ call_fun(Process* p, /* Current process. */ actual_arity = (int) ep->code[2]; if (arity == actual_arity) { - return ep->address; + return ep->addressv[erts_active_code_ix()]; } else { /* * Wrong arity. First build a list of the arguments. @@ -6240,7 +6240,7 @@ call_fun(Process* p, /* Current process. */ reg[1] = function; reg[2] = args; } - return ep->address; + return ep->addressv[erts_active_code_ix()]; } else { badfun: p->current = NULL; @@ -6345,7 +6345,8 @@ erts_is_builtin(Eterm Mod, Eterm Name, int arity) if ((ep = export_get(&e)) == NULL) { return 0; } - return ep->address == ep->code+3 && (ep->code[3] == (BeamInstr) em_apply_bif); + return ep->addressv[erts_active_code_ix()] == ep->code+3 + && (ep->code[3] == (BeamInstr) em_apply_bif); } diff --git a/erts/emulator/beam/beam_load.c b/erts/emulator/beam/beam_load.c index 7768438dd0..c35841af9d 100644 --- a/erts/emulator/beam/beam_load.c +++ b/erts/emulator/beam/beam_load.c @@ -4303,13 +4303,13 @@ final_touch(LoaderState* stp) ep = erts_export_put(stp->module, stp->export[i].function, stp->export[i].arity); if (!on_load) { - ep->address = address; + ep->addressv[erts_loader_code_ix()] = address; } else { /* * Don't make any of the exported functions * callable yet. */ - ep->address = ep->code+3; + ep->addressv[erts_loader_code_ix()] = ep->code+3; ep->code[4] = (BeamInstr) address; } } @@ -5203,7 +5203,7 @@ exported_from_module(Process* p, /* Process whose heap to use. */ if (ep->code[0] == mod) { Eterm tuple; - if (ep->address == ep->code+3 && + if (ep->addressv[code_ix] == ep->code+3 && ep->code[3] == (BeamInstr) em_call_error_handler) { /* There is a call to the function, but it does not exist. */ continue; @@ -5692,7 +5692,7 @@ stub_final_touch(LoaderState* stp, BeamInstr* fp) for (i = 0; i < n; i++) { if (stp->export[i].function == function && stp->export[i].arity == arity) { Export* ep = erts_export_put(mod, function, arity); - ep->address = fp+5; + ep->addressv[erts_loader_code_ix()] = fp+5; return; } } diff --git a/erts/emulator/beam/bif.c b/erts/emulator/beam/bif.c index cb99c1381c..9b2394d92f 100644 --- a/erts/emulator/beam/bif.c +++ b/erts/emulator/beam/bif.c @@ -4438,8 +4438,11 @@ Export bif_return_trap_export; void erts_init_trap_export(Export* ep, Eterm m, Eterm f, Uint a, Eterm (*bif)(BIF_ALIST_0)) { + int i; sys_memset((void *) ep, 0, sizeof(Export)); - ep->address = &ep->code[3]; + for (i=0; iaddressv[i] = &ep->code[3]; + } ep->code[0] = m; ep->code[1] = f; ep->code[2] = a; diff --git a/erts/emulator/beam/bif.h b/erts/emulator/beam/bif.h index d20089a9fb..7cb2c78815 100644 --- a/erts/emulator/beam/bif.h +++ b/erts/emulator/beam/bif.h @@ -125,7 +125,7 @@ do { \ #define ERTS_BIF_PREP_TRAP0(Ret, Trap, Proc) \ do { \ (Proc)->arity = 0; \ - (Proc)->i = (BeamInstr*) ((Trap)->address); \ + (Proc)->i = (BeamInstr*) ((Trap)->addressv[erts_active_code_ix()]); \ (Proc)->freason = TRAP; \ (Ret) = THE_NON_VALUE; \ } while (0) @@ -135,7 +135,7 @@ do { \ Eterm* reg = ERTS_PROC_GET_SCHDATA((Proc))->x_reg_array; \ (Proc)->arity = 1; \ reg[0] = (Eterm) (A0); \ - (Proc)->i = (BeamInstr*) ((Trap)->address); \ + (Proc)->i = (BeamInstr*) ((Trap)->addressv[erts_active_code_ix()]); \ (Proc)->freason = TRAP; \ (Ret) = THE_NON_VALUE; \ } while (0) @@ -146,7 +146,7 @@ do { \ (Proc)->arity = 2; \ reg[0] = (Eterm) (A0); \ reg[1] = (Eterm) (A1); \ - (Proc)->i = (BeamInstr*) ((Trap)->address); \ + (Proc)->i = (BeamInstr*) ((Trap)->addressv[erts_active_code_ix()]); \ (Proc)->freason = TRAP; \ (Ret) = THE_NON_VALUE; \ } while (0) @@ -158,7 +158,7 @@ do { \ reg[0] = (Eterm) (A0); \ reg[1] = (Eterm) (A1); \ reg[2] = (Eterm) (A2); \ - (Proc)->i = (BeamInstr*) ((Trap)->address); \ + (Proc)->i = (BeamInstr*) ((Trap)->addressv[erts_active_code_ix()]); \ (Proc)->freason = TRAP; \ (Ret) = THE_NON_VALUE; \ } while (0) @@ -170,13 +170,13 @@ do { \ reg[0] = (Eterm) (A0); \ reg[1] = (Eterm) (A1); \ reg[2] = (Eterm) (A2); \ - (Proc)->i = (BeamInstr*) ((Trap)->address); \ + (Proc)->i = (BeamInstr*) ((Trap)->addressv[erts_active_code_ix()]); \ (Proc)->freason = TRAP; \ } while (0) #define BIF_TRAP0(p, Trap_) do { \ (p)->arity = 0; \ - (p)->i = (BeamInstr*) ((Trap_)->address); \ + (p)->i = (BeamInstr*) ((Trap_)->addressv[erts_active_code_ix()]); \ (p)->freason = TRAP; \ return THE_NON_VALUE; \ } while(0) @@ -185,7 +185,7 @@ do { \ Eterm* reg = ERTS_PROC_GET_SCHDATA((p))->x_reg_array; \ (p)->arity = 1; \ reg[0] = (A0); \ - (p)->i = (BeamInstr*) ((Trap_)->address); \ + (p)->i = (BeamInstr*) ((Trap_)->addressv[erts_active_code_ix()]); \ (p)->freason = TRAP; \ return THE_NON_VALUE; \ } while(0) @@ -195,7 +195,7 @@ do { \ (p)->arity = 2; \ reg[0] = (A0); \ reg[1] = (A1); \ - (p)->i = (BeamInstr*) ((Trap_)->address); \ + (p)->i = (BeamInstr*) ((Trap_)->addressv[erts_active_code_ix()]); \ (p)->freason = TRAP; \ return THE_NON_VALUE; \ } while(0) @@ -206,7 +206,7 @@ do { \ reg[0] = (A0); \ reg[1] = (A1); \ reg[2] = (A2); \ - (p)->i = (BeamInstr*) ((Trap_)->address); \ + (p)->i = (BeamInstr*) ((Trap_)->addressv[erts_active_code_ix()]); \ (p)->freason = TRAP; \ return THE_NON_VALUE; \ } while(0) diff --git a/erts/emulator/beam/dist.c b/erts/emulator/beam/dist.c index bee61e7273..00d57ceab5 100644 --- a/erts/emulator/beam/dist.c +++ b/erts/emulator/beam/dist.c @@ -2295,15 +2295,15 @@ BIF_RETTYPE setnode_2(BIF_ALIST_2) goto error; /* Check that all trap functions are defined !! */ - if (dsend2_trap->address == NULL || - dsend3_trap->address == NULL || + if (dsend2_trap->addressv[0] == NULL || + dsend3_trap->addressv[0] == NULL || /* dsend_nosuspend_trap->address == NULL ||*/ - dlink_trap->address == NULL || - dunlink_trap->address == NULL || - dmonitor_node_trap->address == NULL || - dgroup_leader_trap->address == NULL || - dmonitor_p_trap->address == NULL || - dexit_trap->address == NULL) { + dlink_trap->addressv[0] == NULL || + dunlink_trap->addressv[0] == NULL || + dmonitor_node_trap->addressv[0] == NULL || + dgroup_leader_trap->addressv[0] == NULL || + dmonitor_p_trap->addressv[0] == NULL || + dexit_trap->addressv[0] == NULL) { goto error; } diff --git a/erts/emulator/beam/erl_bif_trace.c b/erts/emulator/beam/erl_bif_trace.c index 7db764280a..cb43069fa9 100644 --- a/erts/emulator/beam/erl_bif_trace.c +++ b/erts/emulator/beam/erl_bif_trace.c @@ -60,8 +60,8 @@ static Eterm trace_info_pid(Process* p, Eterm pid_spec, Eterm key); static Eterm trace_info_func(Process* p, Eterm pid_spec, Eterm key); static Eterm trace_info_on_load(Process* p, Eterm key); -static int setup_func_trace(Export* ep, void* match_prog); -static int reset_func_trace(Export* ep); +static int setup_func_trace(Export* ep, void* match_prog, ErtsCodeIndex); +static int reset_func_trace(Export* ep, ErtsCodeIndex); static void reset_bif_trace(int bif_index); static void setup_bif_trace(int bif_index); static void set_trace_bif(int bif_index, void* match_prog); @@ -991,7 +991,7 @@ static int function_is_traced(Process *p, e.code[1] = mfa[1]; e.code[2] = mfa[2]; if ((ep = export_get(&e)) != NULL) { - if (ep->address == ep->code+3 && + if (ep->addressv[erts_active_code_ix()] == ep->code+3 && ep->code[3] != (BeamInstr) em_call_error_handler) { if (ep->code[3] == (BeamInstr) em_call_traced_function) { *ms = ep->match_prog_set; @@ -1357,11 +1357,11 @@ erts_set_trace_pattern(Eterm* mfa, int specified, if (j == specified) { if (on) { if (! flags.breakpoint) - matches += setup_func_trace(ep, match_prog_set); + matches += setup_func_trace(ep, match_prog_set, code_ix); else - reset_func_trace(ep); + reset_func_trace(ep, code_ix); } else if (! flags.breakpoint) { - matches += reset_func_trace(ep); + matches += reset_func_trace(ep, code_ix); } } } @@ -1524,9 +1524,9 @@ erts_set_trace_pattern(Eterm* mfa, int specified, */ static int -setup_func_trace(Export* ep, void* match_prog) +setup_func_trace(Export* ep, void* match_prog, ErtsCodeIndex code_ix) { - if (ep->address == ep->code+3) { + if (ep->addressv[code_ix] == ep->code+3) { if (ep->code[3] == (BeamInstr) em_call_error_handler) { return 0; } else if (ep->code[3] == (BeamInstr) em_call_traced_function) { @@ -1545,13 +1545,13 @@ setup_func_trace(Export* ep, void* match_prog) /* * Currently no trace support for native code. */ - if (erts_is_native_break(ep->address)) { + if (erts_is_native_break(ep->addressv[code_ix])) { return 0; } ep->code[3] = (BeamInstr) em_call_traced_function; - ep->code[4] = (BeamInstr) ep->address; - ep->address = ep->code+3; + ep->code[4] = (BeamInstr) ep->addressv[code_ix]; + ep->addressv[code_ix] = ep->code+3; ep->match_prog_set = match_prog; MatchSetRef(ep->match_prog_set); return 1; @@ -1586,13 +1586,13 @@ static void set_trace_bif(int bif_index, void* match_prog) { */ static int -reset_func_trace(Export* ep) +reset_func_trace(Export* ep, ErtsCodeIndex code_ix) { - if (ep->address == ep->code+3) { + if (ep->addressv[code_ix] == ep->code+3) { if (ep->code[3] == (BeamInstr) em_call_error_handler) { return 0; } else if (ep->code[3] == (BeamInstr) em_call_traced_function) { - ep->address = (Uint *) ep->code[4]; + ep->addressv[code_ix] = (Uint *) ep->code[4]; MatchSetUnref(ep->match_prog_set); ep->match_prog_set = NULL; return 1; @@ -1607,7 +1607,7 @@ reset_func_trace(Export* ep) /* * Currently no trace support for native code. */ - if (erts_is_native_break(ep->address)) { + if (erts_is_native_break(ep->addressv[code_ix])) { return 0; } diff --git a/erts/emulator/beam/export.c b/erts/emulator/beam/export.c index 6a71b09472..51d0116110 100644 --- a/erts/emulator/beam/export.c +++ b/erts/emulator/beam/export.c @@ -127,12 +127,13 @@ export_alloc(struct export_entry* tmpl_e) obj->code[0] = tmpl->code[0]; obj->code[1] = tmpl->code[1]; obj->code[2] = tmpl->code[2]; - obj->address = obj->code+3; obj->code[3] = (BeamInstr) em_call_error_handler; obj->code[4] = 0; obj->match_prog_set = NULL; for (i=0; iaddressv[i] = obj->code+3; + blob->entryv[i].slot.index = -1; blob->entryv[i].ep = &blob->exp; } @@ -191,6 +192,9 @@ erts_active_export_entry(Eterm m, Eterm f, unsigned int a) return erts_find_export_entry(m, f, a, erts_active_code_ix()); } +static void sverk_break(void) +{ +} Export* erts_find_export_entry(Eterm m, Eterm f, unsigned int a, @@ -200,6 +204,10 @@ erts_find_export_entry(Eterm m, Eterm f, unsigned int a, int ix; HashBucket* b; + if (ERTS_IS_ATOM_STR("gen_event",m) && ERTS_IS_ATOM_STR("add_handler",f)) { + sverk_break(); + } + ix = hval % export_tables[code_ix].htable.size; b = export_tables[code_ix].htable.bucket[ix]; @@ -246,8 +254,12 @@ erts_find_function(Eterm m, Eterm f, unsigned int a, ErtsCodeIndex code_ix) struct export_templ templ; struct export_entry* ee; + if (ERTS_IS_ATOM_STR("gen_event",m) && ERTS_IS_ATOM_STR("add_handler",f)) { + sverk_break(); + } + ee = hash_get(&export_tables[code_ix].htable, init_template(&templ, m, f, a)); - if (ee == NULL || (ee->ep->address == ee->ep->code+3 && + if (ee == NULL || (ee->ep->addressv[code_ix] == ee->ep->code+3 && ee->ep->code[3] != (BeamInstr) em_call_traced_function)) { return NULL; } @@ -270,6 +282,10 @@ erts_export_put(Eterm mod, Eterm func, unsigned int arity) struct export_templ templ; int ix; + if (ERTS_IS_ATOM_STR("gen_event",mod) && ERTS_IS_ATOM_STR("add_handler",func)) { + sverk_break(); + } + ASSERT(is_atom(mod)); ASSERT(is_atom(func)); ix = index_put(&export_tables[code_ix], init_template(&templ, mod, func, arity)); @@ -361,6 +377,10 @@ Export *export_get(Export *e) { struct export_entry ee; struct export_entry* entry; + + if (ERTS_IS_ATOM_STR("gen_event",e->code[0]) && ERTS_IS_ATOM_STR("add_handler",e->code[1])) { + sverk_break(); + } ee.ep = e; entry = (struct export_entry*)hash_get(&export_tables[erts_active_code_ix()].htable, &ee); return entry ? entry->ep : NULL; @@ -386,23 +406,36 @@ void export_start_load(void) ErtsCodeIndex src_ix = erts_active_code_ix(); IndexTable* dst = &export_tables[dst_ix]; IndexTable* src = &export_tables[src_ix]; + struct export_entry* src_entry; + struct export_entry* dst_entry; + struct export_blob* blob; int i; ASSERT(dst_ix != src_ix); + ASSERT(dst->entries <= src->entries); ASSERT(debug_start_load_ix == -1); - /* Trick hash_put (called by index_put below) - * to insert an already allocated entry. */ + /* + * Make sure our existing entries are up to date + */ + for (i = 0; i < dst->entries; i++) { + src_entry = (struct export_entry*) erts_index_lookup(src, i); + blob = entry_to_blob(src_entry); + blob->exp.addressv[dst_ix] = blob->exp.addressv[src_ix]; + } + + /* + * Insert all new entries from active table + */ + + /* Trick hash_put (called by index_put) to insert existing entries. */ dst->htable.fun.alloc = (HALLOC_FUN) &export_dummy_alloc; for (i = dst->entries; i < src->entries; i++) { - struct export_entry* src_entry; - struct export_entry* dst_entry; - struct export_blob* blob; - src_entry = (struct export_entry*) erts_index_lookup(src, i); blob = entry_to_blob(src_entry); dst_entry = &blob->entryv[++blob->top_ix]; + blob->exp.addressv[dst_ix] = blob->exp.addressv[src_ix]; ASSERT(blob->top_ix < ERTS_NUM_CODE_IX); ASSERT(dst_entry->ep == &blob->exp); ASSERT(dst_entry->slot.index == -1); diff --git a/erts/emulator/beam/export.h b/erts/emulator/beam/export.h index 0aad921b2d..db27606c49 100644 --- a/erts/emulator/beam/export.h +++ b/erts/emulator/beam/export.h @@ -36,7 +36,7 @@ typedef struct export { - void* address; /* Pointer to code for function. */ + void* addressv[ERTS_NUM_CODE_IX]; /* Pointer to code for function. */ struct binary* match_prog_set; /* Match program for tracing. */ BeamInstr fake_op_func_info_for_hipe[2]; /* MUST be just before code[] */ @@ -78,7 +78,7 @@ void export_end_load(int commit); #include "beam_load.h" /* For em_* extern declarations */ #define ExportIsBuiltIn(EntryPtr) \ -(((EntryPtr)->address == (EntryPtr)->code + 3) && \ +(((EntryPtr)->addressv[erts_active_code_ix()] == (EntryPtr)->code + 3) && \ ((EntryPtr)->code[3] == (BeamInstr) em_apply_bif)) #endif diff --git a/erts/emulator/hipe/hipe_bif0.c b/erts/emulator/hipe/hipe_bif0.c index 34f58378c7..4afc2030e7 100644 --- a/erts/emulator/hipe/hipe_bif0.c +++ b/erts/emulator/hipe/hipe_bif0.c @@ -648,7 +648,7 @@ static void *hipe_get_emu_address(Eterm m, Eterm f, unsigned int arity, int is_r /* if not found, stub it via the export entry */ /* no lock needed around erts_export_get_or_make_stub() */ Export *export_entry = erts_export_get_or_make_stub(m, f, arity); - address = export_entry->address; + address = export_entry->addressv[erts_loader_code_ix()]; } return address; } -- cgit v1.2.3 From aac03c5e9ccf9f6066e291a7c87dd58c1181c227 Mon Sep 17 00:00:00 2001 From: Sverker Eriksson Date: Thu, 19 Jan 2012 12:10:20 +0100 Subject: erts: Multiple module tables using code_ix --- erts/emulator/beam/beam_bif_load.c | 182 +++++++++++++++++++++++-------------- erts/emulator/beam/beam_bp.c | 16 ++-- erts/emulator/beam/beam_debug.c | 4 +- erts/emulator/beam/beam_emu.c | 4 +- erts/emulator/beam/beam_load.c | 24 +++-- erts/emulator/beam/break.c | 59 ++++++------ erts/emulator/beam/code_ix.h | 8 +- erts/emulator/beam/erl_nif.c | 2 +- erts/emulator/beam/export.c | 4 - erts/emulator/beam/index.c | 15 +++ erts/emulator/beam/index.h | 2 + erts/emulator/beam/module.c | 109 +++++++++++++++++++--- erts/emulator/beam/module.h | 8 +- erts/emulator/hipe/hipe_bif0.c | 2 +- 14 files changed, 295 insertions(+), 144 deletions(-) diff --git a/erts/emulator/beam/beam_bif_load.c b/erts/emulator/beam/beam_bif_load.c index 346b64033b..458e4794bd 100644 --- a/erts/emulator/beam/beam_bif_load.c +++ b/erts/emulator/beam/beam_bif_load.c @@ -134,16 +134,22 @@ BIF_RETTYPE purge_module_1(BIF_ALIST_1) BIF_RETTYPE code_is_module_native_1(BIF_ALIST_1) { Module* modp; + Eterm res; + ErtsCodeIndex code_ix; if (is_not_atom(BIF_ARG_1)) { BIF_ERROR(BIF_P, BADARG); } - if ((modp = erts_get_module(BIF_ARG_1)) == NULL) { + code_ix = erts_active_code_ix(); + if ((modp = erts_get_module(BIF_ARG_1, code_ix)) == NULL) { return am_undefined; } - return ((modp->curr.code && is_native(modp->curr.code)) || + erts_rlock_old_code(code_ix); + res = ((modp->curr.code && is_native(modp->curr.code)) || (modp->old.code != 0 && is_native(modp->old.code))) ? am_true : am_false; + erts_runlock_old_code(code_ix); + return res; } BIF_RETTYPE code_make_stub_module_3(BIF_ALIST_3) @@ -164,18 +170,23 @@ BIF_RETTYPE code_make_stub_module_3(BIF_ALIST_3) BIF_RETTYPE check_old_code_1(BIF_ALIST_1) { + ErtsCodeIndex code_ix; Module* modp; + Eterm res = am_false; if (is_not_atom(BIF_ARG_1)) { BIF_ERROR(BIF_P, BADARG); } - modp = erts_get_module(BIF_ARG_1); - if (modp == NULL) { /* Doesn't exist. */ - BIF_RET(am_false); - } else if (modp->old.code == NULL) { /* No old code. */ - BIF_RET(am_false); + code_ix = erts_active_code_ix(); + modp = erts_get_module(BIF_ARG_1, code_ix); + if (modp != NULL) { + erts_rlock_old_code(code_ix); + if (modp->old.code != NULL) { + res = am_true; + } + erts_runlock_old_code(code_ix); } - BIF_RET(am_true); + BIF_RET(res); } Eterm @@ -189,13 +200,19 @@ check_process_code_2(BIF_ALIST_2) } if (is_internal_pid(BIF_ARG_1)) { Eterm res; + ErtsCodeIndex code_ix; if (internal_pid_index(BIF_ARG_1) >= erts_max_processes) goto error; - modp = erts_get_module(BIF_ARG_2); + code_ix = erts_active_code_ix(); + modp = erts_get_module(BIF_ARG_2, code_ix); if (modp == NULL) { /* Doesn't exist. */ return am_false; - } else if (modp->old.code == NULL) { /* No old code. */ - return am_false; + } else { + erts_rlock_old_code(code_ix); + if (modp->old.code == NULL) { /* No old code. */ + erts_runlock_old_code(code_ix); + return am_false; + } } #ifdef ERTS_SMP @@ -212,6 +229,7 @@ check_process_code_2(BIF_ALIST_2) BIF_ARG_1, BIF_ARG_2); } res = check_process_code(rp, modp); + erts_runlock_old_code(code_ix); #ifdef ERTS_SMP if (BIF_P != rp) { erts_resume(rp, ERTS_PROC_LOCK_MAIN); @@ -232,6 +250,7 @@ check_process_code_2(BIF_ALIST_2) BIF_RETTYPE delete_module_1(BIF_ALIST_1) { + ErtsCodeIndex code_ix; int res; if (is_not_atom(BIF_ARG_1)) @@ -240,8 +259,9 @@ BIF_RETTYPE delete_module_1(BIF_ALIST_1) erts_smp_proc_unlock(BIF_P, ERTS_PROC_LOCK_MAIN); erts_smp_thr_progress_block(); + code_ix = erts_active_code_ix(); { - Module *modp = erts_get_module(BIF_ARG_1); + Module *modp = erts_get_module(BIF_ARG_1, code_ix); if (!modp) { res = am_undefined; } @@ -272,16 +292,20 @@ BIF_RETTYPE delete_module_1(BIF_ALIST_1) BIF_RETTYPE module_loaded_1(BIF_ALIST_1) { Module* modp; + ErtsCodeIndex code_ix; + Eterm res = am_false; if (is_not_atom(BIF_ARG_1)) { BIF_ERROR(BIF_P, BADARG); } - if ((modp = erts_get_module(BIF_ARG_1)) == NULL || - modp->curr.code == NULL || - modp->curr.code[MI_ON_LOAD_FUNCTION_PTR] != 0) { - BIF_RET(am_false); + code_ix = erts_active_code_ix(); + if ((modp = erts_get_module(BIF_ARG_1, code_ix)) != NULL) { + if (modp->curr.code != NULL + && modp->curr.code[MI_ON_LOAD_FUNCTION_PTR] == 0) { + res = am_true; + } } - BIF_RET(am_true); + BIF_RET(res); } BIF_RETTYPE pre_loaded_0(BIF_ALIST_0) @@ -291,27 +315,28 @@ BIF_RETTYPE pre_loaded_0(BIF_ALIST_0) BIF_RETTYPE loaded_0(BIF_ALIST_0) { + ErtsCodeIndex code_ix = erts_active_code_ix(); + Module* modp; Eterm previous = NIL; Eterm* hp; int i; int j = 0; - - for (i = 0; i < module_code_size(); i++) { - if (module_code(i) != NULL && - ((module_code(i)->curr.code_length != 0) || - (module_code(i)->old.code_length != 0))) { + + for (i = 0; i < module_code_size(code_ix); i++) { + if ((modp = module_code(i, code_ix)) != NULL && + ((modp->curr.code_length != 0) || + (modp->old.code_length != 0))) { j++; } } if (j > 0) { hp = HAlloc(BIF_P, j*2); - for (i = 0; i < module_code_size(); i++) { - if (module_code(i) != NULL && - ((module_code(i)->curr.code_length != 0) || - (module_code(i)->old.code_length != 0))) { - previous = CONS(hp, make_atom(module_code(i)->module), - previous); + for (i = 0; i < module_code_size(code_ix); i++) { + if ((modp=module_code(i,code_ix)) != NULL && + ((modp->curr.code_length != 0) || + (modp->old.code_length != 0))) { + previous = CONS(hp, make_atom(modp->module), previous); hp += 2; } } @@ -321,25 +346,30 @@ BIF_RETTYPE loaded_0(BIF_ALIST_0) BIF_RETTYPE call_on_load_function_1(BIF_ALIST_1) { - Module* modp = erts_get_module(BIF_ARG_1); - Eterm on_load; + ErtsCodeIndex code_ix = erts_active_code_ix(); /*SVERK ?? on_load ?? */ + Module* modp = erts_get_module(BIF_ARG_1, code_ix); + Eterm on_load = 0; - if (!modp || modp->curr.code == 0) { - error: - BIF_ERROR(BIF_P, BADARG); + if (modp) { + if (modp->curr.code) { + on_load = modp->curr.code[MI_ON_LOAD_FUNCTION_PTR]; + } } - if ((on_load = modp->curr.code[MI_ON_LOAD_FUNCTION_PTR]) == 0) { - goto error; + if (on_load) { + BIF_TRAP_CODE_PTR_0(BIF_P, on_load); + } + else { + BIF_ERROR(BIF_P, BADARG); } - BIF_TRAP_CODE_PTR_0(BIF_P, on_load); } BIF_RETTYPE finish_after_on_load_2(BIF_ALIST_2) { ErtsCodeIndex code_ix; - Module* modp = erts_get_module(BIF_ARG_1); + Module* modp; Eterm on_load; code_ix = erts_active_code_ix(); + modp = erts_get_module(BIF_ARG_1, code_ix); if (!modp || modp->curr.code == 0) { error: @@ -439,6 +469,8 @@ check_process_code(Process* rp, Module* modp) #define INSIDE(a) (start <= (a) && (a) < end) + ERTS_SMP_LC_ASSERT(erts_is_old_code_rlocked()); + /* * Pick up limits for the module. */ @@ -645,50 +677,62 @@ any_heap_refs(Eterm* start, Eterm* end, char* mod_start, Uint mod_size) static int purge_module(int module) { + ErtsCodeIndex code_ix; BeamInstr* code; BeamInstr* end; Module* modp; + int ret; + + erts_lock_code_ix(); + code_ix = erts_active_code_ix(); /* * Correct module? */ - if ((modp = erts_get_module(make_atom(module))) == NULL) { - return -2; + if ((modp = erts_get_module(make_atom(module), code_ix)) == NULL) { + ret = -2; } + else { + erts_rwlock_old_code(code_ix); - /* - * Any code to purge? - */ - if (modp->old.code == 0) { - return -1; - } + /* + * Any code to purge? + */ + if (modp->old.code == 0) { + ret = -1; + } + else { + /* + * Unload any NIF library + */ + if (modp->old.nif != NULL) { + erts_unload_nif(modp->old.nif); + modp->old.nif = NULL; + } - /* - * Unload any NIF library - */ - if (modp->old.nif != NULL) { - erts_unload_nif(modp->old.nif); - modp->old.nif = NULL; + /* + * Remove the old code. + */ + ASSERT(erts_total_code_size >= modp->old.code_length); + erts_total_code_size -= modp->old.code_length; + code = modp->old.code; + end = (BeamInstr *)((char *)code + modp->old.code_length); + erts_cleanup_funs_on_purge(code, end); + beam_catches_delmod(modp->old.catches, code, modp->old.code_length, + code_ix); + decrement_refc(code); + erts_free(ERTS_ALC_T_CODE, (void *) code); + modp->old.code = NULL; + modp->old.code_length = 0; + modp->old.catches = BEAM_CATCHES_NIL; + remove_from_address_table(code); + ret = 0; + } + erts_rwunlock_old_code(code_ix); } - - /* - * Remove the old code. - */ - ASSERT(erts_total_code_size >= modp->old.code_length); - erts_total_code_size -= modp->old.code_length; - code = modp->old.code; - end = (BeamInstr *)((char *)code + modp->old.code_length); - erts_cleanup_funs_on_purge(code, end); - beam_catches_delmod(modp->old.catches, code, modp->old.code_length, - erts_active_code_ix()); - decrement_refc(code); - erts_free(ERTS_ALC_T_CODE, (void *) code); - modp->old.code = NULL; - modp->old.code_length = 0; - modp->old.catches = BEAM_CATCHES_NIL; - remove_from_address_table(code); - return 0; + erts_unlock_code_ix(); + return ret; } static void diff --git a/erts/emulator/beam/beam_bp.c b/erts/emulator/beam/beam_bp.c index 872907e232..30c458244b 100644 --- a/erts/emulator/beam/beam_bp.c +++ b/erts/emulator/beam/beam_bp.c @@ -478,7 +478,7 @@ erts_find_local_func(Eterm mfa[3]) { BeamInstr* code_ptr; Uint i,n; - if ((modp = erts_get_module(mfa[0])) == NULL) + if ((modp = erts_get_module(mfa[0], erts_active_code_ix())) == NULL) return NULL; if ((code_base = (BeamInstr **) modp->curr.code) == NULL) return NULL; @@ -850,12 +850,13 @@ static int set_break(Eterm mfa[3], int specified, { Module *modp; int num_processed = 0; + ErtsCodeIndex code_ix = erts_active_code_ix(); if (!specified) { /* Find and process all modules in the system... */ int current; - int last = module_code_size(); + int last = module_code_size(code_ix); for (current = 0; current < last; current++) { - modp = module_code(current); + modp = module_code(current, code_ix); ASSERT(modp != NULL); num_processed += set_module_break(modp, mfa, specified, @@ -864,7 +865,7 @@ static int set_break(Eterm mfa[3], int specified, } } else { /* Process a single module */ - if ((modp = erts_get_module(mfa[0])) != NULL) { + if ((modp = erts_get_module(mfa[0], code_ix)) != NULL) { num_processed += set_module_break(modp, mfa, specified, match_spec, break_op, count_op, @@ -1105,22 +1106,23 @@ static int set_function_break(Module *modp, BeamInstr *pc, int bif, static int clear_break(Eterm mfa[3], int specified, BeamInstr break_op) { + ErtsCodeIndex code_ix = erts_active_code_ix(); int num_processed = 0; Module *modp; if (!specified) { /* Iterate over all modules */ int current; - int last = module_code_size(); + int last = module_code_size(code_ix); for (current = 0; current < last; current++) { - modp = module_code(current); + modp = module_code(current, code_ix); ASSERT(modp != NULL); num_processed += clear_module_break(modp, mfa, specified, break_op); } } else { /* Process a single module */ - if ((modp = erts_get_module(mfa[0])) != NULL) { + if ((modp = erts_get_module(mfa[0], code_ix)) != NULL) { num_processed += clear_module_break(modp, mfa, specified, break_op); } diff --git a/erts/emulator/beam/beam_debug.c b/erts/emulator/beam/beam_debug.c index 608303cf4b..d9e9d0e348 100644 --- a/erts/emulator/beam/beam_debug.c +++ b/erts/emulator/beam/beam_debug.c @@ -226,13 +226,13 @@ erts_debug_disassemble_1(BIF_ALIST_1) goto error; } arity = signed_val(tp[3]); - modp = erts_get_module(mod); + code_ix = erts_active_code_ix(); + modp = erts_get_module(mod, code_ix); /* * Try the export entry first to allow disassembly of special functions * such as erts_debug:apply/4. Then search for it in the module. */ - code_ix = erts_active_code_ix(); if ((ep = erts_find_function(mod, name, arity, code_ix)) != NULL) { /* XXX: add "&& ep->address != ep->code+3" condition? * Consider a traced function. diff --git a/erts/emulator/beam/beam_emu.c b/erts/emulator/beam/beam_emu.c index 4bb4885cbb..d6189c6c65 100644 --- a/erts/emulator/beam/beam_emu.c +++ b/erts/emulator/beam/beam_emu.c @@ -6127,9 +6127,9 @@ call_fun(Process* p, /* Current process. */ * representation (the module has never been loaded), * or the module defining the fun has been unloaded. */ - module = fe->module; - if ((modp = erts_get_module(module)) != NULL && modp->curr.code != NULL) { + if ((modp = erts_get_module(module, code_ix)) != NULL + && modp->curr.code != NULL) { /* * There is a module loaded, but obviously the fun is not * defined in it. We must not call the error_handler diff --git a/erts/emulator/beam/beam_load.c b/erts/emulator/beam/beam_load.c index c35841af9d..fc3e395e91 100644 --- a/erts/emulator/beam/beam_load.c +++ b/erts/emulator/beam/beam_load.c @@ -5027,7 +5027,7 @@ erts_module_info_0(Process* p, Eterm module) return THE_NON_VALUE; } - if (erts_get_module(module) == NULL) { + if (erts_get_module(module, erts_active_code_ix()) == NULL) { return THE_NON_VALUE; } @@ -5091,7 +5091,7 @@ functions_in_module(Process* p, /* Process whose heap to use. */ return THE_NON_VALUE; } - modp = erts_get_module(mod); + modp = erts_get_module(mod, erts_active_code_ix()); if (modp == NULL) { return THE_NON_VALUE; } @@ -5145,7 +5145,7 @@ native_addresses(Process* p, Eterm mod) return THE_NON_VALUE; } - modp = erts_get_module(mod); + modp = erts_get_module(mod, erts_active_code_ix()); if (modp == NULL) { return THE_NON_VALUE; } @@ -5247,7 +5247,7 @@ attributes_for_module(Process* p, /* Process whose heap to use. */ return THE_NON_VALUE; } - modp = erts_get_module(mod); + modp = erts_get_module(mod, erts_active_code_ix()); if (modp == NULL) { return THE_NON_VALUE; } @@ -5287,7 +5287,7 @@ compilation_info_for_module(Process* p, /* Process whose heap to use. */ return THE_NON_VALUE; } - modp = erts_get_module(mod); + modp = erts_get_module(mod, erts_active_code_ix()); if (modp == NULL) { return THE_NON_VALUE; } @@ -6147,6 +6147,7 @@ void erts_start_loader_code_ix(void) { beam_catches_start_load(); export_start_load(); + module_start_load(); /*SVERK and more to come I guess... : */ @@ -6158,8 +6159,10 @@ void erts_commit_loader_code_ix(void) { beam_catches_end_load(1); export_end_load(1); + module_end_load(1); { - ErtsCodeIndex ix = erts_loader_code_ix(); + ErtsCodeIndex ix; + ix = erts_loader_code_ix(); erts_smp_atomic32_set_nob(&the_active_code_index, ix); ix = (ix + 1) % ERTS_NUM_CODE_IX; erts_smp_atomic32_set_nob(&the_loader_code_index, ix); @@ -6171,20 +6174,21 @@ void erts_abort_loader_code_ix(void) { beam_catches_end_load(0); export_end_load(0); + module_end_load(0); CIX_TRACE("abort"); } /*SVERK old_code lock should maybe be part of module.c */ -void erts_rwlock_old_code(void) +void erts_rwlock_old_code(ErtsCodeIndex code_ix) { } -void erts_rwunlock_old_code(void) +void erts_rwunlock_old_code(ErtsCodeIndex code_ix) { } -void erts_rlock_old_code(void) +void erts_rlock_old_code(ErtsCodeIndex code_ix) { } -void erts_runlock_old_code(void) +void erts_runlock_old_code(ErtsCodeIndex code_ix) { } diff --git a/erts/emulator/beam/break.c b/erts/emulator/beam/break.c index d769957210..39f91be7fc 100644 --- a/erts/emulator/beam/break.c +++ b/erts/emulator/beam/break.c @@ -377,17 +377,22 @@ loaded(int to, void *to_arg) int old = 0; int cur = 0; BeamInstr* code; + Module* modp; + ErtsCodeIndex code_ix; + + code_ix = erts_active_code_ix(); + erts_rlock_old_code(code_ix); /* * Calculate and print totals. */ - for (i = 0; i < module_code_size(); i++) { - if (module_code(i) != NULL && - ((module_code(i)->curr.code_length != 0) || - (module_code(i)->old.code_length != 0))) { - cur += module_code(i)->curr.code_length; - if (module_code(i)->old.code_length != 0) { - old += module_code(i)->old.code_length; + for (i = 0; i < module_code_size(code_ix); i++) { + if ((modp = module_code(i, code_ix)) != NULL && + ((modp->curr.code_length != 0) || + (modp->old.code_length != 0))) { + cur += modp->curr.code_length; + if (modp->old.code_length != 0) { + old += modp->old.code_length; } } } @@ -398,21 +403,22 @@ loaded(int to, void *to_arg) * Print one line per module. */ - for (i = 0; i < module_code_size(); i++) { + for (i = 0; i < module_code_size(code_ix); i++) { + modp = module_code(i, code_ix); if (!ERTS_IS_CRASH_DUMPING) { /* * Interactive dump; keep it brief. */ - if (module_code(i) != NULL && - ((module_code(i)->curr.code_length != 0) || - (module_code(i)->old.code_length != 0))) { - erts_print(to, to_arg, "%T", make_atom(module_code(i)->module)); - cur += module_code(i)->curr.code_length; - erts_print(to, to_arg, " %d", module_code(i)->curr.code_length ); - if (module_code(i)->old.code_length != 0) { + if (modp != NULL && + ((modp->curr.code_length != 0) || + (modp->old.code_length != 0))) { + erts_print(to, to_arg, "%T", make_atom(modp->module)); + cur += modp->curr.code_length; + erts_print(to, to_arg, " %d", modp->curr.code_length ); + if (modp->old.code_length != 0) { erts_print(to, to_arg, " (%d old)", - module_code(i)->old.code_length ); - old += module_code(i)->old.code_length; + modp->old.code_length ); + old += modp->old.code_length; } erts_print(to, to_arg, "\n"); } @@ -420,15 +426,15 @@ loaded(int to, void *to_arg) /* * To crash dump; make it parseable. */ - if (module_code(i) != NULL && - ((module_code(i)->curr.code_length != 0) || - (module_code(i)->old.code_length != 0))) { + if (modp != NULL && + ((modp->curr.code_length != 0) || + (modp->old.code_length != 0))) { erts_print(to, to_arg, "=mod:"); - erts_print(to, to_arg, "%T", make_atom(module_code(i)->module)); + erts_print(to, to_arg, "%T", make_atom(modp->module)); erts_print(to, to_arg, "\n"); erts_print(to, to_arg, "Current size: %d\n", - module_code(i)->curr.code_length); - code = module_code(i)->curr.code; + modp->curr.code_length); + code = modp->curr.code; if (code != NULL && code[MI_ATTR_PTR]) { erts_print(to, to_arg, "Current attributes: "); dump_attributes(to, to_arg, (byte *) code[MI_ATTR_PTR], @@ -440,9 +446,9 @@ loaded(int to, void *to_arg) code[MI_COMPILE_SIZE]); } - if (module_code(i)->old.code_length != 0) { - erts_print(to, to_arg, "Old size: %d\n", module_code(i)->old.code_length); - code = module_code(i)->old.code; + if (modp->old.code_length != 0) { + erts_print(to, to_arg, "Old size: %d\n", modp->old.code_length); + code = modp->old.code; if (code[MI_ATTR_PTR]) { erts_print(to, to_arg, "Old attributes: "); dump_attributes(to, to_arg, (byte *) code[MI_ATTR_PTR], @@ -457,6 +463,7 @@ loaded(int to, void *to_arg) } } } + erts_runlock_old_code(code_ix); } diff --git a/erts/emulator/beam/code_ix.h b/erts/emulator/beam/code_ix.h index 6b81102269..585ddd3f20 100644 --- a/erts/emulator/beam/code_ix.h +++ b/erts/emulator/beam/code_ix.h @@ -52,10 +52,10 @@ void erts_start_loader_code_ix(void); void erts_commit_loader_code_ix(void); void erts_abort_loader_code_ix(void); -void erts_rwlock_old_code(void); -void erts_rwunlock_old_code(void); -void erts_rlock_old_code(void); -void erts_runlock_old_code(void); +void erts_rwlock_old_code(ErtsCodeIndex); +void erts_rwunlock_old_code(ErtsCodeIndex); +void erts_rlock_old_code(ErtsCodeIndex); +void erts_runlock_old_code(ErtsCodeIndex); #ifdef ERTS_ENABLE_LOCK_CHECK int erts_is_old_code_rlocked(void); diff --git a/erts/emulator/beam/erl_nif.c b/erts/emulator/beam/erl_nif.c index f6082c09f2..8e8b58a7ad 100644 --- a/erts/emulator/beam/erl_nif.c +++ b/erts/emulator/beam/erl_nif.c @@ -1534,7 +1534,7 @@ BIF_RETTYPE load_nif_2(BIF_ALIST_2) ASSERT(caller != NULL); mod_atom = caller[0]; ASSERT(is_atom(mod_atom)); - mod=erts_get_module(mod_atom); + mod=erts_get_module(mod_atom, erts_active_code_ix()); ASSERT(mod != NULL); if (!in_area(caller, mod->curr.code, mod->curr.code_length)) { diff --git a/erts/emulator/beam/export.c b/erts/emulator/beam/export.c index 51d0116110..e5d9da187a 100644 --- a/erts/emulator/beam/export.c +++ b/erts/emulator/beam/export.c @@ -254,10 +254,6 @@ erts_find_function(Eterm m, Eterm f, unsigned int a, ErtsCodeIndex code_ix) struct export_templ templ; struct export_entry* ee; - if (ERTS_IS_ATOM_STR("gen_event",m) && ERTS_IS_ATOM_STR("add_handler",f)) { - sverk_break(); - } - ee = hash_get(&export_tables[code_ix].htable, init_template(&templ, m, f, a)); if (ee == NULL || (ee->ep->addressv[code_ix] == ee->ep->code+3 && ee->ep->code[3] != (BeamInstr) em_call_traced_function)) { diff --git a/erts/emulator/beam/index.c b/erts/emulator/beam/index.c index a4a3007f93..7cd45440f4 100644 --- a/erts/emulator/beam/index.c +++ b/erts/emulator/beam/index.c @@ -135,3 +135,18 @@ void erts_index_merge(Hash* src, IndexTable* dst) } } } + +void index_erase_latest_from(IndexTable* t, Uint from_ix) +{ + if(from_ix < (Uint)t->entries) { + int ix; + for (ix = from_ix; ix < t->entries; ix++) { + IndexSlot* obj = t->seg_table[ix>>INDEX_PAGE_SHIFT][ix&INDEX_PAGE_MASK]; + hash_erase(&t->htable, obj); + } + t->entries = from_ix; + } + else { + ASSERT(from_ix == t->entries); + } +} diff --git a/erts/emulator/beam/index.h b/erts/emulator/beam/index.h index 4eb9b1f992..67b250590b 100644 --- a/erts/emulator/beam/index.h +++ b/erts/emulator/beam/index.h @@ -58,6 +58,8 @@ int index_get(IndexTable*, void*); int index_put(IndexTable*, void*); void erts_index_merge(Hash*, IndexTable*); +void index_erase_latest_from(IndexTable*, Uint ix); + ERTS_GLB_INLINE IndexSlot* erts_index_lookup(IndexTable*, Uint); #if ERTS_GLB_INLINE_INCL_FUNC_DEF diff --git a/erts/emulator/beam/module.c b/erts/emulator/beam/module.c index 39baabdf54..1c629cd614 100644 --- a/erts/emulator/beam/module.c +++ b/erts/emulator/beam/module.c @@ -26,10 +26,16 @@ #include "global.h" #include "module.h" +#ifdef DEBUG +# define IF_DEBUG(x) x +#else +# define IF_DEBUG(x) +#endif + #define MODULE_SIZE 50 #define MODULE_LIMIT (64*1024) -static IndexTable module_table; +static IndexTable module_tables[ERTS_NUM_CODE_IX]; /* * SMP note: We don't need to look accesses to the module table because @@ -40,7 +46,7 @@ static IndexTable module_table; void module_info(int to, void *to_arg) { - index_info(to, to_arg, &module_table); + index_info(to, to_arg, &module_tables[erts_active_code_ix()]); } @@ -71,33 +77,44 @@ static Module* module_alloc(Module* tmpl) return obj; } +static void module_free(Module* mod) +{ + erts_free(ERTS_ALC_T_MODULE, mod); +} void init_module_table(void) { HashFunctions f; + int i; f.hash = (H_FUN) module_hash; f.cmp = (HCMP_FUN) module_cmp; f.alloc = (HALLOC_FUN) module_alloc; - f.free = 0; + f.free = (HFREE_FUN) module_free; - erts_index_init(ERTS_ALC_T_MODULE_TABLE, &module_table, "module_code", - MODULE_SIZE, MODULE_LIMIT, f); + for (i = 0; i < ERTS_NUM_CODE_IX; i++) { + erts_index_init(ERTS_ALC_T_MODULE_TABLE, &module_tables[i], "module_code", + MODULE_SIZE, MODULE_LIMIT, f); + } } Module* -erts_get_module(Eterm mod) +erts_get_module(Eterm mod, ErtsCodeIndex code_ix) { Module e; int index; + IndexTable* mod_tab; ASSERT(is_atom(mod)); + + mod_tab = &module_tables[code_ix]; + e.module = atom_val(mod); - index = index_get(&module_table, (void*) &e); + index = index_get(mod_tab, (void*) &e); if (index == -1) { return NULL; } else { - return (Module*) erts_index_lookup(&module_table, index); + return (Module*) erts_index_lookup(mod_tab, index); } } @@ -106,26 +123,88 @@ erts_put_module(Eterm mod) { Module e; int index; + IndexTable* mod_tab; ASSERT(is_atom(mod)); ERTS_SMP_LC_ASSERT(erts_initialized == 0 || erts_smp_thr_progress_is_blocking()); + + mod_tab = &module_tables[erts_loader_code_ix()]; e.module = atom_val(mod); - index = index_put(&module_table, (void*) &e); - return (Module*) erts_index_lookup(&module_table, index); + index = index_put(mod_tab, (void*) &e); + return (Module*) erts_index_lookup(mod_tab, index); } -Module *module_code(int i) +Module *module_code(int i, ErtsCodeIndex code_ix) { - return (Module*) erts_index_lookup(&module_table, i); + return (Module*) erts_index_lookup(&module_tables[code_ix], i); } -int module_code_size(void) +int module_code_size(ErtsCodeIndex code_ix) { - return module_table.entries; + return module_tables[code_ix].entries; } int module_table_sz(void) { - return index_table_sz(&module_table); + return index_table_sz(&module_tables[erts_active_code_ix()]); +} + +#ifdef DEBUG +static ErtsCodeIndex dbg_load_code_ix = 0; +#endif + +static int entries_at_start_load = 0; + +void module_start_load(void) +{ + IndexTable* src = &module_tables[erts_active_code_ix()]; + IndexTable* dst = &module_tables[erts_loader_code_ix()]; + Module* src_mod; + Module* dst_mod; + int i; + + ASSERT(dbg_load_code_ix == -1); + ASSERT(dst->entries <= src->entries); + + /* + * Make sure our existing modules are up-to-date + */ + for (i = 0; i < dst->entries; i++) { + src_mod = (Module*) erts_index_lookup(src, i); + dst_mod = (Module*) erts_index_lookup(dst, i); + ASSERT(src_mod->module == dst_mod->module); + + dst_mod->curr = src_mod->curr; + dst_mod->old = src_mod->old; + } + + /* + * Copy all new modules from active table + */ + for (i = dst->entries; i < src->entries; i++) { + src_mod = (Module*) erts_index_lookup(src, i); + dst_mod = (Module*) erts_index_lookup(dst, index_put(dst, src_mod)); + ASSERT(dst_mod != src_mod); + + dst_mod->curr = src_mod->curr; + dst_mod->old = src_mod->old; + } + entries_at_start_load = dst->entries; + + IF_DEBUG(dbg_load_code_ix = erts_loader_code_ix()); +} + +void module_end_load(int commit) +{ + ASSERT(dbg_load_code_ix == erts_loader_code_ix()); + + if (!commit) { /* abort */ + IndexTable* tab = &module_tables[erts_loader_code_ix()]; + + ASSERT(entries_at_start_load <= tab->entries); + index_erase_latest_from(tab, entries_at_start_load); + } + + IF_DEBUG(dbg_load_code_ix = -1); } diff --git a/erts/emulator/beam/module.h b/erts/emulator/beam/module.h index 4a2c92c0f7..8a87ae4952 100644 --- a/erts/emulator/beam/module.h +++ b/erts/emulator/beam/module.h @@ -39,14 +39,16 @@ typedef struct erl_module { struct erl_module_instance old; } Module; -Module* erts_get_module(Eterm mod); +Module* erts_get_module(Eterm mod, ErtsCodeIndex code_ix); Module* erts_put_module(Eterm mod); void init_module_table(void); +void module_start_load(void); +void module_end_load(int commit); void module_info(int, void *); -Module *module_code(int); -int module_code_size(void); +Module *module_code(int, ErtsCodeIndex); +int module_code_size(ErtsCodeIndex); int module_table_sz(void); #endif diff --git a/erts/emulator/hipe/hipe_bif0.c b/erts/emulator/hipe/hipe_bif0.c index 4afc2030e7..cb599bd682 100644 --- a/erts/emulator/hipe/hipe_bif0.c +++ b/erts/emulator/hipe/hipe_bif0.c @@ -609,7 +609,7 @@ static Uint *hipe_find_emu_address(Eterm mod, Eterm name, unsigned int arity) Uint *code_base; int i, n; - modp = erts_get_module(mod); + modp = erts_get_module(mod, erts_active_code_ix()); /*SVERK ?? */ if (modp == NULL || (code_base = modp->curr.code) == NULL) return NULL; n = code_base[MI_NUM_FUNCTIONS]; -- cgit v1.2.3 From c9d4422cb4f54363096d4efb6d667071450fa50b Mon Sep 17 00:00:00 2001 From: Sverker Eriksson Date: Thu, 19 Jan 2012 12:12:30 +0100 Subject: erts: Fix code_ix handling and locking for some more bifs --- erts/emulator/beam/beam_bif_load.c | 31 ++++++++++++++++++++++++++++++- 1 file changed, 30 insertions(+), 1 deletion(-) diff --git a/erts/emulator/beam/beam_bif_load.c b/erts/emulator/beam/beam_bif_load.c index 458e4794bd..7b17790d3a 100644 --- a/erts/emulator/beam/beam_bif_load.c +++ b/erts/emulator/beam/beam_bif_load.c @@ -86,6 +86,7 @@ load_module_2(BIF_ALIST_2) erts_smp_proc_unlock(BIF_P, ERTS_PROC_LOCK_MAIN); erts_smp_thr_progress_block(); + erts_lock_code_ix(); erts_start_loader_code_ix(); reason = erts_finish_loading(stp, BIF_P, 0, &BIF_ARG_1); @@ -103,6 +104,8 @@ load_module_2(BIF_ALIST_2) res = TUPLE2(hp, am_module, BIF_ARG_1); } + erts_unlock_code_ix(); + erts_smp_thr_progress_unblock(); erts_smp_proc_lock(BIF_P, ERTS_PROC_LOCK_MAIN); BIF_RET(res); @@ -160,8 +163,20 @@ BIF_RETTYPE code_make_stub_module_3(BIF_ALIST_3) erts_smp_thr_progress_block(); erts_export_consolidate(erts_active_code_ix()); + + erts_lock_code_ix(); + erts_start_loader_code_ix(); + res = erts_make_stub_module(BIF_P, BIF_ARG_1, BIF_ARG_2, BIF_ARG_3); + if (res == BIF_ARG_1) { + erts_commit_loader_code_ix(); + } + else { + erts_abort_loader_code_ix(); + } + erts_unlock_code_ix(); + erts_smp_thr_progress_unblock(); erts_smp_proc_lock(BIF_P, ERTS_PROC_LOCK_MAIN); return res; @@ -259,7 +274,9 @@ BIF_RETTYPE delete_module_1(BIF_ALIST_1) erts_smp_proc_unlock(BIF_P, ERTS_PROC_LOCK_MAIN); erts_smp_thr_progress_block(); - code_ix = erts_active_code_ix(); + erts_lock_code_ix(); + erts_start_loader_code_ix(); + code_ix = erts_loader_code_ix(); { Module *modp = erts_get_module(BIF_ARG_1, code_ix); if (!modp) { @@ -279,6 +296,14 @@ BIF_RETTYPE delete_module_1(BIF_ALIST_1) } } + if (res == am_true) { + erts_commit_loader_code_ix(); + } + else { + erts_abort_loader_code_ix(); + } + erts_unlock_code_ix(); + erts_smp_thr_progress_unblock(); erts_smp_proc_lock(BIF_P, ERTS_PROC_LOCK_MAIN); @@ -368,6 +393,7 @@ BIF_RETTYPE finish_after_on_load_2(BIF_ALIST_2) ErtsCodeIndex code_ix; Module* modp; Eterm on_load; + code_ix = erts_active_code_ix(); modp = erts_get_module(BIF_ARG_1, code_ix); @@ -385,6 +411,8 @@ BIF_RETTYPE finish_after_on_load_2(BIF_ALIST_2) erts_smp_proc_unlock(BIF_P, ERTS_PROC_LOCK_MAIN); erts_smp_thr_progress_block(); + /*SVERK What if code_ix is not active any more */ + if (BIF_ARG_2 == am_true) { int i; @@ -828,6 +856,7 @@ delete_export_references(Eterm module) continue; } ep->addressv[code_ix] = ep->code+3; + ASSERT(ep->code[3] != (BeamInstr) em_call_traced_function); /*SVERK What to do now? */ ep->code[3] = (BeamInstr) em_call_error_handler; ep->code[4] = 0; MatchSetUnref(ep->match_prog_set); -- cgit v1.2.3 From b45686b4bc9b8bf07190d6b13b2e9a8167c61184 Mon Sep 17 00:00:00 2001 From: Sverker Eriksson Date: Thu, 19 Jan 2012 14:53:26 +0100 Subject: erts: Add abort logic to export tables --- erts/emulator/beam/export.c | 15 ++++++++++----- erts/emulator/beam/index.h | 2 ++ 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/erts/emulator/beam/export.c b/erts/emulator/beam/export.c index e5d9da187a..c74a40b0db 100644 --- a/erts/emulator/beam/export.c +++ b/erts/emulator/beam/export.c @@ -141,13 +141,11 @@ export_alloc(struct export_entry* tmpl_e) return &blob->entryv[blob->top_ix]; } -/*SVERK static void export_free(struct export_entry* obj) { erts_free(ERTS_ALC_T_EXPORT, (void*) obj); } -*/ void init_export_table(void) @@ -163,7 +161,7 @@ init_export_table(void) f.hash = (H_FUN) export_hash; f.cmp = (HCMP_FUN) export_cmp; f.alloc = (HALLOC_FUN) export_alloc; - f.free = (HFREE_FUN) NULL; /*SVERK export_free;*/ + f.free = (HFREE_FUN) export_free; for (i=0; ihtable.fun.alloc = (HALLOC_FUN) &export_alloc; /* restore */ - /*SVERK Remember dst->entries in order to purge on abort */ + entries_at_start_load = dst->entries; IF_DEBUG(debug_start_load_ix = dst_ix); } @@ -449,7 +449,12 @@ void export_end_load(int commit) { ASSERT(debug_start_load_ix == erts_loader_code_ix()); - /*SVERK Purge if abort */ + if (!commit) { /* abort */ + IndexTable* tab = &export_tables[erts_loader_code_ix()]; + + ASSERT(entries_at_start_load <= tab->entries); + index_erase_latest_from(tab, entries_at_start_load); + } IF_DEBUG(debug_start_load_ix = -1); } diff --git a/erts/emulator/beam/index.h b/erts/emulator/beam/index.h index 67b250590b..69d1cc0a22 100644 --- a/erts/emulator/beam/index.h +++ b/erts/emulator/beam/index.h @@ -58,6 +58,8 @@ int index_get(IndexTable*, void*); int index_put(IndexTable*, void*); void erts_index_merge(Hash*, IndexTable*); +/* Erase all entries with index 'ix' and higher +*/ void index_erase_latest_from(IndexTable*, Uint ix); ERTS_GLB_INLINE IndexSlot* erts_index_lookup(IndexTable*, Uint); -- cgit v1.2.3 From f3b2fc3db73e76323bff1a7f233a8914464b29aa Mon Sep 17 00:00:00 2001 From: Sverker Eriksson Date: Thu, 19 Jan 2012 16:56:26 +0100 Subject: erts: Remove unused erts_put_fun_entry2 declaration --- erts/emulator/beam/erl_fun.h | 2 -- 1 file changed, 2 deletions(-) diff --git a/erts/emulator/beam/erl_fun.h b/erts/emulator/beam/erl_fun.h index 2f165afa06..6023fa0448 100644 --- a/erts/emulator/beam/erl_fun.h +++ b/erts/emulator/beam/erl_fun.h @@ -79,8 +79,6 @@ ErlFunEntry* erts_get_fun_entry(Eterm mod, int uniq, int index); ErlFunEntry* erts_put_fun_entry2(Eterm mod, int old_uniq, int old_index, byte* uniq, int index, int arity); -ErlFunEntry* erts_get_fun_entry2(Eterm mod, int old_uniq, int old_index, - byte* uniq, int index, int arity); void erts_erase_fun_entry(ErlFunEntry* fe); #ifndef HYBRID /* FIND ME! */ -- cgit v1.2.3 From dab78e34dac11579cda578ffc6cf9293394456e4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20Gustavsson?= Date: Wed, 18 Jan 2012 16:44:48 +0100 Subject: BEAM loader: Break out handling of ranges into beam_ranges.c Having the entire implementation of range handling (address table) in one source file will help when we'll need to update the ranges without stopping all schedulers in the next commit. --- erts/emulator/Makefile.in | 3 +- erts/emulator/beam/beam_bif_load.c | 24 +---- erts/emulator/beam/beam_load.c | 167 +----------------------------- erts/emulator/beam/beam_load.h | 27 ++++- erts/emulator/beam/beam_ranges.c | 205 +++++++++++++++++++++++++++++++++++++ erts/emulator/beam/erl_alloc.c | 4 +- erts/emulator/beam/global.h | 8 +- 7 files changed, 243 insertions(+), 195 deletions(-) create mode 100644 erts/emulator/beam/beam_ranges.c diff --git a/erts/emulator/Makefile.in b/erts/emulator/Makefile.in index 2bd7297231..dad09383cf 100644 --- a/erts/emulator/Makefile.in +++ b/erts/emulator/Makefile.in @@ -704,7 +704,8 @@ EMU_OBJS = \ $(OBJDIR)/beam_emu.o $(OBJDIR)/beam_opcodes.o \ $(OBJDIR)/beam_load.o $(OBJDIR)/beam_bif_load.o \ $(OBJDIR)/beam_debug.o $(OBJDIR)/beam_bp.o \ - $(OBJDIR)/beam_catches.o + $(OBJDIR)/beam_catches.o \ + $(OBJDIR)/beam_ranges.o RUN_OBJS = \ $(OBJDIR)/erl_pbifs.o $(OBJDIR)/benchmark.o \ diff --git a/erts/emulator/beam/beam_bif_load.c b/erts/emulator/beam/beam_bif_load.c index 7b17790d3a..8fe11746ee 100644 --- a/erts/emulator/beam/beam_bif_load.c +++ b/erts/emulator/beam/beam_bif_load.c @@ -44,7 +44,6 @@ static void decrement_refc(BeamInstr* code); static int is_native(BeamInstr* code); static int any_heap_ref_ptrs(Eterm* start, Eterm* end, char* mod_start, Uint mod_size); static int any_heap_refs(Eterm* start, Eterm* end, char* mod_start, Uint mod_size); -static void remove_from_address_table(BeamInstr* code); Eterm load_module_2(BIF_ALIST_2) @@ -449,7 +448,7 @@ BIF_RETTYPE finish_after_on_load_2(BIF_ALIST_2) modp->curr.code = NULL; modp->curr.code_length = 0; modp->curr.catches = BEAM_CATCHES_NIL; - remove_from_address_table(code); + erts_remove_from_ranges(code); } erts_smp_thr_progress_unblock(); erts_smp_proc_lock(BIF_P, ERTS_PROC_LOCK_MAIN); @@ -754,7 +753,7 @@ purge_module(int module) modp->old.code = NULL; modp->old.code_length = 0; modp->old.catches = BEAM_CATCHES_NIL; - remove_from_address_table(code); + erts_remove_from_ranges(code); ret = 0; } erts_rwunlock_old_code(code_ix); @@ -780,25 +779,6 @@ decrement_refc(BeamInstr* code) } } -static void -remove_from_address_table(BeamInstr* code) -{ - int i; - - for (i = 0; i < num_loaded_modules; i++) { - if (modules[i].start == code) { - num_loaded_modules--; - while (i < num_loaded_modules) { - modules[i] = modules[i+1]; - i++; - } - mid_module = &modules[num_loaded_modules/2]; - return; - } - } - ASSERT(0); /* Not found? */ -} - /* * Move code from current to old. diff --git a/erts/emulator/beam/beam_load.c b/erts/emulator/beam/beam_load.c index fc3e395e91..873b94d175 100644 --- a/erts/emulator/beam/beam_load.c +++ b/erts/emulator/beam/beam_load.c @@ -352,27 +352,6 @@ typedef struct LoaderState { int loc_size; /* Size of location info in bytes (2/4) */ } LoaderState; -/* - * Layout of the line table. - */ - -#define MI_LINE_FNAME_PTR 0 -#define MI_LINE_LOC_TAB 1 -#define MI_LINE_LOC_SIZE 2 -#define MI_LINE_FUNC_TAB 3 - -#define LINE_INVALID_LOCATION (0) - -/* - * Macros for manipulating locations. - */ - -#define IS_VALID_LOCATION(File, Line) \ - ((unsigned) (File) < 255 && (unsigned) (Line) < ((1 << 24) - 1)) -#define MAKE_LOCATION(File, Line) (((File) << 24) | (Line)) -#define LOC_FILE(Loc) ((Loc) >> 24) -#define LOC_LINE(Loc) ((Loc) & ((1 << 24)-1)) - #define GetTagAndValue(Stp, Tag, Val) \ do { \ BeamInstr __w; \ @@ -549,22 +528,9 @@ static Eterm native_addresses(Process* p, Eterm mod); int patch_funentries(Eterm Patchlist); int patch(Eterm Addresses, Uint fe); static int safe_mul(UWord a, UWord b, UWord* resp); -static void lookup_loc(FunctionInfo* fi, BeamInstr* pc, - BeamInstr* modp, int idx); - static int must_swap_floats; -/* - * The following variables keep a sorted list of address ranges for - * each module. It allows us to quickly find a function given an - * instruction pointer. - */ -Range* modules = NULL; /* Sorted lists of module addresses. */ -int num_loaded_modules; /* Number of loaded modules. */ -int allocated_modules; /* Number of slots allocated. */ -Range* mid_module = NULL; /* Cached search start point */ - Uint erts_total_code_size; /**********************************************************************/ @@ -580,11 +546,7 @@ void init_load(void) f.fd = 1.0; must_swap_floats = (f.fw[0] == 0); - allocated_modules = 128; - modules = (Range *) erts_alloc(ERTS_ALC_T_MODULE_REFS, - allocated_modules*sizeof(Range)); - mid_module = modules; - num_loaded_modules = 0; + erts_init_ranges(); } static void @@ -955,7 +917,6 @@ insert_new_code(Process *c_p, ErtsProcLocks c_p_locks, { Module* modp; Eterm retval; - int i; if ((retval = beam_make_current_old(c_p, c_p_locks, module)) != NIL) { erts_dsprintf_buf_t *dsbufp = erts_create_logger_dsbuf(); @@ -977,25 +938,10 @@ insert_new_code(Process *c_p, ErtsProcLocks c_p_locks, modp->curr.catches = BEAM_CATCHES_NIL; /* Will be filled in later. */ /* - * Update address table (used for finding a function from a PC value). + * Update ranges (used for finding a function from a PC value). */ - if (num_loaded_modules == allocated_modules) { - allocated_modules *= 2; - modules = (Range *) erts_realloc(ERTS_ALC_T_MODULE_REFS, - (void *) modules, - allocated_modules * sizeof(Range)); - } - for (i = num_loaded_modules; i > 0; i--) { - if (code > modules[i-1].start) { - break; - } - modules[i] = modules[i-1]; - } - modules[i].start = code; - modules[i].end = (BeamInstr *) (((byte *)code) + size); - num_loaded_modules++; - mid_module = &modules[num_loaded_modules/2]; + erts_update_ranges(code, size); return NIL; } @@ -5305,113 +5251,6 @@ compilation_info_for_module(Process* p, /* Process whose heap to use. */ return result; } -/* - * Find a function from the given pc and fill information in - * the FunctionInfo struct. If the full_info is non-zero, fill - * in all available information (including location in the - * source code). If no function is found, the 'current' field - * will be set to NULL. - */ - -void -erts_lookup_function_info(FunctionInfo* fi, BeamInstr* pc, int full_info) -{ - Range* low = modules; - Range* high = low + num_loaded_modules; - Range* mid = mid_module; - - fi->current = NULL; - fi->needed = 5; - fi->loc = LINE_INVALID_LOCATION; - while (low < high) { - if (pc < mid->start) { - high = mid; - } else if (pc > mid->end) { - low = mid + 1; - } else { - BeamInstr** low1 = (BeamInstr **) (mid->start + MI_FUNCTIONS); - BeamInstr** high1 = low1 + mid->start[MI_NUM_FUNCTIONS]; - BeamInstr** mid1; - - while (low1 < high1) { - mid1 = low1 + (high1-low1) / 2; - if (pc < mid1[0]) { - high1 = mid1; - } else if (pc < mid1[1]) { - mid_module = mid; - fi->current = mid1[0]+2; - if (full_info) { - BeamInstr** fp = (BeamInstr **) (mid->start + - MI_FUNCTIONS); - int idx = mid1 - fp; - lookup_loc(fi, pc, mid->start, idx); - } - return; - } else { - low1 = mid1 + 1; - } - } - return; - } - mid = low + (high-low) / 2; - } -} - -static void -lookup_loc(FunctionInfo* fi, BeamInstr* orig_pc, BeamInstr* modp, int idx) -{ - Eterm* line = (Eterm *) modp[MI_LINE_TABLE]; - Eterm* low; - Eterm* high; - Eterm* mid; - Eterm pc; - - if (line == 0) { - return; - } - - pc = (Eterm) (BeamInstr) orig_pc; - fi->fname_ptr = (Eterm *) (BeamInstr) line[MI_LINE_FNAME_PTR]; - low = (Eterm *) (BeamInstr) line[MI_LINE_FUNC_TAB+idx]; - high = (Eterm *) (BeamInstr) line[MI_LINE_FUNC_TAB+idx+1]; - while (high > low) { - mid = low + (high-low) / 2; - if (pc < mid[0]) { - high = mid; - } else if (pc < mid[1]) { - int file; - int index = mid - (Eterm *) (BeamInstr) line[MI_LINE_FUNC_TAB]; - - if (line[MI_LINE_LOC_SIZE] == 2) { - Uint16* loc_table = - (Uint16 *) (BeamInstr) line[MI_LINE_LOC_TAB]; - fi->loc = loc_table[index]; - } else { - Uint32* loc_table = - (Uint32 *) (BeamInstr) line[MI_LINE_LOC_TAB]; - ASSERT(line[MI_LINE_LOC_SIZE] == 4); - fi->loc = loc_table[index]; - } - if (fi->loc == LINE_INVALID_LOCATION) { - return; - } - fi->needed += 3+2+3+2; - file = LOC_FILE(fi->loc); - if (file == 0) { - /* Special case: Module name with ".erl" appended */ - Atom* mod_atom = atom_tab(atom_val(fi->current[0])); - fi->needed += 2*(mod_atom->len+4); - } else { - Atom* ap = atom_tab(atom_val((fi->fname_ptr)[file-1])); - fi->needed += 2*ap->len; - } - return; - } else { - low = mid + 1; - } - } -} - /* * Build a single {M,F,A,Loction} item to be part of * a stack trace. diff --git a/erts/emulator/beam/beam_load.h b/erts/emulator/beam/beam_load.h index 997ba197db..9da692625b 100644 --- a/erts/emulator/beam/beam_load.h +++ b/erts/emulator/beam/beam_load.h @@ -61,11 +61,6 @@ typedef struct { * instruction pointer. */ -extern Range* modules; -extern int num_loaded_modules; -extern int allocated_modules; -extern Range* mid_module; - /* Total code size in bytes */ extern Uint erts_total_code_size; /* @@ -126,4 +121,26 @@ extern Uint erts_total_code_size; */ #define MI_FUNCTIONS 13 + +/* + * Layout of the line table. + */ + +#define MI_LINE_FNAME_PTR 0 +#define MI_LINE_LOC_TAB 1 +#define MI_LINE_LOC_SIZE 2 +#define MI_LINE_FUNC_TAB 3 + +#define LINE_INVALID_LOCATION (0) + +/* + * Macros for manipulating locations. + */ + +#define IS_VALID_LOCATION(File, Line) \ + ((unsigned) (File) < 255 && (unsigned) (Line) < ((1 << 24) - 1)) +#define MAKE_LOCATION(File, Line) (((File) << 24) | (Line)) +#define LOC_FILE(Loc) ((Loc) >> 24) +#define LOC_LINE(Loc) ((Loc) & ((1 << 24)-1)) + #endif /* _BEAM_LOAD_H */ diff --git a/erts/emulator/beam/beam_ranges.c b/erts/emulator/beam/beam_ranges.c new file mode 100644 index 0000000000..063b319f7a --- /dev/null +++ b/erts/emulator/beam/beam_ranges.c @@ -0,0 +1,205 @@ +/* + * %CopyrightBegin% + * + * Copyright Ericsson AB 2012. All Rights Reserved. + * + * The contents of this file are subject to the Erlang Public License, + * Version 1.1, (the "License"); you may not use this file except in + * compliance with the License. You should have received a copy of the + * Erlang Public License along with this software. If not, it can be + * retrieved online at http://www.erlang.org/. + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and limitations + * under the License. + * + * %CopyrightEnd% + */ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include "sys.h" +#include "erl_vm.h" +#include "global.h" +#include "beam_load.h" + +static void lookup_loc(FunctionInfo* fi, BeamInstr* pc, + BeamInstr* modp, int idx); + +/* + * The following variables keep a sorted list of address ranges for + * each module. It allows us to quickly find a function given an + * instruction pointer. + */ +static Range* modules = NULL; /* Sorted lists of module addresses. */ +static int num_loaded_modules; /* Number of loaded modules. */ +static int allocated_modules; /* Number of slots allocated. */ +static Range* mid_module = NULL; /* Cached search start point */ + +void +erts_init_ranges(void) +{ + allocated_modules = 128; + modules = (Range *) erts_alloc(ERTS_ALC_T_MODULE_REFS, + allocated_modules*sizeof(Range)); + mid_module = modules; + num_loaded_modules = 0; +} + +void +erts_update_ranges(BeamInstr* code, Uint size) +{ + int i; + + if (num_loaded_modules == allocated_modules) { + allocated_modules *= 2; + modules = (Range *) erts_realloc(ERTS_ALC_T_MODULE_REFS, + (void *) modules, + allocated_modules * sizeof(Range)); + } + for (i = num_loaded_modules; i > 0; i--) { + if (code > modules[i-1].start) { + break; + } + modules[i] = modules[i-1]; + } + modules[i].start = code; + modules[i].end = (BeamInstr *) (((byte *)code) + size); + num_loaded_modules++; + mid_module = &modules[num_loaded_modules/2]; +} + +void +erts_remove_from_ranges(BeamInstr* code) +{ + int i; + + for (i = 0; i < num_loaded_modules; i++) { + if (modules[i].start == code) { + num_loaded_modules--; + while (i < num_loaded_modules) { + modules[i] = modules[i+1]; + i++; + } + mid_module = &modules[num_loaded_modules/2]; + return; + } + } + ASSERT(0); /* Not found? */ +} + +Uint +erts_ranges_sz(void) +{ + return allocated_modules*sizeof(Range); +} + +/* + * Find a function from the given pc and fill information in + * the FunctionInfo struct. If the full_info is non-zero, fill + * in all available information (including location in the + * source code). If no function is found, the 'current' field + * will be set to NULL. + */ + +void +erts_lookup_function_info(FunctionInfo* fi, BeamInstr* pc, int full_info) +{ + Range* low = modules; + Range* high = low + num_loaded_modules; + Range* mid = mid_module; + + fi->current = NULL; + fi->needed = 5; + fi->loc = LINE_INVALID_LOCATION; + while (low < high) { + if (pc < mid->start) { + high = mid; + } else if (pc > mid->end) { + low = mid + 1; + } else { + BeamInstr** low1 = (BeamInstr **) (mid->start + MI_FUNCTIONS); + BeamInstr** high1 = low1 + mid->start[MI_NUM_FUNCTIONS]; + BeamInstr** mid1; + + while (low1 < high1) { + mid1 = low1 + (high1-low1) / 2; + if (pc < mid1[0]) { + high1 = mid1; + } else if (pc < mid1[1]) { + mid_module = mid; + fi->current = mid1[0]+2; + if (full_info) { + BeamInstr** fp = (BeamInstr **) (mid->start + + MI_FUNCTIONS); + int idx = mid1 - fp; + lookup_loc(fi, pc, mid->start, idx); + } + return; + } else { + low1 = mid1 + 1; + } + } + return; + } + mid = low + (high-low) / 2; + } +} + +static void +lookup_loc(FunctionInfo* fi, BeamInstr* orig_pc, BeamInstr* modp, int idx) +{ + Eterm* line = (Eterm *) modp[MI_LINE_TABLE]; + Eterm* low; + Eterm* high; + Eterm* mid; + Eterm pc; + + if (line == 0) { + return; + } + + pc = (Eterm) (BeamInstr) orig_pc; + fi->fname_ptr = (Eterm *) (BeamInstr) line[MI_LINE_FNAME_PTR]; + low = (Eterm *) (BeamInstr) line[MI_LINE_FUNC_TAB+idx]; + high = (Eterm *) (BeamInstr) line[MI_LINE_FUNC_TAB+idx+1]; + while (high > low) { + mid = low + (high-low) / 2; + if (pc < mid[0]) { + high = mid; + } else if (pc < mid[1]) { + int file; + int index = mid - (Eterm *) (BeamInstr) line[MI_LINE_FUNC_TAB]; + + if (line[MI_LINE_LOC_SIZE] == 2) { + Uint16* loc_table = + (Uint16 *) (BeamInstr) line[MI_LINE_LOC_TAB]; + fi->loc = loc_table[index]; + } else { + Uint32* loc_table = + (Uint32 *) (BeamInstr) line[MI_LINE_LOC_TAB]; + ASSERT(line[MI_LINE_LOC_SIZE] == 4); + fi->loc = loc_table[index]; + } + if (fi->loc == LINE_INVALID_LOCATION) { + return; + } + fi->needed += 3+2+3+2; + file = LOC_FILE(fi->loc); + if (file == 0) { + /* Special case: Module name with ".erl" appended */ + Atom* mod_atom = atom_tab(atom_val(fi->current[0])); + fi->needed += 2*(mod_atom->len+4); + } else { + Atom* ap = atom_tab(atom_val((fi->fname_ptr)[file-1])); + fi->needed += 2*ap->len; + } + return; + } else { + low = mid + 1; + } + } +} diff --git a/erts/emulator/beam/erl_alloc.c b/erts/emulator/beam/erl_alloc.c index 07a2539367..bf7c53bf1a 100644 --- a/erts/emulator/beam/erl_alloc.c +++ b/erts/emulator/beam/erl_alloc.c @@ -2187,7 +2187,7 @@ erts_memory(int *print_to_p, void *print_to_arg, void *proc, Eterm earg) size.code += export_table_sz(); size.code += export_list_size(erts_active_code_ix()) * sizeof(Export); size.code += erts_fun_table_sz(); - size.code += allocated_modules*sizeof(Range); + size.code += erts_ranges_sz(); size.code += erts_total_code_size; } @@ -2350,7 +2350,7 @@ erts_allocated_areas(int *print_to_p, void *print_to_arg, void *proc) values[i].arity = 2; values[i].name = "module_refs"; - values[i].ui[0] = allocated_modules*sizeof(Range); + values[i].ui[0] = erts_ranges_sz(); i++; values[i].arity = 2; diff --git a/erts/emulator/beam/global.h b/erts/emulator/beam/global.h index 4ce6ed5280..05517ac9e8 100644 --- a/erts/emulator/beam/global.h +++ b/erts/emulator/beam/global.h @@ -884,12 +884,18 @@ void init_load(void); BeamInstr* find_function_from_pc(BeamInstr* pc); Eterm* erts_build_mfa_item(FunctionInfo* fi, Eterm* hp, Eterm args, Eterm* mfa_p); -void erts_lookup_function_info(FunctionInfo* fi, BeamInstr* pc, int full_info); void erts_set_current_function(FunctionInfo* fi, BeamInstr* current); Eterm erts_module_info_0(Process* p, Eterm module); Eterm erts_module_info_1(Process* p, Eterm module, Eterm what); Eterm erts_make_stub_module(Process* p, Eterm Mod, Eterm Beam, Eterm Info); +/* beam_ranges.c */ +void erts_init_ranges(void); +void erts_update_ranges(BeamInstr* code, Uint size); +void erts_remove_from_ranges(BeamInstr* code); +Uint erts_ranges_sz(void); +void erts_lookup_function_info(FunctionInfo* fi, BeamInstr* pc, int full_info); + /* break.c */ void init_break_handler(void); void erts_set_ignore_break(void); -- cgit v1.2.3 From f81dd5da827e86af3bf6fedadeaaeb5fb3347c32 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20Gustavsson?= Date: Thu, 19 Jan 2012 11:00:01 +0100 Subject: beam_ranges: Make ranges safe with multi-scheduling active --- erts/emulator/beam/beam_load.c | 6 +- erts/emulator/beam/beam_ranges.c | 253 +++++++++++++++++++++++++++++---------- erts/emulator/beam/global.h | 4 +- 3 files changed, 195 insertions(+), 68 deletions(-) diff --git a/erts/emulator/beam/beam_load.c b/erts/emulator/beam/beam_load.c index 873b94d175..6cabc6f558 100644 --- a/erts/emulator/beam/beam_load.c +++ b/erts/emulator/beam/beam_load.c @@ -5987,9 +5987,7 @@ void erts_start_loader_code_ix(void) beam_catches_start_load(); export_start_load(); module_start_load(); - /*SVERK and more to come I guess... - : - */ + erts_start_load_ranges(); CIX_TRACE("start"); } @@ -5999,6 +5997,7 @@ void erts_commit_loader_code_ix(void) beam_catches_end_load(1); export_end_load(1); module_end_load(1); + erts_end_load_ranges(1); { ErtsCodeIndex ix; ix = erts_loader_code_ix(); @@ -6014,6 +6013,7 @@ void erts_abort_loader_code_ix(void) beam_catches_end_load(0); export_end_load(0); module_end_load(0); + erts_end_load_ranges(0); CIX_TRACE("abort"); } diff --git a/erts/emulator/beam/beam_ranges.c b/erts/emulator/beam/beam_ranges.c index 063b319f7a..ae701ea0c9 100644 --- a/erts/emulator/beam/beam_ranges.c +++ b/erts/emulator/beam/beam_ranges.c @@ -26,6 +26,7 @@ #include "global.h" #include "beam_load.h" +static Range* find_range(BeamInstr* pc); static void lookup_loc(FunctionInfo* fi, BeamInstr* pc, BeamInstr* modp, int idx); @@ -34,67 +35,175 @@ static void lookup_loc(FunctionInfo* fi, BeamInstr* pc, * each module. It allows us to quickly find a function given an * instruction pointer. */ -static Range* modules = NULL; /* Sorted lists of module addresses. */ -static int num_loaded_modules; /* Number of loaded modules. */ -static int allocated_modules; /* Number of slots allocated. */ -static Range* mid_module = NULL; /* Cached search start point */ +struct ranges { + Range* modules; /* Sorted lists of module addresses. */ + Sint n; /* Number of range entries. */ + Sint allocated; /* Number of allocated entries. */ + erts_smp_atomic_t mid; /* Cached search start point */ +}; +static struct ranges r[ERTS_NUM_CODE_IX]; +static erts_smp_atomic_t mem_used; + +#ifdef HARD_DEBUG +static void check_consistency(struct ranges* p) +{ + int i; + + ASSERT(p->n <= p->allocated); + ASSERT((Uint)(p->mid - p->modules) < p->n || + (p->mid == p->modules && p->n == 0)); + for (i = 0; i < p->n; i++) { + ASSERT(p->modules[i].start <= p->modules[i].end); + ASSERT(!i || p->modules[i-1].end < p->modules[i].start); + } +} +# define CHECK(r) check_consistency(r) +#else +# define CHECK(r) +#endif /* HARD_DEBUG */ + void erts_init_ranges(void) { - allocated_modules = 128; - modules = (Range *) erts_alloc(ERTS_ALC_T_MODULE_REFS, - allocated_modules*sizeof(Range)); - mid_module = modules; - num_loaded_modules = 0; + Sint i; + + erts_smp_atomic_init_nob(&mem_used, 0); + for (i = 0; i < ERTS_NUM_CODE_IX; i++) { + r[i].modules = 0; + r[i].n = 0; + r[i].allocated = 0; + erts_smp_atomic_init_nob(&r[i].mid, 0); + } } void -erts_update_ranges(BeamInstr* code, Uint size) +erts_start_load_ranges(void) { - int i; + ErtsCodeIndex dst = erts_loader_code_ix(); - if (num_loaded_modules == allocated_modules) { - allocated_modules *= 2; - modules = (Range *) erts_realloc(ERTS_ALC_T_MODULE_REFS, - (void *) modules, - allocated_modules * sizeof(Range)); + if (r[dst].modules) { + erts_smp_atomic_add_nob(&mem_used, -r[dst].allocated); + erts_free(ERTS_ALC_T_MODULE_REFS, r[dst].modules); + r[dst].modules = NULL; } - for (i = num_loaded_modules; i > 0; i--) { - if (code > modules[i-1].start) { - break; +} + +void +erts_end_load_ranges(int commit) +{ + ErtsCodeIndex dst = erts_loader_code_ix(); + + if (commit && r[dst].modules == NULL) { + Sint i; + Sint n; + + /* No modules added, just clone src and remove purged code. */ + ErtsCodeIndex src = erts_active_code_ix(); + + erts_smp_atomic_add_nob(&mem_used, r[src].n); + r[dst].modules = erts_alloc(ERTS_ALC_T_MODULE_REFS, + r[src].n * sizeof(Range)); + r[dst].allocated = r[src].n; + n = 0; + for (i = 0; i < r[src].n; i++) { + Range* rp = r[src].modules+i; + if (rp->start < rp->end) { + /* Only insert a module that has not been purged. */ + r[dst].modules[n] = *rp; + n++; + } } - modules[i] = modules[i-1]; + r[dst].n = n; + erts_smp_atomic_set_nob(&r[dst].mid, + (erts_aint_t) (r[dst].modules + n / 2)); } - modules[i].start = code; - modules[i].end = (BeamInstr *) (((byte *)code) + size); - num_loaded_modules++; - mid_module = &modules[num_loaded_modules/2]; } void -erts_remove_from_ranges(BeamInstr* code) +erts_update_ranges(BeamInstr* code, Uint size) { - int i; + ErtsCodeIndex dst = erts_loader_code_ix(); + ErtsCodeIndex src = erts_active_code_ix(); + Sint i; + Sint n; + Sint need; - for (i = 0; i < num_loaded_modules; i++) { - if (modules[i].start == code) { - num_loaded_modules--; - while (i < num_loaded_modules) { - modules[i] = modules[i+1]; - i++; - } - mid_module = &modules[num_loaded_modules/2]; - return; + if (src == dst) { + ASSERT(!erts_initialized); + + /* + * During start-up of system, the indices are the same. + * Handle this by faking a source area. + */ + src = (src+1) % ERTS_NUM_CODE_IX; + if (r[src].modules) { + erts_smp_atomic_add_nob(&mem_used, -r[src].allocated); + erts_free(ERTS_ALC_T_MODULE_REFS, r[src].modules); + } + r[src] = r[dst]; + r[dst].modules = 0; + } + + CHECK(&r[src]); + + ASSERT(r[dst].modules == NULL); + need = r[dst].allocated = r[src].n + 1; + erts_smp_atomic_add_nob(&mem_used, need); + r[dst].modules = (Range *) erts_alloc(ERTS_ALC_T_MODULE_REFS, + need * sizeof(Range)); + n = 0; + for (i = 0; i < r[src].n; i++) { + Range* rp = r[src].modules+i; + if (code < rp->start) { + r[dst].modules[n].start = code; + r[dst].modules[n].end = (BeamInstr *) (((byte *)code) + size); + n++; + break; + } + if (rp->start < rp->end) { + /* Only insert a module that has not been purged. */ + r[dst].modules[n] = *rp; + n++; } } - ASSERT(0); /* Not found? */ + + while (i < r[src].n) { + Range* rp = r[src].modules+i; + if (rp->start < rp->end) { + /* Only insert a module that has not been purged. */ + r[dst].modules[n] = *rp; + n++; + } + i++; + } + + if (n == 0 || code > r[dst].modules[n-1].start) { + r[dst].modules[n].start = code; + r[dst].modules[n].end = (BeamInstr *) (((byte *)code) + size); + n++; + } + + ASSERT(n <= r[src].n+1); + r[dst].n = n; + erts_smp_atomic_set_nob(&r[dst].mid, + (erts_aint_t) (r[dst].modules + n / 2)); + + CHECK(&r[dst]); + CHECK(&r[src]); +} + +void +erts_remove_from_ranges(BeamInstr* code) +{ + Range* rp = find_range(code); + rp->end = rp->start; } -Uint +UWord erts_ranges_sz(void) { - return allocated_modules*sizeof(Range); + return erts_smp_atomic_read_nob(&mem_used) * sizeof(Range); } /* @@ -108,45 +217,61 @@ erts_ranges_sz(void) void erts_lookup_function_info(FunctionInfo* fi, BeamInstr* pc, int full_info) { - Range* low = modules; - Range* high = low + num_loaded_modules; - Range* mid = mid_module; + BeamInstr** low; + BeamInstr** high; + BeamInstr** mid; + Range* rp; fi->current = NULL; fi->needed = 5; fi->loc = LINE_INVALID_LOCATION; + rp = find_range(pc); + if (rp == 0) { + return; + } + + low = (BeamInstr **) (rp->start + MI_FUNCTIONS); + high = low + rp->start[MI_NUM_FUNCTIONS]; + while (low < high) { + mid = low + (high-low) / 2; + if (pc < mid[0]) { + high = mid; + } else if (pc < mid[1]) { + fi->current = mid[0]+2; + if (full_info) { + BeamInstr** fp = (BeamInstr **) (rp->start + + MI_FUNCTIONS); + int idx = mid - fp; + lookup_loc(fi, pc, rp->start, idx); + } + return; + } else { + low = mid + 1; + } + } +} + +static Range* +find_range(BeamInstr* pc) +{ + ErtsCodeIndex active = erts_active_code_ix(); + Range* low = r[active].modules; + Range* high = low + r[active].n; + Range* mid = (Range *) erts_smp_atomic_read_nob(&r[active].mid); + + CHECK(&r[active]); while (low < high) { if (pc < mid->start) { high = mid; } else if (pc > mid->end) { low = mid + 1; } else { - BeamInstr** low1 = (BeamInstr **) (mid->start + MI_FUNCTIONS); - BeamInstr** high1 = low1 + mid->start[MI_NUM_FUNCTIONS]; - BeamInstr** mid1; - - while (low1 < high1) { - mid1 = low1 + (high1-low1) / 2; - if (pc < mid1[0]) { - high1 = mid1; - } else if (pc < mid1[1]) { - mid_module = mid; - fi->current = mid1[0]+2; - if (full_info) { - BeamInstr** fp = (BeamInstr **) (mid->start + - MI_FUNCTIONS); - int idx = mid1 - fp; - lookup_loc(fi, pc, mid->start, idx); - } - return; - } else { - low1 = mid1 + 1; - } - } - return; + erts_smp_atomic_set_nob(&r[active].mid, (erts_aint_t) mid); + return mid; } mid = low + (high-low) / 2; } + return 0; } static void diff --git a/erts/emulator/beam/global.h b/erts/emulator/beam/global.h index 05517ac9e8..e6ff9d8577 100644 --- a/erts/emulator/beam/global.h +++ b/erts/emulator/beam/global.h @@ -891,9 +891,11 @@ Eterm erts_make_stub_module(Process* p, Eterm Mod, Eterm Beam, Eterm Info); /* beam_ranges.c */ void erts_init_ranges(void); +void erts_start_load_ranges(void); +void erts_end_load_ranges(int commit); void erts_update_ranges(BeamInstr* code, Uint size); void erts_remove_from_ranges(BeamInstr* code); -Uint erts_ranges_sz(void); +UWord erts_ranges_sz(void); void erts_lookup_function_info(FunctionInfo* fi, BeamInstr* pc, int full_info); /* break.c */ -- cgit v1.2.3 From dd3036c1a152c66a33b4d298cbbf428c075153b7 Mon Sep 17 00:00:00 2001 From: Sverker Eriksson Date: Thu, 19 Jan 2012 21:16:29 +0100 Subject: First try at non-blocking code loading! Implemented some code_ix locks and commented calls to erts_smp_thr_progress_block() --- erts/emulator/beam/beam_bif_load.c | 73 ++++++++++++++++++++++--------------- erts/emulator/beam/beam_load.c | 33 +++++++++++++---- erts/emulator/beam/code_ix.h | 3 +- erts/emulator/beam/erl_lock_check.c | 2 + erts/emulator/beam/module.c | 1 + 5 files changed, 75 insertions(+), 37 deletions(-) diff --git a/erts/emulator/beam/beam_bif_load.c b/erts/emulator/beam/beam_bif_load.c index 8fe11746ee..f21598a8b7 100644 --- a/erts/emulator/beam/beam_bif_load.c +++ b/erts/emulator/beam/beam_bif_load.c @@ -79,11 +79,11 @@ load_module_2(BIF_ALIST_2) BIF_RET(res); } - /* + /*SVERK * Stop all other processes and finish the loading of the module. - */ + * erts_smp_proc_unlock(BIF_P, ERTS_PROC_LOCK_MAIN); - erts_smp_thr_progress_block(); + erts_smp_thr_progress_block();*/ erts_lock_code_ix(); erts_start_loader_code_ix(); @@ -105,8 +105,9 @@ load_module_2(BIF_ALIST_2) erts_unlock_code_ix(); + /*SVERK erts_smp_thr_progress_unblock(); - erts_smp_proc_lock(BIF_P, ERTS_PROC_LOCK_MAIN); + erts_smp_proc_lock(BIF_P, ERTS_PROC_LOCK_MAIN);*/ BIF_RET(res); } @@ -118,14 +119,17 @@ BIF_RETTYPE purge_module_1(BIF_ALIST_1) BIF_ERROR(BIF_P, BADARG); } + /*SVERK erts_smp_proc_unlock(BIF_P, ERTS_PROC_LOCK_MAIN); erts_smp_thr_progress_block(); - erts_export_consolidate(erts_active_code_ix()); + erts_export_consolidate(erts_active_code_ix());*/ + purge_res = purge_module(atom_val(BIF_ARG_1)); + /*SVERK erts_smp_thr_progress_unblock(); - erts_smp_proc_lock(BIF_P, ERTS_PROC_LOCK_MAIN); + erts_smp_proc_lock(BIF_P, ERTS_PROC_LOCK_MAIN);*/ if (purge_res < 0) { BIF_ERROR(BIF_P, BADARG); @@ -158,14 +162,17 @@ BIF_RETTYPE code_make_stub_module_3(BIF_ALIST_3) { Eterm res; + /*SVERK erts_smp_proc_unlock(BIF_P, ERTS_PROC_LOCK_MAIN); erts_smp_thr_progress_block(); - erts_export_consolidate(erts_active_code_ix()); + erts_export_consolidate(erts_active_code_ix());*/ erts_lock_code_ix(); erts_start_loader_code_ix(); + erts_export_consolidate(erts_loader_code_ix()); + res = erts_make_stub_module(BIF_P, BIF_ARG_1, BIF_ARG_2, BIF_ARG_3); if (res == BIF_ARG_1) { @@ -176,8 +183,9 @@ BIF_RETTYPE code_make_stub_module_3(BIF_ALIST_3) } erts_unlock_code_ix(); + /*SVERK erts_smp_thr_progress_unblock(); - erts_smp_proc_lock(BIF_P, ERTS_PROC_LOCK_MAIN); + erts_smp_proc_lock(BIF_P, ERTS_PROC_LOCK_MAIN);*/ return res; } @@ -221,13 +229,13 @@ check_process_code_2(BIF_ALIST_2) modp = erts_get_module(BIF_ARG_2, code_ix); if (modp == NULL) { /* Doesn't exist. */ return am_false; - } else { - erts_rlock_old_code(code_ix); - if (modp->old.code == NULL) { /* No old code. */ - erts_runlock_old_code(code_ix); - return am_false; - } } + erts_rlock_old_code(code_ix); + if (modp->old.code == NULL) { /* No old code. */ + erts_runlock_old_code(code_ix); + return am_false; + } + erts_runlock_old_code(code_ix); #ifdef ERTS_SMP rp = erts_pid2proc_suspend(BIF_P, ERTS_PROC_LOCK_MAIN, @@ -242,7 +250,13 @@ check_process_code_2(BIF_ALIST_2) ERTS_BIF_YIELD2(bif_export[BIF_check_process_code_2], BIF_P, BIF_ARG_1, BIF_ARG_2); } - res = check_process_code(rp, modp); + erts_rlock_old_code(code_ix); + if (modp->old.code != NULL) { /* must check again */ + res = check_process_code(rp, modp); + } + else { + res = am_false; + } erts_runlock_old_code(code_ix); #ifdef ERTS_SMP if (BIF_P != rp) { @@ -270,12 +284,14 @@ BIF_RETTYPE delete_module_1(BIF_ALIST_1) if (is_not_atom(BIF_ARG_1)) goto badarg; + /*SVERK erts_smp_proc_unlock(BIF_P, ERTS_PROC_LOCK_MAIN); - erts_smp_thr_progress_block(); + erts_smp_thr_progress_block();*/ erts_lock_code_ix(); erts_start_loader_code_ix(); code_ix = erts_loader_code_ix(); + erts_export_consolidate(code_ix); { Module *modp = erts_get_module(BIF_ARG_1, code_ix); if (!modp) { @@ -303,8 +319,9 @@ BIF_RETTYPE delete_module_1(BIF_ALIST_1) } erts_unlock_code_ix(); + /*SVERK erts_smp_thr_progress_unblock(); - erts_smp_proc_lock(BIF_P, ERTS_PROC_LOCK_MAIN); + erts_smp_proc_lock(BIF_P, ERTS_PROC_LOCK_MAIN);*/ if (res == am_badarg) { badarg: @@ -410,7 +427,7 @@ BIF_RETTYPE finish_after_on_load_2(BIF_ALIST_2) erts_smp_proc_unlock(BIF_P, ERTS_PROC_LOCK_MAIN); erts_smp_thr_progress_block(); - /*SVERK What if code_ix is not active any more */ + /*SVERK Use code_ix switch instead */ if (BIF_ARG_2 == am_true) { int i; @@ -496,8 +513,6 @@ check_process_code(Process* rp, Module* modp) #define INSIDE(a) (start <= (a) && (a) < end) - ERTS_SMP_LC_ASSERT(erts_is_old_code_rlocked()); - /* * Pick up limits for the module. */ @@ -787,19 +802,19 @@ decrement_refc(BeamInstr* code) static void delete_code(Process *c_p, ErtsProcLocks c_p_locks, Module* modp) { -#ifdef ERTS_ENABLE_LOCK_CHECK -#ifdef ERTS_SMP - if (c_p && c_p_locks) - erts_proc_lc_chk_only_proc_main(c_p); - else -#endif - erts_lc_check_exact(NULL, 0); -#endif - /* * Clear breakpoints if any */ if (modp->curr.code != NULL && modp->curr.code[MI_NUM_BREAKPOINTS] > 0) { + ASSERT(!"SVERK What to do here"); +#ifdef ERTS_ENABLE_LOCK_CHECK +#ifdef ERTS_SMP + if (c_p && c_p_locks) + erts_proc_lc_chk_only_proc_main(c_p); + else +#endif + erts_lc_check_exact(NULL, 0); +#endif if (c_p && c_p_locks) erts_smp_proc_unlock(c_p, ERTS_PROC_LOCK_MAIN); erts_smp_thr_progress_block(); diff --git a/erts/emulator/beam/beam_load.c b/erts/emulator/beam/beam_load.c index 6cabc6f558..eaaef472b4 100644 --- a/erts/emulator/beam/beam_load.c +++ b/erts/emulator/beam/beam_load.c @@ -753,7 +753,7 @@ erts_finish_loading(LoaderState* stp, Process* c_p, * table which is not protected by any locks. */ - ERTS_SMP_LC_ASSERT(erts_initialized == 0 || + ERTS_SMP_LC_ASSERT(erts_initialized == 0 || erts_is_code_ix_locked() || erts_smp_thr_progress_is_blocking()); /* @@ -5949,6 +5949,9 @@ static int safe_mul(UWord a, UWord b, UWord* resp) static erts_smp_atomic32_t the_active_code_index; static erts_smp_atomic32_t the_loader_code_index; +static erts_smp_mtx_t sverk_code_ix_lock; /*SVERK FIXME */ +static erts_smp_rwmtx_t the_old_code_rwlocks[ERTS_NUM_CODE_IX]; + #ifdef DEBUG # define CIX_TRACE(text) erts_fprintf(stderr, "CIX_TRACE: " text " act=%u load=%u\r\n", erts_active_code_ix(), erts_loader_code_ix()) #else @@ -5957,8 +5960,14 @@ static erts_smp_atomic32_t the_loader_code_index; void erts_code_ix_init(void) { + int i; + erts_smp_atomic32_init_nob(&the_active_code_index, 0); erts_smp_atomic32_init_nob(&the_loader_code_index, 0); + erts_smp_mtx_init_x(&sverk_code_ix_lock, "sverk_code_ix_lock", NIL); /*SVERK FIXME */ + for (i=0; i Date: Fri, 20 Jan 2012 17:39:14 +0100 Subject: erts: Call erts_export_consolidate automatically Renamed merge_secondary_table and called by export_start_load --- erts/emulator/beam/beam_bif_load.c | 3 --- erts/emulator/beam/beam_load.c | 1 - erts/emulator/beam/export.c | 38 ++++++++++++++++---------------------- erts/emulator/beam/export.h | 1 - 4 files changed, 16 insertions(+), 27 deletions(-) diff --git a/erts/emulator/beam/beam_bif_load.c b/erts/emulator/beam/beam_bif_load.c index f21598a8b7..7c09ef7083 100644 --- a/erts/emulator/beam/beam_bif_load.c +++ b/erts/emulator/beam/beam_bif_load.c @@ -171,8 +171,6 @@ BIF_RETTYPE code_make_stub_module_3(BIF_ALIST_3) erts_lock_code_ix(); erts_start_loader_code_ix(); - erts_export_consolidate(erts_loader_code_ix()); - res = erts_make_stub_module(BIF_P, BIF_ARG_1, BIF_ARG_2, BIF_ARG_3); if (res == BIF_ARG_1) { @@ -291,7 +289,6 @@ BIF_RETTYPE delete_module_1(BIF_ALIST_1) erts_lock_code_ix(); erts_start_loader_code_ix(); code_ix = erts_loader_code_ix(); - erts_export_consolidate(code_ix); { Module *modp = erts_get_module(BIF_ARG_1, code_ix); if (!modp) { diff --git a/erts/emulator/beam/beam_load.c b/erts/emulator/beam/beam_load.c index eaaef472b4..e2a3914bf7 100644 --- a/erts/emulator/beam/beam_load.c +++ b/erts/emulator/beam/beam_load.c @@ -774,7 +774,6 @@ erts_finish_loading(LoaderState* stp, Process* c_p, * exported and imported functions. This can't fail. */ - erts_export_consolidate(erts_loader_code_ix()); CHKBLK(ERTS_ALC_T_CODE,stp->code); final_touch(stp); diff --git a/erts/emulator/beam/export.c b/erts/emulator/beam/export.c index c74a40b0db..eb76ec8fd4 100644 --- a/erts/emulator/beam/export.c +++ b/erts/emulator/beam/export.c @@ -292,7 +292,7 @@ erts_export_put(Eterm mod, Eterm func, unsigned int arity) * be called). * * Stub export entries will be placed in the secondary export table. - * erts_export_consolidate() will move all stub export entries into the + * export_start_load() will move all stub export entries into the * main export table (will be done the next time code is loaded). */ @@ -322,33 +322,25 @@ erts_export_get_or_make_stub(Eterm mod, Eterm func, unsigned int arity) } /* - * To be called before loading code (with other threads blocked). - * This function will move all export entries from the secondary - * export table into the primary. + * Move all export entries from the secondary export table into the primary. */ -void -erts_export_consolidate(ErtsCodeIndex code_ix) +static void merge_secondary_table(IndexTable* dst) { -#ifdef DEBUG - HashInfo hi; -#endif - - /*SVERK: Not sure if this is the way to go. - Maye we should always merge into loader ix, - or can loader table act as secondary_export_table?*/ - - ERTS_SMP_LC_ASSERT((erts_is_code_ix_locked() - && code_ix == erts_loader_code_ix()) - || erts_initialized == 0 - || erts_smp_thr_progress_is_blocking()); + ERTS_SMP_LC_ASSERT(erts_is_code_ix_locked()); + /*SVERK && code_ix == erts_loader_code_ix())); + || erts_initialized == 0 + || erts_smp_thr_progress_is_blocking());*/ export_write_lock(); - erts_index_merge(&secondary_export_table, &export_tables[code_ix]); - erts_hash_merge(&secondary_export_table, &export_tables[code_ix].htable); + erts_index_merge(&secondary_export_table, dst); + erts_hash_merge(&secondary_export_table, &dst->htable); export_write_unlock(); #ifdef DEBUG - hash_get_info(&hi, &export_tables[code_ix].htable); - ASSERT(export_tables[code_ix].entries == hi.objs); + { + HashInfo hi; + hash_get_info(&hi, &dst->htable); + ASSERT(dst->entries == hi.objs); + } #endif } @@ -440,6 +432,8 @@ void export_start_load(void) dst->htable.fun.alloc = (HALLOC_FUN) &export_alloc; /* restore */ + merge_secondary_table(dst); + entries_at_start_load = dst->entries; IF_DEBUG(debug_start_load_ix = dst_ix); diff --git a/erts/emulator/beam/export.h b/erts/emulator/beam/export.h index db27606c49..85628aac0b 100644 --- a/erts/emulator/beam/export.h +++ b/erts/emulator/beam/export.h @@ -67,7 +67,6 @@ Export* erts_export_put(Eterm mod, Eterm func, unsigned int arity); Export* erts_export_get_or_make_stub(Eterm, Eterm, unsigned); -void erts_export_consolidate(ErtsCodeIndex); Export *export_list(int,ErtsCodeIndex); int export_list_size(ErtsCodeIndex); -- cgit v1.2.3 From 28a1a227f8097c5c593149f66a98a1b1cf796e99 Mon Sep 17 00:00:00 2001 From: Sverker Eriksson Date: Fri, 20 Jan 2012 17:42:50 +0100 Subject: erts: Rename erts_load_module to erts_preload_module As it can only be used at initialization for preloading --- erts/emulator/beam/beam_load.c | 3 ++- erts/emulator/beam/erl_init.c | 2 +- erts/emulator/beam/global.h | 4 ++-- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/erts/emulator/beam/beam_load.c b/erts/emulator/beam/beam_load.c index e2a3914bf7..54dc663abe 100644 --- a/erts/emulator/beam/beam_load.c +++ b/erts/emulator/beam/beam_load.c @@ -558,7 +558,7 @@ define_file(LoaderState* stp, char* name, int idx) } Eterm -erts_load_module(Process *c_p, +erts_preload_module(Process *c_p, ErtsProcLocks c_p_locks, Eterm group_leader, /* Group leader or NIL if none. */ Eterm* modp, /* @@ -571,6 +571,7 @@ erts_load_module(Process *c_p, LoaderState* stp = erts_alloc_loader_state(); Eterm retval; + ASSERT(!erts_initialized); retval = erts_prepare_loading(stp, c_p, group_leader, modp, code, size); if (retval != NIL) { diff --git a/erts/emulator/beam/erl_init.c b/erts/emulator/beam/erl_init.c index 54b3c19616..487c444df4 100644 --- a/erts/emulator/beam/erl_init.c +++ b/erts/emulator/beam/erl_init.c @@ -453,7 +453,7 @@ load_preloaded(void) if ((code = sys_preload_begin(&preload_p[i])) == 0) erl_exit(1, "Failed to find preloaded code for module %s\n", name); - res = erts_load_module(NULL, 0, NIL, &module_name, code, length); + res = erts_preload_module(NULL, 0, NIL, &module_name, code, length); sys_preload_end(&preload_p[i]); if (res != NIL) erl_exit(1,"Failed loading preloaded module %s (%T)\n", diff --git a/erts/emulator/beam/global.h b/erts/emulator/beam/global.h index e6ff9d8577..6a3c36824b 100644 --- a/erts/emulator/beam/global.h +++ b/erts/emulator/beam/global.h @@ -878,8 +878,8 @@ Eterm erts_prepare_loading(struct LoaderState*, Process *c_p, byte* code, Uint size); Eterm erts_finish_loading(struct LoaderState* stp, Process* c_p, ErtsProcLocks c_p_locks, Eterm* modp); -Eterm erts_load_module(Process *c_p, ErtsProcLocks c_p_locks, - Eterm group_leader, Eterm* mod, byte* code, Uint size); +Eterm erts_preload_module(Process *c_p, ErtsProcLocks c_p_locks, + Eterm group_leader, Eterm* mod, byte* code, Uint size); void init_load(void); BeamInstr* find_function_from_pc(BeamInstr* pc); Eterm* erts_build_mfa_item(FunctionInfo* fi, Eterm* hp, -- cgit v1.2.3 From 8e75055985dfd1ae3c07c6a551359e2aa600a882 Mon Sep 17 00:00:00 2001 From: Sverker Eriksson Date: Fri, 20 Jan 2012 17:49:49 +0100 Subject: erts: Cleanup in export.c --- erts/emulator/beam/export.c | 21 ++++----------------- 1 file changed, 4 insertions(+), 17 deletions(-) diff --git a/erts/emulator/beam/export.c b/erts/emulator/beam/export.c index eb76ec8fd4..e61cd95566 100644 --- a/erts/emulator/beam/export.c +++ b/erts/emulator/beam/export.c @@ -64,8 +64,10 @@ struct export_entry struct export_blob { Export exp; - unsigned top_ix; /*SVERK atomic? */ + unsigned top_ix; /* highest ix used in entryv */ struct export_entry entryv[ERTS_NUM_CODE_IX]; + /* Note that entryv is not indexed by "code_ix". + */ }; /* Helper struct only used as template @@ -190,10 +192,6 @@ erts_active_export_entry(Eterm m, Eterm f, unsigned int a) return erts_find_export_entry(m, f, a, erts_active_code_ix()); } -static void sverk_break(void) -{ -} - Export* erts_find_export_entry(Eterm m, Eterm f, unsigned int a, ErtsCodeIndex code_ix) @@ -202,10 +200,6 @@ erts_find_export_entry(Eterm m, Eterm f, unsigned int a, int ix; HashBucket* b; - if (ERTS_IS_ATOM_STR("gen_event",m) && ERTS_IS_ATOM_STR("add_handler",f)) { - sverk_break(); - } - ix = hval % export_tables[code_ix].htable.size; b = export_tables[code_ix].htable.bucket[ix]; @@ -276,10 +270,6 @@ erts_export_put(Eterm mod, Eterm func, unsigned int arity) struct export_templ templ; int ix; - if (ERTS_IS_ATOM_STR("gen_event",mod) && ERTS_IS_ATOM_STR("add_handler",func)) { - sverk_break(); - } - ASSERT(is_atom(mod)); ASSERT(is_atom(func)); ix = index_put(&export_tables[code_ix], init_template(&templ, mod, func, arity)); @@ -310,7 +300,7 @@ erts_export_get_or_make_stub(Eterm mod, Eterm func, unsigned int arity) struct export_entry* entry; /* * The code is not loaded (yet). Put the export in the secondary - * export table, to avoid having to lock the main export table. + * export table, to avoid having to lock the active export table. */ export_write_lock(); entry = (struct export_entry *) hash_put(&secondary_export_table, @@ -364,9 +354,6 @@ Export *export_get(Export *e) struct export_entry ee; struct export_entry* entry; - if (ERTS_IS_ATOM_STR("gen_event",e->code[0]) && ERTS_IS_ATOM_STR("add_handler",e->code[1])) { - sverk_break(); - } ee.ep = e; entry = (struct export_entry*)hash_get(&export_tables[erts_active_code_ix()].htable, &ee); return entry ? entry->ep : NULL; -- cgit v1.2.3 From 2a04e25043753d1e9de617e85b27b64781b683cb Mon Sep 17 00:00:00 2001 From: Sverker Eriksson Date: Mon, 23 Jan 2012 11:17:46 +0100 Subject: erts: Fix case of breakpoint when deleting module --- erts/emulator/beam/beam_bif_load.c | 36 ++++++++++++++++++++++++++---------- 1 file changed, 26 insertions(+), 10 deletions(-) diff --git a/erts/emulator/beam/beam_bif_load.c b/erts/emulator/beam/beam_bif_load.c index 7c09ef7083..7a65552d76 100644 --- a/erts/emulator/beam/beam_bif_load.c +++ b/erts/emulator/beam/beam_bif_load.c @@ -37,6 +37,7 @@ static void set_default_trace_pattern(Eterm module, ErtsCodeIndex); static Eterm check_process_code(Process* rp, Module* modp); +static void ensure_no_breakpoints(Process *, ErtsProcLocks, Eterm module); static void delete_code(Process *c_p, ErtsProcLocks c_p_locks, Module* modp); static void delete_export_references(Eterm module); static int purge_module(int module); @@ -85,6 +86,8 @@ load_module_2(BIF_ALIST_2) erts_smp_proc_unlock(BIF_P, ERTS_PROC_LOCK_MAIN); erts_smp_thr_progress_block();*/ + ensure_no_breakpoints(BIF_P, 0, BIF_ARG_1); + erts_lock_code_ix(); erts_start_loader_code_ix(); @@ -168,6 +171,8 @@ BIF_RETTYPE code_make_stub_module_3(BIF_ALIST_3) erts_export_consolidate(erts_active_code_ix());*/ + ensure_no_breakpoints(BIF_P, 0, BIF_ARG_1); + erts_lock_code_ix(); erts_start_loader_code_ix(); @@ -286,6 +291,8 @@ BIF_RETTYPE delete_module_1(BIF_ALIST_1) erts_smp_proc_unlock(BIF_P, ERTS_PROC_LOCK_MAIN); erts_smp_thr_progress_block();*/ + ensure_no_breakpoints(BIF_P, 0, BIF_ARG_1); + erts_lock_code_ix(); erts_start_loader_code_ix(); code_ix = erts_loader_code_ix(); @@ -791,19 +798,18 @@ decrement_refc(BeamInstr* code) } } - + /* - * Move code from current to old. + * Clear breakpoints in module if any */ - -static void -delete_code(Process *c_p, ErtsProcLocks c_p_locks, Module* modp) +static void ensure_no_breakpoints(Process *c_p, ErtsProcLocks c_p_locks, + Eterm module) { - /* - * Clear breakpoints if any - */ - if (modp->curr.code != NULL && modp->curr.code[MI_NUM_BREAKPOINTS] > 0) { - ASSERT(!"SVERK What to do here"); + ErtsCodeIndex code_ix = erts_active_code_ix(); + Module* modp = erts_get_module(module, code_ix); + + if (modp && modp->curr.code != NULL + && modp->curr.code[MI_NUM_BREAKPOINTS] > 0) { #ifdef ERTS_ENABLE_LOCK_CHECK #ifdef ERTS_SMP if (c_p && c_p_locks) @@ -821,6 +827,16 @@ delete_code(Process *c_p, ErtsProcLocks c_p_locks, Module* modp) if (c_p && c_p_locks) erts_smp_proc_lock(c_p, ERTS_PROC_LOCK_MAIN); } +} + +/* + * Move code from current to old. + */ + +static void +delete_code(Process *c_p, ErtsProcLocks c_p_locks, Module* modp) +{ + ASSERT(!(modp->curr.code && modp->curr.code[MI_NUM_BREAKPOINTS] > 0)); modp->old = modp->curr; modp->curr.code = NULL; modp->curr.code_length = 0; -- cgit v1.2.3 From 194ae0717f9be27374db3609e6884fad086df4df Mon Sep 17 00:00:00 2001 From: Sverker Eriksson Date: Mon, 23 Jan 2012 11:25:41 +0100 Subject: erts: Refactor export entry allocation Use a more general approach that does not assume in which order the table entries in a blob are allocated and freed. --- erts/emulator/beam/export.c | 106 +++++++++++++++++++++----------------------- 1 file changed, 51 insertions(+), 55 deletions(-) diff --git a/erts/emulator/beam/export.c b/erts/emulator/beam/export.c index e61cd95566..957d93a281 100644 --- a/erts/emulator/beam/export.c +++ b/erts/emulator/beam/export.c @@ -64,7 +64,6 @@ struct export_entry struct export_blob { Export exp; - unsigned top_ix; /* highest ix used in entryv */ struct export_entry entryv[ERTS_NUM_CODE_IX]; /* Note that entryv is not indexed by "code_ix". */ @@ -78,6 +77,11 @@ struct export_templ Export exp; }; +static struct export_blob* entry_to_blob(struct export_entry* ee) +{ + return (struct export_blob*) + ((char*)ee->ep - offsetof(struct export_blob,exp)); +} void export_info(int to, void *to_arg) @@ -117,36 +121,53 @@ export_cmp(struct export_entry* tmpl_e, struct export_entry* obj_e) static struct export_entry* export_alloc(struct export_entry* tmpl_e) { - - Export* tmpl = tmpl_e->ep; - struct export_blob* blob = - (struct export_blob*) erts_alloc(ERTS_ALC_T_EXPORT, sizeof(*blob)); - Export* obj = &blob->exp; - int i; - - obj->fake_op_func_info_for_hipe[0] = 0; - obj->fake_op_func_info_for_hipe[1] = 0; - obj->code[0] = tmpl->code[0]; - obj->code[1] = tmpl->code[1]; - obj->code[2] = tmpl->code[2]; - obj->code[3] = (BeamInstr) em_call_error_handler; - obj->code[4] = 0; - obj->match_prog_set = NULL; - - for (i=0; iaddressv[i] = obj->code+3; - - blob->entryv[i].slot.index = -1; - blob->entryv[i].ep = &blob->exp; + struct export_blob* blob; + unsigned ix; + + if (tmpl_e->slot.index == -1) { /* Template, allocate blob */ + Export* tmpl = tmpl_e->ep; + Export* obj; + + blob = (struct export_blob*) erts_alloc(ERTS_ALC_T_EXPORT, sizeof(*blob)); + obj = &blob->exp; + obj->fake_op_func_info_for_hipe[0] = 0; + obj->fake_op_func_info_for_hipe[1] = 0; + obj->code[0] = tmpl->code[0]; + obj->code[1] = tmpl->code[1]; + obj->code[2] = tmpl->code[2]; + obj->code[3] = (BeamInstr) em_call_error_handler; + obj->code[4] = 0; + obj->match_prog_set = NULL; + + for (ix=0; ixaddressv[ix] = obj->code+3; + + blob->entryv[ix].slot.index = -1; + blob->entryv[ix].ep = &blob->exp; + } + ix = 0; + } + else { /* Existing entry in another table, use free entry in blob */ + blob = entry_to_blob(tmpl_e); + for (ix = 0; blob->entryv[ix].slot.index >= 0; ix++) { + ASSERT(ix < ERTS_NUM_CODE_IX); + } } - blob->top_ix = 0; - return &blob->entryv[blob->top_ix]; + return &blob->entryv[ix]; } -static void +static void export_free(struct export_entry* obj) { - erts_free(ERTS_ALC_T_EXPORT, (void*) obj); + struct export_blob* blob = entry_to_blob(obj); + int i; + obj->slot.index = -1; + for (i=0; i < ERTS_NUM_CODE_IX; i++) { + if (blob->entryv[i].slot.index >= 0) { + return; + } + } + erts_free(ERTS_ALC_T_EXPORT, blob); } void @@ -359,18 +380,6 @@ Export *export_get(Export *e) return entry ? entry->ep : NULL; } -static struct export_entry* -export_dummy_alloc(struct export_entry* entry) -{ - return entry; -} - -static struct export_blob* entry_to_blob(struct export_entry* ee) -{ - return (struct export_blob*) - ((char*)ee->ep - offsetof(struct export_blob,exp)); -} - IF_DEBUG(static ErtsCodeIndex debug_start_load_ix = 0;) static int entries_at_start_load = 0; @@ -383,7 +392,6 @@ void export_start_load(void) IndexTable* src = &export_tables[src_ix]; struct export_entry* src_entry; struct export_entry* dst_entry; - struct export_blob* blob; int i; ASSERT(dst_ix != src_ix); @@ -394,31 +402,19 @@ void export_start_load(void) * Make sure our existing entries are up to date */ for (i = 0; i < dst->entries; i++) { - src_entry = (struct export_entry*) erts_index_lookup(src, i); - blob = entry_to_blob(src_entry); - blob->exp.addressv[dst_ix] = blob->exp.addressv[src_ix]; + dst_entry = (struct export_entry*) erts_index_lookup(dst, i); + dst_entry->ep->addressv[dst_ix] = dst_entry->ep->addressv[src_ix]; } /* * Insert all new entries from active table */ - - /* Trick hash_put (called by index_put) to insert existing entries. */ - dst->htable.fun.alloc = (HALLOC_FUN) &export_dummy_alloc; - for (i = dst->entries; i < src->entries; i++) { src_entry = (struct export_entry*) erts_index_lookup(src, i); - blob = entry_to_blob(src_entry); - dst_entry = &blob->entryv[++blob->top_ix]; - blob->exp.addressv[dst_ix] = blob->exp.addressv[src_ix]; - ASSERT(blob->top_ix < ERTS_NUM_CODE_IX); - ASSERT(dst_entry->ep == &blob->exp); - ASSERT(dst_entry->slot.index == -1); - index_put(dst, dst_entry); + src_entry->ep->addressv[dst_ix] = src_entry->ep->addressv[src_ix]; + index_put(dst, src_entry); } - dst->htable.fun.alloc = (HALLOC_FUN) &export_alloc; /* restore */ - merge_secondary_table(dst); entries_at_start_load = dst->entries; -- cgit v1.2.3 From 48e662a63e80c4f358be1ba062615ff56e09f331 Mon Sep 17 00:00:00 2001 From: Sverker Eriksson Date: Mon, 23 Jan 2012 16:46:53 +0100 Subject: erts: Refactor new function index_put_entry() Same as index_put() but returns pointer to entry instead of index integer. --- erts/emulator/beam/index.c | 8 ++++---- erts/emulator/beam/index.h | 10 +++++++++- erts/emulator/beam/module.c | 6 ++---- 3 files changed, 15 insertions(+), 9 deletions(-) diff --git a/erts/emulator/beam/index.c b/erts/emulator/beam/index.c index 7cd45440f4..25d5cce0f3 100644 --- a/erts/emulator/beam/index.c +++ b/erts/emulator/beam/index.c @@ -68,14 +68,14 @@ erts_index_init(ErtsAlcType_t type, IndexTable* t, char* name, return t; } -int -index_put(IndexTable* t, void* tmpl) +IndexSlot* +index_put_entry(IndexTable* t, void* tmpl) { int ix; IndexSlot* p = (IndexSlot*) hash_put(&t->htable, tmpl); if (p->index >= 0) { - return p->index; + return p; } ix = t->entries; @@ -92,7 +92,7 @@ index_put(IndexTable* t, void* tmpl) t->entries++; p->index = ix; t->seg_table[ix>>INDEX_PAGE_SHIFT][ix&INDEX_PAGE_MASK] = p; - return ix; + return p; } int index_get(IndexTable* t, void* tmpl) diff --git a/erts/emulator/beam/index.h b/erts/emulator/beam/index.h index 69d1cc0a22..3afe48d007 100644 --- a/erts/emulator/beam/index.h +++ b/erts/emulator/beam/index.h @@ -55,16 +55,24 @@ void index_info(int, void *, IndexTable*); int index_table_sz(IndexTable *); int index_get(IndexTable*, void*); -int index_put(IndexTable*, void*); + +IndexSlot* index_put_entry(IndexTable*, void*); void erts_index_merge(Hash*, IndexTable*); /* Erase all entries with index 'ix' and higher */ void index_erase_latest_from(IndexTable*, Uint ix); +ERTS_GLB_INLINE int index_put(IndexTable*, void*); ERTS_GLB_INLINE IndexSlot* erts_index_lookup(IndexTable*, Uint); #if ERTS_GLB_INLINE_INCL_FUNC_DEF + +ERTS_GLB_INLINE int index_put(IndexTable* t, void* tmpl) +{ + return index_put_entry(t, tmpl)->index; +} + ERTS_GLB_INLINE IndexSlot* erts_index_lookup(IndexTable* t, Uint ix) { diff --git a/erts/emulator/beam/module.c b/erts/emulator/beam/module.c index ab4f387982..f326aecebf 100644 --- a/erts/emulator/beam/module.c +++ b/erts/emulator/beam/module.c @@ -122,7 +122,6 @@ Module* erts_put_module(Eterm mod) { Module e; - int index; IndexTable* mod_tab; ASSERT(is_atom(mod)); @@ -132,8 +131,7 @@ erts_put_module(Eterm mod) mod_tab = &module_tables[erts_loader_code_ix()]; e.module = atom_val(mod); - index = index_put(mod_tab, (void*) &e); - return (Module*) erts_index_lookup(mod_tab, index); + return (Module*) index_put_entry(mod_tab, (void*) &e); } Module *module_code(int i, ErtsCodeIndex code_ix) @@ -185,7 +183,7 @@ void module_start_load(void) */ for (i = dst->entries; i < src->entries; i++) { src_mod = (Module*) erts_index_lookup(src, i); - dst_mod = (Module*) erts_index_lookup(dst, index_put(dst, src_mod)); + dst_mod = (Module*) index_put_entry(dst, src_mod); ASSERT(dst_mod != src_mod); dst_mod->curr = src_mod->curr; -- cgit v1.2.3 From a4cb5739b9f3dd88582fdea7a00cbba721fea35d Mon Sep 17 00:00:00 2001 From: Sverker Eriksson Date: Mon, 23 Jan 2012 16:48:28 +0100 Subject: erts: Remove secondary_export_table --- erts/emulator/beam/beam_load.c | 2 + erts/emulator/beam/export.c | 122 ++++++++++++++++------------------------- erts/emulator/beam/export.h | 4 ++ 3 files changed, 52 insertions(+), 76 deletions(-) diff --git a/erts/emulator/beam/beam_load.c b/erts/emulator/beam/beam_load.c index 54dc663abe..cc4bdea20e 100644 --- a/erts/emulator/beam/beam_load.c +++ b/erts/emulator/beam/beam_load.c @@ -6018,10 +6018,12 @@ void erts_commit_loader_code_ix(void) erts_end_load_ranges(1); { ErtsCodeIndex ix; + export_write_lock(); ix = erts_loader_code_ix(); erts_smp_atomic32_set_nob(&the_active_code_index, ix); ix = (ix + 1) % ERTS_NUM_CODE_IX; erts_smp_atomic32_set_nob(&the_loader_code_index, ix); + export_write_unlock(); } CIX_TRACE("commit"); } diff --git a/erts/emulator/beam/export.c b/erts/emulator/beam/export.c index 957d93a281..487d6ee963 100644 --- a/erts/emulator/beam/export.c +++ b/erts/emulator/beam/export.c @@ -39,16 +39,13 @@ #endif static IndexTable export_tables[ERTS_NUM_CODE_IX]; /* Active not locked */ -static Hash secondary_export_table; /* Locked. */ #include "erl_smp.h" -static erts_smp_rwmtx_t export_table_lock; /* Locks the secondary export table. */ +erts_smp_rwmtx_t export_table_lock; /* Locks the secondary export table. */ #define export_read_lock() erts_smp_rwmtx_rlock(&export_table_lock) #define export_read_unlock() erts_smp_rwmtx_runlock(&export_table_lock) -#define export_write_lock() erts_smp_rwmtx_rwlock(&export_table_lock) -#define export_write_unlock() erts_smp_rwmtx_rwunlock(&export_table_lock) extern BeamInstr* em_call_error_handler; extern BeamInstr* em_call_traced_function; @@ -92,7 +89,7 @@ export_info(int to, void *to_arg) export_read_lock(); #endif index_info(to, to_arg, &export_tables[erts_active_code_ix()]); - hash_info(to, to_arg, &secondary_export_table); + hash_info(to, to_arg, &export_tables[erts_loader_code_ix()].htable); #ifdef ERTS_SMP if (lock) export_read_unlock(); @@ -190,8 +187,6 @@ init_export_table(void) erts_index_init(ERTS_ALC_T_EXPORT_TABLE, &export_tables[i], "export_list", EXPORT_INITIAL_SIZE, EXPORT_LIMIT, f); } - hash_init(ERTS_ALC_T_EXPORT_TABLE, &secondary_export_table, - "secondary_export_table", 50, f); } /* @@ -289,12 +284,15 @@ erts_export_put(Eterm mod, Eterm func, unsigned int arity) { ErtsCodeIndex code_ix = erts_loader_code_ix(); struct export_templ templ; - int ix; + struct export_entry* ee; ASSERT(is_atom(mod)); ASSERT(is_atom(func)); - ix = index_put(&export_tables[code_ix], init_template(&templ, mod, func, arity)); - return ((struct export_entry*) erts_index_lookup(&export_tables[code_ix], ix))->ep; + export_write_lock(); + ee = (struct export_entry*) index_put_entry(&export_tables[code_ix], + init_template(&templ, mod, func, arity)); + export_write_unlock(); + return ee->ep; } /* @@ -302,57 +300,46 @@ erts_export_put(Eterm mod, Eterm func, unsigned int arity) * export entry (making a call through it will cause the error_handler to * be called). * - * Stub export entries will be placed in the secondary export table. - * export_start_load() will move all stub export entries into the - * main export table (will be done the next time code is loaded). + * Stub export entries will be placed in the loader export table. */ Export* erts_export_get_or_make_stub(Eterm mod, Eterm func, unsigned int arity) { + ErtsCodeIndex code_ix; Export* ep; + IF_DEBUG(int retrying = 0;) ASSERT(is_atom(mod)); ASSERT(is_atom(func)); - - ep = erts_active_export_entry(mod, func, arity); - if (ep == 0) { - struct export_templ templ; - struct export_entry* entry; - /* - * The code is not loaded (yet). Put the export in the secondary - * export table, to avoid having to lock the active export table. - */ - export_write_lock(); - entry = (struct export_entry *) hash_put(&secondary_export_table, - init_template(&templ, mod, func, arity)); - export_write_unlock(); - ep = entry->ep; - } - return ep; -} -/* - * Move all export entries from the secondary export table into the primary. - */ -static void merge_secondary_table(IndexTable* dst) -{ - ERTS_SMP_LC_ASSERT(erts_is_code_ix_locked()); - /*SVERK && code_ix == erts_loader_code_ix())); - || erts_initialized == 0 - || erts_smp_thr_progress_is_blocking());*/ - - export_write_lock(); - erts_index_merge(&secondary_export_table, dst); - erts_hash_merge(&secondary_export_table, &dst->htable); - export_write_unlock(); -#ifdef DEBUG - { - HashInfo hi; - hash_get_info(&hi, &dst->htable); - ASSERT(dst->entries == hi.objs); - } -#endif + do { + code_ix = erts_active_code_ix(); + ep = erts_find_export_entry(mod, func, arity, code_ix); + if (ep == 0) { + /* + * The code is not loaded (yet). Put the export in the loader + * export table, to avoid having to lock the active export table. + */ + export_write_lock(); + if (erts_active_code_ix() == code_ix) { /*SVERK barrier? */ + struct export_templ templ; + struct export_entry* entry; + + IndexTable* tab = &export_tables[erts_loader_code_ix()]; + init_template(&templ, mod, func, arity); + entry = (struct export_entry *) index_put_entry(tab, &templ.entry); + ep = entry->ep; + ASSERT(ep); + } + else { /* race */ + ASSERT(!retrying); + IF_DEBUG(retrying = 1); + } + export_write_unlock(); + } + } while (!ep); + return ep; } Export *export_list(int i, ErtsCodeIndex code_ix) @@ -382,7 +369,6 @@ Export *export_get(Export *e) IF_DEBUG(static ErtsCodeIndex debug_start_load_ix = 0;) -static int entries_at_start_load = 0; void export_start_load(void) { @@ -395,29 +381,20 @@ void export_start_load(void) int i; ASSERT(dst_ix != src_ix); - ASSERT(dst->entries <= src->entries); ASSERT(debug_start_load_ix == -1); + export_write_lock(); /* - * Make sure our existing entries are up to date - */ - for (i = 0; i < dst->entries; i++) { - dst_entry = (struct export_entry*) erts_index_lookup(dst, i); - dst_entry->ep->addressv[dst_ix] = dst_entry->ep->addressv[src_ix]; - } - - /* - * Insert all new entries from active table + * Insert all entries in src into dst table */ - for (i = dst->entries; i < src->entries; i++) { + /*SVERK Room for optimization to only insert the new ones */ + for (i = 0; i < src->entries; i++) { src_entry = (struct export_entry*) erts_index_lookup(src, i); src_entry->ep->addressv[dst_ix] = src_entry->ep->addressv[src_ix]; - index_put(dst, src_entry); + dst_entry = (struct export_entry*) index_put_entry(dst, src_entry); + ASSERT(entry_to_blob(src_entry) == entry_to_blob(dst_entry)); } - - merge_secondary_table(dst); - - entries_at_start_load = dst->entries; + export_write_unlock(); IF_DEBUG(debug_start_load_ix = dst_ix); } @@ -425,13 +402,6 @@ void export_start_load(void) void export_end_load(int commit) { ASSERT(debug_start_load_ix == erts_loader_code_ix()); - - if (!commit) { /* abort */ - IndexTable* tab = &export_tables[erts_loader_code_ix()]; - - ASSERT(entries_at_start_load <= tab->entries); - index_erase_latest_from(tab, entries_at_start_load); - } - IF_DEBUG(debug_start_load_ix = -1); } + diff --git a/erts/emulator/beam/export.h b/erts/emulator/beam/export.h index 85628aac0b..577e24f266 100644 --- a/erts/emulator/beam/export.h +++ b/erts/emulator/beam/export.h @@ -75,6 +75,10 @@ Export *export_get(Export*); void export_start_load(void); void export_end_load(int commit); +extern erts_smp_rwmtx_t export_table_lock; +#define export_write_lock() erts_smp_rwmtx_rwlock(&export_table_lock) +#define export_write_unlock() erts_smp_rwmtx_rwunlock(&export_table_lock) + #include "beam_load.h" /* For em_* extern declarations */ #define ExportIsBuiltIn(EntryPtr) \ (((EntryPtr)->addressv[erts_active_code_ix()] == (EntryPtr)->code + 3) && \ -- cgit v1.2.3 From 68c3059a7660605b5f7200b4290905b785a3c604 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn-Egil=20Dahlberg?= Date: Mon, 23 Jan 2012 15:16:14 +0100 Subject: test: parallel_load_check_purge_repeat * test trivial non-blocking code loading (smoke test) --- erts/emulator/test/Makefile | 1 + erts/emulator/test/code_parallel_load_SUITE.erl | 137 ++++++++++++++++++++++++ 2 files changed, 138 insertions(+) create mode 100644 erts/emulator/test/code_parallel_load_SUITE.erl diff --git a/erts/emulator/test/Makefile b/erts/emulator/test/Makefile index a3dcbc4cf3..efa3cd475f 100644 --- a/erts/emulator/test/Makefile +++ b/erts/emulator/test/Makefile @@ -47,6 +47,7 @@ MODULES= \ busy_port_SUITE \ call_trace_SUITE \ code_SUITE \ + code_parallel_load_SUITE \ crypto_SUITE \ ddll_SUITE \ decode_packet_SUITE \ diff --git a/erts/emulator/test/code_parallel_load_SUITE.erl b/erts/emulator/test/code_parallel_load_SUITE.erl new file mode 100644 index 0000000000..b86b81a953 --- /dev/null +++ b/erts/emulator/test/code_parallel_load_SUITE.erl @@ -0,0 +1,137 @@ +%% Copyright (C) 2012 Björn-Egil Dahlberg +%% +%% File: code_parallel_load_SUITE.erl +%% Author: Björn-Egil Dahlberg +%% Created: 2012-01-19 +-module(code_parallel_load_SUITE). +-export([ + all/0, + suite/0, + init_per_suite/1, + end_per_suite/1, + init_per_testcase/2, + end_per_testcase/2 + ]). + +-export([ + parallel_load_check_purge_repeat/1 + ]). + +-define(model, my_model). +-define(interval, 1500). +-define(number_of_processes, 160). +-define(passes, 4). + + +-include_lib("test_server/include/test_server.hrl"). + +suite() -> [{ct_hooks,[ts_install_cth]}]. + +all() -> + [parallel_load_check_purge_repeat]. + + +init_per_suite(Config) -> + Config. + +end_per_suite(_Config) -> + ok. + +init_per_testcase(Func, Config) when is_atom(Func), is_list(Config) -> + Dog=?t:timetrap(?t:minutes(3)), + [{watchdog, Dog}|Config]. + +end_per_testcase(_Func, Config) -> + Dog=?config(watchdog, Config), + ?t:timetrap_cancel(Dog). + + +parallel_load_check_purge_repeat(_Conf) -> + Ts = [v1,v2,v3,v4,v5,v6], + Codes = generate_codes(Ts), + setup_code_changer(Codes), + ok. + +setup_code_changer([{Token,Code}|Cs] = Codes) -> + {module, ?model} = erlang:load_module(?model,Code), + Pids = setup_checkers(Token,?number_of_processes), + code_changer(Cs, Codes, ?interval,Pids,?passes), + ok. + +code_changer(_, _, _, Pids, 0) -> + [exit(Pid, normal) || Pid <- Pids], + io:format("done~n"), + ok; +code_changer([], Codes, T, Pids, Ps) -> + code_changer(Codes, Codes, T, Pids, Ps - 1); +code_changer([{Token,Code}|Cs], Codes, T, Pids, Ps) -> + receive after T -> + io:format("load code with token ~4w : pass ~4w~n", [Token, Ps]), + %code:load_binary(?model, ?model, Code), + {module, ?model} = erlang:load_module(?model, Code), + % this is second time we call load_module for this module + % so it should have old code + [Pid ! {self(), change, Token} || Pid <- Pids], + % should we wait a moment or just blantantly try to check and purge repeatadly? + receive after 1 -> ok end, + ok = check_and_purge_processes_code(Pids, ?model), + code_changer(Cs, Codes, T, Pids, Ps) + end. + +%% generate code that receives a token, code switches to new code +%% then matches this token against a literal code token +%% should be identical +%% (smoke test for parallel code loading +generate_codes([]) -> []; +generate_codes([T|Ts]) -> + [{T, generate(?model, [], [ + format("check(T) -> receive {_Pid, change, T1} -> " + " ~w:check(T1)\n" + " after 0 -> T = f(), check(T) end.\n", [?model]), + format("f() -> ~w.~n", [T]) + ])} | generate_codes(Ts)]. + + + +%% aux + +setup_checkers(_,0) -> []; +setup_checkers(T,N) -> [spawn_link(fun() -> ?model:check(T) end) | setup_checkers(T, N-1)]. + +check_and_purge_processes_code(Pids, M) -> + check_and_purge_processes_code(Pids, M, []). +check_and_purge_processes_code([], M, []) -> + erlang:purge_module(M), + ok; +check_and_purge_processes_code([], M, Pending) -> + io:format("Processes ~w are still executing old code - retrying.~n", [Pending]), + check_and_purge_processes_code(Pending, M, []); +check_and_purge_processes_code([Pid|Pids], M, Pending) -> + case erlang:check_process_code(Pid, M) of + false -> + check_and_purge_processes_code(Pids, M, Pending); + true -> + check_and_purge_processes_code(Pids, M, [Pid|Pending]) + end. + + +generate(Module, Attributes, FunStrings) -> + FunForms = function_forms(FunStrings), + Forms = [ + {attribute,1,module,Module}, + {attribute,2,export,[FA || {FA,_} <- FunForms]} + ] ++ [{attribute, 3, A, V}|| {A, V} <- Attributes] ++ + [ Function || {_, Function} <- FunForms], + {ok, Module, Bin} = compile:forms(Forms), + Bin. + + +function_forms([]) -> []; +function_forms([S|Ss]) -> + {ok, Ts,_} = erl_scan:string(S), + {ok, Form} = erl_parse:parse_form(Ts), + Fun = element(3, Form), + Arity = element(4, Form), + [{{Fun,Arity}, Form}|function_forms(Ss)]. + +format(F,Ts) -> lists:flatten(io_lib:format(F, Ts)). -- cgit v1.2.3 From 42b9dbd87d905009fd3f27e0b1d6d1392ea50727 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn-Egil=20Dahlberg?= Date: Mon, 23 Jan 2012 16:29:20 +0100 Subject: test: many_load_distributed_only_once --- erts/emulator/test/code_parallel_load_SUITE.erl | 75 ++++++++++++++++++------- 1 file changed, 56 insertions(+), 19 deletions(-) diff --git a/erts/emulator/test/code_parallel_load_SUITE.erl b/erts/emulator/test/code_parallel_load_SUITE.erl index b86b81a953..e29bebb2f6 100644 --- a/erts/emulator/test/code_parallel_load_SUITE.erl +++ b/erts/emulator/test/code_parallel_load_SUITE.erl @@ -14,10 +14,11 @@ ]). -export([ - parallel_load_check_purge_repeat/1 + multiple_load_check_purge_repeat/1, + many_load_distributed_only_once/1 ]). --define(model, my_model). +-define(model, code_parallel_load_SUITE_model). -define(interval, 1500). -define(number_of_processes, 160). -define(passes, 4). @@ -28,7 +29,10 @@ suite() -> [{ct_hooks,[ts_install_cth]}]. all() -> - [parallel_load_check_purge_repeat]. + [ + multiple_load_check_purge_repeat, + many_load_distributed_only_once + ]. init_per_suite(Config) -> @@ -43,12 +47,27 @@ init_per_testcase(Func, Config) when is_atom(Func), is_list(Config) -> end_per_testcase(_Func, Config) -> Dog=?config(watchdog, Config), - ?t:timetrap_cancel(Dog). - + ?t:timetrap_cancel(Dog), + case erlang:delete_module(?model) of + true -> + erlang:purge_module(?model); + _ -> ok + end. -parallel_load_check_purge_repeat(_Conf) -> +multiple_load_check_purge_repeat(_Conf) -> Ts = [v1,v2,v3,v4,v5,v6], - Codes = generate_codes(Ts), + + %% generate code that receives a token, code switches to new code + %% then matches this token against a literal code token + %% should be identical + %% (smoke test for parallel code loading + Codes = [{T, generate(?model, [], [ + format("check(T) -> receive {_Pid, change, T1} -> " + " ~w:check(T1)\n" + " after 0 -> T = f(), check(T) end.\n", [?model]), + format("f() -> ~w.~n", [T]) + ])} || T <- Ts], + setup_code_changer(Codes), ok. @@ -67,7 +86,6 @@ code_changer([], Codes, T, Pids, Ps) -> code_changer([{Token,Code}|Cs], Codes, T, Pids, Ps) -> receive after T -> io:format("load code with token ~4w : pass ~4w~n", [Token, Ps]), - %code:load_binary(?model, ?model, Code), {module, ?model} = erlang:load_module(?model, Code), % this is second time we call load_module for this module % so it should have old code @@ -78,19 +96,38 @@ code_changer([{Token,Code}|Cs], Codes, T, Pids, Ps) -> code_changer(Cs, Codes, T, Pids, Ps) end. -%% generate code that receives a token, code switches to new code -%% then matches this token against a literal code token -%% should be identical -%% (smoke test for parallel code loading -generate_codes([]) -> []; -generate_codes([T|Ts]) -> - [{T, generate(?model, [], [ - format("check(T) -> receive {_Pid, change, T1} -> " - " ~w:check(T1)\n" - " after 0 -> T = f(), check(T) end.\n", [?model]), + + +many_load_distributed_only_once(_Conf) -> + Ts = [<<"first version">>, <<"second version">>], + + [{Token1,Code1},{Token2, Code2}] = [{T, generate(?model, [], [ + "check({<<\"second version\">> = V, Pid}) -> V = f(), Pid ! {self(), completed, V}, ok;\n" ++ + format("check(T) -> receive {Pid, change, T1, B} -> " + " Res = erlang:load_module(~w, B), Pid ! {self(), change, Res},\n" + " ~w:check({T1, Pid})\n" + " after 0 -> T = f(), check(T) end.\n", [?model, ?model]), format("f() -> ~w.~n", [T]) - ])} | generate_codes(Ts)]. + ])} || T <- Ts], + + + {module, ?model} = erlang:load_module(?model, Code1), + Pids = setup_checkers(Token1,?number_of_processes), + + receive after 1000 -> ok end, % give 'em some time to spin up + [Pid ! {self(), change, Token2, Code2} || Pid <- Pids], + Loads = [receive {Pid, change, Res} -> Res end || Pid <- Pids], + [receive {Pid, completed, Token2} -> ok end || Pid <- Pids], + + ok = ensure_only_one_load(Loads, 0). +ensure_only_one_load([], 1) -> ok; +ensure_only_one_load([], _) -> too_many_loads; +ensure_only_one_load([{module, ?model}|Loads], N) -> + ensure_only_one_load(Loads, N + 1); +ensure_only_one_load([{error, not_purged}|Loads], N) -> + ensure_only_one_load(Loads, N). +% no other return values are allowed from load_module %% aux -- cgit v1.2.3 From 725ebf78ac6d47c760f64f11c07eeb8b850ef920 Mon Sep 17 00:00:00 2001 From: Sverker Eriksson Date: Tue, 24 Jan 2012 10:55:52 +0100 Subject: test: Safe purging in code_parallel_load_SUITE erlang:purge_module/1 is brutal and causes core dump if old code is still executing, especially on debug VM. --- erts/emulator/test/code_parallel_load_SUITE.erl | 54 ++++++++++++++++++------- 1 file changed, 39 insertions(+), 15 deletions(-) diff --git a/erts/emulator/test/code_parallel_load_SUITE.erl b/erts/emulator/test/code_parallel_load_SUITE.erl index e29bebb2f6..aa9e4c96c6 100644 --- a/erts/emulator/test/code_parallel_load_SUITE.erl +++ b/erts/emulator/test/code_parallel_load_SUITE.erl @@ -1,8 +1,23 @@ -%% Copyright (C) 2012 Björn-Egil Dahlberg %% -%% File: code_parallel_load_SUITE.erl +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2012. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% %% Author: Björn-Egil Dahlberg -%% Created: 2012-01-19 + -module(code_parallel_load_SUITE). -export([ all/0, @@ -19,7 +34,7 @@ ]). -define(model, code_parallel_load_SUITE_model). --define(interval, 1500). +-define(interval, 50). -define(number_of_processes, 160). -define(passes, 4). @@ -46,13 +61,20 @@ init_per_testcase(Func, Config) when is_atom(Func), is_list(Config) -> [{watchdog, Dog}|Config]. end_per_testcase(_Func, Config) -> - Dog=?config(watchdog, Config), - ?t:timetrap_cancel(Dog), + SConf = ?config(save_config, Config), + Pids = proplists:get_value(purge_pids, SConf), + + case check_old_code(?model) of + true -> check_and_purge_processes_code(Pids, ?model); + _ -> ok + end, case erlang:delete_module(?model) of - true -> - erlang:purge_module(?model); - _ -> ok - end. + true -> check_and_purge_processes_code(Pids, ?model); + _ -> ok + end, + Dog=?config(watchdog, Config), + ?t:timetrap_cancel(Dog). + multiple_load_check_purge_repeat(_Conf) -> Ts = [v1,v2,v3,v4,v5,v6], @@ -68,17 +90,18 @@ multiple_load_check_purge_repeat(_Conf) -> format("f() -> ~w.~n", [T]) ])} || T <- Ts], - setup_code_changer(Codes), - ok. + Pids = setup_code_changer(Codes), + {save_config, [{purge_pids,Pids}]}. setup_code_changer([{Token,Code}|Cs] = Codes) -> {module, ?model} = erlang:load_module(?model,Code), Pids = setup_checkers(Token,?number_of_processes), code_changer(Cs, Codes, ?interval,Pids,?passes), - ok. + Pids. code_changer(_, _, _, Pids, 0) -> - [exit(Pid, normal) || Pid <- Pids], + [unlink(Pid) || Pid <- Pids], + [exit(Pid, die) || Pid <- Pids], io:format("done~n"), ok; code_changer([], Codes, T, Pids, Ps) -> @@ -119,7 +142,8 @@ many_load_distributed_only_once(_Conf) -> Loads = [receive {Pid, change, Res} -> Res end || Pid <- Pids], [receive {Pid, completed, Token2} -> ok end || Pid <- Pids], - ok = ensure_only_one_load(Loads, 0). + ok = ensure_only_one_load(Loads, 0), + {save_config, [{purge_pids,Pids}]}. ensure_only_one_load([], 1) -> ok; ensure_only_one_load([], _) -> too_many_loads; -- cgit v1.2.3 From 72cab3a723925d0e369466d7de7567d8482b1318 Mon Sep 17 00:00:00 2001 From: Sverker Eriksson Date: Tue, 24 Jan 2012 14:28:39 +0100 Subject: erts: Fix purge of module with loaded nif library Easy fallback solution that goes single threaded if the module to be purged has a loaded nif lib. --- erts/emulator/beam/beam_bif_load.c | 26 ++++++++++++++++++++++---- 1 file changed, 22 insertions(+), 4 deletions(-) diff --git a/erts/emulator/beam/beam_bif_load.c b/erts/emulator/beam/beam_bif_load.c index 7a65552d76..4a01e62dc8 100644 --- a/erts/emulator/beam/beam_bif_load.c +++ b/erts/emulator/beam/beam_bif_load.c @@ -40,7 +40,7 @@ static Eterm check_process_code(Process* rp, Module* modp); static void ensure_no_breakpoints(Process *, ErtsProcLocks, Eterm module); static void delete_code(Process *c_p, ErtsProcLocks c_p_locks, Module* modp); static void delete_export_references(Eterm module); -static int purge_module(int module); +static int purge_module(Process*, int module); static void decrement_refc(BeamInstr* code); static int is_native(BeamInstr* code); static int any_heap_ref_ptrs(Eterm* start, Eterm* end, char* mod_start, Uint mod_size); @@ -128,7 +128,7 @@ BIF_RETTYPE purge_module_1(BIF_ALIST_1) erts_export_consolidate(erts_active_code_ix());*/ - purge_res = purge_module(atom_val(BIF_ARG_1)); + purge_res = purge_module(BIF_P, atom_val(BIF_ARG_1)); /*SVERK erts_smp_thr_progress_unblock(); @@ -721,15 +721,17 @@ any_heap_refs(Eterm* start, Eterm* end, char* mod_start, Uint mod_size) static int -purge_module(int module) +purge_module(Process* c_p, int module) { ErtsCodeIndex code_ix; BeamInstr* code; BeamInstr* end; Module* modp; + int is_blocked = 0; int ret; erts_lock_code_ix(); +retry: code_ix = erts_active_code_ix(); /* @@ -753,6 +755,16 @@ purge_module(int module) * Unload any NIF library */ if (modp->old.nif != NULL) { + if (!is_blocked) { + /*SVERK Do unload nif without blocking */ + erts_rwunlock_old_code(code_ix); + erts_unlock_code_ix(); + erts_smp_proc_unlock(c_p, ERTS_PROC_LOCK_MAIN); + erts_smp_thr_progress_block(); + is_blocked = 1; + goto retry; + } + erts_unload_nif(modp->old.nif); modp->old.nif = NULL; } @@ -777,7 +789,13 @@ purge_module(int module) } erts_rwunlock_old_code(code_ix); } - erts_unlock_code_ix(); + if (is_blocked) { + erts_smp_thr_progress_unblock(); + erts_smp_proc_lock(c_p, ERTS_PROC_LOCK_MAIN); + } + else { + erts_unlock_code_ix(); + } return ret; } -- cgit v1.2.3 From a23f25a3014dbad01d2016dc4e6d6df9d59ba64c Mon Sep 17 00:00:00 2001 From: Sverker Eriksson Date: Tue, 24 Jan 2012 15:42:02 +0100 Subject: erts: Rename "loader" code_ix as "staging" code_ix Staging is a better and more general name as does not necessary need to involve code loading (can be deletion, tracing, etc). --- erts/emulator/beam/beam_bif_load.c | 26 +++++++++++------------ erts/emulator/beam/beam_catches.c | 14 ++++++------- erts/emulator/beam/beam_catches.h | 4 ++-- erts/emulator/beam/beam_load.c | 42 +++++++++++++++++++------------------- erts/emulator/beam/beam_ranges.c | 10 ++++----- erts/emulator/beam/code_ix.h | 8 ++++---- erts/emulator/beam/erl_init.c | 2 +- erts/emulator/beam/export.c | 14 ++++++------- erts/emulator/beam/export.h | 4 ++-- erts/emulator/beam/global.h | 4 ++-- erts/emulator/beam/module.c | 14 ++++++------- erts/emulator/beam/module.h | 4 ++-- erts/emulator/hipe/hipe_bif0.c | 2 +- 13 files changed, 74 insertions(+), 74 deletions(-) diff --git a/erts/emulator/beam/beam_bif_load.c b/erts/emulator/beam/beam_bif_load.c index 4a01e62dc8..c14b86f811 100644 --- a/erts/emulator/beam/beam_bif_load.c +++ b/erts/emulator/beam/beam_bif_load.c @@ -89,20 +89,20 @@ load_module_2(BIF_ALIST_2) ensure_no_breakpoints(BIF_P, 0, BIF_ARG_1); erts_lock_code_ix(); - erts_start_loader_code_ix(); + erts_start_staging_code_ix(); reason = erts_finish_loading(stp, BIF_P, 0, &BIF_ARG_1); if (reason != NIL) { if (reason == am_on_load) { - erts_commit_loader_code_ix(); + erts_commit_staging_code_ix(); } else { - erts_abort_loader_code_ix(); + erts_abort_staging_code_ix(); } res = TUPLE2(hp, am_error, reason); } else { - set_default_trace_pattern(BIF_ARG_1, erts_loader_code_ix()); - erts_commit_loader_code_ix(); + set_default_trace_pattern(BIF_ARG_1, erts_staging_code_ix()); + erts_commit_staging_code_ix(); res = TUPLE2(hp, am_module, BIF_ARG_1); } @@ -174,15 +174,15 @@ BIF_RETTYPE code_make_stub_module_3(BIF_ALIST_3) ensure_no_breakpoints(BIF_P, 0, BIF_ARG_1); erts_lock_code_ix(); - erts_start_loader_code_ix(); + erts_start_staging_code_ix(); res = erts_make_stub_module(BIF_P, BIF_ARG_1, BIF_ARG_2, BIF_ARG_3); if (res == BIF_ARG_1) { - erts_commit_loader_code_ix(); + erts_commit_staging_code_ix(); } else { - erts_abort_loader_code_ix(); + erts_abort_staging_code_ix(); } erts_unlock_code_ix(); @@ -294,8 +294,8 @@ BIF_RETTYPE delete_module_1(BIF_ALIST_1) ensure_no_breakpoints(BIF_P, 0, BIF_ARG_1); erts_lock_code_ix(); - erts_start_loader_code_ix(); - code_ix = erts_loader_code_ix(); + erts_start_staging_code_ix(); + code_ix = erts_staging_code_ix(); { Module *modp = erts_get_module(BIF_ARG_1, code_ix); if (!modp) { @@ -316,10 +316,10 @@ BIF_RETTYPE delete_module_1(BIF_ALIST_1) } if (res == am_true) { - erts_commit_loader_code_ix(); + erts_commit_staging_code_ix(); } else { - erts_abort_loader_code_ix(); + erts_abort_staging_code_ix(); } erts_unlock_code_ix(); @@ -869,7 +869,7 @@ delete_code(Process *c_p, ErtsProcLocks c_p_locks, Module* modp) static void delete_export_references(Eterm module) { - ErtsCodeIndex code_ix = erts_loader_code_ix(); + ErtsCodeIndex code_ix = erts_staging_code_ix(); int i; ASSERT(is_atom(module)); diff --git a/erts/emulator/beam/beam_catches.c b/erts/emulator/beam/beam_catches.c index 72bd3583e1..548c10fa94 100644 --- a/erts/emulator/beam/beam_catches.c +++ b/erts/emulator/beam/beam_catches.c @@ -62,7 +62,7 @@ void beam_catches_init(void) bccix[i] = bccix[i-1]; } /* For initial load: */ - IF_DEBUG(bccix[erts_loader_code_ix()].is_prepared = 1); + IF_DEBUG(bccix[erts_staging_code_ix()].is_prepared = 1); } @@ -78,9 +78,9 @@ static void gc_old_vec(beam_catch_t* vec) } -void beam_catches_start_load(void) +void beam_catches_start_staging(void) { - ErtsCodeIndex dst = erts_loader_code_ix(); + ErtsCodeIndex dst = erts_staging_code_ix(); ErtsCodeIndex src = erts_active_code_ix(); beam_catch_t* prev_vec = bccix[dst].beam_catches; @@ -91,15 +91,15 @@ void beam_catches_start_load(void) IF_DEBUG(bccix[dst].is_prepared = 1); } -void beam_catches_end_load(int commit) +void beam_catches_end_staging(int commit) { - IF_DEBUG(bccix[erts_loader_code_ix()].is_prepared = 0); + IF_DEBUG(bccix[erts_staging_code_ix()].is_prepared = 0); } unsigned beam_catches_cons(BeamInstr *cp, unsigned cdr) { int i; - struct bc_code_ix* p = &bccix[erts_loader_code_ix()]; + struct bc_code_ix* p = &bccix[erts_staging_code_ix()]; ASSERT(p->is_prepared); /* @@ -151,7 +151,7 @@ void beam_catches_delmod(unsigned head, BeamInstr *code, unsigned code_bytes, struct bc_code_ix* p = &bccix[code_ix]; unsigned i, cdr; - ASSERT((code_ix == erts_active_code_ix()) != bccix[erts_loader_code_ix()].is_prepared); + ASSERT((code_ix == erts_active_code_ix()) != bccix[erts_staging_code_ix()].is_prepared); for(i = head; i != (unsigned)-1;) { if (i >= p->tabsize) { erl_exit(1, "beam_catches_delmod: index %#x is out of range\r\n", i); diff --git a/erts/emulator/beam/beam_catches.h b/erts/emulator/beam/beam_catches.h index 970772806b..309b5cc857 100644 --- a/erts/emulator/beam/beam_catches.h +++ b/erts/emulator/beam/beam_catches.h @@ -25,8 +25,8 @@ #define BEAM_CATCHES_NIL (-1) void beam_catches_init(void); -void beam_catches_start_load(void); -void beam_catches_end_load(int commit); +void beam_catches_start_staging(void); +void beam_catches_end_staging(int commit); unsigned beam_catches_cons(BeamInstr* cp, unsigned cdr); BeamInstr *beam_catches_car(unsigned i); void beam_catches_delmod(unsigned head, BeamInstr* code, unsigned code_bytes, diff --git a/erts/emulator/beam/beam_load.c b/erts/emulator/beam/beam_load.c index cc4bdea20e..d393ff6a34 100644 --- a/erts/emulator/beam/beam_load.c +++ b/erts/emulator/beam/beam_load.c @@ -4249,13 +4249,13 @@ final_touch(LoaderState* stp) ep = erts_export_put(stp->module, stp->export[i].function, stp->export[i].arity); if (!on_load) { - ep->addressv[erts_loader_code_ix()] = address; + ep->addressv[erts_staging_code_ix()] = address; } else { /* * Don't make any of the exported functions * callable yet. */ - ep->addressv[erts_loader_code_ix()] = ep->code+3; + ep->addressv[erts_staging_code_ix()] = ep->code+3; ep->code[4] = (BeamInstr) address; } } @@ -5531,7 +5531,7 @@ stub_final_touch(LoaderState* stp, BeamInstr* fp) for (i = 0; i < n; i++) { if (stp->export[i].function == function && stp->export[i].arity == arity) { Export* ep = erts_export_put(mod, function, arity); - ep->addressv[erts_loader_code_ix()] = fp+5; + ep->addressv[erts_staging_code_ix()] = fp+5; return; } } @@ -5953,7 +5953,7 @@ static erts_smp_mtx_t sverk_code_ix_lock; /*SVERK FIXME */ static erts_smp_rwmtx_t the_old_code_rwlocks[ERTS_NUM_CODE_IX]; #ifdef DEBUG -# define CIX_TRACE(text) erts_fprintf(stderr, "CIX_TRACE: " text " act=%u load=%u\r\n", erts_active_code_ix(), erts_loader_code_ix()) +# define CIX_TRACE(text) erts_fprintf(stderr, "CIX_TRACE: " text " act=%u load=%u\r\n", erts_active_code_ix(), erts_staging_code_ix()) #else # define CIX_TRACE(text) #endif @@ -5974,7 +5974,7 @@ ErtsCodeIndex erts_active_code_ix(void) { return erts_smp_atomic32_read_nob(&the_active_code_index); } -ErtsCodeIndex erts_loader_code_ix(void) +ErtsCodeIndex erts_staging_code_ix(void) { return erts_smp_atomic32_read_nob(&the_loader_code_index); } @@ -6000,26 +6000,26 @@ int erts_is_code_ix_locked(void) } #endif -void erts_start_loader_code_ix(void) +void erts_start_staging_code_ix(void) { - beam_catches_start_load(); - export_start_load(); - module_start_load(); - erts_start_load_ranges(); + beam_catches_start_staging(); + export_start_staging(); + module_start_staging(); + erts_start_staging_ranges(); CIX_TRACE("start"); } -void erts_commit_loader_code_ix(void) +void erts_commit_staging_code_ix(void) { - beam_catches_end_load(1); - export_end_load(1); - module_end_load(1); - erts_end_load_ranges(1); + beam_catches_end_staging(1); + export_end_staging(1); + module_end_staging(1); + erts_end_staging_ranges(1); { ErtsCodeIndex ix; export_write_lock(); - ix = erts_loader_code_ix(); + ix = erts_staging_code_ix(); erts_smp_atomic32_set_nob(&the_active_code_index, ix); ix = (ix + 1) % ERTS_NUM_CODE_IX; erts_smp_atomic32_set_nob(&the_loader_code_index, ix); @@ -6028,12 +6028,12 @@ void erts_commit_loader_code_ix(void) CIX_TRACE("commit"); } -void erts_abort_loader_code_ix(void) +void erts_abort_staging_code_ix(void) { - beam_catches_end_load(0); - export_end_load(0); - module_end_load(0); - erts_end_load_ranges(0); + beam_catches_end_staging(0); + export_end_staging(0); + module_end_staging(0); + erts_end_staging_ranges(0); CIX_TRACE("abort"); } diff --git a/erts/emulator/beam/beam_ranges.c b/erts/emulator/beam/beam_ranges.c index ae701ea0c9..0fc8d9dbfd 100644 --- a/erts/emulator/beam/beam_ranges.c +++ b/erts/emulator/beam/beam_ranges.c @@ -78,9 +78,9 @@ erts_init_ranges(void) } void -erts_start_load_ranges(void) +erts_start_staging_ranges(void) { - ErtsCodeIndex dst = erts_loader_code_ix(); + ErtsCodeIndex dst = erts_staging_code_ix(); if (r[dst].modules) { erts_smp_atomic_add_nob(&mem_used, -r[dst].allocated); @@ -90,9 +90,9 @@ erts_start_load_ranges(void) } void -erts_end_load_ranges(int commit) +erts_end_staging_ranges(int commit) { - ErtsCodeIndex dst = erts_loader_code_ix(); + ErtsCodeIndex dst = erts_staging_code_ix(); if (commit && r[dst].modules == NULL) { Sint i; @@ -123,7 +123,7 @@ erts_end_load_ranges(int commit) void erts_update_ranges(BeamInstr* code, Uint size) { - ErtsCodeIndex dst = erts_loader_code_ix(); + ErtsCodeIndex dst = erts_staging_code_ix(); ErtsCodeIndex src = erts_active_code_ix(); Sint i; Sint n; diff --git a/erts/emulator/beam/code_ix.h b/erts/emulator/beam/code_ix.h index 43acd08ebf..1f9c47f33c 100644 --- a/erts/emulator/beam/code_ix.h +++ b/erts/emulator/beam/code_ix.h @@ -25,7 +25,7 @@ typedef unsigned ErtsCodeIndex; void erts_code_ix_init(void); ErtsCodeIndex erts_active_code_ix(void); -ErtsCodeIndex erts_loader_code_ix(void); +ErtsCodeIndex erts_staging_code_ix(void); /* Lock code_ix (enqueue and suspend until we get it) */ @@ -49,9 +49,9 @@ void erts_lock_code_ix(void); */ void erts_unlock_code_ix(void); -void erts_start_loader_code_ix(void); -void erts_commit_loader_code_ix(void); -void erts_abort_loader_code_ix(void); +void erts_start_staging_code_ix(void); +void erts_commit_staging_code_ix(void); +void erts_abort_staging_code_ix(void); void erts_rwlock_old_code(ErtsCodeIndex); void erts_rwunlock_old_code(ErtsCodeIndex); diff --git a/erts/emulator/beam/erl_init.c b/erts/emulator/beam/erl_init.c index 487c444df4..1184cb28fa 100644 --- a/erts/emulator/beam/erl_init.c +++ b/erts/emulator/beam/erl_init.c @@ -1473,7 +1473,7 @@ erl_start(int argc, char **argv) init_shared_memory(boot_argc, boot_argv); load_preloaded(); - erts_commit_loader_code_ix(); + erts_commit_staging_code_ix(); erts_initialized = 1; diff --git a/erts/emulator/beam/export.c b/erts/emulator/beam/export.c index 487d6ee963..b9dcb1fb47 100644 --- a/erts/emulator/beam/export.c +++ b/erts/emulator/beam/export.c @@ -89,7 +89,7 @@ export_info(int to, void *to_arg) export_read_lock(); #endif index_info(to, to_arg, &export_tables[erts_active_code_ix()]); - hash_info(to, to_arg, &export_tables[erts_loader_code_ix()].htable); + hash_info(to, to_arg, &export_tables[erts_staging_code_ix()].htable); #ifdef ERTS_SMP if (lock) export_read_unlock(); @@ -282,7 +282,7 @@ erts_find_function(Eterm m, Eterm f, unsigned int a, ErtsCodeIndex code_ix) Export* erts_export_put(Eterm mod, Eterm func, unsigned int arity) { - ErtsCodeIndex code_ix = erts_loader_code_ix(); + ErtsCodeIndex code_ix = erts_staging_code_ix(); struct export_templ templ; struct export_entry* ee; @@ -326,7 +326,7 @@ erts_export_get_or_make_stub(Eterm mod, Eterm func, unsigned int arity) struct export_templ templ; struct export_entry* entry; - IndexTable* tab = &export_tables[erts_loader_code_ix()]; + IndexTable* tab = &export_tables[erts_staging_code_ix()]; init_template(&templ, mod, func, arity); entry = (struct export_entry *) index_put_entry(tab, &templ.entry); ep = entry->ep; @@ -370,9 +370,9 @@ Export *export_get(Export *e) IF_DEBUG(static ErtsCodeIndex debug_start_load_ix = 0;) -void export_start_load(void) +void export_start_staging(void) { - ErtsCodeIndex dst_ix = erts_loader_code_ix(); + ErtsCodeIndex dst_ix = erts_staging_code_ix(); ErtsCodeIndex src_ix = erts_active_code_ix(); IndexTable* dst = &export_tables[dst_ix]; IndexTable* src = &export_tables[src_ix]; @@ -399,9 +399,9 @@ void export_start_load(void) IF_DEBUG(debug_start_load_ix = dst_ix); } -void export_end_load(int commit) +void export_end_staging(int commit) { - ASSERT(debug_start_load_ix == erts_loader_code_ix()); + ASSERT(debug_start_load_ix == erts_staging_code_ix()); IF_DEBUG(debug_start_load_ix = -1); } diff --git a/erts/emulator/beam/export.h b/erts/emulator/beam/export.h index 577e24f266..21cfafc77d 100644 --- a/erts/emulator/beam/export.h +++ b/erts/emulator/beam/export.h @@ -72,8 +72,8 @@ Export *export_list(int,ErtsCodeIndex); int export_list_size(ErtsCodeIndex); int export_table_sz(void); Export *export_get(Export*); -void export_start_load(void); -void export_end_load(int commit); +void export_start_staging(void); +void export_end_staging(int commit); extern erts_smp_rwmtx_t export_table_lock; #define export_write_lock() erts_smp_rwmtx_rwlock(&export_table_lock) diff --git a/erts/emulator/beam/global.h b/erts/emulator/beam/global.h index 6a3c36824b..b98f810455 100644 --- a/erts/emulator/beam/global.h +++ b/erts/emulator/beam/global.h @@ -891,8 +891,8 @@ Eterm erts_make_stub_module(Process* p, Eterm Mod, Eterm Beam, Eterm Info); /* beam_ranges.c */ void erts_init_ranges(void); -void erts_start_load_ranges(void); -void erts_end_load_ranges(int commit); +void erts_start_staging_ranges(void); +void erts_end_staging_ranges(int commit); void erts_update_ranges(BeamInstr* code, Uint size); void erts_remove_from_ranges(BeamInstr* code); UWord erts_ranges_sz(void); diff --git a/erts/emulator/beam/module.c b/erts/emulator/beam/module.c index f326aecebf..b0a3bd1fab 100644 --- a/erts/emulator/beam/module.c +++ b/erts/emulator/beam/module.c @@ -129,7 +129,7 @@ erts_put_module(Eterm mod) || erts_is_code_ix_locked() || erts_smp_thr_progress_is_blocking()); - mod_tab = &module_tables[erts_loader_code_ix()]; + mod_tab = &module_tables[erts_staging_code_ix()]; e.module = atom_val(mod); return (Module*) index_put_entry(mod_tab, (void*) &e); } @@ -155,10 +155,10 @@ static ErtsCodeIndex dbg_load_code_ix = 0; static int entries_at_start_load = 0; -void module_start_load(void) +void module_start_staging(void) { IndexTable* src = &module_tables[erts_active_code_ix()]; - IndexTable* dst = &module_tables[erts_loader_code_ix()]; + IndexTable* dst = &module_tables[erts_staging_code_ix()]; Module* src_mod; Module* dst_mod; int i; @@ -191,15 +191,15 @@ void module_start_load(void) } entries_at_start_load = dst->entries; - IF_DEBUG(dbg_load_code_ix = erts_loader_code_ix()); + IF_DEBUG(dbg_load_code_ix = erts_staging_code_ix()); } -void module_end_load(int commit) +void module_end_staging(int commit) { - ASSERT(dbg_load_code_ix == erts_loader_code_ix()); + ASSERT(dbg_load_code_ix == erts_staging_code_ix()); if (!commit) { /* abort */ - IndexTable* tab = &module_tables[erts_loader_code_ix()]; + IndexTable* tab = &module_tables[erts_staging_code_ix()]; ASSERT(entries_at_start_load <= tab->entries); index_erase_latest_from(tab, entries_at_start_load); diff --git a/erts/emulator/beam/module.h b/erts/emulator/beam/module.h index 8a87ae4952..209aa3b98a 100644 --- a/erts/emulator/beam/module.h +++ b/erts/emulator/beam/module.h @@ -43,8 +43,8 @@ Module* erts_get_module(Eterm mod, ErtsCodeIndex code_ix); Module* erts_put_module(Eterm mod); void init_module_table(void); -void module_start_load(void); -void module_end_load(int commit); +void module_start_staging(void); +void module_end_staging(int commit); void module_info(int, void *); Module *module_code(int, ErtsCodeIndex); diff --git a/erts/emulator/hipe/hipe_bif0.c b/erts/emulator/hipe/hipe_bif0.c index cb599bd682..e13d8fc182 100644 --- a/erts/emulator/hipe/hipe_bif0.c +++ b/erts/emulator/hipe/hipe_bif0.c @@ -648,7 +648,7 @@ static void *hipe_get_emu_address(Eterm m, Eterm f, unsigned int arity, int is_r /* if not found, stub it via the export entry */ /* no lock needed around erts_export_get_or_make_stub() */ Export *export_entry = erts_export_get_or_make_stub(m, f, arity); - address = export_entry->addressv[erts_loader_code_ix()]; + address = export_entry->addressv[erts_staging_code_ix()]; } return address; } -- cgit v1.2.3 From 88c771c1d69c98169ef9bc10c27ed4378854d368 Mon Sep 17 00:00:00 2001 From: Sverker Eriksson Date: Tue, 24 Jan 2012 17:08:40 +0100 Subject: erts: Cleanup code loading --- erts/emulator/beam/beam_catches.h | 2 +- erts/emulator/beam/beam_load.c | 4 ++-- erts/emulator/beam/erl_init.c | 2 +- erts/emulator/beam/export.c | 9 ++++----- erts/emulator/hipe/hipe_bif0.c | 4 ++-- 5 files changed, 10 insertions(+), 11 deletions(-) diff --git a/erts/emulator/beam/beam_catches.h b/erts/emulator/beam/beam_catches.h index 309b5cc857..4a0e070c69 100644 --- a/erts/emulator/beam/beam_catches.h +++ b/erts/emulator/beam/beam_catches.h @@ -20,7 +20,7 @@ #ifndef __BEAM_CATCHES_H #define __BEAM_CATCHES_H -#include "global.h" /*SVERK the code_ix stuff */ +#include "code_ix.h" #define BEAM_CATCHES_NIL (-1) diff --git a/erts/emulator/beam/beam_load.c b/erts/emulator/beam/beam_load.c index d393ff6a34..4ac426fc9e 100644 --- a/erts/emulator/beam/beam_load.c +++ b/erts/emulator/beam/beam_load.c @@ -1240,7 +1240,7 @@ load_import_table(LoaderState* stp) * If the export entry refers to a BIF, get the pointer to * the BIF function. */ - if ((e = erts_active_export_entry(mod, func, arity)) != NULL) { /*SVERK does it matter which one we use? */ + if ((e = erts_active_export_entry(mod, func, arity)) != NULL) { if (e->code[3] == (BeamInstr) em_apply_bif) { stp->import[i].bf = (BifFunction) e->code[4]; if (func == am_load_nif && mod == am_erlang && arity == 2) { @@ -5952,7 +5952,7 @@ static erts_smp_atomic32_t the_loader_code_index; static erts_smp_mtx_t sverk_code_ix_lock; /*SVERK FIXME */ static erts_smp_rwmtx_t the_old_code_rwlocks[ERTS_NUM_CODE_IX]; -#ifdef DEBUG +#if 0 # define CIX_TRACE(text) erts_fprintf(stderr, "CIX_TRACE: " text " act=%u load=%u\r\n", erts_active_code_ix(), erts_staging_code_ix()) #else # define CIX_TRACE(text) diff --git a/erts/emulator/beam/erl_init.c b/erts/emulator/beam/erl_init.c index 1184cb28fa..2d192b3fc4 100644 --- a/erts/emulator/beam/erl_init.c +++ b/erts/emulator/beam/erl_init.c @@ -236,7 +236,7 @@ void erl_error(char *fmt, va_list args) static int early_init(int *argc, char **argv); void -erts_short_init_SVERK_SAYS_NOT_USED(void) +erts_short_init(void) { int ncpu = early_init(NULL, NULL); erl_init(ncpu); diff --git a/erts/emulator/beam/export.c b/erts/emulator/beam/export.c index b9dcb1fb47..4a2a77a527 100644 --- a/erts/emulator/beam/export.c +++ b/erts/emulator/beam/export.c @@ -274,9 +274,8 @@ erts_find_function(Eterm m, Eterm f, unsigned int a, ErtsCodeIndex code_ix) * Returns a pointer to an existing export entry for a MFA, * or creates a new one and returns the pointer. * - * This function provides unlocked write access to the main export - * table. It should only be used during start up or when - * all other threads are blocked. + * This function acts on the staging export table. It should only be used + * to load new code. */ Export* @@ -318,11 +317,11 @@ erts_export_get_or_make_stub(Eterm mod, Eterm func, unsigned int arity) ep = erts_find_export_entry(mod, func, arity, code_ix); if (ep == 0) { /* - * The code is not loaded (yet). Put the export in the loader + * The code is not loaded (yet). Put the export in the staging * export table, to avoid having to lock the active export table. */ export_write_lock(); - if (erts_active_code_ix() == code_ix) { /*SVERK barrier? */ + if (erts_active_code_ix() == code_ix) { struct export_templ templ; struct export_entry* entry; diff --git a/erts/emulator/hipe/hipe_bif0.c b/erts/emulator/hipe/hipe_bif0.c index e13d8fc182..ad1552e7eb 100644 --- a/erts/emulator/hipe/hipe_bif0.c +++ b/erts/emulator/hipe/hipe_bif0.c @@ -609,7 +609,7 @@ static Uint *hipe_find_emu_address(Eterm mod, Eterm name, unsigned int arity) Uint *code_base; int i, n; - modp = erts_get_module(mod, erts_active_code_ix()); /*SVERK ?? */ + modp = erts_get_module(mod, erts_active_code_ix()); if (modp == NULL || (code_base = modp->curr.code) == NULL) return NULL; n = code_base[MI_NUM_FUNCTIONS]; @@ -1591,7 +1591,7 @@ BIF_RETTYPE hipe_nonclosure_address(BIF_ALIST_2) f = tp[2]; if (is_not_atom(m) || is_not_atom(f)) goto badfun; - if (!erts_active_export_entry(m, f, BIF_ARG_2)) /*SVERK active? */ + if (!erts_active_export_entry(m, f, BIF_ARG_2)) goto badfun; } else goto badfun; -- cgit v1.2.3 From c7b1e15aede41dc2a3d3486dad172c88b7b4bd36 Mon Sep 17 00:00:00 2001 From: Sverker Eriksson Date: Tue, 24 Jan 2012 17:09:38 +0100 Subject: erts: Fix print-bug in lock checker on debug-vm --- erts/emulator/beam/erl_lock_check.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/erts/emulator/beam/erl_lock_check.c b/erts/emulator/beam/erl_lock_check.c index 062e78b806..772d3a03b2 100644 --- a/erts/emulator/beam/erl_lock_check.c +++ b/erts/emulator/beam/erl_lock_check.c @@ -445,7 +445,7 @@ print_lock2(char *prefix, Sint16 id, Wterm extra, Uint16 flags, char *suffix) "%s'%s:%p%s'%s%s", prefix, lname, - boxed_val(extra), + _unchecked_boxed_val(extra), lock_type(flags), rw_op_str(flags), suffix); -- cgit v1.2.3 From 605c7c1bafc72b0cc3a6ee6110abf8676b6b287f Mon Sep 17 00:00:00 2001 From: Sverker Eriksson Date: Wed, 25 Jan 2012 20:49:55 +0100 Subject: test: Force emulator/test/mtx_SUITE to rebuild NIF library This will prevent test to fail when switching between opt and debug emulator. --- erts/emulator/test/mtx_SUITE_data/Makefile.src | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/erts/emulator/test/mtx_SUITE_data/Makefile.src b/erts/emulator/test/mtx_SUITE_data/Makefile.src index b6c843269c..37eb1daa72 100644 --- a/erts/emulator/test/mtx_SUITE_data/Makefile.src +++ b/erts/emulator/test/mtx_SUITE_data/Makefile.src @@ -27,4 +27,11 @@ LIBS = @ERTS_LIBS@ all: $(NIF_LIBS) +mtx_SUITE.c: force_rebuild + touch mtx_SUITE.c + +force_rebuild: + echo "Force rebuild to compensate for emulator type dependencies" + + @SHLIB_RULES@ -- cgit v1.2.3 From e60c9cd4356a91c10657b5de86af8279ccd6eb79 Mon Sep 17 00:00:00 2001 From: Sverker Eriksson Date: Thu, 26 Jan 2012 16:25:26 +0100 Subject: erts: Move number-of-breakpoint counter from code to Module struct The is a refactoring in preparation to add a counter in Module struct for export entry tracing. It is nicer if the two are kept together. --- erts/emulator/beam/beam_bif_load.c | 8 ++++---- erts/emulator/beam/beam_bp.c | 6 +++--- erts/emulator/beam/beam_load.c | 3 --- erts/emulator/beam/beam_load.h | 17 ++++++----------- erts/emulator/beam/module.c | 2 ++ erts/emulator/beam/module.h | 1 + 6 files changed, 16 insertions(+), 21 deletions(-) diff --git a/erts/emulator/beam/beam_bif_load.c b/erts/emulator/beam/beam_bif_load.c index c14b86f811..4265f139df 100644 --- a/erts/emulator/beam/beam_bif_load.c +++ b/erts/emulator/beam/beam_bif_load.c @@ -826,8 +826,8 @@ static void ensure_no_breakpoints(Process *c_p, ErtsProcLocks c_p_locks, ErtsCodeIndex code_ix = erts_active_code_ix(); Module* modp = erts_get_module(module, code_ix); - if (modp && modp->curr.code != NULL - && modp->curr.code[MI_NUM_BREAKPOINTS] > 0) { + if (modp && modp->curr.num_breakpoints > 0) { + ASSERT(modp->curr.code != NULL); #ifdef ERTS_ENABLE_LOCK_CHECK #ifdef ERTS_SMP if (c_p && c_p_locks) @@ -840,7 +840,7 @@ static void ensure_no_breakpoints(Process *c_p, ErtsProcLocks c_p_locks, erts_smp_proc_unlock(c_p, ERTS_PROC_LOCK_MAIN); erts_smp_thr_progress_block(); erts_clear_module_break(modp); - modp->curr.code[MI_NUM_BREAKPOINTS] = 0; + modp->curr.num_breakpoints = 0; erts_smp_thr_progress_unblock(); if (c_p && c_p_locks) erts_smp_proc_lock(c_p, ERTS_PROC_LOCK_MAIN); @@ -854,7 +854,7 @@ static void ensure_no_breakpoints(Process *c_p, ErtsProcLocks c_p_locks, static void delete_code(Process *c_p, ErtsProcLocks c_p_locks, Module* modp) { - ASSERT(!(modp->curr.code && modp->curr.code[MI_NUM_BREAKPOINTS] > 0)); + ASSERT(modp->curr.num_breakpoints == 0); modp->old = modp->curr; modp->curr.code = NULL; modp->curr.code_length = 0; diff --git a/erts/emulator/beam/beam_bp.c b/erts/emulator/beam/beam_bp.c index 30c458244b..ef48d7d05e 100644 --- a/erts/emulator/beam/beam_bp.c +++ b/erts/emulator/beam/beam_bp.c @@ -1099,7 +1099,7 @@ static int set_function_break(Module *modp, BeamInstr *pc, int bif, } if (bif == BREAK_IS_ERL) { - ++(*(BeamInstr*)&code_base[MI_NUM_BREAKPOINTS]); + ++modp->curr.num_breakpoints; } return 1; } @@ -1276,8 +1276,8 @@ static int clear_function_break(Module *m, BeamInstr *pc, int bif, BeamInstr bre } Free(bd); if (bif == BREAK_IS_ERL) { - ASSERT(((BeamInstr) code_base[MI_NUM_BREAKPOINTS]) > 0); - --(*(BeamInstr*)&code_base[MI_NUM_BREAKPOINTS]); + ASSERT(m->curr.num_breakpoints > 0); + --m->curr.num_breakpoints; } if (*rs) { for (ix = 1; ix < erts_no_schedulers; ++ix) { diff --git a/erts/emulator/beam/beam_load.c b/erts/emulator/beam/beam_load.c index 4ac426fc9e..e966f423ec 100644 --- a/erts/emulator/beam/beam_load.c +++ b/erts/emulator/beam/beam_load.c @@ -643,8 +643,6 @@ erts_prepare_loading(LoaderState* stp, Process *c_p, Eterm group_leader, stp->code[MI_COMPILE_PTR] = 0; stp->code[MI_COMPILE_SIZE] = 0; stp->code[MI_COMPILE_SIZE_ON_HEAP] = 0; - stp->code[MI_NUM_BREAKPOINTS] = 0; - /* * Read the atom table. @@ -5811,7 +5809,6 @@ erts_make_stub_module(Process* p, Eterm Mod, Eterm Beam, Eterm Info) code[MI_COMPILE_PTR] = 0; code[MI_COMPILE_SIZE] = 0; code[MI_COMPILE_SIZE_ON_HEAP] = 0; - code[MI_NUM_BREAKPOINTS] = 0; code[MI_LITERALS_START] = 0; code[MI_LITERALS_END] = 0; code[MI_LITERALS_OFF_HEAP] = 0; diff --git a/erts/emulator/beam/beam_load.h b/erts/emulator/beam/beam_load.h index 9da692625b..0f6ad35cbc 100644 --- a/erts/emulator/beam/beam_load.h +++ b/erts/emulator/beam/beam_load.h @@ -88,28 +88,23 @@ extern Uint erts_total_code_size; #define MI_COMPILE_SIZE 5 #define MI_COMPILE_SIZE_ON_HEAP 6 -/* - * Number of breakpoints in module is stored in this word - */ -#define MI_NUM_BREAKPOINTS 7 - /* * Literal area (constant pool). */ -#define MI_LITERALS_START 8 -#define MI_LITERALS_END 9 -#define MI_LITERALS_OFF_HEAP 10 +#define MI_LITERALS_START 7 +#define MI_LITERALS_END 8 +#define MI_LITERALS_OFF_HEAP 9 /* * Pointer to the on_load function (or NULL if none). */ -#define MI_ON_LOAD_FUNCTION_PTR 11 +#define MI_ON_LOAD_FUNCTION_PTR 10 /* * Pointer to the line table (or NULL if none). */ -#define MI_LINE_TABLE 12 +#define MI_LINE_TABLE 11 /* * Start of function pointer table. This table contains pointers to @@ -120,7 +115,7 @@ extern Uint erts_total_code_size; * this table. */ -#define MI_FUNCTIONS 13 +#define MI_FUNCTIONS 12 /* * Layout of the line table. diff --git a/erts/emulator/beam/module.c b/erts/emulator/beam/module.c index b0a3bd1fab..4174f59446 100644 --- a/erts/emulator/beam/module.c +++ b/erts/emulator/beam/module.c @@ -74,6 +74,8 @@ static Module* module_alloc(Module* tmpl) obj->slot.index = -1; obj->curr.nif = NULL; obj->old.nif = NULL; + obj->curr.num_breakpoints = 0; + obj->old.num_breakpoints = 0; return obj; } diff --git a/erts/emulator/beam/module.h b/erts/emulator/beam/module.h index 209aa3b98a..8c09b3628d 100644 --- a/erts/emulator/beam/module.h +++ b/erts/emulator/beam/module.h @@ -29,6 +29,7 @@ struct erl_module_instance { int code_length; /* Length of loaded code in bytes. */ unsigned catches; struct erl_module_nif* nif; + int num_breakpoints; }; typedef struct erl_module { -- cgit v1.2.3 From cd366260e689d97845c56f30ef960853099465ab Mon Sep 17 00:00:00 2001 From: Sverker Eriksson Date: Thu, 26 Jan 2012 19:34:22 +0100 Subject: erts: Keep count of number of global traced functions per module --- erts/emulator/beam/beam_bif_load.c | 46 ++++++++++++++++---------------------- erts/emulator/beam/erl_bif_trace.c | 12 +++++++++- erts/emulator/beam/module.c | 2 ++ erts/emulator/beam/module.h | 1 + 4 files changed, 33 insertions(+), 28 deletions(-) diff --git a/erts/emulator/beam/beam_bif_load.c b/erts/emulator/beam/beam_bif_load.c index 4265f139df..6694f3ae87 100644 --- a/erts/emulator/beam/beam_bif_load.c +++ b/erts/emulator/beam/beam_bif_load.c @@ -38,8 +38,7 @@ static void set_default_trace_pattern(Eterm module, ErtsCodeIndex); static Eterm check_process_code(Process* rp, Module* modp); static void ensure_no_breakpoints(Process *, ErtsProcLocks, Eterm module); -static void delete_code(Process *c_p, ErtsProcLocks c_p_locks, Module* modp); -static void delete_export_references(Eterm module); +static void delete_code(Module* modp); static int purge_module(Process*, int module); static void decrement_refc(BeamInstr* code); static int is_native(BeamInstr* code); @@ -309,8 +308,7 @@ BIF_RETTYPE delete_module_1(BIF_ALIST_1) res = am_badarg; } else { - delete_export_references(BIF_ARG_1); - delete_code(BIF_P, 0, modp); + delete_code(modp); res = am_true; } } @@ -848,32 +846,16 @@ static void ensure_no_breakpoints(Process *c_p, ErtsProcLocks c_p_locks, } /* - * Move code from current to old. + * Move code from current to old and null all export entries for the module */ static void -delete_code(Process *c_p, ErtsProcLocks c_p_locks, Module* modp) -{ - ASSERT(modp->curr.num_breakpoints == 0); - modp->old = modp->curr; - modp->curr.code = NULL; - modp->curr.code_length = 0; - modp->curr.catches = BEAM_CATCHES_NIL; - modp->curr.nif = NULL; -} - - -/* null all references on the export table for the module called with the - atom index below */ - -static void -delete_export_references(Eterm module) +delete_code(Module* modp) { ErtsCodeIndex code_ix = erts_staging_code_ix(); + Eterm module = make_atom(modp->module); int i; - ASSERT(is_atom(module)); - for (i = 0; i < export_list_size(code_ix); i++) { Export *ep = export_list(i, code_ix); if (ep != NULL && (ep->code[0] == module)) { @@ -882,15 +864,26 @@ delete_export_references(Eterm module) continue; } ep->addressv[code_ix] = ep->code+3; - ASSERT(ep->code[3] != (BeamInstr) em_call_traced_function); /*SVERK What to do now? */ + if (ep->code[3] == (BeamInstr) em_call_traced_function) { + ASSERT(modp->curr.num_traced_exports > 0); + --modp->curr.num_traced_exports; + } ep->code[3] = (BeamInstr) em_call_error_handler; ep->code[4] = 0; MatchSetUnref(ep->match_prog_set); ep->match_prog_set = NULL; } } + + ASSERT(modp->curr.num_breakpoints == 0); + ASSERT(modp->curr.num_traced_exports == 0); + modp->old = modp->curr; + modp->curr.code = NULL; + modp->curr.code_length = 0; + modp->curr.catches = BEAM_CATCHES_NIL; + modp->curr.nif = NULL; } - + Eterm beam_make_current_old(Process *c_p, ErtsProcLocks c_p_locks, Eterm module) @@ -905,8 +898,7 @@ beam_make_current_old(Process *c_p, ErtsProcLocks c_p_locks, Eterm module) if (modp->curr.code != NULL && modp->old.code != NULL) { return am_not_purged; } else if (modp->old.code == NULL) { /* Make the current version old. */ - delete_code(c_p, c_p_locks, modp); - delete_export_references(module); + delete_code(modp); } return NIL; } diff --git a/erts/emulator/beam/erl_bif_trace.c b/erts/emulator/beam/erl_bif_trace.c index cb43069fa9..24b16b9679 100644 --- a/erts/emulator/beam/erl_bif_trace.c +++ b/erts/emulator/beam/erl_bif_trace.c @@ -1526,6 +1526,8 @@ erts_set_trace_pattern(Eterm* mfa, int specified, static int setup_func_trace(Export* ep, void* match_prog, ErtsCodeIndex code_ix) { + Module* modp; + if (ep->addressv[code_ix] == ep->code+3) { if (ep->code[3] == (BeamInstr) em_call_error_handler) { return 0; @@ -1548,12 +1550,16 @@ setup_func_trace(Export* ep, void* match_prog, ErtsCodeIndex code_ix) if (erts_is_native_break(ep->addressv[code_ix])) { return 0; } - + ep->code[3] = (BeamInstr) em_call_traced_function; ep->code[4] = (BeamInstr) ep->addressv[code_ix]; ep->addressv[code_ix] = ep->code+3; ep->match_prog_set = match_prog; MatchSetRef(ep->match_prog_set); + + modp = erts_get_module(ep->code[0], code_ix); + ASSERT(modp); + modp->curr.num_traced_exports++; return 1; } @@ -1592,6 +1598,10 @@ reset_func_trace(Export* ep, ErtsCodeIndex code_ix) if (ep->code[3] == (BeamInstr) em_call_error_handler) { return 0; } else if (ep->code[3] == (BeamInstr) em_call_traced_function) { + Module* modp = erts_get_module(ep->code[0], code_ix); + ASSERT(modp); + modp->curr.num_traced_exports--; + ep->addressv[code_ix] = (Uint *) ep->code[4]; MatchSetUnref(ep->match_prog_set); ep->match_prog_set = NULL; diff --git a/erts/emulator/beam/module.c b/erts/emulator/beam/module.c index 4174f59446..26c73fff1a 100644 --- a/erts/emulator/beam/module.c +++ b/erts/emulator/beam/module.c @@ -76,6 +76,8 @@ static Module* module_alloc(Module* tmpl) obj->old.nif = NULL; obj->curr.num_breakpoints = 0; obj->old.num_breakpoints = 0; + obj->curr.num_traced_exports = 0; + obj->old.num_traced_exports = 0; return obj; } diff --git a/erts/emulator/beam/module.h b/erts/emulator/beam/module.h index 8c09b3628d..d63cf56778 100644 --- a/erts/emulator/beam/module.h +++ b/erts/emulator/beam/module.h @@ -30,6 +30,7 @@ struct erl_module_instance { unsigned catches; struct erl_module_nif* nif; int num_breakpoints; + int num_traced_exports; }; typedef struct erl_module { -- cgit v1.2.3 From 0248726417f6c0c709a85c0db930220de5541b9d Mon Sep 17 00:00:00 2001 From: Sverker Eriksson Date: Fri, 27 Jan 2012 19:05:31 +0100 Subject: erts: Fallback to blocking upgrade when tracing is enabled --- erts/emulator/beam/beam_bif_load.c | 166 +++++++++++---------- erts/emulator/beam/erl_bif_trace.c | 5 +- erts/emulator/beam/global.h | 1 + erts/emulator/test/call_trace_SUITE.erl | 120 ++++++++++++++- .../test/call_trace_SUITE_data/my_upgrade_test.erl | 26 ++++ 5 files changed, 238 insertions(+), 80 deletions(-) create mode 100644 erts/emulator/test/call_trace_SUITE_data/my_upgrade_test.erl diff --git a/erts/emulator/beam/beam_bif_load.c b/erts/emulator/beam/beam_bif_load.c index 6694f3ae87..8d41c7499d 100644 --- a/erts/emulator/beam/beam_bif_load.c +++ b/erts/emulator/beam/beam_bif_load.c @@ -37,7 +37,6 @@ static void set_default_trace_pattern(Eterm module, ErtsCodeIndex); static Eterm check_process_code(Process* rp, Module* modp); -static void ensure_no_breakpoints(Process *, ErtsProcLocks, Eterm module); static void delete_code(Module* modp); static int purge_module(Process*, int module); static void decrement_refc(BeamInstr* code); @@ -55,6 +54,7 @@ load_module_2(BIF_ALIST_2) Eterm res; byte* temp_alloc = NULL; struct LoaderState* stp; + int is_blocking = 0; if (is_not_atom(BIF_ARG_1)) { error: @@ -79,18 +79,32 @@ load_module_2(BIF_ALIST_2) BIF_RET(res); } - /*SVERK - * Stop all other processes and finish the loading of the module. - * - erts_smp_proc_unlock(BIF_P, ERTS_PROC_LOCK_MAIN); - erts_smp_thr_progress_block();*/ - - ensure_no_breakpoints(BIF_P, 0, BIF_ARG_1); - erts_lock_code_ix(); - erts_start_staging_code_ix(); + for(;;) { + Module* modp; + erts_start_staging_code_ix(); + modp = erts_put_module(BIF_ARG_1); + if (!is_blocking) { + if (modp->curr.num_breakpoints > 0 + || modp->curr.num_traced_exports > 0 + || erts_is_default_trace_enabled()) { + /* we have tracing, retry single threaded */ + erts_abort_staging_code_ix(); + erts_unlock_code_ix(); + erts_smp_proc_unlock(BIF_P, ERTS_PROC_LOCK_MAIN); + erts_smp_thr_progress_block(); + is_blocking = 1; + continue; + } + } + else if (modp->curr.num_breakpoints) { + erts_clear_module_break(modp); + ASSERT(modp->curr.num_breakpoints == 0); + } + reason = erts_finish_loading(stp, BIF_P, 0, &BIF_ARG_1); + break; + } - reason = erts_finish_loading(stp, BIF_P, 0, &BIF_ARG_1); if (reason != NIL) { if (reason == am_on_load) { erts_commit_staging_code_ix(); @@ -105,11 +119,13 @@ load_module_2(BIF_ALIST_2) res = TUPLE2(hp, am_module, BIF_ARG_1); } - erts_unlock_code_ix(); - - /*SVERK - erts_smp_thr_progress_unblock(); - erts_smp_proc_lock(BIF_P, ERTS_PROC_LOCK_MAIN);*/ + if (is_blocking) { + erts_smp_thr_progress_unblock(); + erts_smp_proc_lock(BIF_P, ERTS_PROC_LOCK_MAIN); + } + else { + erts_unlock_code_ix(); + } BIF_RET(res); } @@ -162,17 +178,20 @@ BIF_RETTYPE code_is_module_native_1(BIF_ALIST_1) BIF_RETTYPE code_make_stub_module_3(BIF_ALIST_3) { + Module* modp; Eterm res; - /*SVERK erts_smp_proc_unlock(BIF_P, ERTS_PROC_LOCK_MAIN); erts_smp_thr_progress_block(); - erts_export_consolidate(erts_active_code_ix());*/ + modp = erts_get_module(BIF_ARG_1, erts_active_code_ix()); - ensure_no_breakpoints(BIF_P, 0, BIF_ARG_1); + if (modp && modp->curr.num_breakpoints > 0) { + ASSERT(modp->curr.code != NULL); + erts_clear_module_break(modp); + ASSERT(modp->curr.num_breakpoints == 0); + } - erts_lock_code_ix(); erts_start_staging_code_ix(); res = erts_make_stub_module(BIF_P, BIF_ARG_1, BIF_ARG_2, BIF_ARG_3); @@ -183,11 +202,8 @@ BIF_RETTYPE code_make_stub_module_3(BIF_ALIST_3) else { erts_abort_staging_code_ix(); } - erts_unlock_code_ix(); - - /*SVERK erts_smp_thr_progress_unblock(); - erts_smp_proc_lock(BIF_P, ERTS_PROC_LOCK_MAIN);*/ + erts_smp_proc_lock(BIF_P, ERTS_PROC_LOCK_MAIN); return res; } @@ -281,7 +297,9 @@ check_process_code_2(BIF_ALIST_2) BIF_RETTYPE delete_module_1(BIF_ALIST_1) { ErtsCodeIndex code_ix; - int res; + Module* modp; + int is_blocking = 0; + Eterm res = NIL; if (is_not_atom(BIF_ARG_1)) goto badarg; @@ -290,13 +308,11 @@ BIF_RETTYPE delete_module_1(BIF_ALIST_1) erts_smp_proc_unlock(BIF_P, ERTS_PROC_LOCK_MAIN); erts_smp_thr_progress_block();*/ - ensure_no_breakpoints(BIF_P, 0, BIF_ARG_1); - erts_lock_code_ix(); - erts_start_staging_code_ix(); - code_ix = erts_staging_code_ix(); - { - Module *modp = erts_get_module(BIF_ARG_1, code_ix); + do { + erts_start_staging_code_ix(); + code_ix = erts_staging_code_ix(); + modp = erts_get_module(BIF_ARG_1, code_ix); if (!modp) { res = am_undefined; } @@ -308,10 +324,26 @@ BIF_RETTYPE delete_module_1(BIF_ALIST_1) res = am_badarg; } else { + if (!is_blocking) { + if (modp->curr.num_breakpoints > 0 || + modp->curr.num_traced_exports > 0) { + /* we have tracing, retry single threaded */ + erts_abort_staging_code_ix(); + erts_unlock_code_ix(); + erts_smp_proc_unlock(BIF_P, ERTS_PROC_LOCK_MAIN); + erts_smp_thr_progress_block(); + is_blocking = 1; + continue; + } + } + else if (modp->curr.num_breakpoints) { + erts_clear_module_break(modp); + ASSERT(modp->curr.num_breakpoints == 0); + } delete_code(modp); res = am_true; } - } + } while (res == NIL); if (res == am_true) { erts_commit_staging_code_ix(); @@ -319,7 +351,13 @@ BIF_RETTYPE delete_module_1(BIF_ALIST_1) else { erts_abort_staging_code_ix(); } - erts_unlock_code_ix(); + if (is_blocking) { + erts_smp_thr_progress_unblock(); + erts_smp_proc_lock(BIF_P, ERTS_PROC_LOCK_MAIN); + } + else { + erts_unlock_code_ix(); + } /*SVERK erts_smp_thr_progress_unblock(); @@ -725,7 +763,7 @@ purge_module(Process* c_p, int module) BeamInstr* code; BeamInstr* end; Module* modp; - int is_blocked = 0; + int is_blocking = 0; int ret; erts_lock_code_ix(); @@ -753,13 +791,13 @@ retry: * Unload any NIF library */ if (modp->old.nif != NULL) { - if (!is_blocked) { + if (!is_blocking) { /*SVERK Do unload nif without blocking */ erts_rwunlock_old_code(code_ix); erts_unlock_code_ix(); erts_smp_proc_unlock(c_p, ERTS_PROC_LOCK_MAIN); erts_smp_thr_progress_block(); - is_blocked = 1; + is_blocking = 1; goto retry; } @@ -787,7 +825,7 @@ retry: } erts_rwunlock_old_code(code_ix); } - if (is_blocked) { + if (is_blocking) { erts_smp_thr_progress_unblock(); erts_smp_proc_lock(c_p, ERTS_PROC_LOCK_MAIN); } @@ -814,37 +852,6 @@ decrement_refc(BeamInstr* code) } } - -/* - * Clear breakpoints in module if any - */ -static void ensure_no_breakpoints(Process *c_p, ErtsProcLocks c_p_locks, - Eterm module) -{ - ErtsCodeIndex code_ix = erts_active_code_ix(); - Module* modp = erts_get_module(module, code_ix); - - if (modp && modp->curr.num_breakpoints > 0) { - ASSERT(modp->curr.code != NULL); -#ifdef ERTS_ENABLE_LOCK_CHECK -#ifdef ERTS_SMP - if (c_p && c_p_locks) - erts_proc_lc_chk_only_proc_main(c_p); - else -#endif - erts_lc_check_exact(NULL, 0); -#endif - if (c_p && c_p_locks) - erts_smp_proc_unlock(c_p, ERTS_PROC_LOCK_MAIN); - erts_smp_thr_progress_block(); - erts_clear_module_break(modp); - modp->curr.num_breakpoints = 0; - erts_smp_thr_progress_unblock(); - if (c_p && c_p_locks) - erts_smp_proc_lock(c_p, ERTS_PROC_LOCK_MAIN); - } -} - /* * Move code from current to old and null all export entries for the module */ @@ -859,19 +866,24 @@ delete_code(Module* modp) for (i = 0; i < export_list_size(code_ix); i++) { Export *ep = export_list(i, code_ix); if (ep != NULL && (ep->code[0] == module)) { - if (ep->addressv[code_ix] == ep->code+3 && - (ep->code[3] == (BeamInstr) em_apply_bif)) { - continue; + if (ep->addressv[code_ix] == ep->code+3) { + if (ep->code[3] == (BeamInstr) em_apply_bif) { + continue; + } + else if (ep->code[3] == (BeamInstr) em_call_traced_function) { + ERTS_SMP_LC_ASSERT(erts_smp_thr_progress_is_blocking()); + ASSERT(modp->curr.num_traced_exports > 0); + --modp->curr.num_traced_exports; + MatchSetUnref(ep->match_prog_set); + ep->match_prog_set = NULL; + } + else ASSERT(ep->code[3] == (BeamInstr) em_call_error_handler + || !erts_initialized); } ep->addressv[code_ix] = ep->code+3; - if (ep->code[3] == (BeamInstr) em_call_traced_function) { - ASSERT(modp->curr.num_traced_exports > 0); - --modp->curr.num_traced_exports; - } ep->code[3] = (BeamInstr) em_call_error_handler; ep->code[4] = 0; - MatchSetUnref(ep->match_prog_set); - ep->match_prog_set = NULL; + ASSERT(ep->match_prog_set == NULL); } } diff --git a/erts/emulator/beam/erl_bif_trace.c b/erts/emulator/beam/erl_bif_trace.c index 24b16b9679..203ba9004b 100644 --- a/erts/emulator/beam/erl_bif_trace.c +++ b/erts/emulator/beam/erl_bif_trace.c @@ -373,7 +373,10 @@ erts_get_default_trace_pattern(int *trace_pattern_is_on, *meta_tracer_pid = erts_default_meta_tracer_pid; } - +int erts_is_default_trace_enabled(void) +{ + return erts_default_trace_pattern_is_on; +} Uint erts_trace_flag2bit(Eterm flag) diff --git a/erts/emulator/beam/global.h b/erts/emulator/beam/global.h index b98f810455..580336470c 100644 --- a/erts/emulator/beam/global.h +++ b/erts/emulator/beam/global.h @@ -1773,6 +1773,7 @@ erts_get_default_trace_pattern(int *trace_pattern_is_on, Binary **meta_match_spec, struct trace_pattern_flags *trace_pattern_flags, Eterm *meta_tracer_pid); +int erts_is_default_trace_enabled(void); void erts_bif_trace_init(void); /* diff --git a/erts/emulator/test/call_trace_SUITE.erl b/erts/emulator/test/call_trace_SUITE.erl index 7030ebed3f..67212cd469 100644 --- a/erts/emulator/test/call_trace_SUITE.erl +++ b/erts/emulator/test/call_trace_SUITE.erl @@ -25,6 +25,7 @@ init_per_testcase/2,end_per_testcase/2, hipe/1,process_specs/1,basic/1,flags/1,errors/1,pam/1,change_pam/1, return_trace/1,exception_trace/1,on_load/1,deep_exception/1, + upgrade/1, exception_nocatch/1,bit_syntax/1]). %% Helper functions. @@ -46,6 +47,7 @@ suite() -> [{ct_hooks,[ts_install_cth]}]. all() -> Common = [errors, on_load], NotHipe = [process_specs, basic, flags, pam, change_pam, + upgrade, return_trace, exception_trace, deep_exception, exception_nocatch, bit_syntax], Hipe = [hipe], @@ -267,6 +269,118 @@ foo() -> foo0. foo(X) -> X+1. foo(X, Y) -> X+Y. + +%% Note that the semantics that this test case verifies +%% are not explicitly specified in the docs (what I could find in R15B). +%% This test case was written to verify that we do not change +%% any behaviour with the introduction of "block-free" upgrade in R16. +%% In short: Do not refer to this test case as an authority of how it must work. +upgrade(doc) -> + "Test tracing on module being upgraded"; +upgrade(Config) when is_list(Config) -> + V1 = compile_version(my_upgrade_test, 1, Config), + V2 = compile_version(my_upgrade_test, 2, Config), + start_tracer(), + upgrade_do(V1, V2, false), + upgrade_do(V1, V2, true). + +upgrade_do(V1, V2, TraceLocalVersion) -> + {module,my_upgrade_test} = erlang:load_module(my_upgrade_test, V1), + + + %% Test that trace is cleared after load_module + + trace_func({my_upgrade_test,'_','_'}, [], [global]), + case TraceLocalVersion of + true -> trace_func({my_upgrade_test,local_version,0}, [], [local]); + _ -> ok + end, + 1 = my_upgrade_test:version(), + 1 = my_upgrade_test:do_local(), + 1 = my_upgrade_test:do_real_local(), + put('F1_exp', my_upgrade_test:make_fun_exp()), + put('F1_loc', my_upgrade_test:make_fun_local()), + 1 = (get('F1_exp'))(), + 1 = (get('F1_loc'))(), + + Self = self(), + expect({trace,Self,call,{my_upgrade_test,version,[]}}), + expect({trace,Self,call,{my_upgrade_test,do_local,[]}}), + expect({trace,Self,call,{my_upgrade_test,do_real_local,[]}}), + case TraceLocalVersion of + true -> expect({trace,Self,call,{my_upgrade_test,local_version,[]}}); + _ -> ok + end, + expect({trace,Self,call,{my_upgrade_test,make_fun_exp,[]}}), + expect({trace,Self,call,{my_upgrade_test,make_fun_local,[]}}), + expect({trace,Self,call,{my_upgrade_test,version,[]}}), % F1_exp + case TraceLocalVersion of + true -> expect({trace,Self,call,{my_upgrade_test,local_version,[]}}); % F1_loc + _ -> ok + end, + + {module,my_upgrade_test} = erlang:load_module(my_upgrade_test, V2), + 2 = my_upgrade_test:version(), + put('F2_exp', my_upgrade_test:make_fun_exp()), + put('F2_loc', my_upgrade_test:make_fun_local()), + 2 = (get('F1_exp'))(), + 1 = (get('F1_loc'))(), + 2 = (get('F2_exp'))(), + 2 = (get('F2_loc'))(), + expect(), + + put('F1_exp', undefined), + put('F1_loc', undefined), + erlang:garbage_collect(), + erlang:purge_module(my_upgrade_test), + + % Test that trace is cleared after delete_module + + trace_func({my_upgrade_test,'_','_'}, [], [global]), + case TraceLocalVersion of + true -> trace_func({my_upgrade_test,local_version,0}, [], [local]); + _ -> ok + end, + 2 = my_upgrade_test:version(), + 2 = my_upgrade_test:do_local(), + 2 = my_upgrade_test:do_real_local(), + 2 = (get('F2_exp'))(), + 2 = (get('F2_loc'))(), + + expect({trace,Self,call,{my_upgrade_test,version,[]}}), + expect({trace,Self,call,{my_upgrade_test,do_local,[]}}), + expect({trace,Self,call,{my_upgrade_test,do_real_local,[]}}), + case TraceLocalVersion of + true -> expect({trace,Self,call,{my_upgrade_test,local_version,[]}}); + _ -> ok + end, + expect({trace,Self,call,{my_upgrade_test,version,[]}}), % F2_exp + case TraceLocalVersion of + true -> expect({trace,Self,call,{my_upgrade_test,local_version,[]}}); % F2_loc + _ -> ok + end, + + true = erlang:delete_module(my_upgrade_test), + {'EXIT',{undef,_}} = (catch my_upgrade_test:version()), + {'EXIT',{undef,_}} = (catch ((get('F2_exp'))())), + 2 = (get('F2_loc'))(), + expect(), + + put('F2_exp', undefined), + put('F2_loc', undefined), + erlang:garbage_collect(), + erlang:purge_module(my_upgrade_test), + ok. + +compile_version(Module, Version, Config) -> + Data = ?config(data_dir, Config), + File = filename:join(Data, atom_to_list(Module)), + {ok,Module,Bin} = compile:file(File, [{d,'VERSION',Version}, + binary,report]), + Bin. + + + %% Test flags (arity, timestamp) for call_trace/3. %% Also, test the '{tracer,Pid}' option. flags(_Config) -> @@ -1151,11 +1265,13 @@ trace_info(What, Key) -> Res. trace_func(MFA, MatchSpec) -> - get(tracer) ! {apply,self(),{erlang,trace_pattern,[MFA, MatchSpec]}}, + trace_func(MFA, MatchSpec, []). +trace_func(MFA, MatchSpec, Flags) -> + get(tracer) ! {apply,self(),{erlang,trace_pattern,[MFA, MatchSpec, Flags]}}, Res = receive {apply_result,Result} -> Result end, - ok = io:format("trace_pattern(~p, ~p) -> ~p", [MFA,MatchSpec,Res]), + ok = io:format("trace_pattern(~p, ~p, ~p) -> ~p", [MFA,MatchSpec,Flags,Res]), Res. trace_pid(Pid, On, Flags) -> diff --git a/erts/emulator/test/call_trace_SUITE_data/my_upgrade_test.erl b/erts/emulator/test/call_trace_SUITE_data/my_upgrade_test.erl new file mode 100644 index 0000000000..11b8a95209 --- /dev/null +++ b/erts/emulator/test/call_trace_SUITE_data/my_upgrade_test.erl @@ -0,0 +1,26 @@ +-module(my_upgrade_test). + +-export([version/0]). +-export([do_local/0]). +-export([do_real_local/0]). +-export([make_fun_exp/0]). +-export([make_fun_local/0]). + + +version() -> + ?VERSION. + +do_local() -> + version(). + +do_real_local() -> + local_version(). + +local_version() -> + ?VERSION. + +make_fun_exp() -> + fun() -> ?MODULE:version() end. + +make_fun_local() -> + fun() -> local_version() end. -- cgit v1.2.3 From 6b97a90f2314b66f4f41b14a986a9c1f1ebebf13 Mon Sep 17 00:00:00 2001 From: Sverker Eriksson Date: Tue, 31 Jan 2012 11:23:09 +0100 Subject: erts: Document code_ix interface --- erts/emulator/beam/code_ix.h | 83 ++++++++++++++++++++++++++++++++++---------- 1 file changed, 65 insertions(+), 18 deletions(-) diff --git a/erts/emulator/beam/code_ix.h b/erts/emulator/beam/code_ix.h index 1f9c47f33c..f6926acab5 100644 --- a/erts/emulator/beam/code_ix.h +++ b/erts/emulator/beam/code_ix.h @@ -16,6 +16,36 @@ * * %CopyrightEnd% */ + +/* Description: + * This is the interface that facilitate changing the beam code + * (load,upgrade,delete) while allowing executing Erlang processes to + * access the code without any locks or other expensive memory barriers. + * + * The basic idea is to maintain several "logical copies" of the code. These + * copies are identified by a global 'code index', an integer of 0, 1 or 2. + * The code index is used as argument to code access structures like + * export, module, beam_catches, beam_ranges. + * + * The current 'active' code index is used to access the current running + * code. The 'staging' code index is used by the process that performs + * a code change operation. When a code change operation completes + * succesfully, the staging code index becomes the new active code index. + * + * The third code index is not explicitly used. It can be thought of as + * the "previous active" or the "next staging" index. It is needed to make + * sure that we do not reuse a code index for staging until we are sure + * that no executing BIFs are still referring it. + * We could get by with only two (0 and 1), but that would require that we + * must wait for all schedulers to re-schedule before each code change + * operation can start staging. + * + * Note that the 'code index' is very loosely coupled to the concept of + * 'current' and 'old' module versions. You can almost say that they are + * orthogonal to each other. Code index is an emulator global concept while + * 'current' and 'old' is specific for each module. + */ + #ifndef __CODE_IX_H__ #define __CODE_IX_H__ @@ -23,34 +53,51 @@ #define ERTS_NUM_CODE_IX 3 typedef unsigned ErtsCodeIndex; +/* Called once at emulator initialization. + */ void erts_code_ix_init(void); + +/* Return active code index. + * Is guaranteed to be valid until the calling BIF returns. + * To get a consistent view of the code only one call to erts_active_code_ix() + * should be made within the same BIF call. + */ ErtsCodeIndex erts_active_code_ix(void); + +/* Return staging code ix. + * Only used by a process performing code loading/upgrading/deleting/purging. + * code_ix must be locked. + */ ErtsCodeIndex erts_staging_code_ix(void); -/* Lock code_ix (enqueue and suspend until we get it) -*/ +/* Lock code_ix. + * Gives (exclusive) access to the staging area and write access to active code index. + * ToDo: Waiting process should be queued and return to be suspended. + */ void erts_lock_code_ix(void); -/*SVERK - erts_lock_code_ix(); - wait for thread progress - (we don't want any retarded threads with pointers to inactive Module) - Copy active -> loader - rlock old_code while copying Modules - Update loader - wait for thread progress - (we need a membarrier for everybody to "see" the new code) - Set loader as new active - erts_unlock_code_ix(); -}*/ - - -/* Unlock code_ix (resume first waiter) -*/ +/* Unlock code_ix + * ToDo: Dequeue and resume waiting processes. + */ void erts_unlock_code_ix(void); +/* Make the "staging area" a complete copy of the active code. + * code_ix must be locked. + * Must be followed by a call to either "commit" or "abort" before code_ix lock + * is released. + */ void erts_start_staging_code_ix(void); + +/* Commit the staging area and update the active code index. + * code_ix must be locked and erts_start_staging_code_ix() called. + * ToDo: Updating active code index should be done according to Rickard's recipe. + * This function might need to be split into two. + */ void erts_commit_staging_code_ix(void); + +/* Abort the staging. + * code_ix must be locked and erts_start_staging_code_ix() called. + */ void erts_abort_staging_code_ix(void); void erts_rwlock_old_code(ErtsCodeIndex); -- cgit v1.2.3 From 7cb4725bcf18f3158e60750ea658e51ab4586e31 Mon Sep 17 00:00:00 2001 From: Sverker Eriksson Date: Tue, 31 Jan 2012 14:24:40 +0100 Subject: erts: Refactor code_ix Move implementation from beam_load into new file code_ix.c and module.c and make some function inline. --- erts/emulator/Makefile.in | 1 + erts/emulator/beam/beam_catches.h | 4 ++ erts/emulator/beam/beam_load.c | 119 -------------------------------------- erts/emulator/beam/code_ix.c | 110 +++++++++++++++++++++++++++++++++++ erts/emulator/beam/code_ix.h | 39 ++++++++++--- erts/emulator/beam/module.c | 7 +++ erts/emulator/beam/module.h | 41 ++++++++++++- 7 files changed, 192 insertions(+), 129 deletions(-) create mode 100644 erts/emulator/beam/code_ix.c diff --git a/erts/emulator/Makefile.in b/erts/emulator/Makefile.in index dad09383cf..942cde3af4 100644 --- a/erts/emulator/Makefile.in +++ b/erts/emulator/Makefile.in @@ -705,6 +705,7 @@ EMU_OBJS = \ $(OBJDIR)/beam_load.o $(OBJDIR)/beam_bif_load.o \ $(OBJDIR)/beam_debug.o $(OBJDIR)/beam_bp.o \ $(OBJDIR)/beam_catches.o \ + $(OBJDIR)/code_ix.o \ $(OBJDIR)/beam_ranges.o RUN_OBJS = \ diff --git a/erts/emulator/beam/beam_catches.h b/erts/emulator/beam/beam_catches.h index 4a0e070c69..b2bd2351a5 100644 --- a/erts/emulator/beam/beam_catches.h +++ b/erts/emulator/beam/beam_catches.h @@ -20,6 +20,10 @@ #ifndef __BEAM_CATCHES_H #define __BEAM_CATCHES_H +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif +#include "sys.h" #include "code_ix.h" #define BEAM_CATCHES_NIL (-1) diff --git a/erts/emulator/beam/beam_load.c b/erts/emulator/beam/beam_load.c index e966f423ec..7ac2b9f77e 100644 --- a/erts/emulator/beam/beam_load.c +++ b/erts/emulator/beam/beam_load.c @@ -5940,122 +5940,3 @@ static int safe_mul(UWord a, UWord b, UWord* resp) } } - -/*SVERK Do these deserve a file of their own maybe? */ - -static erts_smp_atomic32_t the_active_code_index; -static erts_smp_atomic32_t the_loader_code_index; - -static erts_smp_mtx_t sverk_code_ix_lock; /*SVERK FIXME */ -static erts_smp_rwmtx_t the_old_code_rwlocks[ERTS_NUM_CODE_IX]; - -#if 0 -# define CIX_TRACE(text) erts_fprintf(stderr, "CIX_TRACE: " text " act=%u load=%u\r\n", erts_active_code_ix(), erts_staging_code_ix()) -#else -# define CIX_TRACE(text) -#endif - -void erts_code_ix_init(void) -{ - int i; - - erts_smp_atomic32_init_nob(&the_active_code_index, 0); - erts_smp_atomic32_init_nob(&the_loader_code_index, 0); - erts_smp_mtx_init_x(&sverk_code_ix_lock, "sverk_code_ix_lock", NIL); /*SVERK FIXME */ - for (i=0; i Date: Tue, 31 Jan 2012 16:21:22 +0100 Subject: erts: Change module range end to be atomic --- erts/emulator/beam/beam_load.h | 4 ---- erts/emulator/beam/beam_ranges.c | 41 +++++++++++++++++++++++++++++----------- 2 files changed, 30 insertions(+), 15 deletions(-) diff --git a/erts/emulator/beam/beam_load.h b/erts/emulator/beam/beam_load.h index 0f6ad35cbc..f1506a8684 100644 --- a/erts/emulator/beam/beam_load.h +++ b/erts/emulator/beam/beam_load.h @@ -50,10 +50,6 @@ extern BeamInstr beam_debug_apply[]; extern BeamInstr* em_call_error_handler; extern BeamInstr* em_apply_bif; extern BeamInstr* em_call_traced_function; -typedef struct { - BeamInstr* start; /* Pointer to start of module. */ - BeamInstr* end; /* Points one word beyond last function in module. */ -} Range; /* * The following variables keep a sorted list of address ranges for diff --git a/erts/emulator/beam/beam_ranges.c b/erts/emulator/beam/beam_ranges.c index 0fc8d9dbfd..0f2d5d0c2a 100644 --- a/erts/emulator/beam/beam_ranges.c +++ b/erts/emulator/beam/beam_ranges.c @@ -26,6 +26,15 @@ #include "global.h" #include "beam_load.h" +typedef struct { + BeamInstr* start; /* Pointer to start of module. */ + erts_smp_atomic_t end; /* (BeamInstr*) Points one word beyond last function in module. */ +} Range; + +/* Range 'end' needs to be atomic as we purge module + by setting end=start in active code_ix */ +#define RANGE_END(R) ((BeamInstr*)erts_smp_atomic_read_nob(&(R)->end)) + static Range* find_range(BeamInstr* pc); static void lookup_loc(FunctionInfo* fi, BeamInstr* pc, BeamInstr* modp, int idx); @@ -53,8 +62,8 @@ static void check_consistency(struct ranges* p) ASSERT((Uint)(p->mid - p->modules) < p->n || (p->mid == p->modules && p->n == 0)); for (i = 0; i < p->n; i++) { - ASSERT(p->modules[i].start <= p->modules[i].end); - ASSERT(!i || p->modules[i-1].end < p->modules[i].start); + ASSERT(p->modules[i].start <= RANGE_END(&p->modules[i])); + ASSERT(!i || RANGE_END(&p->modules[i-1]) < p->modules[i].start); } } # define CHECK(r) check_consistency(r) @@ -108,7 +117,7 @@ erts_end_staging_ranges(int commit) n = 0; for (i = 0; i < r[src].n; i++) { Range* rp = r[src].modules+i; - if (rp->start < rp->end) { + if (rp->start < RANGE_END(rp)) { /* Only insert a module that has not been purged. */ r[dst].modules[n] = *rp; n++; @@ -157,22 +166,30 @@ erts_update_ranges(BeamInstr* code, Uint size) Range* rp = r[src].modules+i; if (code < rp->start) { r[dst].modules[n].start = code; - r[dst].modules[n].end = (BeamInstr *) (((byte *)code) + size); + erts_smp_atomic_init_nob(&r[dst].modules[n].end, + (erts_aint_t)(((byte *)code) + size)); + ASSERT(!n || RANGE_END(&r[dst].modules[n-1]) < code); n++; break; } - if (rp->start < rp->end) { + if (rp->start < RANGE_END(rp)) { /* Only insert a module that has not been purged. */ - r[dst].modules[n] = *rp; + r[dst].modules[n].start = rp->start; + erts_smp_atomic_init_nob(&r[dst].modules[n].end, + (erts_aint_t)(RANGE_END(rp))); + ASSERT(!n || RANGE_END(&r[dst].modules[n-1]) < rp->start); n++; } } while (i < r[src].n) { Range* rp = r[src].modules+i; - if (rp->start < rp->end) { + if (rp->start < RANGE_END(rp)) { /* Only insert a module that has not been purged. */ - r[dst].modules[n] = *rp; + r[dst].modules[n].start = rp->start; + erts_smp_atomic_init_nob(&r[dst].modules[n].end, + (erts_aint_t)(RANGE_END(rp))); + ASSERT(!n || RANGE_END(&r[dst].modules[n-1]) < rp->start); n++; } i++; @@ -180,7 +197,9 @@ erts_update_ranges(BeamInstr* code, Uint size) if (n == 0 || code > r[dst].modules[n-1].start) { r[dst].modules[n].start = code; - r[dst].modules[n].end = (BeamInstr *) (((byte *)code) + size); + erts_smp_atomic_init_nob(&r[dst].modules[n].end, + (erts_aint_t)(((byte *)code) + size)); + ASSERT(!n || RANGE_END(&r[dst].modules[n-1]) < code); n++; } @@ -197,7 +216,7 @@ void erts_remove_from_ranges(BeamInstr* code) { Range* rp = find_range(code); - rp->end = rp->start; + erts_smp_atomic_set_nob(&rp->end, (erts_aint_t)rp->start); } UWord @@ -263,7 +282,7 @@ find_range(BeamInstr* pc) while (low < high) { if (pc < mid->start) { high = mid; - } else if (pc > mid->end) { + } else if (pc > RANGE_END(mid)) { low = mid + 1; } else { erts_smp_atomic_set_nob(&r[active].mid, (erts_aint_t) mid); -- cgit v1.2.3 From 9dbd1dbf260c41878704728adc533ace1a27c1ff Mon Sep 17 00:00:00 2001 From: Sverker Eriksson Date: Wed, 1 Feb 2012 19:39:31 +0100 Subject: erts: Fix hipe loading bug for new non-blocking load --- erts/emulator/hipe/hipe_bif0.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/erts/emulator/hipe/hipe_bif0.c b/erts/emulator/hipe/hipe_bif0.c index ad1552e7eb..6340c39e69 100644 --- a/erts/emulator/hipe/hipe_bif0.c +++ b/erts/emulator/hipe/hipe_bif0.c @@ -648,7 +648,7 @@ static void *hipe_get_emu_address(Eterm m, Eterm f, unsigned int arity, int is_r /* if not found, stub it via the export entry */ /* no lock needed around erts_export_get_or_make_stub() */ Export *export_entry = erts_export_get_or_make_stub(m, f, arity); - address = export_entry->addressv[erts_staging_code_ix()]; + address = export_entry->addressv[erts_active_code_ix()]; } return address; } -- cgit v1.2.3 From e148e9fc3e11eb6e08e2dc94a468dc433864b11b Mon Sep 17 00:00:00 2001 From: Sverker Eriksson Date: Thu, 2 Feb 2012 11:47:18 +0100 Subject: erts: Fix tracing bug for new non-blocking load Made on_load-tracing always set after commit on active code_ix when system is still blocked. Bug caused cprof_SUITE:on_load to fail. --- erts/emulator/beam/beam_bif_load.c | 13 +++++++------ erts/emulator/beam/erl_bif_trace.c | 7 +++---- erts/emulator/beam/global.h | 3 +-- 3 files changed, 11 insertions(+), 12 deletions(-) diff --git a/erts/emulator/beam/beam_bif_load.c b/erts/emulator/beam/beam_bif_load.c index 8d41c7499d..d241bec441 100644 --- a/erts/emulator/beam/beam_bif_load.c +++ b/erts/emulator/beam/beam_bif_load.c @@ -35,7 +35,7 @@ #include "erl_nif.h" #include "erl_thr_progress.h" -static void set_default_trace_pattern(Eterm module, ErtsCodeIndex); +static void set_default_trace_pattern(Eterm module); static Eterm check_process_code(Process* rp, Module* modp); static void delete_code(Module* modp); static int purge_module(Process*, int module); @@ -114,8 +114,10 @@ load_module_2(BIF_ALIST_2) } res = TUPLE2(hp, am_error, reason); } else { - set_default_trace_pattern(BIF_ARG_1, erts_staging_code_ix()); erts_commit_staging_code_ix(); + if (is_blocking) { + set_default_trace_pattern(BIF_ARG_1); + } res = TUPLE2(hp, am_module, BIF_ARG_1); } @@ -485,7 +487,7 @@ BIF_RETTYPE finish_after_on_load_2(BIF_ALIST_2) } } modp->curr.code[MI_ON_LOAD_FUNCTION_PTR] = 0; - set_default_trace_pattern(BIF_ARG_1, erts_active_code_ix ()); + set_default_trace_pattern(BIF_ARG_1); } else if (BIF_ARG_2 == am_false) { BeamInstr* code; BeamInstr* end; @@ -513,7 +515,7 @@ BIF_RETTYPE finish_after_on_load_2(BIF_ALIST_2) } static void -set_default_trace_pattern(Eterm module, ErtsCodeIndex code_ix) +set_default_trace_pattern(Eterm module) { int trace_pattern_is_on; Binary *match_spec; @@ -533,8 +535,7 @@ set_default_trace_pattern(Eterm module, ErtsCodeIndex code_ix) match_spec, meta_match_spec, 1, trace_pattern_flags, - meta_tracer_pid, - code_ix); + meta_tracer_pid); } } diff --git a/erts/emulator/beam/erl_bif_trace.c b/erts/emulator/beam/erl_bif_trace.c index 203ba9004b..c92e0400e0 100644 --- a/erts/emulator/beam/erl_bif_trace.c +++ b/erts/emulator/beam/erl_bif_trace.c @@ -333,8 +333,7 @@ trace_pattern(Process* p, Eterm MFA, Eterm Pattern, Eterm flaglist) matches = erts_set_trace_pattern(mfa, specified, match_prog_set, match_prog_set, - on, flags, meta_tracer_pid, - erts_active_code_ix()); + on, flags, meta_tracer_pid); MatchSetUnref(match_prog_set); done: @@ -1335,9 +1334,9 @@ int erts_set_trace_pattern(Eterm* mfa, int specified, Binary* match_prog_set, Binary *meta_match_prog_set, int on, struct trace_pattern_flags flags, - Eterm meta_tracer_pid, - ErtsCodeIndex code_ix) + Eterm meta_tracer_pid) { + const ErtsCodeIndex code_ix = erts_active_code_ix(); int matches = 0; int i; diff --git a/erts/emulator/beam/global.h b/erts/emulator/beam/global.h index 580336470c..9a174b1ab1 100644 --- a/erts/emulator/beam/global.h +++ b/erts/emulator/beam/global.h @@ -1765,8 +1765,7 @@ extern int erts_call_time_breakpoint_tracing; int erts_set_trace_pattern(Eterm* mfa, int specified, Binary* match_prog_set, Binary *meta_match_prog_set, int on, struct trace_pattern_flags, - Eterm meta_tracer_pid, - ErtsCodeIndex); + Eterm meta_tracer_pid); void erts_get_default_trace_pattern(int *trace_pattern_is_on, Binary **match_spec, -- cgit v1.2.3 From 63265772e86ca2e0f14a236c8aa964697a7cda70 Mon Sep 17 00:00:00 2001 From: Sverker Eriksson Date: Fri, 3 Feb 2012 18:12:17 +0100 Subject: erts: Fix memory reports from export table Report sum from all code index. --- erts/emulator/beam/erl_alloc.c | 4 ++-- erts/emulator/beam/export.c | 19 +++++++++++++++++-- erts/emulator/beam/export.h | 1 + 3 files changed, 20 insertions(+), 4 deletions(-) diff --git a/erts/emulator/beam/erl_alloc.c b/erts/emulator/beam/erl_alloc.c index bf7c53bf1a..ac92822aca 100644 --- a/erts/emulator/beam/erl_alloc.c +++ b/erts/emulator/beam/erl_alloc.c @@ -2185,7 +2185,7 @@ erts_memory(int *print_to_p, void *print_to_arg, void *proc, Eterm earg) if (want.code) { size.code = module_table_sz(); size.code += export_table_sz(); - size.code += export_list_size(erts_active_code_ix()) * sizeof(Export); + size.code += export_entries_sz(); size.code += erts_fun_table_sz(); size.code += erts_ranges_sz(); size.code += erts_total_code_size; @@ -2335,7 +2335,7 @@ erts_allocated_areas(int *print_to_p, void *print_to_arg, void *proc) values[i].arity = 2; values[i].name = "export_list"; - values[i].ui[0] = export_list_size(erts_active_code_ix ()) * sizeof(Export); + values[i].ui[0] = export_entries_sz(); i++; values[i].arity = 2; diff --git a/erts/emulator/beam/export.c b/erts/emulator/beam/export.c index 4a2a77a527..31de141497 100644 --- a/erts/emulator/beam/export.c +++ b/erts/emulator/beam/export.c @@ -40,6 +40,8 @@ static IndexTable export_tables[ERTS_NUM_CODE_IX]; /* Active not locked */ +static erts_smp_atomic_t total_entries_bytes; + #include "erl_smp.h" erts_smp_rwmtx_t export_table_lock; /* Locks the secondary export table. */ @@ -126,6 +128,7 @@ export_alloc(struct export_entry* tmpl_e) Export* obj; blob = (struct export_blob*) erts_alloc(ERTS_ALC_T_EXPORT, sizeof(*blob)); + erts_smp_atomic_add_nob(&total_entries_bytes, sizeof(*blob)); obj = &blob->exp; obj->fake_op_func_info_for_hipe[0] = 0; obj->fake_op_func_info_for_hipe[1] = 0; @@ -165,6 +168,7 @@ export_free(struct export_entry* obj) } } erts_free(ERTS_ALC_T_EXPORT, blob); + erts_smp_atomic_add_nob(&total_entries_bytes, -sizeof(*blob)); } void @@ -177,6 +181,7 @@ init_export_table(void) rwmtx_opt.lived = ERTS_SMP_RWMTX_LONG_LIVED; erts_smp_rwmtx_init_opt(&export_table_lock, &rwmtx_opt, "export_tab"); + erts_smp_atomic_init_nob(&total_entries_bytes, 0); f.hash = (H_FUN) export_hash; f.cmp = (HCMP_FUN) export_cmp; @@ -353,9 +358,19 @@ int export_list_size(ErtsCodeIndex code_ix) int export_table_sz(void) { - return index_table_sz(&export_tables[erts_active_code_ix()]); -} + int i, bytes = 0; + export_read_lock(); + for (i=0; i Date: Fri, 3 Feb 2012 18:13:37 +0100 Subject: erts: Refactor more renaming as "staging" --- erts/emulator/beam/export.c | 8 ++++---- erts/emulator/beam/export.h | 6 +++--- erts/emulator/beam/module.c | 8 ++++---- 3 files changed, 11 insertions(+), 11 deletions(-) diff --git a/erts/emulator/beam/export.c b/erts/emulator/beam/export.c index 31de141497..9656a67a4a 100644 --- a/erts/emulator/beam/export.c +++ b/erts/emulator/beam/export.c @@ -44,10 +44,10 @@ static erts_smp_atomic_t total_entries_bytes; #include "erl_smp.h" -erts_smp_rwmtx_t export_table_lock; /* Locks the secondary export table. */ +erts_smp_rwmtx_t export_staging_lock; /* Locks the staging export table. */ -#define export_read_lock() erts_smp_rwmtx_rlock(&export_table_lock) -#define export_read_unlock() erts_smp_rwmtx_runlock(&export_table_lock) +#define export_read_lock() erts_smp_rwmtx_rlock(&export_staging_lock) +#define export_read_unlock() erts_smp_rwmtx_runlock(&export_staging_lock) extern BeamInstr* em_call_error_handler; extern BeamInstr* em_call_traced_function; @@ -180,7 +180,7 @@ init_export_table(void) rwmtx_opt.type = ERTS_SMP_RWMTX_TYPE_FREQUENT_READ; rwmtx_opt.lived = ERTS_SMP_RWMTX_LONG_LIVED; - erts_smp_rwmtx_init_opt(&export_table_lock, &rwmtx_opt, "export_tab"); + erts_smp_rwmtx_init_opt(&export_staging_lock, &rwmtx_opt, "export_tab"); erts_smp_atomic_init_nob(&total_entries_bytes, 0); f.hash = (H_FUN) export_hash; diff --git a/erts/emulator/beam/export.h b/erts/emulator/beam/export.h index f59c5e5c89..ef9c1d2680 100644 --- a/erts/emulator/beam/export.h +++ b/erts/emulator/beam/export.h @@ -76,9 +76,9 @@ Export *export_get(Export*); void export_start_staging(void); void export_end_staging(int commit); -extern erts_smp_rwmtx_t export_table_lock; -#define export_write_lock() erts_smp_rwmtx_rwlock(&export_table_lock) -#define export_write_unlock() erts_smp_rwmtx_rwunlock(&export_table_lock) +extern erts_smp_rwmtx_t export_staging_lock; +#define export_write_lock() erts_smp_rwmtx_rwlock(&export_staging_lock) +#define export_write_unlock() erts_smp_rwmtx_rwunlock(&export_staging_lock) #include "beam_load.h" /* For em_* extern declarations */ #define ExportIsBuiltIn(EntryPtr) \ diff --git a/erts/emulator/beam/module.c b/erts/emulator/beam/module.c index d3fd3f118d..6d5f1528b4 100644 --- a/erts/emulator/beam/module.c +++ b/erts/emulator/beam/module.c @@ -163,7 +163,7 @@ int module_table_sz(void) static ErtsCodeIndex dbg_load_code_ix = 0; #endif -static int entries_at_start_load = 0; +static int entries_at_start_staging = 0; void module_start_staging(void) { @@ -199,8 +199,8 @@ void module_start_staging(void) dst_mod->curr = src_mod->curr; dst_mod->old = src_mod->old; } - entries_at_start_load = dst->entries; + entries_at_start_staging = dst->entries; IF_DEBUG(dbg_load_code_ix = erts_staging_code_ix()); } @@ -211,8 +211,8 @@ void module_end_staging(int commit) if (!commit) { /* abort */ IndexTable* tab = &module_tables[erts_staging_code_ix()]; - ASSERT(entries_at_start_load <= tab->entries); - index_erase_latest_from(tab, entries_at_start_load); + ASSERT(entries_at_start_staging <= tab->entries); + index_erase_latest_from(tab, entries_at_start_staging); } IF_DEBUG(dbg_load_code_ix = -1); -- cgit v1.2.3 From c2f62a3813c5c2bd2bb691df816d5fc2fb17206a Mon Sep 17 00:00:00 2001 From: Sverker Eriksson Date: Tue, 7 Feb 2012 16:19:43 +0100 Subject: erts: Fix memory query for non-blocking module table --- erts/emulator/beam/module.c | 31 +++++++++++++++++++++++++------ 1 file changed, 25 insertions(+), 6 deletions(-) diff --git a/erts/emulator/beam/module.c b/erts/emulator/beam/module.c index 6d5f1528b4..1dab24e96a 100644 --- a/erts/emulator/beam/module.c +++ b/erts/emulator/beam/module.c @@ -39,9 +39,12 @@ static IndexTable module_tables[ERTS_NUM_CODE_IX]; erts_smp_rwmtx_t the_old_code_rwlocks[ERTS_NUM_CODE_IX]; -/* - * SMP note: We don't need to look accesses to the module table because - * there is one only scheduler thread when we update it. +static erts_smp_atomic_t tot_module_bytes; + +/* SMP note: Active module table lookup and current module instance can be + * read without any locks. Old module instances are protected by + * "the_old_code_rwlocks" as purging is done on active module table. + * Staging table is protected by the "code_ix lock". */ #include "erl_smp.h" @@ -67,6 +70,7 @@ static int module_cmp(Module* tmpl, Module* obj) static Module* module_alloc(Module* tmpl) { Module* obj = (Module*) erts_alloc(ERTS_ALC_T_MODULE, sizeof(Module)); + erts_smp_atomic_add_nob(&tot_module_bytes, sizeof(Module)); obj->module = tmpl->module; obj->curr.code = 0; @@ -86,6 +90,7 @@ static Module* module_alloc(Module* tmpl) static void module_free(Module* mod) { erts_free(ERTS_ALC_T_MODULE, mod); + erts_smp_atomic_add_nob(&tot_module_bytes, -sizeof(Module)); } void init_module_table(void) @@ -106,6 +111,7 @@ void init_module_table(void) for (i=0; ientries <= src->entries); @@ -191,6 +203,7 @@ void module_start_staging(void) /* * Copy all new modules from active table */ + oldsz = index_table_sz(dst); for (i = dst->entries; i < src->entries; i++) { src_mod = (Module*) erts_index_lookup(src, i); dst_mod = (Module*) index_put_entry(dst, src_mod); @@ -199,6 +212,8 @@ void module_start_staging(void) dst_mod->curr = src_mod->curr; dst_mod->old = src_mod->old; } + newsz = index_table_sz(dst); + erts_smp_atomic_add_nob(&tot_module_bytes, (newsz - oldsz)); entries_at_start_staging = dst->entries; IF_DEBUG(dbg_load_code_ix = erts_staging_code_ix()); @@ -210,9 +225,13 @@ void module_end_staging(int commit) if (!commit) { /* abort */ IndexTable* tab = &module_tables[erts_staging_code_ix()]; + int oldsz, newsz; ASSERT(entries_at_start_staging <= tab->entries); + oldsz = index_table_sz(tab); index_erase_latest_from(tab, entries_at_start_staging); + newsz = index_table_sz(tab); + erts_smp_atomic_add_nob(&tot_module_bytes, (newsz - oldsz)); } IF_DEBUG(dbg_load_code_ix = -1); -- cgit v1.2.3 From fa5213fd7590c6a9ade13af1375c363b958927f1 Mon Sep 17 00:00:00 2001 From: Sverker Eriksson Date: Tue, 7 Feb 2012 19:43:31 +0100 Subject: erts: Cleanup non-blocking load --- erts/emulator/beam/beam_bif_load.c | 33 ++++----------------------------- erts/emulator/beam/beam_catches.c | 34 ++++++++++++++++++---------------- erts/emulator/beam/export.c | 12 +++--------- erts/emulator/beam/export.h | 18 ++++++++++++++---- 4 files changed, 39 insertions(+), 58 deletions(-) diff --git a/erts/emulator/beam/beam_bif_load.c b/erts/emulator/beam/beam_bif_load.c index d241bec441..995b16c376 100644 --- a/erts/emulator/beam/beam_bif_load.c +++ b/erts/emulator/beam/beam_bif_load.c @@ -139,18 +139,8 @@ BIF_RETTYPE purge_module_1(BIF_ALIST_1) BIF_ERROR(BIF_P, BADARG); } - /*SVERK - erts_smp_proc_unlock(BIF_P, ERTS_PROC_LOCK_MAIN); - erts_smp_thr_progress_block(); - - erts_export_consolidate(erts_active_code_ix());*/ - purge_res = purge_module(BIF_P, atom_val(BIF_ARG_1)); - /*SVERK - erts_smp_thr_progress_unblock(); - erts_smp_proc_lock(BIF_P, ERTS_PROC_LOCK_MAIN);*/ - if (purge_res < 0) { BIF_ERROR(BIF_P, BADARG); } @@ -306,10 +296,6 @@ BIF_RETTYPE delete_module_1(BIF_ALIST_1) if (is_not_atom(BIF_ARG_1)) goto badarg; - /*SVERK - erts_smp_proc_unlock(BIF_P, ERTS_PROC_LOCK_MAIN); - erts_smp_thr_progress_block();*/ - erts_lock_code_ix(); do { erts_start_staging_code_ix(); @@ -361,10 +347,6 @@ BIF_RETTYPE delete_module_1(BIF_ALIST_1) erts_unlock_code_ix(); } - /*SVERK - erts_smp_thr_progress_unblock(); - erts_smp_proc_lock(BIF_P, ERTS_PROC_LOCK_MAIN);*/ - if (res == am_badarg) { badarg: BIF_ERROR(BIF_P, BADARG); @@ -429,17 +411,10 @@ BIF_RETTYPE loaded_0(BIF_ALIST_0) BIF_RETTYPE call_on_load_function_1(BIF_ALIST_1) { - ErtsCodeIndex code_ix = erts_active_code_ix(); /*SVERK ?? on_load ?? */ - Module* modp = erts_get_module(BIF_ARG_1, code_ix); - Eterm on_load = 0; + Module* modp = erts_get_module(BIF_ARG_1, erts_active_code_ix()); - if (modp) { - if (modp->curr.code) { - on_load = modp->curr.code[MI_ON_LOAD_FUNCTION_PTR]; - } - } - if (on_load) { - BIF_TRAP_CODE_PTR_0(BIF_P, on_load); + if (modp && modp->curr.code) { + BIF_TRAP_CODE_PTR_0(BIF_P, modp->curr.code[MI_ON_LOAD_FUNCTION_PTR]); } else { BIF_ERROR(BIF_P, BADARG); @@ -793,7 +768,7 @@ retry: */ if (modp->old.nif != NULL) { if (!is_blocking) { - /*SVERK Do unload nif without blocking */ + /* ToDo: Do unload nif without blocking */ erts_rwunlock_old_code(code_ix); erts_unlock_code_ix(); erts_smp_proc_unlock(c_p, ERTS_PROC_LOCK_MAIN); diff --git a/erts/emulator/beam/beam_catches.c b/erts/emulator/beam/beam_catches.c index 548c10fa94..92f7ffe5a2 100644 --- a/erts/emulator/beam/beam_catches.c +++ b/erts/emulator/beam/beam_catches.c @@ -37,16 +37,21 @@ typedef struct { # define IF_DEBUG(x) #endif -struct bc_code_ix { /*SVERK A better name maybe... */ +struct bc_pool { int free_list; unsigned high_mark; unsigned tabsize; beam_catch_t *beam_catches; + /* + * Note that the 'beam_catches' area is shared by pools. Used slots + * are readonly as long as the module is not purgable. The free-list is + * protected by the code_ix lock. + */ - IF_DEBUG(int is_prepared;) + IF_DEBUG(int is_staging;) }; -static struct bc_code_ix bccix[ERTS_NUM_CODE_IX]; +static struct bc_pool bccix[ERTS_NUM_CODE_IX]; void beam_catches_init(void) { @@ -57,12 +62,12 @@ void beam_catches_init(void) bccix[0].high_mark = 0; bccix[0].beam_catches = erts_alloc(ERTS_ALC_T_CODE, sizeof(beam_catch_t)*DEFAULT_TABSIZE); - IF_DEBUG(bccix[0].is_prepared = 0); + IF_DEBUG(bccix[0].is_staging = 0); for (i=1; iis_prepared); + ASSERT(p->is_staging); /* * Allocate from free_list while it is non-empty. * If free_list is empty, allocate at high_mark. - * - * This avoids the need to initialise the free list in - * beam_catches_init(), which would cost O(TABSIZ) time. */ if (p->free_list >= 0) { i = p->free_list; @@ -137,7 +139,7 @@ unsigned beam_catches_cons(BeamInstr *cp, unsigned cdr) BeamInstr *beam_catches_car(unsigned i) { - struct bc_code_ix* p = &bccix[erts_active_code_ix()]; + struct bc_pool* p = &bccix[erts_active_code_ix()]; if (i >= p->tabsize ) { erl_exit(1, "beam_catches_delmod: index %#x is out of range\r\n", i); @@ -148,10 +150,10 @@ BeamInstr *beam_catches_car(unsigned i) void beam_catches_delmod(unsigned head, BeamInstr *code, unsigned code_bytes, ErtsCodeIndex code_ix) { - struct bc_code_ix* p = &bccix[code_ix]; + struct bc_pool* p = &bccix[code_ix]; unsigned i, cdr; - ASSERT((code_ix == erts_active_code_ix()) != bccix[erts_staging_code_ix()].is_prepared); + ASSERT((code_ix == erts_active_code_ix()) != bccix[erts_staging_code_ix()].is_staging); for(i = head; i != (unsigned)-1;) { if (i >= p->tabsize) { erl_exit(1, "beam_catches_delmod: index %#x is out of range\r\n", i); diff --git a/erts/emulator/beam/export.c b/erts/emulator/beam/export.c index 9656a67a4a..78a0b7d269 100644 --- a/erts/emulator/beam/export.c +++ b/erts/emulator/beam/export.c @@ -206,16 +206,11 @@ init_export_table(void) * called through such an export entry. * 3) This function is suitable for the implementation of erlang:apply/3. */ +extern Export* /* inline-helper */ +erts_find_export_entry(Eterm m, Eterm f, unsigned int a,ErtsCodeIndex code_ix); Export* -erts_active_export_entry(Eterm m, Eterm f, unsigned int a) -{ - return erts_find_export_entry(m, f, a, erts_active_code_ix()); -} - -Export* -erts_find_export_entry(Eterm m, Eterm f, unsigned int a, - ErtsCodeIndex code_ix) +erts_find_export_entry(Eterm m, Eterm f, unsigned int a, ErtsCodeIndex code_ix) { HashValue hval = EXPORT_HASH((BeamInstr) m, (BeamInstr) f, (BeamInstr) a); int ix; @@ -401,7 +396,6 @@ void export_start_staging(void) /* * Insert all entries in src into dst table */ - /*SVERK Room for optimization to only insert the new ones */ for (i = 0; i < src->entries; i++) { src_entry = (struct export_entry*) erts_index_lookup(src, i); src_entry->ep->addressv[dst_ix] = src_entry->ep->addressv[src_ix]; diff --git a/erts/emulator/beam/export.h b/erts/emulator/beam/export.h index ef9c1d2680..45c98d6bbb 100644 --- a/erts/emulator/beam/export.h +++ b/erts/emulator/beam/export.h @@ -61,11 +61,9 @@ typedef struct export void init_export_table(void); void export_info(int, void *); -Export* erts_find_export_entry(Eterm m, Eterm f, unsigned int a, ErtsCodeIndex); -Export* erts_active_export_entry(Eterm m, Eterm f, unsigned int a); /*SVERK inline? */ +ERTS_GLB_INLINE Export* erts_active_export_entry(Eterm m, Eterm f, unsigned a); Export* erts_export_put(Eterm mod, Eterm func, unsigned int arity); - Export* erts_export_get_or_make_stub(Eterm, Eterm, unsigned); Export *export_list(int,ErtsCodeIndex); @@ -85,4 +83,16 @@ extern erts_smp_rwmtx_t export_staging_lock; (((EntryPtr)->addressv[erts_active_code_ix()] == (EntryPtr)->code + 3) && \ ((EntryPtr)->code[3] == (BeamInstr) em_apply_bif)) -#endif +#if ERTS_GLB_INLINE_INCL_FUNC_DEF + +ERTS_GLB_INLINE Export* +erts_active_export_entry(Eterm m, Eterm f, unsigned int a) +{ + extern Export* erts_find_export_entry(Eterm m, Eterm f, unsigned a, ErtsCodeIndex); + return erts_find_export_entry(m, f, a, erts_active_code_ix()); +} + +#endif /* ERTS_GLB_INLINE_INCL_FUNC_DEF */ + +#endif /* __EXPORT_H__ */ + -- cgit v1.2.3 From 5d4759518008a3bdd9c7e9d2adde94a4bd01169e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20Gustavsson?= Date: Thu, 12 Jan 2012 15:21:18 +0100 Subject: Use magic binaries in erts_prepare_loading() and erts_finish_loading() --- erts/emulator/beam/beam_bif_load.c | 8 +- erts/emulator/beam/beam_load.c | 194 ++++++++++++++++++++++++------------- erts/emulator/beam/erl_alloc.types | 1 + erts/emulator/beam/global.h | 6 +- 4 files changed, 132 insertions(+), 77 deletions(-) diff --git a/erts/emulator/beam/beam_bif_load.c b/erts/emulator/beam/beam_bif_load.c index 995b16c376..42642e103d 100644 --- a/erts/emulator/beam/beam_bif_load.c +++ b/erts/emulator/beam/beam_bif_load.c @@ -53,7 +53,7 @@ load_module_2(BIF_ALIST_2) byte* code; Eterm res; byte* temp_alloc = NULL; - struct LoaderState* stp; + Binary* magic; int is_blocking = 0; if (is_not_atom(BIF_ARG_1)) { @@ -69,9 +69,9 @@ load_module_2(BIF_ALIST_2) /* * Read the BEAM file and prepare the module for loading. */ - stp = erts_alloc_loader_state(); + magic = erts_alloc_loader_state(); sz = binary_size(BIF_ARG_2); - reason = erts_prepare_loading(stp, BIF_P, BIF_P->group_leader, + reason = erts_prepare_loading(magic, BIF_P, BIF_P->group_leader, &BIF_ARG_1, code, sz); erts_free_aligned_binary_bytes(temp_alloc); if (reason != NIL) { @@ -101,7 +101,7 @@ load_module_2(BIF_ALIST_2) erts_clear_module_break(modp); ASSERT(modp->curr.num_breakpoints == 0); } - reason = erts_finish_loading(stp, BIF_P, 0, &BIF_ARG_1); + reason = erts_finish_loading(magic, BIF_P, 0, &BIF_ARG_1); break; } diff --git a/erts/emulator/beam/beam_load.c b/erts/emulator/beam/beam_load.c index 7ac2b9f77e..a9246a84c1 100644 --- a/erts/emulator/beam/beam_load.c +++ b/erts/emulator/beam/beam_load.c @@ -475,7 +475,8 @@ typedef struct LoaderState { } while (0) -static void free_state(LoaderState* stp); +static void free_loader_state(Binary* magic); +static void loader_state_dtor(Binary* magic); static Eterm insert_new_code(Process *c_p, ErtsProcLocks c_p_locks, Eterm group_leader, Eterm module, BeamInstr* code, Uint size); @@ -568,16 +569,16 @@ erts_preload_module(Process *c_p, byte* code, /* Points to the code to load */ Uint size) /* Size of code to load. */ { - LoaderState* stp = erts_alloc_loader_state(); + Binary* magic = erts_alloc_loader_state(); Eterm retval; ASSERT(!erts_initialized); - retval = erts_prepare_loading(stp, c_p, group_leader, modp, + retval = erts_prepare_loading(magic, c_p, group_leader, modp, code, size); if (retval != NIL) { return retval; } - return erts_finish_loading(stp, c_p, c_p_locks, modp); + return erts_finish_loading(magic, c_p, c_p_locks, modp); } /* #define LOAD_MEMORY_HARD_DEBUG 1*/ @@ -593,11 +594,13 @@ extern void check_allocated_block(Uint type, void *blk); #endif Eterm -erts_prepare_loading(LoaderState* stp, Process *c_p, Eterm group_leader, +erts_prepare_loading(Binary* magic, Process *c_p, Eterm group_leader, Eterm* modp, byte* code, Uint unloaded_size) { Eterm retval = am_badfile; + LoaderState* stp; + stp = ERTS_MAGIC_BIN_DATA(magic); stp->module = *modp; stp->group_leader = group_leader; @@ -736,16 +739,17 @@ erts_prepare_loading(LoaderState* stp, Process *c_p, Eterm group_leader, load_error: if (retval != NIL) { - free_state(stp); + free_loader_state(magic); } return retval; } Eterm -erts_finish_loading(LoaderState* stp, Process* c_p, +erts_finish_loading(Binary* magic, Process* c_p, ErtsProcLocks c_p_locks, Eterm* modp) { Eterm retval; + LoaderState* stp = ERTS_MAGIC_BIN_DATA(magic); /* * No other process may run since we will update the export @@ -798,16 +802,20 @@ erts_finish_loading(LoaderState* stp, Process* c_p, } load_error: - free_state(stp); + free_loader_state(magic); return retval; } -LoaderState* +Binary* erts_alloc_loader_state(void) { LoaderState* stp; + Binary* magic; - stp = erts_alloc(ERTS_ALC_T_LOADER_TMP, sizeof(LoaderState)); + magic = erts_create_magic_binary(sizeof(LoaderState), + loader_state_dtor); + erts_refc_inc(&magic->refc, 1); + stp = ERTS_MAGIC_BIN_DATA(magic); stp->bin = NULL; stp->function = THE_NON_VALUE; /* Function not known yet */ stp->arity = 0; @@ -836,76 +844,102 @@ erts_alloc_loader_state(void) stp->line_instr = 0; stp->func_line = 0; stp->fname = 0; - return stp; + return magic; +} + +static void +free_loader_state(Binary* magic) +{ + loader_state_dtor(magic); + if (erts_refc_dectest(&magic->refc, 0) == 0) { + erts_bin_free(magic); + } } +/* + * This destructor function can safely be called multiple times. + */ static void -free_state(LoaderState* stp) +loader_state_dtor(Binary* magic) { + LoaderState* stp = ERTS_MAGIC_BIN_DATA(magic); + if (stp->bin != 0) { driver_free_binary(stp->bin); + stp->bin = 0; } if (stp->code != 0) { erts_free(ERTS_ALC_T_CODE, stp->code); + stp->code = 0; } - if (stp->labels != NULL) { - erts_free(ERTS_ALC_T_LOADER_TMP, (void *) stp->labels); + if (stp->labels != 0) { + erts_free(ERTS_ALC_T_PREPARED_CODE, (void *) stp->labels); + stp->labels = 0; } - if (stp->atom != NULL) { - erts_free(ERTS_ALC_T_LOADER_TMP, (void *) stp->atom); + if (stp->atom != 0) { + erts_free(ERTS_ALC_T_PREPARED_CODE, (void *) stp->atom); + stp->atom = 0; } - if (stp->import != NULL) { - erts_free(ERTS_ALC_T_LOADER_TMP, (void *) stp->import); + if (stp->import != 0) { + erts_free(ERTS_ALC_T_PREPARED_CODE, (void *) stp->import); + stp->import = 0; } - if (stp->export != NULL) { - erts_free(ERTS_ALC_T_LOADER_TMP, (void *) stp->export); + if (stp->export != 0) { + erts_free(ERTS_ALC_T_PREPARED_CODE, (void *) stp->export); + stp->export = 0; } if (stp->lambdas != stp->def_lambdas) { - erts_free(ERTS_ALC_T_LOADER_TMP, (void *) stp->lambdas); + erts_free(ERTS_ALC_T_PREPARED_CODE, (void *) stp->lambdas); + stp->lambdas = stp->def_lambdas; } - if (stp->literals != NULL) { + if (stp->literals != 0) { int i; for (i = 0; i < stp->num_literals; i++) { - if (stp->literals[i].heap != NULL) { - erts_free(ERTS_ALC_T_LOADER_TMP, + if (stp->literals[i].heap != 0) { + erts_free(ERTS_ALC_T_PREPARED_CODE, (void *) stp->literals[i].heap); + stp->literals[i].heap = 0; } } - erts_free(ERTS_ALC_T_LOADER_TMP, (void *) stp->literals); + erts_free(ERTS_ALC_T_PREPARED_CODE, (void *) stp->literals); + stp->literals = 0; } - while (stp->literal_patches != NULL) { + while (stp->literal_patches != 0) { LiteralPatch* next = stp->literal_patches->next; - erts_free(ERTS_ALC_T_LOADER_TMP, (void *) stp->literal_patches); + erts_free(ERTS_ALC_T_PREPARED_CODE, (void *) stp->literal_patches); stp->literal_patches = next; } - while (stp->string_patches != NULL) { + while (stp->string_patches != 0) { StringPatch* next = stp->string_patches->next; - erts_free(ERTS_ALC_T_LOADER_TMP, (void *) stp->string_patches); + erts_free(ERTS_ALC_T_PREPARED_CODE, (void *) stp->string_patches); stp->string_patches = next; } - while (stp->genop_blocks) { - GenOpBlock* next = stp->genop_blocks->next; - erts_free(ERTS_ALC_T_LOADER_TMP, (void *) stp->genop_blocks); - stp->genop_blocks = next; - } if (stp->line_item != 0) { - erts_free(ERTS_ALC_T_LOADER_TMP, stp->line_item); + erts_free(ERTS_ALC_T_PREPARED_CODE, stp->line_item); + stp->line_item = 0; } if (stp->line_instr != 0) { - erts_free(ERTS_ALC_T_LOADER_TMP, stp->line_instr); + erts_free(ERTS_ALC_T_PREPARED_CODE, stp->line_instr); + stp->line_instr = 0; } if (stp->func_line != 0) { - erts_free(ERTS_ALC_T_LOADER_TMP, stp->func_line); + erts_free(ERTS_ALC_T_PREPARED_CODE, stp->func_line); + stp->func_line = 0; } if (stp->fname != 0) { - erts_free(ERTS_ALC_T_LOADER_TMP, stp->fname); + erts_free(ERTS_ALC_T_PREPARED_CODE, stp->fname); + stp->fname = 0; } - erts_free(ERTS_ALC_T_LOADER_TMP, stp); + /* + * The following data items should have been freed earlier. + */ + + ASSERT(stp->genop_blocks == 0); } static Eterm @@ -1162,7 +1196,7 @@ load_atom_table(LoaderState* stp) GetInt(stp, 4, stp->num_atoms); stp->num_atoms++; - stp->atom = erts_alloc(ERTS_ALC_T_LOADER_TMP, + stp->atom = erts_alloc(ERTS_ALC_T_PREPARED_CODE, stp->num_atoms*sizeof(Eterm)); /* @@ -1207,7 +1241,7 @@ load_import_table(LoaderState* stp) int i; GetInt(stp, 4, stp->num_imports); - stp->import = erts_alloc(ERTS_ALC_T_LOADER_TMP, + stp->import = erts_alloc(ERTS_ALC_T_PREPARED_CODE, stp->num_imports * sizeof(ImportEntry)); for (i = 0; i < stp->num_imports; i++) { int n; @@ -1266,7 +1300,7 @@ read_export_table(LoaderState* stp) stp->num_exps, stp->num_functions); } stp->export - = (ExportEntry *) erts_alloc(ERTS_ALC_T_LOADER_TMP, + = (ExportEntry *) erts_alloc(ERTS_ALC_T_PREPARED_CODE, (stp->num_exps * sizeof(ExportEntry))); for (i = 0; i < stp->num_exps; i++) { @@ -1356,7 +1390,7 @@ read_lambda_table(LoaderState* stp) if (stp->num_lambdas > stp->lambdas_allocated) { ASSERT(stp->lambdas == stp->def_lambdas); stp->lambdas_allocated = stp->num_lambdas; - stp->lambdas = (Lambda *) erts_alloc(ERTS_ALC_T_LOADER_TMP, + stp->lambdas = (Lambda *) erts_alloc(ERTS_ALC_T_PREPARED_CODE, stp->num_lambdas * sizeof(Lambda)); } for (i = 0; i < stp->num_lambdas; i++) { @@ -1408,7 +1442,7 @@ read_literal_table(LoaderState* stp) stp->file_p = uncompressed; stp->file_left = (unsigned) uncompressed_sz; GetInt(stp, 4, stp->num_literals); - stp->literals = (Literal *) erts_alloc(ERTS_ALC_T_LOADER_TMP, + stp->literals = (Literal *) erts_alloc(ERTS_ALC_T_PREPARED_CODE, stp->num_literals * sizeof(Literal)); stp->allocated_literals = stp->num_literals; @@ -1428,7 +1462,7 @@ read_literal_table(LoaderState* stp) if ((heap_size = erts_decode_ext_size(p, sz)) < 0) { LoadError1(stp, "literal %d: bad external format", i); } - hp = stp->literals[i].heap = erts_alloc(ERTS_ALC_T_LOADER_TMP, + hp = stp->literals[i].heap = erts_alloc(ERTS_ALC_T_PREPARED_CODE, heap_size*sizeof(Eterm)); stp->literals[i].off_heap.first = 0; stp->literals[i].off_heap.overhead = 0; @@ -1500,7 +1534,7 @@ read_line_table(LoaderState* stp) */ num_line_items++; - lp = (BeamInstr *) erts_alloc(ERTS_ALC_T_LOADER_TMP, + lp = (BeamInstr *) erts_alloc(ERTS_ALC_T_PREPARED_CODE, num_line_items * sizeof(BeamInstr)); stp->line_item = lp; stp->num_line_items = num_line_items; @@ -1556,7 +1590,7 @@ read_line_table(LoaderState* stp) */ if (stp->num_fnames != 0) { - stp->fname = (Eterm *) erts_alloc(ERTS_ALC_T_LOADER_TMP, + stp->fname = (Eterm *) erts_alloc(ERTS_ALC_T_PREPARED_CODE, stp->num_fnames * sizeof(Eterm)); for (i = 0; i < stp->num_fnames; i++) { @@ -1572,11 +1606,11 @@ read_line_table(LoaderState* stp) /* * Allocate the arrays to be filled while code is being loaded. */ - stp->line_instr = (LineInstr *) erts_alloc(ERTS_ALC_T_LOADER_TMP, + stp->line_instr = (LineInstr *) erts_alloc(ERTS_ALC_T_PREPARED_CODE, stp->num_line_instrs * sizeof(LineInstr)); stp->current_li = 0; - stp->func_line = (int *) erts_alloc(ERTS_ALC_T_LOADER_TMP, + stp->func_line = (int *) erts_alloc(ERTS_ALC_T_PREPARED_CODE, stp->num_functions * sizeof(int)); @@ -1639,7 +1673,7 @@ read_code_header(LoaderState* stp) * Initialize label table. */ - stp->labels = (Label *) erts_alloc(ERTS_ALC_T_LOADER_TMP, + stp->labels = (Label *) erts_alloc(ERTS_ALC_T_PREPARED_CODE, stp->num_labels * sizeof(Label)); for (i = 0; i < stp->num_labels; i++) { stp->labels[i].value = 0; @@ -1693,6 +1727,7 @@ load_code(LoaderState* stp) GenOp* last_op = NULL; GenOp** last_op_next = NULL; int arity; + int retval = 1; /* * The size of the loaded func_info instruction is needed @@ -2422,7 +2457,8 @@ load_code(LoaderState* stp) stp->function = THE_NON_VALUE; stp->genop = NULL; stp->specific_op = -1; - return 1; + retval = 1; + goto cleanup; } /* @@ -2436,9 +2472,20 @@ load_code(LoaderState* stp) } } - load_error: - return 0; + retval = 0; + + cleanup: + /* + * Clean up everything that is not needed any longer. + */ + + while (stp->genop_blocks) { + GenOpBlock* next = stp->genop_blocks->next; + erts_free(ERTS_ALC_T_LOADER_TMP, (void *) stp->genop_blocks); + stp->genop_blocks = next; + } + return retval; } @@ -4898,7 +4945,7 @@ new_label(LoaderState* stp) int num = stp->num_labels; stp->num_labels++; - stp->labels = (Label *) erts_realloc(ERTS_ALC_T_LOADER_TMP, + stp->labels = (Label *) erts_realloc(ERTS_ALC_T_PREPARED_CODE, (void *) stp->labels, stp->num_labels * sizeof(Label)); stp->labels[num].value = 0; @@ -4909,7 +4956,8 @@ new_label(LoaderState* stp) static void new_literal_patch(LoaderState* stp, int pos) { - LiteralPatch* p = erts_alloc(ERTS_ALC_T_LOADER_TMP, sizeof(LiteralPatch)); + LiteralPatch* p = erts_alloc(ERTS_ALC_T_PREPARED_CODE, + sizeof(LiteralPatch)); p->pos = pos; p->next = stp->literal_patches; stp->literal_patches = p; @@ -4918,7 +4966,7 @@ new_literal_patch(LoaderState* stp, int pos) static void new_string_patch(LoaderState* stp, int pos) { - StringPatch* p = erts_alloc(ERTS_ALC_T_LOADER_TMP, sizeof(StringPatch)); + StringPatch* p = erts_alloc(ERTS_ALC_T_PREPARED_CODE, sizeof(StringPatch)); p->pos = pos; p->next = stp->string_patches; stp->string_patches = p; @@ -4936,14 +4984,14 @@ new_literal(LoaderState* stp, Eterm** hpp, Uint heap_size) ASSERT(stp->num_literals == 0); stp->allocated_literals = 8; need = stp->allocated_literals * sizeof(Literal); - stp->literals = (Literal *) erts_alloc(ERTS_ALC_T_LOADER_TMP, + stp->literals = (Literal *) erts_alloc(ERTS_ALC_T_PREPARED_CODE, need); } else if (stp->allocated_literals <= stp->num_literals) { Uint need; stp->allocated_literals *= 2; need = stp->allocated_literals * sizeof(Literal); - stp->literals = (Literal *) erts_realloc(ERTS_ALC_T_LOADER_TMP, + stp->literals = (Literal *) erts_realloc(ERTS_ALC_T_PREPARED_CODE, (void *) stp->literals, need); } @@ -4952,7 +5000,7 @@ new_literal(LoaderState* stp, Eterm** hpp, Uint heap_size) lit = stp->literals + stp->num_literals; lit->offset = 0; lit->heap_size = heap_size; - lit->heap = erts_alloc(ERTS_ALC_T_LOADER_TMP, heap_size*sizeof(Eterm)); + lit->heap = erts_alloc(ERTS_ALC_T_PREPARED_CODE, heap_size*sizeof(Eterm)); lit->term = make_boxed(lit->heap); lit->off_heap.first = 0; lit->off_heap.overhead = 0; @@ -5329,6 +5377,7 @@ code_get_chunk_2(BIF_ALIST_2) Process* p = BIF_P; Eterm Bin = BIF_ARG_1; Eterm Chunk = BIF_ARG_2; + Binary* magic = 0; LoaderState* stp; Uint chunk = 0; ErlSubBin* sb; @@ -5341,12 +5390,13 @@ code_get_chunk_2(BIF_ALIST_2) Eterm real_bin; byte* temp_alloc = NULL; - stp = erts_alloc_loader_state(); + magic = erts_alloc_loader_state(); + stp = ERTS_MAGIC_BIN_DATA(magic); if ((start = erts_get_aligned_binary_bytes(Bin, &temp_alloc)) == NULL) { error: erts_free_aligned_binary_bytes(temp_alloc); - if (stp) { - free_state(stp); + if (magic) { + free_loader_state(magic); } BIF_ERROR(p, BADARG); } @@ -5391,7 +5441,7 @@ code_get_chunk_2(BIF_ALIST_2) done: erts_free_aligned_binary_bytes(temp_alloc); - free_state(stp); + free_loader_state(magic); return res; } @@ -5404,14 +5454,16 @@ code_module_md5_1(BIF_ALIST_1) { Process* p = BIF_P; Eterm Bin = BIF_ARG_1; + Binary* magic; LoaderState* stp; byte* bytes; byte* temp_alloc = NULL; Eterm res; - stp = erts_alloc_loader_state(); + magic = erts_alloc_loader_state(); + stp = ERTS_MAGIC_BIN_DATA(magic); if ((bytes = erts_get_aligned_binary_bytes(Bin, &temp_alloc)) == NULL) { - free_state(stp); + free_loader_state(magic); BIF_ERROR(p, BADARG); } stp->module = THE_NON_VALUE; /* Suppress diagnostiscs */ @@ -5425,7 +5477,7 @@ code_module_md5_1(BIF_ALIST_1) done: erts_free_aligned_binary_bytes(temp_alloc); - free_state(stp); + free_loader_state(magic); return res; } @@ -5481,7 +5533,7 @@ stub_read_export_table(LoaderState* stp) stp->num_exps, stp->num_functions); } stp->export - = (ExportEntry *) erts_alloc(ERTS_ALC_T_LOADER_TMP, + = (ExportEntry *) erts_alloc(ERTS_ALC_T_PREPARED_CODE, stp->num_exps * sizeof(ExportEntry)); for (i = 0; i < stp->num_exps; i++) { @@ -5708,6 +5760,7 @@ patch_funentries(Eterm Patchlist) Eterm erts_make_stub_module(Process* p, Eterm Mod, Eterm Beam, Eterm Info) { + Binary* magic; LoaderState* stp; BeamInstr Funcs; BeamInstr Patchlist; @@ -5729,7 +5782,8 @@ erts_make_stub_module(Process* p, Eterm Mod, Eterm Beam, Eterm Info) * Must initialize stp->lambdas here because the error handling code * at label 'error' uses it. */ - stp = erts_alloc_loader_state(); + magic = erts_alloc_loader_state(); + stp = ERTS_MAGIC_BIN_DATA(magic); if (is_not_atom(Mod)) { goto error; @@ -5916,13 +5970,13 @@ erts_make_stub_module(Process* p, Eterm Mod, Eterm Beam, Eterm Info) if (patch_funentries(Patchlist)) { erts_free_aligned_binary_bytes(temp_alloc); - free_state(stp); + free_loader_state(magic); return Mod; } error: erts_free_aligned_binary_bytes(temp_alloc); - free_state(stp); + free_loader_state(magic); BIF_ERROR(p, BADARG); } diff --git a/erts/emulator/beam/erl_alloc.types b/erts/emulator/beam/erl_alloc.types index 90a6c0cbee..1b697d604c 100644 --- a/erts/emulator/beam/erl_alloc.types +++ b/erts/emulator/beam/erl_alloc.types @@ -164,6 +164,7 @@ type MSG_REF FIXED_SIZE PROCESSES msg_ref type MSG_ROOTS TEMPORARY PROCESSES msg_roots type ROOTSET TEMPORARY PROCESSES root_set type LOADER_TMP TEMPORARY CODE loader_tmp +type PREPARED_CODE SHORT_LIVED CODE prepared_code type BIF_TIMER_TABLE LONG_LIVED SYSTEM bif_timer_table type SL_BIF_TIMER SHORT_LIVED PROCESSES bif_timer_sl type LL_BIF_TIMER STANDARD PROCESSES bif_timer_ll diff --git a/erts/emulator/beam/global.h b/erts/emulator/beam/global.h index 9a174b1ab1..6bafff0d6e 100644 --- a/erts/emulator/beam/global.h +++ b/erts/emulator/beam/global.h @@ -872,11 +872,11 @@ typedef struct { Eterm* fname_ptr; /* Pointer to fname table */ } FunctionInfo; -struct LoaderState* erts_alloc_loader_state(void); -Eterm erts_prepare_loading(struct LoaderState*, Process *c_p, +Binary* erts_alloc_loader_state(void); +Eterm erts_prepare_loading(Binary* loader_state, Process *c_p, Eterm group_leader, Eterm* modp, byte* code, Uint size); -Eterm erts_finish_loading(struct LoaderState* stp, Process* c_p, +Eterm erts_finish_loading(Binary* loader_state, Process* c_p, ErtsProcLocks c_p_locks, Eterm* modp); Eterm erts_preload_module(Process *c_p, ErtsProcLocks c_p_locks, Eterm group_leader, Eterm* mod, byte* code, Uint size); -- cgit v1.2.3 From 64bcf5db63d73fe09298dac8cf5f6cad33fe7253 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20Gustavsson?= Date: Thu, 12 Jan 2012 20:12:59 +0100 Subject: Break apart erlang:load_module/2 into two separate BIFs Introduce two new BIFs, erlang:prepare_loading/2 and erlang:finish_loading/1, and re-implement erlang:load_module/2 in Erlang code. We have two reasons for doing this: * To facilitate suspending a process if another process is already doing code loading. * In the future, we can implement parallel and atomic loading of several modules. Atomic loading works except for modules with on_load handlers. Because of that issue, erlang:finish_loading/2 will currently only accept a list with a single magic binary. --- erts/emulator/beam/beam_bif_load.c | 295 ++++++++++++++++++++++++++----------- erts/emulator/beam/beam_load.c | 21 +++ erts/emulator/beam/bif.tab | 9 +- erts/emulator/beam/global.h | 1 + erts/preloaded/ebin/erlang.beam | Bin 86368 -> 87236 bytes erts/preloaded/src/erlang.erl | 37 ++++- 6 files changed, 270 insertions(+), 93 deletions(-) diff --git a/erts/emulator/beam/beam_bif_load.c b/erts/emulator/beam/beam_bif_load.c index 42642e103d..98e5ad1e3f 100644 --- a/erts/emulator/beam/beam_bif_load.c +++ b/erts/emulator/beam/beam_bif_load.c @@ -44,93 +44,6 @@ static int is_native(BeamInstr* code); static int any_heap_ref_ptrs(Eterm* start, Eterm* end, char* mod_start, Uint mod_size); static int any_heap_refs(Eterm* start, Eterm* end, char* mod_start, Uint mod_size); -Eterm -load_module_2(BIF_ALIST_2) -{ - Eterm reason; - Eterm* hp; - int sz; - byte* code; - Eterm res; - byte* temp_alloc = NULL; - Binary* magic; - int is_blocking = 0; - - if (is_not_atom(BIF_ARG_1)) { - error: - erts_free_aligned_binary_bytes(temp_alloc); - BIF_ERROR(BIF_P, BADARG); - } - if ((code = erts_get_aligned_binary_bytes(BIF_ARG_2, &temp_alloc)) == NULL) { - goto error; - } - hp = HAlloc(BIF_P, 3); - - /* - * Read the BEAM file and prepare the module for loading. - */ - magic = erts_alloc_loader_state(); - sz = binary_size(BIF_ARG_2); - reason = erts_prepare_loading(magic, BIF_P, BIF_P->group_leader, - &BIF_ARG_1, code, sz); - erts_free_aligned_binary_bytes(temp_alloc); - if (reason != NIL) { - res = TUPLE2(hp, am_error, reason); - BIF_RET(res); - } - - erts_lock_code_ix(); - for(;;) { - Module* modp; - erts_start_staging_code_ix(); - modp = erts_put_module(BIF_ARG_1); - if (!is_blocking) { - if (modp->curr.num_breakpoints > 0 - || modp->curr.num_traced_exports > 0 - || erts_is_default_trace_enabled()) { - /* we have tracing, retry single threaded */ - erts_abort_staging_code_ix(); - erts_unlock_code_ix(); - erts_smp_proc_unlock(BIF_P, ERTS_PROC_LOCK_MAIN); - erts_smp_thr_progress_block(); - is_blocking = 1; - continue; - } - } - else if (modp->curr.num_breakpoints) { - erts_clear_module_break(modp); - ASSERT(modp->curr.num_breakpoints == 0); - } - reason = erts_finish_loading(magic, BIF_P, 0, &BIF_ARG_1); - break; - } - - if (reason != NIL) { - if (reason == am_on_load) { - erts_commit_staging_code_ix(); - } - else { - erts_abort_staging_code_ix(); - } - res = TUPLE2(hp, am_error, reason); - } else { - erts_commit_staging_code_ix(); - if (is_blocking) { - set_default_trace_pattern(BIF_ARG_1); - } - res = TUPLE2(hp, am_module, BIF_ARG_1); - } - - if (is_blocking) { - erts_smp_thr_progress_unblock(); - erts_smp_proc_lock(BIF_P, ERTS_PROC_LOCK_MAIN); - } - else { - erts_unlock_code_ix(); - } - BIF_RET(res); -} - BIF_RETTYPE purge_module_1(BIF_ALIST_1) { int purge_res; @@ -199,6 +112,214 @@ BIF_RETTYPE code_make_stub_module_3(BIF_ALIST_3) return res; } +BIF_RETTYPE +prepare_loading_2(BIF_ALIST_2) +{ + byte* temp_alloc = NULL; + byte* code; + Uint sz; + Binary* magic; + Eterm reason; + Eterm* hp; + Eterm res; + + if (is_not_atom(BIF_ARG_1)) { + error: + erts_free_aligned_binary_bytes(temp_alloc); + BIF_ERROR(BIF_P, BADARG); + } + if ((code = erts_get_aligned_binary_bytes(BIF_ARG_2, &temp_alloc)) == NULL) { + goto error; + } + + magic = erts_alloc_loader_state(); + sz = binary_size(BIF_ARG_2); + reason = erts_prepare_loading(magic, BIF_P, BIF_P->group_leader, + &BIF_ARG_1, code, sz); + erts_free_aligned_binary_bytes(temp_alloc); + if (reason != NIL) { + hp = HAlloc(BIF_P, 3); + res = TUPLE2(hp, am_error, reason); + BIF_RET(res); + } + hp = HAlloc(BIF_P, PROC_BIN_SIZE); + res = erts_mk_magic_binary_term(&hp, &MSO(BIF_P), magic); + BIF_RET(res); +} + +struct m { + Binary* code; + Eterm module; + Module* modp; + Uint exception; +}; + +static Eterm +exception_list(Process* p, Eterm tag, struct m* mp, Sint exceptions) +{ + Eterm* hp = HAlloc(p, 3 + 2*exceptions); + Eterm res = NIL; + + mp += exceptions - 1; + while (exceptions > 0) { + if (mp->exception) { + res = CONS(hp, mp->module, res); + hp += 2; + exceptions--; + } + mp--; + } + return TUPLE2(hp, tag, res); +} + + +BIF_RETTYPE +finish_loading_1(BIF_ALIST_1) +{ + int i; + int n; + struct m* p; + Uint exceptions; + Eterm res; + int is_blocking = 0; + + /* + * Validate the argument before we start loading; it must be a + * proper list where each element is a magic binary containing + * prepared (not previously loaded) code. + * + * First count the number of elements and allocate an array + * to keep the elements in. + */ + + n = list_length(BIF_ARG_1); + if (n == -1) { + BIF_ERROR(BIF_P, BADARG); + } + p = erts_alloc(ERTS_ALC_T_LOADER_TMP, n*sizeof(struct m)); + + /* + * We now know that the argument is a proper list. Validate + * and collect the binaries into the array. + */ + + for (i = 0; i < n; i++) { + Eterm* cons = list_val(BIF_ARG_1); + Eterm term = CAR(cons); + ProcBin* pb; + + if (!ERTS_TERM_IS_MAGIC_BINARY(term)) { + error: + erts_free(ERTS_ALC_T_LOADER_TMP, p); + BIF_ERROR(BIF_P, BADARG); + } + pb = (ProcBin*) binary_val(term); + p[i].code = pb->val; + p[i].module = erts_module_for_prepared_code(p[i].code); + if (p[i].module == NIL) { + goto error; + } + BIF_ARG_1 = CDR(cons); + } + + /* + * Since we cannot handle atomic loading of a group of modules + * if one or more of them uses on_load, we will only allow one + * element in the list. This limitation is intended to be + * lifted in the future. + */ + + if (n > 1) { + erts_free(ERTS_ALC_T_LOADER_TMP, p); + BIF_ERROR(BIF_P, SYSTEM_LIMIT); + } + + /* + * All types are correct. There cannot be a BADARG from now on. + * Before we can start loading, we must check whether any of + * the modules already has old code. To avoid a race, we must + * not allow other process to initiate a code loading operation + * from now on. + */ + + res = am_ok; + erts_lock_code_ix(); + erts_start_staging_code_ix(); + + for (i = 0; i < n; i++) { + p[i].modp = erts_put_module(p[i].module); + if (p[i].modp->curr.num_breakpoints > 0 || + p[i].modp->curr.num_traced_exports > 0 || + erts_is_default_trace_enabled()) { + erts_abort_staging_code_ix(); + erts_unlock_code_ix(); + erts_smp_proc_unlock(BIF_P, ERTS_PROC_LOCK_MAIN); + erts_smp_thr_progress_block(); + is_blocking = 1; + break; + } + } + + if (is_blocking) { + for (i = 0; i < n; i++) { + if (p[i].modp->curr.num_breakpoints) { + erts_clear_module_break(p[i].modp); + ASSERT(p[i].modp->curr.num_breakpoints == 0); + } + } + } + + exceptions = 0; + for (i = 0; i < n; i++) { + p[i].exception = 0; + if (p[i].modp->curr.code && p[i].modp->old.code) { + p[i].exception = 1; + exceptions++; + } + } + + if (exceptions) { + res = exception_list(BIF_P, am_not_purged, p, exceptions); + erts_abort_staging_code_ix(); + } else { + /* + * Now we can load all code. This can't fail. + */ + + exceptions = 0; + for (i = 0; i < n; i++) { + Eterm mod; + Eterm retval; + + erts_refc_inc(&p[i].code->refc, 1); + retval = erts_finish_loading(p[i].code, BIF_P, 0, &mod); + ASSERT(retval == NIL || retval == am_on_load); + if (retval == am_on_load) { + p[i].exception = 1; + exceptions++; + } + } + + /* + * Check whether any module has an on_load_handler. + */ + + if (exceptions) { + res = exception_list(BIF_P, am_on_load, p, exceptions); + } + erts_commit_staging_code_ix(); + } + + erts_free(ERTS_ALC_T_LOADER_TMP, p); + if (!is_blocking) { + erts_unlock_code_ix(); + } else { + erts_smp_thr_progress_unblock(); + erts_smp_proc_lock(BIF_P, ERTS_PROC_LOCK_MAIN); + } + BIF_RET(res); +} + BIF_RETTYPE check_old_code_1(BIF_ALIST_1) { diff --git a/erts/emulator/beam/beam_load.c b/erts/emulator/beam/beam_load.c index a9246a84c1..cc4f5b5893 100644 --- a/erts/emulator/beam/beam_load.c +++ b/erts/emulator/beam/beam_load.c @@ -847,6 +847,27 @@ erts_alloc_loader_state(void) return magic; } +/* + * Return the module name (a tagged atom) for the prepared code + * in the magic binary, or NIL if the binary does not contain + * prepared code. + */ +int +erts_module_for_prepared_code(Binary* magic) +{ + LoaderState* stp; + + if (ERTS_MAGIC_BIN_DESTRUCTOR(magic) != loader_state_dtor) { + return NIL; + } + stp = ERTS_MAGIC_BIN_DATA(magic); + if (stp->code != 0) { + return stp->module; + } else { + return NIL; + } +} + static void free_loader_state(Binary* magic) { diff --git a/erts/emulator/beam/bif.tab b/erts/emulator/beam/bif.tab index 8cc568b16c..7f874a2d9c 100644 --- a/erts/emulator/beam/bif.tab +++ b/erts/emulator/beam/bif.tab @@ -142,8 +142,6 @@ bif erlang:list_to_pid/1 bif 'erl.lang.proc':string_to_pid/1 ebif_string_to_pid_1 list_to_pid_1 bif erlang:list_to_tuple/1 bif 'erl.lang.tuple':from_list/1 ebif_list_to_tuple_1 -bif erlang:load_module/2 -bif 'erl.system.code':load/2 ebif_load_module_2 bif erlang:loaded/0 bif 'erl.system.code':loaded/0 ebif_loaded_0 bif erlang:localtime/0 @@ -812,6 +810,13 @@ bif erlang:check_old_code/1 # bif erlang:universaltime_to_posixtime/1 bif erlang:posixtime_to_universaltime/1 + +# +# New in R16B. +# +bif erlang:prepare_loading/2 +bif erlang:finish_loading/1 + # # Obsolete # diff --git a/erts/emulator/beam/global.h b/erts/emulator/beam/global.h index 6bafff0d6e..53a73fd762 100644 --- a/erts/emulator/beam/global.h +++ b/erts/emulator/beam/global.h @@ -873,6 +873,7 @@ typedef struct { } FunctionInfo; Binary* erts_alloc_loader_state(void); +int erts_module_for_prepared_code(Binary* magic); Eterm erts_prepare_loading(Binary* loader_state, Process *c_p, Eterm group_leader, Eterm* modp, byte* code, Uint size); diff --git a/erts/preloaded/ebin/erlang.beam b/erts/preloaded/ebin/erlang.beam index cfd2a50431..efee885c6e 100644 Binary files a/erts/preloaded/ebin/erlang.beam and b/erts/preloaded/ebin/erlang.beam differ diff --git a/erts/preloaded/src/erlang.erl b/erts/preloaded/src/erlang.erl index 2c1821df40..01173ce4d6 100644 --- a/erts/preloaded/src/erlang.erl +++ b/erts/preloaded/src/erlang.erl @@ -82,7 +82,7 @@ -export([delete_module/1, demonitor/1, demonitor/2, display/1]). -export([display_nl/0, display_string/1, dist_exit/3, erase/0, erase/1]). -export([error/1, error/2, exit/1, exit/2, external_size/1]). --export([external_size/2, finish_after_on_load/2, float/1]). +-export([external_size/2, finish_after_on_load/2, finish_loading/1, float/1]). -export([float_to_list/1, fun_info/2, fun_to_list/1, function_exported/3]). -export([garbage_collect/0, garbage_collect/1]). -export([garbage_collect_message_area/0, get/0, get/1, get_keys/1]). @@ -101,7 +101,8 @@ -export([pid_to_list/1, port_close/1, port_command/2, port_command/3]). -export([port_connect/2, port_control/3, port_get_data/1]). -export([port_set_data/2, port_to_list/1, ports/0]). --export([posixtime_to_universaltime/1, pre_loaded/0, process_display/2]). +-export([posixtime_to_universaltime/1, pre_loaded/0, prepare_loading/2]). +-export([process_display/2]). -export([process_flag/3, process_info/1, processes/0, purge_module/1]). -export([put/2, raise/3, read_timer/1, ref_to_list/1, register/2]). -export([registered/0, resume_process/1, round/1, self/0, send_after/3]). @@ -627,6 +628,15 @@ external_size(_Term) -> external_size(_Term, _Options) -> erlang:nif_error(undefined). +%% finish_loading/2 +-spec erlang:finish_loading(PreparedCodeBinaries) -> ok | Error when + PreparedCodeBinaries :: [PreparedCodeBinary], + PreparedCodeBinary :: binary(), + ModuleList :: [module()], + Error :: {not_purged,ModuleList} | {on_load,ModuleList}. +finish_loading(_List) -> + erlang:nif_error(undefined). + %% finish_after_on_load/2 -spec erlang:finish_after_on_load(P1, P2) -> true when P1 :: atom(), @@ -1080,6 +1090,15 @@ ports() -> posixtime_to_universaltime(_P1) -> erlang:nif_error(undefined). +%% prepare_loading/2 +-spec erlang:prepare_loading(Module, Code) -> PreparedCode | {error, Reason} when + Module :: module(), + Code :: binary(), + PreparedCode :: binary(), + Reason :: bad_file. +prepare_loading(_Module, _Code) -> + erlang:nif_error(undefined). + %% pre_loaded/0 -spec pre_loaded() -> [module()]. pre_loaded() -> @@ -1547,8 +1566,18 @@ is_tuple(_Term) -> Module :: module(), Binary :: binary(), Reason :: badfile | not_purged | on_load. -load_module(_Module,_Binary) -> - erlang:nif_error(undefined). +load_module(Mod, Code) -> + case erlang:prepare_loading(Mod, Code) of + {error,_}=Error -> + Error; + Bin when erlang:is_binary(Bin) -> + case erlang:finish_loading([Bin]) of + ok -> + {module,Mod}; + {Error,[Mod]} -> + {error,Error} + end + end. -spec erlang:load_nif(Path, LoadInfo) -> ok | Error when Path :: string(), -- cgit v1.2.3 From 7985815fc4c25c6bfc5d6101cd862138060098b9 Mon Sep 17 00:00:00 2001 From: Sverker Eriksson Date: Thu, 9 Feb 2012 14:40:12 +0100 Subject: erts: Fix type bug --- erts/emulator/beam/beam_load.c | 2 +- erts/emulator/beam/global.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/erts/emulator/beam/beam_load.c b/erts/emulator/beam/beam_load.c index cc4f5b5893..d3f55a2ba4 100644 --- a/erts/emulator/beam/beam_load.c +++ b/erts/emulator/beam/beam_load.c @@ -852,7 +852,7 @@ erts_alloc_loader_state(void) * in the magic binary, or NIL if the binary does not contain * prepared code. */ -int +Eterm erts_module_for_prepared_code(Binary* magic) { LoaderState* stp; diff --git a/erts/emulator/beam/global.h b/erts/emulator/beam/global.h index 53a73fd762..6eac0db363 100644 --- a/erts/emulator/beam/global.h +++ b/erts/emulator/beam/global.h @@ -873,7 +873,7 @@ typedef struct { } FunctionInfo; Binary* erts_alloc_loader_state(void); -int erts_module_for_prepared_code(Binary* magic); +Eterm erts_module_for_prepared_code(Binary* magic); Eterm erts_prepare_loading(Binary* loader_state, Process *c_p, Eterm group_leader, Eterm* modp, byte* code, Uint size); -- cgit v1.2.3 From 8880cb9681f11f91928dc291f2a8ec7ff1934bcd Mon Sep 17 00:00:00 2001 From: Sverker Eriksson Date: Thu, 9 Feb 2012 15:53:31 +0100 Subject: erts: Fix single threaded fallback in new BIF finish_loading_1 Must "start staging" even when we go single threaded. --- erts/emulator/beam/beam_bif_load.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/erts/emulator/beam/beam_bif_load.c b/erts/emulator/beam/beam_bif_load.c index 98e5ad1e3f..8a2169f9e6 100644 --- a/erts/emulator/beam/beam_bif_load.c +++ b/erts/emulator/beam/beam_bif_load.c @@ -248,14 +248,18 @@ finish_loading_1(BIF_ALIST_1) for (i = 0; i < n; i++) { p[i].modp = erts_put_module(p[i].module); + } + for (i = 0; i < n; i++) { if (p[i].modp->curr.num_breakpoints > 0 || p[i].modp->curr.num_traced_exports > 0 || erts_is_default_trace_enabled()) { + /* tracing involved, fallback with thread blocking */ erts_abort_staging_code_ix(); erts_unlock_code_ix(); erts_smp_proc_unlock(BIF_P, ERTS_PROC_LOCK_MAIN); erts_smp_thr_progress_block(); is_blocking = 1; + erts_start_staging_code_ix(); break; } } -- cgit v1.2.3 From 7da22e299ad0d2d6bf389650f4d74f4f22242111 Mon Sep 17 00:00:00 2001 From: Sverker Eriksson Date: Thu, 9 Feb 2012 14:41:58 +0100 Subject: erts: Fix compiler warning in inet_drv --- erts/emulator/drivers/common/inet_drv.c | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/erts/emulator/drivers/common/inet_drv.c b/erts/emulator/drivers/common/inet_drv.c index 47a99fdbe6..608bb5ecaa 100644 --- a/erts/emulator/drivers/common/inet_drv.c +++ b/erts/emulator/drivers/common/inet_drv.c @@ -535,6 +535,12 @@ static int my_strncasecmp(const char *s1, const char *s2, size_t n) #endif /* __WIN32__ */ +#ifdef HAVE_SOCKLEN_T +# define SOCKLEN_T socklen_t +#else +# define SOCKLEN_T int +#endif + #include "packet_parser.h" #define get_int24(s) ((((unsigned char*) (s))[0] << 16) | \ @@ -5340,13 +5346,8 @@ static int setopt_prio_tos_trick int res; int res_prio; int res_tos; -#ifdef HAVE_SOCKLEN_T - socklen_t -#else - int -#endif - tmp_arg_sz_prio = sizeof(tmp_ival_prio), - tmp_arg_sz_tos = sizeof(tmp_ival_tos); + SOCKLEN_T tmp_arg_sz_prio = sizeof(tmp_ival_prio); + SOCKLEN_T tmp_arg_sz_tos = sizeof(tmp_ival_tos); res_prio = sock_getopt(fd, SOL_SOCKET, SO_PRIORITY, (char *) &tmp_ival_prio, &tmp_arg_sz_prio); @@ -7754,8 +7755,8 @@ static ErlDrvSSizeT inet_ctl(inet_descriptor* desc, int cmd, char* buf, desc->state = INET_STATE_BOUND; if ((port = inet_address_port(&local)) == 0) { - len = sizeof(local); - sock_name(desc->s, (struct sockaddr*) &local, (unsigned int*)&len); + SOCKLEN_T adrlen = sizeof(local); + sock_name(desc->s, &local.sa, &adrlen); port = inet_address_port(&local); } port = sock_ntohs(port); -- cgit v1.2.3 From c4a8cc5914157c70ced742d957ec0e8d9c618164 Mon Sep 17 00:00:00 2001 From: Sverker Eriksson Date: Fri, 10 Feb 2012 18:22:42 +0100 Subject: erts: Suspend processes waiting for code_ix lock This will prevent blocking entrire schedulers in the rare case when several processes are racing to load/upgrade/delete/purge code. --- erts/emulator/beam/beam_bif_load.c | 78 ++++++++++++++++++------------------- erts/emulator/beam/code_ix.c | 57 ++++++++++++++++++++++----- erts/emulator/beam/code_ix.h | 12 +++--- erts/emulator/beam/erl_alloc.types | 1 + erts/emulator/beam/erl_lock_check.c | 2 +- 5 files changed, 95 insertions(+), 55 deletions(-) diff --git a/erts/emulator/beam/beam_bif_load.c b/erts/emulator/beam/beam_bif_load.c index 8a2169f9e6..1227af8cbb 100644 --- a/erts/emulator/beam/beam_bif_load.c +++ b/erts/emulator/beam/beam_bif_load.c @@ -38,27 +38,11 @@ static void set_default_trace_pattern(Eterm module); static Eterm check_process_code(Process* rp, Module* modp); static void delete_code(Module* modp); -static int purge_module(Process*, int module); static void decrement_refc(BeamInstr* code); static int is_native(BeamInstr* code); static int any_heap_ref_ptrs(Eterm* start, Eterm* end, char* mod_start, Uint mod_size); static int any_heap_refs(Eterm* start, Eterm* end, char* mod_start, Uint mod_size); -BIF_RETTYPE purge_module_1(BIF_ALIST_1) -{ - int purge_res; - - if (is_not_atom(BIF_ARG_1)) { - BIF_ERROR(BIF_P, BADARG); - } - - purge_res = purge_module(BIF_P, atom_val(BIF_ARG_1)); - - if (purge_res < 0) { - BIF_ERROR(BIF_P, BADARG); - } - BIF_RET(am_true); -} BIF_RETTYPE code_is_module_native_1(BIF_ALIST_1) { @@ -178,11 +162,15 @@ finish_loading_1(BIF_ALIST_1) { int i; int n; - struct m* p; + struct m* p = NULL; Uint exceptions; Eterm res; int is_blocking = 0; + if (!erts_try_lock_code_ix(BIF_P)) { + ERTS_BIF_YIELD1(bif_export[BIF_finish_loading_1], BIF_P, BIF_ARG_1); + } + /* * Validate the argument before we start loading; it must be a * proper list where each element is a magic binary containing @@ -194,7 +182,8 @@ finish_loading_1(BIF_ALIST_1) n = list_length(BIF_ARG_1); if (n == -1) { - BIF_ERROR(BIF_P, BADARG); + ERTS_BIF_PREP_ERROR(res, BIF_P, BADARG); + goto done; } p = erts_alloc(ERTS_ALC_T_LOADER_TMP, n*sizeof(struct m)); @@ -209,15 +198,15 @@ finish_loading_1(BIF_ALIST_1) ProcBin* pb; if (!ERTS_TERM_IS_MAGIC_BINARY(term)) { - error: - erts_free(ERTS_ALC_T_LOADER_TMP, p); - BIF_ERROR(BIF_P, BADARG); + ERTS_BIF_PREP_ERROR(res, BIF_P, BADARG); + goto done; } pb = (ProcBin*) binary_val(term); p[i].code = pb->val; p[i].module = erts_module_for_prepared_code(p[i].code); if (p[i].module == NIL) { - goto error; + ERTS_BIF_PREP_ERROR(res, BIF_P, BADARG); + goto done; } BIF_ARG_1 = CDR(cons); } @@ -230,8 +219,8 @@ finish_loading_1(BIF_ALIST_1) */ if (n > 1) { - erts_free(ERTS_ALC_T_LOADER_TMP, p); - BIF_ERROR(BIF_P, SYSTEM_LIMIT); + ERTS_BIF_PREP_ERROR(res, BIF_P, SYSTEM_LIMIT); + goto done; } /* @@ -243,7 +232,6 @@ finish_loading_1(BIF_ALIST_1) */ res = am_ok; - erts_lock_code_ix(); erts_start_staging_code_ix(); for (i = 0; i < n; i++) { @@ -314,7 +302,10 @@ finish_loading_1(BIF_ALIST_1) erts_commit_staging_code_ix(); } - erts_free(ERTS_ALC_T_LOADER_TMP, p); +done: + if (p) { + erts_free(ERTS_ALC_T_LOADER_TMP, p); + } if (!is_blocking) { erts_unlock_code_ix(); } else { @@ -418,10 +409,14 @@ BIF_RETTYPE delete_module_1(BIF_ALIST_1) int is_blocking = 0; Eterm res = NIL; - if (is_not_atom(BIF_ARG_1)) + if (is_not_atom(BIF_ARG_1)) { goto badarg; + } + + if (!erts_try_lock_code_ix(BIF_P)) { + ERTS_BIF_YIELD1(bif_export[BIF_delete_module_1], BIF_P, BIF_ARG_1); + } - erts_lock_code_ix(); do { erts_start_staging_code_ix(); code_ix = erts_staging_code_ix(); @@ -856,18 +851,23 @@ any_heap_refs(Eterm* start, Eterm* end, char* mod_start, Uint mod_size) #undef in_area - -static int -purge_module(Process* c_p, int module) +BIF_RETTYPE purge_module_1(BIF_ALIST_1) { ErtsCodeIndex code_ix; BeamInstr* code; BeamInstr* end; Module* modp; int is_blocking = 0; - int ret; + Eterm ret; + + if (is_not_atom(BIF_ARG_1)) { + BIF_ERROR(BIF_P, BADARG); + } + + if (!erts_try_lock_code_ix(BIF_P)) { + ERTS_BIF_YIELD1(bif_export[BIF_purge_module_1], BIF_P, BIF_ARG_1); + } - erts_lock_code_ix(); retry: code_ix = erts_active_code_ix(); @@ -875,8 +875,8 @@ retry: * Correct module? */ - if ((modp = erts_get_module(make_atom(module), code_ix)) == NULL) { - ret = -2; + if ((modp = erts_get_module(BIF_ARG_1, code_ix)) == NULL) { + ERTS_BIF_PREP_ERROR(ret, BIF_P, BADARG); } else { erts_rwlock_old_code(code_ix); @@ -885,7 +885,7 @@ retry: * Any code to purge? */ if (modp->old.code == 0) { - ret = -1; + ERTS_BIF_PREP_ERROR(ret, BIF_P, BADARG); } else { /* @@ -896,7 +896,7 @@ retry: /* ToDo: Do unload nif without blocking */ erts_rwunlock_old_code(code_ix); erts_unlock_code_ix(); - erts_smp_proc_unlock(c_p, ERTS_PROC_LOCK_MAIN); + erts_smp_proc_unlock(BIF_P, ERTS_PROC_LOCK_MAIN); erts_smp_thr_progress_block(); is_blocking = 1; goto retry; @@ -922,13 +922,13 @@ retry: modp->old.code_length = 0; modp->old.catches = BEAM_CATCHES_NIL; erts_remove_from_ranges(code); - ret = 0; + ERTS_BIF_PREP_RET(ret, am_true); } erts_rwunlock_old_code(code_ix); } if (is_blocking) { erts_smp_thr_progress_unblock(); - erts_smp_proc_lock(c_p, ERTS_PROC_LOCK_MAIN); + erts_smp_proc_lock(BIF_P, ERTS_PROC_LOCK_MAIN); } else { erts_unlock_code_ix(); diff --git a/erts/emulator/beam/code_ix.c b/erts/emulator/beam/code_ix.c index a8b6599e61..a1db003127 100644 --- a/erts/emulator/beam/code_ix.c +++ b/erts/emulator/beam/code_ix.c @@ -36,7 +36,13 @@ erts_smp_atomic32_t the_active_code_index; erts_smp_atomic32_t the_staging_code_index; -static erts_smp_mtx_t sverk_code_ix_lock; /*SVERK FIXME */ +static int the_code_ix_lock = 0; +struct code_ix_queue_item { + Process *p; + struct code_ix_queue_item* next; +}; +static struct code_ix_queue_item* the_code_ix_queue = NULL; +static erts_smp_mtx_t the_code_ix_queue_lock; void erts_code_ix_init(void) { @@ -46,7 +52,7 @@ void erts_code_ix_init(void) */ erts_smp_atomic32_init_nob(&the_active_code_index, 0); erts_smp_atomic32_init_nob(&the_staging_code_index, 0); - erts_smp_mtx_init_x(&sverk_code_ix_lock, "sverk_code_ix_lock", NIL); /*SVERK FIXME */ + erts_smp_mtx_init(&the_code_ix_queue_lock, "code_ix_queue"); CIX_TRACE("init"); } @@ -88,23 +94,54 @@ void erts_abort_staging_code_ix(void) } -/* Lock code_ix (enqueue and suspend until we get it) -*/ -void erts_lock_code_ix(void) +/* Try lock code_ix + * Calller _must_ yield if we return 0 + */ +int erts_try_lock_code_ix(Process* c_p) { - erts_smp_mtx_lock(&sverk_code_ix_lock); /*SVERK FIXME */ + int success; + + erts_smp_mtx_lock(&the_code_ix_queue_lock); + success = !the_code_ix_lock; + if (success) { + the_code_ix_lock = 1; + } + else { /* Already locked */ + struct code_ix_queue_item* qitem; + qitem = erts_alloc(ERTS_ALC_T_CODE_IX_LOCK_Q, sizeof(*qitem)); + qitem->p = c_p; + erts_smp_proc_inc_refc(c_p); + qitem->next = the_code_ix_queue; + the_code_ix_queue = qitem; + erts_suspend(c_p, ERTS_PROC_LOCK_MAIN, NULL); + } + erts_smp_mtx_unlock(&the_code_ix_queue_lock); + return success; } -/* Unlock code_ix (resume first waiter) +/* Unlock code_ix (resume all waiters) */ -void erts_unlock_code_ix(void) +void erts_unlock_code_ix() { - erts_smp_mtx_unlock(&sverk_code_ix_lock); /*SVERK FIXME */ + erts_smp_mtx_lock(&the_code_ix_queue_lock); + while (the_code_ix_queue != NULL) { /* unleash the entire herd */ + struct code_ix_queue_item* qitem = the_code_ix_queue; + erts_smp_proc_lock(qitem->p, ERTS_PROC_LOCK_STATUS); + if (!ERTS_PROC_IS_EXITING(qitem->p)) { + erts_resume(qitem->p, ERTS_PROC_LOCK_STATUS); + } + erts_smp_proc_unlock(qitem->p, ERTS_PROC_LOCK_STATUS); + the_code_ix_queue = qitem->next; + erts_smp_proc_dec_refc(qitem->p); + erts_free(ERTS_ALC_T_CODE_IX_LOCK_Q, qitem); + } + the_code_ix_lock = 0; + erts_smp_mtx_unlock(&the_code_ix_queue_lock); } #ifdef ERTS_ENABLE_LOCK_CHECK int erts_is_code_ix_locked(void) { - return erts_smp_lc_mtx_is_locked(&sverk_code_ix_lock); + return the_code_ix_lock; } #endif diff --git a/erts/emulator/beam/code_ix.h b/erts/emulator/beam/code_ix.h index 99fd4ec348..66543fa2a8 100644 --- a/erts/emulator/beam/code_ix.h +++ b/erts/emulator/beam/code_ix.h @@ -55,10 +55,13 @@ # endif # include "sys.h" #endif +struct process; + #define ERTS_NUM_CODE_IX 3 typedef unsigned ErtsCodeIndex; + /* Called once at emulator initialization. */ void erts_code_ix_init(void); @@ -78,14 +81,13 @@ ErtsCodeIndex erts_active_code_ix(void); ERTS_GLB_INLINE ErtsCodeIndex erts_staging_code_ix(void); -/* Lock code_ix. - * Gives (exclusive) access to the staging area and write access to active code index. - * ToDo: Waiting process should be queued and return to be suspended. +/* Try lock code_ix that is needed for (exlusive) access of the staging area. + * Main process lock (only) must be held. + * Caller is suspended and *must* yield if 0 is returned. */ -void erts_lock_code_ix(void); +int erts_try_lock_code_ix(struct process*); /* Unlock code_ix - * ToDo: Dequeue and resume waiting processes. */ void erts_unlock_code_ix(void); diff --git a/erts/emulator/beam/erl_alloc.types b/erts/emulator/beam/erl_alloc.types index 1b697d604c..de7d5599bb 100644 --- a/erts/emulator/beam/erl_alloc.types +++ b/erts/emulator/beam/erl_alloc.types @@ -264,6 +264,7 @@ type ZLIB STANDARD SYSTEM zlib type CPU_GRPS_MAP LONG_LIVED SYSTEM cpu_groups_map type AUX_WORK_TMO LONG_LIVED SYSTEM aux_work_timeouts type MISC_AUX_WORK_Q LONG_LIVED SYSTEM misc_aux_work_q +type CODE_IX_LOCK_Q SHORT_LIVED SYSTEM code_ix_lock_q +if threads_no_smp # Need thread safe allocs, but std_alloc and fix_alloc are not; diff --git a/erts/emulator/beam/erl_lock_check.c b/erts/emulator/beam/erl_lock_check.c index 772d3a03b2..8c7e1f36ee 100644 --- a/erts/emulator/beam/erl_lock_check.c +++ b/erts/emulator/beam/erl_lock_check.c @@ -84,7 +84,6 @@ static erts_lc_lock_order_t erts_lock_order[] = { { "reg_tab", NULL }, { "migration_info_update", NULL }, { "proc_main", "pid" }, - { "sverk_code_ix_lock", NULL }, /*SVERK FIXME */ { "old_code", "address" }, #ifdef HIPE { "hipe_mfait_lock", NULL }, @@ -95,6 +94,7 @@ static erts_lc_lock_order_t erts_lock_order[] = { { "proc_msgq", "pid" }, { "dist_entry", "address" }, { "dist_entry_links", "address" }, + { "code_ix_queue", NULL }, { "proc_status", "pid" }, { "proc_tab", NULL }, { "ports_snapshot", NULL }, -- cgit v1.2.3 From dc2b0ecba50cbe6b2f2321b1f24579a0353ced18 Mon Sep 17 00:00:00 2001 From: Sverker Eriksson Date: Wed, 15 Feb 2012 15:12:18 +0100 Subject: erts: Activate staged code in a thread safe way Activation of staged code is scheduled for a later moment when all schedulers have done a full memory barrier. This allow them to read active code index while executing without any memory barriers at all. --- erts/emulator/beam/beam_bif_load.c | 95 +++++++++++++++++++++++++------------- erts/emulator/beam/code_ix.c | 27 ++++++----- erts/emulator/beam/code_ix.h | 23 +++++---- erts/emulator/beam/erl_init.c | 3 +- erts/emulator/beam/erl_process.c | 53 ++++++++++++++++++++- erts/emulator/beam/erl_process.h | 10 ++++ 6 files changed, 154 insertions(+), 57 deletions(-) diff --git a/erts/emulator/beam/beam_bif_load.c b/erts/emulator/beam/beam_bif_load.c index 1227af8cbb..6df5774fdb 100644 --- a/erts/emulator/beam/beam_bif_load.c +++ b/erts/emulator/beam/beam_bif_load.c @@ -35,6 +35,7 @@ #include "erl_nif.h" #include "erl_thr_progress.h" +static Eterm staging_epilogue(Process* c_p, int, Eterm res, int); static void set_default_trace_pattern(Eterm module); static Eterm check_process_code(Process* rp, Module* modp); static void delete_code(Module* modp); @@ -86,7 +87,8 @@ BIF_RETTYPE code_make_stub_module_3(BIF_ALIST_3) res = erts_make_stub_module(BIF_P, BIF_ARG_1, BIF_ARG_2, BIF_ARG_3); if (res == BIF_ARG_1) { - erts_commit_staging_code_ix(); + erts_end_staging_code_ix(); + erts_activate_staging_code_ix(); } else { erts_abort_staging_code_ix(); @@ -166,6 +168,7 @@ finish_loading_1(BIF_ALIST_1) Uint exceptions; Eterm res; int is_blocking = 0; + int do_commit = 0; if (!erts_try_lock_code_ix(BIF_P)) { ERTS_BIF_YIELD1(bif_export[BIF_finish_loading_1], BIF_P, BIF_ARG_1); @@ -272,7 +275,6 @@ finish_loading_1(BIF_ALIST_1) if (exceptions) { res = exception_list(BIF_P, am_not_purged, p, exceptions); - erts_abort_staging_code_ix(); } else { /* * Now we can load all code. This can't fail. @@ -299,20 +301,63 @@ finish_loading_1(BIF_ALIST_1) if (exceptions) { res = exception_list(BIF_P, am_on_load, p, exceptions); } - erts_commit_staging_code_ix(); + do_commit = 1; } done: if (p) { erts_free(ERTS_ALC_T_LOADER_TMP, p); } - if (!is_blocking) { - erts_unlock_code_ix(); - } else { - erts_smp_thr_progress_unblock(); - erts_smp_proc_lock(BIF_P, ERTS_PROC_LOCK_MAIN); + return staging_epilogue(BIF_P, do_commit, res, is_blocking); +} + +static Eterm +staging_epilogue(Process* c_p, int commit, Eterm res, int is_blocking) +{ +#ifdef ERTS_SMP + if (is_blocking || !commit) +#endif + { + if (commit) { + erts_end_staging_code_ix(); + erts_activate_staging_code_ix(); + } + else { + erts_abort_staging_code_ix(); + } + if (is_blocking) { + erts_smp_thr_progress_unblock(); + erts_smp_proc_lock(c_p, ERTS_PROC_LOCK_MAIN); + } + else { + erts_unlock_code_ix(); + } + return res; } - BIF_RET(res); +#ifdef ERTS_SMP + else { + ErtsThrPrgrVal later; + ASSERT(is_value(res)); + + erts_end_staging_code_ix(); + /* + * Now we must wait for all schedulers to do a memory barrier before + * we can activate and let them access the new staged code. This allows + * schedulers to read active code_ix in a safe way while executing + * without any memory barriers at all. + */ + + later = erts_thr_progress_later(); + erts_thr_progress_wakeup(c_p->scheduler_data, later); + erts_notify_code_ix_activation(c_p, later); + erts_suspend(c_p, ERTS_PROC_LOCK_MAIN, NULL); + /* + * handle_code_ix_activation() will do the rest "later" + * and resume this process in bif_return_trap() to return 'res'. + */ + ERTS_BIF_YIELD1(&bif_return_trap_export, c_p, res); + } +#endif } BIF_RETTYPE @@ -407,17 +452,18 @@ BIF_RETTYPE delete_module_1(BIF_ALIST_1) ErtsCodeIndex code_ix; Module* modp; int is_blocking = 0; + int success = 0; Eterm res = NIL; if (is_not_atom(BIF_ARG_1)) { - goto badarg; + BIF_ERROR(BIF_P, BADARG); } if (!erts_try_lock_code_ix(BIF_P)) { ERTS_BIF_YIELD1(bif_export[BIF_delete_module_1], BIF_P, BIF_ARG_1); } - - do { +retry: + { erts_start_staging_code_ix(); code_ix = erts_staging_code_ix(); modp = erts_get_module(BIF_ARG_1, code_ix); @@ -429,7 +475,7 @@ BIF_RETTYPE delete_module_1(BIF_ALIST_1) erts_dsprintf(dsbufp, "Module %T must be purged before loading\n", BIF_ARG_1); erts_send_error_to_logger(BIF_P->group_leader, dsbufp); - res = am_badarg; + ERTS_BIF_PREP_ERROR(res, BIF_P, BADARG); } else { if (!is_blocking) { @@ -441,7 +487,7 @@ BIF_RETTYPE delete_module_1(BIF_ALIST_1) erts_smp_proc_unlock(BIF_P, ERTS_PROC_LOCK_MAIN); erts_smp_thr_progress_block(); is_blocking = 1; - continue; + goto retry; } } else if (modp->curr.num_breakpoints) { @@ -450,28 +496,11 @@ BIF_RETTYPE delete_module_1(BIF_ALIST_1) } delete_code(modp); res = am_true; + success = 1; } - } while (res == NIL); - - if (res == am_true) { - erts_commit_staging_code_ix(); - } - else { - erts_abort_staging_code_ix(); - } - if (is_blocking) { - erts_smp_thr_progress_unblock(); - erts_smp_proc_lock(BIF_P, ERTS_PROC_LOCK_MAIN); - } - else { - erts_unlock_code_ix(); } - if (res == am_badarg) { - badarg: - BIF_ERROR(BIF_P, BADARG); - } - BIF_RET(res); + return staging_epilogue(BIF_P, success, res, is_blocking); } BIF_RETTYPE module_loaded_1(BIF_ALIST_1) diff --git a/erts/emulator/beam/code_ix.c b/erts/emulator/beam/code_ix.c index a1db003127..5565b51e7e 100644 --- a/erts/emulator/beam/code_ix.c +++ b/erts/emulator/beam/code_ix.c @@ -66,22 +66,25 @@ void erts_start_staging_code_ix(void) } -void erts_commit_staging_code_ix(void) +void erts_end_staging_code_ix(void) { beam_catches_end_staging(1); export_end_staging(1); module_end_staging(1); erts_end_staging_ranges(1); - { - ErtsCodeIndex ix; - export_write_lock(); - ix = erts_staging_code_ix(); - erts_smp_atomic32_set_nob(&the_active_code_index, ix); - ix = (ix + 1) % ERTS_NUM_CODE_IX; - erts_smp_atomic32_set_nob(&the_staging_code_index, ix); - export_write_unlock(); - } - CIX_TRACE("commit"); + CIX_TRACE("end"); +} + +void erts_activate_staging_code_ix(void) +{ + ErtsCodeIndex ix; + export_write_lock(); + ix = erts_staging_code_ix(); + erts_smp_atomic32_set_nob(&the_active_code_index, ix); + ix = (ix + 1) % ERTS_NUM_CODE_IX; + erts_smp_atomic32_set_nob(&the_staging_code_index, ix); + export_write_unlock(); + CIX_TRACE("activate"); } void erts_abort_staging_code_ix(void) @@ -121,7 +124,7 @@ int erts_try_lock_code_ix(Process* c_p) /* Unlock code_ix (resume all waiters) */ -void erts_unlock_code_ix() +void erts_unlock_code_ix(void) { erts_smp_mtx_lock(&the_code_ix_queue_lock); while (the_code_ix_queue != NULL) { /* unleash the entire herd */ diff --git a/erts/emulator/beam/code_ix.h b/erts/emulator/beam/code_ix.h index 66543fa2a8..bac8c3365c 100644 --- a/erts/emulator/beam/code_ix.h +++ b/erts/emulator/beam/code_ix.h @@ -91,22 +91,27 @@ int erts_try_lock_code_ix(struct process*); */ void erts_unlock_code_ix(void); -/* Make the "staging area" a complete copy of the active code. +/* Prepare the "staging area" to be a complete copy of the active code. * code_ix must be locked. - * Must be followed by a call to either "commit" or "abort" before code_ix lock - * is released. + * Must be followed by calls to either "end" and "activate" or "abort" before + * code_ix lock is released. */ void erts_start_staging_code_ix(void); -/* Commit the staging area and update the active code index. - * code_ix must be locked and erts_start_staging_code_ix() called. - * ToDo: Updating active code index should be done according to Rickard's recipe. - * This function might need to be split into two. +/* End the staging. + * code_ix must be locked. + * Must be followed by a call to either "activate" or "abort" + * before code_ix lock is released. + */ +void erts_end_staging_code_ix(void); + +/* Set staging code index as new active code index. + * code_ix must be locked and "start" and "end" called. */ -void erts_commit_staging_code_ix(void); +void erts_activate_staging_code_ix(void); /* Abort the staging. - * code_ix must be locked and erts_start_staging_code_ix() called. + * code_ix must be locked and "start" called. */ void erts_abort_staging_code_ix(void); diff --git a/erts/emulator/beam/erl_init.c b/erts/emulator/beam/erl_init.c index 2d192b3fc4..a4690891d5 100644 --- a/erts/emulator/beam/erl_init.c +++ b/erts/emulator/beam/erl_init.c @@ -1473,7 +1473,8 @@ erl_start(int argc, char **argv) init_shared_memory(boot_argc, boot_argv); load_preloaded(); - erts_commit_staging_code_ix(); + erts_end_staging_code_ix(); + erts_activate_staging_code_ix(); erts_initialized = 1; diff --git a/erts/emulator/beam/erl_process.c b/erts/emulator/beam/erl_process.c index 44a99e1f84..aaee951107 100644 --- a/erts/emulator/beam/erl_process.c +++ b/erts/emulator/beam/erl_process.c @@ -366,6 +366,9 @@ dbg_chk_aux_work_val(erts_aint32_t value) #ifdef ERTS_SMP_SCHEDULERS_NEED_TO_CHECK_CHILDREN valid |= ERTS_SSI_AUX_WORK_CHECK_CHILDREN; #endif +#ifdef ERTS_SMP + valid |= ERTS_SSI_AUX_WORK_CODE_IX_ACTIVATION; +#endif if (~valid & value) erl_exit(ERTS_ABORT_EXIT, @@ -861,7 +864,7 @@ set_aux_work_flags_wakeup_nob(ErtsSchedulerSleepInfo *ssi, } } -#if 0 /* Currently not used */ +#ifdef ERTS_SMP static ERTS_INLINE void set_aux_work_flags_wakeup_relb(ErtsSchedulerSleepInfo *ssi, @@ -882,7 +885,7 @@ set_aux_work_flags_wakeup_relb(ErtsSchedulerSleepInfo *ssi, } } -#endif +#endif /* ERTS_SMP */ static ERTS_INLINE erts_aint32_t set_aux_work_flags(ErtsSchedulerSleepInfo *ssi, erts_aint32_t flgs) @@ -1145,7 +1148,49 @@ handle_async_ready_clean(ErtsAuxWorkData *awdp, } } +#endif /* ERTS_USE_ASYNC_READY_Q */ + +#ifdef ERTS_SMP +void +erts_notify_code_ix_activation(Process* p, ErtsThrPrgrVal later) +{ + ErtsAuxWorkData* awdp = &p->scheduler_data->aux_work_data; + ASSERT(awdp->code_ix_activation.code_stager == NULL); + awdp->code_ix_activation.code_stager = p; + awdp->code_ix_activation.thr_prgr = later; + erts_smp_proc_inc_refc(p); + set_aux_work_flags_wakeup_relb(p->scheduler_data->ssi, + ERTS_SSI_AUX_WORK_CODE_IX_ACTIVATION); +} + +static erts_aint32_t +handle_code_ix_activation(ErtsAuxWorkData *awdp, erts_aint32_t aux_work) +{ + Process* p; + if (!erts_thr_progress_has_reached(awdp->code_ix_activation.thr_prgr)) { + return aux_work & ~ERTS_SSI_AUX_WORK_CODE_IX_ACTIVATION; + } + unset_aux_work_flags(awdp->ssi, ERTS_SSI_AUX_WORK_CODE_IX_ACTIVATION); + p = awdp->code_ix_activation.code_stager; + ASSERT(p); +#ifdef DEBUG + awdp->code_ix_activation.code_stager = NULL; #endif + erts_smp_proc_lock(p, ERTS_PROC_LOCK_STATUS); + if (!ERTS_PROC_IS_EXITING(p)) { + erts_activate_staging_code_ix(); + erts_resume(p, ERTS_PROC_LOCK_STATUS); + erts_smp_proc_unlock(p, ERTS_PROC_LOCK_STATUS); + } + else { + erts_smp_proc_unlock(p, ERTS_PROC_LOCK_STATUS); + erts_abort_staging_code_ix(); + } + erts_unlock_code_ix(); + erts_smp_proc_dec_refc(p); + return aux_work & ~ERTS_SSI_AUX_WORK_CODE_IX_ACTIVATION; +} +#endif /* ERTS_SMP */ static ERTS_INLINE erts_aint32_t handle_fix_alloc(ErtsAuxWorkData *awdp, erts_aint32_t aux_work) @@ -1451,6 +1496,10 @@ handle_aux_work(ErtsAuxWorkData *awdp, erts_aint32_t orig_aux_work) handle_mseg_cache_check); #endif +#ifdef ERTS_SMP + HANDLE_AUX_WORK(ERTS_SSI_AUX_WORK_CODE_IX_ACTIVATION, + handle_code_ix_activation); +#endif ERTS_DBG_CHK_AUX_WORK_VAL(aux_work); return aux_work; diff --git a/erts/emulator/beam/erl_process.h b/erts/emulator/beam/erl_process.h index c23810f15a..3f19d92fcd 100644 --- a/erts/emulator/beam/erl_process.h +++ b/erts/emulator/beam/erl_process.h @@ -264,6 +264,7 @@ typedef enum { #define ERTS_SSI_AUX_WORK_CHECK_CHILDREN (((erts_aint32_t) 1) << 8) #define ERTS_SSI_AUX_WORK_SET_TMO (((erts_aint32_t) 1) << 9) #define ERTS_SSI_AUX_WORK_MSEG_CACHE_CHECK (((erts_aint32_t) 1) << 10) +#define ERTS_SSI_AUX_WORK_CODE_IX_ACTIVATION (((erts_aint32_t) 1) << 11) typedef struct ErtsSchedulerSleepInfo_ ErtsSchedulerSleepInfo; @@ -429,6 +430,12 @@ typedef struct { void *queue; } async_ready; #endif +#ifdef ERTS_SMP + struct { + Process* code_stager; + ErtsThrPrgrVal thr_prgr; + } code_ix_activation; +#endif } ErtsAuxWorkData; struct ErtsSchedulerData_ { @@ -1110,6 +1117,9 @@ void erts_smp_notify_check_children_needed(void); #if ERTS_USE_ASYNC_READY_Q void erts_notify_check_async_ready_queue(void *); #endif +#ifdef ERTS_SMP +void erts_notify_code_ix_activation(Process* p, ErtsThrPrgrVal later); +#endif void erts_schedule_misc_aux_work(int sched_id, void (*func)(void *), void *arg); -- cgit v1.2.3 From cd63cd50bae6d98d6d56fa24674f14e7b9457a37 Mon Sep 17 00:00:00 2001 From: Sverker Eriksson Date: Wed, 15 Feb 2012 17:08:47 +0100 Subject: erts: Refactor export staging lock Renamed it export_staging_lock and made change it to ordinary mutex. --- erts/emulator/beam/code_ix.c | 5 +++-- erts/emulator/beam/export.c | 33 +++++++++++++++------------------ erts/emulator/beam/export.h | 6 +++--- 3 files changed, 21 insertions(+), 23 deletions(-) diff --git a/erts/emulator/beam/code_ix.c b/erts/emulator/beam/code_ix.c index 5565b51e7e..d4bf75558d 100644 --- a/erts/emulator/beam/code_ix.c +++ b/erts/emulator/beam/code_ix.c @@ -78,12 +78,13 @@ void erts_end_staging_code_ix(void) void erts_activate_staging_code_ix(void) { ErtsCodeIndex ix; - export_write_lock(); + /* We need to this lock as we are now making the staging export table active */ + export_staging_lock(); ix = erts_staging_code_ix(); erts_smp_atomic32_set_nob(&the_active_code_index, ix); ix = (ix + 1) % ERTS_NUM_CODE_IX; erts_smp_atomic32_set_nob(&the_staging_code_index, ix); - export_write_unlock(); + export_staging_unlock(); CIX_TRACE("activate"); } diff --git a/erts/emulator/beam/export.c b/erts/emulator/beam/export.c index 78a0b7d269..229641cb32 100644 --- a/erts/emulator/beam/export.c +++ b/erts/emulator/beam/export.c @@ -44,10 +44,10 @@ static erts_smp_atomic_t total_entries_bytes; #include "erl_smp.h" -erts_smp_rwmtx_t export_staging_lock; /* Locks the staging export table. */ - -#define export_read_lock() erts_smp_rwmtx_rlock(&export_staging_lock) -#define export_read_unlock() erts_smp_rwmtx_runlock(&export_staging_lock) +/* This lock protects the staging export table from concurrent access + * AND it protects the staging table from becoming active. + */ +erts_smp_mtx_t export_staging_lock; extern BeamInstr* em_call_error_handler; extern BeamInstr* em_call_traced_function; @@ -88,13 +88,13 @@ export_info(int to, void *to_arg) #ifdef ERTS_SMP int lock = !ERTS_IS_CRASH_DUMPING; if (lock) - export_read_lock(); + export_staging_lock(); #endif index_info(to, to_arg, &export_tables[erts_active_code_ix()]); hash_info(to, to_arg, &export_tables[erts_staging_code_ix()].htable); #ifdef ERTS_SMP if (lock) - export_read_unlock(); + export_staging_unlock(); #endif } @@ -175,12 +175,9 @@ void init_export_table(void) { HashFunctions f; - erts_smp_rwmtx_opt_t rwmtx_opt = ERTS_SMP_RWMTX_OPT_DEFAULT_INITER; int i; - rwmtx_opt.type = ERTS_SMP_RWMTX_TYPE_FREQUENT_READ; - rwmtx_opt.lived = ERTS_SMP_RWMTX_LONG_LIVED; - erts_smp_rwmtx_init_opt(&export_staging_lock, &rwmtx_opt, "export_tab"); + erts_smp_mtx_init(&export_staging_lock, "export_tab"); erts_smp_atomic_init_nob(&total_entries_bytes, 0); f.hash = (H_FUN) export_hash; @@ -287,10 +284,10 @@ erts_export_put(Eterm mod, Eterm func, unsigned int arity) ASSERT(is_atom(mod)); ASSERT(is_atom(func)); - export_write_lock(); + export_staging_lock(); ee = (struct export_entry*) index_put_entry(&export_tables[code_ix], init_template(&templ, mod, func, arity)); - export_write_unlock(); + export_staging_unlock(); return ee->ep; } @@ -320,7 +317,7 @@ erts_export_get_or_make_stub(Eterm mod, Eterm func, unsigned int arity) * The code is not loaded (yet). Put the export in the staging * export table, to avoid having to lock the active export table. */ - export_write_lock(); + export_staging_lock(); if (erts_active_code_ix() == code_ix) { struct export_templ templ; struct export_entry* entry; @@ -335,7 +332,7 @@ erts_export_get_or_make_stub(Eterm mod, Eterm func, unsigned int arity) ASSERT(!retrying); IF_DEBUG(retrying = 1); } - export_write_unlock(); + export_staging_unlock(); } } while (!ep); return ep; @@ -355,11 +352,11 @@ int export_table_sz(void) { int i, bytes = 0; - export_read_lock(); + export_staging_lock(); for (i=0; i Date: Tue, 21 Feb 2012 15:20:49 +0100 Subject: erts: Fix race bug in finish_after_on_load Must block system before looking up module to not race with other "code upgrader". --- erts/emulator/beam/beam_bif_load.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/erts/emulator/beam/beam_bif_load.c b/erts/emulator/beam/beam_bif_load.c index 6df5774fdb..c8fc7f9d6b 100644 --- a/erts/emulator/beam/beam_bif_load.c +++ b/erts/emulator/beam/beam_bif_load.c @@ -576,11 +576,18 @@ BIF_RETTYPE finish_after_on_load_2(BIF_ALIST_2) Module* modp; Eterm on_load; + /* ToDo: Use code_ix switch instead */ + + erts_smp_proc_unlock(BIF_P, ERTS_PROC_LOCK_MAIN); + erts_smp_thr_progress_block(); + code_ix = erts_active_code_ix(); modp = erts_get_module(BIF_ARG_1, code_ix); if (!modp || modp->curr.code == 0) { error: + erts_smp_thr_progress_unblock(); + erts_smp_proc_lock(BIF_P, ERTS_PROC_LOCK_MAIN); BIF_ERROR(BIF_P, BADARG); } if ((on_load = modp->curr.code[MI_ON_LOAD_FUNCTION_PTR]) == 0) { @@ -590,11 +597,6 @@ BIF_RETTYPE finish_after_on_load_2(BIF_ALIST_2) goto error; } - erts_smp_proc_unlock(BIF_P, ERTS_PROC_LOCK_MAIN); - erts_smp_thr_progress_block(); - - /*SVERK Use code_ix switch instead */ - if (BIF_ARG_2 == am_true) { int i; -- cgit v1.2.3 From 17c62a8d1158e2c13be403e62d81140c705a8444 Mon Sep 17 00:00:00 2001 From: Sverker Eriksson Date: Tue, 21 Feb 2012 20:43:23 +0100 Subject: erts: Switch order between code_ix lock and thread blocking Make for simpler code when we just can block threads and continue without having to release code_ix lock and repeat code lookups to avoid race. --- erts/emulator/beam/beam_bif_load.c | 70 ++++++++++++++++++-------------------- erts/emulator/beam/code_ix.c | 2 ++ erts/emulator/beam/code_ix.h | 1 + erts/emulator/beam/module.c | 3 +- 4 files changed, 37 insertions(+), 39 deletions(-) diff --git a/erts/emulator/beam/beam_bif_load.c b/erts/emulator/beam/beam_bif_load.c index c8fc7f9d6b..fbab59f794 100644 --- a/erts/emulator/beam/beam_bif_load.c +++ b/erts/emulator/beam/beam_bif_load.c @@ -45,6 +45,7 @@ static int any_heap_ref_ptrs(Eterm* start, Eterm* end, char* mod_start, Uint mod static int any_heap_refs(Eterm* start, Eterm* end, char* mod_start, Uint mod_size); + BIF_RETTYPE code_is_module_native_1(BIF_ALIST_1) { Module* modp; @@ -71,6 +72,11 @@ BIF_RETTYPE code_make_stub_module_3(BIF_ALIST_3) Module* modp; Eterm res; + if (!erts_try_lock_code_ix(BIF_P)) { + ERTS_BIF_YIELD3(bif_export[BIF_code_make_stub_module_3], + BIF_P, BIF_ARG_1, BIF_ARG_2, BIF_ARG_3); + } + erts_smp_proc_unlock(BIF_P, ERTS_PROC_LOCK_MAIN); erts_smp_thr_progress_block(); @@ -95,6 +101,7 @@ BIF_RETTYPE code_make_stub_module_3(BIF_ALIST_3) } erts_smp_thr_progress_unblock(); erts_smp_proc_lock(BIF_P, ERTS_PROC_LOCK_MAIN); + erts_unlock_code_ix(); return res; } @@ -245,12 +252,9 @@ finish_loading_1(BIF_ALIST_1) p[i].modp->curr.num_traced_exports > 0 || erts_is_default_trace_enabled()) { /* tracing involved, fallback with thread blocking */ - erts_abort_staging_code_ix(); - erts_unlock_code_ix(); erts_smp_proc_unlock(BIF_P, ERTS_PROC_LOCK_MAIN); erts_smp_thr_progress_block(); is_blocking = 1; - erts_start_staging_code_ix(); break; } } @@ -329,9 +333,7 @@ staging_epilogue(Process* c_p, int commit, Eterm res, int is_blocking) erts_smp_thr_progress_unblock(); erts_smp_proc_lock(c_p, ERTS_PROC_LOCK_MAIN); } - else { - erts_unlock_code_ix(); - } + erts_unlock_code_ix(); return res; } #ifdef ERTS_SMP @@ -462,7 +464,7 @@ BIF_RETTYPE delete_module_1(BIF_ALIST_1) if (!erts_try_lock_code_ix(BIF_P)) { ERTS_BIF_YIELD1(bif_export[BIF_delete_module_1], BIF_P, BIF_ARG_1); } -retry: + { erts_start_staging_code_ix(); code_ix = erts_staging_code_ix(); @@ -478,28 +480,22 @@ retry: ERTS_BIF_PREP_ERROR(res, BIF_P, BADARG); } else { - if (!is_blocking) { - if (modp->curr.num_breakpoints > 0 || - modp->curr.num_traced_exports > 0) { - /* we have tracing, retry single threaded */ - erts_abort_staging_code_ix(); - erts_unlock_code_ix(); - erts_smp_proc_unlock(BIF_P, ERTS_PROC_LOCK_MAIN); - erts_smp_thr_progress_block(); - is_blocking = 1; - goto retry; + if (modp->curr.num_breakpoints > 0 || + modp->curr.num_traced_exports > 0) { + /* we have tracing, retry single threaded */ + erts_smp_proc_unlock(BIF_P, ERTS_PROC_LOCK_MAIN); + erts_smp_thr_progress_block(); + is_blocking = 1; + if (modp->curr.num_breakpoints) { + erts_clear_module_break(modp); + ASSERT(modp->curr.num_breakpoints == 0); } } - else if (modp->curr.num_breakpoints) { - erts_clear_module_break(modp); - ASSERT(modp->curr.num_breakpoints == 0); - } delete_code(modp); res = am_true; success = 1; } } - return staging_epilogue(BIF_P, success, res, is_blocking); } @@ -576,7 +572,12 @@ BIF_RETTYPE finish_after_on_load_2(BIF_ALIST_2) Module* modp; Eterm on_load; - /* ToDo: Use code_ix switch instead */ + if (!erts_try_lock_code_ix(BIF_P)) { + ERTS_BIF_YIELD2(bif_export[BIF_finish_after_on_load_2], + BIF_P, BIF_ARG_1, BIF_ARG_2); + } + + /* ToDo: Use code_ix staging instead of thread blocking */ erts_smp_proc_unlock(BIF_P, ERTS_PROC_LOCK_MAIN); erts_smp_thr_progress_block(); @@ -588,6 +589,7 @@ BIF_RETTYPE finish_after_on_load_2(BIF_ALIST_2) error: erts_smp_thr_progress_unblock(); erts_smp_proc_lock(BIF_P, ERTS_PROC_LOCK_MAIN); + erts_unlock_code_ix(); BIF_ERROR(BIF_P, BADARG); } if ((on_load = modp->curr.code[MI_ON_LOAD_FUNCTION_PTR]) == 0) { @@ -637,6 +639,7 @@ BIF_RETTYPE finish_after_on_load_2(BIF_ALIST_2) } erts_smp_thr_progress_unblock(); erts_smp_proc_lock(BIF_P, ERTS_PROC_LOCK_MAIN); + erts_unlock_code_ix(); BIF_RET(am_true); } @@ -899,7 +902,6 @@ BIF_RETTYPE purge_module_1(BIF_ALIST_1) ERTS_BIF_YIELD1(bif_export[BIF_purge_module_1], BIF_P, BIF_ARG_1); } -retry: code_ix = erts_active_code_ix(); /* @@ -923,16 +925,12 @@ retry: * Unload any NIF library */ if (modp->old.nif != NULL) { - if (!is_blocking) { - /* ToDo: Do unload nif without blocking */ - erts_rwunlock_old_code(code_ix); - erts_unlock_code_ix(); - erts_smp_proc_unlock(BIF_P, ERTS_PROC_LOCK_MAIN); - erts_smp_thr_progress_block(); - is_blocking = 1; - goto retry; - } - + /* ToDo: Do unload nif without blocking */ + erts_rwunlock_old_code(code_ix); + erts_smp_proc_unlock(BIF_P, ERTS_PROC_LOCK_MAIN); + erts_smp_thr_progress_block(); + is_blocking = 1; + erts_rwlock_old_code(code_ix); erts_unload_nif(modp->old.nif); modp->old.nif = NULL; } @@ -961,9 +959,7 @@ retry: erts_smp_thr_progress_unblock(); erts_smp_proc_lock(BIF_P, ERTS_PROC_LOCK_MAIN); } - else { - erts_unlock_code_ix(); - } + erts_unlock_code_ix(); return ret; } diff --git a/erts/emulator/beam/code_ix.c b/erts/emulator/beam/code_ix.c index d4bf75558d..def7e164e2 100644 --- a/erts/emulator/beam/code_ix.c +++ b/erts/emulator/beam/code_ix.c @@ -105,6 +105,8 @@ int erts_try_lock_code_ix(Process* c_p) { int success; + ASSERT(!erts_smp_thr_progress_is_blocking()); + erts_smp_mtx_lock(&the_code_ix_queue_lock); success = !the_code_ix_lock; if (success) { diff --git a/erts/emulator/beam/code_ix.h b/erts/emulator/beam/code_ix.h index bac8c3365c..c37a5fe8f4 100644 --- a/erts/emulator/beam/code_ix.h +++ b/erts/emulator/beam/code_ix.h @@ -83,6 +83,7 @@ ErtsCodeIndex erts_staging_code_ix(void); /* Try lock code_ix that is needed for (exlusive) access of the staging area. * Main process lock (only) must be held. + * System thread progress must not be blocked. * Caller is suspended and *must* yield if 0 is returned. */ int erts_try_lock_code_ix(struct process*); diff --git a/erts/emulator/beam/module.c b/erts/emulator/beam/module.c index 1dab24e96a..1ef71cda79 100644 --- a/erts/emulator/beam/module.c +++ b/erts/emulator/beam/module.c @@ -144,8 +144,7 @@ erts_put_module(Eterm mod) ASSERT(is_atom(mod)); ERTS_SMP_LC_ASSERT(erts_initialized == 0 - || erts_is_code_ix_locked() - || erts_smp_thr_progress_is_blocking()); + || erts_is_code_ix_locked()); mod_tab = &module_tables[erts_staging_code_ix()]; e.module = atom_val(mod); -- cgit v1.2.3 From 6d7073e33a8f326b8a37eaf5539aa322a06a732c Mon Sep 17 00:00:00 2001 From: Sverker Eriksson Date: Wed, 22 Feb 2012 19:25:59 +0100 Subject: erts: Seize code_ix lock when updating trace settings We want to avoid the race when trace settings are done in the time gap while a code stager process is waiting for thread process before commiting and releasing code_ix lock. --- erts/emulator/beam/beam_debug.c | 6 ++++- erts/emulator/beam/erl_bif_trace.c | 51 +++++++++++++++++++------------------- erts/emulator/beam/erl_nif.c | 8 ++++++ 3 files changed, 39 insertions(+), 26 deletions(-) diff --git a/erts/emulator/beam/beam_debug.c b/erts/emulator/beam/beam_debug.c index d9e9d0e348..d288a37911 100644 --- a/erts/emulator/beam/beam_debug.c +++ b/erts/emulator/beam/beam_debug.c @@ -114,6 +114,10 @@ erts_debug_breakpoint_2(BIF_ALIST_2) mfa[2] = signed_val(mfa[2]); } + if (!erts_try_lock_code_ix(BIF_P)) { + ERTS_BIF_YIELD2(bif_export[BIF_erts_debug_breakpoint_2], + BIF_P, BIF_ARG_1, BIF_ARG_2); + } erts_smp_proc_unlock(p, ERTS_PROC_LOCK_MAIN); erts_smp_thr_progress_block(); @@ -125,7 +129,7 @@ erts_debug_breakpoint_2(BIF_ALIST_2) erts_smp_thr_progress_unblock(); erts_smp_proc_lock(p, ERTS_PROC_LOCK_MAIN); - + erts_unlock_code_ix(); return res; error: diff --git a/erts/emulator/beam/erl_bif_trace.c b/erts/emulator/beam/erl_bif_trace.c index c92e0400e0..6f04787478 100644 --- a/erts/emulator/beam/erl_bif_trace.c +++ b/erts/emulator/beam/erl_bif_trace.c @@ -98,7 +98,7 @@ trace_pattern(Process* p, Eterm MFA, Eterm Pattern, Eterm flaglist) { DeclareTmpHeap(mfa,3,p); /* Not really heap here, but might be when setting pattern */ int i; - int matches = 0; + int matches = -1; int specified = 0; enum erts_break_op on; Binary* match_prog_set; @@ -108,6 +108,9 @@ trace_pattern(Process* p, Eterm MFA, Eterm Pattern, Eterm flaglist) Process *meta_tracer_proc = p; Eterm meta_tracer_pid = p->id; + if (!erts_try_lock_code_ix(p)) { + ERTS_BIF_YIELD3(bif_export[BIF_trace_pattern_3], p, MFA, Pattern, flaglist); + } erts_smp_proc_unlock(p, ERTS_PROC_LOCK_MAIN); erts_smp_thr_progress_block(); @@ -241,7 +244,6 @@ trace_pattern(Process* p, Eterm MFA, Eterm Pattern, Eterm flaglist) erts_default_meta_match_spec = NULL; erts_default_meta_tracer_pid = NIL; } - MatchSetUnref(match_prog_set); if (erts_default_trace_pattern_flags.breakpoint && flags.breakpoint) { /* Breakpoint trace -> breakpoint trace */ @@ -297,8 +299,7 @@ trace_pattern(Process* p, Eterm MFA, Eterm Pattern, Eterm flaglist) erts_default_trace_pattern_is_on = !!flags.breakpoint; } } - - goto done; + matches = 0; } else if (is_tuple(MFA)) { Eterm *tp = tuple_val(MFA); if (tp[0] != make_arityval(3)) { @@ -322,35 +323,29 @@ trace_pattern(Process* p, Eterm MFA, Eterm Pattern, Eterm flaglist) if (is_small(mfa[2])) { mfa[2] = signed_val(mfa[2]); } - } else { - goto error; - } - if (meta_tracer_proc) { - meta_tracer_proc->trace_flags |= F_TRACER; - } - - - matches = erts_set_trace_pattern(mfa, specified, - match_prog_set, match_prog_set, - on, flags, meta_tracer_pid); - MatchSetUnref(match_prog_set); - - done: - UnUseTmpHeap(3,p); - erts_smp_thr_progress_unblock(); - erts_smp_proc_lock(p, ERTS_PROC_LOCK_MAIN); + if (meta_tracer_proc) { + meta_tracer_proc->trace_flags |= F_TRACER; + } - return make_small(matches); + matches = erts_set_trace_pattern(mfa, specified, + match_prog_set, match_prog_set, + on, flags, meta_tracer_pid); + } error: - MatchSetUnref(match_prog_set); - UnUseTmpHeap(3,p); erts_smp_thr_progress_unblock(); erts_smp_proc_lock(p, ERTS_PROC_LOCK_MAIN); - BIF_ERROR(p, BADARG); + erts_unlock_code_ix(); + + if (matches >= 0) { + return make_small(matches); + } + else { + BIF_ERROR(p, BADARG); + } } void @@ -469,6 +464,10 @@ Eterm trace_3(BIF_ALIST_3) BIF_ERROR(p, BADARG); } + if (!erts_try_lock_code_ix(BIF_P)) { + ERTS_BIF_YIELD3(bif_export[BIF_trace_3], BIF_P, BIF_ARG_1, BIF_ARG_2, BIF_ARG_3); + } + if (is_nil(tracer) || is_internal_pid(tracer)) { Process *tracer_proc = erts_pid2proc(p, ERTS_PROC_LOCK_MAIN, @@ -733,6 +732,7 @@ Eterm trace_3(BIF_ALIST_3) erts_smp_proc_lock(p, ERTS_PROC_LOCK_MAIN); } #endif + erts_unlock_code_ix(); BIF_RET(make_small(matches)); @@ -748,6 +748,7 @@ Eterm trace_3(BIF_ALIST_3) erts_smp_proc_lock(p, ERTS_PROC_LOCK_MAIN); } #endif + erts_unlock_code_ix(); BIF_ERROR(p, BADARG); } diff --git a/erts/emulator/beam/erl_nif.c b/erts/emulator/beam/erl_nif.c index 8e8b58a7ad..a0182630b9 100644 --- a/erts/emulator/beam/erl_nif.c +++ b/erts/emulator/beam/erl_nif.c @@ -1513,6 +1513,7 @@ BIF_RETTYPE load_nif_2(BIF_ALIST_2) if (len < 0) { BIF_ERROR(BIF_P, BADARG); } + lib_name = (char *) erts_alloc(ERTS_ALC_T_TMP, len + 1); if (intlist_to_buf(BIF_ARG_1, lib_name, len) != len) { @@ -1521,6 +1522,12 @@ BIF_RETTYPE load_nif_2(BIF_ALIST_2) } lib_name[len] = '\0'; + if (!erts_try_lock_code_ix(BIF_P)) { + erts_free(ERTS_ALC_T_TMP, lib_name); + ERTS_BIF_YIELD2(bif_export[BIF_load_nif_2], + BIF_P, BIF_ARG_1, BIF_ARG_2); + } + /* Block system (is this the right place to do it?) */ erts_smp_proc_unlock(BIF_P, ERTS_PROC_LOCK_MAIN); erts_smp_thr_progress_block(); @@ -1715,6 +1722,7 @@ BIF_RETTYPE load_nif_2(BIF_ALIST_2) erts_smp_thr_progress_unblock(); erts_smp_proc_lock(BIF_P, ERTS_PROC_LOCK_MAIN); + erts_unlock_code_ix(); erts_free(ERTS_ALC_T_TMP, lib_name); if (reload_warning) { -- cgit v1.2.3 From 62a41d25361de2ee08970a3905c63c503d3c89a1 Mon Sep 17 00:00:00 2001 From: Sverker Eriksson Date: Thu, 23 Feb 2012 12:13:31 +0100 Subject: erts: Refactor code loading with renaming Rename lock_code_ix as seize_code_write_permission. Don't want to call it a "lock" as it can be held between schedulings and different threads and is not managed by lock checker. Rename "activate" staging as "commit" staging. Why not be consistent and use git terminology all the way. --- erts/emulator/beam/beam_bif_load.c | 24 ++++++++++++------------ erts/emulator/beam/beam_debug.c | 4 ++-- erts/emulator/beam/code_ix.c | 12 +++++------- erts/emulator/beam/code_ix.h | 25 ++++++++++++------------- erts/emulator/beam/erl_bif_trace.c | 10 +++++----- erts/emulator/beam/erl_init.c | 2 +- erts/emulator/beam/erl_nif.c | 4 ++-- erts/emulator/beam/erl_process.c | 4 ++-- 8 files changed, 41 insertions(+), 44 deletions(-) diff --git a/erts/emulator/beam/beam_bif_load.c b/erts/emulator/beam/beam_bif_load.c index fbab59f794..e06fe52c36 100644 --- a/erts/emulator/beam/beam_bif_load.c +++ b/erts/emulator/beam/beam_bif_load.c @@ -72,7 +72,7 @@ BIF_RETTYPE code_make_stub_module_3(BIF_ALIST_3) Module* modp; Eterm res; - if (!erts_try_lock_code_ix(BIF_P)) { + if (!erts_try_seize_code_write_permission(BIF_P)) { ERTS_BIF_YIELD3(bif_export[BIF_code_make_stub_module_3], BIF_P, BIF_ARG_1, BIF_ARG_2, BIF_ARG_3); } @@ -94,14 +94,14 @@ BIF_RETTYPE code_make_stub_module_3(BIF_ALIST_3) if (res == BIF_ARG_1) { erts_end_staging_code_ix(); - erts_activate_staging_code_ix(); + erts_commit_staging_code_ix(); } else { erts_abort_staging_code_ix(); } erts_smp_thr_progress_unblock(); erts_smp_proc_lock(BIF_P, ERTS_PROC_LOCK_MAIN); - erts_unlock_code_ix(); + erts_release_code_write_permission(); return res; } @@ -177,7 +177,7 @@ finish_loading_1(BIF_ALIST_1) int is_blocking = 0; int do_commit = 0; - if (!erts_try_lock_code_ix(BIF_P)) { + if (!erts_try_seize_code_write_permission(BIF_P)) { ERTS_BIF_YIELD1(bif_export[BIF_finish_loading_1], BIF_P, BIF_ARG_1); } @@ -324,7 +324,7 @@ staging_epilogue(Process* c_p, int commit, Eterm res, int is_blocking) { if (commit) { erts_end_staging_code_ix(); - erts_activate_staging_code_ix(); + erts_commit_staging_code_ix(); } else { erts_abort_staging_code_ix(); @@ -333,7 +333,7 @@ staging_epilogue(Process* c_p, int commit, Eterm res, int is_blocking) erts_smp_thr_progress_unblock(); erts_smp_proc_lock(c_p, ERTS_PROC_LOCK_MAIN); } - erts_unlock_code_ix(); + erts_release_code_write_permission(); return res; } #ifdef ERTS_SMP @@ -461,7 +461,7 @@ BIF_RETTYPE delete_module_1(BIF_ALIST_1) BIF_ERROR(BIF_P, BADARG); } - if (!erts_try_lock_code_ix(BIF_P)) { + if (!erts_try_seize_code_write_permission(BIF_P)) { ERTS_BIF_YIELD1(bif_export[BIF_delete_module_1], BIF_P, BIF_ARG_1); } @@ -572,7 +572,7 @@ BIF_RETTYPE finish_after_on_load_2(BIF_ALIST_2) Module* modp; Eterm on_load; - if (!erts_try_lock_code_ix(BIF_P)) { + if (!erts_try_seize_code_write_permission(BIF_P)) { ERTS_BIF_YIELD2(bif_export[BIF_finish_after_on_load_2], BIF_P, BIF_ARG_1, BIF_ARG_2); } @@ -589,7 +589,7 @@ BIF_RETTYPE finish_after_on_load_2(BIF_ALIST_2) error: erts_smp_thr_progress_unblock(); erts_smp_proc_lock(BIF_P, ERTS_PROC_LOCK_MAIN); - erts_unlock_code_ix(); + erts_release_code_write_permission(); BIF_ERROR(BIF_P, BADARG); } if ((on_load = modp->curr.code[MI_ON_LOAD_FUNCTION_PTR]) == 0) { @@ -639,7 +639,7 @@ BIF_RETTYPE finish_after_on_load_2(BIF_ALIST_2) } erts_smp_thr_progress_unblock(); erts_smp_proc_lock(BIF_P, ERTS_PROC_LOCK_MAIN); - erts_unlock_code_ix(); + erts_release_code_write_permission(); BIF_RET(am_true); } @@ -898,7 +898,7 @@ BIF_RETTYPE purge_module_1(BIF_ALIST_1) BIF_ERROR(BIF_P, BADARG); } - if (!erts_try_lock_code_ix(BIF_P)) { + if (!erts_try_seize_code_write_permission(BIF_P)) { ERTS_BIF_YIELD1(bif_export[BIF_purge_module_1], BIF_P, BIF_ARG_1); } @@ -959,7 +959,7 @@ BIF_RETTYPE purge_module_1(BIF_ALIST_1) erts_smp_thr_progress_unblock(); erts_smp_proc_lock(BIF_P, ERTS_PROC_LOCK_MAIN); } - erts_unlock_code_ix(); + erts_release_code_write_permission(); return ret; } diff --git a/erts/emulator/beam/beam_debug.c b/erts/emulator/beam/beam_debug.c index d288a37911..e69cbc3048 100644 --- a/erts/emulator/beam/beam_debug.c +++ b/erts/emulator/beam/beam_debug.c @@ -114,7 +114,7 @@ erts_debug_breakpoint_2(BIF_ALIST_2) mfa[2] = signed_val(mfa[2]); } - if (!erts_try_lock_code_ix(BIF_P)) { + if (!erts_try_seize_code_write_permission(BIF_P)) { ERTS_BIF_YIELD2(bif_export[BIF_erts_debug_breakpoint_2], BIF_P, BIF_ARG_1, BIF_ARG_2); } @@ -129,7 +129,7 @@ erts_debug_breakpoint_2(BIF_ALIST_2) erts_smp_thr_progress_unblock(); erts_smp_proc_lock(p, ERTS_PROC_LOCK_MAIN); - erts_unlock_code_ix(); + erts_release_code_write_permission(); return res; error: diff --git a/erts/emulator/beam/code_ix.c b/erts/emulator/beam/code_ix.c index def7e164e2..9158d2d05c 100644 --- a/erts/emulator/beam/code_ix.c +++ b/erts/emulator/beam/code_ix.c @@ -75,7 +75,7 @@ void erts_end_staging_code_ix(void) CIX_TRACE("end"); } -void erts_activate_staging_code_ix(void) +void erts_commit_staging_code_ix(void) { ErtsCodeIndex ix; /* We need to this lock as we are now making the staging export table active */ @@ -98,14 +98,14 @@ void erts_abort_staging_code_ix(void) } -/* Try lock code_ix +/* * Calller _must_ yield if we return 0 */ -int erts_try_lock_code_ix(Process* c_p) +int erts_try_seize_code_write_permission(Process* c_p) { int success; - ASSERT(!erts_smp_thr_progress_is_blocking()); + ASSERT(!erts_smp_thr_progress_is_blocking()); /* to avoid deadlock */ erts_smp_mtx_lock(&the_code_ix_queue_lock); success = !the_code_ix_lock; @@ -125,9 +125,7 @@ int erts_try_lock_code_ix(Process* c_p) return success; } -/* Unlock code_ix (resume all waiters) -*/ -void erts_unlock_code_ix(void) +void erts_release_code_write_permission(void) { erts_smp_mtx_lock(&the_code_ix_queue_lock); while (the_code_ix_queue != NULL) { /* unleash the entire herd */ diff --git a/erts/emulator/beam/code_ix.h b/erts/emulator/beam/code_ix.h index c37a5fe8f4..068ff0e6ba 100644 --- a/erts/emulator/beam/code_ix.h +++ b/erts/emulator/beam/code_ix.h @@ -81,38 +81,37 @@ ErtsCodeIndex erts_active_code_ix(void); ERTS_GLB_INLINE ErtsCodeIndex erts_staging_code_ix(void); -/* Try lock code_ix that is needed for (exlusive) access of the staging area. +/* Try seize exclusive code write permission. Needed for code staging. * Main process lock (only) must be held. * System thread progress must not be blocked. * Caller is suspended and *must* yield if 0 is returned. */ -int erts_try_lock_code_ix(struct process*); +int erts_try_seize_code_write_permission(struct process*); -/* Unlock code_ix +/* Release code write permission. + * Will resume any suspended waiters. */ -void erts_unlock_code_ix(void); +void erts_release_code_write_permission(void); /* Prepare the "staging area" to be a complete copy of the active code. - * code_ix must be locked. - * Must be followed by calls to either "end" and "activate" or "abort" before - * code_ix lock is released. + * Code write permission must have been seized. + * Must be followed by calls to either "end" and "commit" or "abort" before + * code write permission can be released. */ void erts_start_staging_code_ix(void); /* End the staging. - * code_ix must be locked. - * Must be followed by a call to either "activate" or "abort" - * before code_ix lock is released. + * Preceded by "start" and followed by "commit" or "abort". */ void erts_end_staging_code_ix(void); /* Set staging code index as new active code index. - * code_ix must be locked and "start" and "end" called. + * Preceded by "end". */ -void erts_activate_staging_code_ix(void); +void erts_commit_staging_code_ix(void); /* Abort the staging. - * code_ix must be locked and "start" called. + * Preceded by "start" or "end". */ void erts_abort_staging_code_ix(void); diff --git a/erts/emulator/beam/erl_bif_trace.c b/erts/emulator/beam/erl_bif_trace.c index 6f04787478..1c99fcdaa6 100644 --- a/erts/emulator/beam/erl_bif_trace.c +++ b/erts/emulator/beam/erl_bif_trace.c @@ -108,7 +108,7 @@ trace_pattern(Process* p, Eterm MFA, Eterm Pattern, Eterm flaglist) Process *meta_tracer_proc = p; Eterm meta_tracer_pid = p->id; - if (!erts_try_lock_code_ix(p)) { + if (!erts_try_seize_code_write_permission(p)) { ERTS_BIF_YIELD3(bif_export[BIF_trace_pattern_3], p, MFA, Pattern, flaglist); } erts_smp_proc_unlock(p, ERTS_PROC_LOCK_MAIN); @@ -338,7 +338,7 @@ trace_pattern(Process* p, Eterm MFA, Eterm Pattern, Eterm flaglist) UnUseTmpHeap(3,p); erts_smp_thr_progress_unblock(); erts_smp_proc_lock(p, ERTS_PROC_LOCK_MAIN); - erts_unlock_code_ix(); + erts_release_code_write_permission(); if (matches >= 0) { return make_small(matches); @@ -464,7 +464,7 @@ Eterm trace_3(BIF_ALIST_3) BIF_ERROR(p, BADARG); } - if (!erts_try_lock_code_ix(BIF_P)) { + if (!erts_try_seize_code_write_permission(BIF_P)) { ERTS_BIF_YIELD3(bif_export[BIF_trace_3], BIF_P, BIF_ARG_1, BIF_ARG_2, BIF_ARG_3); } @@ -732,7 +732,7 @@ Eterm trace_3(BIF_ALIST_3) erts_smp_proc_lock(p, ERTS_PROC_LOCK_MAIN); } #endif - erts_unlock_code_ix(); + erts_release_code_write_permission(); BIF_RET(make_small(matches)); @@ -748,7 +748,7 @@ Eterm trace_3(BIF_ALIST_3) erts_smp_proc_lock(p, ERTS_PROC_LOCK_MAIN); } #endif - erts_unlock_code_ix(); + erts_release_code_write_permission(); BIF_ERROR(p, BADARG); } diff --git a/erts/emulator/beam/erl_init.c b/erts/emulator/beam/erl_init.c index a4690891d5..4db23a0a18 100644 --- a/erts/emulator/beam/erl_init.c +++ b/erts/emulator/beam/erl_init.c @@ -1474,7 +1474,7 @@ erl_start(int argc, char **argv) init_shared_memory(boot_argc, boot_argv); load_preloaded(); erts_end_staging_code_ix(); - erts_activate_staging_code_ix(); + erts_commit_staging_code_ix(); erts_initialized = 1; diff --git a/erts/emulator/beam/erl_nif.c b/erts/emulator/beam/erl_nif.c index a0182630b9..bdbeb3bcf6 100644 --- a/erts/emulator/beam/erl_nif.c +++ b/erts/emulator/beam/erl_nif.c @@ -1522,7 +1522,7 @@ BIF_RETTYPE load_nif_2(BIF_ALIST_2) } lib_name[len] = '\0'; - if (!erts_try_lock_code_ix(BIF_P)) { + if (!erts_try_seize_code_write_permission(BIF_P)) { erts_free(ERTS_ALC_T_TMP, lib_name); ERTS_BIF_YIELD2(bif_export[BIF_load_nif_2], BIF_P, BIF_ARG_1, BIF_ARG_2); @@ -1722,7 +1722,7 @@ BIF_RETTYPE load_nif_2(BIF_ALIST_2) erts_smp_thr_progress_unblock(); erts_smp_proc_lock(BIF_P, ERTS_PROC_LOCK_MAIN); - erts_unlock_code_ix(); + erts_release_code_write_permission(); erts_free(ERTS_ALC_T_TMP, lib_name); if (reload_warning) { diff --git a/erts/emulator/beam/erl_process.c b/erts/emulator/beam/erl_process.c index aaee951107..a7707e9498 100644 --- a/erts/emulator/beam/erl_process.c +++ b/erts/emulator/beam/erl_process.c @@ -1178,7 +1178,7 @@ handle_code_ix_activation(ErtsAuxWorkData *awdp, erts_aint32_t aux_work) #endif erts_smp_proc_lock(p, ERTS_PROC_LOCK_STATUS); if (!ERTS_PROC_IS_EXITING(p)) { - erts_activate_staging_code_ix(); + erts_commit_staging_code_ix(); erts_resume(p, ERTS_PROC_LOCK_STATUS); erts_smp_proc_unlock(p, ERTS_PROC_LOCK_STATUS); } @@ -1186,7 +1186,7 @@ handle_code_ix_activation(ErtsAuxWorkData *awdp, erts_aint32_t aux_work) erts_smp_proc_unlock(p, ERTS_PROC_LOCK_STATUS); erts_abort_staging_code_ix(); } - erts_unlock_code_ix(); + erts_release_code_write_permission(); erts_smp_proc_dec_refc(p); return aux_work & ~ERTS_SSI_AUX_WORK_CODE_IX_ACTIVATION; } -- cgit v1.2.3 From 1bf37a66d522a6f7d42fbd7602fd1236d586652c Mon Sep 17 00:00:00 2001 From: Sverker Eriksson Date: Thu, 23 Feb 2012 15:45:56 +0100 Subject: erts: Use correct macro for "yield-return" --- erts/emulator/beam/beam_bif_load.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/erts/emulator/beam/beam_bif_load.c b/erts/emulator/beam/beam_bif_load.c index e06fe52c36..e4644065b7 100644 --- a/erts/emulator/beam/beam_bif_load.c +++ b/erts/emulator/beam/beam_bif_load.c @@ -355,9 +355,9 @@ staging_epilogue(Process* c_p, int commit, Eterm res, int is_blocking) erts_suspend(c_p, ERTS_PROC_LOCK_MAIN, NULL); /* * handle_code_ix_activation() will do the rest "later" - * and resume this process in bif_return_trap() to return 'res'. + * and resume this process to return 'res'. */ - ERTS_BIF_YIELD1(&bif_return_trap_export, c_p, res); + ERTS_BIF_YIELD_RETURN(c_p, res); } #endif } -- cgit v1.2.3 From 03ecf626b473e1c0015b1469e71403189f878ebc Mon Sep 17 00:00:00 2001 From: Sverker Eriksson Date: Fri, 24 Feb 2012 15:44:48 +0100 Subject: erts: Fix faulty assert in non-smp debug vm "is_blocking" always returns true on non-smp --- erts/emulator/beam/code_ix.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/erts/emulator/beam/code_ix.c b/erts/emulator/beam/code_ix.c index 9158d2d05c..ae4cca1e58 100644 --- a/erts/emulator/beam/code_ix.c +++ b/erts/emulator/beam/code_ix.c @@ -104,8 +104,9 @@ void erts_abort_staging_code_ix(void) int erts_try_seize_code_write_permission(Process* c_p) { int success; - +#ifdef ERTS_SMP ASSERT(!erts_smp_thr_progress_is_blocking()); /* to avoid deadlock */ +#endif erts_smp_mtx_lock(&the_code_ix_queue_lock); success = !the_code_ix_lock; -- cgit v1.2.3 From a1d7879a1c0fc87ff2acf2ed7e443377a85b77aa Mon Sep 17 00:00:00 2001 From: Sverker Eriksson Date: Fri, 24 Feb 2012 15:48:26 +0100 Subject: erts: Set correct default tracing when loading code Default trace (on_load) was lost in commit 64bcf5db63d73fe when load_module/2 was split. --- erts/emulator/beam/beam_bif_load.c | 25 ++++++++++++++++++------- 1 file changed, 18 insertions(+), 7 deletions(-) diff --git a/erts/emulator/beam/beam_bif_load.c b/erts/emulator/beam/beam_bif_load.c index e4644065b7..67c8442636 100644 --- a/erts/emulator/beam/beam_bif_load.c +++ b/erts/emulator/beam/beam_bif_load.c @@ -35,7 +35,6 @@ #include "erl_nif.h" #include "erl_thr_progress.h" -static Eterm staging_epilogue(Process* c_p, int, Eterm res, int); static void set_default_trace_pattern(Eterm module); static Eterm check_process_code(Process* rp, Module* modp); static void delete_code(Module* modp); @@ -147,6 +146,8 @@ struct m { Uint exception; }; +static Eterm staging_epilogue(Process* c_p, int, Eterm res, int, struct m*, int); + static Eterm exception_list(Process* p, Eterm tag, struct m* mp, Sint exceptions) { @@ -309,14 +310,12 @@ finish_loading_1(BIF_ALIST_1) } done: - if (p) { - erts_free(ERTS_ALC_T_LOADER_TMP, p); - } - return staging_epilogue(BIF_P, do_commit, res, is_blocking); + return staging_epilogue(BIF_P, do_commit, res, is_blocking, p, n); } static Eterm -staging_epilogue(Process* c_p, int commit, Eterm res, int is_blocking) +staging_epilogue(Process* c_p, int commit, Eterm res, int is_blocking, + struct m* loaded, int nloaded) { #ifdef ERTS_SMP if (is_blocking || !commit) @@ -325,10 +324,19 @@ staging_epilogue(Process* c_p, int commit, Eterm res, int is_blocking) if (commit) { erts_end_staging_code_ix(); erts_commit_staging_code_ix(); + if (loaded) { + int i; + for (i=0; i < nloaded; i++) { + set_default_trace_pattern(loaded[i].module); + } + } } else { erts_abort_staging_code_ix(); } + if (loaded) { + erts_free(ERTS_ALC_T_LOADER_TMP, loaded); + } if (is_blocking) { erts_smp_thr_progress_unblock(); erts_smp_proc_lock(c_p, ERTS_PROC_LOCK_MAIN); @@ -341,6 +349,9 @@ staging_epilogue(Process* c_p, int commit, Eterm res, int is_blocking) ErtsThrPrgrVal later; ASSERT(is_value(res)); + if (loaded) { + erts_free(ERTS_ALC_T_LOADER_TMP, loaded); + } erts_end_staging_code_ix(); /* * Now we must wait for all schedulers to do a memory barrier before @@ -496,7 +507,7 @@ BIF_RETTYPE delete_module_1(BIF_ALIST_1) success = 1; } } - return staging_epilogue(BIF_P, success, res, is_blocking); + return staging_epilogue(BIF_P, success, res, is_blocking, NULL, 0); } BIF_RETTYPE module_loaded_1(BIF_ALIST_1) -- cgit v1.2.3 From 07e6f64d26878d56e7520ddd262f995ac69737f7 Mon Sep 17 00:00:00 2001 From: Sverker Eriksson Date: Fri, 24 Feb 2012 16:51:14 +0100 Subject: erts: Adapt gdb etp-command for new beam_ranges --- erts/etc/unix/etp-commands | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/erts/etc/unix/etp-commands b/erts/etc/unix/etp-commands index 6a01e0b7e0..fb28a0ec77 100644 --- a/erts/etc/unix/etp-commands +++ b/erts/etc/unix/etp-commands @@ -1022,16 +1022,17 @@ define etp-cp-1 # Non-reentrant # set $etp_cp = (Eterm)($arg0) - set $etp_cp_low = modules - set $etp_cp_high = $etp_cp_low + num_loaded_modules - set $etp_cp_mid = mid_module + set $etp_ranges = &r[(int)the_active_code_index] + set $etp_cp_low = $etp_ranges->modules + set $etp_cp_high = $etp_cp_low + $etp_ranges->n + set $etp_cp_mid = (Range*)$etp_ranges->mid set $etp_cp_p = 0 # while $etp_cp_low < $etp_cp_high if $etp_cp < $etp_cp_mid->start set $etp_cp_high = $etp_cp_mid else - if $etp_cp > $etp_cp_mid->end + if $etp_cp > (BeamInstr*)$etp_cp_mid->end set $etp_cp_low = $etp_cp_mid + 1 else set $etp_cp_p = $etp_cp_low = $etp_cp_high = $etp_cp_mid -- cgit v1.2.3 From 869237370df8133f0252ad2f803fcd6a152d98e7 Mon Sep 17 00:00:00 2001 From: Sverker Eriksson Date: Tue, 6 Mar 2012 11:28:58 +0100 Subject: erts: Fix memory leak in code loading All magic binaries returned by prepare_loading/2 was leaking. prepare_loading/2 left the reference count as 2 of the magic binary when it should be 1 (only owned by the returned term). --- erts/emulator/beam/beam_bif_load.c | 1 + 1 file changed, 1 insertion(+) diff --git a/erts/emulator/beam/beam_bif_load.c b/erts/emulator/beam/beam_bif_load.c index 67c8442636..768c38dae1 100644 --- a/erts/emulator/beam/beam_bif_load.c +++ b/erts/emulator/beam/beam_bif_load.c @@ -136,6 +136,7 @@ prepare_loading_2(BIF_ALIST_2) } hp = HAlloc(BIF_P, PROC_BIN_SIZE); res = erts_mk_magic_binary_term(&hp, &MSO(BIF_P), magic); + erts_refc_dec(&magic->refc, 1); BIF_RET(res); } -- cgit v1.2.3 From 16c60b70936070b0a568473c1d99466479446af2 Mon Sep 17 00:00:00 2001 From: Sverker Eriksson Date: Wed, 7 Mar 2012 16:16:44 +0100 Subject: erts: Fix assert failure when code_server exits "during" commit Simplify by removing the support of abort_staging after end_staging. --- erts/emulator/beam/code_ix.h | 4 ++-- erts/emulator/beam/erl_process.c | 10 +++------- 2 files changed, 5 insertions(+), 9 deletions(-) diff --git a/erts/emulator/beam/code_ix.h b/erts/emulator/beam/code_ix.h index 068ff0e6ba..6b2680044e 100644 --- a/erts/emulator/beam/code_ix.h +++ b/erts/emulator/beam/code_ix.h @@ -101,7 +101,7 @@ void erts_release_code_write_permission(void); void erts_start_staging_code_ix(void); /* End the staging. - * Preceded by "start" and followed by "commit" or "abort". + * Preceded by "start" and must be followed by "commit". */ void erts_end_staging_code_ix(void); @@ -111,7 +111,7 @@ void erts_end_staging_code_ix(void); void erts_commit_staging_code_ix(void); /* Abort the staging. - * Preceded by "start" or "end". + * Preceded by "start". */ void erts_abort_staging_code_ix(void); diff --git a/erts/emulator/beam/erl_process.c b/erts/emulator/beam/erl_process.c index a7707e9498..6c136571d5 100644 --- a/erts/emulator/beam/erl_process.c +++ b/erts/emulator/beam/erl_process.c @@ -1176,17 +1176,13 @@ handle_code_ix_activation(ErtsAuxWorkData *awdp, erts_aint32_t aux_work) #ifdef DEBUG awdp->code_ix_activation.code_stager = NULL; #endif + erts_commit_staging_code_ix(); + erts_release_code_write_permission(); erts_smp_proc_lock(p, ERTS_PROC_LOCK_STATUS); if (!ERTS_PROC_IS_EXITING(p)) { - erts_commit_staging_code_ix(); erts_resume(p, ERTS_PROC_LOCK_STATUS); - erts_smp_proc_unlock(p, ERTS_PROC_LOCK_STATUS); } - else { - erts_smp_proc_unlock(p, ERTS_PROC_LOCK_STATUS); - erts_abort_staging_code_ix(); - } - erts_release_code_write_permission(); + erts_smp_proc_unlock(p, ERTS_PROC_LOCK_STATUS); erts_smp_proc_dec_refc(p); return aux_work & ~ERTS_SSI_AUX_WORK_CODE_IX_ACTIVATION; } -- cgit v1.2.3