aboutsummaryrefslogtreecommitdiffstats
path: root/erts/emulator
diff options
context:
space:
mode:
Diffstat (limited to 'erts/emulator')
-rw-r--r--erts/emulator/Makefile.in37
-rw-r--r--erts/emulator/beam/atom.c12
-rw-r--r--erts/emulator/beam/atom.h21
-rw-r--r--erts/emulator/beam/atom.names12
-rw-r--r--erts/emulator/beam/beam_bif_load.c31
-rw-r--r--erts/emulator/beam/beam_emu.c133
-rw-r--r--erts/emulator/beam/beam_load.c1
-rw-r--r--erts/emulator/beam/bif.c81
-rw-r--r--erts/emulator/beam/bif.tab15
-rw-r--r--erts/emulator/beam/binary.c18
-rw-r--r--erts/emulator/beam/break.c2
-rw-r--r--erts/emulator/beam/erl_arith.c43
-rw-r--r--erts/emulator/beam/erl_bif_guard.c14
-rw-r--r--erts/emulator/beam/erl_bif_info.c183
-rw-r--r--erts/emulator/beam/erl_bif_re.c15
-rw-r--r--erts/emulator/beam/erl_binary.h35
-rw-r--r--erts/emulator/beam/erl_db.c23
-rw-r--r--erts/emulator/beam/erl_db_hash.c16
-rw-r--r--erts/emulator/beam/erl_db_tree.c14
-rw-r--r--erts/emulator/beam/erl_debug.c14
-rw-r--r--erts/emulator/beam/erl_driver.h33
-rw-r--r--erts/emulator/beam/erl_drv_nif.h48
-rw-r--r--erts/emulator/beam/erl_gc.c252
-rw-r--r--erts/emulator/beam/erl_init.c155
-rw-r--r--erts/emulator/beam/erl_lock_check.c13
-rw-r--r--erts/emulator/beam/erl_lock_count.c68
-rw-r--r--erts/emulator/beam/erl_lock_count.h25
-rw-r--r--erts/emulator/beam/erl_message.c24
-rw-r--r--erts/emulator/beam/erl_message.h23
-rw-r--r--erts/emulator/beam/erl_nif.c901
-rw-r--r--erts/emulator/beam/erl_nif.h58
-rw-r--r--erts/emulator/beam/erl_nif_api_funcs.h173
-rw-r--r--erts/emulator/beam/erl_port_task.c70
-rw-r--r--erts/emulator/beam/erl_process.c109
-rw-r--r--erts/emulator/beam/erl_process.h43
-rw-r--r--erts/emulator/beam/erl_term.h108
-rw-r--r--erts/emulator/beam/erl_time_sup.c14
-rw-r--r--erts/emulator/beam/erl_trace.c29
-rw-r--r--erts/emulator/beam/erl_vm.h80
-rw-r--r--erts/emulator/beam/external.c284
-rw-r--r--erts/emulator/beam/external.h26
-rw-r--r--erts/emulator/beam/global.h102
-rw-r--r--erts/emulator/beam/io.c24
-rw-r--r--erts/emulator/beam/module.c18
-rw-r--r--erts/emulator/beam/module.h19
-rw-r--r--erts/emulator/beam/sys.h5
-rw-r--r--erts/emulator/beam/utils.c88
-rw-r--r--erts/emulator/drivers/common/inet_drv.c4
-rw-r--r--erts/emulator/drivers/unix/ttsl_drv.c17
-rw-r--r--erts/emulator/hipe/hipe_amd64_asm.m433
-rw-r--r--erts/emulator/hipe/hipe_amd64_bifs.m4226
-rw-r--r--erts/emulator/hipe/hipe_amd64_glue.S116
-rw-r--r--erts/emulator/hipe/hipe_bif0.c125
-rw-r--r--erts/emulator/pcre/pcre_compile.c21
-rw-r--r--erts/emulator/sys/common/erl_poll.c17
-rw-r--r--erts/emulator/sys/unix/sys.c17
-rw-r--r--erts/emulator/sys/unix/sys_float.c13
-rw-r--r--erts/emulator/test/binary_SUITE.erl46
-rw-r--r--erts/emulator/test/fun_SUITE.erl18
-rw-r--r--erts/emulator/test/nif_SUITE.erl665
-rw-r--r--erts/emulator/test/nif_SUITE_data/Makefile.src13
-rw-r--r--erts/emulator/test/nif_SUITE_data/head.txt5
-rw-r--r--erts/emulator/test/nif_SUITE_data/nif_SUITE.c533
-rw-r--r--erts/emulator/test/nif_SUITE_data/nif_mod.c205
-rw-r--r--erts/emulator/test/nif_SUITE_data/nif_mod.erl10
-rw-r--r--erts/emulator/test/nif_SUITE_data/nif_mod.h5
-rw-r--r--erts/emulator/test/nif_SUITE_data/tail.txt5
-rw-r--r--erts/emulator/test/nif_SUITE_data/testcase_driver.h59
-rw-r--r--erts/emulator/test/nif_SUITE_data/tester.c73
-rw-r--r--erts/emulator/test/nif_SUITE_data/tester.erl13
-rw-r--r--erts/emulator/test/process_SUITE.erl54
-rw-r--r--erts/emulator/test/scheduler_SUITE.erl110
-rw-r--r--erts/emulator/test/statistics_SUITE.erl75
-rw-r--r--erts/emulator/test/system_info_SUITE.erl27
-rw-r--r--erts/emulator/test/trace_SUITE.erl77
-rw-r--r--erts/emulator/test/trace_nif_SUITE_data/trace_nif.c6
-rwxr-xr-xerts/emulator/utils/beam_makeops4
-rw-r--r--erts/emulator/zlib/Makefile.in26
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