aboutsummaryrefslogtreecommitdiffstats
path: root/erts
diff options
context:
space:
mode:
Diffstat (limited to 'erts')
-rw-r--r--erts/configure.in40
-rw-r--r--erts/doc/src/Makefile2
-rw-r--r--erts/doc/src/erlang.xml19
-rw-r--r--erts/emulator/Makefile.in7
-rw-r--r--erts/emulator/beam/beam_debug.c5
-rw-r--r--erts/emulator/beam/beam_emu.c120
-rw-r--r--erts/emulator/beam/beam_load.c50
-rwxr-xr-xerts/emulator/beam/erl_bif_info.c14
-rw-r--r--erts/emulator/beam/erl_db.c24
-rw-r--r--erts/emulator/beam/erl_nif.c111
-rw-r--r--erts/emulator/beam/erl_utils.h21
-rw-r--r--erts/emulator/beam/ops.tab23
-rw-r--r--erts/emulator/beam/utils.c16
-rw-r--r--erts/emulator/sys/unix/sys.c6
-rwxr-xr-xerts/emulator/sys/win32/sys.c8
-rw-r--r--erts/emulator/test/driver_SUITE.erl10
-rw-r--r--erts/emulator/test/driver_SUITE_data/otp_9302_drv.c27
-rw-r--r--erts/emulator/test/nif_SUITE.erl134
-rw-r--r--erts/emulator/test/nif_SUITE_data/nif_SUITE.c1
-rw-r--r--erts/emulator/test/nif_SUITE_data/nif_mod.c50
-rw-r--r--erts/emulator/test/nif_SUITE_data/nif_mod.h6
-rwxr-xr-xerts/emulator/utils/make_version8
-rw-r--r--erts/etc/common/Makefile.in4
-rw-r--r--erts/etc/win32/nsis/erlang.nsi1
-rw-r--r--erts/etc/win32/nsis/erlang20.nsi1
-rw-r--r--erts/start_scripts/Makefile2
-rw-r--r--erts/test/Makefile5
-rw-r--r--erts/test/upgrade_SUITE.erl447
-rw-r--r--erts/test/upgrade_SUITE_data/start.src36
-rw-r--r--erts/vsn.mk5
30 files changed, 1065 insertions, 138 deletions
diff --git a/erts/configure.in b/erts/configure.in
index 6445fec954..51e2e99c88 100644
--- a/erts/configure.in
+++ b/erts/configure.in
@@ -357,6 +357,16 @@ else
fi
AC_SUBST(OTP_RELEASE)
+AC_MSG_CHECKING([OTP release])
+[SYSTEM_VSN=`cat $ERL_TOP/OTP_VERSION | sed "s|\([0-9]*\).*|\1|"`]
+AC_MSG_RESULT([$SYSTEM_VSN])
+AC_SUBST(SYSTEM_VSN)
+
+AC_MSG_CHECKING([OTP version])
+[OTP_VERSION=`cat $ERL_TOP/OTP_VERSION`]
+AC_MSG_RESULT([$OTP_VERSION])
+AC_SUBST(OTP_VERSION)
+
dnl OK, we might have darwin switches off different kinds, lets
dnl check it all before continuing.
TMPSYS=`uname -s`-`uname -m`
@@ -3850,28 +3860,26 @@ esac
if test "$enable_dtrace_test" = "yes" ; then
if test "$DTRACE" = "dtrace" ; then
AC_CHECK_HEADERS(sys/sdt.h)
+ AC_MSG_CHECKING([for 1-stage DTrace precompilation])
# The OS X version of dtrace prints a spurious line here.
if ! dtrace -h $DTRACE_CPP -Iemulator/beam -o ./foo-dtrace.h -s emulator/beam/erlang_dtrace.d; then
AC_MSG_ERROR([Could not precompile erlang_dtrace.d: dtrace -h failed])
fi
+ AC_MSG_RESULT([yes])
- $RM -f dtest.{o,c}
- cat > dtest.c <<_DTEST
- #include "foo-dtrace.h"
- int main(void) { ERLANG_DIST_PORT_BUSY_ENABLED(); return 0; }
-_DTEST
- $CC $CFLAGS -c -o dtest.o dtest.c
-
- $RM -f $DTRACE_2STEP_TEST
- if dtrace -G $DTRACE_CPP $DTRACE_BITS_FLAG -Iemulator/beam -o $DTRACE_2STEP_TEST -s emulator/beam/erlang_dtrace.d dtest.o && \
- test -f $DTRACE_2STEP_TEST ; then
- rm $DTRACE_2STEP_TEST
+ AC_MSG_CHECKING([for 2-stage DTrace precompilation])
+ AC_TRY_COMPILE([ #include "foo-dtrace.h" ],
+ [ERLANG_DIST_PORT_BUSY_ENABLED();],
+ [$RM -f $DTRACE_2STEP_TEST
+ dtrace -G $DTRACE_CPP $DTRACE_BITS_FLAG -Iemulator/beam -o $DTRACE_2STEP_TEST -s emulator/beam/erlang_dtrace.d conftest.$OBJEXT 2>&AS_MESSAGE_LOG_FD
+ if test -f $DTRACE_2STEP_TEST; then
+ rm $DTRACE_2STEP_TEST
DTRACE_ENABLED_2STEP=yes
- AC_MSG_NOTICE([dtrace precompilation for 2-stage DTrace successful])
- else
- AC_MSG_NOTICE([dtrace precompilation for 1-stage DTrace successful])
- fi
- $RM -f dtest.{o,c} foo-dtrace.h
+ fi],
+ [])
+ AS_IF([test "x$DTRACE_ENABLED_2STEP" = "xyes"],
+ [AC_MSG_RESULT([yes])],
+ [AC_MSG_RESULT([no])])
DTRACE_ENABLED=yes
case $OPSYS in
diff --git a/erts/doc/src/Makefile b/erts/doc/src/Makefile
index d4c6fe67d2..e8b856c3ff 100644
--- a/erts/doc/src/Makefile
+++ b/erts/doc/src/Makefile
@@ -139,7 +139,7 @@ man: $(MAN1_FILES) $(MAN3_FILES)
gifs: $(GIF_FILES:%=$(HTMLDIR)/%)
-$(INFO_FILE): $(INFO_FILE_SRC) ../../vsn.mk
+$(INFO_FILE): $(INFO_FILE_SRC) $(ERL_TOP)/make/$(TARGET)/otp.mk
sed -e 's;%RELEASE%;$(SYSTEM_VSN);' $(INFO_FILE_SRC) > $(INFO_FILE)
diff --git a/erts/doc/src/erlang.xml b/erts/doc/src/erlang.xml
index 3004acf124..e440a3d270 100644
--- a/erts/doc/src/erlang.xml
+++ b/erts/doc/src/erlang.xml
@@ -6111,16 +6111,19 @@ ok
<seealso marker="#system_info_multi_scheduling">erlang:system_info(multi_scheduling)</seealso>, and
<seealso marker="#system_info_schedulers">erlang:system_info(schedulers)</seealso>.</p>
</item>
- <tag><marker id="system_info_otp_correction_package"><c>otp_correction_package</c></marker></tag>
- <item>
- <p>Returns a string containing the OTP correction package version
- number that currenly executing VM is part of. Note that other
- OTP applications in the system may be part of other OTP correction
- packages.</p>
- </item>
<tag><marker id="system_info_otp_release"><c>otp_release</c></marker></tag>
<item>
- <p>Returns a string containing the OTP release number.</p>
+ <p>Returns a string containing the OTP release number of the
+ OTP release that the currently executing ERTS application is
+ part of.</p>
+ <p>As of OTP release 17, the OTP release number corresponds to
+ the major OTP version number. There is no
+ <c>erlang:system_info()</c> argument giving the exact OTP
+ version. This since the exact OTP version in the general case
+ is hard to determine. For more information see
+ <seealso marker="doc/installation_guide:otp_version">the
+ documentation of the OTP version in the installation
+ guide</seealso>.</p>
</item>
<tag><marker id="system_info_port_parallelism"><c>port_parallelism</c></marker></tag>
<item><p>Returns the default port parallelism scheduling hint used.
diff --git a/erts/emulator/Makefile.in b/erts/emulator/Makefile.in
index f88a4ccc24..5e5b98bbd6 100644
--- a/erts/emulator/Makefile.in
+++ b/erts/emulator/Makefile.in
@@ -513,10 +513,9 @@ ifdef DTRACE_ENABLED
# global.h causes problems by including dtrace-wrapper.h which includes
# the autogenerated erlang_dtrace.h ... so make erlang_dtrace.h very early.
DTRACE_HEADERS = $(TARGET)/erlang_dtrace.h
-generate: $(DTRACE_HEADERS) $(GENERATE)
+GENERATE+= $(DTRACE_HEADERS)
else
DTRACE_HEADERS =
-generate: $(GENERATE)
endif
ifdef HIPE_ENABLED
@@ -574,8 +573,8 @@ $(TTF_DIR)/erl_alloc_types.h: beam/erl_alloc.types utils/make_alloc_types
GENERATE += $(TTF_DIR)/erl_alloc_types.h
# version include file
-$(TARGET)/erl_version.h: ../vsn.mk
- $(gen_verbose)LANG=C $(PERL) utils/make_version -o $@ $(SYSTEM_VSN) $(SYSTEM_CP_VSN) $(VSN)$(SERIALNO) $(TARGET)
+$(TARGET)/erl_version.h: ../vsn.mk $(ERL_TOP)/make/$(TARGET)/otp.mk
+ $(gen_verbose)LANG=C $(PERL) utils/make_version -o $@ $(SYSTEM_VSN) $(OTP_VERSION) $(VSN)$(SERIALNO) $(TARGET)
GENERATE += $(TARGET)/erl_version.h
# driver table
diff --git a/erts/emulator/beam/beam_debug.c b/erts/emulator/beam/beam_debug.c
index e36ec2a93e..a3cd08834f 100644
--- a/erts/emulator/beam/beam_debug.c
+++ b/erts/emulator/beam/beam_debug.c
@@ -635,6 +635,11 @@ print_op(int to, void *to_arg, int op, int size, BeamInstr* addr)
case op_i_put_tuple_rI:
case op_i_put_tuple_xI:
case op_i_put_tuple_yI:
+ case op_new_map_jdII:
+ case op_update_map_assoc_jsdII:
+ case op_update_map_exact_jsdII:
+ case op_i_has_map_fields_fsI:
+ case op_i_get_map_elements_fsI:
{
int n = unpacked[-1];
diff --git a/erts/emulator/beam/beam_emu.c b/erts/emulator/beam/beam_emu.c
index 1dfff7cb6a..80c1265541 100644
--- a/erts/emulator/beam/beam_emu.c
+++ b/erts/emulator/beam/beam_emu.c
@@ -2359,6 +2359,126 @@ void process_main(void)
Next(4+Arg(3));
}
+ OpCase(i_has_map_fields_fsI): {
+ map_t* mp;
+ Eterm map;
+ Eterm field;
+ Eterm *ks;
+ BeamInstr* fs;
+ Uint sz,n;
+
+ GetArg1(1, map);
+
+ /* this instruction assumes Arg1 is a map,
+ * i.e. that it follows a test is_map if needed.
+ */
+
+ mp = (map_t *)map_val(map);
+ sz = map_get_size(mp);
+
+ if (sz == 0) {
+ SET_I((BeamInstr *) Arg(0));
+ goto has_map_fields_fail;
+ }
+
+ ks = map_get_keys(mp);
+ n = (Uint)Arg(2);
+ fs = &Arg(3); /* pattern fields */
+
+ ASSERT(n>0);
+
+ while(sz) {
+ field = (Eterm)*fs;
+ if (EQ(field,*ks)) {
+ n--;
+ fs++;
+ if (n == 0) break;
+ }
+ ks++; sz--;
+ }
+
+ if (n) {
+ SET_I((BeamInstr *) Arg(0));
+ goto has_map_fields_fail;
+ }
+
+ I += 4 + Arg(2);
+has_map_fields_fail:
+ ASSERT(VALID_INSTR(*I));
+ Goto(*I);
+ }
+
+#define PUT_TERM_REG(term, desc) \
+do { \
+ switch ((desc) & _TAG_IMMED1_MASK) { \
+ case (R_REG_DEF << _TAG_PRIMARY_SIZE) | TAG_PRIMARY_HEADER: \
+ r(0) = (term); \
+ break; \
+ case (X_REG_DEF << _TAG_PRIMARY_SIZE) | TAG_PRIMARY_HEADER: \
+ x((desc) >> _TAG_IMMED1_SIZE) = (term); \
+ break; \
+ case (Y_REG_DEF << _TAG_PRIMARY_SIZE) | TAG_PRIMARY_HEADER: \
+ y((desc) >> _TAG_IMMED1_SIZE) = (term); \
+ break; \
+ default: \
+ ASSERT(0); \
+ break; \
+ } \
+} while(0)
+
+ OpCase(i_get_map_elements_fsI): {
+ Eterm map;
+ map_t *mp;
+ Eterm field;
+ Eterm *ks;
+ Eterm *vs;
+ BeamInstr *fs;
+ Uint sz,n;
+
+ GetArg1(1, map);
+
+ /* this instruction assumes Arg1 is a map,
+ * i.e. that it follows a test is_map if needed.
+ */
+
+ mp = (map_t *)map_val(map);
+ sz = map_get_size(mp);
+
+ if (sz == 0) {
+ SET_I((BeamInstr *) Arg(0));
+ goto get_map_elements_fail;
+ }
+
+ n = (Uint)Arg(2) / 2;
+ fs = &Arg(3); /* pattern fields and target registers */
+ ks = map_get_keys(mp);
+ vs = map_get_values(mp);
+
+ while(sz) {
+ field = (Eterm)*fs;
+ if (EQ(field,*ks)) {
+ PUT_TERM_REG(*vs, fs[1]);
+ n--;
+ fs += 2;
+ /* no more values to fetch, we are done */
+ if (n == 0) break;
+ }
+ ks++; sz--;
+ vs++;
+ }
+
+ if (n) {
+ SET_I((BeamInstr *) Arg(0));
+ goto get_map_elements_fail;
+ }
+
+ I += 4 + Arg(2);
+get_map_elements_fail:
+ ASSERT(VALID_INSTR(*I));
+ Goto(*I);
+ }
+#undef PUT_TERM_REG
+
OpCase(update_map_assoc_jsdII): {
Eterm res;
Eterm map;
diff --git a/erts/emulator/beam/beam_load.c b/erts/emulator/beam/beam_load.c
index b589d1c930..53df7876d8 100644
--- a/erts/emulator/beam/beam_load.c
+++ b/erts/emulator/beam/beam_load.c
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 1996-2013. All Rights Reserved.
+ * Copyright Ericsson AB 1996-2014. 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
@@ -409,7 +409,7 @@ typedef struct LoaderState {
__result = __result << 8 | *Stp->file_p++; \
} \
Dest = __result; \
- } while (0)
+ }
#define GetByte(Stp, Dest) \
if ((Stp)->file_left < 1) { \
@@ -506,6 +506,9 @@ static GenOp* gen_select_literals(LoaderState* stp, GenOpArg S,
static GenOp* const_select_val(LoaderState* stp, GenOpArg S, GenOpArg Fail,
GenOpArg Size, GenOpArg* Rest);
+static GenOp* gen_get_map_element(LoaderState* stp, GenOpArg Fail, GenOpArg Src,
+ GenOpArg Size, GenOpArg* Rest);
+
static int freeze_code(LoaderState* stp);
static void final_touch(LoaderState* stp);
@@ -3951,6 +3954,49 @@ tuple_append_put(LoaderState* stp, GenOpArg Arity, GenOpArg Dst,
return op;
}
+/*
+ * Replace a get_map_elements with one key to an instruction with one
+ * element
+ */
+
+static GenOp*
+gen_get_map_element(LoaderState* stp, GenOpArg Fail, GenOpArg Src,
+ GenOpArg Size, GenOpArg* Rest)
+{
+ GenOp* op;
+
+ ASSERT(Size.type == TAG_u);
+
+ NEW_GENOP(stp, op);
+ op->next = NULL;
+ op->op = genop_get_map_element_4;
+ op->arity = 4;
+
+ op->a[0] = Fail;
+ op->a[1] = Src;
+ op->a[2] = Rest[0];
+ op->a[3] = Rest[1];
+ return op;
+}
+
+static GenOp*
+gen_has_map_field(LoaderState* stp, GenOpArg Fail, GenOpArg Src,
+ GenOpArg Size, GenOpArg* Rest)
+{
+ GenOp* op;
+
+ ASSERT(Size.type == TAG_u);
+
+ NEW_GENOP(stp, op);
+ op->next = NULL;
+ op->op = genop_has_map_field_3;
+ op->arity = 4;
+
+ op->a[0] = Fail;
+ op->a[1] = Src;
+ op->a[2] = Rest[0];
+ return op;
+}
/*
* Freeze the code in memory, move the string table into place,
diff --git a/erts/emulator/beam/erl_bif_info.c b/erts/emulator/beam/erl_bif_info.c
index f25b4dbae5..2adba9b240 100755
--- a/erts/emulator/beam/erl_bif_info.c
+++ b/erts/emulator/beam/erl_bif_info.c
@@ -64,7 +64,7 @@ static Export *gather_gc_info_res_trap;
#define DECL_AM(S) Eterm AM_ ## S = am_atom_put(#S, sizeof(#S) - 1)
-static char otp_correction_package[] = ERLANG_OTP_CORRECTION_PACKAGE;
+static char otp_version[] = ERLANG_OTP_VERSION;
/* Keep erts_system_version as a global variable for easy access from a core */
static char erts_system_version[] = ("Erlang/OTP " ERLANG_OTP_RELEASE
"%s"
@@ -312,7 +312,7 @@ erts_print_system_version(int to, void *arg, Process *c_p)
int i, rc = -1;
char *rc_str = "";
char rc_buf[100];
- char *ocp = otp_correction_package;
+ char *ov = otp_version;
#ifdef ERTS_SMP
Uint total, online, active;
#ifdef ERTS_DIRTY_SCHEDULERS
@@ -323,9 +323,9 @@ erts_print_system_version(int to, void *arg, Process *c_p)
(void) erts_schedulers_state(&total, &online, &active, NULL, NULL, NULL, 0);
#endif
#endif
- for (i = 0; i < sizeof(otp_correction_package)-4; i++) {
- if (ocp[i] == '-' && ocp[i+1] == 'r' && ocp[i+2] == 'c')
- rc = atoi(&ocp[i+3]);
+ for (i = 0; i < sizeof(otp_version)-4; i++) {
+ if (ov[i] == '-' && ov[i+1] == 'r' && ov[i+2] == 'c')
+ rc = atoi(&ov[i+3]);
}
if (rc >= 0) {
if (rc == 0)
@@ -2448,10 +2448,6 @@ BIF_RETTYPE system_info_1(BIF_ALIST_1)
DECL_AM(unknown);
BIF_RET(AM_unknown);
}
- } else if (ERTS_IS_ATOM_STR("otp_correction_package", BIF_ARG_1)) {
- int n = sizeof(ERLANG_OTP_CORRECTION_PACKAGE)-1;
- hp = HAlloc(BIF_P, 2*n);
- BIF_RET(buf_to_intlist(&hp, ERLANG_OTP_CORRECTION_PACKAGE, n, NIL));
} else if (ERTS_IS_ATOM_STR("otp_release", BIF_ARG_1)) {
int n = sizeof(ERLANG_OTP_RELEASE)-1;
hp = HAlloc(BIF_P, 2*n);
diff --git a/erts/emulator/beam/erl_db.c b/erts/emulator/beam/erl_db.c
index 41e64fcd4f..a5d67571e2 100644
--- a/erts/emulator/beam/erl_db.c
+++ b/erts/emulator/beam/erl_db.c
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 1996-2013. All Rights Reserved.
+ * Copyright Ericsson AB 1996-2014. 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
@@ -125,6 +125,7 @@ get_meta_main_tab_lock(unsigned slot)
static erts_smp_spinlock_t meta_main_tab_main_lock;
static Uint meta_main_tab_first_free; /* Index of first free slot */
static int meta_main_tab_cnt; /* Number of active tables */
+static int meta_main_tab_top; /* Highest ever used slot + 1 */
static Uint meta_main_tab_slot_mask; /* The slot index part of an unnamed table id */
static Uint meta_main_tab_seq_incr;
static Uint meta_main_tab_seq_cnt = 0; /* To give unique(-ish) table identifiers */
@@ -1469,6 +1470,10 @@ BIF_RETTYPE ets_new_2(BIF_ALIST_2)
ASSERT(slot>=0 && slot<db_max_tabs);
meta_main_tab_first_free = GET_NEXT_FREE_SLOT(slot);
meta_main_tab_cnt++;
+ if (slot >= meta_main_tab_top) {
+ ASSERT(slot == meta_main_tab_top);
+ meta_main_tab_top = slot + 1;
+ }
if (is_named) {
ret = BIF_ARG_1;
@@ -2058,27 +2063,31 @@ BIF_RETTYPE ets_all_0(BIF_ALIST_0)
{
DbTable* tb;
Eterm previous;
- int i, j;
+ int i;
Eterm* hp;
Eterm* hendp;
int t_tabs_cnt;
- int t_max_tabs;
+ int t_top;
erts_smp_spin_lock(&meta_main_tab_main_lock);
t_tabs_cnt = meta_main_tab_cnt;
- t_max_tabs = db_max_tabs;
+ t_top = meta_main_tab_top;
erts_smp_spin_unlock(&meta_main_tab_main_lock);
hp = HAlloc(BIF_P, 2*t_tabs_cnt);
hendp = hp + 2*t_tabs_cnt;
previous = NIL;
- j = 0;
- for(i = 0; (i < t_max_tabs && j < t_tabs_cnt); i++) {
+ for(i = 0; i < t_top; i++) {
erts_smp_rwmtx_t *mmtl = get_meta_main_tab_lock(i);
erts_smp_rwmtx_rlock(mmtl);
if (IS_SLOT_ALIVE(i)) {
- j++;
+ if (hp == hendp) {
+ /* Racing table creator, grab some more heap space */
+ t_tabs_cnt = 10;
+ hp = HAlloc(BIF_P, 2*t_tabs_cnt);
+ hendp = hp + 2*t_tabs_cnt;
+ }
tb = meta_main_tab[i].u.tb;
previous = CONS(hp, tb->common.id, previous);
hp += 2;
@@ -2849,6 +2858,7 @@ void init_db(void)
ERTS_ETS_MISC_MEM_ADD(size);
meta_main_tab_cnt = 0;
+ meta_main_tab_top = 0;
for (i=1; i<db_max_tabs; i++) {
SET_NEXT_FREE_SLOT(i-1,i);
}
diff --git a/erts/emulator/beam/erl_nif.c b/erts/emulator/beam/erl_nif.c
index 1ddfb2f7bd..63e0d6d0c2 100644
--- a/erts/emulator/beam/erl_nif.c
+++ b/erts/emulator/beam/erl_nif.c
@@ -1237,6 +1237,19 @@ static void steal_resource_type(ErlNifResourceType* type)
}
}
+/* The opened_rt_list is used by enif_open_resource_type()
+ * in order to rollback "creates" and "take-overs" in case the load fails.
+ */
+struct opened_resource_type
+{
+ struct opened_resource_type* next;
+
+ ErlNifResourceFlags op;
+ ErlNifResourceType* type;
+ ErlNifResourceDtor* new_dtor;
+};
+static struct opened_resource_type* opened_rt_list = NULL;
+
ErlNifResourceType*
enif_open_resource_type(ErlNifEnv* env,
const char* module_str,
@@ -1258,22 +1271,21 @@ enif_open_resource_type(ErlNifEnv* env,
if (type == NULL) {
if (flags & ERL_NIF_RT_CREATE) {
type = erts_alloc(ERTS_ALC_T_NIF,
- sizeof(struct enif_resource_type_t));
- type->dtor = dtor;
+ sizeof(struct enif_resource_type_t));
type->module = module_am;
type->name = name_am;
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;
+ #ifdef DEBUG
+ type->dtor = (void*)1;
+ type->owner = (void*)2;
+ type->prev = (void*)3;
+ type->next = (void*)4;
+ #endif
}
}
else {
- if (flags & ERL_NIF_RT_TAKEOVER) {
- steal_resource_type(type);
+ if (flags & ERL_NIF_RT_TAKEOVER) {
op = ERL_NIF_RT_TAKEOVER;
}
else {
@@ -1281,12 +1293,13 @@ enif_open_resource_type(ErlNifEnv* env,
}
}
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);
+ struct opened_resource_type* ort = erts_alloc(ERTS_ALC_T_TMP,
+ sizeof(struct opened_resource_type));
+ ort->op = op;
+ ort->type = type;
+ ort->new_dtor = dtor;
+ ort->next = opened_rt_list;
+ opened_rt_list = ort;
}
if (tried != NULL) {
*tried = op;
@@ -1294,6 +1307,51 @@ enif_open_resource_type(ErlNifEnv* env,
return type;
}
+static void commit_opened_resource_types(struct erl_module_nif* lib)
+{
+ while (opened_rt_list) {
+ struct opened_resource_type* ort = opened_rt_list;
+
+ ErlNifResourceType* type = ort->type;
+
+ if (ort->op == ERL_NIF_RT_CREATE) {
+ type->prev = &resource_type_list;
+ type->next = resource_type_list.next;
+ type->next->prev = type;
+ type->prev->next = type;
+ }
+ else { /* ERL_NIF_RT_TAKEOVER */
+ steal_resource_type(type);
+ }
+
+ type->owner = lib;
+ type->dtor = ort->new_dtor;
+
+ if (type->dtor != NULL) {
+ erts_refc_inc(&lib->rt_dtor_cnt, 1);
+ }
+ erts_refc_inc(&lib->rt_cnt, 1);
+
+ opened_rt_list = ort->next;
+ erts_free(ERTS_ALC_T_TMP, ort);
+ }
+}
+
+static void rollback_opened_resource_types(void)
+{
+ while (opened_rt_list) {
+ struct opened_resource_type* ort = opened_rt_list;
+
+ if (ort->op == ERL_NIF_RT_CREATE) {
+ erts_free(ERTS_ALC_T_NIF, ort->type);
+ }
+
+ opened_rt_list = ort->next;
+ erts_free(ERTS_ALC_T_TMP, ort);
+ }
+}
+
+
static void nif_resource_dtor(Binary* bin)
{
ErlNifResource* resource = (ErlNifResource*) ERTS_MAGIC_BIN_DATA(bin);
@@ -1319,6 +1377,8 @@ void* enif_alloc_resource(ErlNifResourceType* type, size_t size)
{
Binary* bin = erts_create_magic_binary(SIZEOF_ErlNifResource(size), &nif_resource_dtor);
ErlNifResource* resource = ERTS_MAGIC_BIN_DATA(bin);
+
+ ASSERT(type->owner && type->next && type->prev); /* not allowed in load/upgrade */
resource->type = type;
erts_refc_inc(&bin->refc, 1);
#ifdef DEBUG
@@ -2040,9 +2100,15 @@ BIF_RETTYPE load_nif_2(BIF_ALIST_2)
lib->entry = entry;
erts_refc_init(&lib->rt_cnt, 0);
erts_refc_init(&lib->rt_dtor_cnt, 0);
+ ASSERT(opened_rt_list == NULL);
lib->mod = mod;
env.mod_nif = lib;
- if (mod->curr.nif != NULL) { /* Reload */
+ if (mod->curr.nif != NULL) { /*************** Reload ******************/
+ /*
+ * Repeated load_nif calls from same Erlang module instance ("reload")
+ * is deprecated and was only ment as a development feature not to
+ * be used in production systems. (See warning below)
+ */
int k;
lib->priv_data = mod->curr.nif->priv_data;
@@ -2074,6 +2140,7 @@ BIF_RETTYPE load_nif_2(BIF_ALIST_2)
ret = load_nif_error(BIF_P, reload, "Library reload-call unsuccessful.");
}
else {
+ commit_opened_resource_types(lib);
mod->curr.nif->entry = NULL; /* to prevent 'unload' callback */
erts_unload_nif(mod->curr.nif);
reload_warning = 1;
@@ -2081,7 +2148,7 @@ BIF_RETTYPE load_nif_2(BIF_ALIST_2)
}
else {
lib->priv_data = NULL;
- if (mod->old.nif != NULL) { /* Upgrade */
+ 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.");
@@ -2094,17 +2161,18 @@ BIF_RETTYPE load_nif_2(BIF_ALIST_2)
mod->old.nif->priv_data = prev_old_data;
ret = load_nif_error(BIF_P, upgrade, "Library upgrade-call unsuccessful.");
}
- /*else if (mod->old_nif->priv_data != prev_old_data) {
- refresh_cached_nif_data(mod->old_code, mod->old_nif);
- }*/
+ else
+ commit_opened_resource_types(lib);
}
- else if (entry->load != NULL) { /* Initial load */
+ else if (entry->load != NULL) { /********* Initial load ***********/
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.");
}
+ else
+ commit_opened_resource_types(lib);
}
}
if (ret == am_ok) {
@@ -2133,6 +2201,7 @@ BIF_RETTYPE load_nif_2(BIF_ALIST_2)
}
else {
error:
+ rollback_opened_resource_types();
ASSERT(ret != am_ok);
if (lib != NULL) {
erts_free(ERTS_ALC_T_NIF, lib);
diff --git a/erts/emulator/beam/erl_utils.h b/erts/emulator/beam/erl_utils.h
index 5b81d814c6..43a19e97f1 100644
--- a/erts/emulator/beam/erl_utils.h
+++ b/erts/emulator/beam/erl_utils.h
@@ -202,17 +202,18 @@ int eq(Eterm, Eterm);
#define EQ(x,y) (((x) == (y)) || (is_not_both_immed((x),(y)) && eq((x),(y))))
#if HALFWORD_HEAP
-Sint cmp_rel_opt(Eterm, Eterm*, Eterm, Eterm*, int);
-#define cmp_rel(A,A_BASE,B,B_BASE) cmp_rel_opt(A,A_BASE,B,B_BASE,0)
-#define cmp_rel_term(A,A_BASE,B,B_BASE) cmp_rel_opt(A,A_BASE,B,B_BASE,1)
-#define CMP(A,B) cmp_rel_opt(A,NULL,B,NULL,0)
-#define CMP_TERM(A,B) cmp_rel_opt(A,NULL,B,NULL,1)
+Sint erts_cmp_rel_opt(Eterm, Eterm*, Eterm, Eterm*, int);
+#define cmp_rel(A,A_BASE,B,B_BASE) erts_cmp_rel_opt(A,A_BASE,B,B_BASE,0)
+#define cmp_rel_term(A,A_BASE,B,B_BASE) erts_cmp_rel_opt(A,A_BASE,B,B_BASE,1)
+#define CMP(A,B) erts_cmp_rel_opt(A,NULL,B,NULL,0)
+#define CMP_TERM(A,B) erts_cmp_rel_opt(A,NULL,B,NULL,1)
#else
-Sint cmp(Eterm, Eterm, int);
-#define cmp_rel(A,A_BASE,B,B_BASE) cmp(A,B,0)
-#define cmp_rel_term(A,A_BASE,B,B_BASE) cmp(A,B,1)
-#define CMP(A,B) cmp(A,B,0)
-#define CMP_TERM(A,B) cmp(A,B,1)
+Sint cmp(Eterm, Eterm);
+Sint erts_cmp(Eterm, Eterm, int);
+#define cmp_rel(A,A_BASE,B,B_BASE) erts_cmp(A,B,0)
+#define cmp_rel_term(A,A_BASE,B,B_BASE) erts_cmp(A,B,1)
+#define CMP(A,B) erts_cmp(A,B,0)
+#define CMP_TERM(A,B) erts_cmp(A,B,1)
#endif
#define cmp_lt(a,b) (CMP((a),(b)) < 0)
diff --git a/erts/emulator/beam/ops.tab b/erts/emulator/beam/ops.tab
index 9ea3a3a8ea..8406f5344a 100644
--- a/erts/emulator/beam/ops.tab
+++ b/erts/emulator/beam/ops.tab
@@ -1469,11 +1469,6 @@ apply_last I P
# Map instructions in R17.
#
-# put_map Fail Src Dst Live Size Rest=* => jump Fail
-# is_map Fail Src => jump Fail
-# has_map_field Fail Src Key => jump Fail
-# get_map_element Fail Src Key Dst => jump Fail
-
put_map_assoc F n Dst Live Size Rest=* => new_map F Dst Live Size Rest
put_map_exact F n Dst Live Size Rest=* => new_map F Dst Live Size Rest
put_map_assoc F Src Dst Live Size Rest=* => \
@@ -1492,6 +1487,15 @@ is_map f r
is_map f x
is_map f y
+## Transform has_map_field(s) #{ K1 := _, K2 := _ }
+
+has_map_field/3
+
+has_map_fields Fail Src Size=u==1 Rest=* => gen_has_map_field(Fail,Src,Size,Rest)
+has_map_fields Fail Src Size Rest=* => i_has_map_fields Fail Src Size Rest
+
+i_has_map_fields f s I
+
has_map_field Fail Src=rxy Key=arxy => i_has_map_field Fail Src Key
has_map_field Fail Src Key => move Key x | i_has_map_field Fail Src x
@@ -1509,6 +1513,15 @@ i_has_map_field f r y
i_has_map_field f x y
i_has_map_field f y y
+## Transform get_map_elements(s) #{ K1 := V1, K2 := V2 }
+
+get_map_element/4
+
+get_map_elements Fail Src=rxy Size=u==2 Rest=* => gen_get_map_element(Fail,Src,Size,Rest)
+get_map_elements Fail Src Size Rest=* => i_get_map_elements Fail Src Size Rest
+
+i_get_map_elements f s I
+
get_map_element Fail Src=rxy Key=ax Dst => i_get_map_element Fail Src Key Dst
get_map_element Fail Src=rxy Key=rycq Dst => \
move Key x | i_get_map_element Fail Src x Dst
diff --git a/erts/emulator/beam/utils.c b/erts/emulator/beam/utils.c
index bc4a05d385..7da555b18d 100644
--- a/erts/emulator/beam/utils.c
+++ b/erts/emulator/beam/utils.c
@@ -2425,14 +2425,24 @@ static int cmp_atoms(Eterm a, Eterm b)
bb->name+3, bb->len-3);
}
-/* cmp(Eterm a, Eterm b, int exact)
+#if !HALFWORD_HEAP
+/* cmp(Eterm a, Eterm b)
+ * For compatibility with HiPE - arith-based compare.
+ */
+Sint cmp(Eterm a, Eterm b)
+{
+ return erts_cmp(a, b, 0);
+}
+#endif
+
+/* erts_cmp(Eterm a, Eterm b, int exact)
* exact = 1 -> term-based compare
* exact = 0 -> arith-based compare
*/
#if HALFWORD_HEAP
-Sint cmp_rel_opt(Eterm a, Eterm* a_base, Eterm b, Eterm* b_base, int exact)
+Sint erts_cmp_rel_opt(Eterm a, Eterm* a_base, Eterm b, Eterm* b_base, int exact)
#else
-Sint cmp(Eterm a, Eterm b, int exact)
+Sint erts_cmp(Eterm a, Eterm b, int exact)
#endif
{
DECLARE_WSTACK(stack);
diff --git a/erts/emulator/sys/unix/sys.c b/erts/emulator/sys/unix/sys.c
index a5294ad84e..865cb50a56 100644
--- a/erts/emulator/sys/unix/sys.c
+++ b/erts/emulator/sys/unix/sys.c
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 1996-2013. All Rights Reserved.
+ * Copyright Ericsson AB 1996-2014. 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
@@ -2561,7 +2561,7 @@ void *erts_sys_aligned_alloc(UWord alignment, UWord size)
#ifdef HAVE_POSIX_MEMALIGN
void *ptr = NULL;
int error;
- ASSERT(alignment && (alignment & ~alignment) == 0); /* power of 2 */
+ ASSERT(alignment && (alignment & (alignment-1)) == 0); /* power of 2 */
error = posix_memalign(&ptr, (size_t) alignment, (size_t) size);
#if HAVE_ERTS_MSEG
if (error || !ptr) {
@@ -2584,7 +2584,7 @@ void *erts_sys_aligned_alloc(UWord alignment, UWord size)
void erts_sys_aligned_free(UWord alignment, void *ptr)
{
- ASSERT(alignment && (alignment & ~alignment) == 0); /* power of 2 */
+ ASSERT(alignment && (alignment & (alignment-1)) == 0); /* power of 2 */
free(ptr);
}
diff --git a/erts/emulator/sys/win32/sys.c b/erts/emulator/sys/win32/sys.c
index 5ea4703a7a..a11ac73ebc 100755
--- a/erts/emulator/sys/win32/sys.c
+++ b/erts/emulator/sys/win32/sys.c
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 1996-2013. All Rights Reserved.
+ * Copyright Ericsson AB 1996-2014. 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
@@ -2757,7 +2757,7 @@ void erts_sys_free(ErtsAlcType_t t, void *x, void *p)
void *erts_sys_aligned_alloc(UWord alignment, UWord size)
{
void *ptr;
- ASSERT(alignment && (alignment & ~alignment) == 0); /* power of 2 */
+ ASSERT(alignment && (alignment & (alignment-1)) == 0); /* power of 2 */
ptr = _aligned_malloc((size_t) size, (size_t) alignment);
ASSERT(!ptr || (((UWord) ptr) & (alignment - 1)) == 0);
return ptr;
@@ -2765,14 +2765,14 @@ void *erts_sys_aligned_alloc(UWord alignment, UWord size)
void erts_sys_aligned_free(UWord alignment, void *ptr)
{
- ASSERT(alignment && (alignment & ~alignment) == 0); /* power of 2 */
+ ASSERT(alignment && (alignment & (alignment-1)) == 0); /* power of 2 */
_aligned_free(ptr);
}
void *erts_sys_aligned_realloc(UWord alignment, void *ptr, UWord size, UWord old_size)
{
void *new_ptr;
- ASSERT(alignment && (alignment & ~alignment) == 0); /* power of 2 */
+ ASSERT(alignment && (alignment & (alignment-1)) == 0); /* power of 2 */
new_ptr = _aligned_realloc(ptr, (size_t) size, (size_t) alignment);
ASSERT(!new_ptr || (((UWord) new_ptr) & (alignment - 1)) == 0);
return new_ptr;
diff --git a/erts/emulator/test/driver_SUITE.erl b/erts/emulator/test/driver_SUITE.erl
index 06211406b4..c62bc0c454 100644
--- a/erts/emulator/test/driver_SUITE.erl
+++ b/erts/emulator/test/driver_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1997-2013. All Rights Reserved.
+%% Copyright Ericsson AB 1997-2014. 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
@@ -1945,6 +1945,14 @@ otp_9302(Config) when is_list(Config) ->
end.
thr_free_drv(Config) when is_list(Config) ->
+ case erlang:system_info(threads) of
+ false ->
+ {skipped, "No thread support"};
+ true ->
+ thr_free_drv_do(Config)
+ end.
+
+thr_free_drv_do(Config) ->
?line Path = ?config(data_dir, Config),
?line erl_ddll:start(),
?line ok = load_driver(Path, thr_free_drv),
diff --git a/erts/emulator/test/driver_SUITE_data/otp_9302_drv.c b/erts/emulator/test/driver_SUITE_data/otp_9302_drv.c
index 7c144d20cf..ad29d17f06 100644
--- a/erts/emulator/test/driver_SUITE_data/otp_9302_drv.c
+++ b/erts/emulator/test/driver_SUITE_data/otp_9302_drv.c
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2011-2013. All Rights Reserved.
+ * Copyright Ericsson AB 2011-2014. 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
@@ -94,7 +94,7 @@ DRIVER_INIT(otp_9302_drv)
static void stop(ErlDrvData drv_data)
{
Otp9302Data *data = (Otp9302Data *) drv_data;
- if (!data->smp)
+ if (data->msgq.mtx)
erl_drv_mutex_destroy(data->msgq.mtx);
driver_free(data);
}
@@ -114,13 +114,16 @@ static ErlDrvData start(ErlDrvPort port,
driver_system_info(&sys_info, sizeof(ErlDrvSysInfo));
data->smp = sys_info.smp_support;
+ data->msgq.mtx = NULL;
if (!data->smp) {
data->msgq.start = NULL;
data->msgq.end = NULL;
- data->msgq.mtx = erl_drv_mutex_create("");
- if (!data->msgq.mtx) {
- driver_free(data);
- return ERL_DRV_ERROR_GENERAL;
+ if (sys_info.thread_support) {
+ data->msgq.mtx = erl_drv_mutex_create("");
+ if (!data->msgq.mtx) {
+ driver_free(data);
+ return ERL_DRV_ERROR_GENERAL;
+ }
}
}
@@ -143,19 +146,22 @@ static void enqueue_reply(Otp9302AsyncData *adata)
Otp9302MsgQ *msgq = adata->msgq;
adata->next = NULL;
adata->refc++;
- erl_drv_mutex_lock(msgq->mtx);
+ if (msgq->mtx)
+ erl_drv_mutex_lock(msgq->mtx);
if (msgq->end)
msgq->end->next = adata;
else
msgq->end = msgq->start = adata;
msgq->end = adata;
- erl_drv_mutex_unlock(msgq->mtx);
+ if (msgq->mtx)
+ erl_drv_mutex_unlock(msgq->mtx);
}
static void dequeue_replies(Otp9302AsyncData *adata)
{
Otp9302MsgQ *msgq = adata->msgq;
- erl_drv_mutex_lock(msgq->mtx);
+ if (msgq->mtx)
+ erl_drv_mutex_lock(msgq->mtx);
if (--adata->refc == 0)
driver_free(adata);
while (msgq->start) {
@@ -166,7 +172,8 @@ static void dequeue_replies(Otp9302AsyncData *adata)
driver_free(adata);
}
msgq->start = msgq->end = NULL;
- erl_drv_mutex_unlock(msgq->mtx);
+ if (msgq->mtx)
+ erl_drv_mutex_unlock(msgq->mtx);
}
static void async_invoke(void *data)
diff --git a/erts/emulator/test/nif_SUITE.erl b/erts/emulator/test/nif_SUITE.erl
index bcc1f9e5af..a854d3f05b 100644
--- a/erts/emulator/test/nif_SUITE.erl
+++ b/erts/emulator/test/nif_SUITE.erl
@@ -850,6 +850,138 @@ resource_takeover(Config) when is_list(Config) ->
?line ok = forget_resource(AN4),
?line [] = nif_mod_call_history(),
+
+ %%
+ %% Test rollback after failed upgrade of same lib-version
+ %%
+
+ {A5,BinA5} = make_resource(2, Holder, "A5"),
+ {NA5,BinNA5} = make_resource(0, Holder, "NA5"),
+ {AN5,_BinAN5} = make_resource(1, Holder, "AN5"),
+
+ {A6,BinA6} = make_resource(2, Holder, "A6"),
+ {NA6,BinNA6} = make_resource(0, Holder, "NA6"),
+ {AN6,_BinAN6} = make_resource(1, Holder, "AN6"),
+
+ {module,nif_mod} = erlang:load_module(nif_mod,ModBin),
+ undefined = nif_mod:lib_version(),
+ {error,{upgrade,_}} =
+ nif_mod:load_nif_lib(Config, 1,
+ [{resource_type, 4, ?RT_TAKEOVER, "resource_type_A",resource_dtor_B,
+ ?RT_TAKEOVER},
+ {resource_type, 4, ?RT_TAKEOVER bor ?RT_CREATE, "resource_type_null_A",null,
+ ?RT_TAKEOVER},
+ {resource_type, 4, ?RT_TAKEOVER, "resource_type_A_null",resource_dtor_A,
+ ?RT_TAKEOVER},
+ {resource_type, 4, ?RT_CREATE, "Mr Pink", resource_dtor_A,
+ ?RT_CREATE},
+
+ {return, 1} % FAIL
+ ]),
+
+ undefined = nif_mod:lib_version(),
+ [{upgrade,1,5,105}] = nif_mod_call_history(),
+
+ %% Make sure dtor was not changed (from A to B)
+ ok = forget_resource(A5),
+ [{{resource_dtor_A_v1,BinA5},1,6,106}] = nif_mod_call_history(),
+
+ %% Make sure dtor was not nullified (from A to null)
+ ok = forget_resource(NA5),
+ [{{resource_dtor_A_v1,BinNA5},1,7,107}] = nif_mod_call_history(),
+
+ %% Make sure dtor was not added (from null to A)
+ ok = forget_resource(AN5),
+ [] = nif_mod_call_history(),
+
+ %%
+ %% Test rollback after failed upgrade of other lib-version
+ %%
+
+ {error,{upgrade,_}} =
+ nif_mod:load_nif_lib(Config, 2,
+ [{resource_type, 4, ?RT_TAKEOVER, "resource_type_A",resource_dtor_B,
+ ?RT_TAKEOVER},
+ {resource_type, 4, ?RT_TAKEOVER bor ?RT_CREATE, "resource_type_null_A",null,
+ ?RT_TAKEOVER},
+ {resource_type, 4, ?RT_TAKEOVER, "resource_type_A_null",resource_dtor_A,
+ ?RT_TAKEOVER},
+ {resource_type, null, ?RT_TAKEOVER, "Mr Pink", resource_dtor_A,
+ ?RT_TAKEOVER},
+ {resource_type, 4, ?RT_CREATE, "Mr Pink", resource_dtor_A,
+ ?RT_CREATE},
+
+ {return, 1} % FAIL
+ ]),
+
+ undefined = nif_mod:lib_version(),
+ [{upgrade,2,_,_}] = nif_mod_call_history(),
+
+ %% Make sure dtor was not changed (from A to B)
+ ok = forget_resource(A6),
+ [{{resource_dtor_A_v1,BinA6},1,_,_}] = nif_mod_call_history(),
+
+ %% Make sure dtor was not nullified (from A to null)
+ ok = forget_resource(NA6),
+ [{{resource_dtor_A_v1,BinNA6},1,_,_}] = nif_mod_call_history(),
+
+ %% Make sure dtor was not added (from null to A)
+ ok = forget_resource(AN6),
+ [] = nif_mod_call_history(),
+
+ %%
+ %% Test rolback after failed initial load
+ %%
+ false = code:purge(nif_mod),
+ [{unload,1,_,_}] = nif_mod_call_history(),
+ true = code:delete(nif_mod),
+ false = code:purge(nif_mod),
+ [] = nif_mod_call_history(),
+
+
+ {module,nif_mod} = erlang:load_module(nif_mod,ModBin),
+ undefined = nif_mod:lib_version(),
+ {error,{load,_}} =
+ nif_mod:load_nif_lib(Config, 1,
+ [{resource_type, null, ?RT_TAKEOVER, "resource_type_A",resource_dtor_A,
+ ?RT_TAKEOVER},
+ {resource_type, 4, ?RT_TAKEOVER bor ?RT_CREATE, "resource_type_null_A",null,
+ ?RT_CREATE},
+ {resource_type, 4, ?RT_CREATE, "resource_type_A_null",resource_dtor_A,
+ ?RT_CREATE},
+ {resource_type, 4, ?RT_CREATE, "Mr Pink", resource_dtor_A,
+ ?RT_CREATE},
+
+ {return, 1} % FAIL
+ ]),
+
+ undefined = nif_mod:lib_version(),
+ ok = nif_mod:load_nif_lib(Config, 1,
+ [{resource_type, null, ?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_CREATE},
+
+ {resource_type, 1, ?RT_CREATE, "resource_type_A_null", null,
+ ?RT_CREATE},
+ {resource_type, null, ?RT_TAKEOVER, "Mr Pink", resource_dtor_A,
+ ?RT_TAKEOVER},
+
+ {return, 0} % SUCCESS
+ ]),
+
+ ?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(),
+
+ {NA7,BinNA7} = make_resource(0, Holder, "NA7"),
+ {AN7,BinAN7} = make_resource(1, Holder, "AN7"),
+
+ ok = forget_resource(NA7),
+ [{{resource_dtor_A_v1,BinNA7},1,_,_}] = nif_mod_call_history(),
+
+ ok = forget_resource(AN7),
+ [] = nif_mod_call_history(),
+
?line true = lists:member(?MODULE, erlang:system_info(taints)),
?line true = lists:member(nif_mod, erlang:system_info(taints)),
?line verify_tmpmem(TmpMem),
@@ -1406,7 +1538,7 @@ dirty_nif(Config) when is_list(Config) ->
{skipped,"No dirty scheduler support"}
end.
-next_msg(Pid) ->
+next_msg(_Pid) ->
receive
M -> M
after 100 ->
diff --git a/erts/emulator/test/nif_SUITE_data/nif_SUITE.c b/erts/emulator/test/nif_SUITE_data/nif_SUITE.c
index b550d1f16d..160f4843ad 100644
--- a/erts/emulator/test/nif_SUITE_data/nif_SUITE.c
+++ b/erts/emulator/test/nif_SUITE_data/nif_SUITE.c
@@ -1477,7 +1477,6 @@ static ERL_NIF_TERM consume_timeslice_nif(ErlNifEnv* env, int argc, const ERL_NI
{
int percent;
char atom[10];
- int do_repeat;
if (!enif_get_int(env, argv[0], &percent) ||
!enif_get_atom(env, argv[1], atom, sizeof(atom), ERL_NIF_LATIN1)) {
diff --git a/erts/emulator/test/nif_SUITE_data/nif_mod.c b/erts/emulator/test/nif_SUITE_data/nif_mod.c
index e32d10057c..55a0d2ac4f 100644
--- a/erts/emulator/test/nif_SUITE_data/nif_mod.c
+++ b/erts/emulator/test/nif_SUITE_data/nif_mod.c
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2009-2010. All Rights Reserved.
+ * Copyright Ericsson AB 2009-2014. 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
@@ -41,6 +41,7 @@ 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 ERL_NIF_TERM am_return;
static NifModPrivData* priv_data(ErlNifEnv* env)
{
@@ -54,6 +55,7 @@ static void init(ErlNifEnv* env)
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");
+ am_return = enif_make_atom(env, "return");
}
static void add_call_with_arg(ErlNifEnv* env, NifModPrivData* data, const char* func_name,
@@ -105,19 +107,15 @@ static void resource_dtor_B(ErlNifEnv* env, void* 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)
+static void open_resource_type(ErlNifEnv* env, const ERL_NIF_TERM* arr)
{
NifModPrivData* data = priv_data(env);
- const ERL_NIF_TERM* arr;
- int arity;
char rt_name[30];
union { 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(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);
@@ -147,18 +145,32 @@ static void open_resource_type(ErlNifEnv* env, ERL_NIF_TERM op_tpl)
CHECK(got_res.e == exp_res.e);
}
-static void do_load_info(ErlNifEnv* env, ERL_NIF_TERM load_info)
+static void do_load_info(ErlNifEnv* env, ERL_NIF_TERM load_info, int* retvalp)
{
NifModPrivData* data = 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);
+ const ERL_NIF_TERM* arr;
+ int arity;
+
+ CHECK(enif_get_tuple(env, head, &arity, &arr));
+ switch (arity) {
+ case 6:
+ open_resource_type(env, arr);
+ break;
+ case 2:
+ CHECK(arr[0] == am_return);
+ CHECK(enif_get_int(env, arr[1], retvalp));
+ break;
+ default:
+ CHECK(0);
+ }
}
CHECK(enif_is_empty_list(env, head));
}
@@ -166,6 +178,7 @@ static void do_load_info(ErlNifEnv* env, ERL_NIF_TERM load_info)
static int load(ErlNifEnv* env, void** priv, ERL_NIF_TERM load_info)
{
NifModPrivData* data;
+ int retval = 0;
init(env);
data = (NifModPrivData*) enif_alloc(sizeof(NifModPrivData));
@@ -177,38 +190,41 @@ static int load(ErlNifEnv* env, void** priv, ERL_NIF_TERM load_info)
add_call(env, data, "load");
- do_load_info(env, load_info);
- data->calls = 0;
- return 0;
+ do_load_info(env, load_info, &retval);
+ if (retval)
+ NifModPrivData_release(data);
+ return retval;
}
static int reload(ErlNifEnv* env, void** priv, ERL_NIF_TERM load_info)
{
NifModPrivData* data = (NifModPrivData*) *priv;
+ int retval = 0;
init(env);
add_call(env, data, "reload");
- do_load_info(env, load_info);
- return 0;
+ do_load_info(env, load_info, &retval);
+ return retval;
}
static int upgrade(ErlNifEnv* env, void** priv, void** old_priv_data, ERL_NIF_TERM load_info)
{
NifModPrivData* data = (NifModPrivData*) *old_priv_data;
+ int retval = 0;
init(env);
add_call(env, data, "upgrade");
data->ref_cnt++;
*priv = *old_priv_data;
- do_load_info(env, load_info);
+ do_load_info(env, load_info, &retval);
- return 0;
+ return retval;
}
static void unload(ErlNifEnv* env, void* priv)
{
NifModPrivData* data = (NifModPrivData*) priv;
- int is_last;
+
add_call(env, data, "unload");
NifModPrivData_release(data);
}
diff --git a/erts/emulator/test/nif_SUITE_data/nif_mod.h b/erts/emulator/test/nif_SUITE_data/nif_mod.h
index cd0ecf4b54..fb14fee815 100644
--- a/erts/emulator/test/nif_SUITE_data/nif_mod.h
+++ b/erts/emulator/test/nif_SUITE_data/nif_mod.h
@@ -14,7 +14,6 @@ typedef struct call_info_t
typedef struct
{
ErlNifMutex* mtx;
- int calls;
int ref_cnt;
CallInfo* call_history;
ErlNifResourceType* rt_arr[RT_MAX];
@@ -28,6 +27,11 @@ typedef struct
enif_mutex_unlock((NMPD)->mtx); \
if (is_last) { \
enif_mutex_destroy((NMPD)->mtx); \
+ while ((NMPD)->call_history) { \
+ CallInfo* next = (NMPD)->call_history->next; \
+ enif_free((NMPD)->call_history); \
+ (NMPD)->call_history = next; \
+ } \
enif_free((NMPD)); \
} \
}while (0)
diff --git a/erts/emulator/utils/make_version b/erts/emulator/utils/make_version
index 02b68f2b39..0ba1c77930 100755
--- a/erts/emulator/utils/make_version
+++ b/erts/emulator/utils/make_version
@@ -39,10 +39,10 @@ if ($ARGV[0] eq '-o') {
}
my $release = shift;
-defined $release or die "No release specified";
+defined $release or die "No otp release specified";
-my $correction_package = shift;
-defined $correction_package or die "No correction package specified";
+my $otp_version = shift;
+defined $otp_version or die "No otp version specified";
my $version = shift;
defined $version or die "No version name specified";
@@ -56,7 +56,7 @@ open(FILE, ">$outputfile") or die "Can't create $outputfile: $!";
print FILE <<EOF;
/* This file was created by 'make_version' -- don't modify. */
#define ERLANG_OTP_RELEASE "$release"
-#define ERLANG_OTP_CORRECTION_PACKAGE "$correction_package"
+#define ERLANG_OTP_VERSION "$otp_version"
#define ERLANG_VERSION "$version"
#define ERLANG_COMPILE_DATE "$time_str"
#define ERLANG_ARCHITECTURE "$architecture"
diff --git a/erts/etc/common/Makefile.in b/erts/etc/common/Makefile.in
index 5c1ce51644..83560735bc 100644
--- a/erts/etc/common/Makefile.in
+++ b/erts/etc/common/Makefile.in
@@ -1,7 +1,7 @@
#
# %CopyrightBegin%
#
-# Copyright Ericsson AB 1996-2012. All Rights Reserved.
+# Copyright Ericsson AB 1996-2014. 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
@@ -488,7 +488,7 @@ ifneq ($(INSTALL_SRC),)
$(INSTALL_DATA) $(INSTALL_SRC) "$(RELEASE_PATH)/erts-$(VSN)/src"
endif
ifneq ($(INSTALL_EMBEDDED_DATA),)
- $(INSTALL_DATA) $(INSTALL_EMBEDDED_DATA) "$(RELEASE_PATH)/erts-$(VSN)/bin"
+ $(INSTALL_SCRIPT) $(INSTALL_EMBEDDED_DATA) "$(RELEASE_PATH)/erts-$(VSN)/bin"
endif
ifneq ($(INSTALL_LIBS),)
$(INSTALL_DATA) $(INSTALL_LIBS) "$(RELEASE_PATH)/erts-$(VSN)/bin"
diff --git a/erts/etc/win32/nsis/erlang.nsi b/erts/etc/win32/nsis/erlang.nsi
index f4fd2b4cdb..162e634148 100644
--- a/erts/etc/win32/nsis/erlang.nsi
+++ b/erts/etc/win32/nsis/erlang.nsi
@@ -93,6 +93,7 @@ SectionIn 1 RO
skip_silent_mode:
SetOutPath "$INSTDIR"
+ File "${TESTROOT}\OTP_VERSION"
File "${TESTROOT}\Install.ini"
File "${TESTROOT}\Install.exe"
File /r "${TESTROOT}\releases"
diff --git a/erts/etc/win32/nsis/erlang20.nsi b/erts/etc/win32/nsis/erlang20.nsi
index 3333c4a9aa..3ee33e8121 100644
--- a/erts/etc/win32/nsis/erlang20.nsi
+++ b/erts/etc/win32/nsis/erlang20.nsi
@@ -144,6 +144,7 @@ Section "Development" SecErlangDev
SectionIn 1 RO
SetOutPath "$INSTDIR"
+ File "${TESTROOT}\OTP_VERSION"
File "${TESTROOT}\Install.ini"
File "${TESTROOT}\Install.exe"
SetOutPath "$INSTDIR\releases"
diff --git a/erts/start_scripts/Makefile b/erts/start_scripts/Makefile
index 32e65a227f..14d5d46195 100644
--- a/erts/start_scripts/Makefile
+++ b/erts/start_scripts/Makefile
@@ -52,7 +52,7 @@ endif
##############################################################################
# Get version numbers from the VSN files
-# VSN & SYSTEM_VSN
+# VSN
include ../vsn.mk
include $(LIBPATH)/kernel/vsn.mk
include $(LIBPATH)/stdlib/vsn.mk
diff --git a/erts/test/Makefile b/erts/test/Makefile
index 74a5bb1ccc..6fbc19fcae 100644
--- a/erts/test/Makefile
+++ b/erts/test/Makefile
@@ -1,7 +1,7 @@
#
# %CopyrightBegin%
#
-# Copyright Ericsson AB 1997-2012. All Rights Reserved.
+# Copyright Ericsson AB 1997-2014. 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
@@ -36,7 +36,8 @@ MODULES= \
erl_print_SUITE \
run_erl_SUITE \
erlexec_SUITE \
- z_SUITE
+ z_SUITE \
+ upgrade_SUITE
ERL_FILES= $(MODULES:%=%.erl)
diff --git a/erts/test/upgrade_SUITE.erl b/erts/test/upgrade_SUITE.erl
new file mode 100644
index 0000000000..ee84a5dfd7
--- /dev/null
+++ b/erts/test/upgrade_SUITE.erl
@@ -0,0 +1,447 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2014. 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(upgrade_SUITE).
+
+-compile(export_all).
+
+-include_lib("common_test/include/ct.hrl").
+-include_lib("kernel/include/file.hrl").
+
+-define(upgr_sname,otp_upgrade).
+
+%% Applications that are excluded from this test because they can not
+%% just be started in a new node with out specific configuration.
+-define(start_exclude,
+ [cosEvent,cosEventDomain,cosFileTransfer,cosNotification,
+ cosProperty,cosTime,cosTransactions,erts,ic,netconf,orber,
+ safe]).
+
+%% Applications that are excluded from this test because their appup
+%% file don't support the upgrade.
+%% In specific:
+%% - hipe does not support any upgrade at all
+%% - dialyzer requires hipe (in the .app file)
+%% - typer requires hipe (in the .app file)
+-define(appup_exclude,
+ [dialyzer,hipe,typer]).
+
+init_per_suite(Config) ->
+ %% Check that a real release is running, not e.g. cerl
+ ok = application:ensure_started(sasl),
+ case release_handler:which_releases() of
+ [{_,_,[],_}] ->
+ %% Fake release, no applications
+ {skip, "Need a real release running to create other releases"};
+ _ ->
+ rm_rf(filename:join([?config(data_dir,Config),priv_dir])),
+ Config
+ end.
+
+init_per_testcase(Case,Config) ->
+ PrivDir = filename:join([?config(data_dir,Config),priv_dir,Case]),
+ CreateDir = filename:join([PrivDir,create]),
+ InstallDir = filename:join([PrivDir,install]),
+ ok = filelib:ensure_dir(filename:join(CreateDir,"*")),
+ ok = filelib:ensure_dir(filename:join(InstallDir,"*")),
+ Config1 = lists:keyreplace(priv_dir,1,Config,{priv_dir,PrivDir}),
+ [{create_dir,CreateDir},{install_dir,InstallDir}|Config1].
+
+end_per_testcase(_Case,Config) ->
+ Nodes = nodes(),
+ [test_server:stop_node(Node) || Node <- Nodes],
+ case ?config(tc_status,Config) of
+ ok ->
+ %% Note that priv_dir here is per test case!
+ rm_rf(?config(priv_dir,Config));
+ _fail ->
+ %% Test case data can be found under DataDir/priv_dir/Case
+ ok
+ end,
+ ok.
+
+all() ->
+ [minor,major].
+
+%% If this is major release X, then this test performs an upgrade from
+%% major release X-1 to the current release.
+major(Config) ->
+ Current = erlang:system_info(otp_release),
+ PreviousMajor = previous_major(Current),
+ upgrade_test(PreviousMajor,Current,Config).
+
+%% If this is a patched version of major release X, then this test
+%% performs an upgrade from major release X to the current release.
+minor(Config) ->
+ CurrentMajor = erlang:system_info(otp_release),
+ Current = CurrentMajor++"_patched",
+ upgrade_test(CurrentMajor,Current,Config).
+
+%%%-----------------------------------------------------------------
+upgrade_test(FromVsn,ToVsn,Config) ->
+ OldRel =
+ case test_server:is_release_available(FromVsn) of
+ true ->
+ {release,FromVsn};
+ false ->
+ case ct:get_config({otp_releases,list_to_atom(FromVsn)}) of
+ undefined ->
+ false;
+ Prog0 ->
+ case os:find_executable(Prog0) of
+ false ->
+ false;
+ Prog ->
+ {prog,Prog}
+ end
+ end
+ end,
+ case OldRel of
+ false ->
+ %% Note that priv_dir here is per test case!
+ rm_rf(?config(priv_dir,Config)),
+ {skip, "no previous release available"};
+ _ ->
+ upgrade_test1(FromVsn,ToVsn,[{old_rel,OldRel}|Config])
+ end.
+
+upgrade_test1(FromVsn,ToVsn,Config) ->
+ CreateDir = ?config(create_dir,Config),
+ InstallDir = ?config(install_dir,Config),
+ FromRelName = "otp-"++FromVsn,
+ ToRelName = "otp-"++ToVsn,
+
+ {FromRel,FromApps} = target_system(FromRelName, FromVsn,
+ CreateDir, InstallDir,Config),
+ {ToRel,ToApps} = upgrade_system(FromRel, ToRelName, ToVsn,
+ CreateDir, InstallDir),
+ do_upgrade(FromVsn, FromApps, ToRel, ToApps, InstallDir).
+
+%%%-----------------------------------------------------------------
+%%% This is similar to sasl/examples/src/target_system.erl, but with
+%%% the following adjustments:
+%%% - add a log directory
+%%% - use an own 'start' script
+%%% - chmod 'start' and 'start_erl'
+target_system(RelName0,RelVsn,CreateDir,InstallDir,Config) ->
+ {ok,Node} = test_server:start_node(list_to_atom(RelName0),peer,
+ [{erl,[?config(old_rel,Config)]}]),
+
+ {RelName,Apps,ErtsVsn} = create_relfile(Node,CreateDir,RelName0,RelVsn),
+
+ %% Create .script and .boot
+ ok = rpc:call(Node,systools,make_script,[RelName]),
+
+ %% Create base tar file - i.e. erts and all apps
+ ok = rpc:call(Node,systools,make_tar,
+ [RelName,[{erts,rpc:call(Node,code,root_dir,[])}]]),
+
+ %% Unpack the tar to complete the installation
+ erl_tar:extract(RelName ++ ".tar.gz", [{cwd, InstallDir}, compressed]),
+
+ %% Add bin and log dirs
+ BinDir = filename:join([InstallDir, "bin"]),
+ file:make_dir(BinDir),
+ file:make_dir(filename:join(InstallDir,"log")),
+
+ %% Delete start scripts - they will be added later
+ ErtsBinDir = filename:join([InstallDir, "erts-" ++ ErtsVsn, "bin"]),
+ file:delete(filename:join([ErtsBinDir, "erl"])),
+ file:delete(filename:join([ErtsBinDir, "start"])),
+ file:delete(filename:join([ErtsBinDir, "start_erl"])),
+
+ %% Copy .boot to bin/start.boot
+ copy_file(RelName++".boot",filename:join([BinDir, "start.boot"])),
+
+ %% Copy scripts from erts-xxx/bin to bin
+ copy_file(filename:join([ErtsBinDir, "epmd"]),
+ filename:join([BinDir, "epmd"]), [preserve]),
+ copy_file(filename:join([ErtsBinDir, "run_erl"]),
+ filename:join([BinDir, "run_erl"]), [preserve]),
+ copy_file(filename:join([ErtsBinDir, "to_erl"]),
+ filename:join([BinDir, "to_erl"]), [preserve]),
+
+ %% create start_erl.data and sys.config
+ StartErlData = filename:join([InstallDir, "releases", "start_erl.data"]),
+ write_file(StartErlData, io_lib:fwrite("~s ~s~n", [ErtsVsn, RelVsn])),
+ SysConfig = filename:join([InstallDir, "releases", RelVsn, "sys.config"]),
+ write_file(SysConfig, "[]."),
+
+ %% Insert 'start' script from data_dir - modified to add sname and heart
+ copy_file(filename:join(?config(data_dir,Config),"start.src"),
+ filename:join(ErtsBinDir,"start.src")),
+ ok = file:change_mode(filename:join(ErtsBinDir,"start.src"),8#0755),
+
+ %% Make start_erl executable
+ %% (this has been fixed in OTP 17 - is is now installed with
+ %% $INSTALL_SCRIPT instead of $INSTALL_DATA and should therefore
+ %% be executable from the start)
+ ok = file:change_mode(filename:join(ErtsBinDir,"start_erl.src"),8#0755),
+
+ %% Substitute variables in erl.src, start.src and start_erl.src
+ %% (.src found in erts-xxx/bin - result stored in bin)
+ subst_src_scripts(["erl", "start", "start_erl"], ErtsBinDir, BinDir,
+ [{"FINAL_ROOTDIR", InstallDir}, {"EMU", "beam"}],
+ [preserve]),
+
+ %% Create RELEASES
+ RelFile = filename:join([InstallDir, "releases",
+ filename:basename(RelName) ++ ".rel"]),
+ release_handler:create_RELEASES(InstallDir, RelFile),
+
+ true = test_server:stop_node(Node),
+
+ {RelName,Apps}.
+
+%%%-----------------------------------------------------------------
+%%% Create a release containing the current (the test node) OTP
+%%% release, including relup to allow upgrade from an earlier OTP
+%%% release.
+upgrade_system(FromRel, ToRelName0, ToVsn,
+ CreateDir, InstallDir) ->
+
+ {RelName,Apps,_} = create_relfile(node(),CreateDir,ToRelName0,ToVsn),
+ FromPath = filename:join([InstallDir,lib,"*",ebin]),
+
+ ok = systools:make_script(RelName),
+ ok = systools:make_relup(RelName,[FromRel],[FromRel],
+ [{path,[FromPath]},
+ {outdir,CreateDir}]),
+ SysConfig = filename:join([CreateDir, "sys.config"]),
+ write_file(SysConfig, "[]."),
+
+ ok = systools:make_tar(RelName,[{erts,code:root_dir()}]),
+
+ {RelName,Apps}.
+
+%%%-----------------------------------------------------------------
+%%% Start a new node running the release from target_system/5
+%%% above. Then upgrade to the system from upgrade_system/5.
+do_upgrade(FromVsn,FromApps,ToRel,ToApps,InstallDir) ->
+ Start = filename:join([InstallDir,bin,start]),
+ {ok,Node} = start_node(Start,permanent,FromVsn,FromApps),
+
+ [{"OTP upgrade test",FromVsn,_,permanent}] =
+ rpc:call(Node,release_handler,which_releases,[]),
+ {ok,ToVsn} = rpc:call(Node,release_handler,unpack_release,[ToRel]),
+ [{"OTP upgrade test",ToVsn,_,unpacked},
+ {"OTP upgrade test",FromVsn,_,permanent}] =
+ rpc:call(Node,release_handler,which_releases,[]),
+ case rpc:call(Node,release_handler,install_release,[ToVsn]) of
+ {ok,FromVsn,_} ->
+ ok;
+ {continue_after_restart,FromVsn,_} ->
+ wait_node_up(current,ToVsn,ToApps)
+ end,
+ [{"OTP upgrade test",ToVsn,_,current},
+ {"OTP upgrade test",FromVsn,_,permanent}] =
+ rpc:call(Node,release_handler,which_releases,[]),
+ ok = rpc:call(Node,release_handler,make_permanent,[ToVsn]),
+ [{"OTP upgrade test",ToVsn,_,permanent},
+ {"OTP upgrade test",FromVsn,_,old}] =
+ rpc:call(Node,release_handler,which_releases,[]),
+
+ erlang:monitor_node(Node,true),
+ _ = rpc:call(Node,init,stop,[]),
+ receive {nodedown,Node} -> ok end,
+
+ ok.
+
+%%%-----------------------------------------------------------------
+%%% Library functions
+previous_major("17") ->
+ "r16";
+previous_major(Rel) ->
+ integer_to_list(list_to_integer(Rel)-1).
+
+create_relfile(Node,CreateDir,RelName0,RelVsn) ->
+ LibDir = rpc:call(Node,code,lib_dir,[]),
+ SplitLibDir = filename:split(LibDir),
+ Paths = rpc:call(Node,code,get_path,[]),
+ Exclude = ?start_exclude ++ ?appup_exclude,
+ Apps = lists:flatmap(
+ fun(Path) ->
+ case lists:prefix(LibDir,Path) of
+ true ->
+ case filename:split(Path) -- SplitLibDir of
+ [AppVsn,"ebin"] ->
+ case string:tokens(AppVsn,"-") of
+ [AppStr,Vsn] ->
+ App = list_to_atom(AppStr),
+ case lists:member(App,Exclude) of
+ true ->
+ [];
+ false ->
+ [{App,Vsn,restart_type(App)}]
+ end;
+ _ ->
+ []
+ end;
+ _ ->
+ []
+ end;
+ false ->
+ []
+ end
+ end,
+ Paths),
+
+ ErtsVsn = rpc:call(Node, erlang, system_info, [version]),
+
+ %% Create the .rel file
+ RelContent = {release, {"OTP upgrade test", RelVsn}, {erts, ErtsVsn}, Apps},
+ RelName = filename:join(CreateDir,RelName0),
+ RelFile = RelName++".rel",
+ {ok,Fd} = file:open(RelFile,[write,{encoding,utf8}]),
+ io:format(Fd,"~tp.~n",[RelContent]),
+ ok = file:close(Fd),
+ {RelName,Apps,ErtsVsn}.
+
+restart_type(App) when App==kernel; App==stdlib; App==sasl ->
+ permanent;
+restart_type(_) ->
+ temporary.
+
+copy_file(Src, Dest) ->
+ copy_file(Src, Dest, []).
+
+copy_file(Src, Dest, Opts) ->
+ {ok,_} = file:copy(Src, Dest),
+ case lists:member(preserve, Opts) of
+ true ->
+ {ok, FileInfo} = file:read_file_info(Src),
+ file:write_file_info(Dest, FileInfo);
+ false ->
+ ok
+ end.
+
+
+write_file(FName, Conts) ->
+ Enc = file:native_name_encoding(),
+ {ok, Fd} = file:open(FName, [write]),
+ file:write(Fd, unicode:characters_to_binary(Conts,Enc,Enc)),
+ file:close(Fd).
+
+
+subst_src_scripts(Scripts, SrcDir, DestDir, Vars, Opts) ->
+ lists:foreach(fun(Script) ->
+ subst_src_script(Script, SrcDir, DestDir,
+ Vars, Opts)
+ end, Scripts).
+
+subst_src_script(Script, SrcDir, DestDir, Vars, Opts) ->
+ subst_file(filename:join([SrcDir, Script ++ ".src"]),
+ filename:join([DestDir, Script]),
+ Vars, Opts).
+
+subst_file(Src, Dest, Vars, Opts) ->
+ {ok, Bin} = file:read_file(Src),
+ Conts = binary_to_list(Bin),
+ NConts = subst(Conts, Vars),
+ write_file(Dest, NConts),
+ case lists:member(preserve, Opts) of
+ true ->
+ {ok, FileInfo} = file:read_file_info(Src),
+ file:write_file_info(Dest, FileInfo);
+ false ->
+ ok
+ end.
+
+%% subst(Str, Vars)
+%% Vars = [{Var, Val}]
+%% Var = Val = string()
+%% Substitute all occurrences of %Var% for Val in Str, using the list
+%% of variables in Vars.
+%%
+subst(Str, Vars) ->
+ subst(Str, Vars, []).
+
+subst([$%, C| Rest], Vars, Result) when $A =< C, C =< $Z ->
+ subst_var([C| Rest], Vars, Result, []);
+subst([$%, C| Rest], Vars, Result) when $a =< C, C =< $z ->
+ subst_var([C| Rest], Vars, Result, []);
+subst([$%, C| Rest], Vars, Result) when C == $_ ->
+ subst_var([C| Rest], Vars, Result, []);
+subst([C| Rest], Vars, Result) ->
+ subst(Rest, Vars, [C| Result]);
+subst([], _Vars, Result) ->
+ lists:reverse(Result).
+
+subst_var([$%| Rest], Vars, Result, VarAcc) ->
+ Key = lists:reverse(VarAcc),
+ case lists:keysearch(Key, 1, Vars) of
+ {value, {Key, Value}} ->
+ subst(Rest, Vars, lists:reverse(Value, Result));
+ false ->
+ subst(Rest, Vars, [$%| VarAcc ++ [$%| Result]])
+ end;
+subst_var([C| Rest], Vars, Result, VarAcc) ->
+ subst_var(Rest, Vars, Result, [C| VarAcc]);
+subst_var([], Vars, Result, VarAcc) ->
+ subst([], Vars, [VarAcc ++ [$%| Result]]).
+
+
+%%%-----------------------------------------------------------------
+%%%
+start_node(Start,ExpStatus,ExpVsn,ExpApps) ->
+ case open_port({spawn_executable, Start}, []) of
+ Port when is_port(Port) ->
+ unlink(Port),
+ erlang:port_close(Port),
+ wait_node_up(ExpStatus,ExpVsn,ExpApps);
+ Error ->
+ Error
+ end.
+
+wait_node_up(ExpStatus,ExpVsn,ExpApps0) ->
+ ExpApps = [{A,V} || {A,V,_T} <- ExpApps0],
+ Node = node_name(?upgr_sname),
+ wait_node_up(Node,ExpStatus,ExpVsn,lists:keysort(1,ExpApps),60).
+
+wait_node_up(Node,ExpStatus,ExpVsn,ExpApps,0) ->
+ ct:fail({app_check_failed,ExpVsn,ExpApps,
+ rpc:call(Node,release_handler,which_releases,[ExpStatus]),
+ rpc:call(Node,application,which_applications,[])});
+wait_node_up(Node,ExpStatus,ExpVsn,ExpApps,N) ->
+ timer:sleep(2000),
+ case {rpc:call(Node,release_handler,which_releases,[ExpStatus]),
+ rpc:call(Node, application, which_applications, [])} of
+ {[{_,ExpVsn,_,_}],Apps} when is_list(Apps) ->
+ case [{A,V} || {A,_,V} <- lists:keysort(1,Apps)] of
+ ExpApps -> {ok,Node};
+ _ -> wait_node_up(Node,ExpStatus,ExpVsn,ExpApps,N-1)
+ end;
+ _ ->
+ wait_node_up(Node,ExpStatus,ExpVsn,ExpApps,N-1)
+ end.
+
+node_name(Sname) ->
+ {ok,Host} = inet:gethostname(),
+ list_to_atom(atom_to_list(Sname) ++ "@" ++ Host).
+
+rm_rf(Dir) ->
+ case file:read_file_info(Dir) of
+ {ok, #file_info{type = directory}} ->
+ {ok, Content} = file:list_dir_all(Dir),
+ [rm_rf(filename:join(Dir,C)) || C <- Content],
+ ok=file:del_dir(Dir),
+ ok;
+ {ok, #file_info{}} ->
+ ok=file:delete(Dir);
+ _ ->
+ ok
+ end.
diff --git a/erts/test/upgrade_SUITE_data/start.src b/erts/test/upgrade_SUITE_data/start.src
new file mode 100644
index 0000000000..70d1a322c9
--- /dev/null
+++ b/erts/test/upgrade_SUITE_data/start.src
@@ -0,0 +1,36 @@
+#!/bin/sh
+#
+# %CopyrightBegin%
+#
+# Copyright Ericsson AB 2014. 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%
+#
+# This program invokes the erlang emulator by calling run_erl.
+# It should only be used at an embedded target system.
+# It should be modified to give the correct flags to erl (via start_erl),
+# e.g -mode embedded -sname XXX
+#
+# Usage: start [Data]
+#
+ROOTDIR=%FINAL_ROOTDIR%
+
+if [ -z "$RELDIR" ]
+then
+ RELDIR=$ROOTDIR/releases
+fi
+
+START_ERL_DATA=${1:-$RELDIR/start_erl.data}
+
+$ROOTDIR/bin/run_erl -daemon /tmp/ $ROOTDIR/log "exec $ROOTDIR/bin/start_erl $ROOTDIR $RELDIR $START_ERL_DATA -sname otp_upgrade -heart"
diff --git a/erts/vsn.mk b/erts/vsn.mk
index 88a393f3d5..081fb66398 100644
--- a/erts/vsn.mk
+++ b/erts/vsn.mk
@@ -19,11 +19,6 @@
VSN = 6.0
-# OTP major version
-SYSTEM_VSN = 17
-# OTP correction package version
-SYSTEM_CP_VSN = 17.0-rc1
-
# Port number 4365 in 4.2
# Port number 4366 in 4.3
# Port number 4368 in 4.4.0 - 4.6.2