aboutsummaryrefslogtreecommitdiffstats
path: root/erts
diff options
context:
space:
mode:
Diffstat (limited to 'erts')
-rw-r--r--erts/Makefile4
-rw-r--r--erts/doc/src/Makefile24
-rw-r--r--erts/doc/src/erl_nif.xml16
-rw-r--r--erts/doc/src/erlang.xml19
-rw-r--r--erts/doc/src/fascicules.xml18
-rw-r--r--erts/doc/src/notes.xml137
-rw-r--r--erts/doc/src/part_notes.xml38
-rw-r--r--erts/doc/src/part_notes_history.xml36
-rw-r--r--erts/doc/src/run_erl.xml6
-rw-r--r--erts/emulator/beam/atom.h2
-rw-r--r--erts/emulator/beam/beam_bp.c85
-rw-r--r--erts/emulator/beam/beam_load.c35
-rw-r--r--erts/emulator/beam/beam_ranges.c22
-rw-r--r--erts/emulator/beam/break.c80
-rw-r--r--erts/emulator/beam/erl_alloc.types1
-rw-r--r--erts/emulator/beam/erl_gc.c47
-rw-r--r--erts/emulator/beam/erl_nif.c4
-rw-r--r--erts/emulator/beam/erl_nif.h5
-rw-r--r--erts/emulator/beam/erl_process.c8
-rw-r--r--erts/emulator/beam/erl_process_dump.c402
-rw-r--r--erts/emulator/beam/global.h3
-rw-r--r--erts/emulator/beam/index.c2
-rw-r--r--erts/emulator/beam/module.c1
-rw-r--r--erts/emulator/drivers/common/inet_drv.c5
-rw-r--r--erts/emulator/hipe/hipe_amd64_bifs.m437
-rw-r--r--erts/emulator/hipe/hipe_bif0.tab1
-rw-r--r--erts/emulator/hipe/hipe_bif_list.m45
-rw-r--r--erts/emulator/hipe/hipe_debug.c32
-rw-r--r--erts/emulator/hipe/hipe_native_bif.c6
-rw-r--r--erts/emulator/hipe/hipe_native_bif.h2
-rw-r--r--erts/emulator/hipe/hipe_primops.h1
-rw-r--r--erts/emulator/hipe/hipe_risc_stack.c8
-rw-r--r--erts/emulator/hipe/hipe_x86_stack.c8
-rw-r--r--erts/emulator/test/code_SUITE.erl60
-rw-r--r--erts/emulator/test/distribution_SUITE.erl64
-rw-r--r--erts/emulator/test/match_spec_SUITE.erl48
-rw-r--r--erts/emulator/test/process_SUITE.erl13
-rw-r--r--erts/emulator/test/trace_SUITE.erl33
-rw-r--r--erts/etc/common/erlexec.c10
-rw-r--r--erts/etc/unix/cerl.src39
-rw-r--r--erts/etc/unix/run_erl.c7
-rw-r--r--erts/include/internal/erl_printf.h1
-rw-r--r--erts/lib_src/common/erl_printf.c12
43 files changed, 1095 insertions, 292 deletions
diff --git a/erts/Makefile b/erts/Makefile
index 12d2ec57a8..ffada839a7 100644
--- a/erts/Makefile
+++ b/erts/Makefile
@@ -147,3 +147,7 @@ release:
.PHONY: release_docs
release_docs:
$(V_at)( cd doc/src && $(MAKE) $@ )
+
+.PHONY: xmllint
+xmllint:
+ $(MAKE) -C doc/src $@
diff --git a/erts/doc/src/Makefile b/erts/doc/src/Makefile
index b96cbbce40..18c5490d7b 100644
--- a/erts/doc/src/Makefile
+++ b/erts/doc/src/Makefile
@@ -1,7 +1,7 @@
-#
+#
# %CopyrightBegin%
#
-# Copyright Ericsson AB 1997-2016. All Rights Reserved.
+# Copyright Ericsson AB 1997-2017. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -16,7 +16,7 @@
# limitations under the License.
#
# %CopyrightEnd%
-#
+#
SPECS_ESRC = ../../preloaded/src/
@@ -66,11 +66,10 @@ XML_REF3_FILES = \
zlib.xml
XML_PART_FILES = \
- part.xml \
- part_notes.xml \
- part_notes_history.xml
+ part.xml
XML_CHAPTER_FILES = \
+ introduction.xml \
tty.xml \
match_spec.xml \
crash_dump.xml \
@@ -82,8 +81,7 @@ XML_CHAPTER_FILES = \
erl_dist_protocol.xml \
communication.xml \
time_correction.xml \
- notes.xml \
- notes_history.xml
+ notes.xml
TOPDOCDIR=../../../doc
@@ -116,9 +114,9 @@ SPECS_FILES = $(XML_REF3_EFILES:%.xml=$(SPECDIR)/specs_%.xml)
TOP_SPECS_FILE = specs.xml
# ----------------------------------------------------
-# FLAGS
+# FLAGS
# ----------------------------------------------------
-XML_FLAGS +=
+XML_FLAGS +=
KERNEL_SRC=$(ERL_TOP)/lib/kernel/src
KERNEL_INCLUDE=$(ERL_TOP)/lib/kernel/include
@@ -146,7 +144,7 @@ $(INFO_FILE): $(INFO_FILE_SRC) $(ERL_TOP)/make/$(TARGET)/otp.mk
sed -e 's;%RELEASE%;$(SYSTEM_VSN);' $(INFO_FILE_SRC) > $(INFO_FILE)
-debug opt:
+debug opt:
clean:
rm -rf $(HTMLDIR)/*
@@ -154,7 +152,7 @@ clean:
rm -f $(MAN3DIR)/*
rm -f $(TOP_PDF_FILE) $(TOP_PDF_FILE:%.pdf=%.fo)
rm -f $(SPECDIR)/*
- rm -f errs core *~
+ rm -f errs core *~
$(SPECDIR)/specs_%.xml:
escript $(SPECS_EXTRACTOR) $(SPECS_FLAGS) \
@@ -162,7 +160,7 @@ $(SPECDIR)/specs_%.xml:
# ----------------------------------------------------
# Release Target
-# ----------------------------------------------------
+# ----------------------------------------------------
include $(ERL_TOP)/make/otp_release_targets.mk
release_docs_spec: docs
diff --git a/erts/doc/src/erl_nif.xml b/erts/doc/src/erl_nif.xml
index 419e41693e..ef3cdb89e9 100644
--- a/erts/doc/src/erl_nif.xml
+++ b/erts/doc/src/erl_nif.xml
@@ -952,6 +952,8 @@ typedef struct {
<desc>
<p>Allocates memory of <c>size</c> bytes.</p>
<p>Returns <c>NULL</c> if the allocation fails.</p>
+ <p>The returned pointer is suitably aligned for any built-in type that
+ fit in the allocated memory.</p>
</desc>
</func>
@@ -2760,6 +2762,20 @@ enif_map_iterator_destroy(env, &amp;iter);</code>
</func>
<func>
+ <name><ret>void *</ret>
+ <nametext>enif_realloc(void* ptr, size_t size)</nametext></name>
+ <fsummary>Reallocate dynamic memory.</fsummary>
+ <desc>
+ <p>Reallocates memory allocated by
+ <seealso marker="#enif_alloc"><c>enif_alloc</c></seealso> to
+ <c>size</c> bytes.</p>
+ <p>Returns <c>NULL</c> if the reallocation fails.</p>
+ <p>The returned pointer is suitably aligned for any built-in type that
+ fit in the allocated memory.</p>
+ </desc>
+ </func>
+
+ <func>
<name><ret>int</ret>
<nametext>enif_realloc_binary(ErlNifBinary* bin, size_t size)</nametext>
</name>
diff --git a/erts/doc/src/erlang.xml b/erts/doc/src/erlang.xml
index 2465f49581..b04f2b008e 100644
--- a/erts/doc/src/erlang.xml
+++ b/erts/doc/src/erlang.xml
@@ -2955,7 +2955,10 @@ os_prompt%</pre>
<p>The total amount of memory currently allocated for
the emulator that is not directly related to any Erlang
process. Memory presented as <c>processes</c> is not
- included in this memory.</p>
+ included in this memory. <seealso marker="tools:instrument">
+ <c>instrument(3)</c></seealso> can be used to
+ get a more detailed breakdown of what memory is part
+ of this type.</p>
</item>
<tag><c>atom</c></tag>
<item>
@@ -4687,7 +4690,7 @@ RealSystem = system + MissedSystem</code>
<p>The default <c>message_queue_data</c> process flag is determined
by command-line argument <seealso marker="erl#+hmqd">
<c>+hmqd</c></seealso> in <c>erl(1)</c>.</p>
- <p>If the process potentially can get many messages,
+ <p>If the process potentially can get many messages in its queue,
you are advised to set the flag to <c>off_heap</c>. This
because a garbage collection with many messages placed on
the heap can become extremely expensive and the process can
@@ -4960,11 +4963,15 @@ RealSystem = system + MissedSystem</code>
<tag><c>{binary, <anno>BinInfo</anno>}</c></tag>
<item>
<p><c><anno>BinInfo</anno></c> is a list containing miscellaneous
- information about binaries currently referred to by this
- process. This <c><anno>InfoTuple</anno></c> can be changed or
+ information about binaries on the heap of this
+ process.
+ This <c><anno>InfoTuple</anno></c> can be changed or
removed without prior notice. In the current implementation
<c><anno>BinInfo</anno></c> is a list of tuples. The tuples
contain; <c>BinaryId</c>, <c>BinarySize</c>, <c>BinaryRefcCount</c>.</p>
+ <p>The message queue is on the heap depending on the
+ process flag <seealso marker="#process_flag_message_queue_data">
+ <c>message_queue_data</c></seealso>.</p>
</item>
<tag><c>{catchlevel, <anno>CatchLevel</anno>}</c></tag>
<item>
@@ -8869,6 +8876,10 @@ hello
</pre>
<p>See also <seealso marker="#binary_to_term/1">
<c>binary_to_term/1</c></seealso>.</p>
+ <note>
+ <p>There is no guarantee that this function will return
+ the same encoded representation for the same term.</p>
+ </note>
</desc>
</func>
diff --git a/erts/doc/src/fascicules.xml b/erts/doc/src/fascicules.xml
deleted file mode 100644
index 1c371bd9c8..0000000000
--- a/erts/doc/src/fascicules.xml
+++ /dev/null
@@ -1,18 +0,0 @@
-<?xml version="1.0" encoding="utf-8" ?>
-<!DOCTYPE fascicules SYSTEM "fascicules.dtd">
-
-<fascicules>
- <fascicule file="part" href="part_frame.html" entry="no">
- ERTS User's Guide
- </fascicule>
- <fascicule file="ref_man" href="ref_man_frame.html" entry="yes">
- ERTS Reference Manual
- </fascicule>
- <fascicule file="part_notes" href="part_notes_frame.html" entry="no">
- Release Notes
- </fascicule>
- <fascicule file="" href="../../../doc/print.html" entry="no">
- Off-Print
- </fascicule>
-</fascicules>
-
diff --git a/erts/doc/src/notes.xml b/erts/doc/src/notes.xml
index ce388ba3a8..91eabb5607 100644
--- a/erts/doc/src/notes.xml
+++ b/erts/doc/src/notes.xml
@@ -1092,6 +1092,91 @@
</section>
+<section><title>Erts 8.3.5.3</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ A timer internal bit-field used for storing scheduler id
+ was too small. As a result, VM internal timer data
+ structures could become inconsistent when using 1024
+ schedulers on the system. Note that systems with less
+ than 1024 schedulers are not effected by this bug.</p>
+ <p>
+ This bug was introduced in ERTS version 7.0 (OTP 18.0).</p>
+ <p>
+ Own Id: OTP-14548 Aux Id: OTP-11997, ERL-468 </p>
+ </item>
+ <item>
+ <p>
+ Fixed bug in <c>binary_to_term</c> and
+ <c>binary_to_atom</c> that could cause VM crash.
+ Typically happens when the last character of an UTF8
+ string is in the range 128 to 255, but truncated to only
+ one byte. Bug exists in <c>binary_to_term</c> since ERTS
+ version 5.10.2 (OTP_R16B01) and <c>binary_to_atom</c>
+ since ERTS version 9.0 (OTP-20.0).</p>
+ <p>
+ Own Id: OTP-14590 Aux Id: ERL-474 </p>
+ </item>
+ <item>
+ <p>
+ Fix bug causing VM crash when a module with
+ <c>-on_load</c> directive is loaded while
+ <c>erlang:trace(on_load, ...)</c> is enabled.</p>
+ <p>
+ Own Id: OTP-14612</p>
+ </item>
+ <item>
+ <p>
+ Fixed bug that could cause a VM crash when a corrupt
+ message is received on distribution channel from other
+ node.</p>
+ <p>
+ Own Id: OTP-14661 Aux Id: ERIERL-80 </p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>Erts 8.3.5.2</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ Fix performance bug in pre-allocators that could cause
+ them to permanently fall back on normal more expensive
+ memory allocation. Pre-allocators are used for quick
+ allocation of short lived meta data used by messages and
+ other scheduled tasks. Bug exists since OTP_R15B02.</p>
+ <p>
+ Own Id: OTP-14491</p>
+ </item>
+ <item>
+ <p>Fixed a bug that prevented TCP sockets from being
+ closed properly on send timeouts.</p>
+ <p>
+ Own Id: OTP-14509</p>
+ </item>
+ <item>
+ <p>
+ Fixed bug in operator <c>bxor</c> causing erroneuos
+ result when one operand is a big <em>negative</em>
+ integer with the lowest <c>N*W</c> bits as zero and the
+ other operand not larger than <c>N*W</c> bits. <c>N</c>
+ is an integer of 1 or larger and <c>W</c> is 32 or 64
+ depending on word size.</p>
+ <p>
+ Own Id: OTP-14514</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
<section><title>Erts 8.3.5.1</title>
<section><title>Fixed Bugs and Malfunctions</title>
<list>
@@ -2834,6 +2919,58 @@
</section>
+<section><title>Erts 7.3.1.4</title>
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ Fix performance bug in pre-allocators that could cause
+ them to permanently fall back on normal more expensive
+ memory allocation. Pre-allocators are used for quick
+ allocation of short lived meta data used by messages and
+ other scheduled tasks. Bug exists since OTP_R15B02.</p>
+ <p>
+ Own Id: OTP-14491</p>
+ </item>
+ <item>
+ <p>
+ Fixed bug in operator <c>bxor</c> causing erroneuos
+ result when one operand is a big <em>negative</em>
+ integer with the lowest <c>N*W</c> bits as zero and the
+ other operand not larger than <c>N*W</c> bits. <c>N</c>
+ is an integer of 1 or larger and <c>W</c> is 32 or 64
+ depending on word size.</p>
+ <p>
+ Own Id: OTP-14514</p>
+ </item>
+ <item>
+ <p>
+ A timer internal bit-field used for storing scheduler id
+ was too small. As a result, VM internal timer data
+ structures could become inconsistent when using 1024
+ schedulers on the system. Note that systems with less
+ than 1024 schedulers are not effected by this bug.</p>
+ <p>
+ This bug was introduced in ERTS version 7.0 (OTP 18.0).</p>
+ <p>
+ Own Id: OTP-14548 Aux Id: OTP-11997, ERL-468 </p>
+ </item>
+ <item>
+ <p>
+ Fixed bug in <c>binary_to_term</c> and
+ <c>binary_to_atom</c> that could cause VM crash.
+ Typically happens when the last character of an UTF8
+ string is in the range 128 to 255, but truncated to only
+ one byte. Bug exists in <c>binary_to_term</c> since ERTS
+ version 5.10.2 (OTP_R16B01) and <c>binary_to_atom</c>
+ since ERTS version 9.0 (OTP-20.0).</p>
+ <p>
+ Own Id: OTP-14590 Aux Id: ERL-474 </p>
+ </item>
+ </list>
+ </section>
+</section>
+
<section><title>Erts 7.3.1.3</title>
<section><title>Fixed Bugs and Malfunctions</title>
diff --git a/erts/doc/src/part_notes.xml b/erts/doc/src/part_notes.xml
deleted file mode 100644
index e579b7635d..0000000000
--- a/erts/doc/src/part_notes.xml
+++ /dev/null
@@ -1,38 +0,0 @@
-<?xml version="1.0" encoding="utf-8" ?>
-<!DOCTYPE part SYSTEM "part.dtd">
-
-<part xmlns:xi="http://www.w3.org/2001/XInclude">
- <header>
- <copyright>
- <year>2004</year><year>2016</year>
- <holder>Ericsson AB. All Rights Reserved.</holder>
- </copyright>
- <legalnotice>
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
-
- </legalnotice>
-
- <title>ERTS Release Notes</title>
- <prepared></prepared>
- <docno></docno>
- <date>2004-09-07</date>
- <rev>1.0</rev>
- </header>
- <description>
- <p>The Erlang Runtime System application <em>ERTS</em>.</p>
- <p>For information about older versions, see
- <url href="part_notes_history_frame.html">Release Notes History</url>.</p>
- </description>
- <xi:include href="notes.xml"/>
-</part>
-
diff --git a/erts/doc/src/part_notes_history.xml b/erts/doc/src/part_notes_history.xml
deleted file mode 100644
index 277683a2b5..0000000000
--- a/erts/doc/src/part_notes_history.xml
+++ /dev/null
@@ -1,36 +0,0 @@
-<?xml version="1.0" encoding="utf-8" ?>
-<!DOCTYPE part SYSTEM "part.dtd">
-
-<part xmlns:xi="http://www.w3.org/2001/XInclude">
- <header>
- <copyright>
- <year>2006</year><year>2016</year>
- <holder>Ericsson AB. All Rights Reserved.</holder>
- </copyright>
- <legalnotice>
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
-
- </legalnotice>
-
- <title>ERTS Release Notes History</title>
- <prepared></prepared>
- <docno></docno>
- <date></date>
- <rev></rev>
- </header>
- <description>
- <p>The Erlang Runtime System application <em>ERTS</em>.</p>
- </description>
- <xi:include href="notes_history.xml"/>
-</part>
-
diff --git a/erts/doc/src/run_erl.xml b/erts/doc/src/run_erl.xml
index a9b6a7e2c6..e4c1b943c4 100644
--- a/erts/doc/src/run_erl.xml
+++ b/erts/doc/src/run_erl.xml
@@ -181,6 +181,12 @@
<item>
<p>Controls the number of log files written before older
files are reused. Defaults to 5, minimum is 2, maximum is 1000.</p>
+ <p>Note that, as a way to indicate the newest file, <c>run_erl</c> will
+ delete the oldest log file to maintain a "hole" in the file
+ sequences. For example, if log files #1, #2, #4 and #5 exists, that
+ means #2 is the latest and #4 is the oldest. You will therefore at most
+ get one less log file than the value set by
+ <c>RUN_ERL_LOG_GENERATIONS</c>.</p>
</item>
<tag><c>RUN_ERL_LOG_MAXSIZE</c></tag>
<item>
diff --git a/erts/emulator/beam/atom.h b/erts/emulator/beam/atom.h
index be998a46bd..385120a8d9 100644
--- a/erts/emulator/beam/atom.h
+++ b/erts/emulator/beam/atom.h
@@ -36,7 +36,7 @@
/* Internal atom cache needs MAX_ATOM_TABLE_SIZE to be less than an
unsigned 32 bit integer. See external.c(erts_encode_ext_dist_header_setup)
for more details. */
-#define MAX_ATOM_TABLE_SIZE ((MAX_ATOM_INDEX + 1 < (UWORD_CONSTANT(1) << 32)) ? MAX_ATOM_INDEX + 1 : (UWORD_CONSTANT(1) << 32))
+#define MAX_ATOM_TABLE_SIZE ((MAX_ATOM_INDEX + 1 < (UWORD_CONSTANT(1) << 32)) ? MAX_ATOM_INDEX + 1 : ((UWORD_CONSTANT(1) << 31) - 1)) /* Here we use maximum signed interger value to avoid integer overflow */
#else
#define MAX_ATOM_TABLE_SIZE (MAX_ATOM_INDEX + 1)
#endif
diff --git a/erts/emulator/beam/beam_bp.c b/erts/emulator/beam/beam_bp.c
index 950639f7ae..069e7391fd 100644
--- a/erts/emulator/beam/beam_bp.c
+++ b/erts/emulator/beam/beam_bp.c
@@ -642,6 +642,49 @@ erts_clear_export_break(Module* modp, ErtsCodeInfo *ci)
ASSERT(ci->u.gen_bp == NULL);
}
+/*
+ * If c_p->cp is a trace return instruction, we set cp
+ * to be the place where we again start to execute code.
+ *
+ * cp is used by match spec {caller} to get the calling
+ * function, and if we don't do this fixup it will be
+ * 'undefined'. This has the odd side effect of {caller}
+ * not really being which function is the caller, but
+ * rather which function we are about to return to.
+ */
+static void fixup_cp_before_trace(Process *c_p, int *return_to_trace)
+{
+ Eterm *cpp, *E = c_p->stop;
+ BeamInstr w = *c_p->cp;
+ if (w == (BeamInstr) BeamOp(op_return_trace)) {
+ cpp = &E[2];
+ } else if (w == (BeamInstr) BeamOp(op_i_return_to_trace)) {
+ *return_to_trace = 1;
+ cpp = &E[0];
+ } else if (w == (BeamInstr) BeamOp(op_i_return_time_trace)) {
+ cpp = &E[0];
+ } else {
+ cpp = NULL;
+ }
+ if (cpp) {
+ for (;;) {
+ BeamInstr w = *cp_val(*cpp);
+ if (w == (BeamInstr) BeamOp(op_return_trace)) {
+ cpp += 3;
+ } else if (w == (BeamInstr) BeamOp(op_i_return_to_trace)) {
+ *return_to_trace = 1;
+ cpp += 1;
+ } else if (w == (BeamInstr) BeamOp(op_i_return_time_trace)) {
+ cpp += 2;
+ } else {
+ break;
+ }
+ }
+ c_p->cp = (BeamInstr *) cp_val(*cpp);
+ ASSERT(is_CP(*cpp));
+ }
+}
+
BeamInstr
erts_generic_breakpoint(Process* c_p, ErtsCodeInfo *info, Eterm* reg)
{
@@ -752,6 +795,7 @@ erts_bif_trace(int bif_index, Process* p, Eterm* args, BeamInstr* I)
GenericBp* g;
GenericBpData* bp = NULL;
Uint bp_flags = 0;
+ int return_to_trace = 0;
ERTS_SMP_CHK_HAVE_ONLY_MAIN_PROC_LOCK(p);
@@ -767,6 +811,8 @@ erts_bif_trace(int bif_index, Process* p, Eterm* args, BeamInstr* I)
*/
if (!applying) {
p->cp = I;
+ } else {
+ fixup_cp_before_trace(p, &return_to_trace);
}
if (bp_flags & (ERTS_BPF_LOCAL_TRACE|ERTS_BPF_GLOBAL_TRACE) &&
IS_TRACED_FL(p, F_TRACE_CALLS)) {
@@ -945,49 +991,20 @@ static ErtsTracer
do_call_trace(Process* c_p, ErtsCodeInfo* info, Eterm* reg,
int local, Binary* ms, ErtsTracer tracer)
{
- Eterm* cpp;
int return_to_trace = 0;
- BeamInstr w;
BeamInstr *cp_save = c_p->cp;
Uint32 flags;
Uint need = 0;
Eterm* E = c_p->stop;
- w = *c_p->cp;
- if (w == (BeamInstr) BeamOp(op_return_trace)) {
- cpp = &E[2];
- } else if (w == (BeamInstr) BeamOp(op_i_return_to_trace)) {
- return_to_trace = 1;
- cpp = &E[0];
- } else if (w == (BeamInstr) BeamOp(op_i_return_time_trace)) {
- cpp = &E[0];
- } else {
- cpp = NULL;
- }
- if (cpp) {
- for (;;) {
- BeamInstr w = *cp_val(*cpp);
- if (w == (BeamInstr) BeamOp(op_return_trace)) {
- cpp += 3;
- } else if (w == (BeamInstr) BeamOp(op_i_return_to_trace)) {
- return_to_trace = 1;
- cpp += 1;
- } else if (w == (BeamInstr) BeamOp(op_i_return_time_trace)) {
- cpp += 2;
- } else {
- break;
- }
- }
- cp_save = c_p->cp;
- c_p->cp = (BeamInstr *) cp_val(*cpp);
- ASSERT(is_CP(*cpp));
- }
+ fixup_cp_before_trace(c_p, &return_to_trace);
+
ERTS_SMP_UNREQ_PROC_MAIN_LOCK(c_p);
flags = erts_call_trace(c_p, info, ms, reg, local, &tracer);
ERTS_SMP_REQ_PROC_MAIN_LOCK(c_p);
- if (cpp) {
- c_p->cp = cp_save;
- }
+
+ /* restore cp after potential fixup */
+ c_p->cp = cp_save;
ASSERT(!ERTS_PROC_IS_EXITING(c_p));
if ((flags & MATCH_SET_RETURN_TO_TRACE) && !return_to_trace) {
diff --git a/erts/emulator/beam/beam_load.c b/erts/emulator/beam/beam_load.c
index 23258dbe9c..adf8779f11 100644
--- a/erts/emulator/beam/beam_load.c
+++ b/erts/emulator/beam/beam_load.c
@@ -5665,13 +5665,36 @@ erts_release_literal_area(ErtsLiteralArea* literal_area)
return;
oh = literal_area->off_heap;
-
+
while (oh) {
- Binary* bptr;
- ASSERT(thing_subtag(oh->thing_word) == REFC_BINARY_SUBTAG);
- bptr = ((ProcBin*)oh)->val;
- erts_bin_release(bptr);
- oh = oh->next;
+ switch (thing_subtag(oh->thing_word)) {
+ case REFC_BINARY_SUBTAG:
+ {
+ Binary* bptr = ((ProcBin*)oh)->val;
+ erts_bin_release(bptr);
+ break;
+ }
+ case FUN_SUBTAG:
+ {
+ ErlFunEntry* fe = ((ErlFunThing*)oh)->fe;
+ if (erts_smp_refc_dectest(&fe->refc, 0) == 0) {
+ erts_erase_fun_entry(fe);
+ }
+ break;
+ }
+ case REF_SUBTAG:
+ {
+ ErtsMagicBinary *bptr;
+ ASSERT(is_magic_ref_thing(oh));
+ bptr = ((ErtsMRefThing *) oh)->mb;
+ erts_bin_release((Binary *) bptr);
+ break;
+ }
+ default:
+ ASSERT(is_external_header(oh->thing_word));
+ erts_deref_node_entry(((ExternalThing*)oh)->node);
+ }
+ oh = oh->next;
}
erts_free(ERTS_ALC_T_LITERAL, literal_area);
}
diff --git a/erts/emulator/beam/beam_ranges.c b/erts/emulator/beam/beam_ranges.c
index 9b0335e83d..fac4289271 100644
--- a/erts/emulator/beam/beam_ranges.c
+++ b/erts/emulator/beam/beam_ranges.c
@@ -32,6 +32,15 @@ typedef struct {
erts_smp_atomic_t end; /* (BeamInstr*) Points one word beyond last function in module. */
} Range;
+/*
+ * Used for crash dumping of literals. The size of erts_dump_lit_areas is
+ * always twice the number of active ranges (to allow for literals in both
+ * current and old code).
+ */
+
+ErtsLiteralArea** erts_dump_lit_areas;
+Uint erts_dump_num_lit_areas;
+
/* Range 'end' needs to be atomic as we purge module
by setting end=start in active code_ix */
#define RANGE_END(R) ((BeamInstr*)erts_smp_atomic_read_nob(&(R)->end))
@@ -97,6 +106,11 @@ erts_init_ranges(void)
r[i].allocated = 0;
erts_smp_atomic_init_nob(&r[i].mid, 0);
}
+
+ erts_dump_num_lit_areas = 8;
+ erts_dump_lit_areas = (ErtsLiteralArea **)
+ erts_alloc(ERTS_ALC_T_CRASH_DUMP,
+ erts_dump_num_lit_areas * sizeof(ErtsLiteralArea*));
}
void
@@ -164,6 +178,14 @@ erts_end_staging_ranges(int commit)
erts_smp_atomic_set_nob(&r[dst].mid,
(erts_aint_t) (r[dst].modules +
r[dst].n / 2));
+
+ if (r[dst].allocated * 2 > erts_dump_num_lit_areas) {
+ erts_dump_num_lit_areas *= 2;
+ erts_dump_lit_areas = (ErtsLiteralArea **)
+ erts_realloc(ERTS_ALC_T_CRASH_DUMP,
+ (void *) erts_dump_lit_areas,
+ erts_dump_num_lit_areas * sizeof(ErtsLiteralArea*));
+ }
}
}
diff --git a/erts/emulator/beam/break.c b/erts/emulator/beam/break.c
index 76a0c5c716..e4c2801ea2 100644
--- a/erts/emulator/beam/break.c
+++ b/erts/emulator/beam/break.c
@@ -58,6 +58,8 @@ static void dump_attributes(fmtfn_t to, void *to_arg, byte* ptr, int size);
extern char* erts_system_version[];
+#define WRITE_BUFFER_SIZE (64*1024)
+
static void
port_info(fmtfn_t to, void *to_arg)
{
@@ -490,9 +492,7 @@ loaded(fmtfn_t to, void *to_arg)
static void
dump_attributes(fmtfn_t to, void *to_arg, byte* ptr, int size)
{
- while (size-- > 0) {
- erts_print(to, to_arg, "%02X", *ptr++);
- }
+ erts_print_base64(to, to_arg, ptr, size);
erts_print(to, to_arg, "\n");
}
@@ -677,18 +677,28 @@ bin_check(void)
static Sint64 crash_dump_limit = ERTS_SINT64_MAX;
static Sint64 crash_dump_written = 0;
-static int crash_dump_limited_writer(void* vfdp, char* buf, size_t len)
+typedef struct LimitedWriterInfo_ {
+ fmtfn_t to;
+ void* to_arg;
+} LimitedWriterInfo;
+
+static int
+crash_dump_limited_writer(void* vfdp, char* buf, size_t len)
{
const char stop_msg[] = "\n=abort:CRASH DUMP SIZE LIMIT REACHED\n";
+ LimitedWriterInfo* lwi = (LimitedWriterInfo *) vfdp;
crash_dump_written += len;
if (crash_dump_written <= crash_dump_limit) {
- return erts_write_fd(vfdp, buf, len);
+ return lwi->to(lwi->to_arg, buf, len);
}
len -= (crash_dump_written - crash_dump_limit);
- erts_write_fd(vfdp, buf, len);
- erts_write_fd(vfdp, (char*)stop_msg, sizeof(stop_msg)-1);
+ lwi->to(lwi->to_arg, buf, len);
+ lwi->to(lwi->to_arg, (char*)stop_msg, sizeof(stop_msg)-1);
+ if (lwi->to == &erts_write_fp) {
+ fclose((FILE *) lwi->to_arg);
+ }
/* We assume that crash dump was called from erts_exit_vv() */
erts_exit_epilogue();
@@ -713,6 +723,9 @@ erl_crash_dump_v(char *file, int line, char* fmt, va_list args)
int i;
fmtfn_t to = &erts_write_fd;
void* to_arg;
+ FILE* fp = 0;
+ LimitedWriterInfo lwi;
+ static char* write_buffer; /* 'static' to avoid a leak warning in valgrind */
if (ERTS_SOMEONE_IS_CRASH_DUMPING)
return;
@@ -820,9 +833,30 @@ erl_crash_dump_v(char *file, int line, char* fmt, va_list args)
fd = open(dumpname,O_WRONLY | O_CREAT | O_TRUNC,0640);
if (fd < 0)
return; /* Can't create the crash dump, skip it */
- to_arg = (void*)&fd;
+
+ /*
+ * Wrap into a FILE* so that we can use buffered output. Set an
+ * explicit buffer to make sure the first write does not fail because
+ * of a failure to allocate a buffer.
+ */
+ write_buffer = (char *) erts_alloc_fnf(ERTS_ALC_T_TMP, WRITE_BUFFER_SIZE);
+ if (write_buffer && (fp = fdopen(fd, "w")) != NULL) {
+ setvbuf(fp, write_buffer, _IOFBF, WRITE_BUFFER_SIZE);
+ lwi.to = &erts_write_fp;
+ lwi.to_arg = (void*)fp;
+ } else {
+ lwi.to = &erts_write_fd;
+ lwi.to_arg = (void*)&fd;
+ }
+ if (to == &crash_dump_limited_writer) {
+ to_arg = (void *) &lwi;
+ } else {
+ to = lwi.to;
+ to_arg = lwi.to_arg;
+ }
+
time(&now);
- erts_cbprintf(to, to_arg, "=erl_crash_dump:0.3\n%s", ctime(&now));
+ erts_cbprintf(to, to_arg, "=erl_crash_dump:0.5\n%s", ctime(&now));
if (file != NULL)
erts_cbprintf(to, to_arg, "The error occurred in file %s, line %d\n", file, line);
@@ -932,7 +966,35 @@ erl_crash_dump_v(char *file, int line, char* fmt, va_list args)
}
erts_cbprintf(to, to_arg, "=end\n");
+ if (fp) {
+ fclose(fp);
+ }
close(fd);
erts_fprintf(stderr,"done\n");
}
+void
+erts_print_base64(fmtfn_t to, void *to_arg, byte* src, Uint size)
+{
+ static const byte base64_chars[] =
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+
+ while (size >= 3) {
+ erts_putc(to, to_arg, base64_chars[src[0] >> 2]);
+ erts_putc(to, to_arg, base64_chars[((src[0] & 0x03) << 4) | (src[1] >> 4)]);
+ erts_putc(to, to_arg, base64_chars[((src[1] & 0x0f) << 2) | (src[2] >> 6)]);
+ erts_putc(to, to_arg, base64_chars[src[2] & 0x3f]);
+ size -= 3;
+ src += 3;
+ }
+ if (size == 1) {
+ erts_putc(to, to_arg, base64_chars[src[0] >> 2]);
+ erts_putc(to, to_arg, base64_chars[(src[0] & 0x03) << 4]);
+ erts_print(to, to_arg, "==");
+ } else if (size == 2) {
+ erts_putc(to, to_arg, base64_chars[src[0] >> 2]);
+ erts_putc(to, to_arg, base64_chars[((src[0] & 0x03) << 4) | (src[1] >> 4)]);
+ erts_putc(to, to_arg, base64_chars[(src[1] & 0x0f) << 2]);
+ erts_putc(to, to_arg, '=');
+ }
+}
diff --git a/erts/emulator/beam/erl_alloc.types b/erts/emulator/beam/erl_alloc.types
index 50a1d97dd5..252bf1cc7e 100644
--- a/erts/emulator/beam/erl_alloc.types
+++ b/erts/emulator/beam/erl_alloc.types
@@ -285,6 +285,7 @@ type MREF_ENT STANDARD SYSTEM magic_ref_entry
type MREF_TAB_BKTS STANDARD SYSTEM magic_ref_table_buckets
type MREF_TAB LONG_LIVED SYSTEM magic_ref_table
type MINDIRECTION FIXED_SIZE SYSTEM magic_indirection
+type CRASH_DUMP STANDARD SYSTEM crash_dump
+if threads_no_smp
# Need thread safe allocs, but std_alloc and fix_alloc are not;
diff --git a/erts/emulator/beam/erl_gc.c b/erts/emulator/beam/erl_gc.c
index 8cb977a7f3..6a87136463 100644
--- a/erts/emulator/beam/erl_gc.c
+++ b/erts/emulator/beam/erl_gc.c
@@ -1234,8 +1234,8 @@ erts_garbage_collect_literals(Process* p, Eterm* literals,
p->old_htop = old_htop;
/*
- * Prepare to sweep binaries. Since all MSOs on the new heap
- * must be come before MSOs on the old heap, find the end of
+ * Prepare to sweep off-heap objects. Since all MSOs on the new
+ * heap must be come before MSOs on the old heap, find the end of
* current MSO list and use that as a starting point.
*/
@@ -1247,25 +1247,50 @@ erts_garbage_collect_literals(Process* p, Eterm* literals,
}
/*
- * Sweep through all binaries in the temporary literal area.
+ * Sweep through all off-heap objects in the temporary literal area.
*/
while (oh) {
if (IS_MOVED_BOXED(oh->thing_word)) {
- Binary* bptr;
struct erl_off_heap_header* ptr;
- ptr = (struct erl_off_heap_header*) boxed_val(oh->thing_word);
- ASSERT(thing_subtag(ptr->thing_word) == REFC_BINARY_SUBTAG);
- bptr = ((ProcBin*)ptr)->val;
-
- /*
- * This binary has been copied to the heap.
+ /*
+ * This off-heap object has been copied to the heap.
* We must increment its reference count and
* link it into the MSO list for the process.
*/
- erts_refc_inc(&bptr->intern.refc, 1);
+ ptr = (struct erl_off_heap_header*) boxed_val(oh->thing_word);
+ switch (thing_subtag(ptr->thing_word)) {
+ case REFC_BINARY_SUBTAG:
+ {
+ Binary* bptr = ((ProcBin*)ptr)->val;
+ erts_refc_inc(&bptr->intern.refc, 1);
+ break;
+ }
+ case FUN_SUBTAG:
+ {
+ ErlFunEntry* fe = ((ErlFunThing*)ptr)->fe;
+ erts_refc_inc(&fe->refc, 1);
+ break;
+ }
+ case REF_SUBTAG:
+ {
+ ErtsMagicBinary *bptr;
+ ASSERT(is_magic_ref_thing(ptr));
+ bptr = ((ErtsMRefThing *) ptr)->mb;
+ erts_refc_inc(&bptr->intern.refc, 1);
+ break;
+ }
+ default:
+ {
+ ExternalThing *etp;
+ ASSERT(is_external_header(ptr->thing_word));
+ etp = (ExternalThing *) ptr;
+ erts_smp_refc_inc(&etp->node->refc, 1);
+ break;
+ }
+ }
*prev = ptr;
prev = &ptr->next;
}
diff --git a/erts/emulator/beam/erl_nif.c b/erts/emulator/beam/erl_nif.c
index 3ade17b10d..f67b67325d 100644
--- a/erts/emulator/beam/erl_nif.c
+++ b/erts/emulator/beam/erl_nif.c
@@ -550,6 +550,9 @@ void enif_clear_env(ErlNifEnv* env)
ASSERT(p == menv->env.proc);
ASSERT(p->common.id == ERTS_INVALID_PID);
ASSERT(MBUF(p) == menv->env.heap_frag);
+
+ free_tmp_objs(env);
+
if (MBUF(p) != NULL) {
erts_cleanup_offheap(&MSO(p));
clear_offheap(&MSO(p));
@@ -561,7 +564,6 @@ void enif_clear_env(ErlNifEnv* env)
menv->env.hp = menv->env.hp_end = HEAP_TOP(p);
ASSERT(!is_offheap(&MSO(p)));
- free_tmp_objs(env);
}
#ifdef ERTS_SMP
diff --git a/erts/emulator/beam/erl_nif.h b/erts/emulator/beam/erl_nif.h
index d195721054..7fb447e4a8 100644
--- a/erts/emulator/beam/erl_nif.h
+++ b/erts/emulator/beam/erl_nif.h
@@ -50,10 +50,11 @@
** 2.9: 18.2 enif_getenv
** 2.10: Time API
** 2.11: 19.0 enif_snprintf
-** 2.12: 20.0 add enif_queue
+** 2.12: 20.0 add enif_select, enif_open_resource_type_x
+** 2.13: 20.1 add enif_ioq
*/
#define ERL_NIF_MAJOR_VERSION 2
-#define ERL_NIF_MINOR_VERSION 12
+#define ERL_NIF_MINOR_VERSION 13
/*
* The emulator will refuse to load a nif-lib with a major version
diff --git a/erts/emulator/beam/erl_process.c b/erts/emulator/beam/erl_process.c
index 099aa02f10..63e9275ac1 100644
--- a/erts/emulator/beam/erl_process.c
+++ b/erts/emulator/beam/erl_process.c
@@ -11591,7 +11591,7 @@ request_system_task(Process *c_p, Eterm requester, Eterm target,
goto badarg;
req_type = tp[1];
req_id = tp[2];
- req_id_sz = is_immed(req_id) ? req_id : size_object(req_id);
+ req_id_sz = is_immed(req_id) ? 0 : size_object(req_id);
tot_sz = req_id_sz;
for (i = 0; i < ERTS_MAX_PROC_SYS_TASK_ARGS; i++) {
int tix = 3 + i;
@@ -13307,9 +13307,9 @@ send_exit_signal(Process *c_p, /* current process if and only
if ((state & ERTS_PSFLG_TRAP_EXIT)
&& (reason != am_kill || (flags & ERTS_XSIG_FLG_IGN_KILL))) {
- /* have to release the status lock in order to send the exit message */
- erts_smp_proc_unlock(rp, *rp_locks & ERTS_PROC_LOCKS_XSIG_SEND);
- *rp_locks &= ~ERTS_PROC_LOCKS_XSIG_SEND;
+ /* have to release the status and trace lock in order to send the exit message */
+ erts_smp_proc_unlock(rp, *rp_locks & (ERTS_PROC_LOCKS_XSIG_SEND|ERTS_PROC_LOCK_TRACE));
+ *rp_locks &= ~(ERTS_PROC_LOCKS_XSIG_SEND|ERTS_PROC_LOCK_TRACE);
if (have_seqtrace(token) && token_update)
seq_trace_update_send(token_update);
if (is_value(exit_tuple))
diff --git a/erts/emulator/beam/erl_process_dump.c b/erts/emulator/beam/erl_process_dump.c
index b826e6c5d3..e0b795fbf3 100644
--- a/erts/emulator/beam/erl_process_dump.c
+++ b/erts/emulator/beam/erl_process_dump.c
@@ -32,6 +32,7 @@
#include "dist.h"
#include "beam_catches.h"
#include "erl_binary.h"
+#include "erl_map.h"
#define ERTS_WANT_EXTERNAL_TAGS
#include "external.h"
@@ -50,7 +51,14 @@ static void stack_trace_dump(fmtfn_t to, void *to_arg, Eterm* sp);
static void print_function_from_pc(fmtfn_t to, void *to_arg, BeamInstr* x);
static void heap_dump(fmtfn_t to, void *to_arg, Eterm x);
static void dump_binaries(fmtfn_t to, void *to_arg, Binary* root);
+void erts_print_base64(fmtfn_t to, void *to_arg,
+ byte* src, Uint size);
static void dump_externally(fmtfn_t to, void *to_arg, Eterm term);
+static void mark_literal(Eterm* ptr);
+static void init_literal_areas(void);
+static void dump_literals(fmtfn_t to, void *to_arg);
+static void dump_module_literals(fmtfn_t to, void *to_arg,
+ ErtsLiteralArea* lit_area);
static Binary* all_binaries;
@@ -58,14 +66,14 @@ extern BeamInstr beam_apply[];
extern BeamInstr beam_exit[];
extern BeamInstr beam_continue_exit[];
-
void
erts_deep_process_dump(fmtfn_t to, void *to_arg)
{
int i, max = erts_ptab_max(&erts_proc);
all_binaries = NULL;
-
+ init_literal_areas();
+
for (i = 0; i < max; i++) {
Process *p = erts_pix2proc(i);
if (p && p->i != ENULL) {
@@ -75,6 +83,7 @@ erts_deep_process_dump(fmtfn_t to, void *to_arg)
}
}
+ dump_literals(to, to_arg);
dump_binaries(to, to_arg, all_binaries);
}
@@ -186,6 +195,7 @@ dump_dist_ext(fmtfn_t to, void *to_arg, ErtsDistExternal *edep)
else {
byte *e;
size_t sz;
+
if (!(edep->flags & ERTS_DIST_EXT_ATOM_TRANS_TAB))
erts_print(to, to_arg, "D0:");
else {
@@ -203,12 +213,18 @@ dump_dist_ext(fmtfn_t to, void *to_arg, ErtsDistExternal *edep)
else {
ASSERT(*e == VERSION_MAGIC);
}
-
erts_print(to, to_arg, "E%X:", sz);
- if (edep->flags & ERTS_DIST_EXT_DFLAG_HDR)
- erts_print(to, to_arg, "%02X", VERSION_MAGIC);
- while (e < edep->ext_endp)
- erts_print(to, to_arg, "%02X", *e++);
+ if (edep->flags & ERTS_DIST_EXT_DFLAG_HDR) {
+ byte sbuf[3];
+ int i = 0;
+
+ sbuf[i++] = VERSION_MAGIC;
+ while (i < sizeof(sbuf) && e < edep->ext_endp) {
+ sbuf[i++] = *e++;
+ }
+ erts_print_base64(to, to_arg, sbuf, i);
+ }
+ erts_print_base64(to, to_arg, e, edep->ext_endp - e);
}
}
@@ -373,7 +389,9 @@ heap_dump(fmtfn_t to, void *to_arg, Eterm x)
next = (Eterm *) x;
} else if (is_list(x)) {
ptr = list_val(x);
- if (ptr[0] != OUR_NIL) {
+ if (erts_is_literal(x, ptr)) {
+ mark_literal(ptr);
+ } else if (ptr[0] != OUR_NIL) {
erts_print(to, to_arg, PTR_FMT ":l", ptr);
dump_element(to, to_arg, ptr[0]);
erts_putc(to, to_arg, '|');
@@ -392,7 +410,9 @@ heap_dump(fmtfn_t to, void *to_arg, Eterm x)
ptr = boxed_val(x);
hdr = *ptr;
- if (hdr != OUR_NIL) { /* If not visited */
+ if (erts_is_literal(x, ptr)) {
+ mark_literal(ptr);
+ } else if (hdr != OUR_NIL) {
erts_print(to, to_arg, PTR_FMT ":", ptr);
if (is_arity_value(hdr)) {
Uint i;
@@ -433,16 +453,13 @@ heap_dump(fmtfn_t to, void *to_arg, Eterm x)
} else if (is_binary_header(hdr)) {
Uint tag = thing_subtag(hdr);
Uint size = binary_size(x);
- Uint i;
if (tag == HEAP_BINARY_SUBTAG) {
byte* p;
erts_print(to, to_arg, "Yh%X:", size);
p = binary_bytes(x);
- for (i = 0; i < size; i++) {
- erts_print(to, to_arg, "%02X", p[i]);
- }
+ erts_print_base64(to, to_arg, p, size);
} else if (tag == REFC_BINARY_SUBTAG) {
ProcBin* pb = (ProcBin *) binary_val(x);
Binary* val = pb->val;
@@ -498,11 +515,77 @@ heap_dump(fmtfn_t to, void *to_arg, Eterm x)
erts_print(to, to_arg, "p<%beu.%beu>\n",
port_channel_no(x), port_number(x));
*ptr = OUR_NIL;
+ } else if (is_map_header(hdr)) {
+ if (is_flatmap_header(hdr)) {
+ flatmap_t* fmp = (flatmap_t *) flatmap_val(x);
+ Eterm* values = ptr + sizeof(flatmap_t) / sizeof(Eterm);
+ Uint map_size = fmp->size;
+ int i;
+
+ erts_print(to, to_arg, "Mf" ETERM_FMT ":", map_size);
+ dump_element(to, to_arg, fmp->keys);
+ erts_putc(to, to_arg, ':');
+ for (i = 0; i < map_size; i++) {
+ dump_element(to, to_arg, values[i]);
+ if (is_immed(values[i])) {
+ values[i] = make_small(0);
+ }
+ if (i < map_size-1) {
+ erts_putc(to, to_arg, ',');
+ }
+ }
+ erts_putc(to, to_arg, '\n');
+ *ptr = OUR_NIL;
+ x = fmp->keys;
+ if (map_size) {
+ fmp->keys = (Eterm) next;
+ next = &values[map_size-1];
+ }
+ continue;
+ } else {
+ Uint i;
+ Uint sz = 0;
+ Eterm* nodes = ptr + 1;
+
+ switch (MAP_HEADER_TYPE(hdr)) {
+ case MAP_HEADER_TAG_HAMT_HEAD_ARRAY:
+ nodes++;
+ sz = 16;
+ erts_print(to, to_arg, "Mh" ETERM_FMT ":" ETERM_FMT ":",
+ hashmap_size(x), sz);
+ break;
+ case MAP_HEADER_TAG_HAMT_HEAD_BITMAP:
+ nodes++;
+ sz = hashmap_bitcount(MAP_HEADER_VAL(hdr));
+ erts_print(to, to_arg, "Mh" ETERM_FMT ":" ETERM_FMT ":",
+ hashmap_size(x), sz);
+ break;
+ case MAP_HEADER_TAG_HAMT_NODE_BITMAP:
+ sz = hashmap_bitcount(MAP_HEADER_VAL(hdr));
+ erts_print(to, to_arg, "Mn" ETERM_FMT ":", sz);
+ break;
+ }
+ *ptr = OUR_NIL;
+ for (i = 0; i < sz; i++) {
+ dump_element(to, to_arg, nodes[i]);
+ if (is_immed(nodes[i])) {
+ nodes[i] = make_small(0);
+ }
+ if (i < sz-1) {
+ erts_putc(to, to_arg, ',');
+ }
+ }
+ erts_putc(to, to_arg, '\n');
+ x = nodes[0];
+ nodes[0] = (Eterm) next;
+ next = &nodes[sz-1];
+ continue;
+ }
} else {
/*
* All other we dump in the external term format.
*/
- dump_externally(to, to_arg, x);
+ dump_externally(to, to_arg, x);
erts_putc(to, to_arg, '\n');
*ptr = OUR_NIL;
}
@@ -519,16 +602,13 @@ static void
dump_binaries(fmtfn_t to, void *to_arg, Binary* current)
{
while (current) {
- long i;
- long size = current->orig_size;
+ SWord size = current->orig_size;
byte* bytes = (byte*) current->orig_bytes;
erts_print(to, to_arg, "=binary:" PTR_FMT "\n", current);
erts_print(to, to_arg, "%X:", size);
- for (i = 0; i < size; i++) {
- erts_print(to, to_arg, "%02X", bytes[i]);
- }
- erts_putc(to, to_arg, '\n');
+ erts_print_base64(to, to_arg, bytes, size);
+ erts_putc(to, to_arg, '\n');
current = (Binary *) current->intern.flags;
}
}
@@ -564,16 +644,284 @@ dump_externally(fmtfn_t to, void *to_arg, Eterm term)
}
}
- /* Do not handle maps */
- if (is_map(term)) {
- term = am_undefined;
- }
-
s = p = sbuf;
erts_encode_ext(term, &p);
erts_print(to, to_arg, "E%X:", p-s);
- while (s < p) {
- erts_print(to, to_arg, "%02X", *s++);
+ erts_print_base64(to, to_arg, sbuf, p-s);
+}
+
+/*
+ * Handle dumping of literal areas.
+ */
+
+static ErtsLiteralArea** lit_areas;
+static Uint num_lit_areas;
+
+static int compare_areas(const void * a, const void * b)
+{
+ ErtsLiteralArea** a_p = (ErtsLiteralArea **) a;
+ ErtsLiteralArea** b_p = (ErtsLiteralArea **) b;
+
+ if (*a_p < *b_p) {
+ return -1;
+ } else if (*b_p < *a_p) {
+ return 1;
+ } else {
+ return 0;
+ }
+}
+
+
+static void
+init_literal_areas(void)
+{
+ int i;
+ Module* modp;
+ ErtsCodeIndex code_ix;
+ ErtsLiteralArea** area_p;
+
+ code_ix = erts_active_code_ix();
+ erts_rlock_old_code(code_ix);
+
+ lit_areas = area_p = erts_dump_lit_areas;
+ num_lit_areas = 0;
+ for (i = 0; i < module_code_size(code_ix); i++) {
+ modp = module_code(i, code_ix);
+ if (modp == NULL) {
+ continue;
+ }
+ if (modp->curr.code_length > 0 &&
+ modp->curr.code_hdr->literal_area) {
+ *area_p++ = modp->curr.code_hdr->literal_area;
+ }
+ if (modp->old.code_length > 0 && modp->old.code_hdr->literal_area) {
+ *area_p++ = modp->old.code_hdr->literal_area;
+ }
+ }
+
+ num_lit_areas = area_p - lit_areas;
+ ASSERT(num_lit_areas <= erts_dump_num_lit_areas);
+ for (i = 0; i < num_lit_areas; i++) {
+ lit_areas[i]->off_heap = 0;
+ }
+
+ qsort(lit_areas, num_lit_areas, sizeof(ErtsLiteralArea *),
+ compare_areas);
+
+ erts_runlock_old_code(code_ix);
+}
+
+static int search_areas(const void * a, const void * b) {
+ Eterm* key = (Eterm *) a;
+ ErtsLiteralArea** b_p = (ErtsLiteralArea **) b;
+ if (key < b_p[0]->start) {
+ return -1;
+ } else if (b_p[0]->end <= key) {
+ return 1;
+ } else {
+ return 0;
+ }
+}
+
+static void mark_literal(Eterm* ptr)
+{
+ ErtsLiteralArea** ap;
+
+ ap = bsearch(ptr, lit_areas, num_lit_areas, sizeof(ErtsLiteralArea*),
+ search_areas);
+
+ /*
+ * If the literal was created by native code, this search will not
+ * find it and ap will be NULL.
+ */
+
+ if (ap) {
+ ap[0]->off_heap = (struct erl_off_heap_header *) 1;
+ }
+}
+
+
+static void
+dump_literals(fmtfn_t to, void *to_arg)
+{
+ ErtsCodeIndex code_ix;
+ int i;
+
+ code_ix = erts_active_code_ix();
+ erts_rlock_old_code(code_ix);
+
+ erts_print(to, to_arg, "=literals\n");
+ for (i = 0; i < num_lit_areas; i++) {
+ if (lit_areas[i]->off_heap) {
+ dump_module_literals(to, to_arg, lit_areas[i]);
+ }
+ }
+
+ erts_runlock_old_code(code_ix);
+}
+
+static void
+dump_module_literals(fmtfn_t to, void *to_arg, ErtsLiteralArea* lit_area)
+{
+ Eterm* htop;
+ Eterm* hend;
+
+ htop = lit_area->start;
+ hend = lit_area->end;
+ while (htop < hend) {
+ Eterm w = *htop;
+ Eterm term;
+ Uint size;
+
+ switch (primary_tag(w)) {
+ case TAG_PRIMARY_HEADER:
+ term = make_boxed(htop);
+ erts_print(to, to_arg, PTR_FMT ":", htop);
+ if (is_arity_value(w)) {
+ Uint i;
+ Uint arity = arityval(w);
+
+ erts_print(to, to_arg, "t" ETERM_FMT ":", arity);
+ for (i = 1; i <= arity; i++) {
+ dump_element(to, to_arg, htop[i]);
+ if (i < arity) {
+ erts_putc(to, to_arg, ',');
+ }
+ }
+ erts_putc(to, to_arg, '\n');
+ } else if (w == HEADER_FLONUM) {
+ FloatDef f;
+ char sbuf[31];
+ int i;
+
+ GET_DOUBLE_DATA((htop+1), f);
+ i = sys_double_to_chars(f.fd, sbuf, sizeof(sbuf));
+ sys_memset(sbuf+i, 0, 31-i);
+ erts_print(to, to_arg, "F%X:%s\n", i, sbuf);
+ } else if (_is_bignum_header(w)) {
+ erts_print(to, to_arg, "B%T\n", term);
+ } else if (is_binary_header(w)) {
+ Uint tag = thing_subtag(w);
+ Uint size = binary_size(term);
+
+ if (tag == HEAP_BINARY_SUBTAG) {
+ byte* p;
+
+ erts_print(to, to_arg, "Yh%X:", size);
+ p = binary_bytes(term);
+ erts_print_base64(to, to_arg, p, size);
+ } else if (tag == REFC_BINARY_SUBTAG) {
+ ProcBin* pb = (ProcBin *) binary_val(term);
+ Binary* val = pb->val;
+
+ if (erts_atomic_xchg_nob(&val->intern.refc, 0) != 0) {
+ val->intern.flags = (UWord) all_binaries;
+ all_binaries = val;
+ }
+ erts_print(to, to_arg,
+ "Yc" PTR_FMT ":" PTR_FMT ":" PTR_FMT,
+ val,
+ pb->bytes - (byte *)val->orig_bytes,
+ size);
+ } else if (tag == SUB_BINARY_SUBTAG) {
+ ErlSubBin* Sb = (ErlSubBin *) binary_val(term);
+ Eterm* real_bin;
+ void* val;
+
+ real_bin = boxed_val(Sb->orig);
+ if (thing_subtag(*real_bin) == REFC_BINARY_SUBTAG) {
+ /*
+ * Unvisited REFC_BINARY: Point directly to
+ * the binary.
+ */
+ ProcBin* pb = (ProcBin *) real_bin;
+ val = pb->val;
+ } else {
+ /*
+ * Heap binary or visited REFC binary: Point
+ * to heap binary or ProcBin on the heap.
+ */
+ val = real_bin;
+ }
+ erts_print(to, to_arg,
+ "Ys" PTR_FMT ":" PTR_FMT ":" PTR_FMT,
+ val, Sb->offs, size);
+ }
+ erts_putc(to, to_arg, '\n');
+ } else if (is_map_header(w)) {
+ if (is_flatmap_header(w)) {
+ flatmap_t* fmp = (flatmap_t *) flatmap_val(term);
+ Eterm* values = htop + sizeof(flatmap_t) / sizeof(Eterm);
+ Uint map_size = fmp->size;
+ int i;
+
+ erts_print(to, to_arg, "Mf" ETERM_FMT ":", map_size);
+ dump_element(to, to_arg, fmp->keys);
+ erts_putc(to, to_arg, ':');
+ for (i = 0; i < map_size; i++) {
+ dump_element(to, to_arg, values[i]);
+ if (i < map_size-1) {
+ erts_putc(to, to_arg, ',');
+ }
+ }
+ erts_putc(to, to_arg, '\n');
+ } else {
+ Uint i;
+ Uint sz = 0;
+ Eterm* nodes = htop + 1;
+
+ switch (MAP_HEADER_TYPE(w)) {
+ case MAP_HEADER_TAG_HAMT_HEAD_ARRAY:
+ nodes++;
+ sz = 16;
+ erts_print(to, to_arg, "Mh" ETERM_FMT ":" ETERM_FMT ":",
+ hashmap_size(term), sz);
+ break;
+ case MAP_HEADER_TAG_HAMT_HEAD_BITMAP:
+ nodes++;
+ sz = hashmap_bitcount(MAP_HEADER_VAL(w));
+ erts_print(to, to_arg, "Mh" ETERM_FMT ":" ETERM_FMT ":",
+ hashmap_size(term), sz);
+ break;
+ case MAP_HEADER_TAG_HAMT_NODE_BITMAP:
+ sz = hashmap_bitcount(MAP_HEADER_VAL(w));
+ erts_print(to, to_arg, "Mn" ETERM_FMT ":", sz);
+ break;
+ }
+ for (i = 0; i < sz; i++) {
+ dump_element(to, to_arg, nodes[i]);
+ if (i < sz-1) {
+ erts_putc(to, to_arg, ',');
+ }
+ }
+ erts_putc(to, to_arg, '\n');
+ }
+ }
+ size = 1 + header_arity(w);
+ switch (w & _HEADER_SUBTAG_MASK) {
+ case MAP_SUBTAG:
+ if (is_flatmap_header(w)) {
+ size += 1 + flatmap_get_size(htop);
+ } else {
+ size += hashmap_bitcount(MAP_HEADER_VAL(w));
+ }
+ break;
+ case SUB_BINARY_SUBTAG:
+ size += 1;
+ break;
+ }
+ break;
+ default:
+ ASSERT(!is_header(htop[1]));
+ erts_print(to, to_arg, PTR_FMT ":l", htop);
+ dump_element(to, to_arg, htop[0]);
+ erts_putc(to, to_arg, '|');
+ dump_element(to, to_arg, htop[1]);
+ erts_putc(to, to_arg, '\n');
+ size = 2;
+ break;
+ }
+ htop += size;
}
}
diff --git a/erts/emulator/beam/global.h b/erts/emulator/beam/global.h
index 182d3aa44e..9505942307 100644
--- a/erts/emulator/beam/global.h
+++ b/erts/emulator/beam/global.h
@@ -955,6 +955,8 @@ void erts_update_ranges(BeamInstr* code, Uint size);
void erts_remove_from_ranges(BeamInstr* code);
UWord erts_ranges_sz(void);
void erts_lookup_function_info(FunctionInfo* fi, BeamInstr* pc, int full_info);
+ErtsLiteralArea** erts_dump_lit_areas;
+Uint erts_dump_num_lit_areas;
/* break.c */
void init_break_handler(void);
@@ -964,6 +966,7 @@ void process_info(fmtfn_t, void *);
void print_process_info(fmtfn_t, void *, Process*);
void info(fmtfn_t, void *);
void loaded(fmtfn_t, void *);
+void erts_print_base64(fmtfn_t to, void *to_arg, byte* src, Uint size);
/* sighandler sys.c */
int erts_set_signal(Eterm signal, Eterm type);
diff --git a/erts/emulator/beam/index.c b/erts/emulator/beam/index.c
index a1f6f54543..7bf1a032c1 100644
--- a/erts/emulator/beam/index.c
+++ b/erts/emulator/beam/index.c
@@ -58,7 +58,7 @@ IndexTable*
erts_index_init(ErtsAlcType_t type, IndexTable* t, char* name,
int size, int limit, HashFunctions fun)
{
- Uint base_size = ((limit+INDEX_PAGE_SIZE-1)/INDEX_PAGE_SIZE)*sizeof(IndexSlot*);
+ Uint base_size = (((Uint)limit+INDEX_PAGE_SIZE-1)/INDEX_PAGE_SIZE)*sizeof(IndexSlot*);
hash_init(type, &t->htable, name, 3*size/4, fun);
t->size = 0;
diff --git a/erts/emulator/beam/module.c b/erts/emulator/beam/module.c
index 7987cb2eb5..a386407ec2 100644
--- a/erts/emulator/beam/module.c
+++ b/erts/emulator/beam/module.c
@@ -256,4 +256,3 @@ void module_end_staging(int commit)
IF_DEBUG(dbg_load_code_ix = -1);
}
-
diff --git a/erts/emulator/drivers/common/inet_drv.c b/erts/emulator/drivers/common/inet_drv.c
index 7b1f4a0e9c..554c48059f 100644
--- a/erts/emulator/drivers/common/inet_drv.c
+++ b/erts/emulator/drivers/common/inet_drv.c
@@ -2199,13 +2199,16 @@ static int inet_reply_ok(inet_descriptor* desc)
ErlDrvTermData caller = desc->caller;
int i = 0;
+ desc->caller = 0;
+ if (is_not_internal_pid(caller))
+ return 0;
+
i = LOAD_ATOM(spec, i, am_inet_reply);
i = LOAD_PORT(spec, i, desc->dport);
i = LOAD_ATOM(spec, i, am_ok);
i = LOAD_TUPLE(spec, i, 3);
ASSERT(i == sizeof(spec)/sizeof(*spec));
- desc->caller = 0;
return erl_drv_send_term(desc->dport, caller, spec, i);
}
diff --git a/erts/emulator/hipe/hipe_amd64_bifs.m4 b/erts/emulator/hipe/hipe_amd64_bifs.m4
index dca3887564..aff10f1528 100644
--- a/erts/emulator/hipe/hipe_amd64_bifs.m4
+++ b/erts/emulator/hipe/hipe_amd64_bifs.m4
@@ -463,6 +463,43 @@ ASYM($1):
#endif')
/*
+ * nogc_bif_interface_1(nbif_name, cbif_name)
+ *
+ * Generate native interface for a bif with implicit P
+ * The bif can fail but cannot do GC.
+ */
+
+define(nogc_bif_interface_1,
+`
+#ifndef HAVE_$1
+#`define' HAVE_$1
+ TEXT
+ .align 4
+ GLOBAL(ASYM($1))
+ASYM($1):
+ /* set up the parameters */
+ movq P, %rdi
+ NBIF_ARG(%rsi,1,0)
+
+ /* make the call on the C stack */
+ SWITCH_ERLANG_TO_C
+ pushq %rsi
+ movq %rsp, %rsi /* Eterm* BIF__ARGS */
+ sub $(8), %rsp /* stack frame 16-byte alignment */
+ CALL_BIF($2)
+ add $(1*8 + 8), %rsp
+ SWITCH_C_TO_ERLANG
+
+ /* throw exception if failure, otherwise return */
+ TEST_GOT_EXN
+ jz nbif_1_simple_exception
+ NBIF_RET(1)
+ SET_SIZE(ASYM($1))
+ TYPE_FUNCTION(ASYM($1))
+#endif')
+
+
+/*
* noproc_primop_interface_0(nbif_name, cbif_name)
* noproc_primop_interface_1(nbif_name, cbif_name)
* noproc_primop_interface_2(nbif_name, cbif_name)
diff --git a/erts/emulator/hipe/hipe_bif0.tab b/erts/emulator/hipe/hipe_bif0.tab
index 4038ca7ef8..4f73770d24 100644
--- a/erts/emulator/hipe/hipe_bif0.tab
+++ b/erts/emulator/hipe/hipe_bif0.tab
@@ -140,3 +140,4 @@ atom bs_validate_unicode_retract
atom emulate_fpe
atom emasculate_binary
atom is_divisible
+atom is_unicode \ No newline at end of file
diff --git a/erts/emulator/hipe/hipe_bif_list.m4 b/erts/emulator/hipe/hipe_bif_list.m4
index f034c4700c..b86f2dafdc 100644
--- a/erts/emulator/hipe/hipe_bif_list.m4
+++ b/erts/emulator/hipe/hipe_bif_list.m4
@@ -223,6 +223,7 @@ standard_bif_interface_3(nbif_find_na_or_make_stub, hipe_find_na_or_make_stub)
standard_bif_interface_2(nbif_nonclosure_address, hipe_nonclosure_address)
nocons_nofail_primop_interface_0(nbif_fclearerror_error, hipe_fclearerror_error)
standard_bif_interface_2(nbif_is_divisible, hipe_is_divisible)
+noproc_primop_interface_1(nbif_is_unicode, hipe_is_unicode)
/*
* Mbox primops with implicit P parameter.
@@ -247,7 +248,11 @@ nofail_primop_interface_3(nbif_bs_get_float_2, erts_bs_get_float_2)
standard_bif_interface_3(nbif_bs_put_utf8, hipe_bs_put_utf8)
standard_bif_interface_3(nbif_bs_put_utf16be, hipe_bs_put_utf16be)
standard_bif_interface_3(nbif_bs_put_utf16le, hipe_bs_put_utf16le)
+ifdef(`nogc_bif_interface_1',`
+nogc_bif_interface_1(nbif_bs_validate_unicode, hipe_bs_validate_unicode)
+',`
standard_bif_interface_1(nbif_bs_validate_unicode, hipe_bs_validate_unicode)
+')
/*
* Bit-syntax primops without any P parameter.
diff --git a/erts/emulator/hipe/hipe_debug.c b/erts/emulator/hipe/hipe_debug.c
index 222a11db3d..929b2a9432 100644
--- a/erts/emulator/hipe/hipe_debug.c
+++ b/erts/emulator/hipe/hipe_debug.c
@@ -63,12 +63,13 @@ static void print_beam_pc(BeamInstr *pc)
printf("normal-process-exit");
} else {
ErtsCodeMFA *cmfa = find_function_from_pc(pc);
- if (cmfa)
+ if (cmfa) {
+ fflush(stdout);
erts_printf("%T:%T/%bpu + 0x%bpx",
cmfa->module, cmfa->function,
cmfa->arity,
pc - erts_codemfa_to_code(cmfa));
- else
+ } else
printf("?");
}
}
@@ -116,6 +117,7 @@ static void print_stack(Eterm *sp, Eterm *end)
printf(" | 0x%0*lx | 0x%0*lx | ",
2*(int)sizeof(long), (unsigned long)sp,
2*(int)sizeof(long), (unsigned long)val);
+ fflush(stdout);
erts_printf("%.30T", val);
printf("\r\n");
}
@@ -126,7 +128,9 @@ static void print_stack(Eterm *sp, Eterm *end)
void hipe_print_estack(Process *p)
{
- printf(" | BEAM STACK |\r\n");
+ printf(" | %*s BEAM STACK %*s |\r\n",
+ 2*(int)sizeof(long)-3, "",
+ 2*(int)sizeof(long)-4, "");
print_stack(p->stop, STACK_START(p));
}
@@ -135,7 +139,9 @@ static void print_heap(Eterm *pos, Eterm *end)
printf("From: 0x%0*lx to 0x%0*lx\n\r",
2*(int)sizeof(long), (unsigned long)pos,
2*(int)sizeof(long), (unsigned long)end);
- printf(" | H E A P |\r\n");
+ printf(" | %*s H E A P %*s |\r\n",
+ 2*(int)sizeof(long)-1, "",
+ 2*(int)sizeof(long)-1, "");
printf(" | %*s | %*s |\r\n",
2+2*(int)sizeof(long), "Address",
2+2*(int)sizeof(long), "Contents");
@@ -158,8 +164,10 @@ static void print_heap(Eterm *pos, Eterm *end)
++pos;
--ari;
}
- } else
+ } else {
+ fflush(stdout);
erts_printf("%.30T", val);
+ }
printf("\r\n");
}
printf(" |%s|%s|\r\n", dashes, dashes);
@@ -173,11 +181,15 @@ void hipe_print_heap(Process *p)
void hipe_print_pcb(Process *p)
{
printf("P: 0x%0*lx\r\n", 2*(int)sizeof(long), (unsigned long)p);
- printf("-----------------------------------------------\r\n");
- printf("Offset| Name | Value | *Value |\r\n");
+ printf("%.*s\r\n",
+ 6+1+13+1+2*(int)sizeof(long)+4+1+2*(int)sizeof(long)+4+1,
+ "---------------------------------------------------------------");
+ printf("Offset| Name | Value %*s | *Value %*s |\r\n",
+ 2*(int)sizeof(long)-4, "",
+ 2*(int)sizeof(long)-5, "");
#undef U
#define U(n,x) \
- printf(" % 4d | %s | 0x%0*lx | |\r\n", (int)offsetof(Process,x), n, 2*(int)sizeof(long), (unsigned long)p->x)
+ printf(" % 4d | %s | 0x%0*lx | %*s |\r\n", (int)offsetof(Process,x), n, 2*(int)sizeof(long), (unsigned long)p->x, 2*(int)sizeof(long)+2, "")
#undef P
#define P(n,x) \
printf(" % 4d | %s | 0x%0*lx | 0x%0*lx |\r\n", (int)offsetof(Process,x), n, 2*(int)sizeof(long), (unsigned long)p->x, 2*(int)sizeof(long), p->x ? (unsigned long)*(p->x) : -1UL)
@@ -241,5 +253,7 @@ void hipe_print_pcb(Process *p)
#endif /* HIPE */
#undef U
#undef P
- printf("-----------------------------------------------\r\n");
+ printf("%.*s\r\n",
+ 6+1+14+1+2*(int)sizeof(long)+4+1+2*(int)sizeof(long)+4+1,
+ "---------------------------------------------------------------");
}
diff --git a/erts/emulator/hipe/hipe_native_bif.c b/erts/emulator/hipe/hipe_native_bif.c
index d8044fe6da..e1c22701d0 100644
--- a/erts/emulator/hipe/hipe_native_bif.c
+++ b/erts/emulator/hipe/hipe_native_bif.c
@@ -495,6 +495,12 @@ BIF_RETTYPE nbif_impl_hipe_bs_validate_unicode(NBIF_ALIST_1)
return NIL;
}
+Uint hipe_is_unicode(Eterm arg)
+{
+ return (Uint) validate_unicode(arg);
+}
+
+
int hipe_bs_validate_unicode_retract(ErlBinMatchBuffer* mb, Eterm arg)
{
if (!validate_unicode(arg)) {
diff --git a/erts/emulator/hipe/hipe_native_bif.h b/erts/emulator/hipe/hipe_native_bif.h
index 38f874888b..1127d4ac56 100644
--- a/erts/emulator/hipe/hipe_native_bif.h
+++ b/erts/emulator/hipe/hipe_native_bif.h
@@ -67,6 +67,7 @@ AEXTERN(Eterm,nbif_bs_put_utf16be,(Process*,Eterm,byte*,unsigned int));
AEXTERN(Eterm,nbif_bs_put_utf16le,(Process*,Eterm,byte*,unsigned int));
AEXTERN(Eterm,nbif_bs_get_utf16,(void));
AEXTERN(Eterm,nbif_bs_validate_unicode,(Process*,Eterm));
+AEXTERN(Uint,nbif_is_unicode,(Eterm));
AEXTERN(Eterm,nbif_bs_validate_unicode_retract,(void));
AEXTERN(void,nbif_is_divisible,(Process*,Uint,Uint));
@@ -92,6 +93,7 @@ Eterm hipe_bs_utf16_size(Eterm);
BIF_RETTYPE nbif_impl_hipe_bs_put_utf16be(NBIF_ALIST_3);
BIF_RETTYPE nbif_impl_hipe_bs_put_utf16le(NBIF_ALIST_3);
BIF_RETTYPE nbif_impl_hipe_bs_validate_unicode(NBIF_ALIST_1);
+Uint hipe_is_unicode(Eterm);
struct erl_bin_match_buffer;
int hipe_bs_validate_unicode_retract(struct erl_bin_match_buffer*, Eterm);
BIF_RETTYPE nbif_impl_hipe_is_divisible(NBIF_ALIST_2);
diff --git a/erts/emulator/hipe/hipe_primops.h b/erts/emulator/hipe/hipe_primops.h
index 4fcbc9df38..77f0dfe7e5 100644
--- a/erts/emulator/hipe/hipe_primops.h
+++ b/erts/emulator/hipe/hipe_primops.h
@@ -66,6 +66,7 @@ PRIMOP_LIST(am_bs_put_utf16be, &nbif_bs_put_utf16be)
PRIMOP_LIST(am_bs_put_utf16le, &nbif_bs_put_utf16le)
PRIMOP_LIST(am_bs_get_utf16, &nbif_bs_get_utf16)
PRIMOP_LIST(am_bs_validate_unicode, &nbif_bs_validate_unicode)
+PRIMOP_LIST(am_is_unicode, &nbif_is_unicode)
PRIMOP_LIST(am_bs_validate_unicode_retract, &nbif_bs_validate_unicode_retract)
PRIMOP_LIST(am_is_divisible, &nbif_is_divisible)
diff --git a/erts/emulator/hipe/hipe_risc_stack.c b/erts/emulator/hipe/hipe_risc_stack.c
index 4001bedeb6..bb93a918a2 100644
--- a/erts/emulator/hipe/hipe_risc_stack.c
+++ b/erts/emulator/hipe/hipe_risc_stack.c
@@ -47,8 +47,10 @@ static void print_slot(Eterm *sp, unsigned int live)
printf(" | 0x%0*lx | 0x%0*lx | ",
2*(int)sizeof(long), (unsigned long)sp,
2*(int)sizeof(long), val);
- if (live)
+ if (live) {
+ fflush(stdout);
erts_printf("%.30T", val);
+ }
printf("\r\n");
}
@@ -68,7 +70,9 @@ void hipe_print_nstack(Process *p)
[0 ... 2*sizeof(long)+3] = '-'
};
- printf(" | NATIVE STACK |\r\n");
+ printf(" | %*s NATIVE STACK %*s |\r\n",
+ 2*(int)sizeof(long)-5, "",
+ 2*(int)sizeof(long)-4, "");
printf(" |%s|%s|\r\n", dashes, dashes);
printf(" | %*s | 0x%0*lx |\r\n",
2+2*(int)sizeof(long), "heap",
diff --git a/erts/emulator/hipe/hipe_x86_stack.c b/erts/emulator/hipe/hipe_x86_stack.c
index 31582b3a2e..615e07917a 100644
--- a/erts/emulator/hipe/hipe_x86_stack.c
+++ b/erts/emulator/hipe/hipe_x86_stack.c
@@ -43,8 +43,10 @@ static void print_slot(Eterm *sp, unsigned int live)
printf(" | 0x%0*lx | 0x%0*lx | ",
2*(int)sizeof(long), (unsigned long)sp,
2*(int)sizeof(long), val);
- if (live)
+ if (live) {
+ fflush(stdout);
erts_printf("%.30T", val);
+ }
printf("\r\n");
}
@@ -74,7 +76,9 @@ void hipe_print_nstack(Process *p)
sdesc0.livebits[0] = ~1;
sdesc = &sdesc0;
- printf(" | NATIVE STACK |\r\n");
+ printf(" | %*s NATIVE STACK %*s |\r\n",
+ 2*(int)sizeof(long)-5, "",
+ 2*(int)sizeof(long)-4, "");
printf(" |%s|%s|\r\n", dashes, dashes);
printf(" | %*s | 0x%0*lx |\r\n",
2+2*(int)sizeof(long), "heap",
diff --git a/erts/emulator/test/code_SUITE.erl b/erts/emulator/test/code_SUITE.erl
index 77321aa50f..dca600bc7b 100644
--- a/erts/emulator/test/code_SUITE.erl
+++ b/erts/emulator/test/code_SUITE.erl
@@ -25,6 +25,7 @@
multi_proc_purge/1, t_check_old_code/1,
external_fun/1,get_chunk/1,module_md5/1,
constant_pools/1,constant_refc_binaries/1,
+ fake_literals/1,
false_dependency/1,coverage/1,fun_confusion/1,
t_copy_literals/1, t_copy_literals_frags/1]).
@@ -38,7 +39,8 @@ all() ->
call_purged_fun_code_reload, call_purged_fun_code_there,
multi_proc_purge, t_check_old_code, external_fun, get_chunk,
module_md5,
- constant_pools, constant_refc_binaries, false_dependency,
+ constant_pools, constant_refc_binaries, fake_literals,
+ false_dependency,
coverage, fun_confusion, t_copy_literals, t_copy_literals_frags].
init_per_suite(Config) ->
@@ -554,6 +556,62 @@ wait_for_memory_deallocations() ->
wait_for_memory_deallocations()
end.
+fake_literals(_Config) ->
+ Mod = fake__literals__module,
+ try
+ do_fake_literals(Mod)
+ after
+ _ = code:purge(Mod),
+ _ = code:delete(Mod),
+ _ = code:purge(Mod),
+ _ = code:delete(Mod)
+ end,
+ ok.
+
+do_fake_literals(Mod) ->
+ Tid = ets:new(test, []),
+ ExtTerms = get_external_terms(),
+ Term0 = {self(),make_ref(),Tid,fun() -> ok end,ExtTerms},
+ Terms = [begin
+ make_literal_module(Mod, Term0),
+ Mod:term()
+ end || _ <- lists:seq(1, 10)],
+ verify_lit_terms(Terms, Term0),
+ true = ets:delete(Tid),
+ ok.
+
+make_literal_module(Mod, Term) ->
+ Exp = [{term,0}],
+ Attr = [],
+ Fs = [{function,term,0,2,
+ [{label,1},
+ {line,[]},
+ {func_info,{atom,Mod},{atom,term},0},
+ {label,2},
+ {move,{literal,Term},{x,0}},
+ return]}],
+ Asm = {Mod,Exp,Attr,Fs,2},
+ {ok,Mod,Beam} = compile:forms(Asm, [from_asm,binary,report]),
+ code:load_binary(Mod, atom_to_list(Mod), Beam).
+
+verify_lit_terms([H|T], Term) ->
+ case H =:= Term of
+ true ->
+ verify_lit_terms(T, Term);
+ false ->
+ error({bad_term,H})
+ end;
+verify_lit_terms([], _) ->
+ ok.
+
+get_external_terms() ->
+ {ok,Node} = test_server:start_node(?FUNCTION_NAME, slave, []),
+ Ref = rpc:call(Node, erlang, make_ref, []),
+ Ports = rpc:call(Node, erlang, ports, []),
+ Pid = rpc:call(Node, erlang, self, []),
+ _ = test_server:stop_node(Node),
+ {Ref,hd(Ports),Pid}.
+
%% OTP-7559: c_p->cp could contain garbage and create a false dependency
%% to a module in a process. (Thanks to Richard Carlsson.)
false_dependency(Config) when is_list(Config) ->
diff --git a/erts/emulator/test/distribution_SUITE.erl b/erts/emulator/test/distribution_SUITE.erl
index 4a0b299e03..e731b68f2f 100644
--- a/erts/emulator/test/distribution_SUITE.erl
+++ b/erts/emulator/test/distribution_SUITE.erl
@@ -1363,81 +1363,59 @@ bad_dist_structure(Config) when is_list(Config) ->
start_monitor(Offender,P),
P ! one,
send_bad_structure(Offender, P,{?DOP_MONITOR_P_EXIT,'replace',P,normal},2),
- pong = rpc:call(Victim, net_adm, ping, [Offender]),
+
start_monitor(Offender,P),
send_bad_structure(Offender, P,{?DOP_MONITOR_P_EXIT,'replace',P,normal,normal},2),
- pong = rpc:call(Victim, net_adm, ping, [Offender]),
+
start_link(Offender,P),
send_bad_structure(Offender, P,{?DOP_LINK},0),
- pong = rpc:call(Victim, net_adm, ping, [Offender]),
+
start_link(Offender,P),
send_bad_structure(Offender, P,{?DOP_UNLINK,'replace'},2),
- pong = rpc:call(Victim, net_adm, ping, [Offender]),
+
start_link(Offender,P),
send_bad_structure(Offender, P,{?DOP_UNLINK,'replace',make_ref()},2),
- pong = rpc:call(Victim, net_adm, ping, [Offender]),
+
start_link(Offender,P),
send_bad_structure(Offender, P,{?DOP_UNLINK,make_ref(),P},0),
- pong = rpc:call(Victim, net_adm, ping, [Offender]),
+
start_link(Offender,P),
send_bad_structure(Offender, P,{?DOP_UNLINK,normal,normal},0),
- pong = rpc:call(Victim, net_adm, ping, [Offender]),
+
start_monitor(Offender,P),
send_bad_structure(Offender, P,{?DOP_MONITOR_P,'replace',P},2),
- pong = rpc:call(Victim, net_adm, ping, [Offender]),
+
start_monitor(Offender,P),
send_bad_structure(Offender, P,{?DOP_MONITOR_P,'replace',P,normal},2),
- pong = rpc:call(Victim, net_adm, ping, [Offender]),
+
start_monitor(Offender,P),
send_bad_structure(Offender, P,{?DOP_DEMONITOR_P,'replace',P},2),
- pong = rpc:call(Victim, net_adm, ping, [Offender]),
+
start_monitor(Offender,P),
send_bad_structure(Offender, P,{?DOP_DEMONITOR_P,'replace',P,normal},2),
- pong = rpc:call(Victim, net_adm, ping, [Offender]),
+
send_bad_structure(Offender, P,{?DOP_EXIT,'replace',P},2),
- pong = rpc:call(Victim, net_adm, ping, [Offender]),
send_bad_structure(Offender, P,{?DOP_EXIT,make_ref(),normal,normal},0),
- pong = rpc:call(Victim, net_adm, ping, [Offender]),
send_bad_structure(Offender, P,{?DOP_EXIT_TT,'replace',token,P},2),
- pong = rpc:call(Victim, net_adm, ping, [Offender]),
send_bad_structure(Offender, P,{?DOP_EXIT_TT,make_ref(),token,normal,normal},0),
- pong = rpc:call(Victim, net_adm, ping, [Offender]),
send_bad_structure(Offender, P,{?DOP_EXIT2,'replace',P},2),
- pong = rpc:call(Victim, net_adm, ping, [Offender]),
send_bad_structure(Offender, P,{?DOP_EXIT2,make_ref(),normal,normal},0),
- pong = rpc:call(Victim, net_adm, ping, [Offender]),
send_bad_structure(Offender, P,{?DOP_EXIT2_TT,'replace',token,P},2),
- pong = rpc:call(Victim, net_adm, ping, [Offender]),
send_bad_structure(Offender, P,{?DOP_EXIT2_TT,make_ref(),token,normal,normal},0),
- pong = rpc:call(Victim, net_adm, ping, [Offender]),
send_bad_structure(Offender, P,{?DOP_GROUP_LEADER,'replace'},2),
- pong = rpc:call(Victim, net_adm, ping, [Offender]),
send_bad_structure(Offender, P,{?DOP_GROUP_LEADER,'replace','atomic'},2),
- pong = rpc:call(Victim, net_adm, ping, [Offender]),
send_bad_structure(Offender, P,{?DOP_GROUP_LEADER,'replace',P},0),
- pong = rpc:call(Victim, net_adm, ping, [Offender]),
send_bad_structure(Offender, P,{?DOP_REG_SEND_TT,'replace','',name},2,{message}),
- pong = rpc:call(Victim, net_adm, ping, [Offender]),
send_bad_structure(Offender, P,{?DOP_REG_SEND_TT,'replace','',name,token},0,{message}),
- pong = rpc:call(Victim, net_adm, ping, [Offender]),
send_bad_structure(Offender, P,{?DOP_REG_SEND,'replace',''},2,{message}),
- pong = rpc:call(Victim, net_adm, ping, [Offender]),
send_bad_structure(Offender, P,{?DOP_REG_SEND,'replace','',P},0,{message}),
- pong = rpc:call(Victim, net_adm, ping, [Offender]),
send_bad_structure(Offender, P,{?DOP_REG_SEND,'replace','',name},0,{message}),
- pong = rpc:call(Victim, net_adm, ping, [Offender]),
send_bad_structure(Offender, P,{?DOP_REG_SEND,'replace','',name,{token}},2,{message}),
- pong = rpc:call(Victim, net_adm, ping, [Offender]),
send_bad_structure(Offender, P,{?DOP_SEND_TT,'',P},0,{message}),
- pong = rpc:call(Victim, net_adm, ping, [Offender]),
send_bad_structure(Offender, P,{?DOP_SEND_TT,'',name,token},0,{message}),
- pong = rpc:call(Victim, net_adm, ping, [Offender]),
send_bad_structure(Offender, P,{?DOP_SEND,''},0,{message}),
- pong = rpc:call(Victim, net_adm, ping, [Offender]),
send_bad_structure(Offender, P,{?DOP_SEND,'',name},0,{message}),
- pong = rpc:call(Victim, net_adm, ping, [Offender]),
send_bad_structure(Offender, P,{?DOP_SEND,'',P,{token}},0,{message}),
- pong = rpc:call(Victim, net_adm, ping, [Offender]),
P ! two,
P ! check_msgs,
receive
@@ -1683,13 +1661,16 @@ bad_dist_ext_size(Config) when is_list(Config) ->
start_node_monitors([Offender,Victim]),
Parent = self(),
- P = spawn_link(Victim,
+ P = spawn_opt(Victim,
fun () ->
Parent ! {self(), started},
receive check_msgs -> ok end, %% DID CRASH HERE
bad_dist_ext_check_msgs([one]),
Parent ! {self(), messages_checked}
- end),
+ end,
+ [link,
+ %% on_heap to force total_heap_size to inspect msg queue
+ {message_queue_data, on_heap}]),
receive {P, started} -> ok end,
P ! one,
@@ -1712,6 +1693,7 @@ bad_dist_ext_size(Config) when is_list(Config) ->
verify_still_up(Offender, Victim),
+ %% Let process_info(P, total_heap_size) find bad msg and disconnect
rpc:call(Victim, erlang, process_info, [P, total_heap_size]),
verify_down(Offender, connection_closed, Victim, killed),
@@ -1792,10 +1774,11 @@ send_bad_structure(Offender,Victim,Bad,WhereToPutSelf) ->
send_bad_structure(Offender,Victim,Bad,WhereToPutSelf,PayLoad) ->
Parent = self(),
Done = make_ref(),
- spawn(Offender,
+ spawn_link(Offender,
fun () ->
Node = node(Victim),
pong = net_adm:ping(Node),
+ erlang:monitor_node(Node, true),
DPrt = dport(Node),
Bad1 = case WhereToPutSelf of
0 ->
@@ -1809,7 +1792,16 @@ send_bad_structure(Offender,Victim,Bad,WhereToPutSelf,PayLoad) ->
[] -> [];
_Other -> [dmsg_ext(PayLoad)]
end,
+
+ receive {nodedown, Node} -> exit("premature nodedown")
+ after 10 -> ok
+ end,
+
port_command(DPrt, DData),
+
+ receive {nodedown, Node} -> ok
+ after 5000 -> exit("missing nodedown")
+ end,
Parent ! {DData,Done}
end),
receive
diff --git a/erts/emulator/test/match_spec_SUITE.erl b/erts/emulator/test/match_spec_SUITE.erl
index 92ddc23592..08a7b4560c 100644
--- a/erts/emulator/test/match_spec_SUITE.erl
+++ b/erts/emulator/test/match_spec_SUITE.erl
@@ -21,7 +21,7 @@
-module(match_spec_SUITE).
-export([all/0, suite/0, not_run/1]).
--export([test_1/1, test_2/1, test_3/1, bad_match_spec_bin/1,
+-export([test_1/1, test_2/1, test_3/1, caller_and_return_to/1, bad_match_spec_bin/1,
trace_control_word/1, silent/1, silent_no_ms/1, silent_test/1,
ms_trace2/1, ms_trace3/1, ms_trace_dead/1, boxed_and_small/1,
destructive_in_test_bif/1, guard_exceptions/1,
@@ -47,7 +47,7 @@ suite() ->
all() ->
case test_server:is_native(match_spec_SUITE) of
false ->
- [test_1, test_2, test_3, bad_match_spec_bin,
+ [test_1, test_2, test_3, caller_and_return_to, bad_match_spec_bin,
trace_control_word, silent, silent_no_ms, silent_test, ms_trace2,
ms_trace3, ms_trace_dead, boxed_and_small, destructive_in_test_bif,
guard_exceptions, unary_plus, unary_minus, fpe,
@@ -180,6 +180,50 @@ test_3(Config) when is_list(Config) ->
collect(P1, [{trace, P1, call, {?MODULE, f2, [a, b]}, [true]}]),
ok.
+%% Test that caller and return to work as they should
+%% There was a bug where caller would be undefined when return_to was set
+%% for r the bif erlang:put().
+caller_and_return_to(Config) ->
+ tr(
+ fun do_put_wrapper/0,
+ fun (Tracee) ->
+ MsgCaller = [{'_',[],[{message,{caller}}]}],
+ 1 = erlang:trace(Tracee, true, [call,return_to]),
+ 1 = erlang:trace_pattern( {?MODULE,do_put,1}, MsgCaller, [local]),
+ 1 = erlang:trace_pattern( {?MODULE,do_the_put,1}, MsgCaller, [local]),
+ 1 = erlang:trace_pattern( {erlang,integer_to_list,1}, MsgCaller, [local]),
+ 1 = erlang:trace_pattern( {erlang,put,2}, MsgCaller, [local]),
+
+ [{trace,Tracee,call,{?MODULE,do_put,[test]},{?MODULE,do_put_wrapper,0}},
+ {trace,Tracee,call,{?MODULE,do_the_put,[test]},{?MODULE,do_put,1}},
+ {trace,Tracee,call,{erlang,integer_to_list,[1]},{?MODULE,do_the_put,1}},
+ {trace,Tracee,return_to,{?MODULE,do_the_put,1}},
+ {trace,Tracee,call,{erlang,put,[test,"1"]},{?MODULE,do_put,1}},
+ {trace,Tracee,return_to,{?MODULE,do_put,1}},
+
+ %% These last trace messages are a bit strange...
+ %% if call tracing had been enabled for do_put_wrapper
+ %% then caller and return_to would have been {?MODULE,do_put_wrapper,1}
+ %% but since it is not, they are set to do_put instead, but we still
+ %% get the do_put_wrapper return_to message...
+ {trace,Tracee,call,{erlang,integer_to_list,[2]},{?MODULE,do_put,1}},
+ {trace,Tracee,return_to,{?MODULE,do_put,1}},
+ {trace,Tracee,return_to,{?MODULE,do_put_wrapper,0}}
+ ]
+ end),
+ ok.
+
+do_put_wrapper() ->
+ do_put(test),
+ ok.
+
+do_put(Var) ->
+ do_the_put(Var),
+ erlang:integer_to_list(id(2)).
+do_the_put(Var) ->
+ Lst = erlang:integer_to_list(id(1)),
+ erlang:put(Var, Lst).
+
otp_9422(Config) when is_list(Config) ->
Laps = 10000,
Fun1 = fun() -> otp_9422_tracee() end,
diff --git a/erts/emulator/test/process_SUITE.erl b/erts/emulator/test/process_SUITE.erl
index a9f20f9928..a8bcfac84d 100644
--- a/erts/emulator/test/process_SUITE.erl
+++ b/erts/emulator/test/process_SUITE.erl
@@ -2532,8 +2532,13 @@ system_task_on_suspended(Config) when is_list(Config) ->
end.
gc_request_when_gc_disabled(Config) when is_list(Config) ->
- Master = self(),
AIS = erts_debug:set_internal_state(available_internal_state, true),
+ gc_request_when_gc_disabled_do(ref),
+ gc_request_when_gc_disabled_do(immed),
+ erts_debug:set_internal_state(available_internal_state, AIS).
+
+gc_request_when_gc_disabled_do(ReqIdType) ->
+ Master = self(),
{P, M} = spawn_opt(fun () ->
true = erts_debug:set_internal_state(gc_state,
false),
@@ -2545,7 +2550,10 @@ gc_request_when_gc_disabled(Config) when is_list(Config) ->
receive after 100 -> ok end
end, [monitor, link]),
receive {P, gc_state, false} -> ok end,
- ReqId = make_ref(),
+ ReqId = case ReqIdType of
+ ref -> make_ref();
+ immed -> immed
+ end,
async = garbage_collect(P, [{async, ReqId}]),
receive
{garbage_collect, ReqId, Result} ->
@@ -2554,7 +2562,6 @@ gc_request_when_gc_disabled(Config) when is_list(Config) ->
ok
end,
receive {garbage_collect, ReqId, true} -> ok end,
- erts_debug:set_internal_state(available_internal_state, AIS),
receive {'DOWN', M, process, P, _Reason} -> ok end,
ok.
diff --git a/erts/emulator/test/trace_SUITE.erl b/erts/emulator/test/trace_SUITE.erl
index 72acd33033..a81aa64057 100644
--- a/erts/emulator/test/trace_SUITE.erl
+++ b/erts/emulator/test/trace_SUITE.erl
@@ -38,7 +38,7 @@
system_monitor_long_gc_1/1, system_monitor_long_gc_2/1,
system_monitor_large_heap_1/1, system_monitor_large_heap_2/1,
system_monitor_long_schedule/1,
- bad_flag/1, trace_delivered/1]).
+ bad_flag/1, trace_delivered/1, trap_exit_self_receive/1]).
-include_lib("common_test/include/ct.hrl").
@@ -61,7 +61,8 @@ all() ->
more_system_monitor_args, system_monitor_long_gc_1,
system_monitor_long_gc_2, system_monitor_large_heap_1,
system_monitor_long_schedule,
- system_monitor_large_heap_2, bad_flag, trace_delivered].
+ system_monitor_large_heap_2, bad_flag, trace_delivered,
+ trap_exit_self_receive].
init_per_testcase(_Case, Config) ->
[{receiver,spawn(fun receiver/0)}|Config].
@@ -1709,6 +1710,31 @@ trace_delivered(Config) when is_list(Config) ->
ok
end.
+%% This testcase checks that receive trace works on exit signal messages
+%% when the sender of the exit signal is the process itself.
+trap_exit_self_receive(Config) ->
+ Parent = self(),
+ Proc = spawn_link(fun() -> process(Parent) end),
+
+ 1 = erlang:trace(Proc, true, ['receive']),
+ Proc ! {trap_exit_please, true},
+ {trace, Proc, 'receive', {trap_exit_please, true}} = receive_first_trace(),
+
+ %% Make the process call exit(self(), signal)
+ Reason1 = make_ref(),
+ Proc ! {exit_signal_please, Reason1},
+ {trace, Proc, 'receive', {exit_signal_please, Reason1}} = receive_first_trace(),
+ {trace, Proc, 'receive', {'EXIT', Proc, Reason1}} = receive_first_trace(),
+ receive {Proc, {'EXIT', Proc, Reason1}} -> ok end,
+ receive_nothing(),
+
+ unlink(Proc),
+ Reason2 = make_ref(),
+ Proc ! {exit_please, Reason2},
+ {trace, Proc, 'receive', {exit_please, Reason2}} = receive_first_trace(),
+ receive_nothing(),
+ ok.
+
drop_trace_until_down(Proc, Mon) ->
drop_trace_until_down(Proc, Mon, false, 0, 0).
@@ -1791,6 +1817,9 @@ process(Dest) ->
process(Dest);
{exit_please, Reason} ->
exit(Reason);
+ {exit_signal_please, Reason} ->
+ exit(self(), Reason),
+ process(Dest);
{trap_exit_please, State} ->
process_flag(trap_exit, State),
process(Dest);
diff --git a/erts/etc/common/erlexec.c b/erts/etc/common/erlexec.c
index 51ed2d0dff..eaa94cd5e4 100644
--- a/erts/etc/common/erlexec.c
+++ b/erts/etc/common/erlexec.c
@@ -36,6 +36,7 @@
#ifdef __WIN32__
# include "erl_version.h"
# include "init_file.h"
+# include <Shlobj.h>
#endif
#define NO 0
@@ -1541,17 +1542,16 @@ static void get_parameters(int argc, char** argv)
static void
get_home(void)
{
- int len;
- char tmpstr[MAX_PATH+1];
+ wchar_t *profile;
char* homedrive;
char* homepath;
homedrive = get_env("HOMEDRIVE");
homepath = get_env("HOMEPATH");
if (!homedrive || !homepath) {
- if (len = GetWindowsDirectory(tmpstr,MAX_PATH)) {
- home = emalloc(len+1);
- strcpy(home,tmpstr);
+ if (SHGetKnownFolderPath(&FOLDERID_Profile, 0, NULL, &profile) == S_OK) {
+ home = utf16_to_utf8(profile);
+ /* CoTaskMemFree(profile); */
} else
error("HOMEDRIVE or HOMEPATH is not set and GetWindowsDir failed");
} else {
diff --git a/erts/etc/unix/cerl.src b/erts/etc/unix/cerl.src
index 30f2d831b5..862d6eb1d4 100644
--- a/erts/etc/unix/cerl.src
+++ b/erts/etc/unix/cerl.src
@@ -45,6 +45,8 @@
# -valgrind Run emulator compiled for valgrind
# -lcnt Run emulator compiled for lock counting
# -icount Run emulator compiled for instruction counting
+# -rr Run emulator under "rr record"
+# Can be combined with compile targets (like -debug) except valgrind.
# -nox Unset the DISPLAY variable to disable us of X Windows
#
# FIXME For GDB you can also set the break point using "-break FUNCTION".
@@ -84,6 +86,8 @@ GDBARGS=
TYPE=
debug=
run_valgrind=no
+run_rr=no
+skip_erlexec=no
# Default rootdir
ROOTDIR=%SRC_ROOTDIR%
@@ -248,6 +252,13 @@ while [ $# -gt 0 ]; do
cargs="$cargs -valgrind"
TYPE=.valgrind
run_valgrind=yes
+ skip_erlexec=yes
+ ;;
+ "-rr")
+ shift
+ cargs="$cargs -rr"
+ run_rr=yes
+ skip_erlexec=yes
;;
*)
break
@@ -269,7 +280,19 @@ PROGNAME="$PROGNAME$cargs"
EMU="$EMU$TYPE"
EMU_NAME=`$EXEC -emu_name_exit $eeargs`
-if [ $run_valgrind != yes ]; then
+if [ $skip_erlexec = yes ]; then
+ emu_xargs=`echo $xargs | sed "s|+|-|g"`
+ beam_args=`$EXEC -emu_args_exit ${1+"$@"}`
+
+ # Prepare for some argument passing voodoo:
+ # $beam_args is a list of command line arguments separated by newlines.
+ # Make "$@" represent those arguments verbatim (including spaces and quotes).
+ SAVE_IFS="$IFS"
+ IFS='
+'
+ set -- $beam_args
+ IFS="$SAVE_IFS"
+else
xargs="$xargs -pz $PRELOADED --"
fi
if [ "x$GDB" = "x" ]; then
@@ -277,7 +300,6 @@ if [ "x$GDB" = "x" ]; then
valversion=`valgrind --version`
valmajor=`echo $valversion | sed 's,[a-z]*\-\([0-9]*\).*,\1,'`
valminor=`echo $valversion | sed 's,[a-z]*\-[0-9]*.\([0-9]*\).*,\1,'`
- emu_xargs=`echo $xargs | sed "s|+|-|g"`
if [ "x$VALGRIND_LOG_XML" = "x" ]; then
valgrind_xml=
log_file_prefix="--log-file="
@@ -317,17 +339,10 @@ if [ "x$GDB" = "x" ]; then
sched_arg=
fi
- beam_args=`$EXEC -emu_args_exit ${1+"$@"}`
-
- # Time for some argument passing voodoo:
- # $beam_args is a list of command line arguments separated by newlines.
- # Make "$@" represent those arguments verbatim (including spaces and quotes).
- SAVE_IFS="$IFS"
- IFS='
-'
- set -- $beam_args
- IFS="$SAVE_IFS"
exec $taskset1 valgrind $valgrind_xml $valgrind_log $valgrind_misc_flags $BINDIR/$EMU_NAME $sched_arg $emu_xargs "$@" -pz $PRELOADED
+
+ elif [ $run_rr = yes ]; then
+ exec rr record --ignore-nested $BINDIR/$EMU_NAME $emu_xargs "$@" -pz $PRELOADED
else
exec $EXEC $eeargs $xargs ${1+"$@"}
fi
diff --git a/erts/etc/unix/run_erl.c b/erts/etc/unix/run_erl.c
index f05c729eeb..81a0036c99 100644
--- a/erts/etc/unix/run_erl.c
+++ b/erts/etc/unix/run_erl.c
@@ -1343,11 +1343,8 @@ static int sf_open(const char *path, int type, mode_t mode) {
return fd;
}
static int sf_close(int fd) {
- int res = 0;
-
- do { res = close(fd); } while(fd < 0 && errno == EINTR);
-
- return res;
+ /* "close() should not be retried after an EINTR" */
+ return close(fd);
}
/* Extract any control sequences that are ment only for run_erl
* and should not be forwarded to the pty.
diff --git a/erts/include/internal/erl_printf.h b/erts/include/internal/erl_printf.h
index f180a53f18..7e9807f6a8 100644
--- a/erts/include/internal/erl_printf.h
+++ b/erts/include/internal/erl_printf.h
@@ -44,6 +44,7 @@ struct erts_dsprintf_buf_t_ {
typedef int (*fmtfn_t)(void*, char*, size_t);
int erts_write_fd(void *vfdp, char* buf, size_t len);
+int erts_write_fp(void *vfdp, char* buf, size_t len);
int erts_write_ds(void *vdsbufp, char* buf, size_t len);
int erts_printf(const char *, ...);
diff --git a/erts/lib_src/common/erl_printf.c b/erts/lib_src/common/erl_printf.c
index 7781fc2196..3b073bcd1b 100644
--- a/erts/lib_src/common/erl_printf.c
+++ b/erts/lib_src/common/erl_printf.c
@@ -147,8 +147,8 @@ write_f_add_cr(void *vfp, char* buf, size_t len)
return len;
}
-static int
-write_f(void *vfp, char* buf, size_t len)
+int
+erts_write_fp(void *vfp, char* buf, size_t len)
{
ASSERT(vfp);
#ifdef PUTC_ON_SMALL_WRITES
@@ -257,7 +257,7 @@ erts_printf(const char *format, ...)
FLOCKFILE(stdout);
res = erts_printf_format(erts_printf_add_cr_to_stdout
? write_f_add_cr
- : write_f,
+ : erts_write_fp,
(void *) stdout,
(char *) format,
arglist);
@@ -285,7 +285,7 @@ erts_fprintf(FILE *filep, const char *format, ...)
else if (erts_printf_add_cr_to_stderr && filep == stderr)
fmt_f = write_f_add_cr;
else
- fmt_f = write_f;
+ fmt_f = erts_write_fp;
FLOCKFILE(filep);
res = erts_printf_format(fmt_f,(void *)filep,(char *)format,arglist);
FUNLOCKFILE(filep);
@@ -390,7 +390,7 @@ erts_vprintf(const char *format, va_list arglist)
errno = 0;
res = erts_printf_format(erts_printf_add_cr_to_stdout
? write_f_add_cr
- : write_f,
+ : erts_write_fp,
(void *) stdout,
(char *) format,
arglist);
@@ -414,7 +414,7 @@ erts_vfprintf(FILE *filep, const char *format, va_list arglist)
else if (erts_printf_add_cr_to_stderr && filep == stderr)
fmt_f = write_f_add_cr;
else
- fmt_f = write_f;
+ fmt_f = erts_write_fp;
res = erts_printf_format(fmt_f,(void *)filep,(char *)format,arglist);
}
return res;