aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Makefile.in23
-rw-r--r--OTP_VERSION2
-rw-r--r--erts/Makefile4
-rw-r--r--erts/emulator/beam/beam_emu.c11
-rw-r--r--erts/emulator/beam/beam_load.c7
-rw-r--r--erts/emulator/beam/break.c42
-rw-r--r--erts/emulator/beam/dist.c165
-rw-r--r--erts/emulator/beam/dist.h1
-rw-r--r--erts/emulator/beam/erl_bif_info.c1
-rw-r--r--erts/emulator/beam/erl_gc.c24
-rw-r--r--erts/emulator/beam/erl_init.c5
-rw-r--r--erts/emulator/beam/erl_lock_check.c3
-rw-r--r--erts/emulator/beam/erl_message.c24
-rw-r--r--erts/emulator/beam/erl_message.h2
-rw-r--r--erts/emulator/beam/erl_node_tables.c2
-rw-r--r--erts/emulator/beam/erl_proc_sig_queue.c11
-rw-r--r--erts/emulator/beam/erl_process.c45
-rw-r--r--erts/emulator/beam/erl_process.h3
-rw-r--r--erts/emulator/beam/erl_process_dump.c14
-rw-r--r--erts/emulator/beam/erl_vm.h7
-rw-r--r--erts/emulator/beam/ops.tab2
-rw-r--r--erts/emulator/sys/common/erl_poll.c4
-rw-r--r--erts/emulator/test/binary_SUITE.erl11
-rw-r--r--erts/emulator/test/distribution_SUITE.erl38
-rw-r--r--erts/emulator/test/dump_SUITE.erl98
-rw-r--r--erts/emulator/test/efile_SUITE.erl7
-rw-r--r--erts/emulator/test/erts_test_utils.erl1
-rw-r--r--erts/emulator/test/fun_SUITE.erl4
-rw-r--r--erts/emulator/test/process_SUITE.erl9
-rw-r--r--erts/etc/unix/etp-commands.in6
-rw-r--r--lib/common_test/test_server/configure.in25
-rw-r--r--lib/compiler/src/beam_ssa_type.erl23
-rw-r--r--lib/compiler/src/beam_validator.erl10
-rw-r--r--lib/compiler/src/sys_core_fold.erl45
-rw-r--r--lib/compiler/test/beam_type_SUITE.erl18
-rw-r--r--lib/compiler/test/bs_construct_SUITE.erl18
-rw-r--r--lib/compiler/test/bs_match_SUITE.erl18
-rw-r--r--lib/compiler/test/compile_SUITE.erl4
-rw-r--r--lib/compiler/test/test_lib.erl11
-rw-r--r--lib/compiler/test/trycatch_SUITE.erl27
-rw-r--r--lib/inets/test/httpc_SUITE.erl20
-rw-r--r--lib/kernel/test/code_SUITE.erl9
-rw-r--r--lib/observer/test/observer_SUITE.erl3
-rw-r--r--lib/wx/src/Makefile4
-rw-r--r--system/doc/design_principles/statem.xml2
-rw-r--r--system/doc/reference_manual/expressions.xml8
46 files changed, 532 insertions, 289 deletions
diff --git a/Makefile.in b/Makefile.in
index 49a0d9f8af..6cbd92a55b 100644
--- a/Makefile.in
+++ b/Makefile.in
@@ -492,31 +492,14 @@ else
$(MAKE) opt BUILD_ALL=true
$(V_at)test -f $(ERL_TOP)/make/otp_built || echo "OTP built" > $(ERL_TOP)/make/otp_built
endif
-kernel:
- $(make_verbose)cd lib/kernel && \
- ERL_TOP=$(ERL_TOP) PATH=$(BOOT_PREFIX)"$${PATH}" \
- $(MAKE) opt BUILD_ALL=true
-stdlib:
- $(make_verbose)cd lib/stdlib && \
- ERL_TOP=$(ERL_TOP) PATH=$(BOOT_PREFIX)"$${PATH}" \
- $(MAKE) opt BUILD_ALL=true
+APPS=$(patsubst $(ERL_TOP)/lib/%/doc,%,$(wildcard $(ERL_TOP)/lib/*/doc))
-compiler:
- $(make_verbose)cd lib/compiler && \
+$(APPS):
+ $(make_verbose)cd lib/$@ && \
ERL_TOP=$(ERL_TOP) PATH=$(BOOT_PREFIX)"$${PATH}" \
$(MAKE) opt BUILD_ALL=true
-hipe:
- $(make_verbose)cd lib/hipe && \
- ERL_TOP=$(ERL_TOP) PATH=$(BOOT_PREFIX)"$${PATH}" \
- $(MAKE) opt BUILD_ALL=true
-
-syntax_tools:
- $(make_verbose)cd lib/syntax_tools && \
- ERL_TOP=$(ERL_TOP) PATH=$(BOOT_PREFIX)"$${PATH}" \
- $(MAKE) opt BUILD_ALL=true
-
preloaded:
$(make_verbose)cd erts/preloaded/src && \
ERL_TOP=$(ERL_TOP) PATH=$(BOOT_PREFIX)"$${PATH}" \
diff --git a/OTP_VERSION b/OTP_VERSION
index da0a41680b..a5a30a3cfe 100644
--- a/OTP_VERSION
+++ b/OTP_VERSION
@@ -1 +1 @@
-22.0-rc1
+22.0-rc2
diff --git a/erts/Makefile b/erts/Makefile
index 60c70b6a2c..e62c896170 100644
--- a/erts/Makefile
+++ b/erts/Makefile
@@ -129,9 +129,13 @@ makefiles:
.PHONY: release
release:
+ifeq ($(TYPE),)
for t in $(TYPES); do \
( cd emulator && $(MAKE) release TYPE=$$t ) || exit $$?; \
done
+else
+ ( cd emulator && $(MAKE) release TYPE=$(TYPE) ) || exit $$?;
+endif
$(V_at)for d in $(ERTSDIRS) $(XINSTDIRS); do \
if test -d $$d; then \
( cd $$d && $(MAKE) $@ ) || exit $$? ; \
diff --git a/erts/emulator/beam/beam_emu.c b/erts/emulator/beam/beam_emu.c
index 73bf443372..f1d8609066 100644
--- a/erts/emulator/beam/beam_emu.c
+++ b/erts/emulator/beam/beam_emu.c
@@ -1480,7 +1480,16 @@ next_catch(Process* c_p, Eterm *reg) {
ptr = prev = c_p->stop;
ASSERT(ptr <= STACK_START(c_p));
- if (ptr == STACK_START(c_p)) return NULL;
+
+ /* This function is only called if we have active catch tags or have
+ * previously called a function that was exception-traced. As the exception
+ * trace flag isn't cleared after the traced function returns (and the
+ * catch tag inserted by it is gone), it's possible to land here with an
+ * empty stack, and the process should simply die when that happens. */
+ if (ptr == STACK_START(c_p)) {
+ ASSERT(!active_catches && IS_TRACED_FL(c_p, F_EXCEPTION_TRACE));
+ return NULL;
+ }
/*
* Better safe than sorry here. In debug builds, produce a core
diff --git a/erts/emulator/beam/beam_load.c b/erts/emulator/beam/beam_load.c
index d0936060b8..941c3ebbbe 100644
--- a/erts/emulator/beam/beam_load.c
+++ b/erts/emulator/beam/beam_load.c
@@ -3145,6 +3145,13 @@ is_killed(LoaderState* stp, GenOpArg Reg, GenOpArg Live)
Live.val <= Reg.val;
}
+static int
+is_killed_by_call_fun(LoaderState* stp, GenOpArg Reg, GenOpArg Live)
+{
+ return Reg.type == TAG_x && Live.type == TAG_u &&
+ Live.val+1 <= Reg.val;
+}
+
/*
* Test whether register Reg is killed by make_fun instruction that
* creates the fun given by index idx.
diff --git a/erts/emulator/beam/break.c b/erts/emulator/beam/break.c
index 27bf2187c2..06d8c7cda8 100644
--- a/erts/emulator/beam/break.c
+++ b/erts/emulator/beam/break.c
@@ -39,6 +39,7 @@
#include "erl_hl_timer.h"
#include "erl_thr_progress.h"
#include "erl_proc_sig_queue.h"
+#include "dist.h"
/* Forward declarations -- should really appear somewhere else */
static void process_killer(void);
@@ -74,6 +75,7 @@ port_info(fmtfn_t to, void *to_arg)
void
process_info(fmtfn_t to, void *to_arg)
{
+ ErtsSchedulerData *esdp = erts_get_scheduler_data();
int i, max = erts_ptab_max(&erts_proc);
for (i = 0; i < max; i++) {
Process *p = erts_pix2proc(i);
@@ -81,11 +83,35 @@ process_info(fmtfn_t to, void *to_arg)
/* Do not include processes with no heap,
* they are most likely just created and has invalid data
*/
- if (!ERTS_PROC_IS_EXITING(p) && p->heap != NULL)
- print_process_info(to, to_arg, p, 0);
+ if (p->heap != NULL) {
+ ErtsProcLocks locks = (p == esdp->current_process ||
+ p == esdp->free_process) ? ERTS_PROC_LOCK_MAIN : 0;
+ print_process_info(to, to_arg, p, locks);
+ }
}
}
+ /* Look for FREE processes in the run-queues and dist entries.
+ These have been removed from the ptab but we still want them
+ in the crash dump for debugging. */
+
+ /* First loop through all run-queues */
+ for (i = 0; i < erts_no_schedulers + ERTS_NUM_DIRTY_RUNQS; i++) {
+ ErtsRunQueue *rq = ERTS_RUNQ_IX(i);
+ int j;
+ for (j = 0; j < ERTS_NO_PROC_PRIO_QUEUES; j++) {
+ Process *p = rq->procs.prio[j].first;
+ while (p) {
+ if (ERTS_PSFLG_FREE & erts_atomic32_read_acqb(&p->state))
+ print_process_info(to, to_arg, p, 0);
+ p = p->next;
+ }
+ }
+ }
+
+ /* Then check all dist entries */
+ erts_dist_print_procs_suspended_on_de(to, to_arg);
+
port_info(to, to_arg);
}
@@ -199,13 +225,14 @@ static int doit_print_monitor(ErtsMonitor *mon, void *vpcontext, Sint reds)
}
return 1;
}
-
+
/* Display info about an individual Erlang process */
void
print_process_info(fmtfn_t to, void *to_arg, Process *p, ErtsProcLocks orig_locks)
{
int garbing = 0;
int running = 0;
+ int exiting = 0;
Sint len;
struct saved_calls *scb;
erts_aint32_t state;
@@ -226,9 +253,12 @@ print_process_info(fmtfn_t to, void *to_arg, Process *p, ErtsProcLocks orig_lock
| ERTS_PSFLG_DIRTY_RUNNING))
running = 1;
+ if (state & ERTS_PSFLG_EXITING)
+ exiting = 1;
+
if (!(locks & ERTS_PROC_LOCK_MAIN)) {
locks |= ERTS_PROC_LOCK_MAIN;
- if (ERTS_IS_CRASH_DUMPING && running) {
+ if (ERTS_IS_CRASH_DUMPING) {
if (erts_proc_trylock(p, locks)) {
/* crash dumping and main lock taken, this probably means that
the process is doing a GC on a dirty-scheduler... so we cannot
@@ -246,7 +276,7 @@ print_process_info(fmtfn_t to, void *to_arg, Process *p, ErtsProcLocks orig_lock
* If the process is registered as a global process, display the
* registered name
*/
- if (p->common.u.alive.reg)
+ if (!ERTS_PROC_IS_EXITING(p) && p->common.u.alive.reg)
erts_print(to, to_arg, "Name: %T\n", p->common.u.alive.reg->name);
/*
@@ -332,7 +362,7 @@ print_process_info(fmtfn_t to, void *to_arg, Process *p, ErtsProcLocks orig_lock
}
/* display the links only if there are any*/
- if (ERTS_P_LINKS(p) || ERTS_P_MONITORS(p) || ERTS_P_LT_MONITORS(p)) {
+ if (!exiting && (ERTS_P_LINKS(p) || ERTS_P_MONITORS(p) || ERTS_P_LT_MONITORS(p))) {
PrintMonitorContext context = {1, to, to_arg};
erts_print(to, to_arg,"Link list: [");
erts_link_tree_foreach(ERTS_P_LINKS(p), doit_print_link, &context);
diff --git a/erts/emulator/beam/dist.c b/erts/emulator/beam/dist.c
index a1da1addf9..8bbe6450eb 100644
--- a/erts/emulator/beam/dist.c
+++ b/erts/emulator/beam/dist.c
@@ -772,77 +772,25 @@ void init_dist(void)
#define ErtsDistOutputBuf2Binary(OB) OB->bin
-#ifdef DEBUG
-
-struct obuf_list;
-struct obuf_list {
- erts_refc_t refc;
- struct obuf_list *next;
- struct obuf_list *prev;
-};
-#define obuf_list_size sizeof(struct obuf_list)
-static struct obuf_list *erts_obuf_list = NULL;
-static erts_mtx_t erts_obuf_list_mtx;
-
-static void
-insert_obuf(struct obuf_list *obuf, erts_aint_t initial) {
- erts_mtx_lock(&erts_obuf_list_mtx);
- obuf->next = erts_obuf_list;
- obuf->prev = NULL;
- erts_refc_init(&obuf->refc, initial);
- if (erts_obuf_list)
- erts_obuf_list->prev = obuf;
- erts_obuf_list = obuf;
- erts_mtx_unlock(&erts_obuf_list_mtx);
-}
-
-static void
-remove_obuf(struct obuf_list *obuf) {
- if (erts_refc_dectest(&obuf->refc, 0) == 0) {
- erts_mtx_lock(&erts_obuf_list_mtx);
- if (obuf->prev) {
- obuf->prev->next = obuf->next;
- } else {
- erts_obuf_list = obuf->next;
- }
- if (obuf->next) obuf->next->prev = obuf->prev;
- erts_mtx_unlock(&erts_obuf_list_mtx);
- }
-}
-
-void check_obuf(void);
-void check_obuf(void) {
- erts_mtx_lock(&erts_obuf_list_mtx);
- ERTS_ASSERT(erts_obuf_list == NULL);
- erts_mtx_unlock(&erts_obuf_list_mtx);
-}
-#else
-#define insert_obuf(...)
-#define remove_obuf(...)
-#define obuf_list_size 0
-#endif
-
static ERTS_INLINE ErtsDistOutputBuf *
alloc_dist_obuf(Uint size, Uint headers)
{
int i;
ErtsDistOutputBuf *obuf;
Uint obuf_size = sizeof(ErtsDistOutputBuf)*(headers) +
- sizeof(byte)*size + obuf_list_size;
+ sizeof(byte)*size;
Binary *bin = erts_bin_drv_alloc(obuf_size);
- size += obuf_list_size;
obuf = (ErtsDistOutputBuf *) &bin->orig_bytes[size];
erts_refc_add(&bin->intern.refc, headers - 1, 1);
for (i = 0; i < headers; i++) {
obuf[i].bin = bin;
- obuf[i].extp = (byte *)&bin->orig_bytes[0] + obuf_list_size;
+ obuf[i].extp = (byte *)&bin->orig_bytes[0];
#ifdef DEBUG
obuf[i].dbg_pattern = ERTS_DIST_OUTPUT_BUF_DBG_PATTERN;
obuf[i].alloc_endp = obuf->extp + size;
ASSERT(bin == ErtsDistOutputBuf2Binary(obuf));
#endif
}
- insert_obuf((struct obuf_list*)&bin->orig_bytes[0], headers);
return obuf;
}
@@ -851,10 +799,7 @@ free_dist_obuf(ErtsDistOutputBuf *obuf)
{
Binary *bin = ErtsDistOutputBuf2Binary(obuf);
ASSERT(obuf->dbg_pattern == ERTS_DIST_OUTPUT_BUF_DBG_PATTERN);
- remove_obuf((struct obuf_list*)&bin->orig_bytes[0]);
- if (erts_refc_dectest(&bin->intern.refc, 0) == 0) {
- erts_bin_free(bin);
- }
+ erts_bin_release(bin);
}
static ERTS_INLINE Sint
@@ -1968,6 +1913,7 @@ int erts_net_message(Port *prt,
goto invalid_message;
}
reason = tuple[5];
+ edep = NULL;
}
if (is_not_ref(ref))
@@ -2014,12 +1960,14 @@ int erts_net_message(Port *prt,
}
token = NIL;
reason = tuple[4];
+ edep = NULL;
} else if (type == DOP_EXIT_TT){
if (tuple_arity != 5) {
goto invalid_message;
}
token = tuple[4];
reason = tuple[5];
+ edep = NULL;
} else if (type == DOP_PAYLOAD_EXIT) {
if (tuple_arity != 3) {
goto invalid_message;
@@ -2067,12 +2015,14 @@ int erts_net_message(Port *prt,
}
reason = tuple[4];
token = NIL;
+ edep = NULL;
} else if (type == DOP_EXIT2_TT) {
if (tuple_arity != 5) {
goto invalid_message;
}
token = tuple[4];
reason = tuple[5];
+ edep = NULL;
} else if (type == DOP_PAYLOAD_EXIT2) {
if (tuple_arity != 3) {
goto invalid_message;
@@ -2430,8 +2380,8 @@ erts_dsig_send(ErtsDSigSendContext *ctx)
case ERTS_DSIG_SEND_PHASE_FIN: {
ASSERT(ctx->obuf->extp < ctx->obuf->ext_endp);
- ASSERT(((byte*)&ctx->obuf->bin->orig_bytes[0]+obuf_list_size) <= ctx->obuf->extp - ctx->max_finalize_prepend);
- ASSERT(ctx->obuf->ext_endp <= ((byte*)ctx->obuf->bin->orig_bytes+obuf_list_size) + ctx->data_size + ctx->dhdr_ext_size);
+ ASSERT(((byte*)&ctx->obuf->bin->orig_bytes[0]) <= ctx->obuf->extp - ctx->max_finalize_prepend);
+ ASSERT(ctx->obuf->ext_endp <= ((byte*)ctx->obuf->bin->orig_bytes) + ctx->data_size + ctx->dhdr_ext_size);
ctx->data_size = ctx->obuf->ext_endp - ctx->obuf->extp;
@@ -2935,7 +2885,9 @@ erts_dist_command(Port *prt, int initial_reds)
ob = oq.first;
ASSERT(ob);
do {
+ obufsize += size_obuf(ob);
reds = erts_encode_ext_dist_header_finalize(ob, dep, flags, reds);
+ obufsize -= size_obuf(ob);
if (reds < 0)
break;
last_finalized = ob;
@@ -2974,7 +2926,9 @@ erts_dist_command(Port *prt, int initial_reds)
while (oq.first && !preempt) {
ErtsDistOutputBuf *fob;
Uint size;
+ obufsize += size_obuf(oq.first);
reds = erts_encode_ext_dist_header_finalize(oq.first, dep, flags, reds);
+ obufsize -= size_obuf(oq.first);
if (reds < 0) {
preempt = 1;
break;
@@ -3407,14 +3361,13 @@ dist_ctrl_get_data_1(BIF_ALIST_1)
{
DistEntry *dep = ERTS_PROC_GET_DIST_ENTRY(BIF_P);
const Sint initial_reds = ERTS_BIF_REDS_LEFT(BIF_P);
- Sint reds = initial_reds;
+ Sint reds = initial_reds, obufsize = 0;
ErtsDistOutputBuf *obuf;
- Eterm *hp;
+ Eterm *hp, res;
ProcBin *pb;
erts_aint_t qsize;
Uint32 conn_id, get_size;
- Eterm res;
- Uint hsz, bin_sz;
+ Uint hsz = 0, bin_sz;
if (!dep)
BIF_ERROR(BIF_P, EXC_NOTSUP);
@@ -3466,7 +3419,9 @@ dist_ctrl_get_data_1(BIF_ALIST_1)
}
obuf = dep->tmp_out_queue.first;
+ obufsize += size_obuf(obuf);
reds = erts_encode_ext_dist_header_finalize(obuf, dep, dep->flags, reds);
+ obufsize -= size_obuf(obuf);
if (reds < 0) {
erts_de_runlock(dep);
ERTS_BIF_YIELD1(bif_export[BIF_dist_ctrl_get_data_1],
@@ -3482,8 +3437,7 @@ dist_ctrl_get_data_1(BIF_ALIST_1)
erts_de_runlock(dep);
- bin_sz = obuf->ext_endp - obuf->extp;
- hsz = PROC_BIN_SIZE;
+ bin_sz = obuf->ext_endp - obuf->extp + obuf->hdr_endp - obuf->hdrp;
get_size = dep->opts & ERTS_DIST_CTRL_OPT_GET_SIZE;
if (get_size) {
@@ -3492,18 +3446,50 @@ dist_ctrl_get_data_1(BIF_ALIST_1)
hsz += BIG_UINT_HEAP_SIZE;
}
- hp = HAlloc(BIF_P, hsz);
- pb = (ProcBin *) (char *) hp;
- pb->thing_word = HEADER_PROC_BIN;
- pb->size = bin_sz;
- pb->next = MSO(BIF_P).first;
- MSO(BIF_P).first = (struct erl_off_heap_header*) pb;
- pb->val = ErtsDistOutputBuf2Binary(obuf);
- pb->bytes = (byte*) obuf->extp;
- pb->flags = 0;
- hp += PROC_BIN_SIZE;
+ if (!obuf->hdrp) {
+ hp = HAlloc(BIF_P, PROC_BIN_SIZE + hsz);
+ pb = (ProcBin *) (char *) hp;
+ pb->thing_word = HEADER_PROC_BIN;
+ pb->size = obuf->ext_endp - obuf->extp;
+ pb->next = MSO(BIF_P).first;
+ MSO(BIF_P).first = (struct erl_off_heap_header*) pb;
+ pb->val = ErtsDistOutputBuf2Binary(obuf);
+ pb->bytes = (byte*) obuf->extp;
+ pb->flags = 0;
+ res = make_binary(pb);
+ } else {
+ hp = HAlloc(BIF_P, PROC_BIN_SIZE * 2 + 4 + hsz);
+ pb = (ProcBin *) (char *) hp;
+ pb->thing_word = HEADER_PROC_BIN;
+ pb->size = obuf->ext_endp - obuf->extp;
+ pb->next = MSO(BIF_P).first;
+ MSO(BIF_P).first = (struct erl_off_heap_header*) pb;
+ pb->val = ErtsDistOutputBuf2Binary(obuf);
+ pb->bytes = (byte*) obuf->extp;
+ pb->flags = 0;
+ hp += PROC_BIN_SIZE;
+
+ res = CONS(hp, make_binary(pb), NIL);
+ hp += 2;
+
+ pb = (ProcBin *) (char *) hp;
+ pb->thing_word = HEADER_PROC_BIN;
+ pb->size = obuf->hdr_endp - obuf->hdrp;
+ pb->next = MSO(BIF_P).first;
+ MSO(BIF_P).first = (struct erl_off_heap_header*) pb;
+ pb->val = ErtsDistOutputBuf2Binary(obuf);
+ erts_refc_inc(&pb->val->intern.refc, 1);
+ pb->bytes = (byte*) obuf->hdrp;
+ pb->flags = 0;
+ hp += PROC_BIN_SIZE;
+ res = CONS(hp, make_binary(pb), res);
+ hp += 2;
+ }
+
+ obufsize += size_obuf(obuf);
+
+ qsize = erts_atomic_add_read_nob(&dep->qsize, (erts_aint_t) -obufsize);
- qsize = erts_atomic_add_read_nob(&dep->qsize, -size_obuf(obuf));
ASSERT(qsize >= 0);
if (qsize < erts_dist_buf_busy_limit/2
@@ -3518,8 +3504,6 @@ dist_ctrl_get_data_1(BIF_ALIST_1)
}
}
- res = make_binary(pb);
-
if (get_size) {
Eterm sz_term;
if (IS_USMALL(0, bin_sz))
@@ -4711,10 +4695,6 @@ init_nodes_monitors(void)
{
erts_mtx_init(&nodes_monitors_mtx, "nodes_monitors", NIL,
ERTS_LOCK_FLAGS_PROPERTY_STATIC | ERTS_LOCK_FLAGS_CATEGORY_DISTRIBUTION);
-#ifdef DEBUG
- erts_mtx_init(&erts_obuf_list_mtx, "sad", NIL,
- ERTS_LOCK_FLAGS_PROPERTY_STATIC | ERTS_LOCK_FLAGS_CATEGORY_DISTRIBUTION);
-#endif
nodes_monitors = NULL;
no_nodes_monitors = 0;
}
@@ -5105,3 +5085,22 @@ erts_processes_monitoring_nodes(Process *c_p)
return ctxt.res;
}
+
+static void
+print_suspended_on_de(fmtfn_t to, void *to_arg, DistEntry *dep)
+{
+ for (; dep; dep = dep->next) {
+ ErtsProcList *curr = erts_proclist_peek_first(dep->suspended);
+ while (curr) {
+ if (!is_internal_pid(curr->u.pid))
+ print_process_info(to, to_arg, curr->u.p, 0);
+ curr = erts_proclist_peek_next(dep->suspended, curr);
+ }
+ }
+}
+
+void
+erts_dist_print_procs_suspended_on_de(fmtfn_t to, void *to_arg) {
+ print_suspended_on_de(to, to_arg, erts_hidden_dist_entries);
+ print_suspended_on_de(to, to_arg, erts_visible_dist_entries);
+}
diff --git a/erts/emulator/beam/dist.h b/erts/emulator/beam/dist.h
index 9b5e62ab7e..f953a2ab8c 100644
--- a/erts/emulator/beam/dist.h
+++ b/erts/emulator/beam/dist.h
@@ -319,5 +319,6 @@ extern int erts_dsig_prepare(ErtsDSigSendContext *,
int,
int);
+void erts_dist_print_procs_suspended_on_de(fmtfn_t to, void *to_arg);
int erts_auto_connect(DistEntry* dep, Process *proc, ErtsProcLocks proc_locks);
#endif
diff --git a/erts/emulator/beam/erl_bif_info.c b/erts/emulator/beam/erl_bif_info.c
index 504aa8f943..a7424bbcb8 100644
--- a/erts/emulator/beam/erl_bif_info.c
+++ b/erts/emulator/beam/erl_bif_info.c
@@ -4442,6 +4442,7 @@ BIF_RETTYPE erts_debug_set_internal_state_2(BIF_ALIST_2)
BIF_P->fcalls = reds;
else
BIF_P->fcalls = reds - CONTEXT_REDS;
+ BIF_P->scheduler_data->virtual_reds = 0;
}
BIF_RET(am_true);
}
diff --git a/erts/emulator/beam/erl_gc.c b/erts/emulator/beam/erl_gc.c
index 9317850d96..67a73e4d57 100644
--- a/erts/emulator/beam/erl_gc.c
+++ b/erts/emulator/beam/erl_gc.c
@@ -577,7 +577,7 @@ force_reschedule:
}
static ERTS_FORCE_INLINE Uint
-young_gen_usage(Process *p)
+young_gen_usage(Process *p, Uint *ext_msg_usage)
{
Uint hsz;
Eterm *aheap;
@@ -604,7 +604,10 @@ young_gen_usage(Process *p)
if (ERTS_SIG_IS_MSG(mp)
&& mp->data.attached
&& mp->data.attached != ERTS_MSG_COMBINED_HFRAG) {
- hsz += erts_msg_attached_data_size(mp);
+ Uint sz = erts_msg_attached_data_size(mp);
+ if (ERTS_SIG_IS_EXTERNAL_MSG(mp))
+ *ext_msg_usage += sz;
+ hsz += sz;
}
});
}
@@ -676,6 +679,7 @@ garbage_collect(Process* p, ErlHeapFragment *live_hf_end,
{
Uint reclaimed_now = 0;
Uint ygen_usage;
+ Uint ext_msg_usage = 0;
Eterm gc_trace_end_tag;
int reds;
ErtsMonotonicTime start_time;
@@ -698,7 +702,7 @@ garbage_collect(Process* p, ErlHeapFragment *live_hf_end,
return delay_garbage_collection(p, live_hf_end, need, fcalls);
}
- ygen_usage = max_young_gen_usage ? max_young_gen_usage : young_gen_usage(p);
+ ygen_usage = max_young_gen_usage ? max_young_gen_usage : young_gen_usage(p, &ext_msg_usage);
if (!ERTS_SCHEDULER_IS_DIRTY(esdp)) {
check_for_possibly_long_gc(p, ygen_usage);
@@ -739,7 +743,7 @@ garbage_collect(Process* p, ErlHeapFragment *live_hf_end,
trace_gc(p, am_gc_minor_start, need, THE_NON_VALUE);
}
DTRACE2(gc_minor_start, pidbuf, need);
- reds = minor_collection(p, live_hf_end, need, objv, nobj,
+ reds = minor_collection(p, live_hf_end, need + ext_msg_usage, objv, nobj,
ygen_usage, &reclaimed_now);
DTRACE2(gc_minor_end, pidbuf, reclaimed_now);
if (reds == -1) {
@@ -764,7 +768,7 @@ do_major_collection:
trace_gc(p, am_gc_major_start, need, THE_NON_VALUE);
}
DTRACE2(gc_major_start, pidbuf, need);
- reds = major_collection(p, live_hf_end, need, objv, nobj,
+ reds = major_collection(p, live_hf_end, need + ext_msg_usage, objv, nobj,
ygen_usage, &reclaimed_now);
if (ERTS_SCHEDULER_IS_DIRTY(esdp))
p->flags &= ~(F_DIRTY_MAJOR_GC|F_DIRTY_MINOR_GC);
@@ -1101,6 +1105,7 @@ erts_garbage_collect_literals(Process* p, Eterm* literals,
Eterm* old_htop;
Uint n;
Uint ygen_usage = 0;
+ Uint ext_msg_usage = 0;
struct erl_off_heap_header** prev = NULL;
Sint64 reds;
int hibernated = !!(p->flags & F_HIBERNATED);
@@ -1118,7 +1123,7 @@ erts_garbage_collect_literals(Process* p, Eterm* literals,
p->flags &= ~F_DIRTY_CLA;
else {
Uint size = byte_lit_size/sizeof(Uint);
- ygen_usage = young_gen_usage(p);
+ ygen_usage = young_gen_usage(p, &ext_msg_usage);
if (hibernated)
size = size*2 + 3*ygen_usage;
else
@@ -1130,7 +1135,7 @@ erts_garbage_collect_literals(Process* p, Eterm* literals,
}
}
- reds = (Sint64) garbage_collect(p, ERTS_INVALID_HFRAG_PTR, 0,
+ reds = (Sint64) garbage_collect(p, ERTS_INVALID_HFRAG_PTR, ext_msg_usage,
p->arg_reg, p->arity, fcalls,
ygen_usage);
if (ERTS_PROC_IS_EXITING(p)) {
@@ -1348,6 +1353,9 @@ minor_collection(Process* p, ErlHeapFragment *live_hf_end,
Eterm *mature = p->abandoned_heap ? p->abandoned_heap : p->heap;
Uint mature_size = p->high_water - mature;
Uint size_before = ygen_usage;
+#ifdef DEBUG
+ Uint debug_tmp = 0;
+#endif
/*
* Check if we have gone past the max heap size limit
@@ -1484,7 +1492,7 @@ minor_collection(Process* p, ErlHeapFragment *live_hf_end,
process from there */
ASSERT(!MAX_HEAP_SIZE_GET(p) ||
!(MAX_HEAP_SIZE_FLAGS_GET(p) & MAX_HEAP_SIZE_KILL) ||
- MAX_HEAP_SIZE_GET(p) > (young_gen_usage(p) +
+ MAX_HEAP_SIZE_GET(p) > (young_gen_usage(p, &debug_tmp) +
(OLD_HEND(p) - OLD_HEAP(p)) +
(HEAP_END(p) - HEAP_TOP(p))));
diff --git a/erts/emulator/beam/erl_init.c b/erts/emulator/beam/erl_init.c
index 82d5140d1c..12750b9aa6 100644
--- a/erts/emulator/beam/erl_init.c
+++ b/erts/emulator/beam/erl_init.c
@@ -2417,17 +2417,12 @@ erts_exit_vv(int n, int flush_async, char *fmt, va_list args1, va_list args2)
erts_exit_epilogue();
}
-void check_obuf(void);
__decl_noreturn void __noreturn erts_exit_epilogue(void)
{
int n = erts_exit_code;
sys_tty_reset(n);
-#ifdef DEBUG
- check_obuf();
-#endif
-
if (n == ERTS_INTR_EXIT)
exit(0);
else if (n == ERTS_DUMP_EXIT)
diff --git a/erts/emulator/beam/erl_lock_check.c b/erts/emulator/beam/erl_lock_check.c
index 39eabb6710..3aab4828cc 100644
--- a/erts/emulator/beam/erl_lock_check.c
+++ b/erts/emulator/beam/erl_lock_check.c
@@ -164,8 +164,7 @@ static erts_lc_lock_order_t erts_lock_order[] = {
{ "os_monotonic_time", NULL },
{ "erts_alloc_hard_debug", NULL },
{ "hard_dbg_mseg", NULL },
- { "erts_mmap", NULL },
- { "sad", NULL}
+ { "erts_mmap", NULL }
};
#define ERTS_LOCK_ORDER_SIZE \
diff --git a/erts/emulator/beam/erl_message.c b/erts/emulator/beam/erl_message.c
index e350a20339..2a0fb9e2aa 100644
--- a/erts/emulator/beam/erl_message.c
+++ b/erts/emulator/beam/erl_message.c
@@ -1137,10 +1137,28 @@ change_to_off_heap:
return res;
}
-void erts_factory_proc_init(ErtsHeapFactory* factory,
- Process* p)
+void erts_factory_proc_init(ErtsHeapFactory* factory, Process* p)
{
- erts_factory_proc_prealloc_init(factory, p, HEAP_LIMIT(p) - HEAP_TOP(p));
+ /* This function does not use HAlloc to allocate on the heap
+ as we do not want to use INIT_HEAP_MEM on the allocated
+ heap as that completely destroys the DEBUG emulators
+ performance. */
+ ErlHeapFragment *bp = p->mbuf;
+ factory->mode = FACTORY_HALLOC;
+ factory->p = p;
+ factory->hp_start = HEAP_TOP(p);
+ factory->hp = factory->hp_start;
+ factory->hp_end = HEAP_LIMIT(p);
+ factory->off_heap = &p->off_heap;
+ factory->message = NULL;
+ factory->off_heap_saved.first = p->off_heap.first;
+ factory->off_heap_saved.overhead = p->off_heap.overhead;
+ factory->heap_frags_saved = bp;
+ factory->heap_frags_saved_used = bp ? bp->used_size : 0;
+ factory->heap_frags = NULL; /* not used */
+ factory->alloc_type = 0; /* not used */
+
+ HEAP_TOP(p) = HEAP_LIMIT(p);
}
void erts_factory_proc_prealloc_init(ErtsHeapFactory* factory,
diff --git a/erts/emulator/beam/erl_message.h b/erts/emulator/beam/erl_message.h
index e5f623a370..5bd25737a7 100644
--- a/erts/emulator/beam/erl_message.h
+++ b/erts/emulator/beam/erl_message.h
@@ -22,6 +22,7 @@
#define __ERL_MESSAGE_H__
#include "sys.h"
+#include "erl_vm.h"
#define ERTS_PROC_SIG_QUEUE_TYPE_ONLY
#include "erl_proc_sig_queue.h"
#undef ERTS_PROC_SIG_QUEUE_TYPE_ONLY
@@ -117,6 +118,7 @@ erts_produce_heap(ErtsHeapFactory* factory, Uint need, Uint xtra)
}
res = factory->hp;
factory->hp += need;
+ INIT_HEAP_MEM(res, need);
return res;
}
diff --git a/erts/emulator/beam/erl_node_tables.c b/erts/emulator/beam/erl_node_tables.c
index 215dc6fa71..49dea8919b 100644
--- a/erts/emulator/beam/erl_node_tables.c
+++ b/erts/emulator/beam/erl_node_tables.c
@@ -2295,7 +2295,7 @@ reference_table_term(Uint **hpp, ErlOffHeap *ohp, Uint *szp)
tup = MK_2TUP(AM_ets, drp->id);
}
else {
- ASSERT(!drp->ctrl_ref && drp->node_ref && !drp->signal_ref);
+ ASSERT(!drp->ctrl_ref && (drp->node_ref || drp->sequence_ref) && !drp->signal_ref);
ASSERT(is_atom(drp->id));
tup = MK_2TUP(drp->id, MK_UINT(drp->creation));
tup = MK_2TUP(AM_node, tup);
diff --git a/erts/emulator/beam/erl_proc_sig_queue.c b/erts/emulator/beam/erl_proc_sig_queue.c
index bd59c4afa3..4e9f177e51 100644
--- a/erts/emulator/beam/erl_proc_sig_queue.c
+++ b/erts/emulator/beam/erl_proc_sig_queue.c
@@ -611,7 +611,8 @@ proc_queue_signal(Process *c_p, Eterm pid, ErtsSignal *sig, int op)
#endif
return 1;
}
- ASSERT(esdp->pending_signal.dbg_from == esdp->current_process);
+ ASSERT(esdp->pending_signal.dbg_from == esdp->current_process ||
+ esdp->pending_signal.dbg_from == esdp->free_process);
if (pend_sig != sig) {
/* Switch them and send previously pending signal instead */
Eterm pend_to = esdp->pending_signal.to;
@@ -3973,6 +3974,9 @@ clear_seq_trace_token(ErtsMessage *sig)
case ERTS_MON_TYPE_PROC:
case ERTS_MON_TYPE_DIST_PROC:
case ERTS_MON_TYPE_NODE:
+ case ERTS_MON_TYPE_NODES:
+ case ERTS_MON_TYPE_SUSPEND:
+ case ERTS_MON_TYPE_TIME_OFFSET:
break;
default:
ERTS_INTERNAL_ERROR("Unexpected sig type");
@@ -3989,6 +3993,11 @@ clear_seq_trace_token(ErtsMessage *sig)
case ERTS_SIG_Q_OP_LINK:
case ERTS_SIG_Q_OP_UNLINK:
case ERTS_SIG_Q_OP_TRACE_CHANGE_STATE:
+ case ERTS_SIG_Q_OP_GROUP_LEADER:
+ case ERTS_SIG_Q_OP_IS_ALIVE:
+ case ERTS_SIG_Q_OP_PROCESS_INFO:
+ case ERTS_SIG_Q_OP_SYNC_SUSPEND:
+ case ERTS_SIG_Q_OP_RPC:
break;
default:
diff --git a/erts/emulator/beam/erl_process.c b/erts/emulator/beam/erl_process.c
index f34289339f..9e662632b4 100644
--- a/erts/emulator/beam/erl_process.c
+++ b/erts/emulator/beam/erl_process.c
@@ -12090,9 +12090,11 @@ erts_proc_exit_handle_dist_monitor(ErtsMonitor *mon, void *vctxt, Sint reds)
ErtsDSigSendContext ctx;
ErtsMonLnkDist *dist;
DistEntry *dep;
- Eterm watcher;
+ Eterm watcher, ref, *hp;
ErtsMonitorData *mdp = NULL;
Eterm watched;
+ Uint watcher_sz, ref_sz;
+ ErtsHeapFactory factory;
ASSERT(erts_monitor_is_target(mon) && mon->type == ERTS_MON_TYPE_DIST_PROC);
@@ -12124,10 +12126,18 @@ erts_proc_exit_handle_dist_monitor(ErtsMonitor *mon, void *vctxt, Sint reds)
case ERTS_DSIG_PREP_CONNECTED:
if (dist->connection_id != ctx.connection_id)
break;
+ erts_factory_proc_init(&factory, c_p);
+ watcher_sz = size_object(watcher);
+ hp = erts_produce_heap(&factory, watcher_sz, 0);
+ watcher = copy_struct(watcher, watcher_sz, &hp, factory.off_heap);
+ ref_sz = size_object(mdp->ref);
+ hp = erts_produce_heap(&factory, ref_sz, 0);
+ ref = copy_struct(mdp->ref, ref_sz, &hp, factory.off_heap);
+ erts_factory_close(&factory);
code = erts_dsig_send_m_exit(&ctx,
watcher,
watched,
- mdp->ref,
+ ref,
reason);
switch (code) {
case ERTS_DSIG_SEND_CONTINUE:
@@ -12332,13 +12342,15 @@ erts_proc_exit_handle_dist_link(ErtsLink *lnk, void *vctxt, Sint reds)
{
ErtsProcExitContext *ctxt = (ErtsProcExitContext *) vctxt;
Process *c_p = ctxt->c_p;
- Eterm reason = ctxt->reason;
+ Eterm reason = ctxt->reason, item, *hp;
+ Uint item_sz;
int code;
ErtsDSigSendContext ctx;
ErtsMonLnkDist *dist;
DistEntry *dep;
ErtsLink *dlnk;
ErtsLinkData *ldp = NULL;
+ ErtsHeapFactory factory;
ASSERT(lnk->type == ERTS_LNK_TYPE_DIST_PROC);
dlnk = erts_link_to_other(lnk, &ldp);
@@ -12365,9 +12377,14 @@ erts_proc_exit_handle_dist_link(ErtsLink *lnk, void *vctxt, Sint reds)
case ERTS_DSIG_PREP_CONNECTED:
if (dist->connection_id != ctx.connection_id)
break;
+ erts_factory_proc_init(&factory, c_p);
+ item_sz = size_object(lnk->other.item);
+ hp = erts_produce_heap(&factory, item_sz, 0);
+ item = copy_struct(lnk->other.item, item_sz, &hp, factory.off_heap);
+ erts_factory_close(&factory);
code = erts_dsig_send_exit_tt(&ctx,
c_p->common.id,
- lnk->other.item,
+ item,
reason,
SEQ_TRACE_TOKEN(c_p));
switch (code) {
@@ -12584,6 +12601,8 @@ erts_continue_exit_process(Process *p)
if (p->u.terminate) {
trap_state = p->u.terminate;
+ /* Re-set the reason as it may have been gc:ed */
+ trap_state->reason = p->fvalue;
} else {
trap_state->phase = ERTS_CONTINUE_EXIT_TIMERS;
trap_state->reason = p->fvalue;
@@ -12661,11 +12680,11 @@ restart:
p->flags &= ~F_USING_DB;
}
- erts_set_gc_state(p, 1);
-
trap_state->phase = ERTS_CONTINUE_EXIT_CLEAN_SYS_TASKS;
case ERTS_CONTINUE_EXIT_CLEAN_SYS_TASKS:
-
+
+ /* We enable GC again as it can produce more sys-tasks */
+ erts_set_gc_state(p, 1);
state = erts_atomic32_read_acqb(&p->state);
if ((state & ERTS_PSFLG_SYS_TASKS) || p->dirty_sys_tasks) {
reds -= cleanup_sys_tasks(p, state, reds);
@@ -12788,6 +12807,9 @@ restart:
erts_deref_dist_entry(trap_state->dep);
}
+ /* Disable GC so that reason does not get moved */
+ erts_set_gc_state(p, 0);
+
trap_state->pectxt.c_p = p;
trap_state->pectxt.reason = trap_state->reason;
trap_state->pectxt.dist_links = NULL;
@@ -12872,13 +12894,13 @@ restart:
switch (result) {
case ERTS_DSIG_SEND_OK:
case ERTS_DSIG_SEND_TOO_LRG: /*SEND_SYSTEM_LIMIT*/
- case ERTS_DSIG_SEND_YIELD: /*SEND_YIELD_RETURN*/
break;
+ case ERTS_DSIG_SEND_YIELD: /*SEND_YIELD_RETURN*/
case ERTS_DSIG_SEND_CONTINUE: { /*SEND_YIELD_CONTINUE*/
goto yield;
}
}
- erts_set_gc_state(p, 1);
+
trap_state->pectxt.dist_state = NIL;
if (reds <= 0)
goto yield;
@@ -12917,11 +12939,12 @@ restart:
* From this point on we are no longer allowed to yield
* this process.
*/
-
#ifdef DEBUG
yield_allowed = 0;
#endif
+ erts_set_gc_state(p, 1);
+
/* Set state to not active as we don't want this process
to be scheduled in again after this. */
state = erts_atomic32_read_band_relb(&p->state,
@@ -12960,7 +12983,7 @@ restart:
erts_free(ERTS_ALC_T_CONT_EXIT_TRAP, trap_state);
p->u.terminate = NULL;
}
-
+
ERTS_CHK_HAVE_ONLY_MAIN_PROC_LOCK(p);
if (IS_TRACED_FL(p, F_TRACE_SCHED_EXIT))
diff --git a/erts/emulator/beam/erl_process.h b/erts/emulator/beam/erl_process.h
index 4ffa022d5c..711b73417d 100644
--- a/erts/emulator/beam/erl_process.h
+++ b/erts/emulator/beam/erl_process.h
@@ -1322,9 +1322,6 @@ ERTS_GLB_INLINE void erts_heap_frag_shrink(Process* p, Eterm* hp)
#endif /* inline */
Eterm* erts_heap_alloc(Process* p, Uint need, Uint xtra);
-#ifdef CHECK_FOR_HOLES
-Eterm* erts_set_hole_marker(Eterm* ptr, Uint sz);
-#endif
extern erts_rwmtx_t erts_cpu_bind_rwmtx;
/* If any of the erts_system_monitor_* variables are set (enabled),
diff --git a/erts/emulator/beam/erl_process_dump.c b/erts/emulator/beam/erl_process_dump.c
index a164ed543e..71262061dd 100644
--- a/erts/emulator/beam/erl_process_dump.c
+++ b/erts/emulator/beam/erl_process_dump.c
@@ -121,12 +121,14 @@ Uint erts_process_memory(Process *p, int include_sigs_in_transit)
size += sizeof(Process);
- erts_link_tree_foreach(ERTS_P_LINKS(p),
- link_size, (void *) &size);
- erts_monitor_tree_foreach(ERTS_P_MONITORS(p),
- monitor_size, (void *) &size);
- erts_monitor_list_foreach(ERTS_P_LT_MONITORS(p),
- monitor_size, (void *) &size);
+ if ((erts_atomic32_read_nob(&p->state) & ERTS_PSFLG_EXITING) == 0) {
+ erts_link_tree_foreach(ERTS_P_LINKS(p),
+ link_size, (void *) &size);
+ erts_monitor_tree_foreach(ERTS_P_MONITORS(p),
+ monitor_size, (void *) &size);
+ erts_monitor_list_foreach(ERTS_P_LT_MONITORS(p),
+ monitor_size, (void *) &size);
+ }
size += (p->heap_sz + p->mbuf_sz) * sizeof(Eterm);
if (p->abandoned_heap)
size += (p->hend - p->heap) * sizeof(Eterm);
diff --git a/erts/emulator/beam/erl_vm.h b/erts/emulator/beam/erl_vm.h
index 35eae18394..e623148587 100644
--- a/erts/emulator/beam/erl_vm.h
+++ b/erts/emulator/beam/erl_vm.h
@@ -67,9 +67,10 @@
(unsigned long)HEAP_TOP(p),(sz),__FILE__,__LINE__)), \
*/
# ifdef CHECK_FOR_HOLES
-# define INIT_HEAP_MEM(p,sz) erts_set_hole_marker(HEAP_TOP(p), (sz))
+Eterm* erts_set_hole_marker(Eterm* ptr, Uint sz);
+# define INIT_HEAP_MEM(p,sz) erts_set_hole_marker(p, (sz))
# else
-# define INIT_HEAP_MEM(p,sz) sys_memset(HEAP_TOP(p),0x01,(sz)*sizeof(Eterm*))
+# define INIT_HEAP_MEM(p,sz) sys_memset(p,0x01,(sz)*sizeof(Eterm*))
# endif
#else
# define INIT_HEAP_MEM(p,sz) ((void)0)
@@ -91,7 +92,7 @@
ErtsHAllocLockCheck(p), \
(IS_FORCE_HEAP_FRAGS || (((HEAP_LIMIT(p) - HEAP_TOP(p)) < (sz))) \
? erts_heap_alloc((p),(sz),(xtra)) \
- : (INIT_HEAP_MEM(p,sz), \
+ : (INIT_HEAP_MEM(HEAP_TOP(p),sz), \
HEAP_TOP(p) = HEAP_TOP(p) + (sz), HEAP_TOP(p) - (sz))))
#define HAlloc(P, SZ) HAllocX(P,SZ,0)
diff --git a/erts/emulator/beam/ops.tab b/erts/emulator/beam/ops.tab
index abbddbb41f..7a125b0f67 100644
--- a/erts/emulator/beam/ops.tab
+++ b/erts/emulator/beam/ops.tab
@@ -338,7 +338,7 @@ swap_temp R1 R2 Tmp | line Loc | apply Live | is_killed_apply(Tmp, Live) => \
swap_temp R1 R2 Tmp | line Loc | apply_last Live D | is_killed_apply(Tmp, Live) => \
swap R1 R2 | line Loc | apply_last Live D
-swap_temp R1 R2 Tmp | line Loc | call_fun Live | is_killed(Tmp, Live) => \
+swap_temp R1 R2 Tmp | line Loc | call_fun Live | is_killed_by_call_fun(Tmp, Live) => \
swap R1 R2 | line Loc | call_fun Live
swap_temp R1 R2 Tmp | make_fun2 OldIndex=u | is_killed_by_make_fun(Tmp, OldIndex) => \
swap R1 R2 | make_fun2 OldIndex
diff --git a/erts/emulator/sys/common/erl_poll.c b/erts/emulator/sys/common/erl_poll.c
index c71d23f58c..9662996039 100644
--- a/erts/emulator/sys/common/erl_poll.c
+++ b/erts/emulator/sys/common/erl_poll.c
@@ -2354,6 +2354,7 @@ uint32_t epoll_events(int kp_fd, int fd)
fprintf(stderr,"failed to parse file %s on line %d, errno = %d\n", fname,
line,
errno);
+ fclose(f);
return 0;
}
if (fd == ev_fd) {
@@ -2408,6 +2409,7 @@ ERTS_POLL_EXPORT(erts_poll_get_selected_events)(ErtsPollSet *ps,
if (fscanf(f,"pos:\t%x\nflags:\t%x", &pos, &flags) != 2) {
fprintf(stderr,"failed to parse file %s, errno = %d\n", fname, errno);
ASSERT(0);
+ fclose(f);
return;
}
if (fscanf(f,"\nmnt_id:\t%x\n", &mnt_id));
@@ -2422,6 +2424,7 @@ ERTS_POLL_EXPORT(erts_poll_get_selected_events)(ErtsPollSet *ps,
fprintf(stderr,"failed to parse file %s on line %d, errno = %d\n",
fname, line, errno);
ASSERT(0);
+ fclose(f);
return;
}
if (fd == ps->wake_fds[0] || fd == ps->wake_fds[1])
@@ -2437,6 +2440,7 @@ ERTS_POLL_EXPORT(erts_poll_get_selected_events)(ErtsPollSet *ps,
ev[fd] = (ERTS_POLL_EV_IN|ERTS_POLL_EV_OUT) & ERTS_POLL_EV_N2E(events);
line++;
}
+ fclose(f);
#else
for (fd = 0; fd < len; fd++)
ev[fd] = ERTS_POLL_EV_NONE;
diff --git a/erts/emulator/test/binary_SUITE.erl b/erts/emulator/test/binary_SUITE.erl
index 1406ddc9dc..563d60cc3f 100644
--- a/erts/emulator/test/binary_SUITE.erl
+++ b/erts/emulator/test/binary_SUITE.erl
@@ -1703,13 +1703,16 @@ error_after_yield_bad_ext_term() ->
BadAtomExt]). %% Invalid atom at the end
cmp_old_impl(Config) when is_list(Config) ->
- %% Compare results from new yielding implementations with
- %% old non yielding implementations
+ %% This test was originally a comparison with the non yielding
+ %% implementation in R16B. Since OTP 22 we can't talk distribution with such
+ %% old nodes (< 19). The test case it kept but compares with previous major
+ %% version for semantic regression test.
Cookie = atom_to_list(erlang:get_cookie()),
- Rel = "r16b_latest",
+ Rel = (integer_to_list(list_to_integer(erlang:system_info(otp_release)) - 1)
+ ++ "_latest"),
case test_server:is_release_available(Rel) of
false ->
- {skipped, "No "++Rel++" available"};
+ {skipped, "No OTP "++Rel++" available"};
true ->
{ok, Node} = test_server:start_node(list_to_atom(atom_to_list(?MODULE)++"_"++Rel),
peer,
diff --git a/erts/emulator/test/distribution_SUITE.erl b/erts/emulator/test/distribution_SUITE.erl
index 4f70b51aa0..449821e5ad 100644
--- a/erts/emulator/test/distribution_SUITE.erl
+++ b/erts/emulator/test/distribution_SUITE.erl
@@ -744,6 +744,7 @@ link_to_dead_new_node(Config) when is_list(Config) ->
{'EXIT', Pid, noproc} ->
ok;
Other ->
+ stop_node(Node),
ct:fail({unexpected_message, Other})
after 5000 ->
ct:fail(nothing_received)
@@ -1421,7 +1422,7 @@ message_latency_large_exit(Nodename, ReasonFun) ->
FlushTrace = fun F() ->
receive
- {trace, Pid, _, _} = M ->
+ {trace, Pid, _, _} ->
F()
after 0 ->
ok
@@ -1455,8 +1456,14 @@ measure_latency_large_message(Nodename, DataFun) ->
Echo = spawn(N, fun F() -> receive {From, Msg} -> From ! Msg, F() end end),
- %% Test 32 MB and 320 MB and test the latency difference of sent messages
- Payloads = [{I, <<0:(I * 32 * 1024 * 1024 * 8)>>} || I <- [1,10]],
+ case erlang:system_info(build_type) of
+ debug ->
+ %% Test 3.2 MB and 32 MB and test the latency difference of sent messages
+ Payloads = [{I, <<0:(I * 32 * 1024 * 8)>>} || I <- [1,10]];
+ _ ->
+ %% Test 32 MB and 320 MB and test the latency difference of sent messages
+ Payloads = [{I, <<0:(I * 32 * 1024 * 1024 * 8)>>} || I <- [1,10]]
+ end,
IndexTimes = [{I, measure_latency(DataFun, Dropper, Echo, P)}
|| {I, P} <- Payloads],
@@ -1465,6 +1472,8 @@ measure_latency_large_message(Nodename, DataFun) ->
ct:pal("~p",[IndexTimes]),
+ stop_node(N),
+
case {lists:max(Times), lists:min(Times)} of
{Max, Min} when Max * 0.25 > Min ->
ct:fail({incorrect_latency, IndexTimes});
@@ -1487,7 +1496,7 @@ measure_latency(DataFun, Dropper, Echo, Payload) ->
end) || _ <- lists:seq(1,2)],
[receive
- {monitor, _Sender, busy_dist_port, _Info} = M ->
+ {monitor, _Sender, busy_dist_port, _Info} ->
ok
end || _ <- lists:seq(1,10)],
@@ -1733,7 +1742,7 @@ bad_dist_fragments(Config) when is_list(Config) ->
start_monitor(Offender,P),
Exit2Victim = spawn(Victim, fun() -> receive ok -> ok end end),
- send_bad_fragments(Offender, Victim, P,{?DOP_PAYLOAD_EXIT2,P,ExitVictim},2,
+ send_bad_fragments(Offender, Victim, P,{?DOP_PAYLOAD_EXIT2,P,Exit2Victim},2,
[{hdr, 1, [132]}]),
start_monitor(Offender,P),
@@ -2428,17 +2437,22 @@ stop_node(Node) ->
verify_nc(Node) ->
P = self(),
Ref = make_ref(),
- spawn(Node,
- fun() ->
- R = erts_test_utils:check_node_dist(fun(E) -> E end),
- P ! {Ref, R}
- end),
+ Pid = spawn(Node,
+ fun() ->
+ R = erts_test_utils:check_node_dist(fun(E) -> E end),
+ P ! {Ref, R}
+ end),
+ MonRef = monitor(process, Pid),
receive
{Ref, ok} ->
+ demonitor(MonRef,[flush]),
ok;
{Ref, Error} ->
- ct:log("~s",[Error]),
- ct:fail(failed_nc_refc_check)
+ ct:log("~p",[Error]),
+ ct:fail(failed_nc_refc_check);
+ {'DOWN', MonRef, _, _, _} = Down ->
+ ct:log("~p",[Down]),
+ ct:fail(crashed_nc_refc_check)
end.
freeze_node(Node, MS) ->
diff --git a/erts/emulator/test/dump_SUITE.erl b/erts/emulator/test/dump_SUITE.erl
index d0237b78cc..3b860ebdf6 100644
--- a/erts/emulator/test/dump_SUITE.erl
+++ b/erts/emulator/test/dump_SUITE.erl
@@ -24,7 +24,7 @@
-export([all/0, suite/0, init_per_testcase/2, end_per_testcase/2]).
--export([signal_abort/1]).
+-export([signal_abort/1, exiting_dump/1, free_dump/1]).
-export([load/0]).
@@ -35,7 +35,7 @@ suite() ->
{timetrap, {minutes, 2}}].
all() ->
- [signal_abort].
+ [signal_abort, exiting_dump, free_dump].
init_per_testcase(signal_abort, Config) ->
SO = erlang:system_info(schedulers_online),
@@ -48,7 +48,10 @@ init_per_testcase(signal_abort, Config) ->
{skip, "the platform does not support scheduler dump"};
Dump ->
Config
- end.
+ end;
+init_per_testcase(_, Config) ->
+ Config.
+
end_per_testcase(_, Config) ->
Config.
@@ -79,8 +82,6 @@ signal_abort(Config) ->
{ok, Bin} = get_dump_when_done(Dump),
- ct:log("~s",[Bin]),
-
{match, Matches} = re:run(Bin,"Current Process: <",[global]),
ct:log("Found ~p",[Matches]),
@@ -91,6 +92,85 @@ signal_abort(Config) ->
ok.
+load() ->
+ lists:seq(1,10000),
+ load().
+
+
+%% Test that crash dumping when a process is in the state EXITING works
+exiting_dump(Config) when is_list(Config) ->
+ Dump = filename:join(proplists:get_value(priv_dir, Config),"signal_abort.dump"),
+
+ {ok, Node} = start_node(Config),
+
+ Self = self(),
+
+ Pid = spawn_link(Node,
+ fun() ->
+ [begin
+ T = ets:new(hej,[]),
+ [ets:insert(T,{I,I}) || I <- lists:seq(1,1000)]
+ end || _ <- lists:seq(1,1000)],
+ Self ! ready,
+ receive ok -> ok end
+ end),
+
+ true = rpc:call(Node, os, putenv, ["ERL_CRASH_DUMP",Dump]),
+
+ receive ready -> unlink(Pid), Pid ! ok end,
+
+ rpc:call(Node, erlang, halt, ["dump"]),
+
+ {ok, Bin} = get_dump_when_done(Dump),
+
+ {match, Matches} = re:run(Bin,"^State: Exiting", [global, multiline]),
+
+ ct:log("Found ~p",[Matches]),
+
+ true = length(Matches) == 1,
+
+ file:delete(Dump),
+
+ ok.
+
+%% Test that crash dumping when a process is in the state FREE works
+free_dump(Config) when is_list(Config) ->
+ Dump = filename:join(proplists:get_value(priv_dir, Config),"signal_abort.dump"),
+
+ {ok, Node} = start_node(Config),
+
+ Self = self(),
+
+ Pid = spawn_link(Node,
+ fun() ->
+ Self ! ready,
+ receive
+ ok ->
+ unlink(Self),
+ exit(lists:duplicate(1000,1000))
+ end
+ end),
+
+ true = rpc:call(Node, os, putenv, ["ERL_CRASH_DUMP",Dump]),
+
+ [erlang:monitor(process, Pid) || _ <- lists:seq(1,10000)],
+ receive ready -> unlink(Pid), Pid ! ok end,
+
+ rpc:call(Node, erlang, halt, ["dump"]),
+
+ {ok, Bin} = get_dump_when_done(Dump),
+
+ {match, Matches} = re:run(Bin,"^State: Non Existing", [global, multiline]),
+
+ ct:log("Found ~p",[Matches]),
+
+ true = length(Matches) == 1,
+
+ file:delete(Dump),
+
+ ok.
+
+
get_dump_when_done(Dump) ->
case file:read_file_info(Dump) of
{ok, #file_info{ size = Sz }} ->
@@ -104,15 +184,13 @@ get_dump_when_done(Dump, Sz) ->
timer:sleep(1000),
case file:read_file_info(Dump) of
{ok, #file_info{ size = Sz }} ->
- file:read_file(Dump);
+ {ok, Bin} = file:read_file(Dump),
+ ct:log("~s",[Bin]),
+ {ok, Bin};
{ok, #file_info{ size = NewSz }} ->
get_dump_when_done(Dump, NewSz)
end.
-load() ->
- lists:seq(1,10000),
- load().
-
start_node(Config) when is_list(Config) ->
Pa = filename:dirname(code:which(?MODULE)),
Name = list_to_atom(atom_to_list(?MODULE)
diff --git a/erts/emulator/test/efile_SUITE.erl b/erts/emulator/test/efile_SUITE.erl
index 7dcf302742..55c5343739 100644
--- a/erts/emulator/test/efile_SUITE.erl
+++ b/erts/emulator/test/efile_SUITE.erl
@@ -45,7 +45,12 @@ iter_max_files(Config) when is_list(Config) ->
iter_max_files_1(Config) ->
DataDir = proplists:get_value(data_dir,Config),
TestFile = filename:join(DataDir, "existing_file"),
- N = 10,
+ case erlang:system_info(debug_compiled) of
+ true ->
+ N = 5;
+ false ->
+ N = 10
+ end,
%% Run on a different node in order to make the test more stable.
Dir = filename:dirname(code:which(?MODULE)),
{ok,Node} = test_server:start_node(test_iter_max_files,slave,
diff --git a/erts/emulator/test/erts_test_utils.erl b/erts/emulator/test/erts_test_utils.erl
index 0c3ef3e0fc..e4e00a0a16 100644
--- a/erts/emulator/test/erts_test_utils.erl
+++ b/erts/emulator/test/erts_test_utils.erl
@@ -19,6 +19,7 @@
%%
-module(erts_test_utils).
+-compile(r16).
%%
%% THIS MODULE IS ALSO USED BY *OTHER* APPLICATIONS TEST CODE
diff --git a/erts/emulator/test/fun_SUITE.erl b/erts/emulator/test/fun_SUITE.erl
index 4042b58ff2..7f6caa08f1 100644
--- a/erts/emulator/test/fun_SUITE.erl
+++ b/erts/emulator/test/fun_SUITE.erl
@@ -592,7 +592,8 @@ refc_dist(Config) when is_list(Config) ->
3 = fun_refc(F2),
true = erlang:garbage_collect(),
2 = fun_refc(F),
- refc_dist_send(Node, F).
+ refc_dist_send(Node, F),
+ test_server:stop_node(Node).
refc_dist_send(Node, F) ->
Pid = spawn_link(Node, fun() -> receive
@@ -682,6 +683,7 @@ t_arity(Config) when is_list(Config) ->
43 = spawn_call(Node, fun(X, Y) -> A+X+Y end),
1 = spawn_call(Node, fun(X, Y) -> X+Y end),
45 = spawn_call(Node, fun(X, Y, Z) -> A+X+Y+Z end),
+ test_server:stop_node(Node),
ok.
t_is_function2(Config) when is_list(Config) ->
diff --git a/erts/emulator/test/process_SUITE.erl b/erts/emulator/test/process_SUITE.erl
index edf08ce0bd..c698220013 100644
--- a/erts/emulator/test/process_SUITE.erl
+++ b/erts/emulator/test/process_SUITE.erl
@@ -133,6 +133,15 @@ init_per_group(_GroupName, Config) ->
end_per_group(_GroupName, Config) ->
Config.
+init_per_testcase(Func, Config)
+ when Func =:= processes_default_tab;
+ Func =:= processes_this_tab ->
+ case erlang:system_info(debug_compiled) of
+ true ->
+ {skip, "Don't run in debug"};
+ false ->
+ [{testcase, Func} | Config]
+ end;
init_per_testcase(Func, Config) when is_atom(Func), is_list(Config) ->
[{testcase, Func}|Config].
diff --git a/erts/etc/unix/etp-commands.in b/erts/etc/unix/etp-commands.in
index e8dc59156f..dc28107ef5 100644
--- a/erts/etc/unix/etp-commands.in
+++ b/erts/etc/unix/etp-commands.in
@@ -1453,8 +1453,10 @@ define etp-stack-preamble
set $etp_stack_p = ($arg0)->stop
set $etp_stack_end = ($arg0)->hend
printf "%% Stacktrace (%u)\n", $etp_stack_end-$etp_stack_p
- etp-1 ((Eterm)($arg0)->i) 0
- printf " (I)\n"
+ if ($arg0)->i != 0
+ etp-1 ((Eterm)($arg0)->i) 0
+ printf " (I)\n"
+ end
if ($arg0)->cp != 0
etp-1 ((Eterm)($arg0)->cp) 0
printf " (cp)\n"
diff --git a/lib/common_test/test_server/configure.in b/lib/common_test/test_server/configure.in
index e07bd4c2aa..a32d050081 100644
--- a/lib/common_test/test_server/configure.in
+++ b/lib/common_test/test_server/configure.in
@@ -171,7 +171,7 @@ case $system in
fi
SHLIB_EXTRACT_ALL=""
;;
- *-openbsd*)
+ *-openbsd*|*-netbsd*|*-freebsd*|*-dragonfly*)
# Not available on all versions: check for include file.
AC_CHECK_HEADER(dlfcn.h, [
SHLIB_CFLAGS="-fpic"
@@ -194,29 +194,6 @@ case $system in
])
SHLIB_EXTRACT_ALL=""
;;
- *-netbsd*|*-freebsd*|*-dragonfly*)
- # Not available on all versions: check for include file.
- AC_CHECK_HEADER(dlfcn.h, [
- SHLIB_CFLAGS="-fpic"
- SHLIB_LD="ld"
- SHLIB_LDFLAGS="$LDFLAGS -Bshareable -x"
- SHLIB_SUFFIX=".so"
- if test X${enable_m64_build} = Xyes; then
- AC_MSG_ERROR(don't know how to link 64-bit dynamic drivers)
- fi
- if test X${enable_m32_build} = Xyes; then
- AC_MSG_ERROR(don't know how to link 32-bit dynamic drivers)
- fi
- ], [
- # No dynamic loading.
- SHLIB_CFLAGS=""
- SHLIB_LD="ld"
- SHLIB_LDFLAGS=""
- SHLIB_SUFFIX=""
- AC_MSG_ERROR(don't know how to compile and link dynamic drivers)
- ])
- SHLIB_EXTRACT_ALL=""
- ;;
*-solaris2*|*-sysv4*)
SHLIB_CFLAGS="-KPIC"
SHLIB_LD="/usr/ccs/bin/ld"
diff --git a/lib/compiler/src/beam_ssa_type.erl b/lib/compiler/src/beam_ssa_type.erl
index c01ea4af91..06b42f1928 100644
--- a/lib/compiler/src/beam_ssa_type.erl
+++ b/lib/compiler/src/beam_ssa_type.erl
@@ -267,10 +267,29 @@ opt_is([#b_set{op=call,args=Args0,dst=Dst}=I0|Is],
I1 = beam_ssa:normalize(I0#b_set{args=Args}),
{Ts1,Ds,Fdb,I2} = opt_call(I1, D, Ts0, Ds0, Fdb0),
case {map_get(Dst, Ts1),Is} of
- {_,[#b_set{op=succeeded}]} ->
+ {Type,[#b_set{op=succeeded}]} when Type =/= none ->
%% This call instruction is inside a try/catch
- %% block. Don't attempt to optimize it.
+ %% block. Don't attempt to simplify it.
opt_is(Is, Ts1, Ds, Fdb, D, Sub0, [I2|Acc]);
+ {none,[#b_set{op=succeeded}]} ->
+ %% This call instruction is inside a try/catch
+ %% block, but we know it will never return and
+ %% later optimizations may try to exploit that.
+ %%
+ %% For example, if we have an expression that
+ %% either returns this call or a tuple, we know
+ %% that the expression always returns a tuple
+ %% and can turn a later element/3 into
+ %% get_tuple_element.
+ %%
+ %% This is sound but difficult to validate in a
+ %% meaningful way as try/catch currently forces
+ %% us to maintain the illusion that the success
+ %% block is reachable even when its not, so we
+ %% disable the optimization to keep things
+ %% simple.
+ Ts = Ts1#{ Dst := any },
+ opt_is(Is, Ts, Ds, Fdb, D, Sub0, [I2|Acc]);
{none,_} ->
%% This call never returns. The rest of the
%% instructions will not be executed.
diff --git a/lib/compiler/src/beam_validator.erl b/lib/compiler/src/beam_validator.erl
index 4fba3fa1c6..efd2be94cb 100644
--- a/lib/compiler/src/beam_validator.erl
+++ b/lib/compiler/src/beam_validator.erl
@@ -2899,8 +2899,6 @@ lists_mod_return_type(filter, 2, _Vst) ->
list;
lists_mod_return_type(flatten, 1, _Vst) ->
list;
-lists_mod_return_type(flatten, 2, _Vst) ->
- list;
lists_mod_return_type(map, 2, Vst) ->
same_length_type({x,1}, Vst);
lists_mod_return_type(MF, 3, Vst) when MF =:= mapfoldl; MF =:= mapfoldr ->
@@ -2912,8 +2910,6 @@ lists_mod_return_type(reverse, 1, Vst) ->
same_length_type({x,0}, Vst);
lists_mod_return_type(seq, 2, _Vst) ->
list;
-lists_mod_return_type(seq, 3, _Vst) ->
- list;
lists_mod_return_type(sort, 1, Vst) ->
same_length_type({x,0}, Vst);
lists_mod_return_type(sort, 2, Vst) ->
@@ -2927,16 +2923,10 @@ lists_mod_return_type(unzip, 1, Vst) ->
two_tuple(ListType, ListType);
lists_mod_return_type(usort, 1, Vst) ->
same_length_type({x,0}, Vst);
-lists_mod_return_type(usort, 2, Vst) ->
- same_length_type({x,1}, Vst);
lists_mod_return_type(zip, 2, _Vst) ->
list;
-lists_mod_return_type(zip3, 3, _Vst) ->
- list;
lists_mod_return_type(zipwith, 3, _Vst) ->
list;
-lists_mod_return_type(zipwith3, 4, _Vst) ->
- list;
lists_mod_return_type(_, _, _) ->
term.
diff --git a/lib/compiler/src/sys_core_fold.erl b/lib/compiler/src/sys_core_fold.erl
index 7e219da0af..4939a94a92 100644
--- a/lib/compiler/src/sys_core_fold.erl
+++ b/lib/compiler/src/sys_core_fold.erl
@@ -1997,53 +1997,22 @@ case_opt_compiler_generated(Core) ->
%% case_expand_var(Expr0, Sub) -> Expr
-%% If Expr0 is a variable that has been previously matched and
-%% is known to be a tuple, return the tuple instead. Otherwise
+%% If Expr0 is a variable that is known to be bound to a
+%% constructed tuple, return the tuple instead. Otherwise
%% return Expr0 unchanged.
-%%
+
case_expand_var(E, #sub{t=Tdb}) ->
Key = cerl:var_name(E),
case Tdb of
- #{Key:=T0} ->
- case cerl:is_c_tuple(T0) of
- false ->
- E;
- true ->
- %% The pattern was a tuple. Now we must make sure
- %% that the elements of the tuple are suitable. In
- %% particular, we don't want binary or map
- %% construction here, since that means that the
- %% binary or map will be constructed in the 'case'
- %% argument. That is wasteful for binaries. Even
- %% worse is that any map pattern that use the ':='
- %% operator will fail when used in map
- %% construction (only the '=>' operator is allowed
- %% when constructing a map from scratch).
- try
- cerl_trees:map(fun coerce_to_data/1, T0)
- catch
- throw:impossible ->
- %% Something unsuitable was found (map or
- %% or binary). Keep the variable.
- E
- end
+ #{Key:=T} ->
+ case cerl:is_c_tuple(T) of
+ false -> E;
+ true -> T
end;
_ ->
E
end.
-%% coerce_to_data(Core) -> Core'
-%% Coerce an element originally from a pattern to an data item or or
-%% variable. Throw an 'impossible' exception if non-data Core Erlang
-%% terms such as binary construction or map construction are
-%% encountered.
-
-coerce_to_data(C) ->
- case cerl:is_data(C) orelse cerl:is_c_var(C) of
- true -> C;
- false -> throw(impossible)
- end.
-
%% case_opt_nomatch(E, Clauses, LitExpr) -> Clauses'
%% Remove all clauses that cannot possibly match.
diff --git a/lib/compiler/test/beam_type_SUITE.erl b/lib/compiler/test/beam_type_SUITE.erl
index a7ffc3f60a..882e281a44 100644
--- a/lib/compiler/test/beam_type_SUITE.erl
+++ b/lib/compiler/test/beam_type_SUITE.erl
@@ -24,7 +24,7 @@
integers/1,numbers/1,coverage/1,booleans/1,setelement/1,
cons/1,tuple/1,record_float/1,binary_float/1,float_compare/1,
arity_checks/1,elixir_binaries/1,find_best/1,
- test_size/1]).
+ test_size/1,cover_lists_functions/1]).
suite() -> [{ct_hooks,[ts_install_cth]}].
@@ -46,7 +46,8 @@ groups() ->
arity_checks,
elixir_binaries,
find_best,
- test_size
+ test_size,
+ cover_lists_functions
]}].
init_per_suite(Config) ->
@@ -473,5 +474,18 @@ do_test_size(Term) when is_tuple(Term) ->
do_test_size(Term) when is_binary(Term) ->
size(Term).
+cover_lists_functions(Config) ->
+ case lists:suffix([no|Config], Config) of
+ true ->
+ ct:fail(should_be_false);
+ false ->
+ ok
+ end,
+ Zipped = lists:zipwith(fun(A, B) -> {A,B} end,
+ lists:duplicate(length(Config), zip),
+ Config),
+ true = is_list(Zipped),
+ ok.
+
id(I) ->
I.
diff --git a/lib/compiler/test/bs_construct_SUITE.erl b/lib/compiler/test/bs_construct_SUITE.erl
index 69017d87e7..bccd70d6cb 100644
--- a/lib/compiler/test/bs_construct_SUITE.erl
+++ b/lib/compiler/test/bs_construct_SUITE.erl
@@ -27,6 +27,7 @@
-export([all/0, suite/0,groups/0,init_per_suite/1, end_per_suite/1,
init_per_group/2,end_per_group/2,
init_per_testcase/2,end_per_testcase/2,
+ verify_highest_opcode/1,
two/1,test1/1,fail/1,float_bin/1,in_guard/1,in_catch/1,
nasty_literals/1,coerce_to_float/1,side_effect/1,
opt/1,otp_7556/1,float_arith/1,otp_8054/1,
@@ -43,7 +44,8 @@ all() ->
groups() ->
[{p,[parallel],
- [two,test1,fail,float_bin,in_guard,in_catch,
+ [verify_highest_opcode,
+ two,test1,fail,float_bin,in_guard,in_catch,
nasty_literals,side_effect,opt,otp_7556,float_arith,
otp_8054,cover]}].
@@ -68,6 +70,20 @@ init_per_testcase(Case, Config) when is_atom(Case), is_list(Config) ->
end_per_testcase(Case, Config) when is_atom(Case), is_list(Config) ->
ok.
+verify_highest_opcode(_Config) ->
+ case ?MODULE of
+ bs_construct_r21_SUITE ->
+ {ok,Beam} = file:read_file(code:which(?MODULE)),
+ case test_lib:highest_opcode(Beam) of
+ Highest when Highest =< 163 ->
+ ok;
+ TooHigh ->
+ ct:fail({too_high_opcode_for_21,TooHigh})
+ end;
+ _ ->
+ ok
+ end.
+
two(Config) when is_list(Config) ->
<<0,1,2,3,4,6,7,8,9>> = two_1([0], [<<1,2,3,4>>,<<6,7,8,9>>]),
ok.
diff --git a/lib/compiler/test/bs_match_SUITE.erl b/lib/compiler/test/bs_match_SUITE.erl
index 2cfcb841a7..41e4918b1e 100644
--- a/lib/compiler/test/bs_match_SUITE.erl
+++ b/lib/compiler/test/bs_match_SUITE.erl
@@ -24,6 +24,7 @@
-export([all/0, suite/0,groups/0,init_per_suite/1, end_per_suite/1,
init_per_group/2,end_per_group/2,
init_per_testcase/2,end_per_testcase/2,
+ verify_highest_opcode/1,
size_shadow/1,int_float/1,otp_5269/1,null_fields/1,wiger/1,
bin_tail/1,save_restore/1,
partitioned_bs_match/1,function_clause/1,
@@ -60,7 +61,8 @@ all() ->
groups() ->
[{p,[],
- [size_shadow,int_float,otp_5269,null_fields,wiger,
+ [verify_highest_opcode,
+ size_shadow,int_float,otp_5269,null_fields,wiger,
bin_tail,save_restore,
partitioned_bs_match,function_clause,unit,
shared_sub_bins,bin_and_float,dec_subidentifiers,
@@ -101,6 +103,20 @@ init_per_testcase(Case, Config) when is_atom(Case), is_list(Config) ->
end_per_testcase(Case, Config) when is_atom(Case), is_list(Config) ->
ok.
+verify_highest_opcode(_Config) ->
+ case ?MODULE of
+ bs_match_r21_SUITE ->
+ {ok,Beam} = file:read_file(code:which(?MODULE)),
+ case test_lib:highest_opcode(Beam) of
+ Highest when Highest =< 163 ->
+ ok;
+ TooHigh ->
+ ct:fail({too_high_opcode_for_21,TooHigh})
+ end;
+ _ ->
+ ok
+ end.
+
size_shadow(Config) when is_list(Config) ->
%% Originally OTP-5270.
7 = size_shadow_1(),
diff --git a/lib/compiler/test/compile_SUITE.erl b/lib/compiler/test/compile_SUITE.erl
index 408af80dd9..53627b9d81 100644
--- a/lib/compiler/test/compile_SUITE.erl
+++ b/lib/compiler/test/compile_SUITE.erl
@@ -1431,9 +1431,7 @@ bc_options(Config) ->
highest_opcode(DataDir, Mod, Opt) ->
Src = filename:join(DataDir, atom_to_list(Mod)++".erl"),
{ok,Mod,Beam} = compile:file(Src, [binary|Opt]),
- {ok,{Mod,[{"Code",Code}]}} = beam_lib:chunks(Beam, ["Code"]),
- <<16:32,0:32,HighestOpcode:32,_/binary>> = Code,
- HighestOpcode.
+ test_lib:highest_opcode(Beam).
deterministic_include(Config) when is_list(Config) ->
DataDir = proplists:get_value(data_dir, Config),
diff --git a/lib/compiler/test/test_lib.erl b/lib/compiler/test/test_lib.erl
index 39c26c6142..3348c6e9ea 100644
--- a/lib/compiler/test/test_lib.erl
+++ b/lib/compiler/test/test_lib.erl
@@ -22,7 +22,8 @@
-include_lib("common_test/include/ct.hrl").
-compile({no_auto_import,[binary_part/2]}).
-export([id/1,recompile/1,parallel/0,uniq/0,opt_opts/1,get_data_dir/1,
- is_cloned_mod/1,smoke_disasm/1,p_run/2]).
+ is_cloned_mod/1,smoke_disasm/1,p_run/2,
+ highest_opcode/1]).
%% Used by test case that override BIFs.
-export([binary_part/2,binary/1]).
@@ -113,6 +114,14 @@ is_cloned_mod_1("_no_module_opt_SUITE") -> true;
is_cloned_mod_1([_|T]) -> is_cloned_mod_1(T);
is_cloned_mod_1([]) -> false.
+%% Return the highest opcode use in the BEAM module.
+
+highest_opcode(Beam) ->
+ {ok,{_Mod,[{"Code",Code}]}} = beam_lib:chunks(Beam, ["Code"]),
+ FormatNumber = 0,
+ <<16:32,FormatNumber:32,HighestOpcode:32,_/binary>> = Code,
+ HighestOpcode.
+
%% p_run(fun(Data) -> ok|error, List) -> ok
%% Will fail the test case if there were any errors.
diff --git a/lib/compiler/test/trycatch_SUITE.erl b/lib/compiler/test/trycatch_SUITE.erl
index 8f9cd9ab1e..539f9d69fa 100644
--- a/lib/compiler/test/trycatch_SUITE.erl
+++ b/lib/compiler/test/trycatch_SUITE.erl
@@ -27,7 +27,8 @@
nested_horrid/1,last_call_optimization/1,bool/1,
plain_catch_coverage/1,andalso_orelse/1,get_in_try/1,
hockey/1,handle_info/1,catch_in_catch/1,grab_bag/1,
- stacktrace/1,nested_stacktrace/1,raise/1]).
+ stacktrace/1,nested_stacktrace/1,raise/1,
+ no_return_in_try_block/1]).
-include_lib("common_test/include/ct.hrl").
@@ -43,7 +44,8 @@ groups() ->
nested_after,nested_horrid,last_call_optimization,
bool,plain_catch_coverage,andalso_orelse,get_in_try,
hockey,handle_info,catch_in_catch,grab_bag,
- stacktrace,nested_stacktrace,raise]}].
+ stacktrace,nested_stacktrace,raise,
+ no_return_in_try_block]}].
init_per_suite(Config) ->
@@ -1287,5 +1289,26 @@ do_test_raise_4(Expr) ->
erlang:raise(exit, {exception,C,E,Stk}, Stk)
end.
+no_return_in_try_block(Config) when is_list(Config) ->
+ 1.0 = no_return_in_try_block_1(0),
+ 1.0 = no_return_in_try_block_1(0.0),
+
+ gurka = no_return_in_try_block_1(gurka),
+ [] = no_return_in_try_block_1([]),
+
+ ok.
+
+no_return_in_try_block_1(H) ->
+ try
+ Float = if
+ is_number(H) -> float(H);
+ true -> no_return()
+ end,
+ Float + 1
+ catch
+ throw:no_return -> H
+ end.
+
+no_return() -> throw(no_return).
id(I) -> I.
diff --git a/lib/inets/test/httpc_SUITE.erl b/lib/inets/test/httpc_SUITE.erl
index 8357e02014..d4b33ae2c6 100644
--- a/lib/inets/test/httpc_SUITE.erl
+++ b/lib/inets/test/httpc_SUITE.erl
@@ -339,14 +339,6 @@ end_per_testcase(Case, Config)
end_per_testcase(_Case, _Config) ->
ok.
-is_ipv6_supported() ->
- case gen_udp:open(0, [inet6]) of
- {ok, Socket} ->
- gen_udp:close(Socket),
- true;
- _ ->
- false
- end.
%%--------------------------------------------------------------------
@@ -1612,7 +1604,8 @@ post_with_content_type(Config) when is_list(Config) ->
%%--------------------------------------------------------------------
request_options() ->
- [{doc, "Test http get request with socket options against local server (IPv6)"}].
+ [{require, ipv6_hosts},
+ {doc, "Test http get request with socket options against local server (IPv6)"}].
request_options(Config) when is_list(Config) ->
Request = {url(group_name(Config), "/dummy.html", Config), []},
{ok, {{_,200,_}, [_ | _], _ = [_ | _]}} = httpc:request(get, Request, [],
@@ -2945,3 +2938,12 @@ receive_stream_n(Ref, N) ->
ct:pal("Data: ~p", [Data]),
receive_stream_n(Ref, N-1)
end.
+
+is_ipv6_supported() ->
+ {ok, Hostname0} = inet:gethostname(),
+ try
+ lists:member(list_to_atom(Hostname0), ct:get_config(ipv6_hosts))
+ catch
+ _: _ ->
+ false
+ end.
diff --git a/lib/kernel/test/code_SUITE.erl b/lib/kernel/test/code_SUITE.erl
index 99fecbe970..4f0847084f 100644
--- a/lib/kernel/test/code_SUITE.erl
+++ b/lib/kernel/test/code_SUITE.erl
@@ -25,8 +25,8 @@
-export([all/0, suite/0,groups/0,init_per_group/2,end_per_group/2]).
-export([set_path/1, get_path/1, add_path/1, add_paths/1, del_path/1,
replace_path/1, load_file/1, load_abs/1, ensure_loaded/1,
- delete/1, purge/1, purge_many_exits/1, soft_purge/1, is_loaded/1,
- all_loaded/1,
+ delete/1, purge/1, purge_many_exits/0, purge_many_exits/1,
+ soft_purge/1, is_loaded/1, all_loaded/1,
load_binary/1, dir_req/1, object_code/1, set_path_file/1,
upgrade/1,
sticky_dir/1, pa_pz_option/1, add_del_path/1,
@@ -55,7 +55,7 @@
suite() ->
[{ct_hooks,[ts_install_cth]},
- {timetrap,{minutes,5}}].
+ {timetrap,{seconds,30}}].
all() ->
[set_path, get_path, add_path, add_paths, del_path,
@@ -396,6 +396,9 @@ purge(Config) when is_list(Config) ->
process_flag(trap_exit, OldFlag),
ok.
+purge_many_exits() ->
+ [{timetrap, {minutes, 2}}].
+
purge_many_exits(Config) when is_list(Config) ->
OldFlag = process_flag(trap_exit, true),
diff --git a/lib/observer/test/observer_SUITE.erl b/lib/observer/test/observer_SUITE.erl
index 75336cedcc..7d54bb9b3b 100644
--- a/lib/observer/test/observer_SUITE.erl
+++ b/lib/observer/test/observer_SUITE.erl
@@ -41,7 +41,8 @@
%% Default timetrap timeout (set in init_per_testcase)
-define(default_timeout, ?t:minutes(2)).
-suite() -> [{ct_hooks,[ts_install_cth]}].
+suite() -> [{timetrap, {minutes, 5}},
+ {ct_hooks,[ts_install_cth]}].
all() ->
[app_file, appup_file, {group, gui}].
diff --git a/lib/wx/src/Makefile b/lib/wx/src/Makefile
index 21b45af2c4..52f4008e0a 100644
--- a/lib/wx/src/Makefile
+++ b/lib/wx/src/Makefile
@@ -111,10 +111,10 @@ $(APPUP_TARGET): $(APPUP_SRC) ../vsn.mk Makefile
# Rules
$(EBIN)/%.beam: $(ESRC)/%.erl $(HEADER_FILES)
- $(V_ERLC) -W -bbeam $(ERL_FLAGS) $(ERL_COMPILE_FLAGS) -o$(EBIN) $<
+ $(V_ERLC) -W -bbeam $(ERL_COMPILE_FLAGS) -o$(EBIN) $<
$(EBIN)/%.beam: $(EGEN)/%.erl $(HEADER_FILES)
- $(V_ERLC) -W -bbeam $(ERL_FLAGS) $(ERL_COMPILE_FLAGS) -o$(EBIN) $<
+ $(V_ERLC) -W -bbeam $(ERL_COMPILE_FLAGS) -o$(EBIN) $<
# ----------------------------------------------------
# Release Target
diff --git a/system/doc/design_principles/statem.xml b/system/doc/design_principles/statem.xml
index 45ea972ff2..23e9054547 100644
--- a/system/doc/design_principles/statem.xml
+++ b/system/doc/design_principles/statem.xml
@@ -759,7 +759,7 @@ StateName(EventType, EventContent, Data) ->
<p>
Since the <em>state enter call</em> is not an event there are restrictions
on the allowed return value and
- <seealso marker="#State Transition Actions">State Transition Actions</seealso>.
+ <seealso marker="#Transition Actions">State Transition Actions</seealso>.
You may not change the state,
<seealso marker="#Postponing Events">postpone</seealso>
this non-event, or
diff --git a/system/doc/reference_manual/expressions.xml b/system/doc/reference_manual/expressions.xml
index 8c47070890..ea3b2159fc 100644
--- a/system/doc/reference_manual/expressions.xml
+++ b/system/doc/reference_manual/expressions.xml
@@ -1221,10 +1221,10 @@ Ei = Value |
&lt;&lt;1,17,0,42&gt;&gt;
10> <input>H.</input>
&lt;&lt;17,0,42&gt;&gt;
-11> <input>&lt;&lt;G,H/bitstring&gt;&gt; = &lt;&lt;1,17,42:12&gt;&gt;.</input>
-&lt;&lt;1,17,1,10:4&gt;&gt;
-12> <input>H.</input>
-&lt;&lt;17,1,10:4&gt;&gt;
+11> <input>&lt;&lt;G,J/bitstring&gt;&gt; = &lt;&lt;1,17,42:12&gt;&gt;.</input>
+&lt;&lt;1,17,2,10:4&gt;&gt;
+12> <input>J.</input>
+&lt;&lt;17,2,10:4&gt;&gt;
13> <input>&lt;&lt;1024/utf8&gt;&gt;.</input>
&lt;&lt;208,128&gt;&gt;
</pre>