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 (limited to 'erts') 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