diff options
Diffstat (limited to 'erts/emulator')
78 files changed, 4620 insertions, 1510 deletions
diff --git a/erts/emulator/Makefile.in b/erts/emulator/Makefile.in index a2061134a5..a81ab28847 100644 --- a/erts/emulator/Makefile.in +++ b/erts/emulator/Makefile.in @@ -1,24 +1,25 @@ # # %CopyrightBegin% -# -# Copyright Ericsson AB 1996-2009. All Rights Reserved. -# +# +# Copyright Ericsson AB 1996-2010. 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% # include $(ERL_TOP)/make/target.mk include ../vsn.mk +include $(ERL_TOP)/make/$(TARGET)/otp.mk ENABLE_ALLOC_TYPE_VARS = @ENABLE_ALLOC_TYPE_VARS@ HIPE_ENABLED=@HIPE_ENABLED@ @@ -166,6 +167,9 @@ ifeq ($(OPSYS),linux) ppcBEAMLDFLAGS=-Wl,-m,elf32ppc ppc64BEAMLDFLAGS=-Wl,-m,elf64ppc,-T,hipe/elf64ppc.x endif +ifeq ($(OPSYS),darwin) +amd64BEAMLDFLAGS=-pagezero_size 0x10000000 +endif HIPEBEAMLDFLAGS=$($(ARCH)BEAMLDFLAGS) endif @@ -213,7 +217,7 @@ else OPT_LEVEL = -O3 endif -ifeq ($(CC), gcc) +ifeq ($(GCC),yes) ifeq ($(NO_INLINE_FUNCTIONS),true) GEN_OPT_FLGS = $(OPT_LEVEL) -fno-inline-functions else @@ -252,7 +256,7 @@ CS_TYPE_FLAGS = $(subst QUANTIFY,FAKE_QUANTIFY, \ $(subst PURIFY,FAKE_PURIFY, $(TYPE_FLAGS))) endif CS_CFLAGS_ = $(CS_TYPE_FLAGS) @DEFS@ $(WFLAGS) -ifeq ($(CC), gcc) +ifeq ($(GCC),yes) CS_CFLAGS = $(subst -O2, $(GEN_OPT_FLGS) $(UNROLL_FLG), $(CS_CFLAGS_)) else CS_CFLAGS = $(CS_CFLAGS_) @@ -351,7 +355,6 @@ endif CS_EXECUTABLE = child_setup$(TYPEMARKER) # ---------------------------------------------------------------------- -include $(ERL_TOP)/make/$(TARGET)/otp.mk ifeq ($(ERLANG_OSTYPE), unix) UNIX_ONLY_BUILDS = $(BINDIR)/$(CS_EXECUTABLE) @@ -402,7 +405,7 @@ endif $(RM) -f $(TARGET)/*/*/*.c $(TARGET)/*/*/*.h $(TARGET)/*/*/*.S $(RM) -f $(ERL_TOP)/erts/emulator/obj/$(TARGET)/*/*/*.o $(RM) -f $(BINDIR)/beam $(BINDIR)/beam.* - $(RM) -f $(BINDIR)/child_setup $(BINDIR)/child_setup.* + $(RM) -rf $(BINDIR)/child_setup $(BINDIR)/child_setup.* $(RM) -f $(BINDIR)/hipe_mkliterals $(BINDIR)/hipe_mkliterals.* @set -e ; cd zlib && $(MAKE) clean @set -e ; cd pcre && $(MAKE) clean @@ -416,7 +419,7 @@ include $(ERL_TOP)/make/otp_release_targets.mk RELSYSDIR = $(RELEASE_PATH)/erts-$(VSN) -RELEASE_INCLUDES = beam/erl_driver.h sys/$(ERLANG_OSTYPE)/driver_int.h beam/erl_nif.h beam/erl_nif_api_funcs.h +RELEASE_INCLUDES = beam/erl_driver.h sys/$(ERLANG_OSTYPE)/driver_int.h beam/erl_nif.h beam/erl_nif_api_funcs.h beam/erl_drv_nif.h ifeq ($(TARGET),win32) RELEASE_INCLUDES += sys/$(ERLANG_OSTYPE)/erl_win_dyn_driver.h endif @@ -606,7 +609,7 @@ endif ifneq ($(filter tile-%,$(TARGET)),) $(OBJDIR)/beam_emu.o: beam/beam_emu.c - $(CC) $(subst -O2, $(GEN_OPT_FLGS), $(CFLAGS)) \ + $(CC) $(subst -O2, $(GEN_OPT_FLGS), $(CFLAGS)) \ -OPT:Olimit=0 -WOPT:lpre=off:spre=off:epre=off \ $(INCLUDES) -c $< -o $@ endif @@ -692,7 +695,7 @@ $(OBJDIR)/%.kp.o: sys/common/%.c $(OBJDIR)/%.nkp.o: sys/common/%.c $(CC) -DERTS_NO_KERNEL_POLL_VERSION $(subst -O2, $(GEN_OPT_FLGS), $(CFLAGS)) $(INCLUDES) -c $< -o $@ -ifeq ($(CC), gcc) +ifeq ($(GCC),yes) $(OBJDIR)/erl_obsolete.o: beam/erl_obsolete.c $(CC) $(subst -Wstrict-prototypes, , $(subst -O2, $(GEN_OPT_FLGS), $(CFLAGS))) $(INCLUDES) -c $< -o $@ @@ -1086,8 +1089,16 @@ DEP_FLAGS=-MM $(subst -O2,,$(CFLAGS)) $(INCLUDES) -I../etc/win32 -Idrivers/comm # SYS_SRC=$(subst sys/common/erl_poll.c,,$(ALL_SYS_SRC)) else # !win32 + +ifeq ($(findstring tile,$(TARGET)),tile) +# tile-gcc doesn't like -MG +MG_FLAG= +else +MG_FLAG=-MG +endif + DEP_CC=$(CC) -DEP_FLAGS=-MM -MG $(CFLAGS) $(INCLUDES) -Idrivers/common +DEP_FLAGS=-MM $(MG_FLAG) $(CFLAGS) $(INCLUDES) -Idrivers/common SYS_SRC=$(ALL_SYS_SRC) endif diff --git a/erts/emulator/beam/atom.c b/erts/emulator/beam/atom.c index dfc3cde6a7..e2a79d6e4f 100644 --- a/erts/emulator/beam/atom.c +++ b/erts/emulator/beam/atom.c @@ -1,19 +1,19 @@ /* * %CopyrightBegin% - * - * Copyright Ericsson AB 1996-2009. All Rights Reserved. - * + * + * Copyright Ericsson AB 1996-2010. 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% */ @@ -322,7 +322,7 @@ init_atom_table(void) text_list = NULL; erts_index_init(ERTS_ALC_T_ATOM_TABLE, &erts_atom_table, - "atom_tab", ATOM_SIZE, ATOM_LIMIT, f); + "atom_tab", ATOM_SIZE, erts_atom_table_size, f); more_atom_space(); /* Ordinary atoms */ diff --git a/erts/emulator/beam/atom.h b/erts/emulator/beam/atom.h index e7e0dc440d..cb245a87b1 100644 --- a/erts/emulator/beam/atom.h +++ b/erts/emulator/beam/atom.h @@ -1,19 +1,19 @@ /* * %CopyrightBegin% - * - * Copyright Ericsson AB 1996-2009. All Rights Reserved. - * + * + * Copyright Ericsson AB 1996-2010. 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% */ @@ -28,6 +28,17 @@ #define MAX_ATOM_LENGTH 255 #define ATOM_LIMIT (1024*1024) +#define MIN_ATOM_TABLE_SIZE 8192 + +#ifndef ARCH_32 +/* Internal atom cache needs MAX_ATOM_TABLE_SIZE to be less than an + unsigned 32 bit integer. See external.c(erts_encode_ext_dist_header_setup) + for more details. */ +#define MAX_ATOM_TABLE_SIZE ((MAX_ATOM_INDEX + 1 < (1UL << 32)) ? MAX_ATOM_INDEX + 1 : (1UL << 32)) +#else +#define MAX_ATOM_TABLE_SIZE (MAX_ATOM_INDEX + 1) +#endif + /* * Atom entry. diff --git a/erts/emulator/beam/atom.names b/erts/emulator/beam/atom.names index 04eac2d807..57c8b08223 100644 --- a/erts/emulator/beam/atom.names +++ b/erts/emulator/beam/atom.names @@ -1,19 +1,19 @@ # # %CopyrightBegin% -# -# Copyright Ericsson AB 1996-2009. All Rights Reserved. -# +# +# Copyright Ericsson AB 1996-2010. 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% # @@ -303,6 +303,7 @@ atom messages atom meta atom meta_match_spec atom min_heap_size +atom min_bin_vheap_size atom minor_version atom Minus='-' atom module @@ -446,6 +447,7 @@ atom running atom running_ports atom running_procs atom runtime +atom safe atom save_calls atom scheduler atom scheduler_id diff --git a/erts/emulator/beam/beam_bif_load.c b/erts/emulator/beam/beam_bif_load.c index d3a1ed4e7d..b1feec7074 100644 --- a/erts/emulator/beam/beam_bif_load.c +++ b/erts/emulator/beam/beam_bif_load.c @@ -1,19 +1,19 @@ /* * %CopyrightBegin% - * - * Copyright Ericsson AB 1999-2009. All Rights Reserved. - * + * + * Copyright Ericsson AB 1999-2010. 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% */ @@ -642,21 +642,9 @@ purge_module(int module) /* * Unload any NIF library */ - if (modp->old_nif.handle != NULL) { - if (modp->old_nif.entry->unload != NULL) { - ErlNifEnv env; - env.nif_data = modp->old_nif.data; - env.proc = NULL; /* BUGBUG: unlink can not access calling process */ - env.hp = NULL; - env.hp_end = NULL; - env.heap_frag_sz = 0; - env.fpe_was_unmasked = erts_block_fpe(); - modp->old_nif.entry->unload(NULL, modp->old_nif.data); - erts_unblock_fpe(env.fpe_was_unmasked); - } - erts_sys_ddll_close(modp->old_nif.handle); - modp->old_nif.handle = NULL; - modp->old_nif.entry = NULL; + if (modp->old_nif != NULL) { + erts_unload_nif(modp->old_nif); + modp->old_nif = NULL; } /* @@ -732,8 +720,7 @@ delete_code(Process *c_p, ErtsProcLocks c_p_locks, Module* modp) modp->code = NULL; modp->code_length = 0; modp->catches = BEAM_CATCHES_NIL; - modp->nif.handle = NULL; - modp->nif.entry = NULL; + modp->nif = NULL; } diff --git a/erts/emulator/beam/beam_emu.c b/erts/emulator/beam/beam_emu.c index dcaa43b51c..2f7f48193d 100644 --- a/erts/emulator/beam/beam_emu.c +++ b/erts/emulator/beam/beam_emu.c @@ -1,19 +1,19 @@ /* * %CopyrightBegin% - * - * Copyright Ericsson AB 1996-2009. All Rights Reserved. - * + * + * Copyright Ericsson AB 1996-2010. 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% */ @@ -286,6 +286,15 @@ extern int count_instructions; #endif +#ifdef FORCE_HEAP_FRAGS +# define HEAP_SPACE_VERIFIED(Words) do { \ + c_p->space_verified = (Words); \ + c_p->space_verified_from = HTOP; \ + }while(0) +#else +# define HEAP_SPACE_VERIFIED(Words) ((void)0) +#endif + #define PRE_BIF_SWAPOUT(P) \ HEAP_TOP((P)) = HTOP; \ (P)->stop = E; \ @@ -411,6 +420,7 @@ extern int count_instructions; r(0) = reg[0]; \ SWAPIN; \ } \ + HEAP_SPACE_VERIFIED(need); \ } while (0) @@ -432,6 +442,7 @@ extern int count_instructions; r(0) = reg[0]; \ SWAPIN; \ } \ + HEAP_SPACE_VERIFIED(need); \ } while (0) /* @@ -456,6 +467,7 @@ extern int count_instructions; Extra = reg[Live]; \ SWAPIN; \ } \ + HEAP_SPACE_VERIFIED(need); \ } while (0) #ifdef HYBRID @@ -832,6 +844,7 @@ extern int count_instructions; LIGHT_SWAPOUT; \ _result = erts_bs_get_float_2(c_p, _size, (Flags), _mb); \ LIGHT_SWAPIN; \ + HEAP_SPACE_VERIFIED(0); \ if (is_non_value(_result)) { Fail; } \ else { Store(_result, Dst); } \ } while (0) @@ -845,6 +858,7 @@ extern int count_instructions; LIGHT_SWAPOUT; \ _result = erts_bs_get_binary_2(c_p, (Sz), (Flags), _mb); \ LIGHT_SWAPIN; \ + HEAP_SPACE_VERIFIED(0); \ if (is_non_value(_result)) { Fail; } \ else { Store(_result, Dst); } \ } while (0) @@ -859,6 +873,7 @@ extern int count_instructions; LIGHT_SWAPOUT; \ _result = erts_bs_get_binary_2(c_p, _size, (Flags), _mb); \ LIGHT_SWAPIN; \ + HEAP_SPACE_VERIFIED(0); \ if (is_non_value(_result)) { Fail; } \ else { Store(_result, Dst); } \ } while (0) @@ -873,9 +888,12 @@ extern int count_instructions; LIGHT_SWAPOUT; \ _result = erts_bs_get_binary_all_2(c_p, _mb); \ LIGHT_SWAPIN; \ + HEAP_SPACE_VERIFIED(0); \ ASSERT(is_value(_result)); \ Store(_result, Dst); \ - } else { Fail; } \ + } else { \ + HEAP_SPACE_VERIFIED(0); \ + Fail; } \ } while (0) #define BsSkipBits2(Ms, Bits, Unit, Fail) \ @@ -974,10 +992,6 @@ static int hibernate(Process* c_p, Eterm module, Eterm function, static Eterm* call_fun(Process* p, int arity, Eterm* reg, Eterm args); static Eterm* apply_fun(Process* p, Eterm fun, Eterm args, Eterm* reg); static Eterm new_fun(Process* p, Eterm* reg, ErlFunEntry* fe, int num_free); -static BIF_RETTYPE nif_dispatcher_0(Process* p, Uint* I); -static BIF_RETTYPE nif_dispatcher_1(Process* p, Eterm arg1, Uint* I); -static BIF_RETTYPE nif_dispatcher_2(Process* p, Eterm arg1, Eterm arg2, Uint* I); -static BIF_RETTYPE nif_dispatcher_3(Process* p, Eterm arg1, Eterm arg2, Eterm arg3, Uint* I); #if defined(_OSE_) || defined(VXWORKS) static int init_done; @@ -1364,6 +1378,7 @@ void process_main(void) */ c_p->cp = 0; CHECK_TERM(r(0)); + HEAP_SPACE_VERIFIED(0); Goto(*I); } @@ -2383,6 +2398,7 @@ void process_main(void) if (is_big(tmp_arg1)) { HTOP += bignum_header_arity(*HTOP) + 1; } + HEAP_SPACE_VERIFIED(0); if (is_nil(tmp_arg1)) { /* * This result must have been only slight larger @@ -2949,11 +2965,38 @@ void process_main(void) OpCase(call_nif): { - static void* const dispatchers[4] = { - nif_dispatcher_0, nif_dispatcher_1, nif_dispatcher_2, nif_dispatcher_3 - }; - BifFunction vbf = dispatchers[I[-1]]; - goto apply_bif_or_nif; + /* + * call_nif is always first instruction in function: + * + * I[-3]: Module + * I[-2]: Function + * I[-1]: Arity + * I[0]: &&call_nif + * I[1]: Function pointer to NIF function + * I[2]: Pointer to erl_module_nif + */ + BifFunction vbf; + + c_p->current = I-3; /* current and vbf set to please handle_error */ + SWAPOUT; + c_p->fcalls = FCALLS - 1; + PROCESS_MAIN_CHK_LOCKS(c_p); + tmp_arg2 = I[-1]; + ERTS_SMP_UNREQ_PROC_MAIN_LOCK(c_p); + + ASSERT(!ERTS_PROC_IS_EXITING(c_p)); + { + typedef Eterm NifF(struct enif_environment_t*, int argc, Eterm argv[]); + NifF* fp = vbf = (NifF*) I[1]; + struct enif_environment_t env; + erts_pre_nif(&env, c_p, (struct erl_module_nif*)I[2]); + reg[0] = r(0); + tmp_arg1 = (*fp)(&env, tmp_arg2, reg); + erts_post_nif(&env); + } + ASSERT(!ERTS_PROC_IS_EXITING(c_p) || is_non_value(tmp_arg1)); + PROCESS_MAIN_CHK_LOCKS(c_p); + goto apply_bif_or_nif_epilogue; OpCase(apply_bif): /* @@ -2966,17 +3009,15 @@ void process_main(void) * code[3]: &&apply_bif * code[4]: Function pointer to BIF function */ - vbf = (BifFunction) Arg(0); - apply_bif_or_nif: c_p->current = I-3; /* In case we apply process_info/1,2 or load_nif/1 */ c_p->i = I; /* In case we apply check_process_code/2. */ c_p->arity = 0; /* To allow garbage collection on ourselves * (check_process_code/2). */ - SWAPOUT; c_p->fcalls = FCALLS - 1; + vbf = (BifFunction) Arg(0); PROCESS_MAIN_CHK_LOCKS(c_p); tmp_arg2 = I[-1]; ASSERT(tmp_arg2 <= 3); @@ -3019,6 +3060,7 @@ void process_main(void) break; } } +apply_bif_or_nif_epilogue: ERTS_SMP_REQ_PROC_MAIN_LOCK(c_p); ERTS_HOLE_CHECK(c_p); if (c_p->mbuf) { @@ -3203,6 +3245,7 @@ void process_main(void) sb->orig = new_binary; new_binary = make_binary(sb); } + HEAP_SPACE_VERIFIED(0); StoreBifResult(2, new_binary); } else { Binary* bptr; @@ -3690,6 +3733,7 @@ void process_main(void) *dst = *ms; *HTOP = HEADER_BIN_MATCHSTATE(slots); HTOP += wordsneeded; + HEAP_SPACE_VERIFIED(0); StoreResult(make_matchstate(dst), Arg(3)); } } else if (is_binary_header(header)) { @@ -3703,6 +3747,7 @@ void process_main(void) #endif result = erts_bs_start_match_2(c_p, tmp_arg1, slots); HTOP = HEAP_TOP(c_p); + HEAP_SPACE_VERIFIED(0); if (is_non_value(result)) { ClauseFail(); } else { @@ -3895,6 +3940,7 @@ void process_main(void) TestHeap(BIG_UINT_HEAP_SIZE, Arg(1)); _result = uint_to_big((Uint) _integer, HTOP); HTOP += BIG_UINT_HEAP_SIZE; + HEAP_SPACE_VERIFIED(0); } #endif StoreBifResult(2, _result); @@ -3960,6 +4006,7 @@ void process_main(void) LIGHT_SWAPOUT; result = erts_bs_get_integer_2(c_p, tmp_arg2, Arg(1), mb); LIGHT_SWAPIN; + HEAP_SPACE_VERIFIED(0); if (is_non_value(result)) { ClauseFail(); } @@ -3987,6 +4034,7 @@ void process_main(void) LIGHT_SWAPOUT; result = erts_bs_get_integer_2(c_p, size, flags, mb); LIGHT_SWAPIN; + HEAP_SPACE_VERIFIED(0); if (is_non_value(result)) { ClauseFail(); } @@ -5245,6 +5293,7 @@ save_stacktrace(Process* c_p, Eterm* pc, Eterm* reg, BifFunction bf, * The Bif does not really exist (no BIF entry). It is a * TRAP and traps are called through apply_bif, which also * sets c_p->current (luckily). + * OR it is a NIF called by call_nif where current is also set. */ ASSERT(c_p->current); s->current = c_p->current; @@ -6148,51 +6197,3 @@ erts_current_reductions(Process *current, Process *p) } } -static BIF_RETTYPE nif_dispatcher_0(Process* p, Uint* I) -{ - typedef Eterm NifF(struct enif_environment_t*); - NifF* fp = (NifF*) I[1]; - struct enif_environment_t env; - Eterm ret; - erts_pre_nif(&env, p, (void*)I[2]); - ret = (*fp)(&env); - erts_post_nif(&env); - return ret; -} - -static BIF_RETTYPE nif_dispatcher_1(Process* p, Eterm arg1, Uint* I) -{ - typedef Eterm NifF(struct enif_environment_t*, Eterm); - NifF* fp = (NifF*) I[1]; - struct enif_environment_t env; - Eterm ret; - erts_pre_nif(&env, p, (void*)I[2]); - ret = (*fp)(&env, arg1); - erts_post_nif(&env); - return ret; -} - -static BIF_RETTYPE nif_dispatcher_2(Process* p, Eterm arg1, Eterm arg2, Uint* I) -{ - typedef Eterm NifF(struct enif_environment_t*, Eterm, Eterm); - NifF* fp = (NifF*) I[1]; - struct enif_environment_t env; - Eterm ret; - erts_pre_nif(&env, p, (void*)I[2]); - ret = (*fp)(&env, arg1, arg2); - erts_post_nif(&env); - return ret; -} - -static BIF_RETTYPE nif_dispatcher_3(Process* p, Eterm arg1, Eterm arg2, Eterm arg3, Uint* I) -{ - typedef Eterm NifF(struct enif_environment_t*, Eterm, Eterm, Eterm); - NifF* fp = (NifF*) I[1]; - struct enif_environment_t env; - Eterm ret; - erts_pre_nif(&env, p, (void*)I[2]); - ret = (*fp)(&env, arg1, arg2, arg3); - erts_post_nif(&env); - return ret; -} - diff --git a/erts/emulator/beam/beam_load.c b/erts/emulator/beam/beam_load.c index 47dd98117d..99fab28dce 100644 --- a/erts/emulator/beam/beam_load.c +++ b/erts/emulator/beam/beam_load.c @@ -5090,6 +5090,7 @@ erts_make_stub_module(Process* p, Eterm Mod, Eterm Beam, Eterm Info) code[MI_COMPILE_PTR] = 0; code[MI_COMPILE_SIZE_ON_HEAP] = 0; code[MI_NUM_BREAKPOINTS] = 0; + code[MI_ON_LOAD_FUNCTION_PTR] = 0; ci = MI_FUNCTIONS + n + 1; /* diff --git a/erts/emulator/beam/bif.c b/erts/emulator/beam/bif.c index 74b231d56d..1b670585a7 100644 --- a/erts/emulator/beam/bif.c +++ b/erts/emulator/beam/bif.c @@ -1,19 +1,19 @@ /* * %CopyrightBegin% - * - * Copyright Ericsson AB 1996-2009. All Rights Reserved. - * + * + * Copyright Ericsson AB 1996-2010. 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% */ @@ -807,11 +807,12 @@ BIF_RETTYPE spawn_opt_1(BIF_ALIST_1) /* * Store default values for options. */ - so.flags = SPO_USE_ARGS; - so.min_heap_size = H_MIN_SIZE; - so.priority = PRIORITY_NORMAL; - so.max_gen_gcs = (Uint16) erts_smp_atomic_read(&erts_max_gen_gcs); - so.scheduler = 0; + so.flags = SPO_USE_ARGS; + so.min_heap_size = H_MIN_SIZE; + so.min_vheap_size = BIN_VH_MIN_SIZE; + so.priority = PRIORITY_NORMAL; + so.max_gen_gcs = (Uint16) erts_smp_atomic_read(&erts_max_gen_gcs); + so.scheduler = 0; /* * Walk through the option list. @@ -850,6 +851,15 @@ BIF_RETTYPE spawn_opt_1(BIF_ALIST_1) } else { so.min_heap_size = erts_next_heap_size(min_heap_size, 0); } + } else if (arg == am_min_bin_vheap_size && is_small(val)) { + Sint min_vheap_size = signed_val(val); + if (min_vheap_size < 0) { + goto error; + } else if (min_vheap_size < BIN_VH_MIN_SIZE) { + so.min_vheap_size = BIN_VH_MIN_SIZE; + } else { + so.min_vheap_size = erts_next_heap_size(min_vheap_size, 0); + } } else if (arg == am_fullsweep_after && is_small(val)) { Sint max_gen_gcs = signed_val(val); if (max_gen_gcs < 0) { @@ -1485,6 +1495,23 @@ BIF_RETTYPE process_flag_2(BIF_ALIST_2) } BIF_RET(old_value); } + else if (BIF_ARG_1 == am_min_bin_vheap_size) { + Sint i; + if (!is_small(BIF_ARG_2)) { + goto error; + } + i = signed_val(BIF_ARG_2); + if (i < 0) { + goto error; + } + old_value = make_small(BIF_P->min_vheap_size); + if (i < BIN_VH_MIN_SIZE) { + BIF_P->min_vheap_size = BIN_VH_MIN_SIZE; + } else { + BIF_P->min_vheap_size = erts_next_heap_size(i, 0); + } + BIF_RET(old_value); + } else if (BIF_ARG_1 == am_sensitive) { Uint is_sensitive; if (BIF_ARG_2 == am_true) { @@ -3736,10 +3763,35 @@ BIF_RETTYPE system_flag_2(BIF_ALIST_2) BIF_RET(make_small(oval)); } else if (BIF_ARG_1 == am_min_heap_size) { int oval = H_MIN_SIZE; + if (!is_small(BIF_ARG_2) || (n = signed_val(BIF_ARG_2)) < 0) { goto error; } + + erts_smp_proc_unlock(BIF_P, ERTS_PROC_LOCK_MAIN); + erts_smp_block_system(0); + H_MIN_SIZE = erts_next_heap_size(n, 0); + + erts_smp_release_system(); + erts_smp_proc_lock(BIF_P, ERTS_PROC_LOCK_MAIN); + + BIF_RET(make_small(oval)); + } else if (BIF_ARG_1 == am_min_bin_vheap_size) { + int oval = BIN_VH_MIN_SIZE; + + if (!is_small(BIF_ARG_2) || (n = signed_val(BIF_ARG_2)) < 0) { + goto error; + } + + erts_smp_proc_unlock(BIF_P, ERTS_PROC_LOCK_MAIN); + erts_smp_block_system(0); + + BIN_VH_MIN_SIZE = erts_next_heap_size(n, 0); + + erts_smp_release_system(); + erts_smp_proc_lock(BIF_P, ERTS_PROC_LOCK_MAIN); + BIF_RET(make_small(oval)); } else if (BIF_ARG_1 == am_display_items) { int oval = display_items; @@ -4091,6 +4143,7 @@ BIF_RETTYPE blocking_read_file_1(BIF_ALIST_1) FILE *file; struct stat file_info; char *filename = NULL; + size_t size; i = list_length(BIF_ARG_1); if (i < 0) { @@ -4118,9 +4171,13 @@ BIF_RETTYPE blocking_read_file_1(BIF_ALIST_1) fclose(file); BIF_RET(TUPLE2(hp, am_error, am_allocator)); } - fread(buff, 1, buff_size, file); + size = fread(buff, 1, buff_size, file); fclose(file); - bin = new_binary(BIF_P, buff, buff_size); + if (size < 0) + size = 0; + else if (size > buff_size) + size = (size_t) buff_size; + bin = new_binary(BIF_P, buff, (int) size); erts_free(ERTS_ALC_T_TMP, (void *) buff); BIF_RET(TUPLE2(hp, am_ok, bin)); diff --git a/erts/emulator/beam/bif.tab b/erts/emulator/beam/bif.tab index 85a729208f..b6fa06354a 100644 --- a/erts/emulator/beam/bif.tab +++ b/erts/emulator/beam/bif.tab @@ -1,19 +1,19 @@ # # %CopyrightBegin% -# -# Copyright Ericsson AB 1996-2009. All Rights Reserved. -# +# +# Copyright Ericsson AB 1996-2010. 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% # @@ -755,6 +755,11 @@ bif erlang:call_on_load_function/1 bif erlang:finish_after_on_load/2 # +# New Bifs in R13B4 +# +bif erlang:binary_to_term/2 + +# # Obsolete # diff --git a/erts/emulator/beam/binary.c b/erts/emulator/beam/binary.c index 49bc0d6457..08c64610a2 100644 --- a/erts/emulator/beam/binary.c +++ b/erts/emulator/beam/binary.c @@ -1,19 +1,19 @@ /* * %CopyrightBegin% - * - * Copyright Ericsson AB 1996-2009. All Rights Reserved. - * + * + * Copyright Ericsson AB 1996-2010. 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% */ @@ -180,7 +180,7 @@ erts_realloc_binary(Eterm bin, size_t size) } byte* -erts_get_aligned_binary_bytes(Eterm bin, byte** base_ptr) +erts_get_aligned_binary_bytes_extra(Eterm bin, byte** base_ptr, unsigned extra) { byte* bytes; Eterm* real_bin; @@ -208,10 +208,10 @@ erts_get_aligned_binary_bytes(Eterm bin, byte** base_ptr) bytes = (byte *)(&(((ErlHeapBin *) real_bin)->data)) + offs; } if (bit_offs) { - byte* buf = (byte *) erts_alloc(ERTS_ALC_T_TMP, byte_size); - - erts_copy_bits(bytes, bit_offs, 1, buf, 0, 1, byte_size*8); + byte* buf = (byte *) erts_alloc(ERTS_ALC_T_TMP, byte_size + extra); *base_ptr = buf; + buf += extra; + erts_copy_bits(bytes, bit_offs, 1, buf, 0, 1, byte_size*8); bytes = buf; } return bytes; diff --git a/erts/emulator/beam/break.c b/erts/emulator/beam/break.c index 5ea47e16f5..cc69977b79 100644 --- a/erts/emulator/beam/break.c +++ b/erts/emulator/beam/break.c @@ -703,6 +703,8 @@ erl_crash_dump_v(char *file, int line, char* fmt, va_list args) erts_fdprintf(fd, "System version: "); erts_print_system_version(fd, NULL, NULL); erts_fdprintf(fd, "%s\n", "Compiled: " ERLANG_COMPILE_DATE); + erts_fdprintf(fd, "Taints: "); + erts_print_nif_taints(fd, NULL); erts_fdprintf(fd, "Atoms: %d\n", atom_table_size()); info(fd, NULL); /* General system info */ if (process_tab != NULL) /* XXX true at init */ diff --git a/erts/emulator/beam/erl_arith.c b/erts/emulator/beam/erl_arith.c index b692832677..126ec7cc73 100644 --- a/erts/emulator/beam/erl_arith.c +++ b/erts/emulator/beam/erl_arith.c @@ -1,19 +1,19 @@ /* * %CopyrightBegin% - * - * Copyright Ericsson AB 1999-2009. All Rights Reserved. - * + * + * Copyright Ericsson AB 1999-2010. 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% */ @@ -50,18 +50,16 @@ static ERTS_INLINE void maybe_shrink(Process* p, Eterm* hp, Eterm res, Uint allo if (is_immed(res)) { if (p->heap <= hp && hp < p->htop) { p->htop = hp; -#if defined(CHECK_FOR_HOLES) - } else { - erts_arith_shrink(p, hp); -#endif + } + else { + erts_heap_frag_shrink(p, hp); } } else if ((actual = bignum_header_arity(*hp)+1) < alloc) { if (p->heap <= hp && hp < p->htop) { p->htop = hp+actual; -#if defined(CHECK_FOR_HOLES) - } else { - erts_arith_shrink(p, hp+actual); -#endif + } + else { + erts_heap_frag_shrink(p, hp+actual); } } } @@ -397,12 +395,11 @@ erts_mixed_plus(Process* p, Eterm arg1, Eterm arg2) need_heap = BIG_NEED_SIZE(sz); hp = HAlloc(p, need_heap); res = big_plus(arg1, arg2, hp); + maybe_shrink(p, hp, res, need_heap); if (is_nil(res)) { - erts_arith_shrink(p, hp); p->freason = SYSTEM_LIMIT; return THE_NON_VALUE; } - maybe_shrink(p, hp, res, need_heap); return res; case (_TAG_HEADER_FLOAT >> _TAG_PRIMARY_SIZE): if (big_to_double(arg1, &f1.fd) < 0) { @@ -533,12 +530,11 @@ erts_mixed_minus(Process* p, Eterm arg1, Eterm arg2) need_heap = BIG_NEED_SIZE(sz); hp = HAlloc(p, need_heap); res = big_minus(arg1, arg2, hp); + maybe_shrink(p, hp, res, need_heap); if (is_nil(res)) { - erts_arith_shrink(p, hp); p->freason = SYSTEM_LIMIT; return THE_NON_VALUE; } - maybe_shrink(p, hp, res, need_heap); return res; default: goto badarith; @@ -731,12 +727,11 @@ erts_mixed_times(Process* p, Eterm arg1, Eterm arg2) * the absolute value of the other is > 1. */ + maybe_shrink(p, hp, res, need_heap); if (is_nil(res)) { - erts_arith_shrink(p, hp); p->freason = SYSTEM_LIMIT; return THE_NON_VALUE; - } - maybe_shrink(p, hp, res, need_heap); + } return res; case (_TAG_HEADER_FLOAT >> _TAG_PRIMARY_SIZE): if (big_to_double(arg1, &f1.fd) < 0) { @@ -956,12 +951,11 @@ erts_int_div(Process* p, Eterm arg1, Eterm arg2) need = BIG_NEED_SIZE(i-ires+1) + BIG_NEED_SIZE(i); hp = HAlloc(p, need); arg1 = big_div(arg1, arg2, hp); + maybe_shrink(p, hp, arg1, need); if (is_nil(arg1)) { - erts_arith_shrink(p, hp); p->freason = SYSTEM_LIMIT; return THE_NON_VALUE; } - maybe_shrink(p, hp, arg1, need); } return arg1; default: @@ -1004,12 +998,11 @@ erts_int_rem(Process* p, Eterm arg1, Eterm arg2) Eterm* hp = HAlloc(p, need); arg1 = big_rem(arg1, arg2, hp); + maybe_shrink(p, hp, arg1, need); if (is_nil(arg1)) { - erts_arith_shrink(p, hp); p->freason = SYSTEM_LIMIT; return THE_NON_VALUE; } - maybe_shrink(p, hp, arg1, need); } return arg1; default: @@ -1147,7 +1140,7 @@ trim_heap(Process* p, Eterm* hp, Eterm res) * a garbage collection if there is insufficient heap space. */ -#define erts_arith_shrink horrible error +#define erts_heap_frag_shrink horrible error #define maybe_shrink horrible error Eterm diff --git a/erts/emulator/beam/erl_bif_guard.c b/erts/emulator/beam/erl_bif_guard.c index 8b47db10dd..440b0b4f14 100644 --- a/erts/emulator/beam/erl_bif_guard.c +++ b/erts/emulator/beam/erl_bif_guard.c @@ -1,19 +1,19 @@ /* * %CopyrightBegin% - * - * Copyright Ericsson AB 2006-2009. All Rights Reserved. - * + * + * Copyright Ericsson AB 2006-2010. 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% */ @@ -318,6 +318,10 @@ double_to_integer(Process* p, double x) * The following code is used when a guard that may build on the * heap is called directly. They must not use HAlloc(), but must * do a garbage collection if there is insufficient heap space. + * + * Important note: All error checking MUST be done before doing + * a garbage collection. The compiler assumes that all registers + * are still valid if a guard BIF generates an exception. */ #define ERTS_NEED_GC(p, need) ((HEAP_LIMIT((p)) - HEAP_TOP((p))) <= (need)) diff --git a/erts/emulator/beam/erl_bif_info.c b/erts/emulator/beam/erl_bif_info.c index 60216aa8e4..a34d400ed8 100644 --- a/erts/emulator/beam/erl_bif_info.c +++ b/erts/emulator/beam/erl_bif_info.c @@ -1,19 +1,19 @@ /* * %CopyrightBegin% - * - * Copyright Ericsson AB 1999-2009. All Rights Reserved. - * + * + * Copyright Ericsson AB 1999-2010. 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% */ @@ -543,6 +543,8 @@ static Eterm pi_args[] = { am_last_calls, am_total_heap_size, am_suspending, + am_min_heap_size, + am_min_bin_vheap_size, #ifdef HYBRID am_message_binary #endif @@ -589,8 +591,10 @@ pi_arg2ix(Eterm arg) case am_last_calls: return 24; case am_total_heap_size: return 25; case am_suspending: return 26; + case am_min_heap_size: return 27; + case am_min_bin_vheap_size: return 28; #ifdef HYBRID - case am_message_binary: return 27; + case am_message_binary: return 29; #endif default: return -1; } @@ -1355,6 +1359,30 @@ process_info_aux(Process *BIF_P, break; } + case am_fullsweep_after: { + Uint hsz = 3; + (void) erts_bld_uint(NULL, &hsz, MAX_GEN_GCS(rp)); + hp = HAlloc(BIF_P, hsz); + res = erts_bld_uint(&hp, NULL, MAX_GEN_GCS(rp)); + break; + } + + case am_min_heap_size: { + Uint hsz = 3; + (void) erts_bld_uint(NULL, &hsz, MIN_HEAP_SIZE(rp)); + hp = HAlloc(BIF_P, hsz); + res = erts_bld_uint(&hp, NULL, MIN_HEAP_SIZE(rp)); + break; + } + + case am_min_bin_vheap_size: { + Uint hsz = 3; + (void) erts_bld_uint(NULL, &hsz, MIN_VHEAP_SIZE(rp)); + hp = HAlloc(BIF_P, hsz); + res = erts_bld_uint(&hp, NULL, MIN_VHEAP_SIZE(rp)); + break; + } + case am_total_heap_size: { ErlMessage *mp; Uint total_heap_size; @@ -1433,15 +1461,17 @@ process_info_aux(Process *BIF_P, DECL_AM(minor_gcs); Eterm t; - hp = HAlloc(BIF_P, 3+2+3+2+3); - t = TUPLE2(hp, AM_minor_gcs, make_small(GEN_GCS(rp))); - hp += 3; - res = CONS(hp, t, NIL); - hp += 2; - t = TUPLE2(hp, am_fullsweep_after, make_small(MAX_GEN_GCS(rp))); - hp += 3; - res = CONS(hp, t, res); - hp += 2; + hp = HAlloc(BIF_P, 3+2 + 3+2 + 3+2 + 3+2 + 3); /* last "3" is for outside tuple */ + + t = TUPLE2(hp, AM_minor_gcs, make_small(GEN_GCS(rp))); hp += 3; + res = CONS(hp, t, NIL); hp += 2; + t = TUPLE2(hp, am_fullsweep_after, make_small(MAX_GEN_GCS(rp))); hp += 3; + res = CONS(hp, t, res); hp += 2; + + t = TUPLE2(hp, am_min_heap_size, make_small(MIN_HEAP_SIZE(rp))); hp += 3; + res = CONS(hp, t, res); hp += 2; + t = TUPLE2(hp, am_min_bin_vheap_size, make_small(MIN_VHEAP_SIZE(rp))); hp += 3; + res = CONS(hp, t, res); hp += 2; break; } @@ -1897,16 +1927,32 @@ BIF_RETTYPE system_info_1(BIF_ALIST_1) BIF_RET(res); } else if (BIF_ARG_1 == am_garbage_collection){ Uint val = (Uint) erts_smp_atomic_read(&erts_max_gen_gcs); - hp = HAlloc(BIF_P, 3+2); - res = TUPLE2(hp, am_fullsweep_after, make_small(val)); - hp += 3; - res = CONS(hp, res, NIL); + Eterm tup; + hp = HAlloc(BIF_P, 3+2 + 3+2 + 3+2); + + tup = TUPLE2(hp, am_fullsweep_after, make_small(val)); hp += 3; + res = CONS(hp, tup, NIL); hp += 2; + + tup = TUPLE2(hp, am_min_heap_size, make_small(H_MIN_SIZE)); hp += 3; + res = CONS(hp, tup, res); hp += 2; + + tup = TUPLE2(hp, am_min_bin_vheap_size, make_small(BIN_VH_MIN_SIZE)); hp += 3; + res = CONS(hp, tup, res); hp += 2; + BIF_RET(res); } else if (BIF_ARG_1 == am_fullsweep_after){ Uint val = (Uint) erts_smp_atomic_read(&erts_max_gen_gcs); hp = HAlloc(BIF_P, 3); res = TUPLE2(hp, am_fullsweep_after, make_small(val)); BIF_RET(res); + } else if (BIF_ARG_1 == am_min_heap_size) { + hp = HAlloc(BIF_P, 3); + res = TUPLE2(hp, am_min_heap_size,make_small(H_MIN_SIZE)); + BIF_RET(res); + } else if (BIF_ARG_1 == am_min_bin_vheap_size) { + hp = HAlloc(BIF_P, 3); + res = TUPLE2(hp, am_min_bin_vheap_size,make_small(BIN_VH_MIN_SIZE)); + BIF_RET(res); } else if (BIF_ARG_1 == am_process_count) { BIF_RET(make_small(erts_process_count())); } else if (BIF_ARG_1 == am_process_limit) { @@ -3131,6 +3177,13 @@ BIF_RETTYPE erts_debug_get_internal_state_1(BIF_ALIST_1) else if (ERTS_IS_ATOM_STR("available_internal_state", BIF_ARG_1)) { BIF_RET(am_true); } + else if (ERTS_IS_ATOM_STR("force_heap_frags", BIF_ARG_1)) { +#ifdef FORCE_HEAP_FRAGS + BIF_RET(am_true); +#else + BIF_RET(am_false); +#endif + } } else if (is_tuple(BIF_ARG_1)) { Eterm* tp = tuple_val(BIF_ARG_1); @@ -3651,12 +3704,11 @@ static Eterm lcnt_build_lock_term(Eterm **hpp, Uint *szp, erts_lcnt_lock_t *lock ASSERT(ltype); type = am_atom_put(ltype, strlen(ltype)); - name = am_atom_put(lock->name, strlen(lock->name)); if (lock->flag & ERTS_LCNT_LT_ALLOC) { /* use allocator types names as id's for allocator locks */ - ltype = ERTS_ALC_A2AD(signed_val(lock->id)); + ltype = (char *) ERTS_ALC_A2AD(signed_val(lock->id)); id = am_atom_put(ltype, strlen(ltype)); } else if (lock->flag & ERTS_LCNT_LT_PROCLOCK) { /* use registered names as id's for process locks if available */ @@ -3725,17 +3777,28 @@ BIF_RETTYPE erts_debug_lock_counters_1(BIF_ALIST_1) { #ifdef ERTS_ENABLE_LOCK_COUNT Eterm res = NIL; - erts_smp_proc_unlock(BIF_P, ERTS_PROC_LOCK_MAIN); - erts_smp_block_system(0); +#endif + + + if (BIF_ARG_1 == am_enabled) { +#ifdef ERTS_ENABLE_LOCK_COUNT + BIF_RET(am_true); +#else + BIF_RET(am_false); +#endif + } +#ifdef ERTS_ENABLE_LOCK_COUNT - if (BIF_ARG_1 == am_info) { + else if (BIF_ARG_1 == am_info) { erts_lcnt_data_t *data; Uint hsize = 0; Uint *szp; Eterm* hp; - erts_lcnt_set_rt_opt(ERTS_LCNT_OPT_SUSPEND); + erts_smp_proc_unlock(BIF_P, ERTS_PROC_LOCK_MAIN); + erts_smp_block_system(0); + erts_lcnt_set_rt_opt(ERTS_LCNT_OPT_SUSPEND); data = erts_lcnt_get_data(); /* calculate size */ @@ -3750,29 +3813,65 @@ BIF_RETTYPE erts_debug_lock_counters_1(BIF_ALIST_1) res = lcnt_build_result_term(&hp, NULL, data, res); erts_lcnt_clear_rt_opt(ERTS_LCNT_OPT_SUSPEND); + + erts_smp_release_system(); + erts_smp_proc_lock(BIF_P, ERTS_PROC_LOCK_MAIN); - goto done; + BIF_RET(res); } else if (BIF_ARG_1 == am_clear) { + erts_smp_proc_unlock(BIF_P, ERTS_PROC_LOCK_MAIN); + erts_smp_block_system(0); + erts_lcnt_clear_counters(); - res = am_ok; - goto done; + + erts_smp_release_system(); + erts_smp_proc_lock(BIF_P, ERTS_PROC_LOCK_MAIN); + + BIF_RET(am_ok); } else if (is_tuple(BIF_ARG_1)) { - Uint prev = 0; Eterm* tp = tuple_val(BIF_ARG_1); + switch (arityval(tp[0])) { case 2: - if (ERTS_IS_ATOM_STR("process_locks", tp[1])) { + if (ERTS_IS_ATOM_STR("copy_save", tp[1])) { + erts_smp_proc_unlock(BIF_P, ERTS_PROC_LOCK_MAIN); + erts_smp_block_system(0); if (tp[2] == am_true) { - prev = erts_lcnt_set_rt_opt(ERTS_LCNT_OPT_PROCLOCK); - if (prev) res = am_true; - else res = am_false; - goto done; + + res = erts_lcnt_set_rt_opt(ERTS_LCNT_OPT_COPYSAVE) ? am_true : am_false; + } else if (tp[2] == am_false) { - prev = erts_lcnt_clear_rt_opt(ERTS_LCNT_OPT_PROCLOCK); - if (prev) res = am_true; - else res = am_false; - goto done; + + res = erts_lcnt_clear_rt_opt(ERTS_LCNT_OPT_COPYSAVE) ? am_true : am_false; + + } else { + erts_smp_release_system(); + erts_smp_proc_lock(BIF_P, ERTS_PROC_LOCK_MAIN); + BIF_ERROR(BIF_P, BADARG); + } + erts_smp_release_system(); + erts_smp_proc_lock(BIF_P, ERTS_PROC_LOCK_MAIN); + BIF_RET(res); + + } else if (ERTS_IS_ATOM_STR("process_locks", tp[1])) { + erts_smp_proc_unlock(BIF_P, ERTS_PROC_LOCK_MAIN); + erts_smp_block_system(0); + if (tp[2] == am_true) { + + res = erts_lcnt_set_rt_opt(ERTS_LCNT_OPT_PROCLOCK) ? am_true : am_false; + + } else if (tp[2] == am_false) { + + res = erts_lcnt_set_rt_opt(ERTS_LCNT_OPT_PROCLOCK) ? am_true : am_false; + + } else { + erts_smp_release_system(); + erts_smp_proc_lock(BIF_P, ERTS_PROC_LOCK_MAIN); + BIF_ERROR(BIF_P, BADARG); } + erts_smp_release_system(); + erts_smp_proc_lock(BIF_P, ERTS_PROC_LOCK_MAIN); + BIF_RET(res); } break; @@ -3781,16 +3880,8 @@ BIF_RETTYPE erts_debug_lock_counters_1(BIF_ALIST_1) } } - erts_smp_release_system(); - erts_smp_proc_lock(BIF_P, ERTS_PROC_LOCK_MAIN); #endif BIF_ERROR(BIF_P, BADARG); -#ifdef ERTS_ENABLE_LOCK_COUNT -done: - erts_smp_release_system(); - erts_smp_proc_lock(BIF_P, ERTS_PROC_LOCK_MAIN); - BIF_RET(res); -#endif } void diff --git a/erts/emulator/beam/erl_bif_re.c b/erts/emulator/beam/erl_bif_re.c index 16abab65b0..c027cd5984 100644 --- a/erts/emulator/beam/erl_bif_re.c +++ b/erts/emulator/beam/erl_bif_re.c @@ -1,19 +1,19 @@ /* * %CopyrightBegin% - * - * Copyright Ericsson AB 2008-2009. All Rights Reserved. - * + * + * Copyright Ericsson AB 2008-2010. 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% */ @@ -884,7 +884,7 @@ re_run_3(BIF_ALIST_3) int capture_count; if (pflags & PARSE_FLAG_UNICODE && - (!is_binary(BIF_ARG_1) || + (!is_binary(BIF_ARG_2) || !is_binary(BIF_ARG_1) || (is_list_cap && !(pflags & PARSE_FLAG_GLOBAL)))) { BIF_TRAP3(urun_trap_exportp, BIF_P, BIF_ARG_1, BIF_ARG_2, BIF_ARG_3); } @@ -1020,6 +1020,9 @@ re_run_3(BIF_ALIST_3) goto handle_iolist; } pb = (ProcBin *) bptr; + if (pb->flags) { + erts_emasculate_writable_binary(pb); + } restart.subject = (char *) (pb->bytes+offset); restart.flags |= RESTART_FLAG_SUBJECT_IN_BINARY; } else { diff --git a/erts/emulator/beam/erl_binary.h b/erts/emulator/beam/erl_binary.h index dc5539faad..21d4e3fdfd 100644 --- a/erts/emulator/beam/erl_binary.h +++ b/erts/emulator/beam/erl_binary.h @@ -1,19 +1,19 @@ /* * %CopyrightBegin% - * - * Copyright Ericsson AB 2000-2009. All Rights Reserved. - * + * + * Copyright Ericsson AB 2000-2010. 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% */ @@ -150,7 +150,7 @@ do { \ void erts_init_binary(void); -byte* erts_get_aligned_binary_bytes(Eterm, byte**); +byte* erts_get_aligned_binary_bytes_extra(Eterm, byte**, unsigned extra); #if defined(__i386__) || !defined(__GNUC__) /* @@ -166,6 +166,7 @@ byte* erts_get_aligned_binary_bytes(Eterm, byte**); #define ERTS_CHK_BIN_ALIGNMENT(B) \ do { ASSERT(!(B) || (((Uint) &((Binary *)(B))->orig_bytes[0]) & ERTS_BIN_ALIGNMENT_MASK) == ((Uint) 0)) } while(0) +ERTS_GLB_INLINE byte* erts_get_aligned_binary_bytes(Eterm bin, byte** base_ptr); ERTS_GLB_INLINE void erts_free_aligned_binary_bytes(byte* buf); ERTS_GLB_INLINE Binary *erts_bin_drv_alloc_fnf(Uint size); ERTS_GLB_INLINE Binary *erts_bin_drv_alloc(Uint size); @@ -178,6 +179,14 @@ ERTS_GLB_INLINE Binary *erts_create_magic_binary(Uint size, #if ERTS_GLB_INLINE_INCL_FUNC_DEF +#include <stddef.h> /* offsetof */ + +ERTS_GLB_INLINE byte* +erts_get_aligned_binary_bytes(Eterm bin, byte** base_ptr) +{ + return erts_get_aligned_binary_bytes_extra(bin, base_ptr, 0); +} + ERTS_GLB_INLINE void erts_free_aligned_binary_bytes(byte* buf) { @@ -189,7 +198,7 @@ erts_free_aligned_binary_bytes(byte* buf) ERTS_GLB_INLINE Binary * erts_bin_drv_alloc_fnf(Uint size) { - Uint bsize = sizeof(Binary) - 1 + size; + Uint bsize = ERTS_SIZEOF_Binary(size); void *res; res = erts_alloc_fnf(ERTS_ALC_T_DRV_BINARY, bsize); ERTS_CHK_BIN_ALIGNMENT(res); @@ -199,7 +208,7 @@ erts_bin_drv_alloc_fnf(Uint size) ERTS_GLB_INLINE Binary * erts_bin_drv_alloc(Uint size) { - Uint bsize = sizeof(Binary) - 1 + size; + Uint bsize = ERTS_SIZEOF_Binary(size); void *res; res = erts_alloc(ERTS_ALC_T_DRV_BINARY, bsize); ERTS_CHK_BIN_ALIGNMENT(res); @@ -210,7 +219,7 @@ erts_bin_drv_alloc(Uint size) ERTS_GLB_INLINE Binary * erts_bin_nrml_alloc(Uint size) { - Uint bsize = sizeof(Binary) - 1 + size; + Uint bsize = ERTS_SIZEOF_Binary(size); void *res; res = erts_alloc(ERTS_ALC_T_BINARY, bsize); ERTS_CHK_BIN_ALIGNMENT(res); @@ -221,7 +230,7 @@ ERTS_GLB_INLINE Binary * erts_bin_realloc_fnf(Binary *bp, Uint size) { Binary *nbp; - Uint bsize = sizeof(Binary) - 1 + size; + Uint bsize = ERTS_SIZEOF_Binary(size); ASSERT((bp->flags & BIN_FLAG_MAGIC) == 0); if (bp->flags & BIN_FLAG_DRV) nbp = erts_realloc_fnf(ERTS_ALC_T_DRV_BINARY, (void *) bp, bsize); @@ -235,7 +244,7 @@ ERTS_GLB_INLINE Binary * erts_bin_realloc(Binary *bp, Uint size) { Binary *nbp; - Uint bsize = sizeof(Binary) - 1 + size; + Uint bsize = ERTS_SIZEOF_Binary(size); ASSERT((bp->flags & BIN_FLAG_MAGIC) == 0); if (bp->flags & BIN_FLAG_DRV) nbp = erts_realloc_fnf(ERTS_ALC_T_DRV_BINARY, (void *) bp, bsize); @@ -265,13 +274,13 @@ erts_bin_free(Binary *bp) ERTS_GLB_INLINE Binary * erts_create_magic_binary(Uint size, void (*destructor)(Binary *)) { - Uint bsize = sizeof(Binary) - 1 + sizeof(ErtsBinaryMagicPart) - 1 + size; + Uint bsize = ERTS_MAGIC_BIN_SIZE(size); Binary* bptr = erts_alloc_fnf(ERTS_ALC_T_BINARY, bsize); if (!bptr) erts_alloc_n_enomem(ERTS_ALC_T2N(ERTS_ALC_T_BINARY), bsize); ERTS_CHK_BIN_ALIGNMENT(bptr); bptr->flags = BIN_FLAG_MAGIC; - bptr->orig_size = sizeof(ErtsBinaryMagicPart) - 1 + size; + bptr->orig_size = ERTS_MAGIC_BIN_ORIG_SIZE(size); erts_refc_init(&bptr->refc, 0); ERTS_MAGIC_BIN_DESTRUCTOR(bptr) = destructor; return bptr; diff --git a/erts/emulator/beam/erl_db.c b/erts/emulator/beam/erl_db.c index b02150008f..15b1c6bb56 100644 --- a/erts/emulator/beam/erl_db.c +++ b/erts/emulator/beam/erl_db.c @@ -1,19 +1,19 @@ /* * %CopyrightBegin% - * - * Copyright Ericsson AB 1996-2009. All Rights Reserved. - * + * + * Copyright Ericsson AB 1996-2010. 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% */ @@ -261,13 +261,8 @@ static ERTS_INLINE void db_init_lock(DbTable* tb, char *rwname, char* fixname) erts_refc_init(&tb->common.ref, 1); erts_refc_init(&tb->common.fixref, 0); #ifdef ERTS_SMP -# ifdef ERTS_ENABLE_LOCK_COUNT erts_smp_rwmtx_init_x(&tb->common.rwlock, rwname, tb->common.the_name); erts_smp_mtx_init_x(&tb->common.fixlock, fixname, tb->common.the_name); -# else - erts_smp_rwmtx_init(&tb->common.rwlock, rwname); - erts_smp_mtx_init(&tb->common.fixlock, fixname); -# endif tb->common.is_thread_safe = !(tb->common.status & DB_FINE_LOCKED); #endif } @@ -2597,19 +2592,11 @@ void init_db(void) #ifdef ERTS_SMP for (i=0; i<META_MAIN_TAB_LOCK_CNT; i++) { -#ifdef ERTS_ENABLE_LOCK_COUNT erts_smp_spinlock_init_x(&meta_main_tab_locks[i].lck, "meta_main_tab_slot", make_small(i)); -#else - erts_smp_spinlock_init(&meta_main_tab_locks[i].lck, "meta_main_tab_slot"); -#endif } erts_smp_spinlock_init(&meta_main_tab_main_lock, "meta_main_tab_main"); for (i=0; i<META_NAME_TAB_LOCK_CNT; i++) { -#ifdef ERTS_ENABLE_LOCK_COUNT erts_smp_rwmtx_init_x(&meta_name_tab_rwlocks[i].lck, "meta_name_tab", make_small(i)); -#else - erts_smp_rwmtx_init(&meta_name_tab_rwlocks[i].lck, "meta_name_tab"); -#endif } #endif diff --git a/erts/emulator/beam/erl_db_hash.c b/erts/emulator/beam/erl_db_hash.c index dea45053df..4141f9766b 100644 --- a/erts/emulator/beam/erl_db_hash.c +++ b/erts/emulator/beam/erl_db_hash.c @@ -1,19 +1,19 @@ /* * %CopyrightBegin% - * - * Copyright Ericsson AB 1998-2009. All Rights Reserved. - * + * + * Copyright Ericsson AB 1998-2010. 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% */ @@ -628,11 +628,7 @@ int db_create_hash(Process *p, DbTable *tbl) (DbTable *) tb, sizeof(DbTableHashFineLocks)); for (i=0; i<DB_HASH_LOCK_CNT; ++i) { - #ifdef ERTS_ENABLE_LOCK_COUNT - erts_rwmtx_init_x(&tb->locks->lck_vec[i].lck, "db_hash_slot", tb->common.the_name); - #else - erts_rwmtx_init(&tb->locks->lck_vec[i].lck, "db_hash_slot"); - #endif + erts_rwmtx_init_x(&tb->locks->lck_vec[i].lck, "db_hash_slot", make_small(i)); } /* This important property is needed to guarantee that the buckets * involved in a grow/shrink operation it protected by the same lock: diff --git a/erts/emulator/beam/erl_db_tree.c b/erts/emulator/beam/erl_db_tree.c index d3a916d2d9..b421da591b 100644 --- a/erts/emulator/beam/erl_db_tree.c +++ b/erts/emulator/beam/erl_db_tree.c @@ -1,19 +1,19 @@ /* * %CopyrightBegin% - * - * Copyright Ericsson AB 1998-2009. All Rights Reserved. - * + * + * Copyright Ericsson AB 1998-2010. 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% */ @@ -2529,7 +2529,9 @@ static TreeDbTerm *find_node(DbTableTree *tb, Eterm key) this = this->right; } } - release_stack(tb,stack); + if (stack) { + release_stack(tb,stack); + } return this; } diff --git a/erts/emulator/beam/erl_debug.c b/erts/emulator/beam/erl_debug.c index 34ce87bc5d..e5c3c76fdd 100644 --- a/erts/emulator/beam/erl_debug.c +++ b/erts/emulator/beam/erl_debug.c @@ -1,19 +1,19 @@ /* * %CopyrightBegin% - * - * Copyright Ericsson AB 1998-2009. All Rights Reserved. - * + * + * Copyright Ericsson AB 1998-2010. 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% */ @@ -344,7 +344,7 @@ void erts_check_for_holes(Process* p) if (hf == p->last_mbuf) { break; } - check_memory(hf->mem, hf->mem+hf->size); + check_memory(hf->mem, hf->mem+hf->used_size); } p->last_mbuf = MBUF(p); } @@ -386,7 +386,7 @@ void erts_check_heap(Process *p) } while (bp) { - erts_check_memory(p,bp->mem,bp->mem + bp->size); + erts_check_memory(p,bp->mem,bp->mem + bp->used_size); bp = bp->next; } } diff --git a/erts/emulator/beam/erl_driver.h b/erts/emulator/beam/erl_driver.h index cdb584b282..489e74d960 100644 --- a/erts/emulator/beam/erl_driver.h +++ b/erts/emulator/beam/erl_driver.h @@ -1,19 +1,19 @@ /* * %CopyrightBegin% - * - * Copyright Ericsson AB 1999-2009. All Rights Reserved. - * + * + * Copyright Ericsson AB 1999-2010. 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% */ @@ -65,6 +65,8 @@ # error SIZEOF_LONG_LONG mismatch #endif +#include "erl_drv_nif.h" + #include <stdlib.h> #if defined(VXWORKS) @@ -116,7 +118,7 @@ typedef struct { #define ERL_DRV_EXTENDED_MARKER (0xfeeeeeed) #define ERL_DRV_EXTENDED_MAJOR_VERSION 1 -#define ERL_DRV_EXTENDED_MINOR_VERSION 4 +#define ERL_DRV_EXTENDED_MINOR_VERSION 5 /* * The emulator will refuse to load a driver with different major @@ -195,22 +197,6 @@ typedef struct { unsigned char data[sizeof(void *)*4]; } ErlDrvMonitor; - -/* - * System info - */ - -typedef struct { - int driver_major_version; - int driver_minor_version; - char *erts_version; - char *otp_release; - int thread_support; - int smp_support; - int async_threads; - int scheduler_threads; -} ErlDrvSysInfo; - typedef struct { unsigned long megasecs; unsigned long secs; @@ -255,9 +241,6 @@ typedef struct ErlDrvCond_ ErlDrvCond; typedef struct ErlDrvRWLock_ ErlDrvRWLock; typedef int ErlDrvTSDKey; -typedef struct { - int suggested_stack_size; -} ErlDrvThreadOpts; /* * diff --git a/erts/emulator/beam/erl_drv_nif.h b/erts/emulator/beam/erl_drv_nif.h new file mode 100644 index 0000000000..ea013a49a3 --- /dev/null +++ b/erts/emulator/beam/erl_drv_nif.h @@ -0,0 +1,48 @@ +/* + * %CopyrightBegin% + * + * Copyright Ericsson AB 2010. 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% + */ + +/* + * Common structures for both erl_driver.h and erl_nif.h + */ + +#ifndef __ERL_DRV_NIF_H__ +#define __ERL_DRV_NIF_H__ + +typedef struct { + int driver_major_version; + int driver_minor_version; + char *erts_version; + char *otp_release; + int thread_support; + int smp_support; + int async_threads; + int scheduler_threads; + int nif_major_version; + int nif_minor_version; +} ErlDrvSysInfo; + +typedef struct { + int suggested_stack_size; +} ErlDrvThreadOpts; + +#endif /* __ERL_DRV_NIF_H__ */ + + + + diff --git a/erts/emulator/beam/erl_gc.c b/erts/emulator/beam/erl_gc.c index 6945317e65..e9bf37a173 100644 --- a/erts/emulator/beam/erl_gc.c +++ b/erts/emulator/beam/erl_gc.c @@ -1,19 +1,19 @@ /* * %CopyrightBegin% - * - * Copyright Ericsson AB 2002-2009. All Rights Reserved. - * + * + * Copyright Ericsson AB 2002-2010. 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 @@ -961,12 +961,13 @@ do_minor(Process *p, int new_sz, Eterm* objv, int nobj) n_htop = sweep_one_area(n_heap, n_htop, heap, heap_size); } else { Eterm* n_hp = n_heap; + Eterm* ptr; + Eterm val; + Eterm gval; while (n_hp != n_htop) { - Eterm* ptr; - Eterm val; - Eterm gval = *n_hp; - + ASSERT(n_hp < n_htop); + gval = *n_hp; switch (primary_tag(gval)) { case TAG_PRIMARY_BOXED: { ptr = boxed_val(gval); @@ -1402,68 +1403,6 @@ remove_message_buffers(Process* p) } } -/* - * Go through one root set array, move everything that it is one of the - * heap fragments to our new heap. - */ -static Eterm* -collect_root_array(Process* p, Eterm* n_htop, Eterm* objv, int nobj) -{ - ErlHeapFragment* qb; - Eterm gval; - Eterm* ptr; - Eterm val; - - ASSERT(p->htop != NULL); - while (nobj--) { - gval = *objv; - - switch (primary_tag(gval)) { - - case TAG_PRIMARY_BOXED: { - ptr = boxed_val(gval); - val = *ptr; - if (IS_MOVED(val)) { - ASSERT(is_boxed(val)); - *objv++ = val; - } else { - for (qb = MBUF(p); qb != NULL; qb = qb->next) { - if (in_area(ptr, qb->mem, qb->size*sizeof(Eterm))) { - MOVE_BOXED(ptr,val,n_htop,objv); - break; - } - } - objv++; - } - break; - } - - case TAG_PRIMARY_LIST: { - ptr = list_val(gval); - val = *ptr; - if (is_non_value(val)) { - *objv++ = ptr[1]; - } else { - for (qb = MBUF(p); qb != NULL; qb = qb->next) { - if (in_area(ptr, qb->mem, qb->size*sizeof(Eterm))) { - MOVE_CONS(ptr,val,n_htop,objv); - break; - } - } - objv++; - } - break; - } - - default: { - objv++; - break; - } - } - } - return n_htop; -} - #ifdef HARDDEBUG /* @@ -1707,11 +1646,13 @@ sweep_rootset(Rootset* rootset, Eterm* htop, char* src, Uint src_size) static Eterm* sweep_one_area(Eterm* n_hp, Eterm* n_htop, char* src, Uint src_size) { - while (n_hp != n_htop) { - Eterm* ptr; - Eterm val; - Eterm gval = *n_hp; + Eterm* ptr; + Eterm val; + Eterm gval; + while (n_hp != n_htop) { + ASSERT(n_hp < n_htop); + gval = *n_hp; switch (primary_tag(gval)) { case TAG_PRIMARY_BOXED: { ptr = boxed_val(gval); @@ -1820,6 +1761,35 @@ sweep_one_heap(Eterm* heap_ptr, Eterm* heap_end, Eterm* htop, char* src, Uint sr } /* + * Move an area (heap fragment) by sweeping over it and set move markers. + */ +static Eterm* +move_one_area(Eterm* n_htop, char* src, Uint src_size) +{ + Eterm* ptr = (Eterm*) src; + Eterm* end = ptr + src_size/sizeof(Eterm); + Eterm dummy_ref; + + while (ptr != end) { + Eterm val; + ASSERT(ptr < end); + val = *ptr; + ASSERT(val != ERTS_HOLE_MARKER); + if (is_header(val)) { + ASSERT(ptr + header_arity(val) < end); + MOVE_BOXED(ptr, val, n_htop, &dummy_ref); + } + else { /* must be a cons cell */ + ASSERT(ptr+1 < end); + MOVE_CONS(ptr, val, n_htop, &dummy_ref); + ptr += 2; + } + } + + return n_htop; +} + +/* * Collect heap fragments and check that they point in the correct direction. */ @@ -1830,7 +1800,6 @@ collect_heap_frags(Process* p, Eterm* n_hstart, Eterm* n_htop, ErlHeapFragment* qb; char* frag_begin; Uint frag_size; - ErlMessage* mp; /* * We don't allow references to a heap fragments from the stack, heap, @@ -1845,65 +1814,44 @@ collect_heap_frags(Process* p, Eterm* n_hstart, Eterm* n_htop, #endif /* - * Go through the subset of the root set that is allowed to - * reference data in heap fragments and move data from heap fragments - * to our new heap. - */ - - if (nobj != 0) { - n_htop = collect_root_array(p, n_htop, objv, nobj); - } - if (is_not_immed(p->fvalue)) { - n_htop = collect_root_array(p, n_htop, &p->fvalue, 1); - } - if (is_not_immed(p->ftrace)) { - n_htop = collect_root_array(p, n_htop, &p->ftrace, 1); - } - if (is_not_immed(p->seq_trace_token)) { - n_htop = collect_root_array(p, n_htop, &p->seq_trace_token, 1); - } - if (is_not_immed(p->group_leader)) { - n_htop = collect_root_array(p, n_htop, &p->group_leader, 1); - } - - /* - * Go through the message queue, move everything that is in one of the - * heap fragments to our new heap. - */ - - for (mp = p->msg.first; mp != NULL; mp = mp->next) { - /* - * In most cases, mp->data.attached points to a heap fragment which is - * self-contained and we will copy it to the heap at the - * end of the GC to avoid scanning it. - * - * In a few cases, however, such as in process_info(Pid, messages) - * and trace_delivered/1, a new message points to a term that has - * been allocated by HAlloc() and mp->data.attached is NULL. Therefore - * we need this loop. - */ - if (mp->data.attached == NULL) { - n_htop = collect_root_array(p, n_htop, mp->m, 2); - } - } - - /* - * Now all references in the root set point to the new heap. However, - * many references on the new heap point to heap fragments. - */ - + * Move the heap fragments to the new heap. Note that no GC is done on + * the heap fragments. Any garbage will thus be moved as well and survive + * until next GC. + */ qb = MBUF(p); - while (qb != NULL) { - frag_begin = (char *) qb->mem; - frag_size = qb->size * sizeof(Eterm); + while (qb != NULL) { + frag_size = qb->used_size * sizeof(Eterm); if (frag_size != 0) { - n_htop = sweep_one_area(n_hstart, n_htop, frag_begin, frag_size); + frag_begin = (char *) qb->mem; + n_htop = move_one_area(n_htop, frag_begin, frag_size); } qb = qb->next; } return n_htop; } +#ifdef DEBUG +static Eterm follow_moved(Eterm term) +{ + Eterm* ptr; + switch (primary_tag(term)) { + case TAG_PRIMARY_IMMED1: + break; + case TAG_PRIMARY_BOXED: + ptr = boxed_val(term); + if (IS_MOVED(*ptr)) term = *ptr; + break; + case TAG_PRIMARY_LIST: + ptr = list_val(term); + if (is_non_value(ptr[0])) term = ptr[1]; + break; + default: + abort(); + } + return term; +} +#endif + static Uint setup_rootset(Process *p, Eterm *objv, int nobj, Rootset *rootset) { @@ -1932,7 +1880,7 @@ setup_rootset(Process *p, Eterm *objv, int nobj, Rootset *rootset) } ASSERT((is_nil(p->seq_trace_token) || - is_tuple(p->seq_trace_token) || + is_tuple(follow_moved(p->seq_trace_token)) || is_atom(p->seq_trace_token))); if (is_not_immed(p->seq_trace_token)) { roots[n].v = &p->seq_trace_token; @@ -1944,7 +1892,7 @@ setup_rootset(Process *p, Eterm *objv, int nobj, Rootset *rootset) is_internal_pid(p->tracer_proc) || is_internal_port(p->tracer_proc)); - ASSERT(is_pid(p->group_leader)); + ASSERT(is_pid(follow_moved(p->group_leader))); if (is_not_immed(p->group_leader)) { roots[n].v = &p->group_leader; roots[n].sz = 1; @@ -2083,23 +2031,45 @@ shrink_new_heap(Process *p, Uint new_sz, Eterm *objv, int nobj) } static Uint -next_vheap_size(Uint vheap, Uint vheap_sz) { - if (vheap < H_MIN_SIZE) { - return H_MIN_SIZE; - } +do_next_vheap_size(Uint vheap, Uint vheap_sz) { + + /* grow + * + * vheap_sz ====================== + * + * vheap 75% + grow + * ---------------------- + * + * vheap 25 - 75% same + * ---------------------- + * + * vheap ~ - 25% shrink + * + * ---------------------- + */ + + if (vheap > (Uint) (vheap_sz*3/4)) { + + while(vheap > (Uint) (vheap_sz*3/4)) { + vheap_sz = vheap_sz*2; + } - /* grow */ - if (vheap > vheap_sz) { - return erts_next_heap_size(2*vheap, 0); + return erts_next_heap_size(vheap_sz, 0); } - /* shrink */ - if ( vheap < vheap_sz/2) { - return (Uint)vheap_sz*3/4; + + if (vheap < (Uint) (vheap_sz/4)) { + return erts_next_heap_size((Uint) (vheap_sz / 2), 0); } return vheap_sz; + } +static Uint +next_vheap_size(Process* p, Uint vheap, Uint vheap_sz) { + vheap_sz = do_next_vheap_size(vheap, vheap_sz); + return vheap_sz < p->min_vheap_size ? p->min_vheap_size : vheap_sz; +} static void sweep_proc_externals(Process *p, int fullsweep) @@ -2302,8 +2272,8 @@ sweep_proc_bins(Process *p, int fullsweep) FLAGS(p) |= F_NEED_FULLSWEEP; } - BIN_VHEAP_SZ(p) = next_vheap_size(bin_vheap, BIN_VHEAP_SZ(p)); - BIN_OLD_VHEAP_SZ(p) = next_vheap_size(BIN_OLD_VHEAP(p), BIN_OLD_VHEAP_SZ(p)); + BIN_VHEAP_SZ(p) = next_vheap_size(p, bin_vheap, BIN_VHEAP_SZ(p)); + BIN_OLD_VHEAP_SZ(p) = next_vheap_size(p, BIN_OLD_VHEAP(p), BIN_OLD_VHEAP_SZ(p)); MSO(p).overhead = bin_vheap; /* diff --git a/erts/emulator/beam/erl_init.c b/erts/emulator/beam/erl_init.c index 8afd349b85..e97ab328cd 100644 --- a/erts/emulator/beam/erl_init.c +++ b/erts/emulator/beam/erl_init.c @@ -1,19 +1,19 @@ /* * %CopyrightBegin% - * - * Copyright Ericsson AB 1997-2009. All Rights Reserved. - * + * + * Copyright Ericsson AB 1997-2010. 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% */ @@ -84,9 +84,10 @@ int erts_use_sender_punish; * Configurable parameters. */ -Uint display_items; /* no of items to display in traces etc */ +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*/ Uint32 erts_debug_flags; /* Debug flags. */ #ifdef ERTS_OPCODE_COUNTER_SUPPORT @@ -118,6 +119,8 @@ int erts_disable_tolerant_timeofday; /* Time correction can be disabled it is * not and/or it is too slow. */ +int erts_atom_table_size = ATOM_LIMIT; /* Maximum number of atoms */ + int erts_modified_timing_level; int erts_no_crash_dump = 0; /* Use -d to suppress crash dump. */ @@ -252,7 +255,8 @@ erl_init(void) no_schedulers, no_schedulers_online); - H_MIN_SIZE = erts_next_heap_size(H_MIN_SIZE, 0); + H_MIN_SIZE = erts_next_heap_size(H_MIN_SIZE, 0); + BIN_VH_MIN_SIZE = erts_next_heap_size(BIN_VH_MIN_SIZE, 0); erts_init_trace(); erts_init_binary(); @@ -292,6 +296,7 @@ erl_init(void) erl_sys_init_final(); #endif packet_parser_init(); + erl_nif_init(); } static void @@ -513,67 +518,73 @@ void erts_usage(void) /* erts_fprintf(stderr, "-# number set the number of items to be used in traces etc\n"); */ - erts_fprintf(stderr, "-a size suggested stack size in kilo words for threads\n"); - erts_fprintf(stderr, " in the async-thread pool, valid range is [%d-%d]\n", + erts_fprintf(stderr, "-a size suggested stack size in kilo words for threads\n"); + erts_fprintf(stderr, " in the async-thread pool, valid range is [%d-%d]\n", ERTS_ASYNC_THREAD_MIN_STACK_SIZE, ERTS_ASYNC_THREAD_MAX_STACK_SIZE); - erts_fprintf(stderr, "-A number set number of threads in async thread pool,\n"); - erts_fprintf(stderr, " valid range is [0-%d]\n", + erts_fprintf(stderr, "-A number set number of threads in async thread pool,\n"); + erts_fprintf(stderr, " valid range is [0-%d]\n", ERTS_MAX_NO_OF_ASYNC_THREADS); - erts_fprintf(stderr, "-B[c|d|i] c to have Ctrl-c interrupt the Erlang shell,\n"); - erts_fprintf(stderr, " d (or no extra option) to disable the break\n"); - erts_fprintf(stderr, " handler, i to ignore break signals\n"); + erts_fprintf(stderr, "-B[c|d|i] c to have Ctrl-c interrupt the Erlang shell,\n"); + erts_fprintf(stderr, " d (or no extra option) to disable the break\n"); + erts_fprintf(stderr, " handler, i to ignore break signals\n"); /* erts_fprintf(stderr, "-b func set the boot function (default boot)\n"); */ - erts_fprintf(stderr, "-c disable continuous date/time correction with\n"); - erts_fprintf(stderr, " respect to uptime\n"); + erts_fprintf(stderr, "-c disable continuous date/time correction with\n"); + erts_fprintf(stderr, " respect to uptime\n"); - erts_fprintf(stderr, "-d don't write a crash dump for internally detected errors\n"); - erts_fprintf(stderr, " (halt(String) will still produce a crash dump)\n"); + erts_fprintf(stderr, "-d don't write a crash dump for internally detected errors\n"); + erts_fprintf(stderr, " (halt(String) will still produce a crash dump)\n"); - erts_fprintf(stderr, "-h number set minimum heap size in words (default %d)\n", + erts_fprintf(stderr, "-hms size set minimum heap size in words (default %d)\n", H_DEFAULT_SIZE); + erts_fprintf(stderr, "-hmbs size set minimum binary virtual heap size in words (default %d)\n", + VH_DEFAULT_SIZE); /* erts_fprintf(stderr, "-i module set the boot module (default init)\n"); */ - erts_fprintf(stderr, "-K boolean enable or disable kernel poll\n"); + erts_fprintf(stderr, "-K boolean enable or disable kernel poll\n"); - erts_fprintf(stderr, "-l turn on auto load tracing\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"); + erts_fprintf(stderr, "-M<X> <Y> memory allocator switches,\n"); + erts_fprintf(stderr, " see the erts_alloc(3) documentation for more info.\n"); - erts_fprintf(stderr, "-P number set maximum number of processes on this node,\n"); - erts_fprintf(stderr, " valid range is [%d-%d]\n", + erts_fprintf(stderr, "-P number set maximum number of processes on this node,\n"); + erts_fprintf(stderr, " valid range is [%d-%d]\n", ERTS_MIN_PROCESSES, ERTS_MAX_PROCESSES); - erts_fprintf(stderr, "-R number set compatibility release number,\n"); - erts_fprintf(stderr, " valid range [%d-%d]\n", + erts_fprintf(stderr, "-R number set compatibility release number,\n"); + erts_fprintf(stderr, " valid range [%d-%d]\n", ERTS_MIN_COMPAT_REL, this_rel_num()); - erts_fprintf(stderr, "-r force ets memory block to be moved on realloc\n"); - erts_fprintf(stderr, "-sbt type set scheduler bind type, valid types are:\n"); - erts_fprintf(stderr, " u|ns|ts|ps|s|nnts|nnps|tnnps|db\n"); - erts_fprintf(stderr, "-sct cput set cpu topology,\n"); - erts_fprintf(stderr, " see the erl(1) documentation for more info.\n"); - erts_fprintf(stderr, "-sss size suggested stack size in kilo words for scheduler threads,\n"); - erts_fprintf(stderr, " valid range is [%d-%d]\n", + erts_fprintf(stderr, "-r force ets memory block to be moved on realloc\n"); + erts_fprintf(stderr, "-sbt type set scheduler bind type, valid types are:\n"); + erts_fprintf(stderr, " u|ns|ts|ps|s|nnts|nnps|tnnps|db\n"); + erts_fprintf(stderr, "-sct cput set cpu topology,\n"); + erts_fprintf(stderr, " see the erl(1) documentation for more info.\n"); + erts_fprintf(stderr, "-sss size suggested stack size in kilo words for scheduler threads,\n"); + erts_fprintf(stderr, " valid range is [%d-%d]\n", ERTS_SCHED_THREAD_MIN_STACK_SIZE, ERTS_SCHED_THREAD_MAX_STACK_SIZE); - erts_fprintf(stderr, "-S n1:n2 set number of schedulers (n1), and number of\n"); - erts_fprintf(stderr, " schedulers online (n2), valid range for both\n"); - erts_fprintf(stderr, " numbers are [1-%d]\n", + erts_fprintf(stderr, "-S n1:n2 set number of schedulers (n1), and number of\n"); + erts_fprintf(stderr, " schedulers online (n2), valid range for both\n"); + erts_fprintf(stderr, " numbers are [1-%d]\n", ERTS_MAX_NO_OF_SCHEDULERS); - erts_fprintf(stderr, "-T number set modified timing level,\n"); - erts_fprintf(stderr, " valid range is [0-%d]\n", + erts_fprintf(stderr, "-t size set the maximum number of atoms the " + "emulator can handle\n"); + erts_fprintf(stderr, " valid range is [%d-%d]\n", + MIN_ATOM_TABLE_SIZE, MAX_ATOM_TABLE_SIZE); + erts_fprintf(stderr, "-T number set modified timing level,\n"); + erts_fprintf(stderr, " valid range is [0-%d]\n", ERTS_MODIFIED_TIMING_LEVELS-1); - erts_fprintf(stderr, "-V print Erlang version\n"); + erts_fprintf(stderr, "-V print Erlang version\n"); - erts_fprintf(stderr, "-v turn on chatty mode (GCs will be reported etc)\n"); + erts_fprintf(stderr, "-v turn on chatty mode (GCs will be reported etc)\n"); - erts_fprintf(stderr, "-W<i|w> set error logger warnings mapping,\n"); - erts_fprintf(stderr, " see error_logger documentation for details\n"); + erts_fprintf(stderr, "-W<i|w> set error logger warnings mapping,\n"); + erts_fprintf(stderr, " see error_logger documentation for details\n"); erts_fprintf(stderr, "\n"); erts_fprintf(stderr, "Note that if the emulator is started with erlexec (typically\n"); @@ -604,6 +615,7 @@ early_init(int *argc, char **argv) /* erts_async_max_threads = 0; erts_async_thread_suggested_stack_size = ERTS_ASYNC_THREAD_MIN_STACK_SIZE; H_MIN_SIZE = H_DEFAULT_SIZE; + BIN_VH_MIN_SIZE = VH_DEFAULT_SIZE; erts_initialized = 0; @@ -922,17 +934,40 @@ erl_start(int argc, char **argv) fprintf(stderr, "The undocumented +H option has been removed (R10B-6).\n\n"); break; - case 'h': - /* set default heap size */ - arg = get_arg(argv[i]+2, argv[i+1], &i); - if ((H_MIN_SIZE = atoi(arg)) <= 0) { - erts_fprintf(stderr, "bad heap size %s\n", arg); - erts_usage(); + case 'h': { + char *sub_param = argv[i]+2; + /* set default heap size + * + * h|ms - min_heap_size + * h|mbs - min_bin_vheap_size + * + */ + if (has_prefix("mbs", sub_param)) { + arg = get_arg(sub_param+3, argv[i+1], &i); + if ((BIN_VH_MIN_SIZE = atoi(arg)) <= 0) { + erts_fprintf(stderr, "bad heap size %s\n", arg); + erts_usage(); + } + VERBOSE(DEBUG_SYSTEM, ("using minimum binary virtual heap size %d\n", BIN_VH_MIN_SIZE)); + + } else if (has_prefix("ms", sub_param)) { + arg = get_arg(sub_param+2, argv[i+1], &i); + if ((H_MIN_SIZE = atoi(arg)) <= 0) { + erts_fprintf(stderr, "bad heap size %s\n", arg); + erts_usage(); + } + VERBOSE(DEBUG_SYSTEM, ("using minimum heap size %d\n", H_MIN_SIZE)); + } else { + /* backward compatibility */ + arg = get_arg(argv[i]+2, argv[i+1], &i); + if ((H_MIN_SIZE = atoi(arg)) <= 0) { + erts_fprintf(stderr, "bad heap size %s\n", arg); + erts_usage(); + } + VERBOSE(DEBUG_SYSTEM, ("using minimum heap size %d\n", H_MIN_SIZE)); } - VERBOSE(DEBUG_SYSTEM, - ("using minimum heap size %d\n",H_MIN_SIZE)); break; - + } case 'd': /* * Never produce crash dumps for internally detected @@ -1112,6 +1147,22 @@ erl_start(int argc, char **argv) } break; } + case 't': + /* set atom table size */ + arg = get_arg(argv[i]+2, argv[i+1], &i); + errno = 0; + erts_atom_table_size = strtol(arg, NULL, 10); + if (errno != 0 || + erts_atom_table_size < MIN_ATOM_TABLE_SIZE || + erts_atom_table_size > MAX_ATOM_TABLE_SIZE) { + erts_fprintf(stderr, "bad atom table size %s\n", arg); + erts_usage(); + } + VERBOSE(DEBUG_SYSTEM, + ("setting maximum number of atoms to %d\n", + erts_atom_table_size)); + break; + case 'T' : arg = get_arg(argv[i]+2, argv[i+1], &i); errno = 0; diff --git a/erts/emulator/beam/erl_lock_check.c b/erts/emulator/beam/erl_lock_check.c index 25f1d420d1..074b08ea57 100644 --- a/erts/emulator/beam/erl_lock_check.c +++ b/erts/emulator/beam/erl_lock_check.c @@ -1,19 +1,19 @@ /* * %CopyrightBegin% - * - * Copyright Ericsson AB 2005-2009. All Rights Reserved. - * + * + * Copyright Ericsson AB 2005-2010. 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% */ @@ -84,6 +84,9 @@ static erts_lc_lock_order_t erts_lock_order[] = { { "reg_tab", NULL }, { "migration_info_update", NULL }, { "proc_main", "pid" }, +#ifdef HIPE + { "hipe_mfait_lock", NULL }, +#endif { "nodes_monitors", NULL }, { "driver_list", NULL }, { "proc_link", "pid" }, diff --git a/erts/emulator/beam/erl_lock_count.c b/erts/emulator/beam/erl_lock_count.c index 6211983f4b..0d7e1335c1 100644 --- a/erts/emulator/beam/erl_lock_count.c +++ b/erts/emulator/beam/erl_lock_count.c @@ -1,19 +1,19 @@ /* * %CopyrightBegin% - * - * Copyright Ericsson AB 2008-2009. All Rights Reserved. - * + * + * Copyright Ericsson AB 2008-2010. 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% */ @@ -162,7 +162,6 @@ static void print_lock_x(erts_lcnt_lock_t *lock, Uint16 flag, char *action, char long int colls, tries, w_state, r_state; erts_lcnt_lock_stats_t *stats = NULL; - float rate; char *type; int i; @@ -170,8 +169,6 @@ static void print_lock_x(erts_lcnt_lock_t *lock, Uint16 flag, char *action, char ethr_atomic_read(&lock->r_state, &r_state); ethr_atomic_read(&lock->w_state, &w_state); - if (tries > 0) rate = (float)(colls/(float)tries)*100; - else rate = 0.0f; if (lock->flag & flag) { erts_printf("%20s [%30s] [r/w state %4ld/%4ld] id %T %s\r\n", @@ -181,26 +178,13 @@ static void print_lock_x(erts_lcnt_lock_t *lock, Uint16 flag, char *action, char w_state, lock->id, extra); - - for(i = 0; i < lock->n_stats; i++) { - stats = &(lock->stats[i]); - ethr_atomic_read(&stats->tries, &tries); - ethr_atomic_read(&stats->colls, &colls); - fprintf(stderr, "%69s:%5d [tries %9ld] [colls %9ld] [timer_n %8ld] [timer %4ld s %6ld us]\r\n", - stats->file, - stats->line, - tries, - colls, - stats->timer_n, - stats->timer.s, - (unsigned long)stats->timer.ns/1000); - } - fprintf(stderr, "\r\n"); } } static void print_lock(erts_lcnt_lock_t *lock, char *action) { - print_lock_x(lock, ERTS_LCNT_LT_ALL, action, ""); + if (strcmp(lock->name, "proc_main") == 0) { + print_lock_x(lock, ERTS_LCNT_LT_ALL, action, ""); + } } #endif @@ -230,8 +214,8 @@ static void lcnt_update_stats(erts_lcnt_lock_stats_t *stats, int lock_in_conflic ethr_atomic_inc(&stats->tries); - /* beware of trylock */ - if (lock_in_conflict) ethr_atomic_inc(&stats->colls); + if (lock_in_conflict) + ethr_atomic_inc(&stats->colls); if (time_wait) { lcnt_time_add(&(stats->timer), time_wait); @@ -366,6 +350,7 @@ void erts_lcnt_init_lock_x(erts_lcnt_lock_t *lock, char *name, Uint16 flag, Eter for (i = 0; i < ERTS_LCNT_MAX_LOCK_LOCATIONS; i++) { lcnt_clear_stats(&lock->stats[i]); } + erts_lcnt_list_insert(erts_lcnt_data->current_locks, lock); lcnt_unlock(); @@ -373,18 +358,20 @@ void erts_lcnt_init_lock_x(erts_lcnt_lock_t *lock, char *name, Uint16 flag, Eter void erts_lcnt_destroy_lock(erts_lcnt_lock_t *lock) { erts_lcnt_lock_t *deleted_lock; - - /* copy structure and insert the copy */ - deleted_lock = (erts_lcnt_lock_t*)malloc(sizeof(erts_lcnt_lock_t)); lcnt_lock(); - memcpy(deleted_lock, lock, sizeof(erts_lcnt_lock_t)); - deleted_lock->next = NULL; - deleted_lock->prev = NULL; + if (erts_lcnt_rt_options & ERTS_LCNT_OPT_COPYSAVE) { + /* copy structure and insert the copy */ - erts_lcnt_list_insert(erts_lcnt_data->deleted_locks, deleted_lock); + deleted_lock = (erts_lcnt_lock_t*)malloc(sizeof(erts_lcnt_lock_t)); + memcpy(deleted_lock, lock, sizeof(erts_lcnt_lock_t)); + deleted_lock->next = NULL; + deleted_lock->prev = NULL; + + erts_lcnt_list_insert(erts_lcnt_data->deleted_locks, deleted_lock); + } /* delete original */ erts_lcnt_list_delete(erts_lcnt_data->current_locks, lock); @@ -416,9 +403,10 @@ void erts_lcnt_lock_opt(erts_lcnt_lock_t *lock, Uint16 option) { /* we cannot acquire w_lock if either w or r are taken */ /* we cannot acquire r_lock if w_lock is taken */ - if ((w_state > 0) || (r_state > 0)){ + if ((w_state > 0) || (r_state > 0)) { eltd->lock_in_conflict = 1; - if (eltd->timer_set == 0) lcnt_time(&eltd->timer); + if (eltd->timer_set == 0) + lcnt_time(&eltd->timer); eltd->timer_set++; } else { eltd->lock_in_conflict = 0; @@ -445,7 +433,8 @@ void erts_lcnt_lock(erts_lcnt_lock_t *lock) { * 'atomicly'. All other locks will block the thread if w_state > 0 * i.e. locked. */ - if (eltd->timer_set == 0) lcnt_time(&eltd->timer); + if (eltd->timer_set == 0) + lcnt_time(&eltd->timer); eltd->timer_set++; } else { @@ -494,24 +483,23 @@ void erts_lcnt_lock_post_x(erts_lcnt_lock_t *lock, char *file, unsigned int line eltd = lcnt_get_thread_data(); ASSERT(eltd); - + /* if lock was in conflict, time it */ stats = lcnt_get_lock_stats(lock, file, line); if (eltd->timer_set) { lcnt_time(&timer); - - eltd->timer_set--; lcnt_time_diff(&time_wait, &timer, &(eltd->timer)); lcnt_update_stats(stats, eltd->lock_in_conflict, &time_wait); + eltd->timer_set--; ASSERT(eltd->timer_set >= 0); } else { lcnt_update_stats(stats, eltd->lock_in_conflict, NULL); } - + } /* unlock */ diff --git a/erts/emulator/beam/erl_lock_count.h b/erts/emulator/beam/erl_lock_count.h index 8564c36203..e3044c371f 100644 --- a/erts/emulator/beam/erl_lock_count.h +++ b/erts/emulator/beam/erl_lock_count.h @@ -1,19 +1,19 @@ /* * %CopyrightBegin% - * - * Copyright Ericsson AB 2008-2009. All Rights Reserved. - * + * + * Copyright Ericsson AB 2008-2010. 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% */ @@ -39,6 +39,20 @@ * Each instance of a lock is the unique lock, i.e. set and id in that set. * For each lock there is a set of statistics with where and what impact * the lock aqusition had. + * + * Runtime options + * - suspend, used when internal lock-counting can't be applied. For instance + * when allocating a term for the outside and halloc needs to be used. + * Default: off. + * - location, reserved and not used. + * - proclock, disable proclock counting. Used when performance might be an + * issue. Accessible from erts_debug:lock_counters({process_locks, bool()}). + * Default: off. + * - copysave, enable saving of destroyed locks (and thereby its statistics). + * If memory constraints is an issue this need to be disabled. + * Accessible from erts_debug:lock_counters({copy_save, bool()}). + * Default: off. + * */ #include "sys.h" @@ -74,6 +88,7 @@ #define ERTS_LCNT_OPT_SUSPEND (((Uint16) 1) << 0) #define ERTS_LCNT_OPT_LOCATION (((Uint16) 1) << 1) #define ERTS_LCNT_OPT_PROCLOCK (((Uint16) 1) << 2) +#define ERTS_LCNT_OPT_COPYSAVE (((Uint16) 1) << 3) typedef struct { unsigned long s; diff --git a/erts/emulator/beam/erl_message.c b/erts/emulator/beam/erl_message.c index 81fbdfbd5a..a056fce0c5 100644 --- a/erts/emulator/beam/erl_message.c +++ b/erts/emulator/beam/erl_message.c @@ -1,19 +1,19 @@ /* * %CopyrightBegin% - * - * Copyright Ericsson AB 1997-2009. All Rights Reserved. - * + * + * Copyright Ericsson AB 1997-2010. 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% */ /* @@ -114,12 +114,8 @@ erts_resize_message_buffer(ErlHeapFragment *bp, Uint size, nbp = (ErlHeapFragment*) ERTS_HEAP_REALLOC(ERTS_ALC_T_HEAP_FRAG, (void *) bp, - (sizeof(ErlHeapFragment) - - sizeof(Eterm) - + bp->size*sizeof(Eterm)), - (sizeof(ErlHeapFragment) - - sizeof(Eterm) - + size*sizeof(Eterm))); + ERTS_HEAP_FRAG_SIZE(bp->size), + ERTS_HEAP_FRAG_SIZE(size)); if (bp != nbp) { Uint off_sz = size < nbp->size ? size : nbp->size; Eterm *sp = &bp->mem[0]; @@ -140,7 +136,7 @@ erts_resize_message_buffer(ErlHeapFragment *bp, Uint size, #endif } nbp->size = size; - + nbp->used_size = size; #ifdef HARD_DEBUG for (i = 0; i < brefs_size; i++) @@ -175,9 +171,7 @@ free_message_buffer(ErlHeapFragment* bp) erts_cleanup_offheap(&bp->off_heap); ERTS_HEAP_FREE(ERTS_ALC_T_HEAP_FRAG, (void *) bp, - (sizeof(ErlHeapFragment) - - sizeof(Eterm) - + bp->size*sizeof(Eterm))); + ERTS_HEAP_FRAG_SIZE(bp->size)); } static ERTS_INLINE void diff --git a/erts/emulator/beam/erl_message.h b/erts/emulator/beam/erl_message.h index f14f14a586..5cf7c209bd 100644 --- a/erts/emulator/beam/erl_message.h +++ b/erts/emulator/beam/erl_message.h @@ -1,19 +1,19 @@ /* * %CopyrightBegin% - * - * Copyright Ericsson AB 1997-2009. All Rights Reserved. - * + * + * Copyright Ericsson AB 1997-2010. 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% */ @@ -50,19 +50,10 @@ struct erl_heap_fragment { ErlHeapFragment* next; /* Next heap fragment */ ErlOffHeap off_heap; /* Offset heap data. */ unsigned size; /* Size in words of mem */ + unsigned used_size; /* With terms to be moved to heap by GC */ Eterm mem[1]; /* Data */ }; -#define ERTS_SET_MBUF_HEAP_END(BP, HENDP) \ -do { \ - unsigned real_size__ = (BP)->size; \ - ASSERT((BP)->mem <= (HENDP) && (HENDP) <= (BP)->mem + real_size__); \ - (BP)->size = (HENDP) - (BP)->mem; \ - /* We do not reallocate since buffer *might* be moved. */ \ - /* FIXME: Memory count is wrong, but at least it's almost */ \ - /* right... */ \ -} while (0) - typedef struct erl_mesg { struct erl_mesg* next; /* Next message */ union { @@ -196,10 +187,12 @@ do { \ #define ERTS_HEAP_FRAG_SIZE(DATA_WORDS) \ (sizeof(ErlHeapFragment) - sizeof(Eterm) + (DATA_WORDS)*sizeof(Eterm)) + #define ERTS_INIT_HEAP_FRAG(HEAP_FRAG_P, DATA_WORDS) \ do { \ (HEAP_FRAG_P)->next = NULL; \ (HEAP_FRAG_P)->size = (DATA_WORDS); \ + (HEAP_FRAG_P)->used_size = (DATA_WORDS); \ (HEAP_FRAG_P)->off_heap.mso = NULL; \ (HEAP_FRAG_P)->off_heap.funs = NULL; \ (HEAP_FRAG_P)->off_heap.externals = NULL; \ diff --git a/erts/emulator/beam/erl_nif.c b/erts/emulator/beam/erl_nif.c index fa4454a3f3..585a6c1fdf 100644 --- a/erts/emulator/beam/erl_nif.c +++ b/erts/emulator/beam/erl_nif.c @@ -1,19 +1,19 @@ /* * %CopyrightBegin% - * - * Copyright Ericsson AB 2009. All Rights Reserved. - * + * + * Copyright Ericsson AB 2009-2010. 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% */ /* Erlang Native InterFace @@ -34,16 +34,26 @@ #include "beam_bp.h" #include <limits.h> +#include <stddef.h> /* offsetof */ + + +/* Information about a loaded nif library. + * Each successful call to erlang:load_nif will allocate an instance of + * erl_module_nif. Two calls opening the same library will thus have the same + * 'handle'. + */ +struct erl_module_nif { + void* priv_data; + void* handle; /* "dlopen" */ + struct enif_entry_t* entry; + erts_refc_t rt_cnt; /* number of resource types */ + erts_refc_t rt_dtor_cnt; /* number of resource types with destructors */ + int is_orphan; /* if erlang module has been purged */ +}; -/* -static ERTS_INLINE Eterm* alloc_heap(ErlNifEnv* env, unsigned need) -{ - return HAlloc(env->proc, need); -} -*/ #define MIN_HEAP_FRAG_SZ 200 -static Eterm* alloc_heap_heavy(ErlNifEnv* env, unsigned need); +static Eterm* alloc_heap_heavy(ErlNifEnv* env, unsigned need, Eterm* hp); static ERTS_INLINE Eterm* alloc_heap(ErlNifEnv* env, unsigned need) { @@ -52,43 +62,63 @@ static ERTS_INLINE Eterm* alloc_heap(ErlNifEnv* env, unsigned need) if (env->hp <= env->hp_end) { return hp; } - env->hp = hp; - return alloc_heap_heavy(env,need); + return alloc_heap_heavy(env, need, hp); } -static Eterm* alloc_heap_heavy(ErlNifEnv* env, unsigned need) -{ - Eterm* hp; - - if (env->heap_frag_sz == 0) { +static Eterm* alloc_heap_heavy(ErlNifEnv* env, unsigned need, Eterm* hp) +{ + unsigned frag_sz; + env->hp = hp; + if (env->heap_frag == NULL) { ASSERT(HEAP_LIMIT(env->proc) == env->hp_end); HEAP_TOP(env->proc) = env->hp; - env->heap_frag_sz = need + MIN_HEAP_FRAG_SZ; } else { HRelease(env->proc, env->hp_end, env->hp); - env->heap_frag_sz *= 2; } - hp = erts_heap_alloc(env->proc, env->heap_frag_sz); + frag_sz = need + MIN_HEAP_FRAG_SZ; + hp = erts_heap_alloc(env->proc, frag_sz); env->hp = hp + need; - env->hp_end = hp + env->heap_frag_sz; + env->hp_end = hp + frag_sz; + env->heap_frag = MBUF(env->proc); return hp; } -void erts_pre_nif(ErlNifEnv* env, Process* p, void* nif_data) +void erts_pre_nif(ErlNifEnv* env, Process* p, struct erl_module_nif* mod_nif) { - env->nif_data = nif_data; + env->mod_nif = mod_nif; env->proc = p; env->hp = HEAP_TOP(p); env->hp_end = HEAP_LIMIT(p); - env->heap_frag_sz = 0; + env->heap_frag = NULL; + env->fpe_was_unmasked = erts_block_fpe(); + env->tmp_obj_list = NULL; +} + +static void pre_nif_noproc(ErlNifEnv* env, struct erl_module_nif* mod_nif) +{ + env->mod_nif = mod_nif; + env->proc = NULL; + env->hp = NULL; + env->hp_end = NULL; + env->heap_frag = NULL; env->fpe_was_unmasked = erts_block_fpe(); + env->tmp_obj_list = NULL; +} + +static ERTS_INLINE void free_tmp_objs(ErlNifEnv* env) +{ + while (env->tmp_obj_list != NULL) { + struct enif_tmp_obj_t* free_me = env->tmp_obj_list; + env->tmp_obj_list = free_me->next; + free_me->dtor(free_me); + } } void erts_post_nif(ErlNifEnv* env) { erts_unblock_fpe(env->fpe_was_unmasked); - if (env->heap_frag_sz == 0) { + if (env->heap_frag == NULL) { ASSERT(env->hp_end == HEAP_LIMIT(env->proc)); ASSERT(env->hp >= HEAP_TOP(env->proc)); ASSERT(env->hp <= HEAP_LIMIT(env->proc)); @@ -96,14 +126,60 @@ void erts_post_nif(ErlNifEnv* env) } else { ASSERT(env->hp_end != HEAP_LIMIT(env->proc)); - ASSERT(env->hp_end - env->hp <= env->heap_frag_sz); + ASSERT(env->hp_end - env->hp <= env->heap_frag->size); HRelease(env->proc, env->hp_end, env->hp); } + free_tmp_objs(env); +} + +static void post_nif_noproc(ErlNifEnv* env) +{ + erts_unblock_fpe(env->fpe_was_unmasked); + free_tmp_objs(env); } -void* enif_get_data(ErlNifEnv* env) + +/* Flush out our cached heap pointers to allow an ordinary HAlloc +*/ +static void enable_halloc(ErlNifEnv* env) { - return env->nif_data; + if (env->heap_frag == NULL) { + ASSERT(env->hp_end == HEAP_LIMIT(env->proc)); + ASSERT(env->hp >= HEAP_TOP(env->proc)); + ASSERT(env->hp <= HEAP_LIMIT(env->proc)); + HEAP_TOP(env->proc) = env->hp; + } + else { + ASSERT(env->hp_end != HEAP_LIMIT(env->proc)); + ASSERT(env->hp_end - env->hp <= env->heap_frag->size); + HRelease(env->proc, env->hp_end, env->hp); + } +} + +/* Restore cached heap pointers +*/ +static void disable_halloc(ErlNifEnv* env) +{ + if (env->heap_frag == NULL) { + ASSERT(env->hp_end == HEAP_LIMIT(env->proc)); + ASSERT(env->hp <= HEAP_TOP(env->proc)); + ASSERT(env->hp <= HEAP_LIMIT(env->proc)); + env->hp = HEAP_TOP(env->proc); + } + else { + ASSERT(env->hp_end != HEAP_LIMIT(env->proc)); + ASSERT(env->hp_end - env->hp <= env->heap_frag->size); + env->heap_frag = MBUF(env->proc); + ASSERT(env->heap_frag != NULL); + env->hp = env->heap_frag->mem + env->heap_frag->used_size; + env->hp_end = env->heap_frag->mem + env->heap_frag->size; + } +} + + +void* enif_priv_data(ErlNifEnv* env) +{ + return env->mod_nif->priv_data; } void* enif_alloc(ErlNifEnv* env, size_t size) @@ -111,31 +187,114 @@ void* enif_alloc(ErlNifEnv* env, size_t size) return erts_alloc_fnf(ERTS_ALC_T_NIF, (Uint) size); } +void* enif_realloc(ErlNifEnv* env, void* ptr, size_t size) +{ + return erts_realloc_fnf(ERTS_ALC_T_NIF, ptr, size); +} + void enif_free(ErlNifEnv* env, void* ptr) { erts_free(ERTS_ALC_T_NIF, ptr); } +int enif_is_atom(ErlNifEnv* env, ERL_NIF_TERM term) +{ + return is_atom(term); +} int enif_is_binary(ErlNifEnv* env, ERL_NIF_TERM term) { return is_binary(term) && (binary_bitsize(term) % 8 == 0); } - + +int enif_is_empty_list(ErlNifEnv* env, ERL_NIF_TERM term) +{ + return is_nil(term); +} + +int enif_is_fun(ErlNifEnv* env, ERL_NIF_TERM term) +{ + return is_fun(term); +} + +int enif_is_pid(ErlNifEnv* env, ERL_NIF_TERM term) +{ + return is_pid(term); +} + +int enif_is_port(ErlNifEnv* env, ERL_NIF_TERM term) +{ + return is_port(term); +} + +int enif_is_ref(ErlNifEnv* env, ERL_NIF_TERM term) +{ + return is_ref(term); +} + +static void aligned_binary_dtor(struct enif_tmp_obj_t* obj) +{ + erts_free_aligned_binary_bytes((byte*)obj); +} int enif_inspect_binary(ErlNifEnv* env, Eterm bin_term, ErlNifBinary* bin) { - bin->tmp_alloc = NULL; - bin->data = erts_get_aligned_binary_bytes(bin_term, &bin->tmp_alloc); + union { + struct enif_tmp_obj_t* tmp; + byte* raw_ptr; + }u; + u.tmp = NULL; + bin->data = erts_get_aligned_binary_bytes_extra(bin_term, &u.raw_ptr, + sizeof(struct enif_tmp_obj_t)); if (bin->data == NULL) { return 0; } + if (u.tmp != NULL) { + u.tmp->next = env->tmp_obj_list; + u.tmp->dtor = &aligned_binary_dtor; + env->tmp_obj_list = u.tmp; + } bin->bin_term = bin_term; bin->size = binary_size(bin_term); bin->ref_bin = NULL; return 1; } +static void tmp_alloc_dtor(struct enif_tmp_obj_t* obj) +{ + erts_free(ERTS_ALC_T_TMP, obj); +} + +int enif_inspect_iolist_as_binary(ErlNifEnv* env, Eterm term, ErlNifBinary* bin) +{ + struct enif_tmp_obj_t* tobj; + int sz; + if (is_binary(term)) { + return enif_inspect_binary(env,term,bin); + } + if (is_nil(term)) { + bin->data = (unsigned char*) &bin->data; /* dummy non-NULL */ + bin->size = 0; + bin->bin_term = THE_NON_VALUE; + bin->ref_bin = NULL; + return 1; + } + if ((sz = io_list_len(term)) < 0) { + return 0; + } + + tobj = erts_alloc(ERTS_ALC_T_TMP, sz + sizeof(struct enif_tmp_obj_t)); + tobj->next = env->tmp_obj_list; + tobj->dtor = &tmp_alloc_dtor; + env->tmp_obj_list = tobj; + + bin->data = (unsigned char*) &tobj[1]; + bin->size = sz; + bin->bin_term = THE_NON_VALUE; + bin->ref_bin = NULL; + io_list_to_buf(term, (char*) bin->data, sz); + return 1; +} int enif_alloc_binary(ErlNifEnv* env, unsigned size, ErlNifBinary* bin) { @@ -152,41 +311,115 @@ int enif_alloc_binary(ErlNifEnv* env, unsigned size, ErlNifBinary* bin) bin->size = size; bin->data = (unsigned char*) refbin->orig_bytes; bin->bin_term = THE_NON_VALUE; - bin->tmp_alloc = NULL; bin->ref_bin = refbin; return 1; } -void enif_release_binary(ErlNifEnv* env, ErlNifBinary* bin) +int enif_realloc_binary(ErlNifEnv* env, ErlNifBinary* bin, unsigned size) { - if (bin->ref_bin == NULL) { - erts_free_aligned_binary_bytes(bin->tmp_alloc); + if (bin->ref_bin != NULL) { + Binary* oldbin; + Binary* newbin; + + oldbin = (Binary*) bin->ref_bin; + newbin = (Binary *) erts_bin_realloc_fnf(oldbin, size); + if (!newbin) { + return 0; + } + newbin->orig_size = size; + bin->ref_bin = newbin; + bin->data = (unsigned char*) newbin->orig_bytes; + bin->size = size; } else { + unsigned char* old_data = bin->data; + unsigned cpy_sz = (size < bin->size ? size : bin->size); + enif_alloc_binary(env, size, bin); + sys_memcpy(bin->data, old_data, cpy_sz); + } + return 1; +} + + +void enif_release_binary(ErlNifEnv* env, ErlNifBinary* bin) +{ + if (bin->ref_bin != NULL) { Binary* refbin = bin->ref_bin; - ASSERT(bin->tmp_alloc == NULL); ASSERT(bin->bin_term == THE_NON_VALUE); if (erts_refc_dectest(&refbin->refc, 0) == 0) { erts_bin_free(refbin); } } #ifdef DEBUG + bin->data = NULL; bin->bin_term = THE_NON_VALUE; - bin->tmp_alloc = NULL; bin->ref_bin = NULL; #endif } +int enif_is_identical(ErlNifEnv* env, Eterm lhs, Eterm rhs) +{ + return EQ(lhs,rhs); +} + +int enif_compare(ErlNifEnv* env, Eterm lhs, Eterm rhs) +{ + return cmp(lhs,rhs); +} + +int enif_get_tuple(ErlNifEnv* env, Eterm tpl, int* arity, const Eterm** array) +{ + Eterm* ptr; + if (is_not_tuple(tpl)) { + return 0; + } + ptr = tuple_val(tpl); + *arity = arityval(*ptr); + *array = ptr+1; + return 1; +} + +int enif_get_string(ErlNifEnv *env, ERL_NIF_TERM list, char* buf, unsigned len, + ErlNifCharEncoding encoding) +{ + Eterm* listptr; + int n = 0; + + ASSERT(encoding == ERL_NIF_LATIN1); + if (len < 1) { + return 0; + } + while (is_not_nil(list)) { + if (is_not_list(list)) { + buf[n] = '\0'; + return 0; + } + listptr = list_val(list); + + if (!is_byte(*listptr)) { + buf[n] = '\0'; + return 0; + } + buf[n++] = unsigned_val(*listptr); + if (n >= len) { + buf[n-1] = '\0'; /* truncate */ + return -len; + } + list = CDR(listptr); + } + buf[n] = '\0'; + return n + 1; +} + Eterm enif_make_binary(ErlNifEnv* env, ErlNifBinary* bin) { - if (bin->ref_bin == NULL) { - erts_free_aligned_binary_bytes(bin->tmp_alloc); + if (bin->bin_term != THE_NON_VALUE) { return bin->bin_term; } - else { + else if (bin->ref_bin != NULL) { Binary* bptr = bin->ref_bin; ProcBin* pb; - ASSERT(bin->tmp_alloc == NULL); + Eterm bin_term; /* !! Copy-paste from new_binary() !! */ pb = (ProcBin *) alloc_heap(env, PROC_BIN_SIZE); @@ -199,20 +432,72 @@ Eterm enif_make_binary(ErlNifEnv* env, ErlNifBinary* bin) pb->flags = 0; MSO(env->proc).overhead += pb->size / sizeof(Eterm); - return make_binary(pb); + bin_term = make_binary(pb); + if (erts_refc_read(&bptr->refc, 1) == 1) { + /* Total ownership transfer */ + bin->ref_bin = NULL; + bin->bin_term = bin_term; + } + return bin_term; + } + else { + enable_halloc(env); + bin->bin_term = new_binary(env->proc, bin->data, bin->size); + disable_halloc(env); + return bin->bin_term; } } -ERL_NIF_TERM enif_make_badarg(ErlNifEnv* env) +Eterm enif_make_sub_binary(ErlNifEnv* env, ERL_NIF_TERM bin_term, + unsigned pos, unsigned size) +{ + ErlSubBin* sb; + Eterm orig; + Uint offset, bit_offset, bit_size; + unsigned src_size; + + ASSERT(is_binary(bin_term)); + src_size = binary_size(bin_term); + ASSERT(pos <= src_size); + ASSERT(size <= src_size); + ASSERT(pos + size <= src_size); + sb = (ErlSubBin*) alloc_heap(env, ERL_SUB_BIN_SIZE); + ERTS_GET_REAL_BIN(bin_term, orig, offset, bit_offset, bit_size); + sb->thing_word = HEADER_SUB_BIN; + sb->size = size; + sb->offs = offset + pos; + sb->orig = orig; + sb->bitoffs = bit_offset; + sb->bitsize = 0; + sb->is_writable = 0; + return make_binary(sb); +} + + +Eterm enif_make_badarg(ErlNifEnv* env) { BIF_ERROR(env->proc, BADARG); } +int enif_get_atom(ErlNifEnv* env, Eterm atom, char* buf, unsigned len) +{ + Atom* ap; + if (is_not_atom(atom)) { + return 0; + } + ap = atom_tab(atom_val(atom)); + if (ap->len+1 > len) { + return 0; + } + sys_memcpy(buf, ap->name, ap->len); + buf[ap->len] = '\0'; + return ap->len + 1; +} int enif_get_int(ErlNifEnv* env, Eterm term, int* ip) { #if SIZEOF_INT == SIZEOF_VOID_P - return term_to_Sint(term, ip); + return term_to_Sint(term, (Sint*)ip); #elif SIZEOF_LONG == SIZEOF_VOID_P Sint i; if (!term_to_Sint(term, &i) || i < INT_MIN || i > INT_MAX) { @@ -225,6 +510,29 @@ int enif_get_int(ErlNifEnv* env, Eterm term, int* ip) #endif } +int enif_get_uint(ErlNifEnv* env, Eterm term, unsigned* ip) +{ +#if SIZEOF_INT == SIZEOF_VOID_P + return term_to_Uint(term, (Uint*)ip); +#elif SIZEOF_LONG == SIZEOF_VOID_P + Uint i; + if (!term_to_Uint(term, &i) || i > UINT_MAX) { + return 0; + } + *ip = (unsigned) i; + return 1; +#endif +} + +int enif_get_long(ErlNifEnv* env, Eterm term, long* ip) +{ +#if SIZEOF_LONG == SIZEOF_VOID_P + return term_to_Sint(term, ip); +#else +# error Unknown long word size +#endif +} + int enif_get_ulong(ErlNifEnv* env, Eterm term, unsigned long* ip) { #if SIZEOF_LONG == SIZEOF_VOID_P @@ -234,6 +542,17 @@ int enif_get_ulong(ErlNifEnv* env, Eterm term, unsigned long* ip) #endif } +int enif_get_double(ErlNifEnv* env, Eterm term, double* dp) +{ + FloatDef f; + if (is_not_float(term)) { + return 0; + } + GET_DOUBLE(term, f); + *dp = f.fd; + return 1; +} + int enif_get_list_cell(ErlNifEnv* env, Eterm term, Eterm* head, Eterm* tail) { Eterm* val; @@ -253,26 +572,46 @@ ERL_NIF_TERM enif_make_int(ErlNifEnv* env, int i) #endif } -ERL_NIF_TERM enif_make_ulong(ErlNifEnv* env, unsigned long i) +ERL_NIF_TERM enif_make_uint(ErlNifEnv* env, unsigned i) { -#if SIZEOF_LONG == SIZEOF_VOID_P - Eterm* hp; - Uint sz = 0; - erts_bld_uint(NULL, &sz, i); - hp = alloc_heap(env,sz); - return erts_bld_uint(&hp, NULL, i); -#else +#if SIZEOF_INT == SIZEOF_VOID_P + return IS_USMALL(0,i) ? make_small(i) : uint_to_big(i,alloc_heap(env,2)); +#elif SIZEOF_LONG == SIZEOF_VOID_P + return make_small(i); +#endif +} + +ERL_NIF_TERM enif_make_long(ErlNifEnv* env, long i) +{ +#if SIZEOF_LONG != SIZEOF_VOID_P # error Unknown long word size #endif + return IS_SSMALL(i) ? make_small(i) : small_to_big(i, alloc_heap(env,2)); +} +ERL_NIF_TERM enif_make_ulong(ErlNifEnv* env, unsigned long i) +{ + return IS_USMALL(0,i) ? make_small(i) : uint_to_big(i,alloc_heap(env,2)); } +ERL_NIF_TERM enif_make_double(ErlNifEnv* env, double d) +{ + Eterm* hp = alloc_heap(env,FLOAT_SIZE_OBJECT); + FloatDef f; + f.fd = d; + PUT_DOUBLE(f, hp); + return make_float(hp); +} ERL_NIF_TERM enif_make_atom(ErlNifEnv* env, const char* name) { return am_atom_put(name, sys_strlen(name)); } +int enif_make_existing_atom(ErlNifEnv* env, const char* name, ERL_NIF_TERM* atom) +{ + return erts_atom_get(name, sys_strlen(name), atom); +} ERL_NIF_TERM enif_make_tuple(ErlNifEnv* env, unsigned cnt, ...) { @@ -289,6 +628,19 @@ ERL_NIF_TERM enif_make_tuple(ErlNifEnv* env, unsigned cnt, ...) return ret; } +ERL_NIF_TERM enif_make_tuple_from_array(ErlNifEnv* env, const ERL_NIF_TERM arr[], unsigned cnt) +{ + Eterm* hp = alloc_heap(env,cnt+1); + Eterm ret = make_tuple(hp); + const Eterm* src = arr; + + *hp++ = make_arityval(cnt); + while (cnt--) { + *hp++ = *src++; + } + return ret; +} + ERL_NIF_TERM enif_make_list_cell(ErlNifEnv* env, Eterm car, Eterm cdr) { Eterm* hp = alloc_heap(env,2); @@ -318,15 +670,297 @@ ERL_NIF_TERM enif_make_list(ErlNifEnv* env, unsigned cnt, ...) return ret; } -ERL_NIF_TERM enif_make_string(ErlNifEnv* env, const char* string) +ERL_NIF_TERM enif_make_list_from_array(ErlNifEnv* env, const ERL_NIF_TERM arr[], unsigned cnt) +{ + Eterm* hp = alloc_heap(env,cnt*2); + Eterm ret = make_list(hp); + Eterm* last = &ret; + const Eterm* src = arr; + + while (cnt--) { + *last = make_list(hp); + *hp = *src++; + last = ++hp; + ++hp; + } + *last = NIL; + return ret; +} + +ERL_NIF_TERM enif_make_string(ErlNifEnv* env, const char* string, + ErlNifCharEncoding encoding) { - Sint n = strlen(string); + Sint n = sys_strlen(string); Eterm* hp = alloc_heap(env,n*2); + ASSERT(encoding == ERL_NIF_LATIN1); return erts_bld_string_n(&hp,NULL,string,n); } +ERL_NIF_TERM enif_make_ref(ErlNifEnv* env) +{ + Eterm* hp = alloc_heap(env, REF_THING_SIZE); + return erts_make_ref_in_buffer(hp); +} + +void enif_system_info(ErlNifSysInfo *sip, size_t si_size) +{ + driver_system_info(sip, si_size); +} + + +ErlNifMutex* enif_mutex_create(char *name) { return erl_drv_mutex_create(name); } +void enif_mutex_destroy(ErlNifMutex *mtx) { erl_drv_mutex_destroy(mtx); } +int enif_mutex_trylock(ErlNifMutex *mtx) { return erl_drv_mutex_trylock(mtx); } +void enif_mutex_lock(ErlNifMutex *mtx) { erl_drv_mutex_lock(mtx); } +void enif_mutex_unlock(ErlNifMutex *mtx) { erl_drv_mutex_unlock(mtx); } +ErlNifCond* enif_cond_create(char *name) { return erl_drv_cond_create(name); } +void enif_cond_destroy(ErlNifCond *cnd) { erl_drv_cond_destroy(cnd); } +void enif_cond_signal(ErlNifCond *cnd) { erl_drv_cond_signal(cnd); } +void enif_cond_broadcast(ErlNifCond *cnd) { erl_drv_cond_broadcast(cnd); } +void enif_cond_wait(ErlNifCond *cnd, ErlNifMutex *mtx) { erl_drv_cond_wait(cnd,mtx); } +ErlNifRWLock* enif_rwlock_create(char *name) { return erl_drv_rwlock_create(name); } +void enif_rwlock_destroy(ErlNifRWLock *rwlck) { erl_drv_rwlock_destroy(rwlck); } +int enif_rwlock_tryrlock(ErlNifRWLock *rwlck) { return erl_drv_rwlock_tryrlock(rwlck); } +void enif_rwlock_rlock(ErlNifRWLock *rwlck) { erl_drv_rwlock_rlock(rwlck); } +void enif_rwlock_runlock(ErlNifRWLock *rwlck) { erl_drv_rwlock_runlock(rwlck); } +int enif_rwlock_tryrwlock(ErlNifRWLock *rwlck) { return erl_drv_rwlock_tryrwlock(rwlck); } +void enif_rwlock_rwlock(ErlNifRWLock *rwlck) { erl_drv_rwlock_rwlock(rwlck); } +void enif_rwlock_rwunlock(ErlNifRWLock *rwlck) { erl_drv_rwlock_rwunlock(rwlck); } +int enif_tsd_key_create(char *name, ErlNifTSDKey *key) { return erl_drv_tsd_key_create(name,key); } +void enif_tsd_key_destroy(ErlNifTSDKey key) { erl_drv_tsd_key_destroy(key); } +void enif_tsd_set(ErlNifTSDKey key, void *data) { erl_drv_tsd_set(key,data); } +void* enif_tsd_get(ErlNifTSDKey key) { return erl_drv_tsd_get(key); } +ErlNifThreadOpts* enif_thread_opts_create(char *name) { return (ErlNifThreadOpts*) erl_drv_thread_opts_create(name); } +void enif_thread_opts_destroy(ErlNifThreadOpts *opts) { erl_drv_thread_opts_destroy((ErlDrvThreadOpts*)opts); } +int enif_thread_create(char *name, ErlNifTid *tid, void* (*func)(void *), + void *args, ErlNifThreadOpts *opts) { + return erl_drv_thread_create(name,tid,func,args,(ErlDrvThreadOpts*)opts); +} +ErlNifTid enif_thread_self(void) { return erl_drv_thread_self(); } +int enif_equal_tids(ErlNifTid tid1, ErlNifTid tid2) { return erl_drv_equal_tids(tid1,tid2); } +void enif_thread_exit(void *resp) { erl_drv_thread_exit(resp); } +int enif_thread_join(ErlNifTid tid, void **respp) { return erl_drv_thread_join(tid,respp); } + +int enif_fprintf(void* filep, const char* format, ...) +{ + int ret; + va_list arglist; + va_start(arglist, format); + ret = erts_vfprintf((FILE*)filep, format, arglist); + va_end(arglist); + return ret; +} + +/*********************************************************** + ** Memory managed (GC'ed) "resource" objects ** + ***********************************************************/ + + +struct enif_resource_type_t +{ + struct enif_resource_type_t* next; /* list of all resource types */ + struct enif_resource_type_t* prev; + struct erl_module_nif* owner; /* that created this type and thus implements the destructor*/ + ErlNifResourceDtor* dtor; /* user destructor function */ + erts_refc_t refc; /* num of resources of this type (HOTSPOT warning) + +1 for active erl_module_nif */ + char name[1]; +}; + +/* dummy node in circular list */ +struct enif_resource_type_t resource_type_list; + +typedef struct enif_resource_t +{ + struct enif_resource_type_t* type; +#ifdef DEBUG + erts_refc_t nif_refc; +#endif + char data[1]; +}ErlNifResource; + +#define SIZEOF_ErlNifResource(SIZE) (offsetof(ErlNifResource,data) + (SIZE)) +#define DATA_TO_RESOURCE(PTR) ((ErlNifResource*)((char*)(PTR) - offsetof(ErlNifResource,data))) + +static ErlNifResourceType* find_resource_type(const char* name) +{ + ErlNifResourceType* type; + for (type = resource_type_list.next; + type != &resource_type_list; + type = type->next) { + + if (sys_strcmp(type->name, name) == 0) { + return type; + } + } + return NULL; +} + +#define in_area(ptr,start,nbytes) \ + ((unsigned long)((char*)(ptr) - (char*)(start)) < (nbytes)) + + +static void close_lib(struct erl_module_nif* lib) +{ + ASSERT(lib != NULL); + ASSERT(lib->handle != NULL); + ASSERT(erts_refc_read(&lib->rt_dtor_cnt,0) == 0); + + if (lib->entry != NULL && lib->entry->unload != NULL) { + ErlNifEnv env; + pre_nif_noproc(&env, lib); + lib->entry->unload(&env, lib->priv_data); + post_nif_noproc(&env); + } + erts_sys_ddll_close(lib->handle); + lib->handle = NULL; +} +static void steal_resource_type(ErlNifResourceType* type) +{ + struct erl_module_nif* lib = type->owner; + if (type->dtor != NULL + && erts_refc_dectest(&lib->rt_dtor_cnt, 0) == 0 + && lib->is_orphan) { + /* last type with destructor gone, close orphan lib */ + + close_lib(lib); + } + if (erts_refc_dectest(&lib->rt_cnt, 0) == 0 + && lib->is_orphan) { + erts_free(ERTS_ALC_T_NIF, lib); + } +} + +ErlNifResourceType* +enif_open_resource_type(ErlNifEnv* env, const char* type_name, + ErlNifResourceDtor* dtor, + enum ErlNifResourceFlags flags, + enum ErlNifResourceFlags* tried) +{ + ErlNifResourceType* type = find_resource_type(type_name); + enum ErlNifResourceFlags op = flags; + ASSERT(erts_smp_is_system_blocked(0)); + if (type == NULL) { + if (flags & ERL_NIF_RT_CREATE) { + type = erts_alloc(ERTS_ALC_T_NIF, + sizeof(struct enif_resource_type_t) + + sys_strlen(type_name)); + type->dtor = dtor; + sys_strcpy(type->name, type_name); + erts_refc_init(&type->refc, 1); + type->owner = env->mod_nif; + type->prev = &resource_type_list; + type->next = resource_type_list.next; + type->next->prev = type; + type->prev->next = type; + op = ERL_NIF_RT_CREATE; + } + } + else { + if (flags & ERL_NIF_RT_TAKEOVER) { + steal_resource_type(type); + op = ERL_NIF_RT_TAKEOVER; + } + else { + type = NULL; + } + } + if (type != NULL) { + type->owner = env->mod_nif; + type->dtor = dtor; + if (type->dtor != NULL) { + erts_refc_inc(&type->owner->rt_dtor_cnt, 1); + } + erts_refc_inc(&type->owner->rt_cnt, 1); + } + if (tried != NULL) { + *tried = op; + } + return type; +} + +static void nif_resource_dtor(Binary* bin) +{ + ErlNifResource* resource = (ErlNifResource*) ERTS_MAGIC_BIN_DATA(bin); + ErlNifResourceType* type = resource->type; + ASSERT(ERTS_MAGIC_BIN_DESTRUCTOR(bin) == &nif_resource_dtor); + + if (type->dtor != NULL) { + ErlNifEnv env; + pre_nif_noproc(&env, type->owner); + type->dtor(&env,resource->data); + post_nif_noproc(&env); + } + if (erts_refc_dectest(&type->refc, 0) == 0) { + ASSERT(type->next == NULL); + ASSERT(type->owner != NULL); + ASSERT(type->owner->is_orphan); + steal_resource_type(type); + erts_free(ERTS_ALC_T_NIF, type); + } +} + +void* enif_alloc_resource(ErlNifEnv* env, ErlNifResourceType* type, unsigned size) +{ + Binary* bin = erts_create_magic_binary(SIZEOF_ErlNifResource(size), &nif_resource_dtor); + ErlNifResource* resource = ERTS_MAGIC_BIN_DATA(bin); + resource->type = type; + erts_refc_inc(&bin->refc, 1); +#ifdef DEBUG + erts_refc_init(&resource->nif_refc, 1); +#endif + erts_refc_inc(&resource->type->refc, 2); + return resource->data; +} + +void enif_release_resource(ErlNifEnv* env, void* obj) +{ + ErlNifResource* resource = DATA_TO_RESOURCE(obj); + ErtsBinary* bin = ERTS_MAGIC_BIN_FROM_DATA(resource); + + ASSERT(ERTS_MAGIC_BIN_DESTRUCTOR(bin) == &nif_resource_dtor); +#ifdef DEBUG + erts_refc_dec(&resource->nif_refc, 0); +#endif + if (erts_refc_dectest(&bin->binary.refc, 0) == 0) { + erts_bin_free(&bin->binary); + } +} + +ERL_NIF_TERM enif_make_resource(ErlNifEnv* env, void* obj) +{ + ErlNifResource* resource = DATA_TO_RESOURCE(obj); + ErtsBinary* bin = ERTS_MAGIC_BIN_FROM_DATA(resource); + Eterm* hp = alloc_heap(env,PROC_BIN_SIZE); + return erts_mk_magic_binary_term(&hp, &MSO(env->proc), &bin->binary); +} + +int enif_get_resource(ErlNifEnv* env, ERL_NIF_TERM term, ErlNifResourceType* type, + void** objp) +{ + Binary* mbin; + ErlNifResource* resource; + if (!ERTS_TERM_IS_MAGIC_BINARY(term)) { + return 0; + } + mbin = ((ProcBin*) binary_val(term))->val; + resource = (ErlNifResource*) ERTS_MAGIC_BIN_DATA(mbin); + if (ERTS_MAGIC_BIN_DESTRUCTOR(mbin) != &nif_resource_dtor + || resource->type != type) { + return 0; + } + *objp = resource->data; + return 1; +} + +unsigned enif_sizeof_resource(ErlNifEnv* env, void* obj) +{ + ErlNifResource* resource = DATA_TO_RESOURCE(obj); + Binary* bin = &ERTS_MAGIC_BIN_FROM_DATA(resource)->binary; + return ERTS_MAGIC_BIN_DATA_SIZE(bin) - offsetof(ErlNifResource,data); +} /*************************************************************************** ** load_nif/2 ** @@ -349,10 +983,7 @@ static Uint** get_func_pp(Eterm* mod_code, Eterm f_atom, unsigned arity) return NULL; } -#define in_area(ptr,start,nbytes) \ - ((unsigned long)((char*)(ptr) - (char*)(start)) < (nbytes)) - -static void refresh_cached_nif_data(Eterm* mod_code, +/*static void refresh_cached_nif_data(Eterm* mod_code, struct erl_module_nif* mod_nif) { int i; @@ -361,11 +992,11 @@ static void refresh_cached_nif_data(Eterm* mod_code, ErlNifFunc* func = &mod_nif->entry->funcs[i]; Uint* code_ptr; - erts_atom_get(func->name, strlen(func->name), &f_atom); + erts_atom_get(func->name, sys_strlen(func->name), &f_atom); code_ptr = *get_func_pp(mod_code, f_atom, func->arity); - code_ptr[5+2] = (Uint) mod_nif->data; + code_ptr[5+2] = (Uint) mod_nif->priv_data; } -} +}*/ static Eterm mkatom(const char *str) { @@ -411,6 +1042,18 @@ Eterm erts_nif_taints(Process* p) return list; } +void erts_print_nif_taints(int to, void* to_arg) +{ + struct tainted_module_t* t; + const char* delim = ""; + for (t=first_tainted_module ; t!=NULL; t=t->next) { + const Atom* atom = atom_tab(atom_val(t->module_atom)); + erts_print(to,to_arg,"%s%.*s", delim, atom->len, atom->name); + delim = ","; + } + erts_print(to,to_arg,"\n"); +} + static Eterm load_nif_error(Process* p, const char* atom, const char* format, ...) { @@ -428,7 +1071,8 @@ static Eterm load_nif_error(Process* p, const char* atom, const char* format, .. for (;;) { Eterm txt = erts_bld_string_n(hpp, &sz, dsbufp->str, dsbufp->str_len); - ret = erts_bld_tuple(hpp, szp, 3, am_error, mkatom(atom), txt); + ret = erts_bld_tuple(hpp, szp, 2, am_error, + erts_bld_tuple(hpp, szp, 2, mkatom(atom), txt)); if (hpp != NULL) { break; } @@ -458,6 +1102,7 @@ BIF_RETTYPE load_nif_2(BIF_ALIST_2) ErtsSysDdllError errdesc = ERTS_SYS_DDLL_ERROR_INIT; Eterm ret = am_ok; int veto; + struct erl_module_nif* lib = NULL; len = intlist_to_buf(BIF_ARG_1, lib_name, sizeof(lib_name)-1); if (len < 1) { @@ -489,8 +1134,13 @@ BIF_RETTYPE load_nif_2(BIF_ALIST_2) "module '%T' not allowed", mod_atom); } else if ((err=erts_sys_ddll_open2(lib_name, &handle, &errdesc)) != ERL_DE_NO_ERROR) { - ret = load_nif_error(BIF_P, "load_failed", "Failed to load NIF library" - " %s: '%s'", lib_name, errdesc.str); + const char slogan[] = "Failed to load NIF library"; + if (strstr(errdesc.str, lib_name) != NULL) { + ret = load_nif_error(BIF_P, "load_failed", "%s: '%s'", slogan, errdesc.str); + } + else { + ret = load_nif_error(BIF_P, "load_failed", "%s %s: '%s'", slogan, lib_name, errdesc.str); + } } else if (erts_sys_ddll_load_nif_init(handle, &init_func, &errdesc) != ERL_DE_NO_ERROR) { ret = load_nif_error(BIF_P, bad_lib, "Failed to find library init" @@ -517,12 +1167,8 @@ BIF_RETTYPE load_nif_2(BIF_ALIST_2) for (i=0; i < entry->num_of_funcs && ret==am_ok; i++) { Uint** code_pp; ErlNifFunc* f = &entry->funcs[i]; - if (f->arity > 3) { - ret = load_nif_error(BIF_P,bad_lib,"Function arity too high for NIF %s/%u", - f->name, f->arity); - } - else if (!erts_atom_get(f->name, strlen(f->name), &f_atom) - || (code_pp = get_func_pp(mod->code, f_atom, f->arity))==NULL) { + if (!erts_atom_get(f->name, sys_strlen(f->name), &f_atom) + || (code_pp = get_func_pp(mod->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); } @@ -542,16 +1188,27 @@ BIF_RETTYPE load_nif_2(BIF_ALIST_2) /* Call load, reload or upgrade: */ - if (mod->nif.handle != NULL) { /* Reload */ + + + lib = erts_alloc(ERTS_ALC_T_NIF, sizeof(struct erl_module_nif)); + lib->handle = handle; + lib->entry = entry; + erts_refc_init(&lib->rt_cnt, 0); + erts_refc_init(&lib->rt_dtor_cnt, 0); + lib->is_orphan = 0; + env.mod_nif = lib; + if (mod->nif != NULL) { /* Reload */ int k; - ASSERT(mod->nif.entry != NULL); + lib->priv_data = mod->nif->priv_data; + + ASSERT(mod->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->nif->entry->num_of_funcs; k++) { + ErlNifFunc* old_func = &mod->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) { @@ -565,37 +1222,39 @@ BIF_RETTYPE load_nif_2(BIF_ALIST_2) goto error; } } - erts_pre_nif(&env, BIF_P, mod->nif.data); - veto = entry->reload(&env, &env.nif_data, BIF_ARG_2); + erts_pre_nif(&env, BIF_P, lib); + veto = entry->reload(&env, &lib->priv_data, BIF_ARG_2); erts_post_nif(&env); if (veto) { ret = load_nif_error(BIF_P, reload, "Library reload-call unsuccessful."); } else { - erts_sys_ddll_close(mod->nif.handle); + mod->nif->entry = NULL; /* to prevent 'unload' callback */ + erts_unload_nif(mod->nif); } } else { - if (mod->old_nif.handle != NULL) { /* Upgrade */ - void* prev_old_data = mod->old_nif.data; + lib->priv_data = NULL; + 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, NULL); - veto = entry->upgrade(&env, &env.nif_data, &mod->old_nif.data, BIF_ARG_2); + erts_pre_nif(&env, BIF_P, lib); + veto = entry->upgrade(&env, &lib->priv_data, &mod->old_nif->priv_data, BIF_ARG_2); erts_post_nif(&env); if (veto) { - mod->old_nif.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.data != prev_old_data) { - refresh_cached_nif_data(mod->old_code, &mod->old_nif); - } + /*else if (mod->old_nif->priv_data != prev_old_data) { + refresh_cached_nif_data(mod->old_code, mod->old_nif); + }*/ } else if (entry->load != NULL) { /* Initial load */ - erts_pre_nif(&env, BIF_P, NULL); - veto = entry->load(&env, &env.nif_data, BIF_ARG_2); + erts_pre_nif(&env, BIF_P, lib); + veto = entry->load(&env, &lib->priv_data, BIF_ARG_2); erts_post_nif(&env); if (veto) { ret = load_nif_error(BIF_P, "load", "Library load-call unsuccessful."); @@ -606,28 +1265,30 @@ BIF_RETTYPE load_nif_2(BIF_ALIST_2) /* ** Everything ok, patch the beam code with op_call_nif */ - mod->nif.data = env.nif_data; - mod->nif.handle = handle; - mod->nif.entry = entry; + mod->nif = lib; for (i=0; i < entry->num_of_funcs; i++) { Uint* code_ptr; - erts_atom_get(entry->funcs[i].name, strlen(entry->funcs[i].name), &f_atom); + 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); if (code_ptr[1] == 0) { code_ptr[5+0] = (Uint) BeamOp(op_call_nif); - } else { /* Function traced, patch the original instruction word */ + } + else { /* Function traced, patch the original instruction word */ BpData* bp = (BpData*) code_ptr[1]; bp->orig_instr = (Uint) BeamOp(op_call_nif); } code_ptr[5+1] = (Uint) entry->funcs[i].fptr; - code_ptr[5+2] = (Uint) mod->nif.data; + code_ptr[5+2] = (Uint) lib; } } else { error: ASSERT(ret != am_ok); + if (lib != NULL) { + erts_free(ERTS_ALC_T_NIF, lib); + } if (handle != NULL) { erts_sys_ddll_close(handle); } @@ -639,3 +1300,53 @@ BIF_RETTYPE load_nif_2(BIF_ALIST_2) BIF_RET(ret); } + +void +erts_unload_nif(struct erl_module_nif* lib) +{ + ErlNifResourceType* rt; + ErlNifResourceType* next; + ASSERT(erts_smp_is_system_blocked(0)); + ASSERT(lib != NULL); + ASSERT(!lib->is_orphan); + for (rt = resource_type_list.next; + rt != &resource_type_list; + rt = next) { + + next = rt->next; + if (rt->owner == lib) { + rt->next->prev = rt->prev; + rt->prev->next = rt->next; + rt->next = NULL; + rt->prev = NULL; + if (erts_refc_dectest(&rt->refc, 0) == 0) { + if (rt->dtor != NULL) { + erts_refc_dec(&lib->rt_dtor_cnt, 0); + } + erts_refc_dec(&lib->rt_cnt, 0); + erts_free(ERTS_ALC_T_NIF, rt); + } + } + } + if (erts_refc_read(&lib->rt_dtor_cnt, 0) == 0) { + close_lib(lib); + if (erts_refc_read(&lib->rt_cnt, 0) == 0) { + erts_free(ERTS_ALC_T_NIF, lib); + return; + } + } + else { + ASSERT(erts_refc_read(&lib->rt_cnt, 1) > 0); + } + lib->is_orphan = 1; +} + +void erl_nif_init() +{ + resource_type_list.next = &resource_type_list; + resource_type_list.prev = &resource_type_list; + resource_type_list.dtor = NULL; + resource_type_list.owner = NULL; + resource_type_list.name[0] = '\0'; +} + diff --git a/erts/emulator/beam/erl_nif.h b/erts/emulator/beam/erl_nif.h index 8650b7ce47..1ccf00293e 100644 --- a/erts/emulator/beam/erl_nif.h +++ b/erts/emulator/beam/erl_nif.h @@ -1,42 +1,51 @@ /* * %CopyrightBegin% - * - * Copyright Ericsson AB 2009. All Rights Reserved. - * + * + * Copyright Ericsson AB 2009-2010. 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% */ /* Include file for writers of Native Implemented Functions. */ -#define ERL_NIF_MAJOR_VERSION 0 -#define ERL_NIF_MINOR_VERSION 1 +#ifndef __ERL_NIF_H__ +#define __ERL_NIF_H__ + +#include "erl_drv_nif.h" + +/* Version history: +** 0.1: R13B03 +** 1.0: R13B04 +*/ +#define ERL_NIF_MAJOR_VERSION 1 +#define ERL_NIF_MINOR_VERSION 0 #include <stdlib.h> typedef unsigned long ERL_NIF_TERM; +struct enif_environment_t; +typedef struct enif_environment_t ErlNifEnv; + typedef struct { const char* name; unsigned arity; - void* fptr; //ERL_NIF_TERM (*fptr)(void*, ...); + ERL_NIF_TERM (*fptr)(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); }ErlNifFunc; -struct enif_environment_t; -typedef struct enif_environment_t ErlNifEnv; - typedef struct enif_entry_t { int major; @@ -59,11 +68,32 @@ typedef struct /* Internals (avert your eyes) */ ERL_NIF_TERM bin_term; - unsigned char* tmp_alloc; void* ref_bin; - }ErlNifBinary; +typedef struct enif_resource_type_t ErlNifResourceType; +typedef void ErlNifResourceDtor(ErlNifEnv*, void*); +enum ErlNifResourceFlags +{ + ERL_NIF_RT_CREATE = 1, + ERL_NIF_RT_TAKEOVER = 2 +}; + +typedef enum +{ + ERL_NIF_LATIN1 = 1 +}ErlNifCharEncoding; + +typedef ErlDrvSysInfo ErlNifSysInfo; + +typedef struct ErlDrvTid_ *ErlNifTid; +typedef struct ErlDrvMutex_ ErlNifMutex; +typedef struct ErlDrvCond_ ErlNifCond; +typedef struct ErlDrvRWLock_ ErlNifRWLock; +typedef int ErlNifTSDKey; + +typedef ErlDrvThreadOpts ErlNifThreadOpts; + #if (defined(__WIN32__) || defined(_WIN32) || defined(_WIN32_)) # define ERL_NIF_API_FUNC_DECL(RET_TYPE, NAME, ARGS) RET_TYPE (*NAME) ARGS typedef struct { @@ -120,3 +150,5 @@ ERL_NIF_INIT_DECL(NAME) \ return &entry; \ } +#endif /* __ERL_NIF_H__ */ + diff --git a/erts/emulator/beam/erl_nif_api_funcs.h b/erts/emulator/beam/erl_nif_api_funcs.h index 400c1822cc..ec07a976b2 100644 --- a/erts/emulator/beam/erl_nif_api_funcs.h +++ b/erts/emulator/beam/erl_nif_api_funcs.h @@ -1,19 +1,19 @@ /* * %CopyrightBegin% - * - * Copyright Ericsson AB 2009. All Rights Reserved. - * + * + * Copyright Ericsson AB 2009-2010. 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% */ @@ -22,47 +22,204 @@ #endif #ifdef ERL_NIF_API_FUNC_DECL -ERL_NIF_API_FUNC_DECL(void*,enif_get_data,(ErlNifEnv*)); +ERL_NIF_API_FUNC_DECL(void*,enif_priv_data,(ErlNifEnv*)); ERL_NIF_API_FUNC_DECL(void*,enif_alloc,(ErlNifEnv*, size_t size)); ERL_NIF_API_FUNC_DECL(void,enif_free,(ErlNifEnv*, void* ptr)); +ERL_NIF_API_FUNC_DECL(int,enif_is_atom,(ErlNifEnv*, ERL_NIF_TERM term)); ERL_NIF_API_FUNC_DECL(int,enif_is_binary,(ErlNifEnv*, ERL_NIF_TERM term)); +ERL_NIF_API_FUNC_DECL(int,enif_is_ref,(ErlNifEnv*, ERL_NIF_TERM term)); ERL_NIF_API_FUNC_DECL(int,enif_inspect_binary,(ErlNifEnv*, ERL_NIF_TERM bin_term, ErlNifBinary* bin)); ERL_NIF_API_FUNC_DECL(int,enif_alloc_binary,(ErlNifEnv*, unsigned size, ErlNifBinary* bin)); +ERL_NIF_API_FUNC_DECL(int,enif_realloc_binary,(ErlNifEnv*, ErlNifBinary* bin, unsigned size)); ERL_NIF_API_FUNC_DECL(void,enif_release_binary,(ErlNifEnv*, ErlNifBinary* bin)); ERL_NIF_API_FUNC_DECL(int,enif_get_int,(ErlNifEnv*, ERL_NIF_TERM term, int* ip)); ERL_NIF_API_FUNC_DECL(int,enif_get_ulong,(ErlNifEnv*, ERL_NIF_TERM term, unsigned long* ip)); +ERL_NIF_API_FUNC_DECL(int,enif_get_double,(ErlNifEnv*, ERL_NIF_TERM term, double* dp)); ERL_NIF_API_FUNC_DECL(int,enif_get_list_cell,(ErlNifEnv* env, ERL_NIF_TERM term, ERL_NIF_TERM* head, ERL_NIF_TERM* tail)); +ERL_NIF_API_FUNC_DECL(int,enif_get_tuple,(ErlNifEnv* env, ERL_NIF_TERM tpl, int* arity, const ERL_NIF_TERM** array)); +ERL_NIF_API_FUNC_DECL(int,enif_is_identical,(ErlNifEnv* env, ERL_NIF_TERM lhs, ERL_NIF_TERM rhs)); +ERL_NIF_API_FUNC_DECL(int,enif_compare,(ErlNifEnv* env, ERL_NIF_TERM lhs, ERL_NIF_TERM rhs)); ERL_NIF_API_FUNC_DECL(ERL_NIF_TERM,enif_make_binary,(ErlNifEnv* env, ErlNifBinary* bin)); ERL_NIF_API_FUNC_DECL(ERL_NIF_TERM,enif_make_badarg,(ErlNifEnv* env)); ERL_NIF_API_FUNC_DECL(ERL_NIF_TERM,enif_make_int,(ErlNifEnv* env, int i)); ERL_NIF_API_FUNC_DECL(ERL_NIF_TERM,enif_make_ulong,(ErlNifEnv* env, unsigned long i)); +ERL_NIF_API_FUNC_DECL(ERL_NIF_TERM,enif_make_double,(ErlNifEnv* env, double d)); ERL_NIF_API_FUNC_DECL(ERL_NIF_TERM,enif_make_atom,(ErlNifEnv* env, const char* name)); +ERL_NIF_API_FUNC_DECL(int,enif_make_existing_atom,(ErlNifEnv* env, const char* name, ERL_NIF_TERM* atom)); ERL_NIF_API_FUNC_DECL(ERL_NIF_TERM,enif_make_tuple,(ErlNifEnv* env, unsigned cnt, ...)); ERL_NIF_API_FUNC_DECL(ERL_NIF_TERM,enif_make_list,(ErlNifEnv* env, unsigned cnt, ...)); ERL_NIF_API_FUNC_DECL(ERL_NIF_TERM,enif_make_list_cell,(ErlNifEnv* env, ERL_NIF_TERM car, ERL_NIF_TERM cdr)); -ERL_NIF_API_FUNC_DECL(ERL_NIF_TERM,enif_make_string,(ErlNifEnv* env, const char* string)); +ERL_NIF_API_FUNC_DECL(ERL_NIF_TERM,enif_make_string,(ErlNifEnv* env, const char* string, ErlNifCharEncoding)); +ERL_NIF_API_FUNC_DECL(ERL_NIF_TERM,enif_make_ref,(ErlNifEnv* env)); + +ERL_NIF_API_FUNC_DECL(ErlNifMutex*,enif_mutex_create,(char *name)); +ERL_NIF_API_FUNC_DECL(void,enif_mutex_destroy,(ErlNifMutex *mtx)); +ERL_NIF_API_FUNC_DECL(int,enif_mutex_trylock,(ErlNifMutex *mtx)); +ERL_NIF_API_FUNC_DECL(void,enif_mutex_lock,(ErlNifMutex *mtx)); +ERL_NIF_API_FUNC_DECL(void,enif_mutex_unlock,(ErlNifMutex *mtx)); +ERL_NIF_API_FUNC_DECL(ErlNifCond*,enif_cond_create,(char *name)); +ERL_NIF_API_FUNC_DECL(void,enif_cond_destroy,(ErlNifCond *cnd)); +ERL_NIF_API_FUNC_DECL(void,enif_cond_signal,(ErlNifCond *cnd)); +ERL_NIF_API_FUNC_DECL(void,enif_cond_broadcast,(ErlNifCond *cnd)); +ERL_NIF_API_FUNC_DECL(void,enif_cond_wait,(ErlNifCond *cnd, ErlNifMutex *mtx)); +ERL_NIF_API_FUNC_DECL(ErlNifRWLock*,enif_rwlock_create,(char *name)); +ERL_NIF_API_FUNC_DECL(void,enif_rwlock_destroy,(ErlNifRWLock *rwlck)); +ERL_NIF_API_FUNC_DECL(int,enif_rwlock_tryrlock,(ErlNifRWLock *rwlck)); +ERL_NIF_API_FUNC_DECL(void,enif_rwlock_rlock,(ErlNifRWLock *rwlck)); +ERL_NIF_API_FUNC_DECL(void,enif_rwlock_runlock,(ErlNifRWLock *rwlck)); +ERL_NIF_API_FUNC_DECL(int,enif_rwlock_tryrwlock,(ErlNifRWLock *rwlck)); +ERL_NIF_API_FUNC_DECL(void,enif_rwlock_rwlock,(ErlNifRWLock *rwlck)); +ERL_NIF_API_FUNC_DECL(void,enif_rwlock_rwunlock,(ErlNifRWLock *rwlck)); +ERL_NIF_API_FUNC_DECL(int,enif_tsd_key_create,(char *name, ErlNifTSDKey *key)); +ERL_NIF_API_FUNC_DECL(void,enif_tsd_key_destroy,(ErlNifTSDKey key)); +ERL_NIF_API_FUNC_DECL(void,enif_tsd_set,(ErlNifTSDKey key, void *data)); +ERL_NIF_API_FUNC_DECL(void*,enif_tsd_get,(ErlNifTSDKey key)); +ERL_NIF_API_FUNC_DECL(ErlNifThreadOpts*,enif_thread_opts_create,(char *name)); +ERL_NIF_API_FUNC_DECL(void,enif_thread_opts_destroy,(ErlNifThreadOpts *opts)); +ERL_NIF_API_FUNC_DECL(int,enif_thread_create,(char *name,ErlNifTid *tid,void * (*func)(void *),void *args,ErlNifThreadOpts *opts)); +ERL_NIF_API_FUNC_DECL(ErlNifTid,enif_thread_self,(void)); +ERL_NIF_API_FUNC_DECL(int,enif_equal_tids,(ErlNifTid tid1, ErlNifTid tid2)); +ERL_NIF_API_FUNC_DECL(void,enif_thread_exit,(void *resp)); +ERL_NIF_API_FUNC_DECL(int,enif_thread_join,(ErlNifTid, void **respp)); + +ERL_NIF_API_FUNC_DECL(void*,enif_realloc,(ErlNifEnv*, void* ptr, size_t size)); +ERL_NIF_API_FUNC_DECL(void,enif_system_info,(ErlNifSysInfo *sip, size_t si_size)); +ERL_NIF_API_FUNC_DECL(int,enif_fprintf,(void/* FILE* */ *filep, const char *format, ...)); +ERL_NIF_API_FUNC_DECL(int,enif_inspect_iolist_as_binary,(ErlNifEnv*, ERL_NIF_TERM term, ErlNifBinary* bin)); +ERL_NIF_API_FUNC_DECL(ERL_NIF_TERM,enif_make_sub_binary,(ErlNifEnv*, ERL_NIF_TERM bin_term, unsigned pos, unsigned size)); +ERL_NIF_API_FUNC_DECL(int,enif_get_string,(ErlNifEnv*, ERL_NIF_TERM list, char* buf, unsigned len, ErlNifCharEncoding)); +ERL_NIF_API_FUNC_DECL(int,enif_get_atom,(ErlNifEnv*, ERL_NIF_TERM atom, char* buf, unsigned len)); +ERL_NIF_API_FUNC_DECL(int,enif_is_fun,(ErlNifEnv*, ERL_NIF_TERM term)); +ERL_NIF_API_FUNC_DECL(int,enif_is_pid,(ErlNifEnv*, ERL_NIF_TERM term)); +ERL_NIF_API_FUNC_DECL(int,enif_is_port,(ErlNifEnv*, ERL_NIF_TERM term)); +ERL_NIF_API_FUNC_DECL(int,enif_get_uint,(ErlNifEnv*, ERL_NIF_TERM term, unsigned* ip)); +ERL_NIF_API_FUNC_DECL(int,enif_get_long,(ErlNifEnv*, ERL_NIF_TERM term, long* ip)); +ERL_NIF_API_FUNC_DECL(ERL_NIF_TERM,enif_make_uint,(ErlNifEnv*, unsigned i)); +ERL_NIF_API_FUNC_DECL(ERL_NIF_TERM,enif_make_long,(ErlNifEnv*, long i)); +ERL_NIF_API_FUNC_DECL(ERL_NIF_TERM,enif_make_tuple_from_array,(ErlNifEnv*, const ERL_NIF_TERM arr[], unsigned cnt)); +ERL_NIF_API_FUNC_DECL(ERL_NIF_TERM,enif_make_list_from_array,(ErlNifEnv*, const ERL_NIF_TERM arr[], unsigned cnt)); +ERL_NIF_API_FUNC_DECL(int,enif_is_empty_list,(ErlNifEnv*, ERL_NIF_TERM term)); +ERL_NIF_API_FUNC_DECL(ErlNifResourceType*,enif_open_resource_type,(ErlNifEnv*, const char* type_name, void (*dtor)(ErlNifEnv*,void *), enum ErlNifResourceFlags flags, enum ErlNifResourceFlags* tried)); +ERL_NIF_API_FUNC_DECL(void*,enif_alloc_resource,(ErlNifEnv*, ErlNifResourceType* type, unsigned size)); +ERL_NIF_API_FUNC_DECL(void,enif_release_resource,(ErlNifEnv*, void* obj)); +ERL_NIF_API_FUNC_DECL(ERL_NIF_TERM,enif_make_resource,(ErlNifEnv*, void* obj)); +ERL_NIF_API_FUNC_DECL(int,enif_get_resource,(ErlNifEnv*, ERL_NIF_TERM term, ErlNifResourceType* type, void** objp)); +ERL_NIF_API_FUNC_DECL(unsigned,enif_sizeof_resource,(ErlNifEnv*, void* obj)); +/* +** Add last to keep compatibility on Windows!!! +*/ #endif #ifdef ERL_NIF_API_FUNC_MACRO -# define enif_get_data ERL_NIF_API_FUNC_MACRO(enif_get_data) +# define enif_priv_data ERL_NIF_API_FUNC_MACRO(enif_priv_data) # define enif_alloc ERL_NIF_API_FUNC_MACRO(enif_alloc) # define enif_free ERL_NIF_API_FUNC_MACRO(enif_free) +# define enif_is_atom ERL_NIF_API_FUNC_MACRO(enif_is_atom) # define enif_is_binary ERL_NIF_API_FUNC_MACRO(enif_is_binary) +# define enif_is_ref ERL_NIF_API_FUNC_MACRO(enif_is_ref) # define enif_inspect_binary ERL_NIF_API_FUNC_MACRO(enif_inspect_binary) # define enif_alloc_binary ERL_NIF_API_FUNC_MACRO(enif_alloc_binary) +# define enif_realloc_binary ERL_NIF_API_FUNC_MACRO(enif_realloc_binary) # define enif_release_binary ERL_NIF_API_FUNC_MACRO(enif_release_binary) # define enif_get_int ERL_NIF_API_FUNC_MACRO(enif_get_int) # define enif_get_ulong ERL_NIF_API_FUNC_MACRO(enif_get_ulong) +# define enif_get_double ERL_NIF_API_FUNC_MACRO(enif_get_double) +# define enif_get_tuple ERL_NIF_API_FUNC_MACRO(enif_get_tuple) # define enif_get_list_cell ERL_NIF_API_FUNC_MACRO(enif_get_list_cell) +# define enif_is_identical ERL_NIF_API_FUNC_MACRO(enif_is_identical) +# define enif_compare ERL_NIF_API_FUNC_MACRO(enif_compare) # define enif_make_binary ERL_NIF_API_FUNC_MACRO(enif_make_binary) # define enif_make_badarg ERL_NIF_API_FUNC_MACRO(enif_make_badarg) # define enif_make_int ERL_NIF_API_FUNC_MACRO(enif_make_int) # define enif_make_ulong ERL_NIF_API_FUNC_MACRO(enif_make_ulong) +# define enif_make_double ERL_NIF_API_FUNC_MACRO(enif_make_double) # define enif_make_atom ERL_NIF_API_FUNC_MACRO(enif_make_atom) +# define enif_make_existing_atom ERL_NIF_API_FUNC_MACRO(enif_make_existing_atom) # define enif_make_tuple ERL_NIF_API_FUNC_MACRO(enif_make_tuple) # define enif_make_list ERL_NIF_API_FUNC_MACRO(enif_make_list) # define enif_make_list_cell ERL_NIF_API_FUNC_MACRO(enif_make_list_cell) # define enif_make_string ERL_NIF_API_FUNC_MACRO(enif_make_string) +# define enif_make_ref ERL_NIF_API_FUNC_MACRO(enif_make_ref) + +# define enif_mutex_create ERL_NIF_API_FUNC_MACRO(enif_mutex_create) +# define enif_mutex_destroy ERL_NIF_API_FUNC_MACRO(enif_mutex_destroy) +# define enif_mutex_trylock ERL_NIF_API_FUNC_MACRO(enif_mutex_trylock) +# define enif_mutex_lock ERL_NIF_API_FUNC_MACRO(enif_mutex_lock) +# define enif_mutex_unlock ERL_NIF_API_FUNC_MACRO(enif_mutex_unlock) +# define enif_cond_create ERL_NIF_API_FUNC_MACRO(enif_cond_create) +# define enif_cond_destroy ERL_NIF_API_FUNC_MACRO(enif_cond_destroy) +# define enif_cond_signal ERL_NIF_API_FUNC_MACRO(enif_cond_signal) +# define enif_cond_broadcast ERL_NIF_API_FUNC_MACRO(enif_cond_broadcast) +# define enif_cond_wait ERL_NIF_API_FUNC_MACRO(enif_cond_wait) +# define enif_rwlock_create ERL_NIF_API_FUNC_MACRO(enif_rwlock_create) +# define enif_rwlock_destroy ERL_NIF_API_FUNC_MACRO(enif_rwlock_destroy) +# define enif_rwlock_tryrlock ERL_NIF_API_FUNC_MACRO(enif_rwlock_tryrlock) +# define enif_rwlock_rlock ERL_NIF_API_FUNC_MACRO(enif_rwlock_rlock) +# define enif_rwlock_runlock ERL_NIF_API_FUNC_MACRO(enif_rwlock_runlock) +# define enif_rwlock_tryrwlock ERL_NIF_API_FUNC_MACRO(enif_rwlock_tryrwlock) +# define enif_rwlock_rwlock ERL_NIF_API_FUNC_MACRO(enif_rwlock_rwlock) +# define enif_rwlock_rwunlock ERL_NIF_API_FUNC_MACRO(enif_rwlock_rwunlock) +# define enif_tsd_key_create ERL_NIF_API_FUNC_MACRO(enif_tsd_key_create) +# define enif_tsd_key_destroy ERL_NIF_API_FUNC_MACRO(enif_tsd_key_destroy) +# define enif_tsd_set ERL_NIF_API_FUNC_MACRO(enif_tsd_set) +# define enif_tsd_get ERL_NIF_API_FUNC_MACRO(enif_tsd_get) +# define enif_thread_opts_create ERL_NIF_API_FUNC_MACRO(enif_thread_opts_create) +# define enif_thread_opts_destroy ERL_NIF_API_FUNC_MACRO(enif_thread_opts_destroy) +# define enif_thread_create ERL_NIF_API_FUNC_MACRO(enif_thread_create) +# define enif_thread_self ERL_NIF_API_FUNC_MACRO(enif_thread_self) +# define enif_equal_tids ERL_NIF_API_FUNC_MACRO(enif_equal_tids) +# define enif_thread_exit ERL_NIF_API_FUNC_MACRO(enif_thread_exit) +# define enif_thread_join ERL_NIF_API_FUNC_MACRO(enif_thread_join) + +# define enif_realloc ERL_NIF_API_FUNC_MACRO(enif_realloc) +# define enif_system_info ERL_NIF_API_FUNC_MACRO(enif_system_info) +# define enif_fprintf ERL_NIF_API_FUNC_MACRO(enif_fprintf) +# define enif_inspect_iolist_as_binary ERL_NIF_API_FUNC_MACRO(enif_inspect_iolist_as_binary) +# define enif_make_sub_binary ERL_NIF_API_FUNC_MACRO(enif_make_sub_binary) +# define enif_get_string ERL_NIF_API_FUNC_MACRO(enif_get_string) +# define enif_get_atom ERL_NIF_API_FUNC_MACRO(enif_get_atom) +# define enif_is_fun ERL_NIF_API_FUNC_MACRO(enif_is_fun) +# define enif_is_pid ERL_NIF_API_FUNC_MACRO(enif_is_pid) +# define enif_is_port ERL_NIF_API_FUNC_MACRO(enif_is_port) +# define enif_get_uint ERL_NIF_API_FUNC_MACRO(enif_get_uint) +# define enif_get_long ERL_NIF_API_FUNC_MACRO(enif_get_long) +# define enif_make_uint ERL_NIF_API_FUNC_MACRO(enif_make_uint) +# define enif_make_long ERL_NIF_API_FUNC_MACRO(enif_make_long) +# define enif_make_tuple_from_array ERL_NIF_API_FUNC_MACRO(enif_make_tuple_from_array) +# define enif_make_list_from_array ERL_NIF_API_FUNC_MACRO(enif_make_list_from_array) +# define enif_is_empty_list ERL_NIF_API_FUNC_MACRO(enif_is_empty_list) +# define enif_open_resource_type ERL_NIF_API_FUNC_MACRO(enif_open_resource_type) +# define enif_alloc_resource ERL_NIF_API_FUNC_MACRO(enif_alloc_resource) +# define enif_release_resource ERL_NIF_API_FUNC_MACRO(enif_release_resource) +# define enif_make_resource ERL_NIF_API_FUNC_MACRO(enif_make_resource) +# define enif_get_resource ERL_NIF_API_FUNC_MACRO(enif_get_resource) +# define enif_sizeof_resource ERL_NIF_API_FUNC_MACRO(enif_sizeof_resource) + +#endif + +#ifndef enif_make_list1 +# define enif_make_list1(ENV,E1) enif_make_list(ENV,1,E1) +# define enif_make_list2(ENV,E1,E2) enif_make_list(ENV,2,E1,E2) +# define enif_make_list3(ENV,E1,E2,E3) enif_make_list(ENV,3,E1,E2,E3) +# define enif_make_list4(ENV,E1,E2,E3,E4) enif_make_list(ENV,4,E1,E2,E3,E4) +# define enif_make_list5(ENV,E1,E2,E3,E4,E5) enif_make_list(ENV,5,E1,E2,E3,E4,E5) +# define enif_make_list6(ENV,E1,E2,E3,E4,E5,E6) enif_make_list(ENV,6,E1,E2,E3,E4,E5,E6) +# define enif_make_list7(ENV,E1,E2,E3,E4,E5,E6,E7) enif_make_list(ENV,7,E1,E2,E3,E4,E5,E6,E7) +# define enif_make_list8(ENV,E1,E2,E3,E4,E5,E6,E7,E8) enif_make_list(ENV,8,E1,E2,E3,E4,E5,E6,E7,E8) +# define enif_make_list9(ENV,E1,E2,E3,E4,E5,E6,E7,E8,E9) enif_make_list(ENV,9,E1,E2,E3,E4,E5,E6,E7,E8,E9) +# define enif_make_tuple1(ENV,E1) enif_make_tuple(ENV,1,E1) +# define enif_make_tuple2(ENV,E1,E2) enif_make_tuple(ENV,2,E1,E2) +# define enif_make_tuple3(ENV,E1,E2,E3) enif_make_tuple(ENV,3,E1,E2,E3) +# define enif_make_tuple4(ENV,E1,E2,E3,E4) enif_make_tuple(ENV,4,E1,E2,E3,E4) +# define enif_make_tuple5(ENV,E1,E2,E3,E4,E5) enif_make_tuple(ENV,5,E1,E2,E3,E4,E5) +# define enif_make_tuple6(ENV,E1,E2,E3,E4,E5,E6) enif_make_tuple(ENV,6,E1,E2,E3,E4,E5,E6) +# define enif_make_tuple7(ENV,E1,E2,E3,E4,E5,E6,E7) enif_make_tuple(ENV,7,E1,E2,E3,E4,E5,E6,E7) +# define enif_make_tuple8(ENV,E1,E2,E3,E4,E5,E6,E7,E8) enif_make_tuple(ENV,8,E1,E2,E3,E4,E5,E6,E7,E8) +# define enif_make_tuple9(ENV,E1,E2,E3,E4,E5,E6,E7,E8,E9) enif_make_tuple(ENV,9,E1,E2,E3,E4,E5,E6,E7,E8,E9) +#endif + +#ifndef enif_get_data +# define enif_get_data enif_priv_data /* deprecated */ #endif diff --git a/erts/emulator/beam/erl_port_task.c b/erts/emulator/beam/erl_port_task.c index 0fb264a53c..0b6bb0d8e9 100644 --- a/erts/emulator/beam/erl_port_task.c +++ b/erts/emulator/beam/erl_port_task.c @@ -1,19 +1,19 @@ /* * %CopyrightBegin% - * - * Copyright Ericsson AB 2006-2009. All Rights Reserved. - * + * + * Copyright Ericsson AB 2006-2010. 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% */ @@ -575,7 +575,7 @@ erts_port_task_schedule(Eterm id, } #endif - ASSERT(!(runq->flags & ERTS_RUNQ_FLG_SUSPENDED)); + ASSERT(!enq_port || !(runq->flags & ERTS_RUNQ_FLG_SUSPENDED)); ASSERT(pp->sched.taskq); ASSERT(ptp); @@ -601,6 +601,15 @@ erts_port_task_schedule(Eterm id, break; } +#ifndef ERTS_SMP + /* + * When (!enq_port && !pp->sched.exe_taskq) is true in the smp case, + * the port might not be in the run queue. If this is the case, another + * thread is in the process of enqueueing the port. This very seldom + * occur, but do occur and is a valid scenario. Debug info showing this + * enqueue in progress must be introduced before we can enable (modified + * versions of these) assertions in the smp case again. + */ #if defined(HARD_DEBUG) if (pp->sched.exe_taskq || enq_port) ERTS_PT_CHK_NOT_IN_PORTQ(runq, pp); @@ -612,6 +621,7 @@ erts_port_task_schedule(Eterm id, ASSERT(pp->sched.prev || runq->ports.start == pp); } #endif +#endif if (!enq_port) { ERTS_PT_CHK_PRES_PORTQ(runq, pp); @@ -902,25 +912,45 @@ erts_port_task_execute(ErtsRunQueue *runq, Port **curr_port_pp) *curr_port_pp = NULL; - if (pp->sched.taskq) { +#ifdef ERTS_SMP + ASSERT(runq == (ErtsRunQueue *) erts_smp_atomic_read(&pp->run_queue)); +#endif + + if (!pp->sched.taskq) { + ASSERT(pp->sched.exe_taskq); + pp->sched.exe_taskq = NULL; + } + else { +#ifdef ERTS_SMP + ErtsRunQueue *xrunq; +#endif + ASSERT(!(pp->status & ERTS_PORT_SFLGS_DEAD)); ASSERT(pp->sched.taskq->first); - enqueue_port(runq, pp); - port_was_enqueued = 1; - - /* - erts_smp_notify_inc_runq(); - * No need to notify schedulers about the increase in run - * queue length since at least this thread, which is a - * scheduler, will discover that the port run queue isn't - * empty before trying to go to sleep. - */ +#ifdef ERTS_SMP + xrunq = erts_check_emigration_need(runq, ERTS_PORT_PRIO_LEVEL); + if (!xrunq) { +#endif + enqueue_port(runq, pp); + ASSERT(pp->sched.exe_taskq); + pp->sched.exe_taskq = NULL; + /* No need to notify ourselves about inc in runq. */ +#ifdef ERTS_SMP + } + else { + /* Port emigrated ... */ + erts_smp_atomic_set(&pp->run_queue, (long) xrunq); + enqueue_port(xrunq, pp); + ASSERT(pp->sched.exe_taskq); + pp->sched.exe_taskq = NULL; + erts_smp_notify_inc_runq(xrunq); + erts_smp_runq_unlock(xrunq); + } +#endif + port_was_enqueued = 1; } - ASSERT(pp->sched.exe_taskq); - pp->sched.exe_taskq = NULL; - res = erts_smp_atomic_read(&erts_port_task_outstanding_io_tasks) != (long) 0; ERTS_PT_CHK_PRES_PORTQ(runq, pp); diff --git a/erts/emulator/beam/erl_process.c b/erts/emulator/beam/erl_process.c index 9960172366..996806fc75 100644 --- a/erts/emulator/beam/erl_process.c +++ b/erts/emulator/beam/erl_process.c @@ -1,19 +1,19 @@ /* * %CopyrightBegin% - * - * Copyright Ericsson AB 1996-2009. All Rights Reserved. - * + * + * Copyright Ericsson AB 1996-2010. 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% */ @@ -219,7 +219,7 @@ ErtsSchedulerData *erts_scheduler_data; ErtsAlignedRunQueue *erts_aligned_run_queues; Uint erts_no_run_queues; -typedef struct { +typedef union { ErtsSchedulerData esd; char align[ERTS_ALC_CACHE_LINE_ALIGN_SIZE(sizeof(ErtsSchedulerData))]; } ErtsAlignedSchedulerData; @@ -2095,7 +2095,11 @@ erts_init_scheduling(int mrq, int no_schedulers, int no_schedulers_online) rq->ix = ix; erts_smp_atomic_init(&rq->info_flags, ERTS_RUNQ_IFLG_NONEMPTY); - erts_smp_mtx_init(&rq->mtx, "run_queue"); + /* make sure that the "extra" id correponds to the schedulers + * id if the esdp->no <-> ix+1 mapping change. + */ + + erts_smp_mtx_init_x(&rq->mtx, "run_queue", make_small(ix + 1)); erts_smp_cnd_init(&rq->cnd); erts_smp_atomic_init(&rq->spin_waiter, 0); @@ -2522,8 +2526,11 @@ suspend_scheduler(ErtsSchedulerData *esdp) NULL); } - erts_smp_atomic_inc(&schdlr_sspnd.active); - + active_schedulers = erts_smp_atomic_inctest(&schdlr_sspnd.active); + if (schdlr_sspnd.changing == ERTS_SCHED_CHANGING_MULTI_SCHED + && schdlr_sspnd.online == active_schedulers) { + schdlr_sspnd.changing = 0; + } erts_smp_mtx_unlock(&schdlr_sspnd.mtx); if (erts_system_profile_flags.scheduler) @@ -2750,18 +2757,19 @@ erts_block_multi_scheduling(Process *p, ErtsProcLocks plocks, int on, int all) ErtsProcList *plp; erts_smp_mtx_lock(&schdlr_sspnd.mtx); - if (on) { - if (schdlr_sspnd.changing) { - res = ERTS_SCHDLR_SSPND_YIELD_RESTART; /* Yield */ - } - else if (erts_is_multi_scheduling_blocked()) { + + if (schdlr_sspnd.changing) { + res = ERTS_SCHDLR_SSPND_YIELD_RESTART; /* Yield */ + } + else if (on) { /* ------ BLOCK ------ */ + if (erts_is_multi_scheduling_blocked()) { plp = proclist_create(p); plp->next = schdlr_sspnd.msb.procs; schdlr_sspnd.msb.procs = plp; p->flags |= F_HAVE_BLCKD_MSCHED; ASSERT(erts_smp_atomic_read(&schdlr_sspnd.active) == 1); ASSERT(p->scheduler_data->no == 1); - res = 1; + res = ERTS_SCHDLR_SSPND_DONE_MSCHED_BLOCKED; } else { p->flags |= F_HAVE_BLCKD_MSCHED; @@ -2842,10 +2850,11 @@ erts_block_multi_scheduling(Process *p, ErtsProcLocks plocks, int on, int all) } } else if (!ongoing_multi_scheduling_block()) { + /* unblock not ongoing */ ASSERT(!schdlr_sspnd.msb.procs); res = ERTS_SCHDLR_SSPND_DONE; } - else { + else { /* ------ UNBLOCK ------ */ if (p->flags & F_HAVE_BLCKD_MSCHED) { ErtsProcList **plpp = &schdlr_sspnd.msb.procs; plp = schdlr_sspnd.msb.procs; @@ -2891,12 +2900,16 @@ erts_block_multi_scheduling(Process *p, ErtsProcLocks plocks, int on, int all) #endif p->flags &= ~F_HAVE_BLCKD_MSCHED; erts_smp_atomic_set(&schdlr_sspnd.msb.ongoing, 0); - if (schdlr_sspnd.online == 1) - /* No schedulers to resume */; + if (schdlr_sspnd.online == 1) { + /* No schedulers to resume */ + ASSERT(erts_smp_atomic_read(&schdlr_sspnd.active) == 1); + schdlr_sspnd.changing = 0; + } else if (erts_common_run_queue) { for (ix = 1; ix < schdlr_sspnd.online; ix++) erts_smp_atomic_set(&ERTS_SCHEDULER_IX(ix)->suspended, 0); wake_all_schedulers(); + erts_smp_cnd_broadcast(&schdlr_sspnd.cnd); } else { int online = schdlr_sspnd.online; @@ -2928,9 +2941,8 @@ erts_block_multi_scheduling(Process *p, ErtsProcLocks plocks, int on, int all) erts_smp_runq_unlock(ERTS_RUNQ_IX(0)); erts_smp_mtx_unlock(&balance_info.update_mtx); erts_smp_mtx_lock(&schdlr_sspnd.mtx); + erts_smp_cnd_broadcast(&schdlr_sspnd.cnd); } - erts_smp_cnd_broadcast(&schdlr_sspnd.cnd); - schdlr_sspnd.changing = 0; res = ERTS_SCHDLR_SSPND_DONE; } } @@ -5517,6 +5529,8 @@ erts_proc_migrate(Process *p, ErtsProcLocks *plcks, p->run_queue = to_rq; enqueue_process(to_rq, p); + smp_notify_inc_runq(to_rq); + return ERTS_MIGRATE_SUCCESS; } #endif /* ERTS_SMP */ @@ -6272,7 +6286,9 @@ Process *schedule(Process *p, int calls) erts_check_my_tracer_proc(p); #endif - if ((FLAGS(p) & F_FORCE_GC) || (MSO(p).overhead >= BIN_VHEAP_SZ(p))) { + if (!ERTS_PROC_IS_EXITING(p) + && ((FLAGS(p) & F_FORCE_GC) + || (MSO(p).overhead > BIN_VHEAP_SZ(p)))) { reds -= erts_garbage_collect(p, 0, p->arg_reg, p->arity); if (reds < 0) { reds = 1; @@ -6683,13 +6699,15 @@ erl_create_process(Process* parent, /* Parent of process (default group leader). * noone except us has access to the process. */ if (so->flags & SPO_USE_ARGS) { - p->min_heap_size = so->min_heap_size; - p->prio = so->priority; - p->max_gen_gcs = so->max_gen_gcs; + p->min_heap_size = so->min_heap_size; + p->min_vheap_size = so->min_vheap_size; + p->prio = so->priority; + p->max_gen_gcs = so->max_gen_gcs; } else { - p->min_heap_size = H_MIN_SIZE; - p->prio = PRIORITY_NORMAL; - p->max_gen_gcs = (Uint16) erts_smp_atomic_read(&erts_max_gen_gcs); + p->min_heap_size = H_MIN_SIZE; + p->min_vheap_size = BIN_VH_MIN_SIZE; + p->prio = PRIORITY_NORMAL; + p->max_gen_gcs = (Uint16) erts_smp_atomic_read(&erts_max_gen_gcs); } p->skipped = 0; ASSERT(p->min_heap_size == erts_next_heap_size(p->min_heap_size, 0)); @@ -6736,9 +6754,9 @@ erl_create_process(Process* parent, /* Parent of process (default group leader). p->heap_sz = sz; p->catches = 0; - p->bin_vheap_sz = H_MIN_SIZE; - p->bin_old_vheap_sz = H_MIN_SIZE; - p->bin_old_vheap = 0; + p->bin_vheap_sz = p->min_vheap_size; + p->bin_old_vheap_sz = p->min_vheap_size; + p->bin_old_vheap = 0; /* No need to initialize p->fcalls. */ @@ -6969,6 +6987,7 @@ void erts_init_empty_process(Process *p) p->gen_gcs = 0; p->max_gen_gcs = 0; p->min_heap_size = 0; + p->min_vheap_size = 0; p->status = P_RUNABLE; p->gcstatus = P_RUNABLE; p->rstatus = P_RUNABLE; @@ -6985,8 +7004,8 @@ void erts_init_empty_process(Process *p) p->ftrace = NIL; p->fcalls = 0; - p->bin_vheap_sz=H_MIN_SIZE; - p->bin_old_vheap_sz=H_MIN_SIZE; + p->bin_vheap_sz = BIN_VH_MIN_SIZE; + p->bin_old_vheap_sz = BIN_VH_MIN_SIZE; p->bin_old_vheap = 0; #ifdef ERTS_SMP p->u.ptimer = NULL; @@ -8024,11 +8043,6 @@ erts_do_exit_process(Process* p, Eterm reason) if (p->bif_timers) erts_cancel_bif_timers(p, ERTS_PROC_LOCKS_ALL); -#ifdef ERTS_SMP - if (p->flags & F_HAVE_BLCKD_MSCHED) - erts_block_multi_scheduling(p, ERTS_PROC_LOCKS_ALL, 0, 1); -#endif - erts_smp_proc_unlock(p, ERTS_PROC_LOCKS_ALL_MINOR); #ifdef ERTS_SMP @@ -8073,6 +8087,27 @@ continue_exit_process(Process *p erts_smp_proc_unlock(p, ERTS_PROC_LOCK_STATUS); #endif +#ifdef ERTS_SMP + if (p->flags & F_HAVE_BLCKD_MSCHED) { + ErtsSchedSuspendResult ssr; + ssr = erts_block_multi_scheduling(p, ERTS_PROC_LOCK_MAIN, 0, 1); + switch (ssr) { + case ERTS_SCHDLR_SSPND_YIELD_RESTART: + goto yield; + case ERTS_SCHDLR_SSPND_DONE_MSCHED_BLOCKED: + case ERTS_SCHDLR_SSPND_YIELD_DONE_MSCHED_BLOCKED: + case ERTS_SCHDLR_SSPND_DONE: + case ERTS_SCHDLR_SSPND_YIELD_DONE: + p->flags &= ~F_HAVE_BLCKD_MSCHED; + break; + case ERTS_SCHDLR_SSPND_EINVAL: + default: + erl_exit(ERTS_ABORT_EXIT, "%s:%d: Internal error: %d\n", + __FILE__, __LINE__, (int) ssr); + } + } +#endif + if (p->flags & F_USING_DB) { if (erts_db_process_exiting(p, ERTS_PROC_LOCK_MAIN)) goto yield; diff --git a/erts/emulator/beam/erl_process.h b/erts/emulator/beam/erl_process.h index 7bae1e4efc..f58b6932b3 100644 --- a/erts/emulator/beam/erl_process.h +++ b/erts/emulator/beam/erl_process.h @@ -1,19 +1,19 @@ /* * %CopyrightBegin% - * - * Copyright Ericsson AB 1996-2009. All Rights Reserved. - * + * + * Copyright Ericsson AB 1996-2010. 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% */ @@ -339,9 +339,14 @@ do { \ struct ErtsSchedulerData_ { #ifdef ERTS_SMP - ethr_tid tid; /* Thread id */ + /* + * Keep X registers first (so we get as many low + * numbered registers as possible in the same cache + * line). + */ Eterm save_reg[ERTS_X_REGS_ALLOCATED]; /* X registers */ FloatDef freg[MAX_REG]; /* Floating point registers. */ + ethr_tid tid; /* Thread id */ struct erl_bits_state erl_bits_state; /* erl_bits.c state */ void *match_pseudo_process; /* erl_db_util.c:db_prog_match() */ Process *free_process; @@ -472,6 +477,7 @@ struct ErtsPendingSuspend_ { # define MSO(p) (p)->off_heap # define MIN_HEAP_SIZE(p) (p)->min_heap_size +# define MIN_VHEAP_SIZE(p) (p)->min_vheap_size # define BIN_VHEAP_SZ(p) (p)->bin_vheap_sz # define BIN_OLD_VHEAP_SZ(p) (p)->bin_old_vheap_sz # define BIN_OLD_VHEAP(p) (p)->bin_old_vheap @@ -490,6 +496,7 @@ struct process { Eterm* hend; /* Heap end */ Uint heap_sz; /* Size of heap in words */ Uint min_heap_size; /* Minimum size of heap (in words). */ + Uint min_vheap_size; /* Minimum size of virtual heap (in words). */ #if !defined(NO_FPE_SIGNALS) volatile unsigned long fp_exception; @@ -649,6 +656,11 @@ struct process { * heap fragments. */ #endif + +#ifdef FORCE_HEAP_FRAGS + Uint space_verified; /* Avoid HAlloc forcing heap fragments when */ + Eterm* space_verified_from; /* we rely on available heap space (TestHeap) */ +#endif }; #ifdef CHECK_FOR_HOLES @@ -720,8 +732,8 @@ typedef struct { * The following items are only initialized if the SPO_USE_ARGS flag is set. */ Uint min_heap_size; /* Minimum heap size (must be a valued returned - * from next_heap_size()). - */ + * from next_heap_size()). */ + Uint min_vheap_size; /* Minimum virtual heap size */ int priority; /* Priority for process. */ Uint16 max_gen_gcs; /* Maximum number of gen GCs before fullsweep. */ int scheduler; @@ -733,7 +745,20 @@ typedef struct { #define KILL_CATCHES(p) (p)->catches = -1 -void erts_arith_shrink(Process* p, Eterm* hp); +/* Shrink heap fragment from _last_ HAlloc. +*/ +ERTS_GLB_INLINE void erts_heap_frag_shrink(Process* p, Eterm* hp); +#if ERTS_GLB_INLINE_INCL_FUNC_DEF +ERTS_GLB_INLINE void erts_heap_frag_shrink(Process* p, Eterm* hp) +{ + ErlHeapFragment* hf = MBUF(p); + + ASSERT(hf!=NULL && (hp - hf->mem < (unsigned long)hf->size)); + + hf->used_size = hp - hf->mem; +} +#endif /* inline */ + Eterm* erts_heap_alloc(Process* p, Uint need); #ifdef CHECK_FOR_HOLES Eterm* erts_set_hole_marker(Eterm* ptr, Uint sz); diff --git a/erts/emulator/beam/erl_term.h b/erts/emulator/beam/erl_term.h index b0a57a3ebe..a6596558fa 100644 --- a/erts/emulator/beam/erl_term.h +++ b/erts/emulator/beam/erl_term.h @@ -1,19 +1,19 @@ /* * %CopyrightBegin% - * - * Copyright Ericsson AB 2000-2009. All Rights Reserved. - * + * + * Copyright Ericsson AB 2000-2010. 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% */ @@ -38,7 +38,7 @@ struct erl_node_; /* Declared in erl_node_tables.h */ #endif #if ET_DEBUG -#define _ET_DECLARE_CHECKED(TF,F,TX) extern TF checked_##F(TX,const char*,unsigned) +#define _ET_DECLARE_CHECKED(TF,F,TX) extern TF checked_##F(TX,const char*,unsigned); #define _ET_APPLY(F,X) checked_##F(X,__FILE__,__LINE__) #else #define _ET_DECLARE_CHECKED(TF,F,TX) @@ -160,27 +160,27 @@ struct erl_node_; /* Declared in erl_node_tables.h */ /* boxed object access methods */ #define _is_aligned(x) (((Uint)(x) & 0x3) == 0) #define _unchecked_make_boxed(x) ((Uint)(x) + TAG_PRIMARY_BOXED) -_ET_DECLARE_CHECKED(Eterm,make_boxed,Eterm*); +_ET_DECLARE_CHECKED(Eterm,make_boxed,Eterm*) #define make_boxed(x) _ET_APPLY(make_boxed,(x)) #if 1 #define _is_not_boxed(x) ((x) & (_TAG_PRIMARY_MASK-TAG_PRIMARY_BOXED)) #define _unchecked_is_boxed(x) (!_is_not_boxed((x))) -_ET_DECLARE_CHECKED(int,is_boxed,Eterm); +_ET_DECLARE_CHECKED(int,is_boxed,Eterm) #define is_boxed(x) _ET_APPLY(is_boxed,(x)) #else #define is_boxed(x) (((x) & _TAG_PRIMARY_MASK) == TAG_PRIMARY_BOXED) #endif #define _unchecked_boxed_val(x) ((Eterm*)((x) - TAG_PRIMARY_BOXED)) -_ET_DECLARE_CHECKED(Eterm*,boxed_val,Eterm); +_ET_DECLARE_CHECKED(Eterm*,boxed_val,Eterm) #define boxed_val(x) _ET_APPLY(boxed_val,(x)) /* cons cell ("list") access methods */ #define _unchecked_make_list(x) ((Uint)(x) + TAG_PRIMARY_LIST) -_ET_DECLARE_CHECKED(Eterm,make_list,Eterm*); +_ET_DECLARE_CHECKED(Eterm,make_list,Eterm*) #define make_list(x) _ET_APPLY(make_list,(x)) #if 1 #define _unchecked_is_not_list(x) ((x) & (_TAG_PRIMARY_MASK-TAG_PRIMARY_LIST)) -_ET_DECLARE_CHECKED(int,is_not_list,Eterm); +_ET_DECLARE_CHECKED(int,is_not_list,Eterm) #define is_not_list(x) _ET_APPLY(is_not_list,(x)) #define is_list(x) (!is_not_list((x))) #else @@ -188,7 +188,7 @@ _ET_DECLARE_CHECKED(int,is_not_list,Eterm); #define is_not_list(x) (!is_list((x))) #endif #define _unchecked_list_val(x) ((Eterm*)((x) - TAG_PRIMARY_LIST)) -_ET_DECLARE_CHECKED(Eterm*,list_val,Eterm); +_ET_DECLARE_CHECKED(Eterm*,list_val,Eterm) #define list_val(x) _ET_APPLY(list_val,(x)) #define CONS(hp, car, cdr) \ @@ -221,10 +221,10 @@ _ET_DECLARE_CHECKED(Eterm*,list_val,Eterm); #define is_not_valid_bit_size(x) (!is_valid_bit_size((x))) #define MY_IS_SSMALL(x) (((Uint) (((x) >> (SMALL_BITS-1)) + 1)) < 2) #define _unchecked_unsigned_val(x) ((x) >> _TAG_IMMED1_SIZE) -_ET_DECLARE_CHECKED(Uint,unsigned_val,Eterm); +_ET_DECLARE_CHECKED(Uint,unsigned_val,Eterm) #define unsigned_val(x) _ET_APPLY(unsigned_val,(x)) #define _unchecked_signed_val(x) ((Sint)(x) >> _TAG_IMMED1_SIZE) -_ET_DECLARE_CHECKED(Sint,signed_val,Eterm); +_ET_DECLARE_CHECKED(Sint,signed_val,Eterm) #define signed_val(x) _ET_APPLY(signed_val,(x)) #if _TAG_IMMED1_SMALL == 0x0F @@ -247,14 +247,14 @@ _ET_DECLARE_CHECKED(Sint,signed_val,Eterm); #define is_atom(x) (((x) & _TAG_IMMED2_MASK) == _TAG_IMMED2_ATOM) #define is_not_atom(x) (!is_atom(x)) #define _unchecked_atom_val(x) ((x) >> _TAG_IMMED2_SIZE) -_ET_DECLARE_CHECKED(Uint,atom_val,Eterm); +_ET_DECLARE_CHECKED(Uint,atom_val,Eterm) #define atom_val(x) _ET_APPLY(atom_val,(x)) /* header (arityval or thing) access methods */ #define _make_header(sz,tag) ((Uint)(((sz) << _HEADER_ARITY_OFFS) + (tag))) #define is_header(x) (((x) & _TAG_PRIMARY_MASK) == TAG_PRIMARY_HEADER) #define _unchecked_header_arity(x) ((x) >> _HEADER_ARITY_OFFS) -_ET_DECLARE_CHECKED(Uint,header_arity,Eterm); +_ET_DECLARE_CHECKED(Uint,header_arity,Eterm) #define header_arity(x) _ET_APPLY(header_arity,(x)) /* arityval access methods */ @@ -262,16 +262,16 @@ _ET_DECLARE_CHECKED(Uint,header_arity,Eterm); #define is_arity_value(x) (((x) & _TAG_HEADER_MASK) == _TAG_HEADER_ARITYVAL) #define is_not_arity_value(x) (!is_arity_value((x))) #define _unchecked_arityval(x) _unchecked_header_arity((x)) -_ET_DECLARE_CHECKED(Uint,arityval,Eterm); +_ET_DECLARE_CHECKED(Uint,arityval,Eterm) #define arityval(x) _ET_APPLY(arityval,(x)) /* thing access methods */ #define is_thing(x) (is_header((x)) && header_is_thing((x))) #define _unchecked_thing_arityval(x) _unchecked_header_arity((x)) -_ET_DECLARE_CHECKED(Uint,thing_arityval,Eterm); +_ET_DECLARE_CHECKED(Uint,thing_arityval,Eterm) #define thing_arityval(x) _ET_APPLY(thing_arityval,(x)) #define _unchecked_thing_subtag(x) ((x) & _HEADER_SUBTAG_MASK) -_ET_DECLARE_CHECKED(Uint,thing_subtag,Eterm); +_ET_DECLARE_CHECKED(Uint,thing_subtag,Eterm) #define thing_subtag(x) _ET_APPLY(thing_subtag,(x)) /* @@ -301,7 +301,7 @@ _ET_DECLARE_CHECKED(Uint,thing_subtag,Eterm); #define is_binary(x) (is_boxed((x)) && is_binary_header(*boxed_val((x)))) #define is_not_binary(x) (!is_binary((x))) #define _unchecked_binary_val(x) _unchecked_boxed_val((x)) -_ET_DECLARE_CHECKED(Eterm*,binary_val,Eterm); +_ET_DECLARE_CHECKED(Eterm*,binary_val,Eterm) #define binary_val(x) _ET_APPLY(binary_val,(x)) /* process binaries stuff (special case of binaries) */ @@ -318,7 +318,7 @@ _ET_DECLARE_CHECKED(Eterm*,binary_val,Eterm); #define is_fun(x) (is_boxed((x)) && is_fun_header(*boxed_val((x)))) #define is_not_fun(x) (!is_fun((x))) #define _unchecked_fun_val(x) _unchecked_boxed_val((x)) -_ET_DECLARE_CHECKED(Eterm*,fun_val,Eterm); +_ET_DECLARE_CHECKED(Eterm*,fun_val,Eterm) #define fun_val(x) _ET_APPLY(fun_val,(x)) /* export access methods */ @@ -326,7 +326,7 @@ _ET_DECLARE_CHECKED(Eterm*,fun_val,Eterm); #define is_export(x) (is_boxed((x)) && is_export_header(*boxed_val((x)))) #define is_not_export(x) (!is_export((x))) #define _unchecked_export_val(x) _unchecked_boxed_val(x) -_ET_DECLARE_CHECKED(Eterm*,export_val,Eterm); +_ET_DECLARE_CHECKED(Eterm*,export_val,Eterm) #define export_val(x) _ET_APPLY(export_val,(x)) #define is_export_header(x) ((x) == HEADER_EXPORT) #define HEADER_EXPORT _make_header(1,_TAG_HEADER_EXPORT) @@ -336,20 +336,20 @@ _ET_DECLARE_CHECKED(Eterm*,export_val,Eterm); #define make_neg_bignum_header(sz) _make_header((sz),_TAG_HEADER_NEG_BIG) #define _is_bignum_header(x) (((x) & (_TAG_HEADER_MASK-_BIG_SIGN_BIT)) == _TAG_HEADER_POS_BIG) #define _unchecked_bignum_header_is_neg(x) ((x) & _BIG_SIGN_BIT) -_ET_DECLARE_CHECKED(int,bignum_header_is_neg,Eterm); +_ET_DECLARE_CHECKED(int,bignum_header_is_neg,Eterm) #define bignum_header_is_neg(x) _ET_APPLY(bignum_header_is_neg,(x)) #define _unchecked_bignum_header_neg(x) ((x) | _BIG_SIGN_BIT) -_ET_DECLARE_CHECKED(Eterm,bignum_header_neg,Eterm); +_ET_DECLARE_CHECKED(Eterm,bignum_header_neg,Eterm) #define bignum_header_neg(x) _ET_APPLY(bignum_header_neg,(x)) #define _unchecked_bignum_header_arity(x) _unchecked_header_arity((x)) -_ET_DECLARE_CHECKED(Uint,bignum_header_arity,Eterm); +_ET_DECLARE_CHECKED(Uint,bignum_header_arity,Eterm) #define bignum_header_arity(x) _ET_APPLY(bignum_header_arity,(x)) #define BIG_ARITY_MAX ((1 << 19)-1) #define make_big(x) make_boxed((x)) #define is_big(x) (is_boxed((x)) && _is_bignum_header(*boxed_val((x)))) #define is_not_big(x) (!is_big((x))) #define _unchecked_big_val(x) _unchecked_boxed_val((x)) -_ET_DECLARE_CHECKED(Eterm*,big_val,Eterm); +_ET_DECLARE_CHECKED(Eterm*,big_val,Eterm) #define big_val(x) _ET_APPLY(big_val,(x)) /* flonum ("float") access methods */ @@ -362,7 +362,7 @@ _ET_DECLARE_CHECKED(Eterm*,big_val,Eterm); #define is_float(x) (is_boxed((x)) && *boxed_val((x)) == HEADER_FLONUM) #define is_not_float(x) (!is_float(x)) #define _unchecked_float_val(x) _unchecked_boxed_val((x)) -_ET_DECLARE_CHECKED(Eterm*,float_val,Eterm); +_ET_DECLARE_CHECKED(Eterm*,float_val,Eterm) #define float_val(x) _ET_APPLY(float_val,(x)) /* Float definition for byte and word access */ @@ -409,7 +409,7 @@ typedef union float_def (is_boxed((x)) && *boxed_val((x)) == make_arityval((a))) #define is_not_tuple_arity(x, a) (!is_tuple_arity((x),(a))) #define _unchecked_tuple_val(x) _unchecked_boxed_val(x) -_ET_DECLARE_CHECKED(Eterm*,tuple_val,Eterm); +_ET_DECLARE_CHECKED(Eterm*,tuple_val,Eterm) #define tuple_val(x) _ET_APPLY(tuple_val,(x)) #define TUPLE0(t) \ @@ -548,11 +548,11 @@ _ET_DECLARE_CHECKED(Eterm*,tuple_val,Eterm); #define is_not_internal_pid(x) (!is_internal_pid((x))) #define _unchecked_internal_pid_data(x) _GET_PID_DATA((x)) -_ET_DECLARE_CHECKED(Uint,internal_pid_data,Eterm); +_ET_DECLARE_CHECKED(Uint,internal_pid_data,Eterm) #define internal_pid_data(x) _ET_APPLY(internal_pid_data,(x)) #define _unchecked_internal_pid_node(x) erts_this_node -_ET_DECLARE_CHECKED(struct erl_node_*,internal_pid_node,Eterm); +_ET_DECLARE_CHECKED(struct erl_node_*,internal_pid_node,Eterm) #define internal_pid_node(x) _ET_APPLY(internal_pid_node,(x)) #define internal_pid_number(x) _GET_PID_NUM(internal_pid_data((x))) @@ -604,13 +604,13 @@ _ET_DECLARE_CHECKED(struct erl_node_*,internal_pid_node,Eterm); #define is_not_internal_port(x) (!is_internal_port(x)) #define _unchecked_internal_port_data(x) _GET_PORT_DATA((x)) -_ET_DECLARE_CHECKED(Uint,internal_port_data,Eterm); +_ET_DECLARE_CHECKED(Uint,internal_port_data,Eterm) #define internal_port_data(x) _ET_APPLY(internal_port_data,(x)) #define internal_port_number(x) _GET_PORT_NUM(internal_port_data((x))) #define _unchecked_internal_port_node(x) erts_this_node -_ET_DECLARE_CHECKED(struct erl_node_*,internal_port_node,Eterm); +_ET_DECLARE_CHECKED(struct erl_node_*,internal_port_node,Eterm) #define internal_port_node(x) _ET_APPLY(internal_port_node,(x)) #define internal_port_data_words(x) (1) @@ -753,20 +753,20 @@ do { \ (!is_internal_ref((x))) #define _unchecked_internal_ref_val(x) _unchecked_boxed_val((x)) -_ET_DECLARE_CHECKED(Eterm*,internal_ref_val,Eterm); +_ET_DECLARE_CHECKED(Eterm*,internal_ref_val,Eterm) #define internal_ref_val(x) _ET_APPLY(internal_ref_val,(x)) #define _unchecked_internal_ref_data_words(x) \ (_unchecked_thing_arityval(*_unchecked_internal_ref_val(x))) -_ET_DECLARE_CHECKED(Uint,internal_ref_data_words,Eterm); +_ET_DECLARE_CHECKED(Uint,internal_ref_data_words,Eterm) #define internal_ref_data_words(x) _ET_APPLY(internal_ref_data_words,(x)) #define _unchecked_internal_ref_data(x) (_unchecked_ref_thing_ptr(x)->data.ui32) -_ET_DECLARE_CHECKED(Uint32*,internal_ref_data,Eterm); +_ET_DECLARE_CHECKED(Uint32*,internal_ref_data,Eterm) #define internal_ref_data(x) _ET_APPLY(internal_ref_data,(x)) #define _unchecked_internal_ref_node(x) erts_this_node -_ET_DECLARE_CHECKED(struct erl_node_*,internal_ref_node,Eterm); +_ET_DECLARE_CHECKED(struct erl_node_*,internal_ref_node,Eterm) #define internal_ref_node(x) _ET_APPLY(internal_ref_node,(x)) /* @@ -864,7 +864,7 @@ typedef struct external_thing_ { #define make_external_ref make_external #define _unchecked_external_val(x) _unchecked_boxed_val((x)) -_ET_DECLARE_CHECKED(Eterm*,external_val,Eterm); +_ET_DECLARE_CHECKED(Eterm*,external_val,Eterm) #define external_val(x) _ET_APPLY(external_val,(x)) #define external_thing_ptr(x) ((ExternalThing *) external_val((x))) @@ -874,7 +874,7 @@ _ET_DECLARE_CHECKED(Eterm*,external_val,Eterm); #define _unchecked_external_data_words(x) \ (_unchecked_thing_arityval(_unchecked_external_thing_ptr((x))->header) \ + (1 - EXTERNAL_THING_HEAD_SIZE)) -_ET_DECLARE_CHECKED(Uint,external_data_words,Eterm); +_ET_DECLARE_CHECKED(Uint,external_data_words,Eterm) #define external_data_words(x) _ET_APPLY(external_data_words,(x)) #define _unchecked_external_data(x) (_unchecked_external_thing_ptr((x))->data.ui) @@ -885,15 +885,15 @@ _ET_DECLARE_CHECKED(Uint,external_data_words,Eterm); #define _unchecked_external_pid_data_words(x) \ _unchecked_external_data_words((x)) -_ET_DECLARE_CHECKED(Uint,external_pid_data_words,Eterm); +_ET_DECLARE_CHECKED(Uint,external_pid_data_words,Eterm) #define external_pid_data_words(x) _ET_APPLY(external_pid_data_words,(x)) #define _unchecked_external_pid_data(x) _unchecked_external_data((x))[0] -_ET_DECLARE_CHECKED(Uint,external_pid_data,Eterm); +_ET_DECLARE_CHECKED(Uint,external_pid_data,Eterm) #define external_pid_data(x) _ET_APPLY(external_pid_data,(x)) #define _unchecked_external_pid_node(x) _unchecked_external_node((x)) -_ET_DECLARE_CHECKED(struct erl_node_*,external_pid_node,Eterm); +_ET_DECLARE_CHECKED(struct erl_node_*,external_pid_node,Eterm) #define external_pid_node(x) _ET_APPLY(external_pid_node,(x)) #define external_pid_number(x) _GET_PID_NUM(external_pid_data((x))) @@ -901,30 +901,30 @@ _ET_DECLARE_CHECKED(struct erl_node_*,external_pid_node,Eterm); #define _unchecked_external_port_data_words(x) \ _unchecked_external_data_words((x)) -_ET_DECLARE_CHECKED(Uint,external_port_data_words,Eterm); +_ET_DECLARE_CHECKED(Uint,external_port_data_words,Eterm) #define external_port_data_words(x) _ET_APPLY(external_port_data_words,(x)) #define _unchecked_external_port_data(x) _unchecked_external_data((x))[0] -_ET_DECLARE_CHECKED(Uint,external_port_data,Eterm); +_ET_DECLARE_CHECKED(Uint,external_port_data,Eterm) #define external_port_data(x) _ET_APPLY(external_port_data,(x)) #define _unchecked_external_port_node(x) _unchecked_external_node((x)) -_ET_DECLARE_CHECKED(struct erl_node_*,external_port_node,Eterm); +_ET_DECLARE_CHECKED(struct erl_node_*,external_port_node,Eterm) #define external_port_node(x) _ET_APPLY(external_port_node,(x)) #define external_port_number(x) _GET_PORT_NUM(external_port_data((x))) #define _unchecked_external_ref_data_words(x) \ _unchecked_external_data_words((x)) -_ET_DECLARE_CHECKED(Uint,external_ref_data_words,Eterm); +_ET_DECLARE_CHECKED(Uint,external_ref_data_words,Eterm) #define external_ref_data_words(x) _ET_APPLY(external_ref_data_words,(x)) #define _unchecked_external_ref_data(x) (_unchecked_external_thing_ptr((x))->data.ui32) -_ET_DECLARE_CHECKED(Uint32*,external_ref_data,Eterm); +_ET_DECLARE_CHECKED(Uint32*,external_ref_data,Eterm) #define external_ref_data(x) _ET_APPLY(external_ref_data,(x)) #define _unchecked_external_ref_node(x) _unchecked_external_node((x)) -_ET_DECLARE_CHECKED(struct erl_node_*,external_ref_node,Eterm); +_ET_DECLARE_CHECKED(struct erl_node_*,external_ref_node,Eterm) #define external_ref_node(x) _ET_APPLY(external_ref_node,(x)) /* number tests */ @@ -945,21 +945,21 @@ _ET_DECLARE_CHECKED(struct erl_node_*,external_ref_node,Eterm); #endif #define _unchecked_make_cp(x) ((Eterm)(x)) -_ET_DECLARE_CHECKED(Eterm,make_cp,Uint*); +_ET_DECLARE_CHECKED(Eterm,make_cp,Uint*) #define make_cp(x) _ET_APPLY(make_cp,(x)) #define is_not_CP(x) ((x) & _CPMASK) #define is_CP(x) (!is_not_CP(x)) #define _unchecked_cp_val(x) ((Uint*)(x)) -_ET_DECLARE_CHECKED(Uint*,cp_val,Eterm); +_ET_DECLARE_CHECKED(Uint*,cp_val,Eterm) #define cp_val(x) _ET_APPLY(cp_val,(x)) #define make_catch(x) (((x) << _TAG_IMMED2_SIZE) | _TAG_IMMED2_CATCH) #define is_catch(x) (((x) & _TAG_IMMED2_MASK) == _TAG_IMMED2_CATCH) #define is_not_catch(x) (!is_catch(x)) #define _unchecked_catch_val(x) ((x) >> _TAG_IMMED2_SIZE) -_ET_DECLARE_CHECKED(Uint,catch_val,Eterm); +_ET_DECLARE_CHECKED(Uint,catch_val,Eterm) #define catch_val(x) _ET_APPLY(catch_val,(x)) #define make_blank(X) ((X) = NIL) @@ -989,21 +989,21 @@ _ET_DECLARE_CHECKED(Uint,catch_val,Eterm); #define _is_yreg(x) (beam_reg_tag(x) == Y_REG_DEF) #define _unchecked_x_reg_offset(R) ((R) - X_REG_DEF) -_ET_DECLARE_CHECKED(Uint,x_reg_offset,Uint); +_ET_DECLARE_CHECKED(Uint,x_reg_offset,Uint) #define x_reg_offset(R) _ET_APPLY(x_reg_offset,(R)) #define _unchecked_y_reg_offset(R) ((R) - Y_REG_DEF) -_ET_DECLARE_CHECKED(Uint,y_reg_offset,Uint); +_ET_DECLARE_CHECKED(Uint,y_reg_offset,Uint) #define y_reg_offset(R) _ET_APPLY(y_reg_offset,(R)) #define reg_index(R) ((R) / sizeof(Eterm)) #define _unchecked_x_reg_index(R) ((R) >> 2) -_ET_DECLARE_CHECKED(Uint,x_reg_index,Uint); +_ET_DECLARE_CHECKED(Uint,x_reg_index,Uint) #define x_reg_index(R) _ET_APPLY(x_reg_index,(R)) #define _unchecked_y_reg_index(R) ((R) >> 2) -_ET_DECLARE_CHECKED(Uint,y_reg_index,Uint); +_ET_DECLARE_CHECKED(Uint,y_reg_index,Uint) #define y_reg_index(R) _ET_APPLY(y_reg_index,(R)) /* diff --git a/erts/emulator/beam/erl_time_sup.c b/erts/emulator/beam/erl_time_sup.c index 76bfdecd9f..c15f85f8f1 100644 --- a/erts/emulator/beam/erl_time_sup.c +++ b/erts/emulator/beam/erl_time_sup.c @@ -1,19 +1,19 @@ /* * %CopyrightBegin% - * - * Copyright Ericsson AB 1999-2009. All Rights Reserved. - * + * + * Copyright Ericsson AB 1999-2010. 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% */ @@ -754,12 +754,8 @@ get_sys_now(Uint* megasec, Uint* sec, Uint* microsec) { SysTimeval now; - erts_smp_mtx_lock(&erts_timeofday_mtx); - sys_gettimeofday(&now); - erts_smp_mtx_unlock(&erts_timeofday_mtx); - *megasec = (Uint) (now.tv_sec / 1000000); *sec = (Uint) (now.tv_sec % 1000000); *microsec = (Uint) (now.tv_usec); diff --git a/erts/emulator/beam/erl_trace.c b/erts/emulator/beam/erl_trace.c index 2afb16fc52..2842c2361a 100644 --- a/erts/emulator/beam/erl_trace.c +++ b/erts/emulator/beam/erl_trace.c @@ -1,19 +1,19 @@ /* * %CopyrightBegin% - * - * Copyright Ericsson AB 1999-2009. All Rights Reserved. - * + * + * Copyright Ericsson AB 1999-2010. 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% */ @@ -2171,6 +2171,11 @@ erts_bif_trace(int bif_index, Process* p, void trace_gc(Process *p, Eterm what) { + ERTS_DECL_AM(bin_vheap_size); + ERTS_DECL_AM(bin_vheap_block_size); + ERTS_DECL_AM(bin_old_vheap_size); + ERTS_DECL_AM(bin_old_vheap_block_size); + ErlHeapFragment *bp = NULL; ErlOffHeap *off_heap; ERTS_TRACER_REF_TYPE tracer_ref = ERTS_NULL_TRACER_REF; /* Initialized @@ -2180,6 +2185,7 @@ trace_gc(Process *p, Eterm what) Eterm* hp; Eterm msg = NIL; Uint size; + Eterm tags[] = { am_old_heap_block_size, am_heap_block_size, @@ -2187,8 +2193,13 @@ trace_gc(Process *p, Eterm what) am_recent_size, am_stack_size, am_old_heap_size, - am_heap_size + am_heap_size, + AM_bin_vheap_size, + AM_bin_vheap_block_size, + AM_bin_old_vheap_size, + AM_bin_old_vheap_block_size }; + Uint values[] = { OLD_HEAP(p) ? OLD_HEND(p) - OLD_HEAP(p) : 0, HEAP_SIZE(p), @@ -2196,7 +2207,11 @@ trace_gc(Process *p, Eterm what) HIGH_WATER(p) - HEAP_START(p), STACK_START(p) - p->stop, OLD_HEAP(p) ? OLD_HTOP(p) - OLD_HEAP(p) : 0, - HEAP_TOP(p) - HEAP_START(p) + HEAP_TOP(p) - HEAP_START(p), + MSO(p).overhead, + BIN_VHEAP_SZ(p), + BIN_OLD_VHEAP(p), + BIN_OLD_VHEAP_SZ(p) }; Eterm local_heap[(sizeof(values)/sizeof(Uint)) *(2/*cons*/ + 3/*2-tuple*/ + BIG_UINT_HEAP_SIZE) diff --git a/erts/emulator/beam/erl_vm.h b/erts/emulator/beam/erl_vm.h index 4d8315ab95..50b3e5b61c 100644 --- a/erts/emulator/beam/erl_vm.h +++ b/erts/emulator/beam/erl_vm.h @@ -1,19 +1,19 @@ /* * %CopyrightBegin% - * - * Copyright Ericsson AB 1996-2009. All Rights Reserved. - * + * + * Copyright Ericsson AB 1996-2010. 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% */ @@ -22,6 +22,13 @@ /* #define ERTS_OPCODE_COUNTER_SUPPORT */ +/* FORCE_HEAP_FRAGS: + * Debug provocation to make HAlloc always create heap fragments (if allowed) + * even if there is room on heap. + */ +/* #define FORCE_HEAP_FRAGS */ + + #if defined(HYBRID) /* # define CHECK_FOR_HOLES */ #endif @@ -50,7 +57,8 @@ #define INPUT_REDUCTIONS (2 * CONTEXT_REDS) -#define H_DEFAULT_SIZE 233 /* default (heap + stack) min size */ +#define H_DEFAULT_SIZE 233 /* default (heap + stack) min size */ +#define VH_DEFAULT_SIZE 32768 /* default virtual (bin) heap min size (words) */ #ifdef HYBRID # define SH_DEFAULT_SIZE 2629425 /* default message area min size */ @@ -70,6 +78,7 @@ && (P) == (P)->scheduler_data->match_pseudo_process) \ || erts_is_system_blocked(0)) + #ifdef DEBUG /* * Debug HAlloc that initialize all memory to bad things. @@ -80,55 +89,43 @@ VERBOSE(DEBUG_ALLOCATION,("HAlloc @ 0x%08lx (%d) %s:%d\n", \ (unsigned long)HEAP_TOP(p),(sz),__FILE__,__LINE__)), \ */ -#ifdef CHECK_FOR_HOLES -#define HAlloc(p, sz) \ - (ASSERT_EXPR((sz) >= 0), \ - ErtsHAllocLockCheck(p), \ - ((((HEAP_LIMIT(p) - HEAP_TOP(p)) < (sz))) \ - ? erts_heap_alloc((p),(sz)) \ - : (erts_set_hole_marker(HEAP_TOP(p), (sz)), \ - HEAP_TOP(p) = HEAP_TOP(p) + (sz), HEAP_TOP(p) - (sz)))) +# ifdef CHECK_FOR_HOLES +# define INIT_HEAP_MEM(p,sz) erts_set_hole_marker(HEAP_TOP(p), (sz)) +# else +# define INIT_HEAP_MEM(p,sz) memset(HEAP_TOP(p),DEBUG_BAD_BYTE,(sz)*sizeof(Eterm*)) +# endif #else -#define HAlloc(p, sz) \ - (ASSERT_EXPR((sz) >= 0), \ - ErtsHAllocLockCheck(p), \ - ((((HEAP_LIMIT(p) - HEAP_TOP(p)) < (sz))) \ - ? erts_heap_alloc((p),(sz)) \ - : (memset(HEAP_TOP(p),DEBUG_BAD_BYTE,(sz)*sizeof(Eterm*)), \ - HEAP_TOP(p) = HEAP_TOP(p) + (sz), HEAP_TOP(p) - (sz)))) -#endif +# define INIT_HEAP_MEM(p,sz) ((void)0) +#endif /* DEBUG */ + + +#ifdef FORCE_HEAP_FRAGS +# define IS_FORCE_HEAP_FRAGS 1 #else +# define IS_FORCE_HEAP_FRAGS 0 +#endif /* * Allocate heap memory, first on the ordinary heap; * failing that, in a heap fragment. */ -#define HAlloc(p, sz) \ - (ASSERT_EXPR((sz) >= 0), \ - ErtsHAllocLockCheck(p), \ - ((((HEAP_LIMIT(p) - HEAP_TOP(p)) < (sz))) \ - ? erts_heap_alloc((p),(sz)) \ - : (HEAP_TOP(p) = HEAP_TOP(p) + (sz), HEAP_TOP(p) - (sz)))) +#define HAlloc(p, sz) \ + (ASSERT_EXPR((sz) >= 0), \ + ErtsHAllocLockCheck(p), \ + (IS_FORCE_HEAP_FRAGS || (((HEAP_LIMIT(p) - HEAP_TOP(p)) < (sz))) \ + ? erts_heap_alloc((p),(sz)) \ + : (INIT_HEAP_MEM(p,sz), \ + HEAP_TOP(p) = HEAP_TOP(p) + (sz), HEAP_TOP(p) - (sz)))) -#endif /* DEBUG */ -#if defined(CHECK_FOR_HOLES) -# define HRelease(p, endp, ptr) \ +#define HRelease(p, endp, ptr) \ if ((ptr) == (endp)) { \ ; \ } else if (HEAP_START(p) <= (ptr) && (ptr) < HEAP_TOP(p)) { \ HEAP_TOP(p) = (ptr); \ } else { \ - erts_arith_shrink(p, ptr); \ + erts_heap_frag_shrink(p, ptr); \ } -#else -# define HRelease(p, endp, ptr) \ - if ((ptr) == (endp)) { \ - ; \ - } else if (HEAP_START(p) <= (ptr) && (ptr) < HEAP_TOP(p)) { \ - HEAP_TOP(p) = (ptr); \ - } -#endif #define HeapWordsLeft(p) (HEAP_LIMIT(p) - HEAP_TOP(p)) @@ -182,6 +179,9 @@ extern int num_instructions; /* Number of instruction in opc[]. */ #define MAX_PORT_LINK 8 /* Maximum number of links to a port */ extern int H_MIN_SIZE; /* minimum (heap + stack) */ +extern int BIN_VH_MIN_SIZE; /* minimum virtual (bin) heap */ + +extern int erts_atom_table_size;/* Atom table size */ #define ORIG_CREATION 0 diff --git a/erts/emulator/beam/external.c b/erts/emulator/beam/external.c index f856cce18f..099eddd195 100644 --- a/erts/emulator/beam/external.c +++ b/erts/emulator/beam/external.c @@ -1,19 +1,19 @@ /* * %CopyrightBegin% - * - * Copyright Ericsson AB 1996-2009. All Rights Reserved. - * + * + * Copyright Ericsson AB 1996-2010. 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% */ @@ -271,11 +271,8 @@ erts_encode_ext_dist_header_size(ErtsAtomCacheMap *acmp) byte *erts_encode_ext_dist_header_setup(byte *ctl_ext, ErtsAtomCacheMap *acmp) { -#ifndef ARCH_32 -#if ATOM_LIMIT >= (1UL << 32) -#error "ATOM_LIMIT too large for interal atom cache update instructions. New instructions needed." -#endif -#endif + /* Maximum number of atom must be less than the maximum of a 32 bits + unsigned integer. Check is done in erl_init.c, erl_start function. */ if (!acmp) return ctl_ext; else { @@ -1013,6 +1010,35 @@ term_to_binary_2(Process* p, Eterm Term, Eterm Flags) return erts_term_to_binary(p, Term, level, flags); } +static uLongf binary2term_uncomp_size(byte* data, Sint size) +{ + z_stream stream; + int err; + const uInt chunk_size = 64*1024; /* Ask tmp-alloc about a suitable size? */ + void* tmp_buf = erts_alloc(ERTS_ALC_T_TMP, chunk_size); + uLongf uncomp_size = 0; + + stream.next_in = (Bytef*)data; + stream.avail_in = (uInt)size; + stream.next_out = tmp_buf; + stream.avail_out = (uInt)chunk_size; + + erl_zlib_alloc_init(&stream); + + err = inflateInit(&stream); + if (err == Z_OK) { + do { + stream.next_out = tmp_buf; + stream.avail_out = chunk_size; + err = inflate(&stream, Z_NO_FLUSH); + uncomp_size += chunk_size - stream.avail_out; + }while (err == Z_OK); + inflateEnd(&stream); + } + erts_free(ERTS_ALC_T_TMP, tmp_buf); + return err == Z_STREAM_END ? uncomp_size : 0; +} + static ERTS_INLINE Sint binary2term_prepare(ErtsBinary2TermState *state, byte *data, Sint data_size) { @@ -1036,10 +1062,18 @@ binary2term_prepare(ErtsBinary2TermState *state, byte *data, Sint data_size) state->extp = bytes; } else { - uLongf dest_len = get_int32(bytes+1); - state->extp = erts_alloc(ERTS_ALC_T_TMP, dest_len); + uLongf dest_len = (Uint32) get_int32(bytes+1); + bytes += 5; + size -= 5; + if (dest_len > 32*1024*1024 + || (state->extp = erts_alloc_fnf(ERTS_ALC_T_TMP, dest_len)) == NULL) { + if (dest_len != binary2term_uncomp_size(bytes, size)) { + goto error; + } + state->extp = erts_alloc(ERTS_ALC_T_TMP, dest_len); + } state->exttmp = 1; - if (erl_zlib_uncompress(state->extp, &dest_len, bytes+5, size-5) != Z_OK) + if (erl_zlib_uncompress(state->extp, &dest_len, bytes, size) != Z_OK) goto error; size = (Sint) dest_len; } @@ -1059,10 +1093,10 @@ binary2term_abort(ErtsBinary2TermState *state) } static ERTS_INLINE Eterm -binary2term_create(ErtsBinary2TermState *state, Eterm **hpp, ErlOffHeap *ohp) +binary2term_create(ErtsDistExternal *edep, ErtsBinary2TermState *state, Eterm **hpp, ErlOffHeap *ohp) { Eterm res; - if (!dec_term(NULL, hpp, state->extp, ohp, &res)) + if (!dec_term(edep, hpp, state->extp, ohp, &res)) res = THE_NON_VALUE; if (state->exttmp) { state->exttmp = 0; @@ -1086,7 +1120,7 @@ erts_binary2term_abort(ErtsBinary2TermState *state) Eterm erts_binary2term_create(ErtsBinary2TermState *state, Eterm **hpp, ErlOffHeap *ohp) { - return binary2term_create(state, hpp, ohp); + return binary2term_create(NULL,state, hpp, ohp); } BIF_RETTYPE binary_to_term_1(BIF_ALIST_1) @@ -1114,7 +1148,67 @@ BIF_RETTYPE binary_to_term_1(BIF_ALIST_1) hp = HAlloc(BIF_P, heap_size); endp = hp + heap_size; - res = binary2term_create(&b2ts, &hp, &MSO(BIF_P)); + res = binary2term_create(NULL, &b2ts, &hp, &MSO(BIF_P)); + + erts_free_aligned_binary_bytes(temp_alloc); + + if (hp > endp) { + erl_exit(1, ":%s, line %d: heap overrun by %d words(s)\n", + __FILE__, __LINE__, hp-endp); + } + + HRelease(BIF_P, endp, hp); + + if (res == THE_NON_VALUE) + goto error; + + return res; +} + +BIF_RETTYPE binary_to_term_2(BIF_ALIST_2) +{ + Sint heap_size; + Eterm res; + Eterm opts; + Eterm opt; + Eterm* hp; + Eterm* endp; + Sint size; + byte* bytes; + byte* temp_alloc = NULL; + ErtsBinary2TermState b2ts; + ErtsDistExternal fakedep; + + fakedep.flags = 0; + opts = BIF_ARG_2; + while (is_list(opts)) { + opt = CAR(list_val(opts)); + if (opt == am_safe) { + fakedep.flags |= ERTS_DIST_EXT_BTT_SAFE; + } else { + goto error; + } + opts = CDR(list_val(opts)); + } + + if (is_not_nil(opts)) + goto error; + + if ((bytes = erts_get_aligned_binary_bytes(BIF_ARG_1, &temp_alloc)) == NULL) { + error: + erts_free_aligned_binary_bytes(temp_alloc); + BIF_ERROR(BIF_P, BADARG); + } + size = binary_size(BIF_ARG_1); + + heap_size = binary2term_prepare(&b2ts, bytes, size); + if (heap_size < 0) + goto error; + + hp = HAlloc(BIF_P, heap_size); + endp = hp + heap_size; + + res = binary2term_create(&fakedep, &b2ts, &hp, &MSO(BIF_P)); erts_free_aligned_binary_bytes(temp_alloc); @@ -1300,7 +1394,7 @@ dec_atom(ErtsDistExternal *edep, byte* ep, Eterm* objp) switch (*ep++) { case ATOM_CACHE_REF: - if (!(edep->flags & ERTS_DIST_EXT_ATOM_TRANS_TAB)) + if (!(edep && (edep->flags & ERTS_DIST_EXT_ATOM_TRANS_TAB))) goto error; n = get_int8(ep); ep++; @@ -1312,13 +1406,18 @@ dec_atom(ErtsDistExternal *edep, byte* ep, Eterm* objp) case ATOM_EXT: len = get_int16(ep), ep += 2; - *objp = am_atom_put((char*)ep, len); - ep += len; - break; + goto dec_atom_common; case SMALL_ATOM_EXT: len = get_int8(ep); ep++; - *objp = am_atom_put((char*)ep, len); + dec_atom_common: + if (edep && (edep->flags & ERTS_DIST_EXT_BTT_SAFE)) { + if (!erts_atom_get((char*)ep, len, objp)) { + goto error; + } + } else { + *objp = am_atom_put((char*)ep, len); + } ep += len; break; default: @@ -1775,9 +1874,80 @@ is_external_string(Eterm list, int* p_is_string) return len; } +/* Assumes that the ones to undo are preluding the lists. */ +static void +undo_offheap_in_area(ErlOffHeap* off_heap, Eterm* start, Eterm* end) +{ + const Uint area_sz = (end - start) * sizeof(Eterm); + struct proc_bin* mso; + struct proc_bin** mso_nextp = NULL; +#ifndef HYBRID /* FIND ME! */ + struct erl_fun_thing* funs; + struct erl_fun_thing** funs_nextp = NULL; +#endif + struct external_thing_* ext; + struct external_thing_** ext_nextp = NULL; + + for (mso = off_heap->mso; ; mso=mso->next) { + if (!in_area(mso, start, area_sz)) { + if (mso_nextp != NULL) { + *mso_nextp = NULL; + erts_cleanup_mso(off_heap->mso); + off_heap->mso = mso; + } + break; + } + mso_nextp = &mso->next; + } + +#ifndef HYBRID /* FIND ME! */ + for (funs = off_heap->funs; ; funs=funs->next) { + if (!in_area(funs, start, area_sz)) { + if (funs_nextp != NULL) { + *funs_nextp = NULL; + erts_cleanup_funs(off_heap->funs); + off_heap->funs = funs; + } + break; + } + funs_nextp = &funs->next; + } +#endif + for (ext = off_heap->externals; ; ext=ext->next) { + if (!in_area(ext, start, area_sz)) { + if (ext_nextp != NULL) { + *ext_nextp = NULL; + erts_cleanup_externals(off_heap->externals); + off_heap->externals = ext; + } + break; + } + ext_nextp = &ext->next; + } + + /* Assert that the ones to undo were indeed preluding the lists. */ +#ifdef DEBUG + for (mso = off_heap->mso; mso != NULL; mso=mso->next) { + ASSERT(!in_area(mso, start, area_sz)); + } +# ifndef HYBRID /* FIND ME! */ + for (funs = off_heap->funs; funs != NULL; funs=funs->next) { + ASSERT(!in_area(funs, start, area_sz)); + } +# endif + for (ext = off_heap->externals; ext != NULL; ext=ext->next) { + ASSERT(!in_area(ext, start, area_sz)); + } +#endif /* DEBUG */ +} + +/* Decode term from external format into *objp. +** On failure return NULL and (R13B04) *hpp will be unchanged. +*/ static byte* dec_term(ErtsDistExternal *edep, Eterm** hpp, byte* ep, ErlOffHeap* off_heap, Eterm* objp) { + Eterm* hp_saved = *hpp; int n; register Eterm* hp = *hpp; /* Please don't take the address of hp */ Eterm* next = objp; @@ -1864,13 +2034,18 @@ dec_term(ErtsDistExternal *edep, Eterm** hpp, byte* ep, ErlOffHeap* off_heap, Et case ATOM_EXT: n = get_int16(ep); ep += 2; - *objp = am_atom_put((char*)ep, n); - ep += n; - break; + goto dec_term_atom_common; case SMALL_ATOM_EXT: n = get_int8(ep); ep++; - *objp = am_atom_put((char*)ep, n); +dec_term_atom_common: + if (edep && (edep->flags & ERTS_DIST_EXT_BTT_SAFE)) { + if (!erts_atom_get((char*)ep, n, objp)) { + goto error; + } + } else { + *objp = am_atom_put((char*)ep, n); + } ep += n; break; case LARGE_TUPLE_EXT: @@ -1973,7 +2148,7 @@ dec_term(ErtsDistExternal *edep, Eterm** hpp, byte* ep, ErlOffHeap* off_heap, Et ep = dec_pid(edep, hpp, ep, off_heap, objp); hp = *hpp; if (ep == NULL) { - return NULL; + goto error; } break; case PORT_EXT: @@ -2039,7 +2214,6 @@ dec_term(ErtsDistExternal *edep, Eterm** hpp, byte* ep, ErlOffHeap* off_heap, Et goto ref_ext_common; case NEW_REFERENCE_EXT: - ref_words = get_int16(ep); ep += 2; @@ -2209,7 +2383,7 @@ dec_term(ErtsDistExternal *edep, Eterm** hpp, byte* ep, ErlOffHeap* off_heap, Et ep = dec_term(edep, hpp, ep, off_heap, &temp); hp = *hpp; if (ep == NULL) { - return NULL; + goto error; } if (!is_small(temp)) { goto error; @@ -2218,6 +2392,10 @@ dec_term(ErtsDistExternal *edep, Eterm** hpp, byte* ep, ErlOffHeap* off_heap, Et if (arity < 0) { goto error; } + if (edep && (edep->flags & ERTS_DIST_EXT_BTT_SAFE)) { + if (!erts_find_export_entry(mod, name, arity)) + goto error; + } *objp = make_export(hp); *hp++ = HEADER_EXPORT; *hp++ = (Eterm) erts_export_get_or_make_stub(mod, name, arity); @@ -2235,8 +2413,6 @@ dec_term(ErtsDistExternal *edep, Eterm** hpp, byte* ep, ErlOffHeap* off_heap, Et Sint old_index; unsigned num_free; int i; - Eterm* temp_hp; - Eterm** hpp = &temp_hp; Eterm temp; ep += 4; /* Skip total size in bytes */ @@ -2248,23 +2424,16 @@ dec_term(ErtsDistExternal *edep, Eterm** hpp, byte* ep, ErlOffHeap* off_heap, Et num_free = get_int32(ep); ep += 4; hp += ERL_FUN_SIZE; - if (num_free > 0) { - /* Don't leave a hole in case we fail */ - *hp = make_pos_bignum_header(num_free-1); - } hp += num_free; - *hpp = hp; funp->thing_word = HEADER_FUN; funp->num_free = num_free; - funp->creator = NIL; /* Don't leave a hole in case we fail */ *objp = make_fun(funp); /* Module */ - if ((ep = dec_atom(edep, ep, &temp)) == NULL) { + if ((ep = dec_atom(edep, ep, &module)) == NULL) { goto error; } - module = temp; - + *hpp = hp; /* Index */ if ((ep = dec_term(edep, hpp, ep, off_heap, &temp)) == NULL) { goto error; @@ -2321,17 +2490,11 @@ dec_term(ErtsDistExternal *edep, Eterm** hpp, byte* ep, ErlOffHeap* off_heap, Et Sint old_index; unsigned num_free; int i; - Eterm* temp_hp; - Eterm** hpp = &temp_hp; Eterm temp; num_free = get_int32(ep); ep += 4; hp += ERL_FUN_SIZE; - if (num_free > 0) { - /* Don't leave a hole in the heap in case we fail. */ - *hp = make_pos_bignum_header(num_free-1); - } hp += num_free; *hpp = hp; funp->thing_word = HEADER_FUN; @@ -2339,23 +2502,16 @@ dec_term(ErtsDistExternal *edep, Eterm** hpp, byte* ep, ErlOffHeap* off_heap, Et *objp = make_fun(funp); /* Creator pid */ - switch(*ep) { - case PID_EXT: - ep = dec_pid(edep, hpp, ++ep, off_heap, &funp->creator); - if (ep == NULL) { - funp->creator = NIL; /* Don't leave a hole in the heap */ - goto error; - } - break; - default: + if (*ep != PID_EXT + || (ep = dec_pid(edep, hpp, ++ep, off_heap, + &funp->creator))==NULL) { goto error; } /* Module */ - if ((ep = dec_atom(edep, ep, &temp)) == NULL) { + if ((ep = dec_atom(edep, ep, &module)) == NULL) { goto error; } - module = temp; /* Index */ if ((ep = dec_term(edep, hpp, ep, off_heap, &temp)) == NULL) { @@ -2382,7 +2538,6 @@ dec_term(ErtsDistExternal *edep, Eterm** hpp, byte* ep, ErlOffHeap* off_heap, Et funp->next = off_heap->funs; off_heap->funs = funp; #endif - old_uniq = unsigned_val(temp); funp->fe = erts_put_fun_entry(module, old_uniq, old_index); @@ -2401,12 +2556,15 @@ dec_term(ErtsDistExternal *edep, Eterm** hpp, byte* ep, ErlOffHeap* off_heap, Et } default: error: - /* - * Be careful to return the updated heap pointer, to avoid - * that the caller wipes out binaries or other off-heap objects - * that may have been linked into the process. + /* UNDO: + * Must unlink all off-heap objects that may have been + * linked into the process. */ - *hpp = hp; + if (hp < *hpp) { /* Sometimes we used hp and sometimes *hpp */ + hp = *hpp; /* the largest must be the freshest */ + } + undo_offheap_in_area(off_heap, hp_saved, hp); + *hpp = hp_saved; return NULL; } } diff --git a/erts/emulator/beam/external.h b/erts/emulator/beam/external.h index f308680f89..eada6d4f27 100644 --- a/erts/emulator/beam/external.h +++ b/erts/emulator/beam/external.h @@ -1,19 +1,19 @@ /* * %CopyrightBegin% - * - * Copyright Ericsson AB 1996-2009. All Rights Reserved. - * + * + * Copyright Ericsson AB 1996-2010. 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% */ @@ -98,9 +98,19 @@ typedef struct { Eterm atom[ERTS_ATOM_CACHE_SIZE]; } ErtsAtomTranslationTable; -#define ERTS_DIST_EXT_DFLAG_HDR (((Uint32) 1) << 31) -#define ERTS_DIST_EXT_ATOM_TRANS_TAB (((Uint32) 1) << 30) -#define ERTS_DIST_EXT_CON_ID_MASK ((Uint32) 0x3fffffff) +/* + * These flags are tagged onto the high bits of a connection ID and stored in + * the ErtsDistExternal structure's flags field. They are used to indicate + * various bits of state necessary to decode binaries in a variety of + * scenarios. The mask ERTS_DIST_EXT_CON_ID_MASK is used later to separate the + * connection ID from the flags. Be careful to ensure that the mask does not + * overlap any of the bits used for flags, or ERTS will leak flags bits into + * connection IDs and leak connection ID bits into the flags. + */ +#define ERTS_DIST_EXT_DFLAG_HDR ((Uint32) 0x80000000) +#define ERTS_DIST_EXT_ATOM_TRANS_TAB ((Uint32) 0x40000000) +#define ERTS_DIST_EXT_BTT_SAFE ((Uint32) 0x20000000) +#define ERTS_DIST_EXT_CON_ID_MASK ((Uint32) 0x1fffffff) #define ERTS_DIST_EXT_CON_ID(DIST_EXTP) \ ((DIST_EXTP)->flags & ERTS_DIST_EXT_CON_ID_MASK) diff --git a/erts/emulator/beam/global.h b/erts/emulator/beam/global.h index 1b64e23174..cab249a53f 100644 --- a/erts/emulator/beam/global.h +++ b/erts/emulator/beam/global.h @@ -1,19 +1,19 @@ /* * %CopyrightBegin% - * - * Copyright Ericsson AB 1996-2009. All Rights Reserved. - * + * + * Copyright Ericsson AB 1996-2010. 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% */ @@ -21,6 +21,7 @@ #define __GLOBAL_H__ #include "sys.h" +#include <stddef.h> /* offsetof() */ #include "erl_alloc.h" #include "erl_vm.h" #include "erl_node_container_utils.h" @@ -75,18 +76,29 @@ typedef struct line_buf { /* Buffer used in line oriented I/O */ The rest is the overflow buffer. */ } LineBuf; +/* Temporary object header, auto-deallocated when NIF returns. */ +struct enif_tmp_obj_t { + struct enif_tmp_obj_t* next; + void (*dtor)(struct enif_tmp_obj_t*); + /*char data[];*/ +}; struct enif_environment_t /* ErlNifEnv */ { - void* nif_data; + struct erl_module_nif* mod_nif; Process* proc; Eterm* hp; Eterm* hp_end; - unsigned heap_frag_sz; + ErlHeapFragment* heap_frag; int fpe_was_unmasked; + struct enif_tmp_obj_t* tmp_obj_list; }; -extern void erts_pre_nif(struct enif_environment_t*, Process*, void* nif_data); +extern void erts_pre_nif(struct enif_environment_t*, Process*, + struct erl_module_nif*); extern void erts_post_nif(struct enif_environment_t* env); -extern Eterm erts_nif_taints(Process* p); +extern Eterm erts_nif_taints(Process* p); +extern void erts_print_nif_taints(int to, void* to_arg); +void erts_unload_nif(struct erl_module_nif* nif); +extern void erl_nif_init(void); /* * Port Specific Data. @@ -381,17 +393,45 @@ extern Eterm erts_ddll_monitor_driver(Process *p, ** and Binary, the macros below can convert one type to the other, as they both ** in reality are equal. */ -typedef struct binary { - Uint flags; - erts_refc_t refc; + #ifdef ARCH_32 - Uint32 align__; /* *DO NOT USE* only for alignment. */ + /* *DO NOT USE* only for alignment. */ +#define ERTS_BINARY_STRUCT_ALIGNMENT Uint32 align__; +#else +#define ERTS_BINARY_STRUCT_ALIGNMENT #endif - /* Add fields BEFORE this, otherwise the drivers crash */ + +/* Add fields in ERTS_INTERNAL_BINARY_FIELDS, otherwise the drivers crash */ +#define ERTS_INTERNAL_BINARY_FIELDS \ + Uint flags; \ + erts_refc_t refc; \ + ERTS_BINARY_STRUCT_ALIGNMENT + +typedef struct binary { + ERTS_INTERNAL_BINARY_FIELDS long orig_size; char orig_bytes[1]; /* to be continued */ } Binary; +#define ERTS_SIZEOF_Binary(Sz) \ + (offsetof(Binary,orig_bytes) + (Sz)) + +typedef struct { + ERTS_INTERNAL_BINARY_FIELDS + long orig_size; + void (*destructor)(Binary *); + char magic_bin_data[1]; +} ErtsMagicBinary; + +typedef union { + Binary binary; + ErtsMagicBinary magic_binary; + struct { + ERTS_INTERNAL_BINARY_FIELDS + ErlDrvBinary binary; + } driver; +} ErtsBinary; + /* * 'Binary' alignment: * Address of orig_bytes[0] of a Binary should always be 8-byte aligned. @@ -399,25 +439,23 @@ typedef struct binary { * 32-bits architectures and 8 bytes on 64-bits architectures. */ -/* - * "magic" binary. - */ -typedef struct { - void (*destructor)(Binary *); - char magic_bin_data[1]; -} ErtsBinaryMagicPart; - #define ERTS_MAGIC_BIN_DESTRUCTOR(BP) \ - (((ErtsBinaryMagicPart *) (BP)->orig_bytes)->destructor) + ((ErtsBinary *) (BP))->magic_binary.destructor #define ERTS_MAGIC_BIN_DATA(BP) \ - ((void *) (((ErtsBinaryMagicPart *) (BP)->orig_bytes)->magic_bin_data)) + ((void *) ((ErtsBinary *) (BP))->magic_binary.magic_bin_data) #define ERTS_MAGIC_BIN_DATA_SIZE(BP) \ - ((BP)->orig_size - (sizeof(ErtsBinaryMagicPart) - 1)) - -#define Binary2ErlDrvBinary(B) ((ErlDrvBinary *) (&((B)->orig_size))) + ((BP)->orig_size - sizeof(void (*)(Binary *))) +#define ERTS_MAGIC_BIN_ORIG_SIZE(Sz) \ + (sizeof(void (*)(Binary *)) + (Sz)) +#define ERTS_MAGIC_BIN_SIZE(Sz) \ + (offsetof(ErtsMagicBinary,magic_bin_data) + (Sz)) +#define ERTS_MAGIC_BIN_FROM_DATA(DATA) \ + ((ErtsBinary*)((char*)(DATA) - offsetof(ErtsMagicBinary,magic_bin_data))) + +#define Binary2ErlDrvBinary(B) (&((ErtsBinary *) (B))->driver.binary) #define ErlDrvBinary2Binary(D) ((Binary *) \ - (((char *) (D)) - \ - ((char *) &(((Binary *) 0)->orig_size)))) + (((char *) (D)) \ + - offsetof(ErtsBinary, driver.binary))) /* A "magic" binary flag */ #define BIN_FLAG_MAGIC 1 @@ -1405,6 +1443,11 @@ void p_slpq(_VOID_); /* utils.c */ +/* + * To be used to silence unused result warnings, but do not abuse it. + */ +void erts_silence_warn_unused_result(long unused); + void erts_cleanup_offheap(ErlOffHeap *offheap); void erts_cleanup_externals(ExternalThing *); @@ -1657,7 +1700,6 @@ void erts_bif_trace_init(void); /* ** Call_trace uses this API for the parameter matching functions */ - struct erl_heap_fragment* saved_program_buf; #define MatchSetRef(MPSP) \ do { \ diff --git a/erts/emulator/beam/io.c b/erts/emulator/beam/io.c index 61985271e6..ad0b909b2a 100644 --- a/erts/emulator/beam/io.c +++ b/erts/emulator/beam/io.c @@ -1,19 +1,19 @@ /* * %CopyrightBegin% - * - * Copyright Ericsson AB 1996-2009. All Rights Reserved. - * + * + * Copyright Ericsson AB 1996-2010. 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% */ @@ -31,6 +31,7 @@ /* must be included BEFORE global.h (since it includes erl_driver.h) */ #include "erl_sys_driver.h" +#include "erl_nif.h" #include "erl_vm.h" #include "global.h" @@ -1078,7 +1079,7 @@ int erts_write_to_port(Eterm caller_id, Port *p, Eterm list) } cbin = driver_alloc_binary(csize); if (!cbin) - erts_alloc_enomem(ERTS_ALC_T_DRV_BINARY, sizeof(Binary) + csize); + erts_alloc_enomem(ERTS_ALC_T_DRV_BINARY, ERTS_SIZEOF_Binary(csize)); /* Element 0 is for driver usage to add header block */ ivp[0].iov_base = NULL; @@ -1227,7 +1228,7 @@ void init_io(void) erts_smp_atomic_init(&erts_port[i].refc, 0); erts_port[i].lock = NULL; erts_port[i].xports = NULL; - erts_smp_spinlock_init(&erts_port[i].state_lck, "port_state"); + erts_smp_spinlock_init_x(&erts_port[i].state_lck, "port_state", make_small(i)); #endif erts_port[i].tracer_proc = NIL; erts_port[i].trace_flags = 0; @@ -4473,7 +4474,14 @@ driver_system_info(ErlDrvSysInfo *sip, size_t si_size) sip->async_threads = erts_async_max_threads; sip->scheduler_threads = erts_no_schedulers; } - + /* + * 'nif_minor_version' is the last field in the third version + * (driver version 1.5, NIF version 1.0) + */ + if (si_size >= ERL_DRV_SYS_INFO_SIZE(nif_minor_version)) { + sip->nif_major_version = ERL_NIF_MAJOR_VERSION; + sip->nif_minor_version = ERL_NIF_MINOR_VERSION; + } } diff --git a/erts/emulator/beam/module.c b/erts/emulator/beam/module.c index 57a43c89f4..91e4ccce70 100644 --- a/erts/emulator/beam/module.c +++ b/erts/emulator/beam/module.c @@ -1,19 +1,19 @@ /* * %CopyrightBegin% - * - * Copyright Ericsson AB 1996-2009. All Rights Reserved. - * + * + * Copyright Ericsson AB 1996-2010. 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% */ @@ -66,12 +66,8 @@ static Module* module_alloc(Module* tmpl) obj->code_length = 0; obj->old_code_length = 0; obj->slot.index = -1; - obj->nif.handle = NULL; - obj->old_nif.handle = NULL; - obj->nif.entry = NULL; - obj->old_nif.entry = NULL; - obj->nif.data = NULL; - obj->old_nif.data = NULL; + obj->nif = NULL; + obj->old_nif = NULL; return obj; } diff --git a/erts/emulator/beam/module.h b/erts/emulator/beam/module.h index 314be8e2ee..87d13b3607 100644 --- a/erts/emulator/beam/module.h +++ b/erts/emulator/beam/module.h @@ -1,19 +1,19 @@ /* * %CopyrightBegin% - * - * Copyright Ericsson AB 1996-2009. All Rights Reserved. - * + * + * Copyright Ericsson AB 1996-2010. 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% */ @@ -24,11 +24,6 @@ #include "index.h" #endif -struct erl_module_nif { - void* handle; - struct enif_entry_t* entry; - void* data; -}; typedef struct erl_module { IndexSlot slot; /* Must be located at top of struct! */ @@ -39,8 +34,8 @@ typedef struct erl_module { 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_nif* nif; + struct erl_module_nif* old_nif; } Module; Module* erts_get_module(Eterm mod); diff --git a/erts/emulator/beam/sys.h b/erts/emulator/beam/sys.h index 71cb6a36cc..4b949523fa 100644 --- a/erts/emulator/beam/sys.h +++ b/erts/emulator/beam/sys.h @@ -239,6 +239,11 @@ EXTERN_FUNCTION(int, real_printf, (const char *fmt, ...)); ** Sint16: A signed integer of 16 bits exactly. */ +#if !((SIZEOF_VOID_P >= 4) && (SIZEOF_VOID_P == SIZEOF_SIZE_T) \ + && ((SIZEOF_VOID_P == SIZEOF_INT) || (SIZEOF_VOID_P == SIZEOF_LONG))) +#error Cannot handle this combination of int/long/void*/size_t sizes +#endif + #if SIZEOF_VOID_P == 8 #undef ARCH_32 #define ARCH_64 diff --git a/erts/emulator/beam/utils.c b/erts/emulator/beam/utils.c index be442fa480..31efddc0f2 100644 --- a/erts/emulator/beam/utils.c +++ b/erts/emulator/beam/utils.c @@ -1,19 +1,19 @@ /* * %CopyrightBegin% - * - * Copyright Ericsson AB 1996-2009. All Rights Reserved. - * + * + * Copyright Ericsson AB 1996-2010. 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% */ @@ -95,6 +95,7 @@ dispatch_profile_msg_q(profile_sched_msg_q *psmq) #endif + Eterm* erts_heap_alloc(Process* p, Uint need) { @@ -105,28 +106,46 @@ erts_heap_alloc(Process* p, Uint need) Uint i; #endif +#ifdef FORCE_HEAP_FRAGS + if (p->space_verified && p->space_verified_from!=NULL + && HEAP_TOP(p) >= p->space_verified_from + && HEAP_TOP(p) + need <= p->space_verified_from + p->space_verified + && HEAP_LIMIT(p) - HEAP_TOP(p) >= need) { + + Uint consumed = need + (HEAP_TOP(p) - p->space_verified_from); + ASSERT(consumed <= p->space_verified); + p->space_verified -= consumed; + p->space_verified_from += consumed; + HEAP_TOP(p) = p->space_verified_from; + return HEAP_TOP(p) - need; + } + p->space_verified = 0; + p->space_verified_from = NULL; +#endif /* FORCE_HEAP_FRAGS */ + n = need; + bp = MBUF(p); + if (bp != NULL && need <= (bp->size - bp->used_size)) { + Eterm* ret = bp->mem + bp->used_size; + bp->used_size += need; + return ret; + } #ifdef DEBUG n++; #endif bp = (ErlHeapFragment*) - ERTS_HEAP_ALLOC(ERTS_ALC_T_HEAP_FRAG, - sizeof(ErlHeapFragment) + ((n-1)*sizeof(Eterm))); + ERTS_HEAP_ALLOC(ERTS_ALC_T_HEAP_FRAG, ERTS_HEAP_FRAG_SIZE(n)); -#ifdef DEBUG - n--; -#endif - -#if defined(DEBUG) - for (i = 0; i <= n; i++) { - bp->mem[i] = ERTS_HOLE_MARKER; - } -#elif defined(CHECK_FOR_HOLES) +#if defined(DEBUG) || defined(CHECK_FOR_HOLES) for (i = 0; i < n; i++) { bp->mem[i] = ERTS_HOLE_MARKER; } #endif +#ifdef DEBUG + n--; +#endif + /* * When we have created a heap fragment, we are no longer allowed * to store anything more on the heap. @@ -140,6 +159,7 @@ erts_heap_alloc(Process* p, Uint need) bp->next = MBUF(p); MBUF(p) = bp; bp->size = n; + bp->used_size = n; MBUF_SIZE(p) += n; bp->off_heap.mso = NULL; #ifndef HYBRID /* FIND ME! */ @@ -151,34 +171,6 @@ erts_heap_alloc(Process* p, Uint need) return bp->mem; } -void erts_arith_shrink(Process* p, Eterm* hp) -{ -#if defined(CHECK_FOR_HOLES) - ErlHeapFragment* hf; - - /* - * We must find the heap fragment that hp points into. - * If we are unlucky, we might have to search through - * a large part of the list. We'll hope that will not - * happen too often. - */ - for (hf = MBUF(p); hf != 0; hf = hf->next) { - if (hp - hf->mem < (unsigned long)hf->size) { - /* - * We are not allowed to changed hf->size (because the - * size must be correct when deallocating). Therefore, - * clear out the uninitialized part of the heap fragment. - */ - Eterm* to = hf->mem + hf->size; - while (hp < to) { - *hp++ = NIL; - } - break; - } - } -#endif -} - #ifdef CHECK_FOR_HOLES Eterm* erts_set_hole_marker(Eterm* ptr, Uint sz) @@ -3992,6 +3984,14 @@ erts_write_env(char *key, char *value) return res; } +/* + * To be used to silence unused result warnings, but do not abuse it. + */ +void erts_silence_warn_unused_result(long unused) +{ + +} + #ifdef DEBUG /* * Handy functions when using a debugger - don't use in the code! diff --git a/erts/emulator/drivers/common/inet_drv.c b/erts/emulator/drivers/common/inet_drv.c index b7b577da5b..c6e23ee647 100644 --- a/erts/emulator/drivers/common/inet_drv.c +++ b/erts/emulator/drivers/common/inet_drv.c @@ -1205,8 +1205,8 @@ static void *realloc_wrapper(void *current, size_t size){ /* For AssocID, 4 bytes should be enough -- checked by "init": */ # define GET_ASSOC_ID get_int32 # define ASSOC_ID_LEN 4 -# define LOAD_ASSOC_ID LOAD_INT -# define LOAD_ASSOC_ID_CNT LOAD_INT_CNT +# define LOAD_ASSOC_ID LOAD_UINT +# define LOAD_ASSOC_ID_CNT LOAD_UINT_CNT # define SCTP_ANC_BUFF_SIZE INET_DEF_BUFFER/2 /* XXX: not very good... */ #endif diff --git a/erts/emulator/drivers/unix/ttsl_drv.c b/erts/emulator/drivers/unix/ttsl_drv.c index 4c2514669b..4cd54c073f 100644 --- a/erts/emulator/drivers/unix/ttsl_drv.c +++ b/erts/emulator/drivers/unix/ttsl_drv.c @@ -1,19 +1,19 @@ /* * %CopyrightBegin% - * - * Copyright Ericsson AB 1996-2009. All Rights Reserved. - * + * + * Copyright Ericsson AB 1996-2010. 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% */ /* @@ -142,7 +142,9 @@ static int tty_init(int,int,int,int); static int tty_set(int); static int tty_reset(int); static int ttysl_control(ErlDrvData, unsigned int, char *, int, char **, int); +#ifdef ERTS_NOT_USED static RETSIGTYPE suspend(int); +#endif static RETSIGTYPE cont(int); static RETSIGTYPE winch(int); @@ -1265,6 +1267,9 @@ static int tty_reset(int fd) /* of terminal device */ * to the orignal settings */ +#ifdef ERTS_NOT_USED +/* XXX: A mistake that it isn't used, or should it be removed? */ + static RETSIGTYPE suspend(int sig) { if (tty_reset(ttysl_fd) < 0) { @@ -1284,6 +1289,8 @@ static RETSIGTYPE suspend(int sig) } } +#endif + static RETSIGTYPE cont(int sig) { if (tty_set(ttysl_fd) < 0) { diff --git a/erts/emulator/hipe/hipe_amd64_asm.m4 b/erts/emulator/hipe/hipe_amd64_asm.m4 index 9ce9b4fc5b..7f563c35d8 100644 --- a/erts/emulator/hipe/hipe_amd64_asm.m4 +++ b/erts/emulator/hipe/hipe_amd64_asm.m4 @@ -1,20 +1,20 @@ changecom(`/*', `*/')dnl /* * %CopyrightBegin% - * - * Copyright Ericsson AB 2004-2009. All Rights Reserved. - * + * + * Copyright Ericsson AB 2004-2010. 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% */ /* @@ -37,6 +37,29 @@ define(SIMULATE_NSP,0)dnl change to 1 to simulate call/ret insns `#define LEAF_WORDS 'LEAF_WORDS /* + * Workarounds for Darwin. + */ +ifelse(OPSYS,darwin,`` +/* Darwin */ +#define TEXT .text +#define JOIN(X,Y) X##Y +#define CSYM(NAME) JOIN(_,NAME) +#define ASYM(NAME) CSYM(NAME) +#define GLOBAL(NAME) .globl NAME +#define SET_SIZE(NAME) /*empty*/ +#define TYPE_FUNCTION(NAME) /*empty*/ +'',`` +/* Not Darwin */ +#define TEXT .section ".text" +#define CSYM(NAME) NAME +#define ASYM(NAME) NAME +#define GLOBAL(NAME) .global NAME +#define SET_SIZE(NAME) .size NAME,.-NAME +#define TYPE_FUNCTION(NAME) .type NAME,@function +'')dnl + + +/* * Reserved registers. */ `#define P %rbp' diff --git a/erts/emulator/hipe/hipe_amd64_bifs.m4 b/erts/emulator/hipe/hipe_amd64_bifs.m4 index 66fd167f47..f7c9604e2b 100644 --- a/erts/emulator/hipe/hipe_amd64_bifs.m4 +++ b/erts/emulator/hipe/hipe_amd64_bifs.m4 @@ -1,20 +1,20 @@ changecom(`/*', `*/')dnl /* * %CopyrightBegin% - * - * Copyright Ericsson AB 2004-2009. All Rights Reserved. - * + * + * Copyright Ericsson AB 2004-2010. 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% */ /* @@ -46,17 +46,17 @@ define(standard_bif_interface_1, ` #ifndef HAVE_$1 #`define' HAVE_$1 - .section ".text" + TEXT .align 4 - .global $1 -$1: + GLOBAL(ASYM($1)) +ASYM($1): /* set up the parameters */ movq P, %rdi NBIF_ARG(%rsi,1,0) /* make the call on the C stack */ SWITCH_ERLANG_TO_C - call $2 + call CSYM($2) TEST_GOT_MBUF SWITCH_C_TO_ERLANG @@ -65,18 +65,18 @@ $1: jz nbif_1_simple_exception NBIF_RET(1) HANDLE_GOT_MBUF(1) - .size $1,.-$1 - .type $1,@function + SET_SIZE(ASYM($1)) + TYPE_FUNCTION(ASYM($1)) #endif') define(standard_bif_interface_2, ` #ifndef HAVE_$1 #`define' HAVE_$1 - .section ".text" + TEXT .align 4 - .global $1 -$1: + GLOBAL(ASYM($1)) +ASYM($1): /* set up the parameters */ movq P, %rdi NBIF_ARG(%rsi,2,0) @@ -84,7 +84,7 @@ $1: /* make the call on the C stack */ SWITCH_ERLANG_TO_C - call $2 + call CSYM($2) TEST_GOT_MBUF SWITCH_C_TO_ERLANG @@ -93,18 +93,18 @@ $1: jz nbif_2_simple_exception NBIF_RET(2) HANDLE_GOT_MBUF(2) - .size $1,.-$1 - .type $1,@function + SET_SIZE(ASYM($1)) + TYPE_FUNCTION(ASYM($1)) #endif') define(standard_bif_interface_3, ` #ifndef HAVE_$1 #`define' HAVE_$1 - .section ".text" + TEXT .align 4 - .global $1 -$1: + GLOBAL(ASYM($1)) +ASYM($1): /* set up the parameters */ movq P, %rdi NBIF_ARG(%rsi,3,0) @@ -113,7 +113,7 @@ $1: /* make the call on the C stack */ SWITCH_ERLANG_TO_C - call $2 + call CSYM($2) TEST_GOT_MBUF SWITCH_C_TO_ERLANG @@ -122,8 +122,8 @@ $1: jz nbif_3_simple_exception NBIF_RET(3) HANDLE_GOT_MBUF(3) - .size $1,.-$1 - .type $1,@function + SET_SIZE(ASYM($1)) + TYPE_FUNCTION(ASYM($1)) #endif') /* @@ -136,16 +136,16 @@ define(fail_bif_interface_0, ` #ifndef HAVE_$1 #`define' HAVE_$1 - .section ".text" + TEXT .align 4 - .global $1 -$1: + GLOBAL(ASYM($1)) +ASYM($1): /* set up the parameters */ movq P, %rdi /* make the call on the C stack */ SWITCH_ERLANG_TO_C - call $2 + call CSYM($2) TEST_GOT_MBUF SWITCH_C_TO_ERLANG @@ -154,8 +154,8 @@ $1: jz nbif_0_simple_exception NBIF_RET(0) HANDLE_GOT_MBUF(0) - .size $1,.-$1 - .type $1,@function + SET_SIZE(ASYM($1)) + TYPE_FUNCTION(ASYM($1)) #endif') /* @@ -172,59 +172,59 @@ define(nofail_primop_interface_0, ` #ifndef HAVE_$1 #`define' HAVE_$1 - .section ".text" + TEXT .align 4 - .global $1 -$1: + GLOBAL(ASYM($1)) +ASYM($1): /* set up the parameters */ movq P, %rdi /* make the call on the C stack */ SWITCH_ERLANG_TO_C - call $2 + call CSYM($2) TEST_GOT_MBUF SWITCH_C_TO_ERLANG /* return */ NBIF_RET(0) HANDLE_GOT_MBUF(0) - .size $1,.-$1 - .type $1,@function + SET_SIZE(ASYM($1)) + TYPE_FUNCTION(ASYM($1)) #endif') define(nofail_primop_interface_1, ` #ifndef HAVE_$1 #`define' HAVE_$1 - .section ".text" + TEXT .align 4 - .global $1 -$1: + GLOBAL(ASYM($1)) +ASYM($1): /* set up the parameters */ movq P, %rdi NBIF_ARG(%rsi,1,0) /* make the call on the C stack */ SWITCH_ERLANG_TO_C - call $2 + call CSYM($2) TEST_GOT_MBUF SWITCH_C_TO_ERLANG /* return */ NBIF_RET(1) HANDLE_GOT_MBUF(1) - .size $1,.-$1 - .type $1,@function + SET_SIZE(ASYM($1)) + TYPE_FUNCTION(ASYM($1)) #endif') define(nofail_primop_interface_2, ` #ifndef HAVE_$1 #`define' HAVE_$1 - .section ".text" + TEXT .align 4 - .global $1 -$1: + GLOBAL(ASYM($1)) +ASYM($1): /* set up the parameters */ movq P, %rdi NBIF_ARG(%rsi,2,0) @@ -232,25 +232,25 @@ $1: /* make the call on the C stack */ SWITCH_ERLANG_TO_C - call $2 + call CSYM($2) TEST_GOT_MBUF SWITCH_C_TO_ERLANG /* return */ NBIF_RET(2) HANDLE_GOT_MBUF(2) - .size $1,.-$1 - .type $1,@function + SET_SIZE(ASYM($1)) + TYPE_FUNCTION(ASYM($1)) #endif') define(nofail_primop_interface_3, ` #ifndef HAVE_$1 #`define' HAVE_$1 - .section ".text" + TEXT .align 4 - .global $1 -$1: + GLOBAL(ASYM($1)) +ASYM($1): /* set up the parameters */ movq P, %rdi NBIF_ARG(%rsi,3,0) @@ -259,15 +259,15 @@ $1: /* make the call on the C stack */ SWITCH_ERLANG_TO_C - call $2 + call CSYM($2) TEST_GOT_MBUF SWITCH_C_TO_ERLANG /* return */ NBIF_RET(3) HANDLE_GOT_MBUF(3) - .size $1,.-$1 - .type $1,@function + SET_SIZE(ASYM($1)) + TYPE_FUNCTION(ASYM($1)) #endif') /* @@ -285,55 +285,55 @@ define(nocons_nofail_primop_interface_0, ` #ifndef HAVE_$1 #`define' HAVE_$1 - .section ".text" + TEXT .align 4 - .global $1 -$1: + GLOBAL(ASYM($1)) +ASYM($1): /* set up the parameters */ movq P, %rdi /* make the call on the C stack */ SWITCH_ERLANG_TO_C_QUICK - call $2 + call CSYM($2) SWITCH_C_TO_ERLANG_QUICK /* return */ NBIF_RET(0) - .size $1,.-$1 - .type $1,@function + SET_SIZE(ASYM($1)) + TYPE_FUNCTION(ASYM($1)) #endif') define(nocons_nofail_primop_interface_1, ` #ifndef HAVE_$1 #`define' HAVE_$1 - .section ".text" + TEXT .align 4 - .global $1 -$1: + GLOBAL(ASYM($1)) +ASYM($1): /* set up the parameters */ movq P, %rdi NBIF_ARG(%rsi,1,0) /* make the call on the C stack */ SWITCH_ERLANG_TO_C_QUICK - call $2 + call CSYM($2) SWITCH_C_TO_ERLANG_QUICK /* return */ NBIF_RET(1) - .size $1,.-$1 - .type $1,@function + SET_SIZE(ASYM($1)) + TYPE_FUNCTION(ASYM($1)) #endif') define(nocons_nofail_primop_interface_2, ` #ifndef HAVE_$1 #`define' HAVE_$1 - .section ".text" + TEXT .align 4 - .global $1 -$1: + GLOBAL(ASYM($1)) +ASYM($1): /* set up the parameters */ movq P, %rdi NBIF_ARG(%rsi,2,0) @@ -341,23 +341,23 @@ $1: /* make the call on the C stack */ SWITCH_ERLANG_TO_C_QUICK - call $2 + call CSYM($2) SWITCH_C_TO_ERLANG_QUICK /* return */ NBIF_RET(2) - .size $1,.-$1 - .type $1,@function + SET_SIZE(ASYM($1)) + TYPE_FUNCTION(ASYM($1)) #endif') define(nocons_nofail_primop_interface_3, ` #ifndef HAVE_$1 #`define' HAVE_$1 - .section ".text" + TEXT .align 4 - .global $1 -$1: + GLOBAL(ASYM($1)) +ASYM($1): /* set up the parameters */ movq P, %rdi NBIF_ARG(%rsi,3,0) @@ -366,23 +366,23 @@ $1: /* make the call on the C stack */ SWITCH_ERLANG_TO_C_QUICK - call $2 + call CSYM($2) SWITCH_C_TO_ERLANG_QUICK /* return */ NBIF_RET(3) - .size $1,.-$1 - .type $1,@function + SET_SIZE(ASYM($1)) + TYPE_FUNCTION(ASYM($1)) #endif') define(nocons_nofail_primop_interface_5, ` #ifndef HAVE_$1 #`define' HAVE_$1 - .section ".text" + TEXT .align 4 - .global $1 -$1: + GLOBAL(ASYM($1)) +ASYM($1): /* set up the parameters */ movq P, %rdi NBIF_ARG(%rsi,5,0) @@ -393,13 +393,13 @@ $1: /* make the call on the C stack */ SWITCH_ERLANG_TO_C_QUICK - call $2 + call CSYM($2) SWITCH_C_TO_ERLANG_QUICK /* return */ NBIF_RET(5) - .size $1,.-$1 - .type $1,@function + SET_SIZE(ASYM($1)) + TYPE_FUNCTION(ASYM($1)) #endif') /* @@ -417,74 +417,74 @@ define(noproc_primop_interface_0, ` #ifndef HAVE_$1 #`define' HAVE_$1 - .section ".text" + TEXT .align 4 - .global $1 -$1: + GLOBAL(ASYM($1)) +ASYM($1): /* make the call on the C stack */ SWITCH_ERLANG_TO_C_QUICK - call $2 + call CSYM($2) SWITCH_C_TO_ERLANG_QUICK /* return */ NBIF_RET(0) - .size $1,.-$1 - .type $1,@function + SET_SIZE(ASYM($1)) + TYPE_FUNCTION(ASYM($1)) #endif') define(noproc_primop_interface_1, ` #ifndef HAVE_$1 #`define' HAVE_$1 - .section ".text" + TEXT .align 4 - .global $1 -$1: + GLOBAL(ASYM($1)) +ASYM($1): /* set up the parameters */ NBIF_ARG(%rdi,1,0) /* make the call on the C stack */ SWITCH_ERLANG_TO_C_QUICK - call $2 + call CSYM($2) SWITCH_C_TO_ERLANG_QUICK /* return */ NBIF_RET(1) - .size $1,.-$1 - .type $1,@function + SET_SIZE(ASYM($1)) + TYPE_FUNCTION(ASYM($1)) #endif') define(noproc_primop_interface_2, ` #ifndef HAVE_$1 #`define' HAVE_$1 - .section ".text" + TEXT .align 4 - .global $1 -$1: + GLOBAL(ASYM($1)) +ASYM($1): /* set up the parameters */ NBIF_ARG(%rdi,2,0) NBIF_ARG(%rsi,2,1) /* make the call on the C stack */ SWITCH_ERLANG_TO_C_QUICK - call $2 + call CSYM($2) SWITCH_C_TO_ERLANG_QUICK /* return */ NBIF_RET(2) - .size $1,.-$1 - .type $1,@function + SET_SIZE(ASYM($1)) + TYPE_FUNCTION(ASYM($1)) #endif') define(noproc_primop_interface_3, ` #ifndef HAVE_$1 #`define' HAVE_$1 - .section ".text" + TEXT .align 4 - .global $1 -$1: + GLOBAL(ASYM($1)) +ASYM($1): /* set up the parameters */ NBIF_ARG(%rdi,3,0) NBIF_ARG(%rsi,3,1) @@ -492,23 +492,23 @@ $1: /* make the call on the C stack */ SWITCH_ERLANG_TO_C_QUICK - call $2 + call CSYM($2) SWITCH_C_TO_ERLANG_QUICK /* return */ NBIF_RET(3) - .size $1,.-$1 - .type $1,@function + SET_SIZE(ASYM($1)) + TYPE_FUNCTION(ASYM($1)) #endif') define(noproc_primop_interface_5, ` #ifndef HAVE_$1 #`define' HAVE_$1 - .section ".text" + TEXT .align 4 - .global $1 -$1: + GLOBAL(ASYM($1)) +ASYM($1): /* set up the parameters */ NBIF_ARG(%rdi,5,0) NBIF_ARG(%rsi,5,1) @@ -518,13 +518,13 @@ $1: /* make the call on the C stack */ SWITCH_ERLANG_TO_C_QUICK - call $2 + call CSYM($2) SWITCH_C_TO_ERLANG_QUICK /* return */ NBIF_RET(5) - .size $1,.-$1 - .type $1,@function + SET_SIZE(ASYM($1)) + TYPE_FUNCTION(ASYM($1)) #endif') /* diff --git a/erts/emulator/hipe/hipe_amd64_glue.S b/erts/emulator/hipe/hipe_amd64_glue.S index 872c5dc9e3..83b7b0397b 100644 --- a/erts/emulator/hipe/hipe_amd64_glue.S +++ b/erts/emulator/hipe/hipe_amd64_glue.S @@ -1,19 +1,19 @@ /* * %CopyrightBegin% - * - * Copyright Ericsson AB 2004-2009. All Rights Reserved. - * + * + * Copyright Ericsson AB 2004-2010. 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% */ /* @@ -56,16 +56,16 @@ /* switch to native stack */ \ SWITCH_C_TO_ERLANG - .section ".text" + TEXT /* * int x86_call_to_native(Process *p); * Emulated code recursively calls native code. */ .align 4 - .global x86_call_to_native - .global nbif_return -x86_call_to_native: + GLOBAL(CSYM(x86_call_to_native)) + GLOBAL(ASYM(nbif_return)) +CSYM(x86_call_to_native): ENTER_FROM_C /* get argument registers */ LOAD_ARG_REGS @@ -77,7 +77,7 @@ x86_call_to_native: * * This is where native code returns to emulated code. */ -nbif_return: +ASYM(nbif_return): movq %rax, P_ARG0(P) # save retval movl $HIPE_MODE_SWITCH_RES_RETURN, %eax /* FALLTHROUGH to .flush_exit @@ -118,8 +118,8 @@ nbif_return: * XXX: Different stubs for different number of register parameters? */ .align 4 - .global nbif_callemu -nbif_callemu: + GLOBAL(ASYM(nbif_callemu)) +ASYM(nbif_callemu): STORE_ARG_REGS movl $HIPE_MODE_SWITCH_RES_CALL, %eax jmp .suspend_exit @@ -128,8 +128,8 @@ nbif_callemu: * nbif_apply */ .align 4 - .global nbif_apply -nbif_apply: + GLOBAL(ASYM(nbif_apply)) +ASYM(nbif_apply): STORE_ARG_REGS movl $HIPE_MODE_SWITCH_RES_APPLY, %eax jmp .suspend_exit @@ -145,8 +145,8 @@ nbif_apply: */ #if NR_ARG_REGS >= 6 .align 4 - .global nbif_ccallemu6 -nbif_ccallemu6: + GLOBAL(ASYM(nbif_ccallemu6)) +ASYM(nbif_ccallemu6): movq ARG5, P_ARG5(P) #if NR_ARG_REGS > 6 movq ARG6, ARG5 @@ -158,8 +158,8 @@ nbif_ccallemu6: #if NR_ARG_REGS >= 5 .align 4 - .global nbif_ccallemu5 -nbif_ccallemu5: + GLOBAL(ASYM(nbif_ccallemu5)) +ASYM(nbif_ccallemu5): movq ARG4, P_ARG4(P) #if NR_ARG_REGS > 5 movq ARG5, ARG4 @@ -171,8 +171,8 @@ nbif_ccallemu5: #if NR_ARG_REGS >= 4 .align 4 - .global nbif_ccallemu4 -nbif_ccallemu4: + GLOBAL(ASYM(nbif_ccallemu4)) +ASYM(nbif_ccallemu4): movq ARG3, P_ARG3(P) #if NR_ARG_REGS > 4 movq ARG4, ARG3 @@ -184,8 +184,8 @@ nbif_ccallemu4: #if NR_ARG_REGS >= 3 .align 4 - .global nbif_ccallemu3 -nbif_ccallemu3: + GLOBAL(ASYM(nbif_ccallemu3)) +ASYM(nbif_ccallemu3): movq ARG2, P_ARG2(P) #if NR_ARG_REGS > 3 movq ARG3, ARG2 @@ -197,8 +197,8 @@ nbif_ccallemu3: #if NR_ARG_REGS >= 2 .align 4 - .global nbif_ccallemu2 -nbif_ccallemu2: + GLOBAL(ASYM(nbif_ccallemu2)) +ASYM(nbif_ccallemu2): movq ARG1, P_ARG1(P) #if NR_ARG_REGS > 2 movq ARG2, ARG1 @@ -210,8 +210,8 @@ nbif_ccallemu2: #if NR_ARG_REGS >= 1 .align 4 - .global nbif_ccallemu1 -nbif_ccallemu1: + GLOBAL(ASYM(nbif_ccallemu1)) +ASYM(nbif_ccallemu1): movq ARG0, P_ARG0(P) #if NR_ARG_REGS > 1 movq ARG1, ARG0 @@ -222,8 +222,8 @@ nbif_ccallemu1: #endif .align 4 - .global nbif_ccallemu0 -nbif_ccallemu0: + GLOBAL(ASYM(nbif_ccallemu0)) +ASYM(nbif_ccallemu0): /* We use %rsi not ARG0 here because ARG0 is not defined when NR_ARG_REGS == 0. */ #if NR_ARG_REGS == 0 @@ -237,8 +237,8 @@ nbif_ccallemu0: * This is where native code suspends. */ .align 4 - .global nbif_suspend_0 -nbif_suspend_0: + GLOBAL(ASYM(nbif_suspend_0)) +ASYM(nbif_suspend_0): movl $HIPE_MODE_SWITCH_RES_SUSPEND, %eax jmp .suspend_exit @@ -246,8 +246,8 @@ nbif_suspend_0: * Suspend from a receive (waiting for a message) */ .align 4 - .global nbif_suspend_msg -nbif_suspend_msg: + GLOBAL(ASYM(nbif_suspend_msg)) +ASYM(nbif_suspend_msg): movl $HIPE_MODE_SWITCH_RES_WAIT, %eax jmp .suspend_exit @@ -257,8 +257,8 @@ nbif_suspend_msg: * else { return 0; } */ .align 4 - .global nbif_suspend_msg_timeout -nbif_suspend_msg_timeout: + GLOBAL(ASYM(nbif_suspend_msg_timeout)) +ASYM(nbif_suspend_msg_timeout): movq P_FLAGS(P), %rax /* this relies on F_TIMO (1<<2) fitting in a byte */ testb $F_TIMO, %al # F_TIMO set? @@ -275,8 +275,8 @@ nbif_suspend_msg_timeout: * Emulated code returns to its native code caller. */ .align 4 - .global x86_return_to_native -x86_return_to_native: + GLOBAL(CSYM(x86_return_to_native)) +CSYM(x86_return_to_native): ENTER_FROM_C /* get return value */ movq P_ARG0(P), %rax @@ -292,8 +292,8 @@ x86_return_to_native: * Emulated code tailcalls native code. */ .align 4 - .global x86_tailcall_to_native -x86_tailcall_to_native: + GLOBAL(CSYM(x86_tailcall_to_native)) +CSYM(x86_tailcall_to_native): ENTER_FROM_C /* get argument registers */ LOAD_ARG_REGS @@ -305,8 +305,8 @@ x86_tailcall_to_native: * Emulated code throws an exception to its native code caller. */ .align 4 - .global x86_throw_to_native -x86_throw_to_native: + GLOBAL(CSYM(x86_throw_to_native)) +CSYM(x86_throw_to_native): ENTER_FROM_C /* invoke the handler */ jmp *P_NCALLEE(P) # set by hipe_find_handler() @@ -315,15 +315,15 @@ x86_throw_to_native: * This is the default exception handler for native code. */ .align 4 - .global nbif_fail -nbif_fail: + GLOBAL(ASYM(nbif_fail)) +ASYM(nbif_fail): movl $HIPE_MODE_SWITCH_RES_THROW, %eax jmp .flush_exit - .global nbif_0_gc_after_bif - .global nbif_1_gc_after_bif - .global nbif_2_gc_after_bif - .global nbif_3_gc_after_bif + GLOBAL(nbif_0_gc_after_bif) + GLOBAL(nbif_1_gc_after_bif) + GLOBAL(nbif_2_gc_after_bif) + GLOBAL(nbif_3_gc_after_bif) .align 4 nbif_0_gc_after_bif: xorl %edx, %edx @@ -346,7 +346,7 @@ nbif_3_gc_after_bif: subq $(16-8), %rsp movq P, %rdi movq %rax, %rsi - call erts_gc_after_bif_call + call CSYM(erts_gc_after_bif_call) addq $(16-8), %rsp movl $0, P_NARITY(P) # Note: narity is a 32-bit field ret @@ -356,10 +356,10 @@ nbif_3_gc_after_bif: * exceptional condition. * The stack/heap registers were just read from P. */ - .global nbif_0_simple_exception - .global nbif_1_simple_exception - .global nbif_2_simple_exception - .global nbif_3_simple_exception + GLOBAL(nbif_0_simple_exception) + GLOBAL(nbif_1_simple_exception) + GLOBAL(nbif_2_simple_exception) + GLOBAL(nbif_3_simple_exception) .align 4 nbif_0_simple_exception: xorl %eax, %eax @@ -389,7 +389,7 @@ nbif_3_simple_exception: /* find and prepare to invoke the handler */ SWITCH_ERLANG_TO_C_QUICK # The cached state is clean and need not be saved. movq P, %rdi - call hipe_handle_exception # Note: hipe_handle_exception() conses + call CSYM(hipe_handle_exception) # Note: hipe_handle_exception() conses SWITCH_C_TO_ERLANG # %rsp updated by hipe_find_handler() /* now invoke the handler */ jmp *P_NCALLEE(P) # set by hipe_find_handler() @@ -408,15 +408,15 @@ nbif_3_simple_exception: * nbif_stack_trap_ra: trap return address for maintaining * the gray/white stack boundary */ - .global nbif_stack_trap_ra + GLOBAL(ASYM(nbif_stack_trap_ra)) .align 4 -nbif_stack_trap_ra: # a return address, not a function +ASYM(nbif_stack_trap_ra): # a return address, not a function # This only handles a single return value. # If we have more, we need to save them in the PCB. movq %rax, TEMP_RV # save retval SWITCH_ERLANG_TO_C_QUICK movq P, %rdi - call hipe_handle_stack_trap # must not cons; preserves TEMP_RV + call CSYM(hipe_handle_stack_trap) # must not cons; preserves TEMP_RV movq %rax, %rdx # original RA SWITCH_C_TO_ERLANG_QUICK movq TEMP_RV, %rax # restore retval @@ -425,15 +425,15 @@ nbif_stack_trap_ra: # a return address, not a function /* * nbif_inc_stack_0 */ - .global nbif_inc_stack_0 + GLOBAL(ASYM(nbif_inc_stack_0)) .align 4 -nbif_inc_stack_0: +ASYM(nbif_inc_stack_0): SWITCH_ERLANG_TO_C_QUICK STORE_ARG_REGS movq P, %rdi # hipe_inc_nstack reads and writes NSP and NSP_LIMIT, # but does not access HP or FCALLS (or the non-amd64 NRA). - call hipe_inc_nstack + call CSYM(hipe_inc_nstack) LOAD_ARG_REGS SWITCH_C_TO_ERLANG_QUICK NSP_RET0 diff --git a/erts/emulator/hipe/hipe_bif0.c b/erts/emulator/hipe/hipe_bif0.c index 032bf2e896..b0abfd2310 100644 --- a/erts/emulator/hipe/hipe_bif0.c +++ b/erts/emulator/hipe/hipe_bif0.c @@ -1,22 +1,22 @@ /* * %CopyrightBegin% - * - * Copyright Ericsson AB 2001-2009. All Rights Reserved. - * + * + * Copyright Ericsson AB 2001-2010. 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% */ -/* $Id$ +/* * hipe_bif0.c * * Compiler and linker support. @@ -656,6 +656,7 @@ static void *hipe_get_emu_address(Eterm m, Eterm f, unsigned int arity, int is_r address = hipe_find_emu_address(m, f, arity); if (!address) { /* 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; } @@ -1188,8 +1189,31 @@ static struct { unsigned int mask; /* INV: mask == (1 << log2size)-1 */ unsigned int used; struct hipe_mfa_info **bucket; + /* + * The mfa info table is normally updated by the loader, + * which runs in non-concurrent mode. Unfortunately runtime + * apply operations (get_na_nofail) update the table if + * they create a new stub for the mfa, which forces locking. + * XXX: Redesign apply et al to avoid those updates. + */ + erts_smp_mtx_t lock; } hipe_mfa_info_table; +static inline void hipe_mfa_info_table_init_lock(void) +{ + erts_smp_mtx_init(&hipe_mfa_info_table.lock, "hipe_mfait_lock"); +} + +static inline void hipe_mfa_info_table_lock(void) +{ + erts_smp_mtx_lock(&hipe_mfa_info_table.lock); +} + +static inline void hipe_mfa_info_table_unlock(void) +{ + erts_smp_mtx_unlock(&hipe_mfa_info_table.lock); +} + #define HIPE_MFA_HASH(M,F,A) ((M) * (F) + (A)) static struct hipe_mfa_info **hipe_mfa_info_table_alloc_bucket(unsigned int size) @@ -1258,9 +1282,11 @@ void hipe_mfa_info_table_init(void) hipe_mfa_info_table.mask = size - 1; hipe_mfa_info_table.used = 0; hipe_mfa_info_table.bucket = hipe_mfa_info_table_alloc_bucket(size); + + hipe_mfa_info_table_init_lock(); } -static inline struct hipe_mfa_info *hipe_mfa_info_table_get(Eterm m, Eterm f, unsigned int arity) +static inline struct hipe_mfa_info *hipe_mfa_info_table_get_locked(Eterm m, Eterm f, unsigned int arity) { unsigned long h; unsigned int i; @@ -1286,7 +1312,7 @@ void *hipe_mfa_find_na(Eterm m, Eterm f, unsigned int arity) } #endif -static struct hipe_mfa_info *hipe_mfa_info_table_put(Eterm m, Eterm f, unsigned int arity) +static struct hipe_mfa_info *hipe_mfa_info_table_put_locked(Eterm m, Eterm f, unsigned int arity) { unsigned long h; unsigned int i; @@ -1313,7 +1339,10 @@ static struct hipe_mfa_info *hipe_mfa_info_table_put(Eterm m, Eterm f, unsigned static void hipe_mfa_set_na(Eterm m, Eterm f, unsigned int arity, void *address, int is_exported) { - struct hipe_mfa_info *p = hipe_mfa_info_table_put(m, f, arity); + struct hipe_mfa_info *p; + + hipe_mfa_info_table_lock(); + p = hipe_mfa_info_table_put_locked(m, f, arity); #ifdef DEBUG_LINKER printf("%s: ", __FUNCTION__); print_mfa(m, f, arity); @@ -1322,19 +1351,30 @@ static void hipe_mfa_set_na(Eterm m, Eterm f, unsigned int arity, void *address, p->local_address = address; if (is_exported) p->remote_address = address; + hipe_mfa_info_table_unlock(); } #if defined(__powerpc__) || defined(__ppc__) || defined(__powerpc64__) || defined(__arm__) void *hipe_mfa_get_trampoline(Eterm m, Eterm f, unsigned int arity) { - struct hipe_mfa_info *p = hipe_mfa_info_table_put(m, f, arity); - return p->trampoline; + struct hipe_mfa_info *p; + void *trampoline; + + hipe_mfa_info_table_lock(); + p = hipe_mfa_info_table_put_locked(m, f, arity); + trampoline = p->trampoline; + hipe_mfa_info_table_unlock(); + return trampoline; } void hipe_mfa_set_trampoline(Eterm m, Eterm f, unsigned int arity, void *trampoline) { - struct hipe_mfa_info *p = hipe_mfa_info_table_put(m, f, arity); + struct hipe_mfa_info *p; + + hipe_mfa_info_table_lock(); + p = hipe_mfa_info_table_put_locked(m, f, arity); p->trampoline = trampoline; + hipe_mfa_info_table_unlock(); } #endif @@ -1365,12 +1405,13 @@ BIF_RETTYPE hipe_bifs_invalidate_funinfo_native_addresses_1(BIF_ALIST_1) struct mfa mfa; struct hipe_mfa_info *p; + hipe_mfa_info_table_lock(); lst = BIF_ARG_1; while (is_list(lst)) { if (!term_to_mfa(CAR(list_val(lst)), &mfa)) - BIF_ERROR(BIF_P, BADARG); + break; lst = CDR(list_val(lst)); - p = hipe_mfa_info_table_get(mfa.mod, mfa.fun, mfa.ari); + p = hipe_mfa_info_table_get_locked(mfa.mod, mfa.fun, mfa.ari); if (p) { p->remote_address = NULL; p->local_address = NULL; @@ -1393,6 +1434,7 @@ BIF_RETTYPE hipe_bifs_invalidate_funinfo_native_addresses_1(BIF_ALIST_1) } } } + hipe_mfa_info_table_unlock(); if (is_not_nil(lst)) BIF_ERROR(BIF_P, BADARG); BIF_RET(NIL); @@ -1406,7 +1448,8 @@ void hipe_mfa_save_orig_beam_op(Eterm mod, Eterm fun, unsigned int ari, Eterm *p orig_beam_op = pc[0]; if (orig_beam_op != BeamOpCode(op_hipe_trap_call_closure) && orig_beam_op != BeamOpCode(op_hipe_trap_call)) { - p = hipe_mfa_info_table_put(mod, fun, ari); + hipe_mfa_info_table_lock(); + p = hipe_mfa_info_table_put_locked(mod, fun, ari); #ifdef DEBUG_LINKER printf("%s: ", __FUNCTION__); print_mfa(mod, fun, ari); @@ -1414,6 +1457,7 @@ void hipe_mfa_save_orig_beam_op(Eterm mod, Eterm fun, unsigned int ari, Eterm *p #endif p->beam_code = pc; p->orig_beam_op = orig_beam_op; + hipe_mfa_info_table_unlock(); } else { #ifdef DEBUG_LINKER printf("%s: ", __FUNCTION__); @@ -1440,12 +1484,12 @@ static void *hipe_make_stub(Eterm m, Eterm f, unsigned int arity, int is_remote) return StubAddress; } -static void *hipe_get_na_nofail(Eterm m, Eterm f, unsigned int a, int is_remote) +static void *hipe_get_na_nofail_locked(Eterm m, Eterm f, unsigned int a, int is_remote) { struct hipe_mfa_info *p; void *address; - p = hipe_mfa_info_table_get(m, f, a); + p = hipe_mfa_info_table_get_locked(m, f, a); if (p) { /* find address, predicting for a runtime apply call */ address = p->remote_address; @@ -1459,13 +1503,23 @@ static void *hipe_get_na_nofail(Eterm m, Eterm f, unsigned int a, int is_remote) if (address) return address; } else - p = hipe_mfa_info_table_put(m, f, a); + p = hipe_mfa_info_table_put_locked(m, f, a); address = hipe_make_stub(m, f, a, is_remote); /* XXX: how to tell if a BEAM MFA is exported or not? */ p->remote_address = address; return address; } +static void *hipe_get_na_nofail(Eterm m, Eterm f, unsigned int a, int is_remote) +{ + void *p; + + hipe_mfa_info_table_lock(); + p = hipe_get_na_nofail_locked(m, f, a, is_remote); + hipe_mfa_info_table_unlock(); + return p; +} + /* used for apply/3 in hipe_mode_switch */ void *hipe_get_remote_na(Eterm m, Eterm f, unsigned int a) { @@ -1549,6 +1603,8 @@ int hipe_find_mfa_from_ra(const void *ra, Eterm *m, Eterm *f, unsigned int *a) /* Note about locking: the table is only updated from the loader, which runs with the rest of the system suspended. */ + /* XXX: alas not true; see comment at hipe_mfa_info_table.lock */ + hipe_mfa_info_table_lock(); bucket = hipe_mfa_info_table.bucket; nrbuckets = 1 << hipe_mfa_info_table.log2size; mfa = NULL; @@ -1564,12 +1620,13 @@ int hipe_find_mfa_from_ra(const void *ra, Eterm *m, Eterm *f, unsigned int *a) b = b->bucket.next; } } - if (!mfa) - return 0; - *m = mfa->m; - *f = mfa->f; - *a = mfa->a; - return 1; + if (mfa) { + *m = mfa->m; + *f = mfa->f; + *a = mfa->a; + } + hipe_mfa_info_table_unlock(); + return mfa ? 1 : 0; } /* @@ -1645,8 +1702,9 @@ BIF_RETTYPE hipe_bifs_add_ref_2(BIF_ALIST_2) default: goto badarg; } - callee_mfa = hipe_mfa_info_table_put(callee.mod, callee.fun, callee.ari); - caller_mfa = hipe_mfa_info_table_put(caller.mod, caller.fun, caller.ari); + hipe_mfa_info_table_lock(); + callee_mfa = hipe_mfa_info_table_put_locked(callee.mod, callee.fun, callee.ari); + caller_mfa = hipe_mfa_info_table_put_locked(caller.mod, caller.fun, caller.ari); refers_to = erts_alloc(ERTS_ALC_T_HIPE, sizeof(*refers_to)); refers_to->mfa = callee_mfa; @@ -1660,6 +1718,7 @@ BIF_RETTYPE hipe_bifs_add_ref_2(BIF_ALIST_2) ref->flags = flags; ref->next = callee_mfa->referred_from; callee_mfa->referred_from = ref; + hipe_mfa_info_table_unlock(); BIF_RET(NIL); @@ -1679,10 +1738,12 @@ BIF_RETTYPE hipe_bifs_mark_referred_from_1(BIF_ALIST_1) /* get_refs_from */ if (!term_to_mfa(BIF_ARG_1, &mfa)) BIF_ERROR(BIF_P, BADARG); - p = hipe_mfa_info_table_get(mfa.mod, mfa.fun, mfa.ari); + hipe_mfa_info_table_lock(); + p = hipe_mfa_info_table_get_locked(mfa.mod, mfa.fun, mfa.ari); if (p) for (ref = p->referred_from; ref != NULL; ref = ref->next) ref->flags |= REF_FLAG_PENDING_REDIRECT; + hipe_mfa_info_table_unlock(); BIF_RET(NIL); } @@ -1695,7 +1756,8 @@ BIF_RETTYPE hipe_bifs_remove_refs_from_1(BIF_ALIST_1) if (!term_to_mfa(BIF_ARG_1, &mfa)) BIF_ERROR(BIF_P, BADARG); - caller_mfa = hipe_mfa_info_table_get(mfa.mod, mfa.fun, mfa.ari); + hipe_mfa_info_table_lock(); + caller_mfa = hipe_mfa_info_table_get_locked(mfa.mod, mfa.fun, mfa.ari); if (caller_mfa) { refers_to = caller_mfa->refers_to; while (refers_to) { @@ -1725,6 +1787,7 @@ BIF_RETTYPE hipe_bifs_remove_refs_from_1(BIF_ALIST_1) } caller_mfa->refers_to = NULL; } + hipe_mfa_info_table_unlock(); BIF_RET(NIL); } @@ -1742,14 +1805,15 @@ BIF_RETTYPE hipe_bifs_redirect_referred_from_1(BIF_ALIST_1) if (!term_to_mfa(BIF_ARG_1, &mfa)) BIF_ERROR(BIF_P, BADARG); - p = hipe_mfa_info_table_get(mfa.mod, mfa.fun, mfa.ari); + hipe_mfa_info_table_lock(); + p = hipe_mfa_info_table_get_locked(mfa.mod, mfa.fun, mfa.ari); if (p) { prev = &p->referred_from; ref = *prev; while (ref) { if (ref->flags & REF_FLAG_PENDING_REDIRECT) { is_remote = ref->flags & REF_FLAG_IS_REMOTE; - new_address = hipe_get_na_nofail(p->m, p->f, p->a, is_remote); + new_address = hipe_get_na_nofail_locked(p->m, p->f, p->a, is_remote); if (ref->flags & REF_FLAG_IS_LOAD_MFA) res = hipe_patch_insn(ref->address, (Uint)new_address, am_load_mfa); else @@ -1772,6 +1836,7 @@ BIF_RETTYPE hipe_bifs_redirect_referred_from_1(BIF_ALIST_1) } } } + hipe_mfa_info_table_unlock(); BIF_RET(NIL); } diff --git a/erts/emulator/pcre/pcre_compile.c b/erts/emulator/pcre/pcre_compile.c index 235617fc06..29743362d4 100644 --- a/erts/emulator/pcre/pcre_compile.c +++ b/erts/emulator/pcre/pcre_compile.c @@ -4820,10 +4820,8 @@ we set the flag only if there is a literal "\r" or "\n" in the class. */ both phases. If we are not at the pattern start, compile code to change the ims - options if this setting actually changes any of them. We also pass the - new setting back so that it can be put at the start of any following - branches, and when this group ends (if we are in a group), a resetting - item can be compiled. */ + options if this setting actually changes any of them, and reset the + greedy defaults and the case value for firstbyte and reqbyte. */ if (*ptr == ')') { @@ -4831,7 +4829,6 @@ we set the flag only if there is a literal "\r" or "\n" in the class. */ (lengthptr == NULL || *lengthptr == 2 + 2*LINK_SIZE)) { cd->external_options = newoptions; - options = newoptions; } else { @@ -4840,17 +4837,17 @@ we set the flag only if there is a literal "\r" or "\n" in the class. */ *code++ = OP_OPT; *code++ = newoptions & PCRE_IMS; } - - /* Change options at this level, and pass them back for use - in subsequent branches. Reset the greedy defaults and the case - value for firstbyte and reqbyte. */ - - *optionsptr = options = newoptions; greedy_default = ((newoptions & PCRE_UNGREEDY) != 0); greedy_non_default = greedy_default ^ 1; - req_caseopt = ((options & PCRE_CASELESS) != 0)? REQ_CASELESS : 0; + req_caseopt = ((newoptions & PCRE_CASELESS) != 0)? REQ_CASELESS : 0; } + /* Change options at this level, and pass them back for use + in subsequent branches. When not at the start of the pattern, this + information is also necessary so that a resetting item can be + compiled at the end of a group (if we are in a group). */ + + *optionsptr = options = newoptions; previous = NULL; /* This item can't be repeated */ continue; /* It is complete */ } diff --git a/erts/emulator/sys/common/erl_poll.c b/erts/emulator/sys/common/erl_poll.c index 169d4579a2..5cca33d7eb 100644 --- a/erts/emulator/sys/common/erl_poll.c +++ b/erts/emulator/sys/common/erl_poll.c @@ -1,19 +1,19 @@ /* * %CopyrightBegin% - * - * Copyright Ericsson AB 2006-2009. All Rights Reserved. - * + * + * Copyright Ericsson AB 2006-2010. 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% */ @@ -350,6 +350,7 @@ unset_interrupted_chk(ErtsPollSet ps) #endif +void erts_silence_warn_unused_result(long unused); static void fatal_error(char *format, ...); static void fatal_error_async_signal_safe(char *error_str); @@ -2554,8 +2555,10 @@ fatal_error_async_signal_safe(char *error_str) int len = 0; while (error_str[len]) len++; - if (len) - (void) write(2, error_str, len); /* async signal safe */ + if (len) { + /* async signal safe */ + erts_silence_warn_unused_result(write(2, error_str, len)); + } } abort(); } diff --git a/erts/emulator/sys/unix/sys.c b/erts/emulator/sys/unix/sys.c index 183525b222..31ab5d03de 100644 --- a/erts/emulator/sys/unix/sys.c +++ b/erts/emulator/sys/unix/sys.c @@ -1,19 +1,19 @@ /* * %CopyrightBegin% - * - * Copyright Ericsson AB 1996-2009. All Rights Reserved. - * + * + * Copyright Ericsson AB 1996-2010. 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% */ @@ -709,7 +709,7 @@ prepare_crash_dump(void) if (nice_val > 39) { nice_val = 39; } - nice(nice_val); + erts_silence_warn_unused_result(nice(nice_val)); } envsz = sizeof(env); @@ -2332,7 +2332,7 @@ sys_async_ready_failed(int fd, int r, int err) char buf[120]; sprintf(buf, "sys_async_ready(): Fatal error: fd=%d, r=%d, errno=%d\n", fd, r, err); - (void) write(2, buf, strlen(buf)); + erts_silence_warn_unused_result(write(2, buf, strlen(buf))); abort(); } @@ -2891,7 +2891,7 @@ smp_sig_notify(char c) char msg[] = "smp_sig_notify(): Failed to notify signal-dispatcher thread " "about received signal"; - (void) write(2, msg, sizeof(msg)); + erts_silence_warn_unused_result(write(2, msg, sizeof(msg))); abort(); } } @@ -3121,7 +3121,6 @@ erl_sys_args(int* argc, char** argv) *argc = j; } - #ifdef ERTS_TIMER_THREAD /* diff --git a/erts/emulator/sys/unix/sys_float.c b/erts/emulator/sys/unix/sys_float.c index 15da6ab45c..c59c99f65e 100644 --- a/erts/emulator/sys/unix/sys_float.c +++ b/erts/emulator/sys/unix/sys_float.c @@ -1,19 +1,19 @@ /* * %CopyrightBegin% - * - * Copyright Ericsson AB 2001-2009. All Rights Reserved. - * + * + * Copyright Ericsson AB 2001-2010. 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% */ @@ -93,7 +93,8 @@ void erts_fp_check_init_error(volatile unsigned long *fpexnp) char buf[64]; snprintf(buf, sizeof buf, "ERTS_FP_CHECK_INIT at %p: detected unhandled FPE at %p\r\n", __builtin_return_address(0), (void*)*fpexnp); - write(2, buf, strlen(buf)); + if (write(2, buf, strlen(buf)) <= 0) + erl_exit(ERTS_ABORT_EXIT, "%s", buf); *fpexnp = 0; #if defined(__i386__) || defined(__x86_64__) erts_restore_fpu(); diff --git a/erts/emulator/test/binary_SUITE.erl b/erts/emulator/test/binary_SUITE.erl index e47dfa18f7..db2b3e10db 100644 --- a/erts/emulator/test/binary_SUITE.erl +++ b/erts/emulator/test/binary_SUITE.erl @@ -1,19 +1,19 @@ %% %% %CopyrightBegin% -%% -%% Copyright Ericsson AB 1997-2009. All Rights Reserved. -%% +%% +%% Copyright Ericsson AB 1997-2010. 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% %% @@ -27,6 +27,7 @@ %% binary_to_list/1 %% binary_to_list/3 %% binary_to_term/1 +%% binary_to_term/2 %% bitstr_to_list/1 %% term_to_binary/1 %% erlang:external_size/1 @@ -49,7 +50,7 @@ t_hash/1, bad_size/1, bad_term_to_binary/1, - bad_binary_to_term_2/1, + bad_binary_to_term_2/1,safe_binary_to_term2/1, bad_binary_to_term/1, bad_terms/1, more_bad_terms/1, otp_5484/1,otp_5933/1, ordering/1,unaligned_order/1,gc_test/1, @@ -66,7 +67,7 @@ all(suite) -> t_split_binary, bad_split, t_concat_binary, bad_list_to_binary, bad_binary_to_list, terms, terms_float, external_size, t_iolist_size, - bad_binary_to_term_2, + bad_binary_to_term_2,safe_binary_to_term2, bad_binary_to_term, bad_terms, t_hash, bad_size, bad_term_to_binary, more_bad_terms, otp_5484, otp_5933, ordering, unaligned_order, gc_test, bit_sized_binary_sizes, bitlevel_roundtrip, otp_6817, otp_8117, @@ -438,8 +439,11 @@ terms(Config) when is_list(Config) -> ok end, Term = binary_to_term(Bin), + Term = erlang:binary_to_term(Bin, [safe]), Unaligned = make_unaligned_sub_binary(Bin), Term = binary_to_term(Unaligned), + Term = erlang:binary_to_term(Unaligned, []), + Term = erlang:binary_to_term(Bin, [safe]), BinC = erlang:term_to_binary(Term, [compressed]), Term = binary_to_term(BinC), true = size(BinC) =< size(Bin), @@ -538,6 +542,23 @@ bad_binary_to_term(Config) when is_list(Config) -> bad_bin_to_term(BadBin) -> {'EXIT',{badarg,_}} = (catch binary_to_term(BadBin)). +bad_bin_to_term(BadBin,Opts) -> + {'EXIT',{badarg,_}} = (catch erlang:binary_to_term(BadBin,Opts)). + +safe_binary_to_term2(doc) -> "Test safety options for binary_to_term/2"; +safe_binary_to_term2(Config) when is_list(Config) -> + ?line bad_bin_to_term(<<131,100,0,14,"undefined_atom">>, [safe]), + ?line bad_bin_to_term(<<131,100,0,14,"other_bad_atom">>, [safe]), + BadHostAtom = <<100,0,14,"badguy@badhost">>, + Empty = <<0,0,0,0>>, + BadRef = <<131,114,0,3,BadHostAtom/binary,0,<<0,0,0,255>>/binary, + Empty/binary,Empty/binary>>, + ?line bad_bin_to_term(BadRef, [safe]), % good ref, with a bad atom + ?line fullsweep_after = erlang:binary_to_term(<<131,100,0,15,"fullsweep_after">>, [safe]), % should be a good atom + BadExtFun = <<131,113,100,0,4,98,108,117,101,100,0,4,109,111,111,110,97,3>>, + ?line bad_bin_to_term(BadExtFun, [safe]), + ok. + %% Tests bad input to binary_to_term/1. bad_terms(suite) -> []; @@ -559,11 +580,18 @@ corrupter(Term) -> ?line corrupter(CompressedBin, size(CompressedBin)-1). corrupter(Bin, Pos) when Pos >= 0 -> - ?line {ShorterBin, _} = split_binary(Bin, Pos), + ?line {ShorterBin, Rest} = split_binary(Bin, Pos), ?line catch binary_to_term(ShorterBin), %% emulator shouldn't crash ?line MovedBin = list_to_binary([ShorterBin]), ?line catch binary_to_term(MovedBin), %% emulator shouldn't crash - ?line corrupter(MovedBin, Pos-1); + + %% Bit faults, shouldn't crash + <<Byte,Tail/binary>> = Rest, + Fun = fun(M) -> FaultyByte = Byte bxor M, + catch binary_to_term(<<ShorterBin/binary, + FaultyByte, Tail/binary>>) end, + ?line lists:foreach(Fun,[1,2,4,8,16,32,64,128,255]), + ?line corrupter(Bin, Pos-1); corrupter(_Bin, _) -> ok. diff --git a/erts/emulator/test/fun_SUITE.erl b/erts/emulator/test/fun_SUITE.erl index 716ee3707d..a7889dfe90 100644 --- a/erts/emulator/test/fun_SUITE.erl +++ b/erts/emulator/test/fun_SUITE.erl @@ -1,19 +1,19 @@ %% %% %CopyrightBegin% -%% -%% Copyright Ericsson AB 1999-2009. All Rights Reserved. -%% +%% +%% Copyright Ericsson AB 1999-2010. 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% %% @@ -627,7 +627,13 @@ refc_dist_1() -> %% Fun is passed in an exit signal. Wait until it is gone. ?line wait_until(fun () -> 4 =/= fun_refc(F2) end), ?line 3 = fun_refc(F2), - ?line 3 = fun_refc(F), + erts_debug:set_internal_state(available_internal_state, true), + ?line F_refc = case erts_debug:get_internal_state(force_heap_frags) of + false -> 3; + true -> 2 % GC after bif already decreased it + end, + ?line F_refc = fun_refc(F), + erts_debug:set_internal_state(available_internal_state, false), refc_dist_send(Node, F). refc_dist_send(Node, F) -> diff --git a/erts/emulator/test/nif_SUITE.erl b/erts/emulator/test/nif_SUITE.erl index 213ff6637a..522caec8f1 100644 --- a/erts/emulator/test/nif_SUITE.erl +++ b/erts/emulator/test/nif_SUITE.erl @@ -1,37 +1,50 @@ %% %% %CopyrightBegin% -%% -%% Copyright Ericsson AB 2009. All Rights Reserved. -%% +%% +%% Copyright Ericsson AB 2009-2010. 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% %% -module(nif_SUITE). %%-define(line_trace,true). +%%-define(CHECK(Exp,Got), ?line check(Exp,Got,?LINE)). +-define(CHECK(Exp,Got), ?line Exp = Got). -include("test_server.hrl"). -export([all/1, fin_per_testcase/2, basic/1, reload/1, upgrade/1, heap_frag/1, - neg/1]). + types/1, many_args/1, binaries/1, get_string/1, get_atom/1, api_macros/1, + from_array/1, iolist_as_binary/1, resource/1, resource_takeover/1, + threading/1, neg/1]). +-export([many_args_100/100]). -define(nif_stub,nif_stub_error(?LINE)). all(suite) -> - [basic, reload, upgrade, heap_frag, neg]. + [basic, reload, upgrade, heap_frag, types, many_args, binaries, get_string, + get_atom, api_macros, from_array, iolist_as_binary, resource, + resource_takeover, threading, neg]. + +%%init_per_testcase(_Case, Config) -> +%% ?line Dog = ?t:timetrap(?t:seconds(60*60*24)), +%% [{watchdog, Dog}|Config]. fin_per_testcase(_Func, _Config) -> + %%Dog = ?config(watchdog, Config), + %%?t:timetrap_cancel(Dog), P1 = code:purge(nif_mod), Del = code:delete(nif_mod), P2 = code:purge(nif_mod), @@ -50,6 +63,7 @@ basic(Config) when is_list(Config) -> reload(doc) -> ["Test reload callback in nif lib"]; reload(suite) -> []; reload(Config) when is_list(Config) -> + TmpMem = tmpmem(), ensure_lib_loaded(Config), ?line Data = ?config(data_dir, Config), @@ -57,16 +71,16 @@ reload(Config) when is_list(Config) -> ?line {ok,nif_mod,Bin} = compile:file(File, [binary,return_errors]), ?line {module,nif_mod} = erlang:load_module(nif_mod,Bin), - ?line nif_mod:load_nif_lib(Config, 1), + ?line ok = nif_mod:load_nif_lib(Config, 1), ?line hold_nif_mod_priv_data(nif_mod:get_priv_data_ptr()), ?line [{load,1,1,101},{get_priv_data_ptr,1,2,102}] = nif_mod_call_history(), - ?line nif_mod:load_nif_lib(Config, 2), + ?line ok = nif_mod:load_nif_lib(Config, 2), ?line 2 = nif_mod:lib_version(), ?line [{reload,2,1,201},{lib_version,2,2,202}] = nif_mod_call_history(), - ?line nif_mod:load_nif_lib(Config, 1), + ?line ok = nif_mod:load_nif_lib(Config, 1), ?line 1 = nif_mod:lib_version(), ?line [{reload,1,1,101},{lib_version,1,2,102}] = nif_mod_call_history(), @@ -78,11 +92,13 @@ reload(Config) when is_list(Config) -> ?line [{unload,1,3,103}] = nif_mod_call_history(), ?line [?MODULE, nif_mod] = erlang:system_info(taints), + ?line verify_tmpmem(TmpMem), ok. upgrade(doc) -> ["Test upgrade callback in nif lib"]; upgrade(suite) -> []; upgrade(Config) when is_list(Config) -> + TmpMem = tmpmem(), ensure_lib_loaded(Config), ?line Data = ?config(data_dir, Config), @@ -90,7 +106,7 @@ upgrade(Config) when is_list(Config) -> ?line {ok,nif_mod,Bin} = compile:file(File, [binary,return_errors]), ?line {module,nif_mod} = erlang:load_module(nif_mod,Bin), - ?line nif_mod:load_nif_lib(Config, 1), + ?line ok = nif_mod:load_nif_lib(Config, 1), ?line {Pid,MRef} = nif_mod:start(), ?line 1 = call(Pid,lib_version), @@ -103,7 +119,7 @@ upgrade(Config) when is_list(Config) -> ?line 1 = call(Pid,lib_version), ?line [{lib_version,1,4,104}] = nif_mod_call_history(), - ?line nif_mod:load_nif_lib(Config, 1), + ?line ok = nif_mod:load_nif_lib(Config, 1), ?line 1 = nif_mod:lib_version(), ?line [{upgrade,1,5,105},{lib_version,1,6,106}] = nif_mod_call_history(), @@ -130,7 +146,7 @@ upgrade(Config) when is_list(Config) -> ?line {Pid2,MRef2} = nif_mod:start(), ?line undefined = call(Pid2,lib_version), - ?line nif_mod:load_nif_lib(Config, 1), + ?line ok = nif_mod:load_nif_lib(Config, 1), ?line hold_nif_mod_priv_data(nif_mod:get_priv_data_ptr()), ?line 1 = call(Pid2,lib_version), ?line [{load,1,1,101},{get_priv_data_ptr,1,2,102},{lib_version,1,3,103}] = nif_mod_call_history(), @@ -141,7 +157,7 @@ upgrade(Config) when is_list(Config) -> ?line 1 = call(Pid2,lib_version), ?line [{lib_version,1,4,104}] = nif_mod_call_history(), - ?line nif_mod:load_nif_lib(Config, 2), + ?line ok = nif_mod:load_nif_lib(Config, 2), ?line 2 = nif_mod:lib_version(), ?line [{upgrade,2,1,201},{lib_version,2,2,202}] = nif_mod_call_history(), @@ -166,14 +182,17 @@ upgrade(Config) when is_list(Config) -> ?line [{unload,2,4,204}] = nif_mod_call_history(), ?line [?MODULE, nif_mod] = erlang:system_info(taints), + ?line verify_tmpmem(TmpMem), ok. heap_frag(doc) -> ["Test NIF building heap fragments"]; heap_frag(suite) -> []; heap_frag(Config) when is_list(Config) -> + TmpMem = tmpmem(), ensure_lib_loaded(Config), heap_frag_do(1,1000000), + ?line verify_tmpmem(TmpMem), ok. heap_frag_do(N, Max) when N > Max -> @@ -184,36 +203,614 @@ heap_frag_do(N, Max) -> L = list_seq(N), heap_frag_do(((N*5) div 4) + 1, Max). +types(doc) -> ["Type tests"]; +types(suite) -> []; +types(Config) when is_list(Config) -> + TmpMem = tmpmem(), + ensure_lib_loaded(Config), + ?line ok = type_test(), + lists:foreach(fun(Tpl) -> + Lst = erlang:tuple_to_list(Tpl), + Lst = tuple_2_list(Tpl) + end, + [{},{ok},{{}},{[],{}},{1,2,3,4,5}]), + Stuff = [[],{},0,0.0,(1 bsl 100),(fun()-> ok end),make_ref(),self()], + [eq_cmp(A,clone(B)) || A<-Stuff, B<-Stuff], + ?line verify_tmpmem(TmpMem), + ok. + +clone(X) -> + binary_to_term(term_to_binary(X)). + +eq_cmp(A,B) -> + eq_cmp_do(A,B), + eq_cmp_do([A,B],[A,B]), + eq_cmp_do({A,B},{A,B}). + +eq_cmp_do(A,B) -> + %%?t:format("compare ~p and ~p\n",[A,B]), + Eq = (A =:= B), + ?line Eq = is_identical(A,B), + ?line Cmp = if + A < B -> -1; + A == B -> 0; + A > B -> 1 + end, + ?line Cmp = case compare(A,B) of + C when is_integer(C), C < 0 -> -1; + 0 -> 0; + C when is_integer(C) -> 1 + end, + ok. + + +many_args(doc) -> ["Test NIF with many arguments"]; +many_args(suite) -> []; +many_args(Config) when is_list(Config) -> + TmpMem = tmpmem(), + ?line ensure_lib_loaded(Config ,1), + ?line ok = apply(?MODULE,many_args_100,lists:seq(1,100)), + ?line ok = many_args_100(1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,96,97,98,99,100), + ?line verify_tmpmem(TmpMem), + ok. + +binaries(doc) -> ["Test NIF binary handling."]; +binaries(suite) -> []; +binaries(Config) when is_list(Config) -> + TmpMem = tmpmem(), + ?line ensure_lib_loaded(Config, 1), + ?line RefcBin = list_to_binary(lists:seq(1,255)), + ?line RefcBin = clone_bin(RefcBin), + ?line HeapBin = list_to_binary(lists:seq(1,20)), + ?line HeapBin = clone_bin(HeapBin), + ?line <<_:8,Sub1:6/binary,_/binary>> = RefcBin, + ?line <<_:8,Sub2:6/binary,_/binary>> = HeapBin, + ?line Sub1 = Sub2, + ?line Sub1 = clone_bin(Sub1), + ?line Sub2 = clone_bin(Sub2), + ?line <<_:9,Sub3:6/binary,_/bitstring>> = RefcBin, + ?line <<_:9,Sub4:6/binary,_/bitstring>> = HeapBin, + ?line Sub3 = Sub4, + ?line Sub3 = clone_bin(Sub3), + ?line Sub4 = clone_bin(Sub4), + %% When NIFs get bitstring support + %%?line <<_:8,Sub5:27/bitstring,_/bitstring>> = RefcBin, + %%?line <<_:8,Sub6:27/bitstring,_/bitstring>> = HeapBin, + %%?line Sub5 = Sub6, + %%?line Sub5 = clone_bin(Sub5), + %%?line Sub6 = clone_bin(Sub6), + %%?line <<_:9,Sub7:27/bitstring,_/bitstring>> = RefcBin, + %%?line <<_:9,Sub8:27/bitstring,_/bitstring>> = HeapBin, + %%?line Sub7 = Sub8, + %%?line Sub7 = clone_bin(Sub7), + %%?line Sub8 = clone_bin(Sub8), + %%?line <<>> = clone_bin(<<>>), + + <<_:8,SubBinA:200/binary,_/binary>> = RefcBin, + <<_:9,SubBinB:200/binary,_/bitstring>> = RefcBin, + <<_:8,SubBinC:17/binary,_/binary>> = HeapBin, + <<_:9,SubBinD:17/binary,_/bitstring>> = HeapBin, + test_make_sub_bin(RefcBin), + test_make_sub_bin(HeapBin), + test_make_sub_bin(SubBinA), + test_make_sub_bin(SubBinB), + test_make_sub_bin(SubBinC), + test_make_sub_bin(SubBinD), + + ?line verify_tmpmem(TmpMem), + ok. + +test_make_sub_bin(Bin) -> + Size = byte_size(Bin), + Rest10 = Size - 10, + Rest1 = Size - 1, + ?line Bin = make_sub_bin(Bin, 0, Size), + <<_:10/binary,Sub0:Rest10/binary>> = Bin, + ?line Sub0 = make_sub_bin(Bin, 10, Rest10), + <<Sub1:10/binary,_/binary>> = Bin, + ?line Sub1 = make_sub_bin(Bin, 0, 10), + <<_:7/binary,Sub2:10/binary,_/binary>> = Bin, + ?line Sub2 = make_sub_bin(Bin, 7, 10), + ?line <<>> = make_sub_bin(Bin, 0, 0), + ?line <<>> = make_sub_bin(Bin, 10, 0), + ?line <<>> = make_sub_bin(Bin, Rest1, 0), + ?line <<>> = make_sub_bin(Bin, Size, 0), + ok. + +get_string(doc) -> ["Test enif_get_string"]; +get_string(suite) -> []; +get_string(Config) when is_list(Config) -> + ?line ensure_lib_loaded(Config, 1), + ?line {7, <<"hejsan",0,_:3/binary>>} = string_to_bin("hejsan",10), + ?line {7, <<"hejsan",0,_>>} = string_to_bin("hejsan",8), + ?line {7, <<"hejsan",0>>} = string_to_bin("hejsan",7), + ?line {-6, <<"hejsa",0>>} = string_to_bin("hejsan",6), + ?line {-5, <<"hejs",0>>} = string_to_bin("hejsan",5), + ?line {-1, <<0>>} = string_to_bin("hejsan",1), + ?line {0, <<>>} = string_to_bin("hejsan",0), + ?line {1, <<0>>} = string_to_bin("",1), + ?line {0, <<>>} = string_to_bin("",0), + ok. + +get_atom(doc) -> ["Test enif_get_atom"]; +get_atom(suite) -> []; +get_atom(Config) when is_list(Config) -> + ?line ensure_lib_loaded(Config, 1), + ?line {7, <<"hejsan",0,_:3/binary>>} = atom_to_bin(hejsan,10), + ?line {7, <<"hejsan",0,_>>} = atom_to_bin(hejsan,8), + ?line {7, <<"hejsan",0>>} = atom_to_bin(hejsan,7), + ?line {0, <<_:6/binary>>} = atom_to_bin(hejsan,6), + ?line {0, <<>>} = atom_to_bin(hejsan,0), + ?line {1, <<0>>} = atom_to_bin('',1), + ?line {0, <<>>} = atom_to_bin('',0), + ok. + +api_macros(doc) -> ["Test macros enif_make_list<N> and enif_make_tuple<N>"]; +api_macros(suite) -> []; +api_macros(Config) when is_list(Config) -> + ?line ensure_lib_loaded(Config, 1), + Expected = {[lists:seq(1,N) || N <- lists:seq(1,9)], + [list_to_tuple(lists:seq(1,N)) || N <- lists:seq(1,9)] + }, + ?line Expected = macros(list_to_tuple(lists:seq(1,9))), + ok. + +from_array(doc) -> ["enif_make_[tuple|list]_from_array"]; +from_array(suite) -> []; +from_array(Config) when is_list(Config) -> + ?line ensure_lib_loaded(Config, 1), + lists:foreach(fun(Tpl) -> + Lst = tuple_to_list(Tpl), + ?line {Lst,Tpl} = tuple_2_list_and_tuple(Tpl) + end, + [{}, {1,2,3}, {[4,5],[],{},{6,7}}, {{}}, {[]}]), + ok. + +iolist_as_binary(doc) -> ["enif_inspect_iolist_as_binary"]; +iolist_as_binary(suite) -> []; +iolist_as_binary(Config) when is_list(Config) -> + ?line ensure_lib_loaded(Config, 1), + TmpMem = tmpmem(), + List = [<<"hejsan">>, <<>>, [], [17], [<<>>], + [127,128,255,0], + [1, 2, 3, <<"abc">>, [<<"def">>,4], 5, <<"ghi">>], + [1, 2, 3, <<"abc">>, [<<"def">>,4], 5 | <<"ghi">>]], + + lists:foreach(fun(IoL) -> + B1 = erlang:iolist_to_binary(IoL), + ?line B2 = iolist_2_bin(IoL), + ?line B1 = B2 + end, + List), + ?line verify_tmpmem(TmpMem), + ok. + +resource(doc) -> ["Test memory managed objects, aka 'resources'"]; +resource(suite) -> []; +resource(Config) when is_list(Config) -> + ?line ensure_lib_loaded(Config, 1), + ?line Type = get_resource_type(0), + resource_hugo(Type), + resource_otto(Type), + resource_new(Type), + resource_neg(Type), + ok. + +resource_hugo(Type) -> + DtorCall = resource_hugo_do(Type), + erlang:garbage_collect(), + ?line DtorCall = last_resource_dtor_call(), + ok. + +resource_hugo_do(Type) -> + HugoBin = <<"Hugo Hacker">>, + ?line HugoPtr = alloc_resource(Type, HugoBin), + ?line Hugo = make_resource(HugoPtr), + ?line <<>> = Hugo, + release_resource(HugoPtr), + erlang:garbage_collect(), + ?line {HugoPtr,HugoBin} = get_resource(Type,Hugo), + Pid = spawn_link(fun() -> + receive {Pid, Type, Resource, Ptr, Bin} -> + Pid ! {self(), got_it}, + receive {Pid, check_it} -> + ?line {Ptr,Bin} = get_resource(Type,Resource), + Pid ! {self(), ok} + end + end + end), + Pid ! {self(), Type, Hugo, HugoPtr, HugoBin}, + ?line {Pid, got_it} = receive_any(), + erlang:garbage_collect(), % just to make our ProcBin move in memory + Pid ! {self(), check_it}, + ?line {Pid, ok} = receive_any(), + ?line [] = last_resource_dtor_call(), + ?line {HugoPtr,HugoBin} = get_resource(Type,Hugo), + {HugoPtr, HugoBin, 1}. + +resource_otto(Type) -> + {OttoPtr, OttoBin} = resource_otto_do(Type), + erlang:garbage_collect(), + ?line [] = last_resource_dtor_call(), + release_resource(OttoPtr), + ?line {OttoPtr,OttoBin,1} = last_resource_dtor_call(), + ok. + +resource_otto_do(Type) -> + OttoBin = <<"Otto Ordonnans">>, + ?line OttoPtr = alloc_resource(Type, OttoBin), + ?line Otto = make_resource(OttoPtr), + ?line <<>> = Otto, + %% forget resource term but keep referenced by NIF + {OttoPtr, OttoBin}. + +resource_new(Type) -> + ?line {PtrB,BinB} = resource_new_do1(Type), + erlang:garbage_collect(), + ?line {PtrB,BinB,1} = last_resource_dtor_call(), + ok. + +resource_new_do1(Type) -> + ?line {{PtrA,BinA}, {ResB,PtrB,BinB}} = resource_new_do2(Type), + erlang:garbage_collect(), + ?line {PtrA,BinA,1} = last_resource_dtor_call(), + ?line {PtrB,BinB} = get_resource(Type, ResB), + %% forget ResB and make it garbage + {PtrB,BinB}. + +resource_new_do2(Type) -> + BinA = <<"NewA">>, + BinB = <<"NewB">>, + ?line ResA = make_new_resource(Type, BinA), + ?line ResB = make_new_resource(Type, BinB), + ?line <<>> = ResA, + ?line <<>> = ResB, + ?line {PtrA,BinA} = get_resource(Type, ResA), + ?line {PtrB,BinB} = get_resource(Type, ResB), + ?line true = (PtrA =/= PtrB), + ?line [] = last_resource_dtor_call(), + %% forget ResA and make it garbage + {{PtrA,BinA}, {ResB,PtrB,BinB}}. + +resource_neg(TypeA) -> + TypeB = get_resource_type(1), + Aptr = alloc_resource(TypeA, <<"Arnold">>), + Bptr = alloc_resource(TypeB, <<"Bobo">>), + ?line {'EXIT',{badarg,_}} = (catch get_resource(TypeA, Bptr)), + ?line {'EXIT',{badarg,_}} = (catch get_resource(TypeB, Aptr)), + ok. + +-define(RT_CREATE,1). +-define(RT_TAKEOVER,2). + +resource_takeover(doc) -> ["Test resource takeover by module reload and upgrade"]; +resource_takeover(suite) -> []; +resource_takeover(Config) when is_list(Config) -> + TmpMem = tmpmem(), + ensure_lib_loaded(Config), + + ?line Data = ?config(data_dir, Config), + ?line File = filename:join(Data, "nif_mod"), + ?line {ok,nif_mod,ModBin} = compile:file(File, [binary,return_errors]), + ?line {module,nif_mod} = erlang:load_module(nif_mod,ModBin), + + ?line ok = nif_mod:load_nif_lib(Config, 1, + [{resource_type, 0, ?RT_CREATE, "resource_type_A",resource_dtor_A, + ?RT_CREATE}, + {resource_type, 1, ?RT_CREATE, "resource_type_null_A",null, + ?RT_CREATE}, + {resource_type, 2, ?RT_CREATE bor ?RT_TAKEOVER, "resource_type_A_null",resource_dtor_A, + ?RT_CREATE}, + {resource_type, 3, ?RT_CREATE, "resource_type_B_goneX",resource_dtor_B, + ?RT_CREATE}, + {resource_type, 4, ?RT_CREATE, "resource_type_null_goneX",null, + ?RT_CREATE}, + {resource_type, null, ?RT_TAKEOVER, "Pink unicorn", resource_dtor_A, + ?RT_TAKEOVER} + ]), + + ?line hold_nif_mod_priv_data(nif_mod:get_priv_data_ptr()), + ?line [{load,1,1,101},{get_priv_data_ptr,1,2,102}] = nif_mod_call_history(), + + ?line {Holder, _MRef} = spawn_opt(fun resource_holder/0, [link, monitor]), + + {A1,BinA1} = make_resource(0,Holder,"A1"), + {A2,BinA2} = make_resource(0,Holder,"A2"), + {A3,BinA3} = make_resource(0,Holder,"A3"), + + {NA1,_BinNA1} = make_resource(1,Holder,"NA1"), + {NA2,BinNA2} = make_resource(1,Holder,"NA2"), + {NA3,_BinNA3} = make_resource(1,Holder,"NA3"), + + {AN1,BinAN1} = make_resource(2,Holder,"AN1"), + {AN2,_BinAN2} = make_resource(2,Holder,"AN2"), + {AN3,BinAN3} = make_resource(2,Holder,"AN3"), + + {BGX1,BinBGX1} = make_resource(3,Holder,"BGX1"), + {BGX2,BinBGX2} = make_resource(3,Holder,"BGX2"), + + {NGX1,_BinNGX1} = make_resource(4,Holder,"NGX1"), + {NGX2,_BinNGX2} = make_resource(4,Holder,"NGX2"), + + ?line [] = nif_mod_call_history(), + + ?line ok = forget_resource(A1), + ?line [{{resource_dtor_A_v1,BinA1},1,3,103}] = nif_mod_call_history(), + + ?line ok = forget_resource(NA1), + ?line [] = nif_mod_call_history(), % no dtor + + ?line ok = forget_resource(AN1), + ?CHECK([{{resource_dtor_A_v1,BinAN1},1,4,104}] , nif_mod_call_history()), + + ?line ok = forget_resource(BGX1), + ?CHECK([{{resource_dtor_B_v1,BinBGX1},1,5,105}], nif_mod_call_history()), + + ?line ok = forget_resource(NGX1), + ?CHECK([], nif_mod_call_history()), % no dtor + + ?line ok = nif_mod:load_nif_lib(Config, 2, + [{resource_type, 0, ?RT_TAKEOVER, "resource_type_A",resource_dtor_A, + ?RT_TAKEOVER}, + {resource_type, 1, ?RT_TAKEOVER bor ?RT_CREATE, "resource_type_null_A",resource_dtor_A, + ?RT_TAKEOVER}, + {resource_type, 2, ?RT_TAKEOVER, "resource_type_A_null",null, + ?RT_TAKEOVER}, + {resource_type, null, ?RT_TAKEOVER, "Pink unicorn", resource_dtor_A, + ?RT_TAKEOVER}, + {resource_type, null, ?RT_CREATE, "resource_type_B_goneX",resource_dtor_B, + ?RT_CREATE}, + {resource_type, null, ?RT_CREATE, "resource_type_null_goneX",null, + ?RT_CREATE}, + {resource_type, 3, ?RT_CREATE, "resource_type_B_goneY",resource_dtor_B, + ?RT_CREATE}, + {resource_type, 4, ?RT_CREATE, "resource_type_null_goneY",null, + ?RT_CREATE} + ]), + ?CHECK([{reload,2,1,201}], nif_mod_call_history()), + + ?line BinA2 = read_resource(0,A2), + ?line ok = forget_resource(A2), + ?CHECK([{{resource_dtor_A_v2,BinA2},2,2,202}], nif_mod_call_history()), + + ?line ok = forget_resource(NA2), + ?CHECK([{{resource_dtor_A_v2,BinNA2},2,3,203}], nif_mod_call_history()), + + ?line ok = forget_resource(AN2), + ?CHECK([], nif_mod_call_history()), % no dtor + + ?line ok = forget_resource(BGX2), % calling dtor in orphan library v1 still loaded + ?CHECK([{{resource_dtor_B_v1,BinBGX2},1,6,106}], nif_mod_call_history()), + % How to test that lib v1 is closed here? + + ?line ok = forget_resource(NGX2), + ?CHECK([], nif_mod_call_history()), % no dtor + + {BGY1,BinBGY1} = make_resource(3,Holder,"BGY1"), + {NGY1,_BinNGY1} = make_resource(4,Holder,"NGY1"), + %% Module upgrade with same lib-version + ?line {module,nif_mod} = erlang:load_module(nif_mod,ModBin), + ?line undefined = nif_mod:lib_version(), + ?line ok = nif_mod:load_nif_lib(Config, 2, + [{resource_type, 2, ?RT_TAKEOVER, "resource_type_A",resource_dtor_B, + ?RT_TAKEOVER}, + {resource_type, 0, ?RT_TAKEOVER bor ?RT_CREATE, "resource_type_null_A",null, + ?RT_TAKEOVER}, + {resource_type, 1, ?RT_TAKEOVER, "resource_type_A_null",resource_dtor_A, + ?RT_TAKEOVER}, + {resource_type, null, ?RT_TAKEOVER, "Pink elephant", resource_dtor_A, + ?RT_TAKEOVER}, + {resource_type, 3, ?RT_CREATE, "resource_type_B_goneZ",resource_dtor_B, + ?RT_CREATE}, + {resource_type, 4, ?RT_CREATE, "resource_type_null_goneZ",null, + ?RT_CREATE} + ]), + + ?line 2 = nif_mod:lib_version(), + ?CHECK([{upgrade,2,4,204},{lib_version,2,5,205}], nif_mod_call_history()), + + ?line ok = forget_resource(A3), + ?CHECK([{{resource_dtor_B_v2,BinA3},2,6,206}], nif_mod_call_history()), + + ?line ok = forget_resource(NA3), + ?CHECK([], nif_mod_call_history()), + + ?line ok = forget_resource(AN3), + ?CHECK([{{resource_dtor_A_v2,BinAN3},2,7,207}], nif_mod_call_history()), + + {A4,BinA4} = make_resource(2,Holder, "A4"), + {NA4,BinNA4} = make_resource(0,Holder, "NA4"), + {AN4,_BinAN4} = make_resource(1,Holder, "AN4"), + + {BGZ1,BinBGZ1} = make_resource(3,Holder,"BGZ1"), + {NGZ1,_BinNGZ1} = make_resource(4,Holder,"NGZ1"), + + ?line false = code:purge(nif_mod), + ?line [] = nif_mod_call_history(), + + ?line ok = forget_resource(NGY1), + ?line [] = nif_mod_call_history(), + + ?line ok = forget_resource(BGY1), % calling dtor in orphan library v2 still loaded + ?line [{{resource_dtor_B_v2,BinBGY1},2,8,208},{unload,2,9,209}] = nif_mod_call_history(), + + %% Module upgrade with other lib-version + ?line {module,nif_mod} = erlang:load_module(nif_mod,ModBin), + ?line undefined = nif_mod:lib_version(), + ?line ok = nif_mod:load_nif_lib(Config, 1, + [{resource_type, 2, ?RT_TAKEOVER, "resource_type_A",resource_dtor_A, + ?RT_TAKEOVER}, + {resource_type, 0, ?RT_TAKEOVER bor ?RT_CREATE, "resource_type_null_A",resource_dtor_A, + ?RT_TAKEOVER}, + {resource_type, 1, ?RT_TAKEOVER, "resource_type_A_null",null, + ?RT_TAKEOVER}, + {resource_type, null, ?RT_TAKEOVER, "Mr Pink", resource_dtor_A, + ?RT_TAKEOVER} + ]), + + ?line 1 = nif_mod:lib_version(), + ?line [{upgrade,1,1,101},{lib_version,1,2,102}] = nif_mod_call_history(), + + %%?line false= check_process_code(Pid, nif_mod), + ?line false = code:purge(nif_mod), + %% no unload here as we still have instances with destructors + ?line [] = nif_mod_call_history(), + + ?line ok = forget_resource(BGZ1), % calling dtor in orphan library v2 still loaded + ?line [{{resource_dtor_B_v2,BinBGZ1},2,10,210},{unload,2,11,211}] = nif_mod_call_history(), + + ?line ok = forget_resource(NGZ1), + ?line [] = nif_mod_call_history(), + + ?line ok = forget_resource(A4), + ?line [{{resource_dtor_A_v1,BinA4},1,3,103}] = nif_mod_call_history(), + + ?line ok = forget_resource(NA4), + ?line [{{resource_dtor_A_v1,BinNA4},1,4,104}] = nif_mod_call_history(), + + ?line ok = forget_resource(AN4), + ?line [] = nif_mod_call_history(), + + ?line [?MODULE, nif_mod] = erlang:system_info(taints), + ?line verify_tmpmem(TmpMem), + ok. + +make_resource(Type,Holder,Str) when is_list(Str) -> + Bin = list_to_binary(Str), + A1 = make_resource_do(Type,Holder,Bin), + ?line Bin = read_resource(Type,A1), + {A1,Bin}. + +make_resource_do(Type, Holder, Bin) -> + Holder ! {self(), make, Type, Bin}, + {Holder, make_ok, Id} = receive_any(), + {Holder,Id}. + +read_resource(Type, {Holder,Id}) -> + Holder ! {self(), get, Type, Id}, + {Holder, get_ok, Bin} = receive_any(), + Bin. + +forget_resource({Holder,Id}) -> + Holder ! {self(), forget, Id}, + {Holder, forget_ok, Id} = receive_any(), + ok. + + +resource_holder() -> + resource_holder([]). +resource_holder(List) -> + %%io:format("resource_holder waiting for msg\n", []), + Msg = receive_any(), + %%io:format("resource_holder got ~p with list = ~p\n", [Msg,List]), + case Msg of + {Pid, make, Type, Bin} -> + ?line Resource = nif_mod:make_new_resource(Type, Bin), + Id = {make_ref(),Bin}, + Pid ! {self(), make_ok, Id}, + resource_holder([{Id,Resource} | List]); + {Pid, get, Type, Id} -> + {Id,Resource} = lists:keyfind(Id, 1, List), + Pid ! {self(), get_ok, nif_mod:get_resource(Type, Resource)}, + resource_holder(List); + + {Pid, forget, Id} -> + NewList = lists:keydelete(Id, 1, List), + %%io:format("resource_holder forget: NewList = ~p\n", [NewList]), + resource_holder(Pid, {self(),forget_ok,Id}, NewList) + end. + +resource_holder(Pid,Reply,List) -> + erlang:garbage_collect(), + %%io:format("resource_holder GC'ed, now send ~p to ~p\n", [Reply,Pid]), + Pid ! Reply, + resource_holder(List). + + +threading(doc) -> ["Test the threading API functions (reuse tests from driver API)"]; +threading(Config) when is_list(Config) -> + ?line Data = ?config(data_dir, Config), + ?line File = filename:join(Data, "tester"), + ?line {ok,tester,ModBin} = compile:file(File, [binary,return_errors]), + ?line {module,tester} = erlang:load_module(tester,ModBin), + + ?line ok = tester:load_nif_lib(Config, "basic"), + ?line ok = tester:run(), + + ?line ok = tester:load_nif_lib(Config, "rwlock"), + ?line ok = tester:run(), + + ?line ok = tester:load_nif_lib(Config, "tsd"), + ?line ok = tester:run(). + neg(doc) -> ["Negative testing of load_nif"]; -neg(suite) -> []; neg(Config) when is_list(Config) -> + TmpMem = tmpmem(), ?line {'EXIT',{badarg,_}} = (catch erlang:load_nif(badarg, 0)), - ?line {error,load_failed,_} = erlang:load_nif("pink_unicorn", 0), + ?line {error,{load_failed,_}} = erlang:load_nif("pink_unicorn", 0), ?line Data = ?config(data_dir, Config), ?line File = filename:join(Data, "nif_mod"), ?line {ok,nif_mod,Bin} = compile:file(File, [binary,return_errors]), ?line {module,nif_mod} = erlang:load_module(nif_mod,Bin), - ?line {error,bad_lib,_} = nif_mod:load_nif_lib(Config, no_init), + ?line {error,{bad_lib,_}} = nif_mod:load_nif_lib(Config, no_init), + ?line verify_tmpmem(TmpMem), ?line ok. ensure_lib_loaded(Config) -> ensure_lib_loaded(Config, 1). - ensure_lib_loaded(Config, Ver) -> ?line case lib_version() of undefined -> ?line Path = ?config(data_dir, Config), ?line Lib = "nif_SUITE." ++ integer_to_list(Ver), - ?line ok = erlang:load_nif(filename:join(Path,Lib), 0); + ?line ok = erlang:load_nif(filename:join(Path,Lib), []); Ver when is_integer(Ver) -> ok end. +tmpmem() -> + case erlang:system_info({allocator,temp_alloc}) of + false -> undefined; + MemInfo -> + MSBCS = lists:foldl( + fun ({instance, _, L}, Acc) -> + {value,{_,MBCS}} = lists:keysearch(mbcs, 1, L), + {value,{_,SBCS}} = lists:keysearch(sbcs, 1, L), + [MBCS,SBCS | Acc] + end, + [], + MemInfo), + lists:foldl( + fun(L, {Bl0,BlSz0}) -> + {value,{_,Bl,_,_}} = lists:keysearch(blocks, 1, L), + {value,{_,BlSz,_,_}} = lists:keysearch(blocks_size, 1, L), + {Bl0+Bl,BlSz0+BlSz} + end, {0,0}, MSBCS) + end. + +verify_tmpmem(MemInfo) -> + %%wait_for_test_procs(), + case tmpmem() of + MemInfo -> + io:format("Tmp mem info: ~p", [MemInfo]), + case MemInfo of + {notsup,undefined} -> + %% Use 'erl +Mea max' to do more complete memory leak testing. + {comment,"Incomplete or no mem leak testing"}; + _ -> + ok + end; + Other -> + io:format("Expected: ~p", [MemInfo]), + io:format("Actual: ~p", [Other]), + ?t:fail() + end. + call(Pid,Cmd) -> %%io:format("~p calling ~p with ~p\n",[self(), Pid, Cmd]), Pid ! {self(), Cmd}, @@ -224,12 +821,40 @@ call(Pid,Cmd) -> receive_any() -> receive M -> M end. +%% check(Exp,Got,Line) -> +%% case Got of +%% Exp -> Exp; +%% _ -> +%% io:format("CHECK at ~p: Expected ~p but got ~p\n",[Line,Exp,Got]), +%% Got +%% end. + + %% The NIFs: lib_version() -> undefined. call_history() -> ?nif_stub. hold_nif_mod_priv_data(_Ptr) -> ?nif_stub. nif_mod_call_history() -> ?nif_stub. list_seq(_To) -> ?nif_stub. - +type_test() -> ?nif_stub. +tuple_2_list(_) -> ?nif_stub. +is_identical(_,_) -> ?nif_stub. +compare(_,_) -> ?nif_stub. +many_args_100(_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_) -> ?nif_stub. +clone_bin(_) -> ?nif_stub. +make_sub_bin(_,_,_) -> ?nif_stub. +string_to_bin(_,_) -> ?nif_stub. +atom_to_bin(_,_) -> ?nif_stub. +macros(_) -> ?nif_stub. +tuple_2_list_and_tuple(_) -> ?nif_stub. +iolist_2_bin(_) -> ?nif_stub. +get_resource_type(_) -> ?nif_stub. +alloc_resource(_,_) -> ?nif_stub. +make_resource(_) -> ?nif_stub. +get_resource(_,_) -> ?nif_stub. +release_resource(_) -> ?nif_stub. +last_resource_dtor_call() -> ?nif_stub. +make_new_resource(_,_) -> ?nif_stub. + nif_stub_error(Line) -> exit({nif_not_loaded,module,?MODULE,line,Line}). diff --git a/erts/emulator/test/nif_SUITE_data/Makefile.src b/erts/emulator/test/nif_SUITE_data/Makefile.src index 6a8b4f1245..ab4ff77add 100644 --- a/erts/emulator/test/nif_SUITE_data/Makefile.src +++ b/erts/emulator/test/nif_SUITE_data/Makefile.src @@ -4,11 +4,22 @@ NIF_LIBS = nif_SUITE.1@dll@ \ nif_mod.2@dll@ \ nif_mod.3@dll@ -all: $(NIF_LIBS) +all: $(NIF_LIBS) basic@dll@ rwlock@dll@ tsd@dll@ @SHLIB_RULES@ $(NIF_LIBS): nif_SUITE.c nif_mod.c nif_mod.h +basic@dll@: tester.c testcase_driver.h +rwlock@dll@: tester.c testcase_driver.h + +tsd@dll@: tester.c testcase_driver.h + +DRIVER_DIR = ../erl_drv_thread_SUITE_data + +basic.c rwlock.c tsd.c: $(DRIVER_DIR)/$@ + cat head.txt > $@ + cat $(DRIVER_DIR)/$@ | sed -e 's/erl_drv_/enif_/g' -e 's/driver_/enif_/g' -e 's/ErlDrv/ErlNif/g' >> $@ + cat tail.txt >> $@ diff --git a/erts/emulator/test/nif_SUITE_data/head.txt b/erts/emulator/test/nif_SUITE_data/head.txt new file mode 100644 index 0000000000..4b9b44276f --- /dev/null +++ b/erts/emulator/test/nif_SUITE_data/head.txt @@ -0,0 +1,5 @@ +/* Do NOT edit this file!!! +** +** This is a NIF'ified COPY of the original in ../erl_drv_thread_SUITE_data/ +*/ + diff --git a/erts/emulator/test/nif_SUITE_data/nif_SUITE.c b/erts/emulator/test/nif_SUITE_data/nif_SUITE.c index 852495e234..7d05a9a880 100644 --- a/erts/emulator/test/nif_SUITE_data/nif_SUITE.c +++ b/erts/emulator/test/nif_SUITE_data/nif_SUITE.c @@ -1,6 +1,9 @@ #include "erl_nif.h" + +#include <stdio.h> #include <string.h> #include <assert.h> +#include <limits.h> #include "nif_mod.h" @@ -12,6 +15,7 @@ typedef struct int ref_cnt; CallInfo* call_history; NifModPrivData* nif_mod; + union { ErlNifResourceType* t; long l; } rt_arr[2]; }PrivData; void add_call(ErlNifEnv* env, PrivData* data, const char* func_name) @@ -23,12 +27,29 @@ void add_call(ErlNifEnv* env, PrivData* data, const char* func_name) call->static_cntA = ++static_cntA; call->static_cntB = ++static_cntB; data->call_history = call; + call->arg = NULL; + call->arg_sz = 0; } #define ADD_CALL(FUNC_NAME) add_call(env, enif_get_data(env),FUNC_NAME) +static void* resource_dtor_last = NULL; +static unsigned resource_dtor_last_sz = 0; +static char resource_dtor_last_data[20]; +static int resource_dtor_cnt = 0; + +static void resource_dtor(ErlNifEnv* env, void* obj) +{ + resource_dtor_last = obj; + resource_dtor_cnt++; + resource_dtor_last_sz = enif_sizeof_resource(env, obj); + assert(resource_dtor_last_sz <= sizeof(resource_dtor_last_data)); + memcpy(resource_dtor_last_data, obj, resource_dtor_last_sz); +} + static int load(ErlNifEnv* env, void** priv_data, ERL_NIF_TERM load_info) { + /*ERL_NIF_TERM head, tail;*/ PrivData* data = enif_alloc(env, sizeof(PrivData)); assert(data != NULL); data->ref_cnt = 1; @@ -36,7 +57,26 @@ static int load(ErlNifEnv* env, void** priv_data, ERL_NIF_TERM load_info) data->nif_mod = NULL; add_call(env, data, "load"); - + + /* + head = load_info; + data->rt_cnt = 0; + for (head=load_info; enif_get_list_cell(env,load_info,&head,&tail); + head=tail) { + char buf[20]; + int n = enif_get_string(env,head,buf,sizeof(buf)); + assert(n > 0); + assert(i < sizeof(data->rt_arr)/sizeof(*data->rt_arr)); + data->rt_arr[data->rt_cnt++].t = enif_create_resource_type(env,buf,resource_dtor, + ERL_NIF_RT_CREATE,NULL); + } + assert(enif_is_empty_list(env,head)); + */ + data->rt_arr[0].t = enif_open_resource_type(env,"Gold",resource_dtor, + ERL_NIF_RT_CREATE,NULL); + data->rt_arr[1].t = enif_open_resource_type(env,"Silver",resource_dtor, + ERL_NIF_RT_CREATE,NULL); + *priv_data = data; return 0; } @@ -65,7 +105,7 @@ static void unload(ErlNifEnv* env, void* priv_data) } } -static ERL_NIF_TERM lib_version(ErlNifEnv* env) +static ERL_NIF_TERM lib_version(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) { ADD_CALL("lib_version"); return enif_make_int(env, NIF_SUITE_LIB_VER); @@ -77,11 +117,19 @@ static ERL_NIF_TERM make_call_history(ErlNifEnv* env, CallInfo** headp) while (*headp != NULL) { CallInfo* call = *headp; - ERL_NIF_TERM tpl = enif_make_tuple(env, 4, - enif_make_atom(env,call->func_name), - enif_make_int(env,call->lib_ver), - enif_make_int(env,call->static_cntA), - enif_make_int(env,call->static_cntB)); + ERL_NIF_TERM func_term = enif_make_atom(env,call->func_name); + ERL_NIF_TERM tpl; + if (call->arg != NULL) { + ErlNifBinary arg_bin; + enif_alloc_binary(env, call->arg_sz, &arg_bin); + memcpy(arg_bin.data, call->arg, call->arg_sz); + func_term = enif_make_tuple2(env, func_term, + enif_make_binary(env, &arg_bin)); + } + tpl = enif_make_tuple4(env, func_term, + enif_make_int(env,call->lib_ver), + enif_make_int(env,call->static_cntA), + enif_make_int(env,call->static_cntB)); list = enif_make_list_cell(env, tpl, list); *headp = call->next; enif_free(env,call); @@ -89,19 +137,19 @@ static ERL_NIF_TERM make_call_history(ErlNifEnv* env, CallInfo** headp) return list; } -static ERL_NIF_TERM call_history(ErlNifEnv* env) +static ERL_NIF_TERM call_history(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) { PrivData* data = (PrivData*) enif_get_data(env); return make_call_history(env,&data->call_history); } -static ERL_NIF_TERM hold_nif_mod_priv_data(ErlNifEnv* env, ERL_NIF_TERM a1) +static ERL_NIF_TERM hold_nif_mod_priv_data(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) { PrivData* data = (PrivData*) enif_get_data(env); unsigned long ptr_as_ulong; - if (!enif_get_ulong(env,a1,&ptr_as_ulong)) { + if (!enif_get_ulong(env,argv[0],&ptr_as_ulong)) { return enif_make_badarg(env); } if (data->nif_mod != NULL && --(data->nif_mod->ref_cnt) == 0) { @@ -111,21 +159,24 @@ static ERL_NIF_TERM hold_nif_mod_priv_data(ErlNifEnv* env, ERL_NIF_TERM a1) return enif_make_int(env,++(data->nif_mod->ref_cnt)); } -static ERL_NIF_TERM nif_mod_call_history(ErlNifEnv* env) +static ERL_NIF_TERM nif_mod_call_history(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) { PrivData* data = (PrivData*) enif_get_data(env); - + ERL_NIF_TERM ret; if (data->nif_mod == NULL) { - return enif_make_string(env,"nif_mod pointer is NULL"); + return enif_make_string(env,"nif_mod pointer is NULL", ERL_NIF_LATIN1); } - return make_call_history(env,&data->nif_mod->call_history); + enif_mutex_lock(data->nif_mod->mtx); + ret = make_call_history(env, &data->nif_mod->call_history); + enif_mutex_unlock(data->nif_mod->mtx); + return ret; } -static ERL_NIF_TERM list_seq(ErlNifEnv* env, ERL_NIF_TERM a1) +static ERL_NIF_TERM list_seq(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) { ERL_NIF_TERM list; int n; - if (!enif_get_int(env, a1, &n)) { + if (!enif_get_int(env, argv[0], &n)) { return enif_make_badarg(env); } list = enif_make_list(env, 0); /* NIL */ @@ -136,13 +187,461 @@ static ERL_NIF_TERM list_seq(ErlNifEnv* env, ERL_NIF_TERM a1) return list; } +static int test_int(ErlNifEnv* env, int i1) +{ + int i2 = 0; + ERL_NIF_TERM int_term = enif_make_int(env, i1); + if (!enif_get_int(env,int_term, &i2) || i1 != i2) { + fprintf(stderr, "test_int(%d) ...FAILED i2=%d\r\n", i1, i2); + return 0; + } + return 1; +} + +static int test_uint(ErlNifEnv* env, unsigned i1) +{ + unsigned i2 = 0; + ERL_NIF_TERM int_term = enif_make_uint(env, i1); + if (!enif_get_uint(env,int_term, &i2) || i1 != i2) { + fprintf(stderr, "test_uint(%u) ...FAILED i2=%u\r\n", i1, i2); + return 0; + } + return 1; +} + +static int test_long(ErlNifEnv* env, long i1) +{ + long i2 = 0; + ERL_NIF_TERM int_term = enif_make_long(env, i1); + if (!enif_get_long(env,int_term, &i2) || i1 != i2) { + fprintf(stderr, "test_long(%ld) ...FAILED i2=%ld\r\n", i1, i2); + return 0; + } + return 1; +} + +static int test_ulong(ErlNifEnv* env, unsigned long i1) +{ + unsigned long i2 = 0; + ERL_NIF_TERM int_term = enif_make_ulong(env, i1); + if (!enif_get_ulong(env,int_term, &i2) || i1 != i2) { + fprintf(stderr, "test_ulong(%lu) ...FAILED i2=%lu\r\n", i1, i2); + return 0; + } + return 1; +} + +static int test_double(ErlNifEnv* env, double d1) +{ + double d2 = 0; + ERL_NIF_TERM term = enif_make_double(env, d1); + if (!enif_get_double(env,term, &d2) || d1 != d2) { + fprintf(stderr, "test_double(%e) ...FAILED i2=%e\r\n", d1, d2); + return 0; + } + return 1; +} + +#define TAG_BITS 4 +#define SMALL_BITS (sizeof(void*)*8 - TAG_BITS) +#define MAX_SMALL ((1L << (SMALL_BITS-1))-1) +#define MIN_SMALL (-(1L << (SMALL_BITS-1))) + +static ERL_NIF_TERM type_test(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) +{ + int i; + int sint; + unsigned uint; + long slong; + unsigned long ulong; + double d; + ERL_NIF_TERM atom, ref1, ref2; + + sint = INT_MIN; + do { + if (!test_int(env,sint)) { + goto error; + } + sint += ~sint / 3 + 1; + } while (sint < 0); + sint = INT_MAX; + do { + if (!test_int(env,sint)) { + goto error; + } + sint -= sint / 3 + 1; + } while (sint >= 0); + + slong = LONG_MIN; + do { + if (!test_long(env,slong)) { + goto error; + } + slong += ~slong / 3 + 1; + } while (slong < 0); + slong = LONG_MAX; + do { + if (!test_long(env,slong)) { + goto error; + } + slong -= slong / 3 + 1; + } while (slong >= 0); + + + uint = UINT_MAX; + for (;;) { + if (!test_uint(env,uint)) { + + } + if (uint == 0) break; + uint -= uint / 3 + 1; + } + ulong = ULONG_MAX; + for (;;) { + if (!test_ulong(env,ulong)) { + + } + if (ulong == 0) break; + ulong -= ulong / 3 + 1; + } + + if (MAX_SMALL < INT_MAX) { /* 32-bit */ + for (i=-10 ; i <= 10; i++) { + if (!test_int(env,MAX_SMALL+i)) { + goto error; + } + } + for (i=-10 ; i <= 10; i++) { + if (!test_int(env,MIN_SMALL+i)) { + goto error; + } + } + for (i=-10 ; i <= 10; i++) { + if (!test_uint(env,MAX_SMALL+i)) { + goto error; + } + } + } + assert((MAX_SMALL < INT_MAX) == (MIN_SMALL > INT_MIN)); + + for (i=-10 ; i < 10; i++) { + if (!test_long(env,MAX_SMALL+i) || !test_ulong(env,MAX_SMALL+i) || + !test_long(env,MIN_SMALL+i)) { + goto error; + } + } + + for (d=3.141592e-100 ; d < 1e100 ; d *= 9.97) { + if (!test_double(env,d) || !test_double(env,-d)) { + goto error; + } + } + + if (!enif_make_existing_atom(env,"nif_SUITE", &atom) + || !enif_is_identical(env,atom,enif_make_atom(env,"nif_SUITE"))) { + fprintf(stderr, "nif_SUITE not an atom?\r\n"); + goto error; + } + for (i=2; i; i--) { + if (enif_make_existing_atom(env,"nif_SUITE_pink_unicorn", &atom)) { + fprintf(stderr, "pink unicorn exist?\r\n"); + goto error; + } + } + ref1 = enif_make_ref(env); + ref2 = enif_make_ref(env); + if (!enif_is_ref(env,ref1) || !enif_is_ref(env,ref2) + || enif_is_identical(env,ref1,ref2) || enif_compare(env,ref1,ref2)==0) { + fprintf(stderr, "strange refs?\r\n"); + goto error; + } + return enif_make_atom(env,"ok"); + +error: + return enif_make_atom(env,"error"); +} + +static ERL_NIF_TERM tuple_2_list(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) +{ + int arity = -1; + const ERL_NIF_TERM* ptr; + ERL_NIF_TERM list = enif_make_list(env,0); + + if (argc!=1 || !enif_get_tuple(env,argv[0],&arity,&ptr)) { + return enif_make_badarg(env); + } + while (--arity >= 0) { + list = enif_make_list_cell(env,ptr[arity],list); + } + return list; +} + +static ERL_NIF_TERM is_identical(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) +{ + if (argc != 2) { + return enif_make_badarg(env); + } + return enif_make_atom(env, (enif_is_identical(env,argv[0],argv[1]) ? + "true" : "false")); +} + +static ERL_NIF_TERM compare(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) +{ + if (argc != 2) { + return enif_make_badarg(env); + } + return enif_make_int(env, enif_compare(env,argv[0],argv[1])); +} + +static ERL_NIF_TERM many_args_100(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) +{ + int i, k; + if (argc == 100) { + for (i=1; i<=100; i++) { + if (!enif_get_int(env,argv[i-1],&k) || k!=i) { + goto badarg; + } + } + return enif_make_atom(env,"ok"); + } +badarg: + return enif_make_badarg(env); +} + +static ERL_NIF_TERM clone_bin(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) +{ + ErlNifBinary ibin; + if (enif_inspect_binary(env,argv[0],&ibin)) { + ErlNifBinary obin; + enif_alloc_binary(env,ibin.size,&obin); + memcpy(obin.data,ibin.data,ibin.size); + /*enif_release_binary(env,&ibin);*/ + return enif_make_binary(env,&obin); + } + else { + return enif_make_badarg(env); + } +} + +static ERL_NIF_TERM make_sub_bin(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) +{ + int pos, size; + if (!enif_get_int(env,argv[1],&pos) || !enif_get_int(env,argv[2],&size)) { + return enif_make_badarg(env); + } + return enif_make_sub_binary(env,argv[0],pos,size); +} + +static ERL_NIF_TERM string_to_bin(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) +{ + ErlNifBinary obin; + unsigned size; + int n; + if (!enif_get_int(env,argv[1],(int*)&size) + || !enif_alloc_binary(env,size,&obin)) { + return enif_make_badarg(env); + } + n = enif_get_string(env, argv[0], (char*)obin.data, size, ERL_NIF_LATIN1); + return enif_make_tuple(env, 2, enif_make_int(env,n), + enif_make_binary(env,&obin)); +} + +static ERL_NIF_TERM atom_to_bin(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) +{ + ErlNifBinary obin; + unsigned size; + int n; + if (!enif_get_int(env,argv[1],(int*)&size) + || !enif_alloc_binary(env,size,&obin)) { + return enif_make_badarg(env); + } + n = enif_get_atom(env, argv[0], (char*)obin.data, size); + return enif_make_tuple(env, 2, enif_make_int(env,n), + enif_make_binary(env,&obin)); +} + +static ERL_NIF_TERM macros(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) +{ + const ERL_NIF_TERM* a; + ERL_NIF_TERM lists, tuples; + int arity; + if (!enif_get_tuple(env, argv[0], &arity, &a) || arity != 9) { + return enif_make_badarg(env); + } + + lists = enif_make_list(env,9, + enif_make_list1(env,a[0]), + enif_make_list2(env,a[0],a[1]), + enif_make_list3(env,a[0],a[1],a[2]), + enif_make_list4(env,a[0],a[1],a[2],a[3]), + enif_make_list5(env,a[0],a[1],a[2],a[3],a[4]), + enif_make_list6(env,a[0],a[1],a[2],a[3],a[4],a[5]), + enif_make_list7(env,a[0],a[1],a[2],a[3],a[4],a[5],a[6]), + enif_make_list8(env,a[0],a[1],a[2],a[3],a[4],a[5],a[6],a[7]), + enif_make_list9(env,a[0],a[1],a[2],a[3],a[4],a[5],a[6],a[7],a[8])); + tuples = enif_make_list(env,9, + enif_make_tuple1(env,a[0]), + enif_make_tuple2(env,a[0],a[1]), + enif_make_tuple3(env,a[0],a[1],a[2]), + enif_make_tuple4(env,a[0],a[1],a[2],a[3]), + enif_make_tuple5(env,a[0],a[1],a[2],a[3],a[4]), + enif_make_tuple6(env,a[0],a[1],a[2],a[3],a[4],a[5]), + enif_make_tuple7(env,a[0],a[1],a[2],a[3],a[4],a[5],a[6]), + enif_make_tuple8(env,a[0],a[1],a[2],a[3],a[4],a[5],a[6],a[7]), + enif_make_tuple9(env,a[0],a[1],a[2],a[3],a[4],a[5],a[6],a[7],a[8])); + return enif_make_tuple2(env,lists,tuples); +} + +static ERL_NIF_TERM tuple_2_list_and_tuple(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) +{ + const ERL_NIF_TERM* arr; + int arity; + if (!enif_get_tuple(env,argv[0],&arity,&arr)) { + return enif_make_badarg(env); + } + return enif_make_tuple2(env, + enif_make_list_from_array(env, arr, arity), + enif_make_tuple_from_array(env, arr, arity)); +} + +static ERL_NIF_TERM iolist_2_bin(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) +{ + ErlNifBinary obin; + if (!enif_inspect_iolist_as_binary(env, argv[0], &obin)) { + return enif_make_badarg(env); + } + return enif_make_binary(env,&obin); +} + +static ERL_NIF_TERM last_resource_dtor_call(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) +{ + ErlNifBinary bin; + ERL_NIF_TERM ret; + if (resource_dtor_last != NULL) { + enif_alloc_binary(env, resource_dtor_last_sz, &bin); + memcpy(bin.data, resource_dtor_last_data, resource_dtor_last_sz); + ret = enif_make_tuple3(env, + enif_make_long(env, (long)resource_dtor_last), + enif_make_binary(env, &bin), + enif_make_int(env, resource_dtor_cnt)); + } + else { + ret = enif_make_list(env,0); + } + resource_dtor_last = NULL; + resource_dtor_last_sz = 0; + resource_dtor_cnt = 0; + return ret; +} + +static ERL_NIF_TERM get_resource_type(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) +{ + PrivData* data = (PrivData*) enif_get_data(env); + int ix; + + if (!enif_get_int(env, argv[0], &ix) || ix >= 2) { + return enif_make_badarg(env); + } + return enif_make_long(env, data->rt_arr[ix].l); +} + +static ERL_NIF_TERM alloc_resource(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) +{ + ErlNifBinary data_bin; + union { ErlNifResourceType* t; long l;} type; + union { void* p; long l;} data; + if (!enif_get_long(env, argv[0], &type.l) + || !enif_inspect_binary(env, argv[1], &data_bin) + || (data.p = enif_alloc_resource(env, type.t, data_bin.size))==NULL) { + + return enif_make_badarg(env); + } + memcpy(data.p, data_bin.data, data_bin.size); + return enif_make_long(env, data.l); +} + +static ERL_NIF_TERM make_resource(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) +{ + union { void* p; long l; } data; + if (!enif_get_long(env, argv[0], &data.l)) { + return enif_make_badarg(env); + } + return enif_make_resource(env, data.p); +} + +static ERL_NIF_TERM make_new_resource(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) +{ + ErlNifBinary data_bin; + union { ErlNifResourceType* t; long l;} type; + void* data; + ERL_NIF_TERM ret; + if (!enif_get_long(env, argv[0], &type.l) + || !enif_inspect_binary(env, argv[1], &data_bin) + || (data = enif_alloc_resource(env, type.t, data_bin.size))==NULL) { + + return enif_make_badarg(env); + } + ret = enif_make_resource(env, data); + memcpy(data, data_bin.data, data_bin.size); + enif_release_resource(env, data); + return ret; +} + +static ERL_NIF_TERM get_resource(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) +{ + ErlNifBinary data_bin; + union { ErlNifResourceType* t; long l; } type; + union { void* p; long l; } data; + + if (!enif_get_long(env, argv[0], &type.l) + || !enif_get_resource(env, argv[1], type.t, &data.p)) { + return enif_make_badarg(env); + } + + enif_alloc_binary(env, enif_sizeof_resource(env,data.p), &data_bin); + memcpy(data_bin.data, data.p, data_bin.size); + return enif_make_tuple2(env, enif_make_long(env,data.l), + enif_make_binary(env, &data_bin)); +} + +static ERL_NIF_TERM release_resource(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) +{ + union { void* p; long l; } data; + if (!enif_get_long(env, argv[0], &data.l)) { + return enif_make_badarg(env); + } + enif_release_resource(env, data.p); + return enif_make_atom(env,"ok"); +} + + static ErlNifFunc nif_funcs[] = { {"lib_version", 0, lib_version}, {"call_history", 0, call_history}, {"hold_nif_mod_priv_data", 1, hold_nif_mod_priv_data}, {"nif_mod_call_history", 0, nif_mod_call_history}, - {"list_seq", 1, list_seq} + {"list_seq", 1, list_seq}, + {"type_test", 0, type_test}, + {"tuple_2_list", 1, tuple_2_list}, + {"is_identical",2,is_identical}, + {"compare",2,compare}, + {"many_args_100", 100, many_args_100}, + {"clone_bin", 1, clone_bin}, + {"make_sub_bin", 3, make_sub_bin}, + {"string_to_bin", 2, string_to_bin}, + {"atom_to_bin", 2, atom_to_bin}, + {"macros", 1, macros}, + {"tuple_2_list_and_tuple",1,tuple_2_list_and_tuple}, + {"iolist_2_bin", 1, iolist_2_bin}, + {"get_resource_type", 1, get_resource_type}, + {"alloc_resource", 2, alloc_resource}, + {"make_resource", 1, make_resource}, + {"get_resource", 2, get_resource}, + {"release_resource", 1, release_resource}, + {"last_resource_dtor_call", 0, last_resource_dtor_call}, + {"make_new_resource", 2, make_new_resource} + }; ERL_NIF_INIT(nif_SUITE,nif_funcs,load,reload,upgrade,unload) diff --git a/erts/emulator/test/nif_SUITE_data/nif_mod.c b/erts/emulator/test/nif_SUITE_data/nif_mod.c index 18f676335a..c075b74c57 100644 --- a/erts/emulator/test/nif_SUITE_data/nif_mod.c +++ b/erts/emulator/test/nif_SUITE_data/nif_mod.c @@ -1,51 +1,182 @@ #include "erl_nif.h" #include <string.h> -#include <assert.h> +#include <stdio.h> #include "nif_mod.h" +#define CHECK(X) ((void)((X) || (check_abort(__LINE__),1))) +#ifdef __GNUC__ +static void check_abort(unsigned line) __attribute__((noreturn)); +#endif +static void check_abort(unsigned line) +{ + enif_fprintf(stderr, "Test CHECK failed at %s:%u\r\n", + __FILE__, line); + abort(); +} static int static_cntA; /* zero by default */ static int static_cntB = NIF_LIB_VER * 100; -static void add_call(ErlNifEnv* env, NifModPrivData* data, const char* func_name) +static ERL_NIF_TERM am_true; +static ERL_NIF_TERM am_null; +static ERL_NIF_TERM am_resource_type; +static ERL_NIF_TERM am_resource_dtor_A; +static ERL_NIF_TERM am_resource_dtor_B; + +static void init(ErlNifEnv* env) +{ + am_true = enif_make_atom(env, "true"); + am_null = enif_make_atom(env, "null"); + am_resource_type = enif_make_atom(env, "resource_type"); + am_resource_dtor_A = enif_make_atom(env, "resource_dtor_A"); + am_resource_dtor_B = enif_make_atom(env, "resource_dtor_B"); +} + +static void add_call_with_arg(ErlNifEnv* env, NifModPrivData* data, const char* func_name, + const char* arg, int arg_sz) { - CallInfo* call = enif_alloc(env, sizeof(CallInfo)+strlen(func_name)); + CallInfo* call = enif_alloc(env, sizeof(CallInfo)+strlen(func_name) + arg_sz); strcpy(call->func_name, func_name); call->lib_ver = NIF_LIB_VER; call->static_cntA = ++static_cntA; call->static_cntB = ++static_cntB; + call->arg_sz = arg_sz; + if (arg != NULL) { + call->arg = call->func_name + strlen(func_name) + 1; + memcpy(call->arg, arg, arg_sz); + } + else { + call->arg = NULL; + } + enif_mutex_lock(data->mtx); call->next = data->call_history; data->call_history = call; + enif_mutex_unlock(data->mtx); +} + +static void add_call(ErlNifEnv* env, NifModPrivData* data,const char* func_name) +{ + add_call_with_arg(env, data, func_name, NULL, 0); +} + +#define ADD_CALL(FUNC_NAME) add_call(env, enif_priv_data(env),FUNC_NAME) + +#define STRINGIFY_(X) #X +#define STRINGIFY(X) STRINGIFY_(X) + +static void resource_dtor_A(ErlNifEnv* env, void* a) +{ + const char dtor_name[] = "resource_dtor_A_v" STRINGIFY(NIF_LIB_VER); + + add_call_with_arg(env, enif_priv_data(env), dtor_name, + a, enif_sizeof_resource(env, a)); +} + +static void resource_dtor_B(ErlNifEnv* env, void* a) +{ + const char dtor_name[] = "resource_dtor_B_v" STRINGIFY(NIF_LIB_VER); + + add_call_with_arg(env, enif_priv_data(env), dtor_name, + a, enif_sizeof_resource(env, a)); +} + +/* {resource_type, Ix|null, ErlNifResourceFlags in, "TypeName", dtor(A|B|null), ErlNifResourceFlags out}*/ +static void open_resource_type(ErlNifEnv* env, ERL_NIF_TERM op_tpl) +{ + NifModPrivData* data = enif_priv_data(env); + const ERL_NIF_TERM* arr; + int arity; + char rt_name[30]; + union { enum ErlNifResourceFlags e; int i; } flags, exp_res, got_res; + unsigned ix; + ErlNifResourceDtor* dtor; + ErlNifResourceType* got_ptr; + + CHECK(enif_get_tuple(env, op_tpl, &arity, &arr)); + CHECK(arity == 6); + CHECK(enif_is_identical(env, arr[0], am_resource_type)); + CHECK(enif_get_int(env, arr[2], &flags.i)); + CHECK(enif_get_string(env, arr[3], rt_name, sizeof(rt_name), ERL_NIF_LATIN1) > 0); + CHECK(enif_get_int(env, arr[5], &exp_res.i)); + + if (enif_is_identical(env, arr[4], am_null)) { + dtor = NULL; + } + else if (enif_is_identical(env, arr[4], am_resource_dtor_A)) { + dtor = resource_dtor_A; + } + else { + CHECK(enif_is_identical(env, arr[4], am_resource_dtor_B)); + dtor = resource_dtor_B; + } + + got_ptr = enif_open_resource_type(env, rt_name, dtor, + flags.e, &got_res.e); + + if (enif_get_uint(env, arr[1], &ix) && ix < RT_MAX && got_ptr != NULL) { + data->rt_arr[ix] = got_ptr; + } + else { + CHECK(enif_is_identical(env, arr[1], am_null)); + CHECK(got_ptr == NULL); + } + CHECK(got_res.e == exp_res.e); } -#define ADD_CALL(FUNC_NAME) add_call(env, enif_get_data(env),FUNC_NAME) +static void do_load_info(ErlNifEnv* env, ERL_NIF_TERM load_info) +{ + NifModPrivData* data = enif_priv_data(env); + ERL_NIF_TERM head, tail; + unsigned ix; + for (ix=0; ix<RT_MAX; ix++) { + data->rt_arr[ix] = NULL; + } + for (head = load_info; enif_get_list_cell(env, head, &head, &tail); + head = tail) { + + open_resource_type(env, head); + } + CHECK(enif_is_empty_list(env, head)); +} static int load(ErlNifEnv* env, void** priv_data, ERL_NIF_TERM load_info) { - NifModPrivData* data = enif_alloc(env, sizeof(NifModPrivData)); - assert(data != NULL); + NifModPrivData* data; + + init(env); + data = enif_alloc(env, sizeof(NifModPrivData)); + CHECK(data != NULL); + *priv_data = data; + data->mtx = enif_mutex_create("nif_mod_priv_data"); data->ref_cnt = 1; data->call_history = NULL; add_call(env, data, "load"); - data->calls = 0; - *priv_data = data; + do_load_info(env, load_info); + data->calls = 0; return 0; } static int reload(ErlNifEnv* env, void** priv_data, ERL_NIF_TERM load_info) { + init(env); add_call(env, *priv_data, "reload"); + + do_load_info(env, load_info); return 0; } static int upgrade(ErlNifEnv* env, void** priv_data, void** old_priv_data, ERL_NIF_TERM load_info) { NifModPrivData* data = *old_priv_data; + init(env); add_call(env, data, "upgrade"); data->ref_cnt++; + *priv_data = *old_priv_data; + do_load_info(env, load_info); + return 0; } @@ -53,46 +184,66 @@ static void unload(ErlNifEnv* env, void* priv_data) { NifModPrivData* data = priv_data; add_call(env, data, "unload"); + enif_mutex_lock(data->mtx); if (--data->ref_cnt == 0) { + enif_mutex_unlock(data->mtx); + enif_mutex_destroy(data->mtx); enif_free(env, data); } + enif_mutex_unlock(data->mtx); } -static ERL_NIF_TERM lib_version(ErlNifEnv* env) +static ERL_NIF_TERM lib_version(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) { ADD_CALL("lib_version"); return enif_make_int(env, NIF_LIB_VER); } -static ERL_NIF_TERM call_history(ErlNifEnv* env) +static ERL_NIF_TERM get_priv_data_ptr(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) { - NifModPrivData* data = (NifModPrivData*) enif_get_data(env); - ERL_NIF_TERM list = enif_make_list(env, 0); /* NIL */ + ADD_CALL("get_priv_data_ptr"); + return enif_make_ulong(env, (unsigned long)enif_priv_data(env)); +} - while (data->call_history != NULL) { - CallInfo* call = data->call_history; - ERL_NIF_TERM tpl = enif_make_tuple(env, 2, - enif_make_atom(env,call->func_name), - enif_make_int(env,call->lib_ver)); - list = enif_make_list_cell(env, tpl, list); - data->call_history = call->next; - enif_free(env,call); +static ERL_NIF_TERM make_new_resource(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) +{ + NifModPrivData* data = (NifModPrivData*) enif_priv_data(env); + ErlNifBinary ibin; + char* a; + ERL_NIF_TERM ret; + unsigned ix; + if (!enif_get_uint(env, argv[0], &ix) || ix >= RT_MAX + || !enif_inspect_binary(env, argv[1], &ibin)) { + return enif_make_badarg(env); } - return list; + a = enif_alloc_resource(env, data->rt_arr[ix], ibin.size); + memcpy(a, ibin.data, ibin.size); + ret = enif_make_resource(env, a); + enif_release_resource(env, a); + return ret; } -static ERL_NIF_TERM get_priv_data_ptr(ErlNifEnv* env) +static ERL_NIF_TERM get_resource(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) { - ADD_CALL("get_priv_data_ptr"); - return enif_make_ulong(env, (unsigned long)enif_get_data(env)); + NifModPrivData* data = (NifModPrivData*) enif_priv_data(env); + ErlNifBinary obin; + unsigned ix; + void* a; + if (!enif_get_uint(env, argv[0], &ix) || ix >= RT_MAX + || !enif_get_resource(env, argv[1], data->rt_arr[ix], &a) + || !enif_alloc_binary(env, enif_sizeof_resource(env, a), &obin)) { + return enif_make_badarg(env); + } + memcpy(obin.data, a, obin.size); + return enif_make_binary(env, &obin); } - static ErlNifFunc nif_funcs[] = { {"lib_version", 0, lib_version}, - {"call_history", 0, call_history}, - {"get_priv_data_ptr", 0, get_priv_data_ptr} + {"get_priv_data_ptr", 0, get_priv_data_ptr}, + {"make_new_resource", 2, make_new_resource}, + {"get_resource", 2, get_resource} }; #if NIF_LIB_VER != 3 diff --git a/erts/emulator/test/nif_SUITE_data/nif_mod.erl b/erts/emulator/test/nif_SUITE_data/nif_mod.erl index 93da6590a0..7888a589e7 100644 --- a/erts/emulator/test/nif_SUITE_data/nif_mod.erl +++ b/erts/emulator/test/nif_SUITE_data/nif_mod.erl @@ -21,15 +21,19 @@ -include("test_server.hrl"). --export([load_nif_lib/2, start/0, lib_version/0, call_history/0, get_priv_data_ptr/0]). +-export([load_nif_lib/2, load_nif_lib/3, start/0, lib_version/0, call_history/0, + get_priv_data_ptr/0, make_new_resource/2, get_resource/2]). -export([loop/0, upgrade/1]). -define(nif_stub,nif_stub_error(?LINE)). load_nif_lib(Config, Ver) -> + load_nif_lib(Config, Ver, []). + +load_nif_lib(Config, Ver, LoadInfo) -> ?line Path = ?config(data_dir, Config), - erlang:load_nif(filename:join(Path,libname(Ver)), 0). + erlang:load_nif(filename:join(Path,libname(Ver)), LoadInfo). libname(no_init) -> libname(3); libname(Ver) when is_integer(Ver) -> @@ -59,6 +63,8 @@ lib_version() -> % NIF call_history() -> ?nif_stub. get_priv_data_ptr() -> ?nif_stub. +make_new_resource(_,_) -> ?nif_stub. +get_resource(_,_) -> ?nif_stub. nif_stub_error(Line) -> exit({nif_not_loaded,module,?MODULE,line,Line}). diff --git a/erts/emulator/test/nif_SUITE_data/nif_mod.h b/erts/emulator/test/nif_SUITE_data/nif_mod.h index 2dfdc75176..0eaf91d6e1 100644 --- a/erts/emulator/test/nif_SUITE_data/nif_mod.h +++ b/erts/emulator/test/nif_SUITE_data/nif_mod.h @@ -4,14 +4,19 @@ typedef struct call_info_t unsigned lib_ver; int static_cntA; int static_cntB; + char* arg; + int arg_sz; char func_name[1]; /* must be last */ }CallInfo; +#define RT_MAX 5 typedef struct { + ErlNifMutex* mtx; int calls; int ref_cnt; CallInfo* call_history; + ErlNifResourceType* rt_arr[RT_MAX]; }NifModPrivData; diff --git a/erts/emulator/test/nif_SUITE_data/tail.txt b/erts/emulator/test/nif_SUITE_data/tail.txt new file mode 100644 index 0000000000..7f06c118c1 --- /dev/null +++ b/erts/emulator/test/nif_SUITE_data/tail.txt @@ -0,0 +1,5 @@ + + +#include "tester.c" /* poor mans linker */ + + diff --git a/erts/emulator/test/nif_SUITE_data/testcase_driver.h b/erts/emulator/test/nif_SUITE_data/testcase_driver.h new file mode 100644 index 0000000000..98339e4746 --- /dev/null +++ b/erts/emulator/test/nif_SUITE_data/testcase_driver.h @@ -0,0 +1,59 @@ +/* ``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 via the world wide web 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. + * + * The Initial Developer of the Original Code is Ericsson Utvecklings AB. + * Portions created by Ericsson are Copyright 1999, Ericsson Utvecklings + * AB. All Rights Reserved.'' + * + * $Id$ + */ + +#ifndef TESTCASE_DRIVER_H__ +#define TESTCASE_DRIVER_H__ + +#include "erl_nif.h" +#include <stdlib.h> +#include <stdio.h> + +typedef struct { + char *testcase_name; + char *command; + int command_len; + void *extra; +} TestCaseState_t; + +#define ASSERT_CLNUP(TCS, B, CLN) \ +do { \ + if (!(B)) { \ + CLN; \ + testcase_assertion_failed((TCS), __FILE__, __LINE__, #B); \ + } \ +} while (0) + +#define ASSERT(TCS, B) ASSERT_CLNUP(TCS, B, (void) 0) + + +void testcase_printf(TestCaseState_t *tcs, char *frmt, ...); +void testcase_succeeded(TestCaseState_t *tcs, char *frmt, ...); +void testcase_skipped(TestCaseState_t *tcs, char *frmt, ...); +void testcase_failed(TestCaseState_t *tcs, char *frmt, ...); +int testcase_assertion_failed(TestCaseState_t *tcs, char *file, int line, + char *assertion); +void *testcase_alloc(size_t size); +void *testcase_realloc(void *ptr, size_t size); +void testcase_free(void *ptr); + + +char *testcase_name(void); +void testcase_run(TestCaseState_t *tcs); +void testcase_cleanup(TestCaseState_t *tcs); + +#endif diff --git a/erts/emulator/test/nif_SUITE_data/tester.c b/erts/emulator/test/nif_SUITE_data/tester.c new file mode 100644 index 0000000000..08466d0f18 --- /dev/null +++ b/erts/emulator/test/nif_SUITE_data/tester.c @@ -0,0 +1,73 @@ +#include "erl_nif.h" + +#include <stdio.h> +#include <stdarg.h> + +void testcase_printf(TestCaseState_t *tcs, char *frmt, ...) +{ + va_list va; + va_start(va, frmt); + vfprintf(stderr, frmt, va); + va_end(va); + fprintf(stderr, "\r"); +} + +void testcase_succeeded(TestCaseState_t *tcs, char *frmt, ...) +{ +} + +void testcase_skipped(TestCaseState_t *tcs, char *frmt, ...) +{ +} + +void testcase_failed(TestCaseState_t *tcs, char *frmt, ...) +{ + va_list va; + va_start(va, frmt); + vfprintf(stderr, frmt, va); + va_end(va); + abort(); +} + +int testcase_assertion_failed(TestCaseState_t *tcs, char *file, int line, + char *assertion) +{ + testcase_failed(tcs, "ASSERTION '%s' FAILED at %s:%d\r\n", + assertion, file, line); + abort(); + return 0; /*?*/ +} + +void *testcase_alloc(size_t size) +{ + return malloc(size); +} +void *testcase_realloc(void *ptr, size_t size) +{ + return realloc(ptr, size); +} +void testcase_free(void *ptr) +{ + free(ptr); +} + +void testcase_run(TestCaseState_t *tcs); + +static int reload(ErlNifEnv* env, void** priv_data, ERL_NIF_TERM load_info) +{ + return 0; +} + +static ERL_NIF_TERM run(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) +{ + testcase_run(NULL); + return enif_make_atom(env, "ok"); +} + +static ErlNifFunc nif_funcs[] = +{ + {"run", 0, run} +}; + +ERL_NIF_INIT(tester,nif_funcs,NULL,reload,NULL,NULL) + diff --git a/erts/emulator/test/nif_SUITE_data/tester.erl b/erts/emulator/test/nif_SUITE_data/tester.erl new file mode 100644 index 0000000000..9df2158200 --- /dev/null +++ b/erts/emulator/test/nif_SUITE_data/tester.erl @@ -0,0 +1,13 @@ +-module(tester). + +-include("test_server.hrl"). + +-export([load_nif_lib/2, run/0]). + + +load_nif_lib(Config, LibName) -> + ?line Path = ?config(data_dir, Config), + erlang:load_nif(filename:join(Path,LibName), []). + +run() -> + exit({nif_not_loaded,?MODULE,?LINE}). diff --git a/erts/emulator/test/process_SUITE.erl b/erts/emulator/test/process_SUITE.erl index fdedf30e78..77f850d0fb 100644 --- a/erts/emulator/test/process_SUITE.erl +++ b/erts/emulator/test/process_SUITE.erl @@ -1,19 +1,19 @@ %% %% %CopyrightBegin% -%% -%% Copyright Ericsson AB 1997-2009. All Rights Reserved. -%% +%% +%% Copyright Ericsson AB 1997-2010. 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% %% @@ -41,7 +41,8 @@ bump_reductions/1, low_prio/1, binary_owner/1, yield/1, yield2/1, process_status_exiting/1, otp_4725/1, bad_register/1, garbage_collect/1, otp_6237/1, - process_info_messages/1, process_flag_badarg/1, + process_info_messages/1, process_flag_badarg/1, process_flag_heap_size/1, + spawn_opt_heap_size/1, processes_large_tab/1, processes_default_tab/1, processes_small_tab/1, processes_this_tab/1, processes_apply_trap/1, processes_last_call_trap/1, processes_gc_trap/1, @@ -63,9 +64,8 @@ all(suite) -> process_info_lock_reschedule, process_info_lock_reschedule2, process_status_exiting, bump_reductions, low_prio, yield, yield2, otp_4725, bad_register, - garbage_collect, process_info_messages, process_flag_badarg, otp_6237, - processes_bif, - otp_7738]. + garbage_collect, process_info_messages, process_flag_badarg, process_flag_heap_size, + spawn_opt_heap_size, otp_6237, processes_bif, otp_7738]. init_per_testcase(Func, Config) when is_atom(Func), is_list(Config) -> Dog=?t:timetrap(?t:minutes(10)), @@ -388,6 +388,8 @@ t_process_info(Config) when is_list(Config) -> ?line register(my_name, self()), ?line {registered_name, my_name} = process_info(self(), registered_name), ?line {status, running} = process_info(self(), status), + ?line {min_heap_size, 233} = process_info(self(), min_heap_size), + ?line {min_bin_vheap_size, 46368} = process_info(self(), min_bin_vheap_size), ?line {current_function, {?MODULE, t_process_info, 1}} = process_info(self(), current_function), ?line Gleader = group_leader(), @@ -437,6 +439,10 @@ process_info_other_msg(Config) when is_list(Config) -> empty -> ok end, ?line {messages,[]} = process_info(Pid, messages), + + ?line {min_heap_size, 233} = process_info(Pid, min_heap_size), + ?line {min_bin_vheap_size, 46368} = process_info(Pid, min_bin_vheap_size), + ?line Pid ! stop, ok. @@ -1148,6 +1154,8 @@ process_flag_badarg(Config) when is_list(Config) -> ?line chk_badarg(fun () -> process_flag(trap_exit, gurka) end), ?line chk_badarg(fun () -> process_flag(error_handler, 1) end), ?line chk_badarg(fun () -> process_flag(min_heap_size, gurka) end), + ?line chk_badarg(fun () -> process_flag(min_bin_vheap_size, gurka) end), + ?line chk_badarg(fun () -> process_flag(min_bin_vheap_size, -1) end), ?line chk_badarg(fun () -> process_flag(priority, 4711) end), ?line chk_badarg(fun () -> process_flag(save_calls, hmmm) end), ?line P= spawn_link(fun () -> receive die -> ok end end), @@ -1774,6 +1782,34 @@ processes_gc_trap(Config) when is_list(Config) -> ?line exit(Suspendee, bang), ?line ok. +process_flag_heap_size(doc) -> + []; +process_flag_heap_size(suite) -> + []; +process_flag_heap_size(Config) when is_list(Config) -> + HSize = 2584, % must be gc fib number + VHSize = 317811, % must be gc fib number + ?line OldHmin = erlang:process_flag(min_heap_size, HSize), + ?line {min_heap_size, HSize} = erlang:process_info(self(), min_heap_size), + ?line OldVHmin = erlang:process_flag(min_bin_vheap_size, VHSize), + ?line {min_bin_vheap_size, VHSize} = erlang:process_info(self(), min_bin_vheap_size), + ?line HSize = erlang:process_flag(min_heap_size, OldHmin), + ?line VHSize = erlang:process_flag(min_bin_vheap_size, OldVHmin), + ?line ok. + +spawn_opt_heap_size(doc) -> + []; +spawn_opt_heap_size(suite) -> + []; +spawn_opt_heap_size(Config) when is_list(Config) -> + HSize = 987, % must be gc fib number + VHSize = 46368, % must be gc fib number + ?line Pid = spawn_opt(fun () -> receive stop -> ok end end, + [{min_heap_size, HSize},{ min_bin_vheap_size, VHSize}]), + ?line {min_heap_size, HSize} = process_info(Pid, min_heap_size), + ?line {min_bin_vheap_size, VHSize} = process_info(Pid, min_bin_vheap_size), + ?line Pid ! stop, + ?line ok. processes_term_proc_list(doc) -> []; diff --git a/erts/emulator/test/scheduler_SUITE.erl b/erts/emulator/test/scheduler_SUITE.erl index e644ad4dc8..c9101b77c2 100644 --- a/erts/emulator/test/scheduler_SUITE.erl +++ b/erts/emulator/test/scheduler_SUITE.erl @@ -1,19 +1,19 @@ %% %% %CopyrightBegin% -%% -%% Copyright Ericsson AB 2008-2009. All Rights Reserved. -%% +%% +%% Copyright Ericsson AB 2008-2010. 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% %% @@ -48,7 +48,8 @@ scheduler_bind_types/1, cpu_topology/1, sct_cmd/1, - sbt_cmd/1]). + sbt_cmd/1, + scheduler_suspend/1]). -define(DEFAULT_TIMEOUT, ?t:minutes(10)). @@ -65,7 +66,8 @@ all(suite) -> equal_with_high, equal_with_high_max, bound_process, - scheduler_bind]. + scheduler_bind, + scheduler_suspend]. init_per_testcase(Case, Config) when is_list(Config) -> Dog = ?t:timetrap(?DEFAULT_TIMEOUT), @@ -882,11 +884,103 @@ sbt_test(Config, CpuTCmd, ClBt, Bt, LP) -> ?line stop_node(Node), ?line ok. +scheduler_suspend(Config) when is_list(Config) -> + ?line Dog = ?t:timetrap(?t:minutes(2)), + ?line lists:foreach(fun (S) -> scheduler_suspend_test(Config, S) end, + [64, 32, 16, default]), + ?line ?t:timetrap_cancel(Dog), + ?line ok. +scheduler_suspend_test(Config, Schedulers) -> + ?line Cmd = case Schedulers of + default -> + ""; + _ -> + S = integer_to_list(Schedulers), + "+S"++S++":"++S + end, + ?line {ok, Node} = start_node(Config, Cmd), + ?line [SState] = mcall(Node, [fun () -> + erlang:system_info(schedulers_state) + end]), + ?line {Sched, _, _} = SState, + ?line true = is_integer(Sched), + ?line [ok] = mcall(Node, [fun () -> sst0_loop(300) end]), + ?line [ok] = mcall(Node, [fun () -> sst1_loop(300) end]), + ?line [ok] = mcall(Node, [fun () -> sst2_loop(300) end]), + ?line [ok, ok, ok, ok, ok] = mcall(Node, + [fun () -> sst0_loop(200) end, + fun () -> sst1_loop(200) end, + fun () -> sst2_loop(200) end, + fun () -> sst2_loop(200) end, + fun () -> sst3_loop(Sched, 200) end]), + ?line [SState] = mcall(Node, [fun () -> + erlang:system_info(schedulers_state) + end]), + ?line stop_node(Node), + ?line ok. + + +sst0_loop(0) -> + ok; +sst0_loop(N) -> + erlang:system_flag(multi_scheduling, block), + erlang:system_flag(multi_scheduling, unblock), + erlang:yield(), + sst0_loop(N-1). + +sst1_loop(0) -> + ok; +sst1_loop(N) -> + erlang:system_flag(multi_scheduling, block), + erlang:system_flag(multi_scheduling, unblock), + sst1_loop(N-1). + +sst2_loop(0) -> + ok; +sst2_loop(N) -> + erlang:system_flag(multi_scheduling, block), + erlang:system_flag(multi_scheduling, block), + erlang:system_flag(multi_scheduling, block), + erlang:system_flag(multi_scheduling, unblock), + erlang:system_flag(multi_scheduling, unblock), + erlang:system_flag(multi_scheduling, unblock), + sst2_loop(N-1). + +sst3_loop(_S, 0) -> + ok; +sst3_loop(S, N) -> + erlang:system_flag(schedulers_online, (S div 2)+1), + erlang:system_flag(schedulers_online, 1), + erlang:system_flag(schedulers_online, (S div 2)+1), + erlang:system_flag(schedulers_online, S), + erlang:system_flag(schedulers_online, 1), + erlang:system_flag(schedulers_online, S), + sst3_loop(S, N-1). + -% +%% %% Utils %% +mcall(Node, Funs) -> + Parent = self(), + Refs = lists:map(fun (Fun) -> + Ref = make_ref(), + spawn_link(Node, + fun () -> + Res = Fun(), + unlink(Parent), + Parent ! {Ref, Res} + end), + Ref + end, Funs), + lists:map(fun (Ref) -> + receive + {Ref, Res} -> + Res + end + end, Refs). + erl_rel_flag_var() -> "ERL_"++erlang:system_info(otp_release)++"_FLAGS". diff --git a/erts/emulator/test/statistics_SUITE.erl b/erts/emulator/test/statistics_SUITE.erl index bc12821887..898908c40f 100644 --- a/erts/emulator/test/statistics_SUITE.erl +++ b/erts/emulator/test/statistics_SUITE.erl @@ -1,19 +1,19 @@ %% %% %CopyrightBegin% -%% -%% Copyright Ericsson AB 1997-2009. All Rights Reserved. -%% +%% +%% Copyright Ericsson AB 1997-2010. 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% %% @@ -25,7 +25,7 @@ init_per_testcase/2, fin_per_testcase/2, wall_clock/1, wall_clock_zero_diff/1, wall_clock_update/1, - runtime/1, runtime_zero_diff/1, runtime_zero_update/1, + runtime/1, runtime_zero_diff/1, runtime_update/1, runtime_diff/1, run_queue/1, run_queue_one/1, reductions/1, reductions_big/1, garbage_collection/1, io/1, @@ -99,8 +99,7 @@ wall_clock_update1(0) -> %%% Test statistics(runtime). -runtime(suite) -> [runtime_zero_diff, runtime_zero_update, runtime_update, - runtime_diff]. +runtime(suite) -> [runtime_zero_diff, runtime_update, runtime_diff]. runtime_zero_diff(doc) -> "Tests that the difference between the times returned from two consectuitive " @@ -117,55 +116,32 @@ runtime_zero_diff1(N) when N > 0 -> runtime_zero_diff1(0) -> ?line test_server:fail("statistics(runtime) never returned zero difference"). -runtime_zero_update(doc) -> - "Test that the time differences returned by two calls to " - "statistics(runtime) several seconds apart is zero."; -runtime_zero_update(Config) when is_list(Config) -> - case ?t:is_debug() of - false -> ?line runtime_zero_update1(6); - true -> {skip,"Unreliable in DEBUG build"} - end. - -runtime_zero_update1(N) when N > 0 -> - ?line {T1, _} = statistics(runtime), - ?line receive after 7000 -> ok end, - ?line case statistics(runtime) of - {T, Td} when Td =< 80 -> - test_server:format("ok, Runtime before: {~p, _} after: {~p, ~p}", - [T1, T, Td]), - ok; - {T, R} -> - test_server:format("nok, Runtime before: {~p, _} after: {~p, ~p}", - [T1, T, R]), - runtime_zero_update1(N-1) - end; -runtime_zero_update1(0) -> - ?line test_server:fail("statistics(runtime) never returned zero difference"). - runtime_update(doc) -> - "Test that the statistics(runtime) returns a substanstially updated difference " - "after running a process that takes all CPU power of the Erlang process " - "for a second."; + "Test that the statistics(runtime) returns a substanstially " + "updated difference after running a process that takes all CPU " + " power of the Erlang process for a second."; runtime_update(Config) when is_list(Config) -> case ?t:is_cover() of false -> ?line process_flag(priority, high), - ?line test_server:m_out_of_n(1, 10, fun runtime_update/0); + do_runtime_update(10); true -> {skip,"Cover-compiled"} end. -runtime_update() -> - ?line {T1,_} = statistics(runtime), +do_runtime_update(0) -> + {comment,"Never close enough"}; +do_runtime_update(N) -> + ?line {T1,Diff0} = statistics(runtime), ?line spawn_link(fun cpu_heavy/0), receive after 1000 -> ok end, ?line {T2,Diff} = statistics(runtime), - ?line Delta = abs(Diff-1000), - ?line test_server:format("T1 = ~p, T2 = ~p, Diff = ~p, abs(Diff-1000) = ~p", - [T1,T2,Diff,Delta]), + ?line true = is_integer(T1+T2+Diff0+Diff), + ?line test_server:format("T1 = ~p, T2 = ~p, Diff = ~p, T2-T1 = ~p", + [T1,T2,Diff,T2-T1]), ?line if - abs(Diff-1000) =:= Delta, Delta =< 100 -> - ok + T2 - T1 =:= Diff, 900 =< Diff, Diff =< 1500 -> ok; + true -> do_runtime_update(N-1) end. cpu_heavy() -> @@ -212,17 +188,18 @@ reductions(Config) when is_list(Config) -> %% 300 * 4 is more than CONTEXT_REDS (1000). Thus, there will be one or %% more context switches. - reductions(300, Reductions). + Mask = (1 bsl erlang:system_info(wordsize)*8) - 1, + reductions(300, Reductions, Mask). -reductions(N, Previous) when N > 0 -> +reductions(N, Previous, Mask) when N > 0 -> ?line {Reductions, Diff} = statistics(reductions), ?line build_some_garbage(), ?line if Reductions > 0 -> ok end, ?line if Diff >= 0 -> ok end, io:format("Previous = ~p, Reductions = ~p, Diff = ~p, DiffShouldBe = ~p", - [Previous, Reductions, Diff, Reductions-Previous]), - ?line if Reductions == Previous+Diff -> reductions(N-1, Reductions) end; -reductions(0, _) -> + [Previous, Reductions, Diff, (Reductions-Previous) band Mask]), + ?line if Reductions == ((Previous+Diff) band Mask) -> reductions(N-1, Reductions, Mask) end; +reductions(0, _, _) -> ok. build_some_garbage() -> diff --git a/erts/emulator/test/system_info_SUITE.erl b/erts/emulator/test/system_info_SUITE.erl index 2c7124839a..e782d2f293 100644 --- a/erts/emulator/test/system_info_SUITE.erl +++ b/erts/emulator/test/system_info_SUITE.erl @@ -1,19 +1,19 @@ %% %% %CopyrightBegin% -%% -%% Copyright Ericsson AB 2005-2009. All Rights Reserved. -%% +%% +%% Copyright Ericsson AB 2005-2010. 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% %% @@ -35,12 +35,12 @@ %-compile(export_all). -export([all/1, init_per_testcase/2, fin_per_testcase/2]). --export([process_count/1, system_version/1, misc_smoke_tests/1]). +-export([process_count/1, system_version/1, misc_smoke_tests/1, heap_size/1]). -define(DEFAULT_TIMEOUT, ?t:minutes(2)). all(doc) -> []; -all(suite) -> [process_count, system_version, misc_smoke_tests]. +all(suite) -> [process_count, system_version, misc_smoke_tests, heap_size]. init_per_testcase(_Case, Config) when is_list(Config) -> Dog = ?t:timetrap(?DEFAULT_TIMEOUT), @@ -135,8 +135,13 @@ misc_smoke_tests(Config) when is_list(Config) -> ?line ok. - - - - +heap_size(doc) -> []; +heap_size(suite) -> []; +heap_size(Config) when is_list(Config) -> + ?line {min_bin_vheap_size, VHmin} = erlang:system_info(min_bin_vheap_size), + ?line {min_heap_size, Hmin} = erlang:system_info(min_heap_size), + ?line GCinf = erlang:system_info(garbage_collection), + ?line VHmin = proplists:get_value(min_bin_vheap_size, GCinf), + ?line Hmin = proplists:get_value(min_heap_size, GCinf), + ok. diff --git a/erts/emulator/test/trace_SUITE.erl b/erts/emulator/test/trace_SUITE.erl index 2c60ba6838..e9713fcf0f 100644 --- a/erts/emulator/test/trace_SUITE.erl +++ b/erts/emulator/test/trace_SUITE.erl @@ -1,19 +1,19 @@ %% %% %CopyrightBegin% -%% -%% Copyright Ericsson AB 1997-2009. All Rights Reserved. -%% +%% +%% Copyright Ericsson AB 1997-2010. 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% %% @@ -498,19 +498,23 @@ system_monitor_long_gc_1(doc) -> ["Tests erlang:system_monitor(Pid, [{long_gc,Time}])"]; system_monitor_long_gc_1(Config) when is_list(Config) -> erts_debug:set_internal_state(available_internal_state, true), - try - %% Add ?LONG_GC_SLEEP ms to all gc - ?line erts_debug:set_internal_state(test_long_gc_sleep, - ?LONG_GC_SLEEP), - ?line LoadFun = - fun () -> - garbage_collect(), - self() - end, - ?line long_gc(LoadFun, false) + try + case erts_debug:get_internal_state(force_heap_frags) of + true -> + {skip,"emulator with FORCE_HEAP_FRAGS defined"}; + false -> + %% Add ?LONG_GC_SLEEP ms to all gc + ?line erts_debug:set_internal_state(test_long_gc_sleep, + ?LONG_GC_SLEEP), + ?line LoadFun = fun () -> + garbage_collect(), + self() + end, + ?line long_gc(LoadFun, false) + end after erts_debug:set_internal_state(test_long_gc_sleep, 0), - erts_debug:set_internal_state(available_internal_state, false) + erts_debug:set_internal_state(available_internal_state, false) end. system_monitor_long_gc_2(suite) -> @@ -520,24 +524,29 @@ system_monitor_long_gc_2(doc) -> system_monitor_long_gc_2(Config) when is_list(Config) -> erts_debug:set_internal_state(available_internal_state, true), try - %% Add ?LONG_GC_SLEEP ms to all gc - ?line erts_debug:set_internal_state(test_long_gc_sleep, - ?LONG_GC_SLEEP), - ?line Parent = self(), - ?line LoadFun = - fun () -> - Ref = make_ref(), - Pid = - spawn_link( - fun () -> - garbage_collect(), - Parent ! {Ref, self()} - end), - receive {Ref, Pid} -> Pid end - end, - ?line long_gc(LoadFun, true), - ?line long_gc(LoadFun, true), - ?line long_gc(LoadFun, true) + case erts_debug:get_internal_state(force_heap_frags) of + true -> + {skip,"emulator with FORCE_HEAP_FRAGS defined"}; + false -> + %% Add ?LONG_GC_SLEEP ms to all gc + ?line erts_debug:set_internal_state(test_long_gc_sleep, + ?LONG_GC_SLEEP), + ?line Parent = self(), + ?line LoadFun = + fun () -> + Ref = make_ref(), + Pid = + spawn_link( + fun () -> + garbage_collect(), + Parent ! {Ref, self()} + end), + receive {Ref, Pid} -> Pid end + end, + ?line long_gc(LoadFun, true), + ?line long_gc(LoadFun, true), + ?line long_gc(LoadFun, true) + end after erts_debug:set_internal_state(test_long_gc_sleep, 0), erts_debug:set_internal_state(available_internal_state, false) diff --git a/erts/emulator/test/trace_nif_SUITE_data/trace_nif.c b/erts/emulator/test/trace_nif_SUITE_data/trace_nif.c index 732f1010ae..26f2420b8b 100644 --- a/erts/emulator/test/trace_nif_SUITE_data/trace_nif.c +++ b/erts/emulator/test/trace_nif_SUITE_data/trace_nif.c @@ -20,18 +20,18 @@ static void unload(ErlNifEnv* env, void* priv_data) { } -static ERL_NIF_TERM nif_0(ErlNifEnv* env) +static ERL_NIF_TERM nif_0(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) { return enif_make_tuple(env,2, enif_make_atom(env,"ok"), enif_make_list(env,0)); } -static ERL_NIF_TERM nif_1(ErlNifEnv* env, ERL_NIF_TERM a1) +static ERL_NIF_TERM nif_1(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) { return enif_make_tuple(env,2, enif_make_atom(env,"ok"), - enif_make_list(env,1,a1)); + enif_make_list(env,1,argv[0])); } diff --git a/erts/emulator/utils/beam_makeops b/erts/emulator/utils/beam_makeops index 2b7e8a6dde..4a859c3094 100755 --- a/erts/emulator/utils/beam_makeops +++ b/erts/emulator/utils/beam_makeops @@ -753,8 +753,8 @@ sub comment { print "$prefix$line\n"; } } else { - print "$prefix Warning: Do not edit this file. It was automatically\n"; - print "$prefix generated by '$prog' on ", (scalar localtime), ".\n"; + print "$prefix Warning: Do not edit this file.\n"; + print "$prefix Auto-generated by '$prog'.\n"; } if ($lang eq 'C') { print " */\n"; diff --git a/erts/emulator/zlib/Makefile.in b/erts/emulator/zlib/Makefile.in index 5c99b460c1..b44a87551d 100644 --- a/erts/emulator/zlib/Makefile.in +++ b/erts/emulator/zlib/Makefile.in @@ -14,12 +14,7 @@ # make install prefix=$HOME ARFLAGS = rc -ifeq ($(findstring ose,$(TARGET)),ose) - TYPE_FLAGS = -else - TYPE_FLAGS = -O3 -endif -CFLAGS = @CFLAGS@ @DEFS@ @EMU_THR_DEFS@ $(TYPE_FLAGS) +CFLAGS = $(subst -O2, -O3, @CFLAGS@ @DEFS@ @EMU_THR_DEFS@) #CFLAGS=-O -DMAX_WBITS=14 -DMAX_MEM_LEVEL=7 #CFLAGS=-g -DDEBUG #CFLAGS=-O3 -Wall -Wwrite-strings -Wpointer-arith -Wconversion \ @@ -36,24 +31,15 @@ OBJS = $(O:%=$(OBJDIR)/%) include $(ERL_TOP)/make/target.mk -# On windows we need a separate zlib during debug build -ifeq ($(TARGET),win32) - -ifeq ($(TYPE),debug) -CFLAGS = $(subst -O2, -g, @CFLAGS@ @DEFS@ @DEBUG_FLAGS@) -endif # debug - -else # win32 - ifeq ($(TYPE),gcov) -CFLAGS = $(subst -O2, -g, -O0 -fprofile-arcs -ftest-coverage @CFLAGS@ @DEFS@ @DEBUG_FLAGS@) -TYPE_FLAGS= +CFLAGS = -O0 -fprofile-arcs -ftest-coverage @DEBUG_CFLAGS@ @DEFS@ @EMU_THR_DEFS@ else # gcov -# On other platforms we use no special debug version of zlib +ifeq ($(TYPE),debug) +CFLAGS = @DEBUG_CFLAGS@ @DEFS@ @EMU_THR_DEFS@ +endif # debug endif # gcov -endif # win32 - +# On windows we *need* a separate zlib during debug build OBJDIR= $(ERL_TOP)/erts/emulator/zlib/obj/$(TARGET)/$(TYPE) include $(ERL_TOP)/make/$(TARGET)/otp.mk |