diff options
-rw-r--r-- | erts/doc/src/erlang.xml | 6 | ||||
-rw-r--r-- | erts/emulator/beam/beam_bif_load.c | 70 | ||||
-rw-r--r-- | erts/emulator/beam/beam_load.c | 560 | ||||
-rw-r--r-- | erts/emulator/beam/beam_load.h | 4 | ||||
-rw-r--r-- | erts/emulator/beam/erl_alloc.c | 18 | ||||
-rw-r--r-- | erts/emulator/beam/erl_bif_ddll.c | 30 | ||||
-rw-r--r-- | erts/emulator/beam/erl_db_hash.c | 24 | ||||
-rw-r--r-- | erts/emulator/beam/erl_db_hash.h | 3 | ||||
-rw-r--r-- | erts/emulator/beam/erl_init.c | 14 | ||||
-rw-r--r-- | erts/emulator/beam/global.h | 11 | ||||
-rw-r--r-- | erts/emulator/drivers/common/inet_drv.c | 27 | ||||
-rw-r--r-- | erts/emulator/valgrind/suppress.patched.3.6.0 | 307 | ||||
-rw-r--r-- | erts/emulator/valgrind/suppress.standard | 268 | ||||
-rw-r--r-- | lib/diameter/src/base/diameter.appup.src | 25 | ||||
-rw-r--r-- | lib/diameter/test/diameter_app_SUITE.erl | 12 | ||||
-rw-r--r-- | lib/diameter/vsn.mk | 2 | ||||
-rw-r--r-- | lib/kernel/doc/src/net_kernel.xml | 4 | ||||
-rw-r--r-- | lib/stdlib/doc/src/supervisor.xml | 61 | ||||
-rw-r--r-- | system/doc/design_principles/sup_princ.xml | 7 |
19 files changed, 1004 insertions, 449 deletions
diff --git a/erts/doc/src/erlang.xml b/erts/doc/src/erlang.xml index b923a5f1fc..2ea144eb3f 100644 --- a/erts/doc/src/erlang.xml +++ b/erts/doc/src/erlang.xml @@ -3719,12 +3719,6 @@ os_prompt%</pre> <tag><c>process_flag(save_calls, N)</c></tag> <item> - <p>When there are runnable processes on priority <c>max</c> - no processes on priority <c>low</c>, <c>normal</c>, or - <c>high</c> will be selected for execution. As with the - <c>high</c> priority, processes on lower priorities might - execute in parallel with processes on priority <c>max</c>. - </p> <p><c>N</c> must be an integer in the interval 0..10000. If <c>N</c> > 0, call saving is made active for the process, which means that information about the <c>N</c> diff --git a/erts/emulator/beam/beam_bif_load.c b/erts/emulator/beam/beam_bif_load.c index 294b1578be..efb72cd3e7 100644 --- a/erts/emulator/beam/beam_bif_load.c +++ b/erts/emulator/beam/beam_bif_load.c @@ -50,11 +50,11 @@ load_module_2(BIF_ALIST_2) { Eterm reason; Eterm* hp; - int i; int sz; byte* code; Eterm res; byte* temp_alloc = NULL; + struct LoaderState* stp; if (is_not_atom(BIF_ARG_1)) { error: @@ -64,47 +64,37 @@ load_module_2(BIF_ALIST_2) if ((code = erts_get_aligned_binary_bytes(BIF_ARG_2, &temp_alloc)) == NULL) { goto error; } - erts_smp_proc_unlock(BIF_P, ERTS_PROC_LOCK_MAIN); - erts_smp_thr_progress_block(); - hp = HAlloc(BIF_P, 3); + + /* + * Read the BEAM file and prepare the module for loading. + */ + stp = erts_alloc_loader_state(); sz = binary_size(BIF_ARG_2); - if ((i = erts_load_module(BIF_P, 0, - BIF_P->group_leader, &BIF_ARG_1, code, sz)) < 0) { - switch (i) { - case -1: reason = am_badfile; break; - case -2: reason = am_nofile; break; - case -3: reason = am_not_purged; break; - case -4: - reason = am_atom_put("native_code", sizeof("native_code")-1); - break; - case -5: - { - /* - * The module contains an on_load function. The loader - * has loaded the module as usual, except that the - * export entries does not point into the module, so it - * is not possible to call any code in the module. - */ - - ERTS_DECL_AM(on_load); - reason = AM_on_load; - break; - } - default: reason = am_badfile; break; - } + reason = erts_prepare_loading(stp, 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); - goto done; + BIF_RET(res); } - set_default_trace_pattern(BIF_ARG_1); - res = TUPLE2(hp, am_module, BIF_ARG_1); + /* + * 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(); + + reason = erts_finish_loading(stp, BIF_P, 0, &BIF_ARG_1); + if (reason != NIL) { + res = TUPLE2(hp, am_error, reason); + } else { + set_default_trace_pattern(BIF_ARG_1); + res = TUPLE2(hp, am_module, BIF_ARG_1); + } - done: - erts_free_aligned_binary_bytes(temp_alloc); erts_smp_thr_progress_unblock(); erts_smp_proc_lock(BIF_P, ERTS_PROC_LOCK_MAIN); - BIF_RET(res); } @@ -654,9 +644,6 @@ purge_module(int module) * Any code to purge? */ if (modp->old_code == 0) { - if (display_loads) { - erts_printf("No code to purge for %T\n", make_atom(module)); - } return -1; } @@ -772,7 +759,7 @@ delete_export_references(Eterm module) } -int +Eterm beam_make_current_old(Process *c_p, ErtsProcLocks c_p_locks, Eterm module) { Module* modp = erts_put_module(module); @@ -783,15 +770,12 @@ beam_make_current_old(Process *c_p, ErtsProcLocks c_p_locks, Eterm module) */ if (modp->code != NULL && modp->old_code != NULL) { - return -3; + return am_not_purged; } else if (modp->old_code == NULL) { /* Make the current version old. */ - if (display_loads) { - erts_printf("saving old code\n"); - } delete_code(c_p, c_p_locks, modp); delete_export_references(module); } - return 0; + return NIL; } static int diff --git a/erts/emulator/beam/beam_load.c b/erts/emulator/beam/beam_load.c index 3836f1ae96..10ed46417b 100644 --- a/erts/emulator/beam/beam_load.c +++ b/erts/emulator/beam/beam_load.c @@ -245,7 +245,7 @@ typedef struct { * This structure contains all information about the module being loaded. */ -typedef struct { +typedef struct LoaderState { /* * The current logical file within the binary. */ @@ -287,7 +287,6 @@ typedef struct { BeamInstr* code; /* Loaded code. */ int ci; /* Current index into loaded code. */ Label* labels; - BeamInstr new_bs_put_strings; /* Linked list of i_new_bs_put_string instructions. */ StringPatch* string_patches; /* Linked list of position into string table to patch. */ BeamInstr catches; /* Linked list of catch_yf instructions. */ unsigned loaded_size; /* Final size of code when loaded. */ @@ -351,11 +350,6 @@ typedef struct { int loc_size; /* Size of location info in bytes (2/4) */ } LoaderState; -typedef struct { - unsigned num_functions; /* Number of functions. */ - Eterm* func_tab[1]; /* Pointers to each function. */ -} LoadedCode; - /* * Layout of the line table. */ @@ -500,12 +494,10 @@ typedef struct { } while (0) -static int bin_load(Process *c_p, ErtsProcLocks c_p_locks, - Eterm group_leader, Eterm* modp, byte* bytes, int unloaded_size); -static void init_state(LoaderState* stp); -static int insert_new_code(Process *c_p, ErtsProcLocks c_p_locks, - Eterm group_leader, Eterm module, - BeamInstr* code, Uint size, BeamInstr catches); +static void free_state(LoaderState* stp); +static Eterm insert_new_code(Process *c_p, ErtsProcLocks c_p_locks, + Eterm group_leader, Eterm module, + BeamInstr* code, Uint size); static int scan_iff_file(LoaderState* stp, Uint* chunk_types, Uint num_types, Uint num_mandatory); static int load_atom_table(LoaderState* stp); @@ -598,7 +590,7 @@ define_file(LoaderState* stp, char* name, int idx) stp->file_left = stp->chunks[idx].size; } -int +Eterm erts_load_module(Process *c_p, ErtsProcLocks c_p_locks, Eterm group_leader, /* Group leader or NIL if none. */ @@ -607,29 +599,17 @@ erts_load_module(Process *c_p, * On return, contains the actual module name. */ byte* code, /* Points to the code to load */ - int size) /* Size of code to load. */ + Uint size) /* Size of code to load. */ { - ErlDrvBinary* bin; - int result; + LoaderState* stp = erts_alloc_loader_state(); + Eterm retval; - if (size >= 4 && code[0] == 'F' && code[1] == 'O' && - code[2] == 'R' && code[3] == '1') { - /* - * The BEAM module is not compressed. - */ - result = bin_load(c_p, c_p_locks, group_leader, modp, code, size); - } else { - /* - * The BEAM module is compressed (or possibly invalid/corrupted). - */ - if ((bin = (ErlDrvBinary *) erts_gzinflate_buffer((char*)code, size)) == NULL) { - return -1; - } - result = bin_load(c_p, c_p_locks, group_leader, modp, - (byte*)bin->orig_bytes, bin->orig_size); - driver_free_binary(bin); + retval = erts_prepare_loading(stp, c_p, group_leader, modp, + code, size); + if (retval != NIL) { + return retval; } - return result; + return erts_finish_loading(stp, c_p, c_p_locks, modp); } /* #define LOAD_MEMORY_HARD_DEBUG 1*/ @@ -644,16 +624,30 @@ extern void check_allocated_block(Uint type, void *blk); #define CHKBLK(TYPE,BLK) /* nothing */ #endif -static int -bin_load(Process *c_p, ErtsProcLocks c_p_locks, - Eterm group_leader, Eterm* modp, byte* bytes, int unloaded_size) +Eterm +erts_prepare_loading(LoaderState* stp, Process *c_p, Eterm group_leader, + Eterm* modp, byte* code, Uint unloaded_size) { - LoaderState state; - int rval = -1; + Eterm retval = am_badfile; + ErlDrvBinary* bin = NULL; - init_state(&state); - state.module = *modp; - state.group_leader = group_leader; + stp->module = *modp; + stp->group_leader = group_leader; + + /* + * Check if the module is compressed (or possibly invalid/corrupted). + */ + if ( !(unloaded_size >= 4 && + code[0] == 'F' && code[1] == 'O' && + code[2] == 'R' && code[3] == '1') ) { + bin = (ErlDrvBinary *) + erts_gzinflate_buffer((char*)code, unloaded_size); + if (bin == NULL) { + goto load_error; + } + code = (byte*)bin->orig_bytes; + unloaded_size = bin->orig_size; + } /* * Scan the IFF file. @@ -664,11 +658,11 @@ bin_load(Process *c_p, ErtsProcLocks c_p_locks, #endif CHKALLOC(); - CHKBLK(ERTS_ALC_T_CODE,state.code); - state.file_name = "IFF header for Beam file"; - state.file_p = bytes; - state.file_left = unloaded_size; - if (!scan_iff_file(&state, chunk_types, NUM_CHUNK_TYPES, NUM_MANDATORY)) { + CHKBLK(ERTS_ALC_T_CODE,stp->code); + stp->file_name = "IFF header for Beam file"; + stp->file_p = code; + stp->file_left = unloaded_size; + if (!scan_iff_file(stp, chunk_types, NUM_CHUNK_TYPES, NUM_MANDATORY)) { goto load_error; } @@ -676,38 +670,38 @@ bin_load(Process *c_p, ErtsProcLocks c_p_locks, * Read the header for the code chunk. */ - CHKBLK(ERTS_ALC_T_CODE,state.code); - define_file(&state, "code chunk header", CODE_CHUNK); - if (!read_code_header(&state)) { + CHKBLK(ERTS_ALC_T_CODE,stp->code); + define_file(stp, "code chunk header", CODE_CHUNK); + if (!read_code_header(stp)) { goto load_error; } /* * Initialize code area. */ - state.code_buffer_size = erts_next_heap_size(2048 + state.num_functions, 0); - state.code = (BeamInstr *) erts_alloc(ERTS_ALC_T_CODE, - sizeof(BeamInstr) * state.code_buffer_size); + stp->code_buffer_size = erts_next_heap_size(2048 + stp->num_functions, 0); + stp->code = (BeamInstr *) erts_alloc(ERTS_ALC_T_CODE, + sizeof(BeamInstr) * stp->code_buffer_size); - state.code[MI_NUM_FUNCTIONS] = state.num_functions; - state.ci = MI_FUNCTIONS + state.num_functions + 1; + stp->code[MI_NUM_FUNCTIONS] = stp->num_functions; + stp->ci = MI_FUNCTIONS + stp->num_functions + 1; - state.code[MI_ATTR_PTR] = 0; - state.code[MI_ATTR_SIZE] = 0; - state.code[MI_ATTR_SIZE_ON_HEAP] = 0; - state.code[MI_COMPILE_PTR] = 0; - state.code[MI_COMPILE_SIZE] = 0; - state.code[MI_COMPILE_SIZE_ON_HEAP] = 0; - state.code[MI_NUM_BREAKPOINTS] = 0; + stp->code[MI_ATTR_PTR] = 0; + stp->code[MI_ATTR_SIZE] = 0; + stp->code[MI_ATTR_SIZE_ON_HEAP] = 0; + 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. */ - CHKBLK(ERTS_ALC_T_CODE,state.code); - define_file(&state, "atom table", ATOM_CHUNK); - if (!load_atom_table(&state)) { + CHKBLK(ERTS_ALC_T_CODE,stp->code); + define_file(stp, "atom table", ATOM_CHUNK); + if (!load_atom_table(stp)) { goto load_error; } @@ -715,9 +709,9 @@ bin_load(Process *c_p, ErtsProcLocks c_p_locks, * Read the import table. */ - CHKBLK(ERTS_ALC_T_CODE,state.code); - define_file(&state, "import table", IMP_CHUNK); - if (!load_import_table(&state)) { + CHKBLK(ERTS_ALC_T_CODE,stp->code); + define_file(stp, "import table", IMP_CHUNK); + if (!load_import_table(stp)) { goto load_error; } @@ -725,10 +719,10 @@ bin_load(Process *c_p, ErtsProcLocks c_p_locks, * Read the lambda (fun) table. */ - CHKBLK(ERTS_ALC_T_CODE,state.code); - if (state.chunks[LAMBDA_CHUNK].size > 0) { - define_file(&state, "lambda (fun) table", LAMBDA_CHUNK); - if (!read_lambda_table(&state)) { + CHKBLK(ERTS_ALC_T_CODE,stp->code); + if (stp->chunks[LAMBDA_CHUNK].size > 0) { + define_file(stp, "lambda (fun) table", LAMBDA_CHUNK); + if (!read_lambda_table(stp)) { goto load_error; } } @@ -737,10 +731,10 @@ bin_load(Process *c_p, ErtsProcLocks c_p_locks, * Read the literal table. */ - CHKBLK(ERTS_ALC_T_CODE,state.code); - if (state.chunks[LITERAL_CHUNK].size > 0) { - define_file(&state, "literals table (constant pool)", LITERAL_CHUNK); - if (!read_literal_table(&state)) { + CHKBLK(ERTS_ALC_T_CODE,stp->code); + if (stp->chunks[LITERAL_CHUNK].size > 0) { + define_file(stp, "literals table (constant pool)", LITERAL_CHUNK); + if (!read_literal_table(stp)) { goto load_error; } } @@ -749,35 +743,27 @@ bin_load(Process *c_p, ErtsProcLocks c_p_locks, * Read the line table (if present). */ - CHKBLK(ERTS_ALC_T_CODE,state.code); - if (state.chunks[LINE_CHUNK].size > 0) { - define_file(&state, "line table", LINE_CHUNK); - if (!read_line_table(&state)) { + CHKBLK(ERTS_ALC_T_CODE,stp->code); + if (stp->chunks[LINE_CHUNK].size > 0) { + define_file(stp, "line table", LINE_CHUNK); + if (!read_line_table(stp)) { goto load_error; } } /* - * Since the literal table *may* have contained external - * funs (containing references to export entries), now is - * the time to consolidate the export tables. - */ - - erts_export_consolidate(); - - /* * Load the code chunk. */ - CHKBLK(ERTS_ALC_T_CODE,state.code); - state.file_name = "code chunk"; - state.file_p = state.code_start; - state.file_left = state.code_size; - if (!load_code(&state)) { + CHKBLK(ERTS_ALC_T_CODE,stp->code); + stp->file_name = "code chunk"; + stp->file_p = stp->code_start; + stp->file_left = stp->code_size; + if (!load_code(stp)) { goto load_error; } - CHKBLK(ERTS_ALC_T_CODE,state.code); - if (!freeze_code(&state)) { + CHKBLK(ERTS_ALC_T_CODE,stp->code); + if (!freeze_code(stp)) { goto load_error; } @@ -787,9 +773,52 @@ bin_load(Process *c_p, ErtsProcLocks c_p_locks, * loading the code, because it contains labels.) */ - CHKBLK(ERTS_ALC_T_CODE,state.code); - define_file(&state, "export table", EXP_CHUNK); - if (!read_export_table(&state)) { + CHKBLK(ERTS_ALC_T_CODE,stp->code); + define_file(stp, "export table", EXP_CHUNK); + if (!read_export_table(stp)) { + goto load_error; + } + + /* + * Good so far. + */ + + retval = NIL; + + load_error: + if (bin) { + driver_free_binary(bin); + } + if (retval != NIL) { + free_state(stp); + } + return retval; +} + +Eterm +erts_finish_loading(LoaderState* stp, Process* c_p, + ErtsProcLocks c_p_locks, Eterm* modp) +{ + Eterm retval; + + /* + * No other process may run since we will update the export + * table which is not protected by any locks. + */ + + ERTS_SMP_LC_ASSERT(erts_initialized == 0 || + erts_smp_thr_progress_is_blocking()); + + /* + * Make current code for the module old and insert the new code + * as current. This will fail if there already exists old code + * for the module. + */ + + CHKBLK(ERTS_ALC_T_CODE,stp->code); + retval = insert_new_code(c_p, c_p_locks, stp->group_leader, stp->module, + stp->code, stp->loaded_size); + if (retval != NIL) { goto load_error; } @@ -798,104 +827,42 @@ bin_load(Process *c_p, ErtsProcLocks c_p_locks, * exported and imported functions. This can't fail. */ - CHKBLK(ERTS_ALC_T_CODE,state.code); - rval = insert_new_code(c_p, c_p_locks, state.group_leader, state.module, - state.code, state.loaded_size, state.catches); - if (rval < 0) { - goto load_error; - } - CHKBLK(ERTS_ALC_T_CODE,state.code); - final_touch(&state); + erts_export_consolidate(); + CHKBLK(ERTS_ALC_T_CODE,stp->code); + final_touch(stp); /* * Loading succeded. */ - CHKBLK(ERTS_ALC_T_CODE,state.code); + CHKBLK(ERTS_ALC_T_CODE,stp->code); #if defined(LOAD_MEMORY_HARD_DEBUG) && defined(DEBUG) erts_fprintf(stderr,"Loaded %T\n",*modp); #if 0 - debug_dump_code(state.code,state.ci); + debug_dump_code(stp->code,stp->ci); #endif #endif - rval = 0; - state.code = NULL; /* Prevent code from being freed. */ - *modp = state.module; + stp->code = NULL; /* Prevent code from being freed. */ + *modp = stp->module; /* * If there is an on_load function, signal an error to * indicate that the on_load function must be run. */ - if (state.on_load) { - rval = -5; + if (stp->on_load) { + retval = am_on_load; } load_error: - if (state.code != 0) { - erts_free(ERTS_ALC_T_CODE, state.code); - } - if (state.labels != NULL) { - erts_free(ERTS_ALC_T_LOADER_TMP, (void *) state.labels); - } - if (state.atom != NULL) { - erts_free(ERTS_ALC_T_LOADER_TMP, (void *) state.atom); - } - if (state.import != NULL) { - erts_free(ERTS_ALC_T_LOADER_TMP, (void *) state.import); - } - if (state.export != NULL) { - erts_free(ERTS_ALC_T_LOADER_TMP, (void *) state.export); - } - if (state.lambdas != state.def_lambdas) { - erts_free(ERTS_ALC_T_LOADER_TMP, (void *) state.lambdas); - } - if (state.literals != NULL) { - int i; - for (i = 0; i < state.num_literals; i++) { - if (state.literals[i].heap != NULL) { - erts_free(ERTS_ALC_T_LOADER_TMP, (void *) state.literals[i].heap); - } - } - erts_free(ERTS_ALC_T_LOADER_TMP, (void *) state.literals); - } - while (state.literal_patches != NULL) { - LiteralPatch* next = state.literal_patches->next; - erts_free(ERTS_ALC_T_LOADER_TMP, (void *) state.literal_patches); - state.literal_patches = next; - } - while (state.string_patches != NULL) { - StringPatch* next = state.string_patches->next; - erts_free(ERTS_ALC_T_LOADER_TMP, (void *) state.string_patches); - state.string_patches = next; - } - while (state.genop_blocks) { - GenOpBlock* next = state.genop_blocks->next; - erts_free(ERTS_ALC_T_LOADER_TMP, (void *) state.genop_blocks); - state.genop_blocks = next; - } - - if (state.line_item != 0) { - erts_free(ERTS_ALC_T_LOADER_TMP, state.line_item); - } - - if (state.line_instr != 0) { - erts_free(ERTS_ALC_T_LOADER_TMP, state.line_instr); - } - - if (state.func_line != 0) { - erts_free(ERTS_ALC_T_LOADER_TMP, state.func_line); - } - - if (state.fname != 0) { - erts_free(ERTS_ALC_T_LOADER_TMP, state.fname); - } - - return rval; + free_state(stp); + return retval; } - -static void -init_state(LoaderState* stp) +LoaderState* +erts_alloc_loader_state(void) { + LoaderState* stp; + + stp = erts_alloc(ERTS_ALC_T_LOADER_TMP, sizeof(LoaderState)); stp->function = THE_NON_VALUE; /* Function not known yet */ stp->arity = 0; stp->specific_op = -1; @@ -923,23 +890,90 @@ init_state(LoaderState* stp) stp->line_instr = 0; stp->func_line = 0; stp->fname = 0; + return stp; } -static int +static void +free_state(LoaderState* stp) +{ + if (stp->code != 0) { + erts_free(ERTS_ALC_T_CODE, stp->code); + } + if (stp->labels != NULL) { + erts_free(ERTS_ALC_T_LOADER_TMP, (void *) stp->labels); + } + if (stp->atom != NULL) { + erts_free(ERTS_ALC_T_LOADER_TMP, (void *) stp->atom); + } + if (stp->import != NULL) { + erts_free(ERTS_ALC_T_LOADER_TMP, (void *) stp->import); + } + if (stp->export != NULL) { + erts_free(ERTS_ALC_T_LOADER_TMP, (void *) stp->export); + } + if (stp->lambdas != stp->def_lambdas) { + erts_free(ERTS_ALC_T_LOADER_TMP, (void *) stp->lambdas); + } + if (stp->literals != NULL) { + int i; + for (i = 0; i < stp->num_literals; i++) { + if (stp->literals[i].heap != NULL) { + erts_free(ERTS_ALC_T_LOADER_TMP, + (void *) stp->literals[i].heap); + } + } + erts_free(ERTS_ALC_T_LOADER_TMP, (void *) stp->literals); + } + while (stp->literal_patches != NULL) { + LiteralPatch* next = stp->literal_patches->next; + erts_free(ERTS_ALC_T_LOADER_TMP, (void *) stp->literal_patches); + stp->literal_patches = next; + } + while (stp->string_patches != NULL) { + StringPatch* next = stp->string_patches->next; + erts_free(ERTS_ALC_T_LOADER_TMP, (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); + } + + if (stp->line_instr != 0) { + erts_free(ERTS_ALC_T_LOADER_TMP, stp->line_instr); + } + + if (stp->func_line != 0) { + erts_free(ERTS_ALC_T_LOADER_TMP, stp->func_line); + } + + if (stp->fname != 0) { + erts_free(ERTS_ALC_T_LOADER_TMP, stp->fname); + } + erts_free(ERTS_ALC_T_LOADER_TMP, stp); +} + +static Eterm insert_new_code(Process *c_p, ErtsProcLocks c_p_locks, - Eterm group_leader, Eterm module, BeamInstr* code, Uint size, BeamInstr catches) + Eterm group_leader, Eterm module, BeamInstr* code, + Uint size) { Module* modp; - int rval; + Eterm retval; int i; - if ((rval = beam_make_current_old(c_p, c_p_locks, module)) < 0) { + if ((retval = beam_make_current_old(c_p, c_p_locks, module)) < 0) { erts_dsprintf_buf_t *dsbufp = erts_create_logger_dsbuf(); erts_dsprintf(dsbufp, "Module %T must be purged before loading\n", module); erts_send_error_to_logger(group_leader, dsbufp); - return rval; + return retval; } /* @@ -950,7 +984,7 @@ insert_new_code(Process *c_p, ErtsProcLocks c_p_locks, modp = erts_put_module(module); modp->code = code; modp->code_length = size; - modp->catches = catches; + modp->catches = BEAM_CATCHES_NIL; /* Will be filled in later. */ /* * Update address table (used for finding a function from a PC value). @@ -972,7 +1006,7 @@ insert_new_code(Process *c_p, ErtsProcLocks c_p_locks, modules[i].end = (BeamInstr *) (((byte *)code) + size); num_loaded_modules++; mid_module = &modules[num_loaded_modules/2]; - return 0; + return NIL; } static int @@ -1607,7 +1641,6 @@ read_code_header(LoaderState* stp) #endif } - stp->new_bs_put_strings = 0; stp->catches = 0; return 1; @@ -2319,32 +2352,6 @@ load_code(LoaderState* stp) stp->on_load = ci; break; case op_bs_put_string_II: - { - /* - * At entry: - * - * code[ci-3] &&lb_i_new_bs_put_string_II - * code[ci-2] length of string - * code[ci-1] offset into string table - * - * Since we don't know the address of the string table yet, - * just check the offset and length for validity, and use - * the instruction field as a link field to link all put_string - * instructions into a single linked list. At exit: - * - * code[ci-3] pointer to next i_new_bs_put_string instruction (or 0 - * if this is the last) - */ - Uint offset = code[ci-1]; - Uint len = code[ci-2]; - unsigned strtab_size = stp->chunks[STR_CHUNK].size; - if (offset > strtab_size || offset + len > strtab_size) { - LoadError2(stp, "invalid string reference %d, size %d", offset, len); - } - code[ci-3] = stp->new_bs_put_strings; - stp->new_bs_put_strings = ci - 3; - } - break; case op_i_bs_match_string_rfII: case op_i_bs_match_string_xfII: new_string_patch(stp, ci-1); @@ -3881,14 +3888,12 @@ freeze_code(LoaderState* stp) { BeamInstr* code = stp->code; Uint *literal_end = NULL; - Uint index; int i; byte* str_table; unsigned strtab_size = stp->chunks[STR_CHUNK].size; unsigned attr_size = stp->chunks[ATTR_CHUNK].size; unsigned compile_size = stp->chunks[COMPILE_CHUNK].size; Uint size; - unsigned catches; Sint decoded_size; Uint line_size; @@ -4101,20 +4106,8 @@ freeze_code(LoaderState* stp) ((byte *) code) + size); /* - * Go through all i_new_bs_put_strings instructions, restore the pointer to - * the instruction and convert string offsets to pointers (to the - * FIRST character). + * Patch all instructions that refer to the string table. */ - - index = stp->new_bs_put_strings; - while (index != 0) { - Uint next = code[index]; - code[index] = BeamOpCode(op_bs_put_string_II); - code[index+2] = (BeamInstr) (str_table + code[index+2]); - index = next; - } - CHKBLK(ERTS_ALC_T_CODE,code); - { StringPatch* sp = stp->string_patches; @@ -4155,21 +4148,6 @@ freeze_code(LoaderState* stp) CHKBLK(ERTS_ALC_T_CODE,code); /* - * Fix all catch_yf instructions. - */ - index = stp->catches; - catches = BEAM_CATCHES_NIL; - while (index != 0) { - BeamInstr next = code[index]; - code[index] = BeamOpCode(op_catch_yf); - catches = beam_catches_cons((BeamInstr *)code[index+2], catches); - code[index+2] = make_catch(catches); - index = next; - } - stp->catches = catches; - CHKBLK(ERTS_ALC_T_CODE,code); - - /* * Save the updated code pointer and code size. */ @@ -4194,6 +4172,26 @@ final_touch(LoaderState* stp) { int i; int on_load = stp->on_load; + unsigned catches; + Uint index; + BeamInstr* code = stp->code; + Module* modp; + + /* + * Allocate catch indices and fix up all catch_yf instructions. + */ + + index = stp->catches; + catches = BEAM_CATCHES_NIL; + while (index != 0) { + BeamInstr next = code[index]; + code[index] = BeamOpCode(op_catch_yf); + catches = beam_catches_cons((BeamInstr *)code[index+2], catches); + code[index+2] = make_catch(catches); + index = next; + } + modp = erts_put_module(stp->module); + modp->catches = catches; /* * Export functions. @@ -5731,7 +5729,7 @@ patch_funentries(Eterm Patchlist) Eterm erts_make_stub_module(Process* p, Eterm Mod, Eterm Beam, Eterm Info) { - LoaderState state; + LoaderState* stp; BeamInstr Funcs; BeamInstr Patchlist; Eterm* tp; @@ -5750,10 +5748,10 @@ erts_make_stub_module(Process* p, Eterm Mod, Eterm Beam, Eterm Info) Uint size; /* - * Must initialize state.lambdas here because the error handling code + * Must initialize stp->lambdas here because the error handling code * at label 'error' uses it. */ - init_state(&state); + stp = erts_alloc_loader_state(); if (is_not_atom(Mod)) { goto error; @@ -5793,31 +5791,31 @@ erts_make_stub_module(Process* p, Eterm Mod, Eterm Beam, Eterm Info) * Scan the Beam binary and read the interesting sections. */ - state.file_name = "IFF header for Beam file"; - state.file_p = bytes; - state.file_left = size; - state.module = Mod; - state.group_leader = p->group_leader; - state.num_functions = n; - if (!scan_iff_file(&state, chunk_types, NUM_CHUNK_TYPES, NUM_MANDATORY)) { + stp->file_name = "IFF header for Beam file"; + stp->file_p = bytes; + stp->file_left = size; + stp->module = Mod; + stp->group_leader = p->group_leader; + stp->num_functions = n; + if (!scan_iff_file(stp, chunk_types, NUM_CHUNK_TYPES, NUM_MANDATORY)) { goto error; } - define_file(&state, "code chunk header", CODE_CHUNK); - if (!read_code_header(&state)) { + define_file(stp, "code chunk header", CODE_CHUNK); + if (!read_code_header(stp)) { goto error; } - define_file(&state, "atom table", ATOM_CHUNK); - if (!load_atom_table(&state)) { + define_file(stp, "atom table", ATOM_CHUNK); + if (!load_atom_table(stp)) { goto error; } - define_file(&state, "export table", EXP_CHUNK); - if (!stub_read_export_table(&state)) { + define_file(stp, "export table", EXP_CHUNK); + if (!stub_read_export_table(stp)) { goto error; } - if (state.chunks[LAMBDA_CHUNK].size > 0) { - define_file(&state, "lambda (fun) table", LAMBDA_CHUNK); - if (!read_lambda_table(&state)) { + if (stp->chunks[LAMBDA_CHUNK].size > 0) { + define_file(stp, "lambda (fun) table", LAMBDA_CHUNK); + if (!read_lambda_table(stp)) { goto error; } } @@ -5827,8 +5825,8 @@ erts_make_stub_module(Process* p, Eterm Mod, Eterm Beam, Eterm Info) */ code_size = ((WORDS_PER_FUNCTION+1)*n + MI_FUNCTIONS + 2) * sizeof(BeamInstr); - code_size += state.chunks[ATTR_CHUNK].size; - code_size += state.chunks[COMPILE_CHUNK].size; + code_size += stp->chunks[ATTR_CHUNK].size; + code_size += stp->chunks[COMPILE_CHUNK].size; code = erts_alloc_fnf(ERTS_ALC_T_CODE, code_size); if (!code) { goto error; @@ -5918,12 +5916,12 @@ erts_make_stub_module(Process* p, Eterm Mod, Eterm Beam, Eterm Info) */ info = (byte *) fp; - info = stub_copy_info(&state, ATTR_CHUNK, info, + info = stub_copy_info(stp, ATTR_CHUNK, info, code+MI_ATTR_PTR, code+MI_ATTR_SIZE_ON_HEAP); if (info == NULL) { goto error; } - info = stub_copy_info(&state, COMPILE_CHUNK, info, + info = stub_copy_info(stp, COMPILE_CHUNK, info, code+MI_COMPILE_PTR, code+MI_COMPILE_SIZE_ON_HEAP); if (info == NULL) { goto error; @@ -5933,9 +5931,8 @@ erts_make_stub_module(Process* p, Eterm Mod, Eterm Beam, Eterm Info) * Insert the module in the module table. */ - rval = insert_new_code(p, 0, p->group_leader, Mod, code, code_size, - BEAM_CATCHES_NIL); - if (rval < 0) { + rval = insert_new_code(p, 0, p->group_leader, Mod, code, code_size); + if (rval != NIL) { goto error; } @@ -5945,18 +5942,13 @@ erts_make_stub_module(Process* p, Eterm Mod, Eterm Beam, Eterm Info) fp = code + ci; for (i = 0; i < n; i++) { - stub_final_touch(&state, fp); + stub_final_touch(stp, fp); fp += WORDS_PER_FUNCTION; } if (patch_funentries(Patchlist)) { erts_free_aligned_binary_bytes(temp_alloc); - if (state.lambdas != state.def_lambdas) { - erts_free(ERTS_ALC_T_LOADER_TMP, (void *) state.lambdas); - } - erts_free(ERTS_ALC_T_LOADER_TMP, (void *) state.labels); - erts_free(ERTS_ALC_T_LOADER_TMP, (void *) state.atom); - erts_free(ERTS_ALC_T_LOADER_TMP, (void *) state.export); + free_state(stp); if (bin != NULL) { driver_free_binary(bin); } @@ -5964,27 +5956,7 @@ erts_make_stub_module(Process* p, Eterm Mod, Eterm Beam, Eterm Info) } error: - erts_free_aligned_binary_bytes(temp_alloc); - if (code != NULL) { - erts_free(ERTS_ALC_T_CODE, code); - } - if (state.labels != NULL) { - erts_free(ERTS_ALC_T_LOADER_TMP, (void *) state.labels); - } - if (state.lambdas != state.def_lambdas) { - erts_free(ERTS_ALC_T_LOADER_TMP, (void *) state.lambdas); - } - if (state.atom != NULL) { - erts_free(ERTS_ALC_T_LOADER_TMP, (void *) state.atom); - } - if (state.export != NULL) { - erts_free(ERTS_ALC_T_LOADER_TMP, (void *) state.export); - } - if (bin != NULL) { - driver_free_binary(bin); - } - - + free_state(stp); BIF_ERROR(p, BADARG); } diff --git a/erts/emulator/beam/beam_load.h b/erts/emulator/beam/beam_load.h index 9d4a60fed1..126d9a3935 100644 --- a/erts/emulator/beam/beam_load.h +++ b/erts/emulator/beam/beam_load.h @@ -23,7 +23,9 @@ #include "beam_opcodes.h" #include "erl_process.h" -int beam_make_current_old(Process *c_p, ErtsProcLocks c_p_locks, Eterm module); +Eterm beam_make_current_old(Process *c_p, ErtsProcLocks c_p_locks, + Eterm module); + typedef struct gen_op_entry { char* name; diff --git a/erts/emulator/beam/erl_alloc.c b/erts/emulator/beam/erl_alloc.c index 33d6cf5f2f..140a84d5fc 100644 --- a/erts/emulator/beam/erl_alloc.c +++ b/erts/emulator/beam/erl_alloc.c @@ -2758,16 +2758,18 @@ erts_allocator_options(void *proc) void *erts_alloc_permanent_cache_aligned(ErtsAlcType_t type, Uint size) { - UWord v = (UWord) erts_alloc(type, size + (ERTS_CACHE_LINE_SIZE-1)); + UWord v = (UWord) erts_alloc(type, size + (ERTS_CACHE_LINE_SIZE-1) +#ifdef VALGRIND + + sizeof(UWord) +#endif + ); #ifdef VALGRIND - { /* Avoid Leak_PossiblyLost */ - static UWord vg_root_set[10]; - static unsigned ix = 0; - if (ix >= sizeof(vg_root_set) / sizeof(*vg_root_set)) { - erl_exit(ERTS_ABORT_EXIT, "Too many erts_alloc_permanent_cache_aligned's\n"); - } - vg_root_set[ix++] = v; /* not thread safe */ + { /* Link them to avoid Leak_PossiblyLost */ + static UWord* first_in_list = NULL; + *(UWord**)v = first_in_list; + first_in_list = (UWord*) v; + v += sizeof(UWord); } #endif diff --git a/erts/emulator/beam/erl_bif_ddll.c b/erts/emulator/beam/erl_bif_ddll.c index a9fd28c66b..b2d5722e9b 100644 --- a/erts/emulator/beam/erl_bif_ddll.c +++ b/erts/emulator/beam/erl_bif_ddll.c @@ -1569,14 +1569,14 @@ static int do_load_driver_entry(DE_Handle *dh, char *path, char *name) if ((res = erts_sys_ddll_load_driver_init(dh->handle, &init_handle)) != ERL_DE_NO_ERROR) { - erts_sys_ddll_close(dh->handle); - return ERL_DE_LOAD_ERROR_NO_INIT; + res = ERL_DE_LOAD_ERROR_NO_INIT; + goto error; } dp = erts_sys_ddll_call_init(init_handle); if (dp == NULL) { - erts_sys_ddll_close(dh->handle); - return ERL_DE_LOAD_ERROR_FAILED_INIT; + res = ERL_DE_LOAD_ERROR_FAILED_INIT; + goto error; } switch (dp->extended_marker) { @@ -1594,24 +1594,27 @@ static int do_load_driver_entry(DE_Handle *dh, char *path, char *name) || dp->handle2 != NULL || dp->process_exit != NULL) { /* Old driver; needs to be recompiled... */ - return ERL_DE_LOAD_ERROR_INCORRECT_VERSION; + res = ERL_DE_LOAD_ERROR_INCORRECT_VERSION; + goto error; } break; case ERL_DRV_EXTENDED_MARKER: if (ERL_DRV_EXTENDED_MAJOR_VERSION != dp->major_version || ERL_DRV_EXTENDED_MINOR_VERSION < dp->minor_version) { /* Incompatible driver version */ - return ERL_DE_LOAD_ERROR_INCORRECT_VERSION; + res = ERL_DE_LOAD_ERROR_INCORRECT_VERSION; + goto error; } break; default: /* Old driver; needs to be recompiled... */ - return ERL_DE_LOAD_ERROR_INCORRECT_VERSION; + res = ERL_DE_LOAD_ERROR_INCORRECT_VERSION; + goto error; } if (strcmp(name, dp->driver_name) != 0) { - erts_sys_ddll_close(dh->handle); - return ERL_DE_LOAD_ERROR_BAD_NAME; + res = ERL_DE_LOAD_ERROR_BAD_NAME; + goto error; } erts_smp_atomic_init_nob(&(dh->refc), (erts_aint_t) 0); dh->port_count = 0; @@ -1626,11 +1629,14 @@ static int do_load_driver_entry(DE_Handle *dh, char *path, char *name) */ erts_free(ERTS_ALC_T_DDLL_HANDLE, dh->full_path); dh->full_path = NULL; - erts_sys_ddll_close(dh->handle); - return ERL_DE_LOAD_ERROR_FAILED_INIT; + res = ERL_DE_LOAD_ERROR_FAILED_INIT; + goto error; } - return ERL_DE_NO_ERROR; + +error: + erts_sys_ddll_close(dh->handle); + return res; } static int do_unload_driver_entry(DE_Handle *dh, Eterm *save_name) diff --git a/erts/emulator/beam/erl_db_hash.c b/erts/emulator/beam/erl_db_hash.c index e3380a57b2..038a667b06 100644 --- a/erts/emulator/beam/erl_db_hash.c +++ b/erts/emulator/beam/erl_db_hash.c @@ -312,15 +312,24 @@ struct ext_segment { struct segment* segtab[1]; /* The segment table */ }; #define SIZEOF_EXTSEG(NSEGS) \ - (sizeof(struct ext_segment) - sizeof(struct segment*) + sizeof(struct segment*)*(NSEGS)) + (offsetof(struct ext_segment,segtab) + sizeof(struct segment*)*(NSEGS)) -#ifdef DEBUG -# include <stddef.h> /* offsetof */ +#if defined(DEBUG) || defined(VALGRIND) # define EXTSEG(SEGTAB_PTR) \ ((struct ext_segment*) (((char*)(SEGTAB_PTR)) - offsetof(struct ext_segment,segtab))) #endif +static ERTS_INLINE void SET_SEGTAB(DbTableHash* tb, + struct segment** segtab) +{ + erts_smp_atomic_set_wb(&tb->segtab, (erts_aint_t) segtab); +#ifdef VALGRIND + tb->top_ptr_to_segment_with_active_segtab = EXTSEG(segtab); +#endif +} + + /* How the table segments relate to each other: ext_segment: ext_segment: "plain" segment @@ -649,7 +658,8 @@ int db_create_hash(Process *p, DbTable *tbl) erts_smp_atomic_init_nob(&tb->szm, SEGSZ_MASK); erts_smp_atomic_init_nob(&tb->nactive, SEGSZ); erts_smp_atomic_init_nob(&tb->fixdel, (erts_aint_t)NULL); - erts_smp_atomic_init_nob(&tb->segtab, (erts_aint_t) alloc_ext_seg(tb,0,NULL)->segtab); + erts_smp_atomic_init_nob(&tb->segtab, (erts_aint_t)NULL); + SET_SEGTAB(tb, alloc_ext_seg(tb,0,NULL)->segtab); tb->nsegs = NSEG_1; tb->nslots = SEGSZ; @@ -2357,7 +2367,7 @@ static int alloc_seg(DbTableHash *tb) struct ext_segment* eseg; eseg = (struct ext_segment*) SEGTAB(tb)[seg_ix-1]; MY_ASSERT(eseg!=NULL && eseg->s.is_ext_segment); - erts_smp_atomic_set_wb(&tb->segtab, (erts_aint_t) eseg->segtab); + SET_SEGTAB(tb, eseg->segtab); tb->nsegs = eseg->nsegs; } ASSERT(seg_ix < tb->nsegs); @@ -2429,7 +2439,7 @@ static int free_seg(DbTableHash *tb, int free_records) MY_ASSERT(newtop->s.is_ext_segment); if (newtop->prev_segtab != NULL) { /* Time to use a smaller segtab */ - erts_smp_atomic_set_wb(&tb->segtab, (erts_aint_t)newtop->prev_segtab); + SET_SEGTAB(tb, newtop->prev_segtab); tb->nsegs = seg_ix; ASSERT(tb->nsegs == EXTSEG(SEGTAB(tb))->nsegs); } @@ -2446,7 +2456,7 @@ static int free_seg(DbTableHash *tb, int free_records) if (seg_ix > 0) { if (seg_ix < tb->nsegs) SEGTAB(tb)[seg_ix] = NULL; } else { - erts_smp_atomic_set_wb(&tb->segtab, (erts_aint_t)NULL); + SET_SEGTAB(tb, NULL); } #endif tb->nslots -= SEGSZ; diff --git a/erts/emulator/beam/erl_db_hash.h b/erts/emulator/beam/erl_db_hash.h index e0285fa5ed..23ac493118 100644 --- a/erts/emulator/beam/erl_db_hash.h +++ b/erts/emulator/beam/erl_db_hash.h @@ -58,6 +58,9 @@ typedef struct db_table_hash { #ifdef ERTS_SMP DbTableHashFineLocks* locks; #endif +#ifdef VALGRIND + struct ext_segment* top_ptr_to_segment_with_active_segtab; +#endif } DbTableHash; diff --git a/erts/emulator/beam/erl_init.c b/erts/emulator/beam/erl_init.c index 7c047891d9..7ae9f990ad 100644 --- a/erts/emulator/beam/erl_init.c +++ b/erts/emulator/beam/erl_init.c @@ -92,7 +92,6 @@ int erts_use_sender_punish; */ Uint display_items; /* no of items to display in traces etc */ -Uint display_loads; /* print info about loaded modules */ int H_MIN_SIZE; /* The minimum heap grain */ int BIN_VH_MIN_SIZE; /* The minimum binary virtual*/ @@ -437,7 +436,7 @@ static void load_preloaded(void) { int i; - int res; + Eterm res; Preload* preload_p; Eterm module_name; byte* code; @@ -456,8 +455,9 @@ load_preloaded(void) name); res = erts_load_module(NULL, 0, NIL, &module_name, code, length); sys_preload_end(&preload_p[i]); - if (res < 0) - erl_exit(1,"Failed loading preloaded module %s\n", name); + if (res != NIL) + erl_exit(1,"Failed loading preloaded module %s (%T)\n", + name, res); i++; } } @@ -499,8 +499,6 @@ void erts_usage(void) erts_fprintf(stderr, "-K boolean enable or disable kernel poll\n"); - erts_fprintf(stderr, "-l turn on auto load tracing\n"); - erts_fprintf(stderr, "-M<X> <Y> memory allocator switches,\n"); erts_fprintf(stderr, " see the erts_alloc(3) documentation for more info.\n"); @@ -616,7 +614,6 @@ early_init(int *argc, char **argv) /* erts_printf_eterm_func = erts_printf_term; erts_disable_tolerant_timeofday = 0; display_items = 200; - display_loads = 0; erts_backtrace_depth = DEFAULT_BACKTRACE_SIZE; erts_async_max_threads = 0; erts_async_thread_suggested_stack_size = ERTS_ASYNC_THREAD_MIN_STACK_SIZE; @@ -981,9 +978,6 @@ erl_start(int argc, char **argv) erts_fprintf(stderr, "%s unknown flag %s\n", argv[0], argv[i]); erts_usage(); } - case 'l': - display_loads++; - break; case 'L': erts_no_line_info = 1; break; diff --git a/erts/emulator/beam/global.h b/erts/emulator/beam/global.h index 4a4973baab..9f19172e08 100644 --- a/erts/emulator/beam/global.h +++ b/erts/emulator/beam/global.h @@ -555,7 +555,6 @@ extern Eterm node_cookie; extern erts_smp_atomic_t erts_bytes_out; /* no bytes written out */ extern erts_smp_atomic_t erts_bytes_in; /* no bytes sent into the system */ extern Uint display_items; /* no of items to display in traces etc */ -extern Uint display_loads; /* print info about loaded modules */ extern int erts_backtrace_depth; extern erts_smp_atomic32_t erts_max_gen_gcs; @@ -867,8 +866,14 @@ typedef struct { Eterm* fname_ptr; /* Pointer to fname table */ } FunctionInfo; -int erts_load_module(Process *c_p, ErtsProcLocks c_p_locks, - Eterm group_leader, Eterm* mod, byte* code, int size); +struct LoaderState* erts_alloc_loader_state(void); +Eterm erts_prepare_loading(struct LoaderState*, Process *c_p, + Eterm group_leader, Eterm* modp, + 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); void init_load(void); BeamInstr* find_function_from_pc(BeamInstr* pc); Eterm* erts_build_mfa_item(FunctionInfo* fi, Eterm* hp, diff --git a/erts/emulator/drivers/common/inet_drv.c b/erts/emulator/drivers/common/inet_drv.c index 7c9dc9fd3b..2ff5f744d6 100644 --- a/erts/emulator/drivers/common/inet_drv.c +++ b/erts/emulator/drivers/common/inet_drv.c @@ -8614,32 +8614,29 @@ static int tcp_deliver(tcp_descriptor* desc, int len) } while (len > 0) { - int code = 0; + int code; inet_input_count(INETP(desc), len); /* deliver binary? */ if (len*4 >= desc->i_buf->orig_size*3) { /* >=75% */ + code = tcp_reply_binary_data(desc, desc->i_buf, + (desc->i_ptr_start - + desc->i_buf->orig_bytes), + len); + if (code < 0) + return code; + /* something after? */ if (desc->i_ptr_start + len == desc->i_ptr) { /* no */ - code = tcp_reply_binary_data(desc, desc->i_buf, - (desc->i_ptr_start - - desc->i_buf->orig_bytes), - len); tcp_clear_input(desc); } else { /* move trail to beginning of a new buffer */ - ErlDrvBinary* bin; + ErlDrvBinary* bin = alloc_buffer(desc->i_bufsz); char* ptr_end = desc->i_ptr_start + len; int sz = desc->i_ptr - ptr_end; - bin = alloc_buffer(desc->i_bufsz); memcpy(bin->orig_bytes, ptr_end, sz); - - code = tcp_reply_binary_data(desc, desc->i_buf, - (desc->i_ptr_start- - desc->i_buf->orig_bytes), - len); free_buffer(desc->i_buf); desc->i_buf = bin; desc->i_ptr_start = desc->i_buf->orig_bytes; @@ -8651,17 +8648,15 @@ static int tcp_deliver(tcp_descriptor* desc, int len) code = tcp_reply_data(desc, desc->i_ptr_start, len); /* XXX The buffer gets thrown away on error (code < 0) */ /* Windows needs workaround for this in tcp_inet_event... */ + if (code < 0) + return code; desc->i_ptr_start += len; if (desc->i_ptr_start == desc->i_ptr) tcp_clear_input(desc); else desc->i_remain = 0; - } - if (code < 0) - return code; - count++; len = 0; diff --git a/erts/emulator/valgrind/suppress.patched.3.6.0 b/erts/emulator/valgrind/suppress.patched.3.6.0 new file mode 100644 index 0000000000..2647949672 --- /dev/null +++ b/erts/emulator/valgrind/suppress.patched.3.6.0 @@ -0,0 +1,307 @@ +# Valgrind suppression file updated to support the patched +# Valgrind used in daily builds on ahmed. + +{ + libc internal error + Memcheck:Addr8 + obj:/lib64/ld-2.3.5.so +} +{ + libc internal error + Memcheck:Addr8 + fun:_dl_start +} +{ + libc internal error + Memcheck:Addr8 + fun:__libc_start_main + obj:* +} +{ + libc internal error + Memcheck:Addr4 + fun:__sigjmp_save + fun:__libc_start_main + obj:* +} +{ + libc internal error + Memcheck:Addr8 + fun:__sigsetjmp + fun:__libc_start_main + obj:* +} +{ + Intentional error in testcase + Memcheck:Param + pipe(filedes) + fun:pipe + fun:chkio_drv_timeout +} +{ + Intentional error in testcase + Memcheck:Param + pipe(filedes) + fun:pipe + fun:io_ready_exit_drv_control + fun:erts_port_control + fun:port_control_3 + fun:process_main +} +{ + Leak in libc putenv + Memcheck:Leak + fun:malloc + fun:realloc + fun:__add_to_environ + fun:putenv + fun:erts_sys_putenv + fun:os_putenv_2 + fun:process_main +} +{ +Leak in libc putenv +Memcheck:Leak +fun:malloc +fun:erts_sys_alloc +... +fun:erts_alloc +fun:erts_sys_putenv +fun:os_putenv_2 +fun:process_main +} +{ + erronous warning + Memcheck:Leak + fun:malloc + fun:erts_sys_alloc + ... + fun:fix_core_alloc + fun:erts_init_fix_alloc + fun:erts_alloc_init + fun:early_init + fun:erl_start +} +{ + pthread internal error + Memcheck:Param + futex(utime) + fun:__lll_mutex_unlock_wake +} +{ + libc internal error + Memcheck:Param + socketcall.sendto(msg) + ... + fun:getifaddrs +} +{ +inet_drv; pointer inside allocated block +Memcheck:Leak +PossiblyLost +fun:realloc +fun:erts_sys_realloc +... +fun:erts_realloc_fnf +fun:erts_bin_realloc_fnf +fun:driver_realloc_binary +} +{ +inet_drv; pointer inside allocated block +Memcheck:Leak +PossiblyLost +fun:malloc +fun:erts_sys_alloc +... +fun:erts_alloc_fnf +fun:erts_bin_drv_alloc_fnf +fun:driver_alloc_binary +} +{ +pthread leak or erroneous valgrind warning +Memcheck:Leak +fun:calloc +fun:allocate_dtv +fun:_dl_allocate_tls +fun:pthread_create@@GLIBC_2.2.5 +} +{ +pthread leak or erroneous valgrind warning +Memcheck:Leak +fun:calloc +fun:_dl_allocate_tls +fun:pthread_create@@GLIBC_2.2.5 +} +{ +zlib; ok according to zlib developers +Memcheck:Cond +fun:longest_match +fun:deflate_slow +fun:deflate +} +{ +zlib; ok according to zlib developers +Memcheck:Cond +fun:longest_match +fun:deflate_fast +fun:deflate +} +{ +zlib; ok accordnig to zlib (this one popped up with valgrind-3.6.0) +Memcheck:Cond +fun:deflate_slow +fun:deflate +fun:zlib_deflate +fun:zlib_ctl +} +{ +No leak; pointer into block +Memcheck:Leak +fun:malloc +fun:erts_sys_alloc +... +fun:erts_alloc +fun:erts_init_scheduling +fun:erl_init +fun:erl_start +fun:main +} +{ +No leak; pointer into block +Memcheck:Leak +PossiblyLost +fun:malloc +fun:erts_sys_alloc +... +fun:erts_alloc +fun:init_db +fun:erl_init +fun:erl_start +fun:main +} +{ +No leak; sometimes pointer into block +Memcheck:Leak +PossiblyLost +fun:malloc +fun:erts_sys_alloc +... +fun:erts_alloc_fnf +fun:driver_alloc +fun:get_bufstk +fun:alloc_buffer +} +{ + Crypto internal... +Memcheck:Cond +obj:*/crypto.valgrind.* +} +{ + Crypto internal... +Memcheck:Cond +obj:*/libcrypto.* +} +{ + Crypto internal... +Memcheck:Cond +obj:*/openssl.* +} +{ + Crypto internal... +Memcheck:Cond +obj:*/ssleay.* +} +{ + Crypto internal... +Memcheck:Value8 +obj:*/crypto.valgrind.* +} +{ + Crypto internal... +Memcheck:Value8 +obj:*/libcrypto.* +} +{ + Crypto internal... +Memcheck:Value8 +obj:*/openssl.* +} +{ + Crypto internal... +Memcheck:Value8 +obj:*/ssleay.* +} +{ + Crypto internal... + Memcheck:Cond + fun:memset + fun:BN_lshift + fun:BN_div + fun:BN_MONT_CTX_set + fun:BN_is_prime_fasttest_ex + fun:BN_generate_prime_ex + fun:DH_generate_parameters_ex + fun:DH_generate_parameters + fun:dh_generate_parameters_nif + fun:process_main + fun:sched_thread_func + fun:thr_wrapper +} +{ + Crypto internal... + Memcheck:Cond + fun:memset + fun:BN_lshift + fun:BN_div + fun:BN_nnmod + fun:BN_mod_inverse + fun:BN_MONT_CTX_set + fun:BN_is_prime_fasttest_ex + fun:BN_generate_prime_ex + fun:DH_generate_parameters_ex + fun:DH_generate_parameters + fun:dh_generate_parameters_nif + fun:process_main +} +{ + Crypto internal... + Memcheck:Value8 + fun:BN_mod_exp_mont_consttime + fun:generate_key + fun:dh_generate_key_nif + fun:process_main + fun:sched_thread_func + fun:thr_wrapper + fun:start_thread + fun:clone +} + +{ +erts_bits_init_state; Why is this needed? +Memcheck:Leak +PossiblyLost +fun:malloc +fun:erts_sys_alloc +... +fun:erts_alloc +fun:erts_bits_init_state +fun:erts_init_scheduling +fun:erl_init +fun:erl_start +fun:main +} + +{ +Prebuilt constant terms in os_info_init +Memcheck:Leak +PossiblyLost +fun:malloc +fun:erts_sys_alloc +... +fun:erts_alloc +fun:os_info_init +fun:erts_bif_info_init +fun:erl_init +fun:erl_start +fun:main +} diff --git a/erts/emulator/valgrind/suppress.standard b/erts/emulator/valgrind/suppress.standard new file mode 100644 index 0000000000..d759038c97 --- /dev/null +++ b/erts/emulator/valgrind/suppress.standard @@ -0,0 +1,268 @@ +{ + libc internal error + Memcheck:Addr8 + obj:/lib64/ld-2.3.5.so +} +{ + libc internal error + Memcheck:Addr8 + fun:_dl_start +} +{ + libc internal error + Memcheck:Addr8 + fun:__libc_start_main + obj:* +} +{ + libc internal error + Memcheck:Addr4 + fun:__sigjmp_save + fun:__libc_start_main + obj:* +} +{ + libc internal error + Memcheck:Addr8 + fun:__sigsetjmp + fun:__libc_start_main + obj:* +} +{ + Intentional error in testcase + Memcheck:Param + pipe(filedes) + fun:pipe + fun:chkio_drv_timeout +} +{ + Intentional error in testcase + Memcheck:Param + pipe(filedes) + fun:pipe + fun:io_ready_exit_drv_control + fun:erts_port_control + fun:port_control_3 + fun:process_main +} +{ + Leak in libc putenv + Memcheck:Leak + fun:malloc + fun:realloc + fun:__add_to_environ + fun:putenv + fun:erts_sys_putenv + fun:os_putenv_2 + fun:process_main +} +{ +Leak in libc putenv +Memcheck:Leak +fun:malloc +fun:erts_sys_alloc +... +fun:erts_alloc +fun:erts_sys_putenv +fun:os_putenv_2 +fun:process_main +} +{ + erronous warning + Memcheck:Leak + fun:malloc + fun:erts_sys_alloc + fun:fix_core_alloc + fun:erts_init_fix_alloc + fun:erts_alloc_init + fun:early_init + fun:erl_start +} +{ + pthread internal error + Memcheck:Param + futex(utime) + fun:__lll_mutex_unlock_wake +} +{ + libc internal error + Memcheck:Param + socketcall.sendto(msg) + ... + fun:getifaddrs +} +{ +inet_drv; pointer inside allocated block +Memcheck:Leak +fun:realloc +fun:erts_sys_realloc +... +fun:erts_realloc_fnf +fun:erts_bin_realloc_fnf +fun:driver_realloc_binary +} +{ +inet_drv; pointer inside allocated block +Memcheck:Leak +fun:malloc +fun:erts_sys_alloc +... +fun:erts_alloc_fnf +fun:erts_bin_drv_alloc_fnf +fun:driver_alloc_binary +} +{ +pthread leak or erroneous valgrind warning +Memcheck:Leak +fun:calloc +fun:allocate_dtv +fun:_dl_allocate_tls +fun:pthread_create@@GLIBC_2.2.5 +} +{ +zlib; ok according to zlib developers +Memcheck:Cond +fun:longest_match +fun:deflate_slow +fun:deflate +} +{ +zlib; ok according to zlib developers +Memcheck:Cond +fun:longest_match +fun:deflate_fast +fun:deflate +} +{ +No leak; pointer into block +Memcheck:Leak +fun:malloc +fun:erts_sys_alloc +... +fun:erts_alloc +fun:erts_init_scheduling +fun:erl_init +fun:erl_start +fun:main +} +{ +No leak; pointer into block +Memcheck:Leak +fun:malloc +fun:erts_sys_alloc +... +fun:erts_alloc +fun:init_db +fun:erl_init +fun:erl_start +fun:main +} +{ +No leak; sometimes pointer into block +Memcheck:Leak +fun:malloc +fun:erts_sys_alloc +... +fun:erts_alloc_fnf +fun:driver_alloc +fun:get_bufstk +fun:alloc_buffer +} +{ + Crypto internal... +Memcheck:Cond +obj:*/crypto.valgrind.* +} +{ + Crypto internal... +Memcheck:Cond +obj:*/libcrypto.* +} +{ + Crypto internal... +Memcheck:Cond +obj:*/openssl.* +} +{ + Crypto internal... +Memcheck:Cond +obj:*/ssleay.* +} +{ + Crypto internal... +Memcheck:Value8 +obj:*/crypto.valgrind.* +} +{ + Crypto internal... +Memcheck:Value8 +obj:*/libcrypto.* +} +{ + Crypto internal... +Memcheck:Value8 +obj:*/openssl.* +} +{ + Crypto internal... +Memcheck:Value8 +obj:*/ssleay.* +} +{ + Crypto internal... + Memcheck:Cond + fun:memset + fun:BN_lshift + fun:BN_div + fun:BN_MONT_CTX_set + fun:BN_is_prime_fasttest_ex + fun:BN_generate_prime_ex + fun:DH_generate_parameters_ex + fun:DH_generate_parameters + fun:dh_generate_parameters_nif + fun:process_main + fun:sched_thread_func + fun:thr_wrapper +} +{ + Crypto internal... + Memcheck:Cond + fun:memset + fun:BN_lshift + fun:BN_div + fun:BN_nnmod + fun:BN_mod_inverse + fun:BN_MONT_CTX_set + fun:BN_is_prime_fasttest_ex + fun:BN_generate_prime_ex + fun:DH_generate_parameters_ex + fun:DH_generate_parameters + fun:dh_generate_parameters_nif + fun:process_main +} +{ + Crypto internal... + Memcheck:Value8 + fun:BN_mod_exp_mont_consttime + fun:generate_key + fun:dh_generate_key_nif + fun:process_main + fun:sched_thread_func + fun:thr_wrapper + fun:start_thread + fun:clone +} + +{ +Prebuilt constant terms in os_info_init (PossiblyLost) +Memcheck:Leak +fun:malloc +fun:erts_sys_alloc +... +fun:erts_alloc +fun:os_info_init +fun:erts_bif_info_init +fun:erl_init +fun:erl_start +fun:main +} diff --git a/lib/diameter/src/base/diameter.appup.src b/lib/diameter/src/base/diameter.appup.src index 6d8ceadb92..b1c94d4cc8 100644 --- a/lib/diameter/src/base/diameter.appup.src +++ b/lib/diameter/src/base/diameter.appup.src @@ -20,28 +20,11 @@ {"%VSN%", [ - {"0.9", - [ - {load_module, diameter, soft_purge, soft_purge, []}, - {load_module, diameter_capx, soft_purge, soft_purge, []}, - {load_module, diameter_codec, soft_purge, soft_purge, [diameter_lib]}, - {load_module, diameter_lib, soft_purge, soft_purge, []}, - {load_module, diameter_types, soft_purge, soft_purge, []}, - {load_module, diameter_gen_base_accounting, soft_purge, soft_purge, []}, - {load_module, diameter_gen_base_rfc3588, soft_purge, soft_purge, []}, - {load_module, diameter_gen_relay, soft_purge, soft_purge, []}, - {update, diameter_service, soft, soft_purge, soft_purge, [diameter_lib]}, - {update, diameter_config, soft, soft_purge, soft_purge, []}, - {update, diameter_peer, soft, soft_purge, soft_purge, []}, - {update, diameter_peer_fsm, soft, soft_purge, soft_purge, [diameter_lib]}, - {update, diameter_reg, soft, soft_purge, soft_purge, []}, - {update, diameter_sctp, soft, soft_purge, soft_purge, []}, - {update, diameter_stats, soft, soft_purge, soft_purge, []}, - {update, diameter_sync, soft, soft_purge, soft_purge, []}, - {update, diameter_watchdog, soft, soft_purge, soft_purge, [diameter_lib]} - ] - } + {"0.9", [{restart_application, diameter}]}, + {"0.10", [{restart_application, diameter}]} ], [ + {"0.9", [{restart_application, diameter}]}, + {"0.10", [{restart_application, diameter}]} ] }. diff --git a/lib/diameter/test/diameter_app_SUITE.erl b/lib/diameter/test/diameter_app_SUITE.erl index d5ecdea291..7f53a4ddd4 100644 --- a/lib/diameter/test/diameter_app_SUITE.erl +++ b/lib/diameter/test/diameter_app_SUITE.erl @@ -134,13 +134,16 @@ release(Config) -> Rel = {release, {"diameter test release", fetch(vsn, App)}, {erts, erlang:system_info(version)}, - [{A, appvsn(A)} || A <- fetch(applications, App)]}, + [{A, appvsn(A)} || A <- [sasl | fetch(applications, App)]]}, Dir = fetch(priv_dir, Config), ok = write_file(filename:join([Dir, "diameter_test.rel"]), Rel), {ok, _, []} = systools:make_script("diameter_test", [{path, [Dir]}, {outdir, Dir}, silent]). +%% sasl need to be included to avoid a missing_sasl warning, error +%% in the case of relup/1. + appvsn(Name) -> [{application, Name, App}] = diameter_util:consult(Name, app), fetch(vsn, App). @@ -208,7 +211,7 @@ relup(Config) -> App = fetch(app, Config), Rel = [{erts, erlang:system_info(version)} - | [{A, appvsn(A)} || A <- fetch(applications, App)]], + | [{A, appvsn(A)} || A <- [sasl | fetch(applications, App)]]], Dir = fetch(priv_dir, Config), @@ -216,12 +219,15 @@ relup(Config) -> UpFrom = acc_rel(Dir, Rel, Up), DownTo = acc_rel(Dir, Rel, Down), - {[Name], [Name], UpFrom, DownTo} %% no intersections + {[Name], [Name], [], []} %% no current in up/down and go both ways = {[Name] -- UpFrom, [Name] -- DownTo, UpFrom -- DownTo, DownTo -- UpFrom}, + [[], []] = [S -- sets:to_list(sets:from_list(S)) + || S <- [UpFrom, DownTo]], + {ok, _, _, []} = systools:make_relup(Name, UpFrom, DownTo, [{path, [Dir]}, {outdir, Dir}, silent]). diff --git a/lib/diameter/vsn.mk b/lib/diameter/vsn.mk index c783450c9f..b1d3ba2241 100644 --- a/lib/diameter/vsn.mk +++ b/lib/diameter/vsn.mk @@ -18,7 +18,7 @@ # %CopyrightEnd% APPLICATION = diameter -DIAMETER_VSN = 0.10 +DIAMETER_VSN = 0.11 PRE_VSN = APP_VSN = "$(APPLICATION)-$(DIAMETER_VSN)$(PRE_VSN)" diff --git a/lib/kernel/doc/src/net_kernel.xml b/lib/kernel/doc/src/net_kernel.xml index 3b7a710664..e54a427ff0 100644 --- a/lib/kernel/doc/src/net_kernel.xml +++ b/lib/kernel/doc/src/net_kernel.xml @@ -210,6 +210,10 @@ <p><c>net_kernel</c> is currently changing <c>net_ticktime</c> to <c><anno>NetTicktime</anno></c> seconds.</p> </item> + <tag><c>ignored</c></tag> + <item> + <p>The local node is not alive.</p> + </item> </taglist> </desc> </func> diff --git a/lib/stdlib/doc/src/supervisor.xml b/lib/stdlib/doc/src/supervisor.xml index 30514dfee9..cddb55e5c5 100644 --- a/lib/stdlib/doc/src/supervisor.xml +++ b/lib/stdlib/doc/src/supervisor.xml @@ -158,7 +158,7 @@ child_spec() = {Id,StartFunc,Restart,Shutdown,Type,Modules} death causes the temporary process to be terminated) and a <c>transient</c> child process should be restarted only if it terminates abnormally, i.e. with another exit reason - than <c>normal</c>.</p> + than <c>normal</c>, <c>shutdown</c> or <c>{shutdown,Term}</c>.</p> </item> <item> <p><c>Shutdown</c> defines how a child process should be @@ -355,14 +355,23 @@ child_spec() = {Id,StartFunc,Restart,Shutdown,Type,Modules} <desc> <p>Tells the supervisor <c><anno>SupRef</anno></c> to terminate the given child.</p> + <p>If the supervisor is not <c>simple_one_for_one</c>, - <c><anno>Id</anno></c> must be the child specification identifier. The - process, if there is one, is terminated but the child - specification is kept by the supervisor. The child process - may later be restarted by the supervisor. The child process - can also be restarted explicitly by calling + <c><anno>Id</anno></c> must be the child specification + identifier. The process, if there is one, is terminated and, + unless it is a temporary child, the child specification is + kept by the supervisor. The child process may later be + restarted by the supervisor. The child process can also be + restarted explicitly by calling <c>restart_child/2</c>. Use <c>delete_child/2</c> to remove the child specification.</p> + + <p>If the child is temporary, the child specification is deleted as + soon as the process terminates. This means + that <c>delete_child/2</c> has no meaning + and <c>restart_child/2</c> can not be used for these + children.</p> + <p>If the supervisor is <c>simple_one_for_one</c>, <c><anno>Id</anno></c> must be the child process' <c>pid()</c>. I the specified process is alive, but is not a child of the given @@ -399,26 +408,34 @@ child_spec() = {Id,StartFunc,Restart,Shutdown,Type,Modules} <name name="restart_child" arity="2"/> <fsummary>Restart a terminated child process belonging to a supervisor.</fsummary> <desc> - <p>Tells the supervisor <c><anno>SupRef</anno></c> to restart a child process - corresponding to the child specification identified by - <c><anno>Id</anno></c>. The child specification must exist and - the corresponding child process must not be running.</p> - <p>See <seealso marker="#SupRef"><c>start_child/2</c></seealso> for a description of - <c>SupRef</c>.</p> - <p>If the child specification identified by <c><anno>Id</anno></c> does not - exist, the function returns <c>{error,not_found}</c>. If - the child specification exists but the corresponding process - is already running, the function returns + <p>Tells the supervisor <c><anno>SupRef</anno></c> to restart + a child process corresponding to the child specification + identified by <c><anno>Id</anno></c>. The child + specification must exist and the corresponding child process + must not be running.</p> + <p>Note that for temporary children, the child specification + is automatically deleted when the child terminates, and thus + it is not possible to restart such children.</p> + <p>See <seealso marker="#SupRef"><c>start_child/2</c></seealso> + for a description of <c>SupRef</c>.</p> + <p>If the child specification identified + by <c><anno>Id</anno></c> does not exist, the function + returns <c>{error,not_found}</c>. If the child specification + exists but the corresponding process is already running, the + function returns <c>{error,running}</c>.</p> - <p>If the child process start function returns <c>{ok,<anno>Child</anno>}</c> - or <c>{ok,<anno>Child</anno>,<anno>Info</anno>}</c>, the pid is added to the supervisor - and the function returns the same value.</p> + <p>If the child process start function + returns <c>{ok,<anno>Child</anno>}</c> + or <c>{ok,<anno>Child</anno>,<anno>Info</anno>}</c>, the pid + is added to the supervisor and the function returns the same + value.</p> <p>If the child process start function returns <c>ignore</c>, the pid remains set to <c>undefined</c> and the function returns <c>{ok,undefined}</c>.</p> - <p>If the child process start function returns an error tuple or - an erroneous value, or if it fails, the function returns - <c>{error,<anno>Error</anno>}</c> where <c><anno>Error</anno></c> is a term containing + <p>If the child process start function returns an error tuple + or an erroneous value, or if it fails, the function returns + <c>{error,<anno>Error</anno>}</c> + where <c><anno>Error</anno></c> is a term containing information about the error.</p> </desc> </func> diff --git a/system/doc/design_principles/sup_princ.xml b/system/doc/design_principles/sup_princ.xml index a432f9458b..5b8fd604c8 100644 --- a/system/doc/design_principles/sup_princ.xml +++ b/system/doc/design_principles/sup_princ.xml @@ -160,10 +160,13 @@ init(...) -> be restarted.</p> <list type="bulleted"> <item>A <c>permanent</c> child process is always restarted.</item> - <item>A <c>temporary</c> child process is never restarted.</item> + <item>A <c>temporary</c> child process is never restarted + (not even when the supervisor's restart strategy + is <c>rest_for_one</c> or <c>one_for_all</c> and a sibling's + death causes the temporary process to be terminated).</item> <item>A <c>transient</c> child process is restarted only if it terminates abnormally, i.e. with another exit reason than - <c>normal</c>.</item> + <c>normal</c>, <c>shutdown</c> or <c>{shutdown,Term}</c>.</item> </list> </item> <item> |