aboutsummaryrefslogtreecommitdiffstats
path: root/erts
diff options
context:
space:
mode:
Diffstat (limited to 'erts')
-rw-r--r--erts/Makefile.in3
-rw-r--r--erts/configure.in39
-rw-r--r--erts/doc/src/absform.xml12
-rw-r--r--erts/doc/src/erl_ext_dist.xml6
-rw-r--r--erts/doc/src/erlang.xml333
-rw-r--r--erts/doc/src/erlc.xml10
-rw-r--r--erts/doc/src/erts_alloc.xml55
-rw-r--r--erts/doc/src/notes.xml259
-rw-r--r--erts/emulator/beam/atom.names2
-rw-r--r--erts/emulator/beam/beam_bif_load.c145
-rw-r--r--erts/emulator/beam/bif.c76
-rw-r--r--erts/emulator/beam/bif.tab15
-rw-r--r--erts/emulator/beam/break.c12
-rw-r--r--erts/emulator/beam/erl_alloc.c50
-rw-r--r--erts/emulator/beam/erl_alloc.types2
-rw-r--r--erts/emulator/beam/erl_alloc_util.c68
-rw-r--r--erts/emulator/beam/erl_alloc_util.h7
-rwxr-xr-xerts/emulator/beam/erl_bif_info.c18
-rw-r--r--erts/emulator/beam/erl_bif_os.c22
-rw-r--r--erts/emulator/beam/erl_bif_port.c34
-rw-r--r--erts/emulator/beam/erl_binary.h2
-rw-r--r--erts/emulator/beam/erl_bits.c111
-rw-r--r--erts/emulator/beam/erl_debug.c5
-rw-r--r--erts/emulator/beam/erl_gc.c15
-rw-r--r--erts/emulator/beam/erl_message.c2
-rw-r--r--erts/emulator/beam/erl_message.h5
-rw-r--r--erts/emulator/beam/erl_port_task.h11
-rw-r--r--erts/emulator/beam/erl_process.c1444
-rw-r--r--erts/emulator/beam/erl_process.h89
-rw-r--r--erts/emulator/beam/erl_process_dump.c46
-rw-r--r--erts/emulator/beam/erl_zlib.c40
-rw-r--r--erts/emulator/beam/erl_zlib.h6
-rw-r--r--erts/emulator/beam/external.c760
-rw-r--r--erts/emulator/beam/external.h1
-rwxr-xr-xerts/emulator/beam/global.h9
-rw-r--r--erts/emulator/beam/io.c4
-rw-r--r--erts/emulator/beam/ops.tab14
-rw-r--r--erts/emulator/beam/sys.h46
-rw-r--r--erts/emulator/beam/utils.c2
-rw-r--r--erts/emulator/drivers/common/erl_efile.h1
-rw-r--r--erts/emulator/drivers/common/inet_drv.c242
-rw-r--r--erts/emulator/drivers/unix/unix_efile.c9
-rw-r--r--erts/emulator/drivers/win32/win_efile.c7
-rw-r--r--erts/emulator/drivers/win32/winsock_func.h102
-rw-r--r--erts/emulator/hipe/hipe_bif_list.m43
-rw-r--r--erts/emulator/hipe/hipe_native_bif.c17
-rw-r--r--erts/emulator/sys/common/erl_mmap.c12
-rw-r--r--erts/emulator/sys/common/erl_mmap.h4
-rw-r--r--erts/emulator/sys/common/erl_poll.c3
-rw-r--r--erts/emulator/sys/unix/sys.c10
-rw-r--r--erts/emulator/sys/win32/sys_env.c18
-rw-r--r--erts/emulator/test/alloc_SUITE.erl19
-rw-r--r--erts/emulator/test/bif_SUITE.erl10
-rw-r--r--erts/emulator/test/binary_SUITE.erl163
-rw-r--r--erts/emulator/test/code_parallel_load_SUITE.erl36
-rw-r--r--erts/emulator/test/fun_SUITE.erl10
-rw-r--r--erts/emulator/test/hash_SUITE.erl6
-rw-r--r--erts/emulator/test/match_spec_SUITE.erl16
-rw-r--r--erts/emulator/test/process_SUITE.erl219
-rw-r--r--erts/etc/common/erlexec.c34
-rw-r--r--erts/etc/unix/Install.src2
-rw-r--r--erts/etc/unix/cerl.src2
-rw-r--r--erts/etc/unix/etp-commands.in96
-rw-r--r--erts/etc/win32/Install.c2
-rw-r--r--erts/preloaded/ebin/erl_prim_loader.beambin54520 -> 54696 bytes
-rw-r--r--erts/preloaded/ebin/erlang.beambin94272 -> 97872 bytes
-rw-r--r--erts/preloaded/ebin/erts_internal.beambin3276 -> 4096 bytes
-rw-r--r--erts/preloaded/ebin/init.beambin48788 -> 48804 bytes
-rw-r--r--erts/preloaded/ebin/otp_ring0.beambin1436 -> 1464 bytes
-rw-r--r--erts/preloaded/ebin/prim_eval.beambin1352 -> 1340 bytes
-rw-r--r--erts/preloaded/ebin/prim_file.beambin44232 -> 44612 bytes
-rw-r--r--erts/preloaded/ebin/prim_inet.beambin71452 -> 72916 bytes
-rw-r--r--erts/preloaded/ebin/prim_zip.beambin23400 -> 23436 bytes
-rw-r--r--erts/preloaded/ebin/zlib.beambin12828 -> 13148 bytes
-rw-r--r--erts/preloaded/src/Makefile2
-rw-r--r--erts/preloaded/src/erl_prim_loader.erl7
-rw-r--r--erts/preloaded/src/erlang.erl154
-rw-r--r--erts/preloaded/src/erts_internal.erl33
-rw-r--r--erts/preloaded/src/prim_file.erl6
-rw-r--r--erts/preloaded/src/prim_inet.erl98
-rw-r--r--erts/start_scripts/Makefile33
-rw-r--r--erts/start_scripts/no_dot_erlang.rel.src21
-rw-r--r--erts/vsn.mk4
83 files changed, 4238 insertions, 943 deletions
diff --git a/erts/Makefile.in b/erts/Makefile.in
index 92fdc7a862..e3db37d3fd 100644
--- a/erts/Makefile.in
+++ b/erts/Makefile.in
@@ -107,7 +107,8 @@ local_setup:
fi
@cd start_scripts && $(MAKE) $(ERL_TOP)/bin/start.script \
$(ERL_TOP)/bin/start_sasl.script \
- $(ERL_TOP)/bin/start_clean.script
+ $(ERL_TOP)/bin/start_clean.script \
+ $(ERL_TOP)/bin/no_dot_erlang.script
# Run the configure script
.PHONY: configure
diff --git a/erts/configure.in b/erts/configure.in
index 14eae10841..3b4c46d4a5 100644
--- a/erts/configure.in
+++ b/erts/configure.in
@@ -393,30 +393,17 @@ if test X${enable_darwin_64bit} = Xyes -o X${enable_m64_build} = Xyes; then
;;
esac
else
- case $host_os in
- darwin*)
- case $CFLAGS in
- *-m32*)
- ;;
- *)
- CFLAGS="-m32 $CFLAGS"
- ;;
- esac
- ;;
- *)
- if test X${enable_m32_build} = Xyes;
- then
- enable_hipe=no;
- case $CFLAGS in
- *-m32*)
- ;;
- *)
- CFLAGS="-m32 $CFLAGS"
- ;;
- esac ;
- fi
- ;;
- esac
+ if test X${enable_m32_build} = Xyes;
+ then
+ enable_hipe=no;
+ case $CFLAGS in
+ *-m32*)
+ ;;
+ *)
+ CFLAGS="-m32 $CFLAGS"
+ ;;
+ esac ;
+ fi
fi
AC_ARG_ENABLE(static-nifs,
@@ -1658,7 +1645,7 @@ if test "x$enable_sctp" != "xno" ; then
fi
if test x"$ac_cv_header_netinet_sctp_h" = x"yes"; then
- AC_CHECK_FUNCS([sctp_bindx sctp_peeloff])
+ AC_CHECK_FUNCS([sctp_bindx sctp_peeloff sctp_getladdrs sctp_freeladdrs sctp_getpaddrs sctp_freepaddrs])
AC_CHECK_DECLS([SCTP_UNORDERED, SCTP_ADDR_OVER, SCTP_ABORT,
SCTP_EOF, SCTP_SENDALL, SCTP_ADDR_CONFIRMED,
SCTP_DELAYED_ACK_TIME,
@@ -1988,7 +1975,7 @@ AC_CHECK_FUNCS([ieee_handler fpsetmask finite isnan isinf res_gethostbyname dlop
gethrtime localtime_r gmtime_r inet_pton \
mmap mremap memcpy mallopt sbrk _sbrk __sbrk brk _brk __brk \
flockfile fstat strlcpy strlcat setsid posix2time time2posix \
- setlocale nl_langinfo poll])
+ setlocale nl_langinfo poll mlockall])
case X$erl_xcomp_posix_memalign in
diff --git a/erts/doc/src/absform.xml b/erts/doc/src/absform.xml
index 55aef9f8ab..4acc03b133 100644
--- a/erts/doc/src/absform.xml
+++ b/erts/doc/src/absform.xml
@@ -290,6 +290,18 @@
<item>If E is <c><![CDATA[fun Fc_1 ; ... ; Fc_k end]]></c>
where each <c><![CDATA[Fc_i]]></c> is a function clause then Rep(E) =
<c><![CDATA[{'fun',LINE,{clauses,[Rep(Fc_1), ..., Rep(Fc_k)]}}]]></c>.</item>
+ <item>If E is <c><![CDATA[fun Name Fc_1 ; ... ; Name Fc_k end]]></c>
+ where <c><![CDATA[Name]]></c> is a variable and each
+ <c><![CDATA[Fc_i]]></c> is a function clause then Rep(E) =
+ <c><![CDATA[{named_fun,LINE,Name,[Rep(Fc_1), ..., Rep(Fc_k)]}]]></c>.
+ </item>
+ <item>If E is <c><![CDATA[query [E_0 || W_1, ..., W_k] end]]></c>,
+ where each <c><![CDATA[W_i]]></c> is a generator or a filter, then
+ Rep(E) = <c><![CDATA[{'query',LINE,{lc,LINE,Rep(E_0),[Rep(W_1), ..., Rep(W_k)]}}]]></c>.
+ For Rep(W), see below.</item>
+ <item>If E is <c><![CDATA[E_0.Field]]></c>, a Mnesia record access
+ inside a query, then
+ Rep(E) = <c><![CDATA[{record_field,LINE,Rep(E_0),Rep(Field)}]]></c>.</item>
<item>If E is <c><![CDATA[( E_0 )]]></c>, then
Rep(E) = <c><![CDATA[Rep(E_0)]]></c>,
i.e., parenthesized expressions cannot be distinguished from their bodies.</item>
diff --git a/erts/doc/src/erl_ext_dist.xml b/erts/doc/src/erl_ext_dist.xml
index 28e6f1d05e..f91ed78122 100644
--- a/erts/doc/src/erl_ext_dist.xml
+++ b/erts/doc/src/erl_ext_dist.xml
@@ -1014,10 +1014,10 @@
</row>
<tcaption></tcaption></table>
<p>
- This term represents a bitstring whose length in bits is not a
- multiple of 8 (created using the bit syntax in R12B and later).
+ This term represents a bitstring whose length in bits does
+ not have to be a multiple of 8.
The <c>Len</c> field is an unsigned 4 byte integer (big endian).
- The <c>Bits</c> field is the number of bits that are used
+ The <c>Bits</c> field is the number of bits (1-8) that are used
in the last byte in the data field,
counting from the most significant bit towards the least
significant.
diff --git a/erts/doc/src/erlang.xml b/erts/doc/src/erlang.xml
index 7089d2275c..711473afd2 100644
--- a/erts/doc/src/erlang.xml
+++ b/erts/doc/src/erlang.xml
@@ -501,16 +501,87 @@
<name name="check_process_code" arity="2"/>
<fsummary>Check if a process is executing old code for a module</fsummary>
<desc>
- <p>Returns <c>true</c> if the process <c><anno>Pid</anno></c> is executing
- old code for <c><anno>Module</anno></c>. That is, if the current call of
- the process executes old code for this module, or if the
- process has references to old code for this module, or if the
- process contains funs that references old code for this
- module. Otherwise, it returns <c>false</c>.</p>
- <pre>
-> <input>check_process_code(Pid, lists).</input>
-false</pre>
+ <p>The same as
+ <seealso marker="#check_process_code/3"><c>erlang:check_process_code(<anno>Pid</anno>,
+ <anno>Module</anno>, [])</c></seealso>.</p>
+ </desc>
+ </func>
+ <func>
+ <name name="check_process_code" arity="3"/>
+ <fsummary>Check if a process is executing old code for a module</fsummary>
+ <desc>
+ <p>Check if the node local process identified by <c><anno>Pid</anno></c>
+ is executing old code for <c><anno>Module</anno></c>.</p>
+ <p>Currently available <c><anno>Option</anno>s</c>:</p>
+ <taglist>
+ <tag><c>{allow_gc, boolean()}</c></tag>
+ <item>
+ Determines if garbage collection is allowed when performing
+ the operation. If <c>{allow_gc, false}</c> is passed, and
+ a garbage collection is needed in order to determine the
+ result of the operation, the operation will be aborted
+ (see information on <c><anno>CheckResult</anno></c> below).
+ The default is to allow garbage collection, i.e.,
+ <c>{allow_gc, true}</c>.
+ </item>
+ <tag><c>{async, RequestId}</c></tag>
+ <item>
+ The <c>check_process_code/3</c> function will return
+ the value <c>async</c> immediately after the request
+ has been sent. When the request has been processed, the
+ process that called this function will be passed a
+ message on the form:<br/>
+ <c>{check_process_code, <anno>RequestId</anno>, <anno>CheckResult</anno>}</c>.
+ </item>
+ </taglist>
+ <p>If <c><anno>Pid</anno></c> equals <c>self()</c>, and
+ no <c>async</c> option has been passed, the operation will
+ be performed at once. In all other cases a request for
+ the operation will be sent to the process identified by
+ <c><anno>Pid</anno></c>, and will be handled when
+ appropriate. If no <c>async</c> option has been passed,
+ the caller will block until <c><anno>CheckResult</anno></c>
+ is available and can be returned.</p>
+ <p><c><anno>CheckResult</anno></c> informs about the result of
+ the request:</p>
+ <taglist>
+ <tag><c>true</c></tag>
+ <item>
+ The process identified by <c><anno>Pid</anno></c> is
+ executing old code for <c><anno>Module</anno></c>.
+ That is, the current call of the process executes old
+ code for this module, or the process has references
+ to old code for this module, or the process contains
+ funs that references old code for this module.
+ </item>
+ <tag><c>false</c></tag>
+ <item>
+ The process identified by <c><anno>Pid</anno></c> is
+ not executing old code for <c><anno>Module</anno></c>.
+ </item>
+ <tag><c>aborted</c></tag>
+ <item>
+ The operation was aborted since the process needed to
+ be garbage collected in order to determine the result
+ of the operation, and the operation was requested
+ by passing the <c>{allow_gc, false}</c> option.</item>
+ </taglist>
<p>See also <seealso marker="kernel:code">code(3)</seealso>.</p>
+ <p>Failures:</p>
+ <taglist>
+ <tag><c>badarg</c></tag>
+ <item>
+ If <c><anno>Pid</anno></c> is not a node local process identifier.
+ </item>
+ <tag><c>badarg</c></tag>
+ <item>
+ If <c><anno>Module</anno></c> is not an atom.
+ </item>
+ <tag><c>badarg</c></tag>
+ <item>
+ If <c><anno>OptionList</anno></c> is not a valid list of options.
+ </item>
+ </taglist>
</desc>
</func>
<func>
@@ -1197,20 +1268,74 @@ true
that the spontaneous garbage collection will occur too late
or not at all. Improper use may seriously degrade system
performance.</p>
- <p>Compatibility note: In versions of OTP prior to R7,
- the garbage collection took place at the next context switch,
- not immediately. To force a context switch after a call to
- <c>erlang:garbage_collect()</c>, it was sufficient to make
- any function call.</p>
</desc>
</func>
<func>
<name name="garbage_collect" arity="1"/>
- <fsummary>Force an immediate garbage collection of a process</fsummary>
+ <fsummary>Garbage collect a process</fsummary>
<desc>
- <p>Works like <c>erlang:garbage_collect()</c> but on any
- process. The same caveats apply. Returns <c>false</c> if
- <c><anno>Pid</anno></c> refers to a dead process; <c>true</c> otherwise.</p>
+ <p>The same as
+ <seealso marker="#garbage_collect/2"><c>garbage_collect(<anno>Pid</anno>, [])</c></seealso>.</p>
+ </desc>
+ </func>
+ <func>
+ <name name="garbage_collect" arity="2"/>
+ <fsummary>Garbage collect a process</fsummary>
+ <desc>
+ <p>Garbage collect the node local process identified by
+ <c><anno>Pid</anno></c>.</p>
+ <p>Currently available <c><anno>Option</anno></c>s:</p>
+ <taglist>
+ <tag><c>{async, RequestId}</c></tag>
+ <item>
+ The <c>garbage_collect/2</c> function will return
+ the value <c>async</c> immediately after the request
+ has been sent. When the request has been processed, the
+ process that called this function will be passed a
+ message on the form:<br/>
+ <c>{garbage_collect, <anno>RequestId</anno>, <anno>GCResult</anno>}</c>.
+ </item>
+ </taglist>
+ <p>If <c><anno>Pid</anno></c> equals <c>self()</c>, and
+ no <c>async</c> option has been passed, the garbage
+ collection will be performed at once, i.e. the same as
+ calling
+ <seealso marker="#garbage_collect/0">garbage_collect/0</seealso>.
+ In all other cases a request for garbage collection will
+ be sent to the process identified by <c><anno>Pid</anno></c>,
+ and will be handled when appropriate. If no <c>async</c>
+ option has been passed, the caller will block until
+ <c><anno>GCResult</anno></c> is available and can be
+ returned.</p>
+ <p><c><anno>GCResult</anno></c> informs about the result of
+ the garbage collection request:</p>
+ <taglist>
+ <tag><c>true</c></tag>
+ <item>
+ The process identified by <c><anno>Pid</anno></c> has
+ been garbage collected.
+ </item>
+ <tag><c>false</c></tag>
+ <item>
+ No garbage collection was performed. This since the
+ the process identified by <c><anno>Pid</anno></c>
+ terminated before the request could be satisfied.
+ </item>
+ </taglist>
+ <p>Note that the same caveats as for
+ <seealso marker="#garbage_collect/0">garbage_collect/0</seealso>
+ apply.</p>
+ <p>Failures:</p>
+ <taglist>
+ <tag><c>badarg</c></tag>
+ <item>
+ If <c><anno>Pid</anno></c> is not a node local process identifier.
+ </item>
+ <tag><c>badarg</c></tag>
+ <item>
+ If <c><anno>OptionList</anno></c> is not a valid list of options.
+ </item>
+ </taglist>
</desc>
</func>
<func>
@@ -3012,7 +3137,10 @@ os_prompt% </pre>
(see below), being synchronous, and that the port does
<em>not</em> reply with <c>{Port, closed}</c>. Any process may
close a port with <c>port_close/1</c>, not only the port owner
- (the connected process).</p>
+ (the connected process). If the calling process is linked to
+ port identified by <c><anno>Port</anno></c>, an exit signal due
+ to that link will be received by the process prior to the return
+ from <c>port_close/1</c>.</p>
<p>For comparison: <c><anno>Port</anno> ! {self(), close}</c> fails with
<c>badarg</c> if <c><anno>Port</anno></c> cannot be sent to (i.e.,
<c><anno>Port</anno></c> refers neither to a port nor to a process). If
@@ -3021,6 +3149,7 @@ os_prompt% </pre>
the port replies with <c>{Port, closed}</c> when all buffers
have been flushed and the port really closes, but if
the calling process is not the port owner the <em>port owner</em> fails with <c>badsig</c>.</p>
+
<p>Note that any process can close a port using
<c><anno>Port</anno> ! {PortOwner, close}</c> just as if it itself was
the port owner, but the reply always goes to the port owner.</p>
@@ -3030,8 +3159,17 @@ os_prompt% </pre>
implementation has been synchronous. <c>port_close/1</c> is
however still fully synchronous. This due to its error
behavior.</p>
- <p>Failure: <c>badarg</c> if <c><anno>Port</anno></c> is not an open port or
- the registered name of an open port.</p>
+ <p>Failure:</p>
+ <taglist>
+ <tag><c>badarg</c></tag>
+ <item>
+ If <c><anno>Port</anno></c> is not an identifier of an open
+ port, or the registered name of an open port. If the calling
+ process was linked to the previously open port identified by
+ <c><anno>Port</anno></c>, an exit signal due to this link
+ was received by the process prior to this exception.
+ </item>
+ </taglist>
</desc>
</func>
<func>
@@ -3066,8 +3204,11 @@ os_prompt% </pre>
<taglist>
<tag><c>badarg</c></tag>
<item>
- If <c><anno>Port</anno></c> is not an open port or the registered name
- of an open port.
+ If <c><anno>Port</anno></c> is not an identifier of an open
+ port, or the registered name of an open port. If the calling
+ process was linked to the previously open port identified by
+ <c><anno>Port</anno></c>, an exit signal due to this link
+ was received by the process prior to this exception.
</item>
<tag><c>badarg</c></tag>
<item>
@@ -3110,8 +3251,11 @@ os_prompt% </pre>
<taglist>
<tag><c>badarg</c></tag>
<item>
- If <c><anno>Port</anno></c> is not an open port or the registered name
- of an open port.
+ If <c><anno>Port</anno></c> is not an identifier of an open
+ port, or the registered name of an open port. If the calling
+ process was linked to the previously open port identified by
+ <c><anno>Port</anno></c>, an exit signal due to this link
+ was received by the process prior to this exception.
</item>
<tag><c>badarg</c></tag>
<item>
@@ -3178,9 +3322,20 @@ os_prompt% </pre>
implementation has been synchronous. <c>port_connect/2</c> is
however still fully synchronous. This due to its error
behavior.</p>
- <p>Failure: <c>badarg</c> if <c><anno>Port</anno></c> is not an open port
- or the registered name of an open port, or if <c>Pid</c> is
- not an existing local pid.</p>
+ <p>Failures:</p>
+ <taglist>
+ <tag><c>badarg</c></tag>
+ <item>
+ If <c><anno>Port</anno></c> is not an identifier of an open
+ port, or the registered name of an open port. If the calling
+ process was linked to the previously open port identified by
+ <c><anno>Port</anno></c>, an exit signal due to this link
+ was received by the process prior to this exception.
+ </item>
+ <tag><c>badarg</c></tag>
+ <item>If process identified by <c>Pid</c> is not an existing
+ local process.</item>
+ </taglist>
</desc>
</func>
<func>
@@ -3216,12 +3371,33 @@ os_prompt% </pre>
binary term format and sent to the port.</p>
<p>Returns: a term from the driver. The meaning of the returned
data also depends on the port driver.</p>
- <p>Failure: <c>badarg</c> if <c><anno>Port</anno></c> is not an open port or
- the registered name of an open port, if <c><anno>Operation</anno></c>
- cannot fit in a 32-bit integer, if the port driver does not
- support synchronous control operations, or if the port driver
- so decides for any reason (probably something wrong with
- <c><anno>Operation</anno></c> or <c><anno>Data</anno></c>).</p>
+ <p>Failures:</p>
+ <taglist>
+ <tag><c>badarg</c></tag>
+ <item>
+ If <c><anno>Port</anno></c> is not an identifier of an open
+ port, or the registered name of an open port. If the calling
+ process was linked to the previously open port identified by
+ <c><anno>Port</anno></c>, an exit signal due to this link
+ was received by the process prior to this exception.
+ </item>
+ <tag><c>badarg</c></tag>
+ <item>
+ If <c><anno>Operation</anno></c> does not fit in a
+ 32-bit integer.
+ </item>
+ <tag><c>badarg</c></tag>
+ <item>
+ If the port driver does not support synchronous control
+ operations.
+ </item>
+ <tag><c>badarg</c></tag>
+ <item>
+ If the port driver so decides for any reason (probably
+ something wrong with <c><anno>Operation</anno></c>, or
+ <c><anno>Data</anno></c>).
+ </item>
+ </taglist>
</desc>
</func>
<func>
@@ -3231,7 +3407,12 @@ os_prompt% </pre>
<p>Returns a list containing tuples with information about
the <c><anno>Port</anno></c>, or <c>undefined</c> if the port is not open.
The order of the tuples is not defined, nor are all the
- tuples mandatory.</p>
+ tuples mandatory.
+ If <c>undefined</c> is returned and the calling process
+ was linked to a previously open port identified by
+ <c><anno>Port</anno></c>, an exit signal due to this link
+ was received by the process prior to the return from
+ <c>port_info/1</c>.</p>
<p>Currently the result will containt information about the
following <c>Item</c>s: <c>registered_name</c> (if the port has
a registered name), <c>id</c>, <c>connected</c>, <c>links</c>,
@@ -3249,7 +3430,11 @@ os_prompt% </pre>
<p><c><anno>Pid</anno></c> is the process identifier of the process
connected to the port.</p>
<p>If the port identified by <c><anno>Port</anno></c> is not open,
- <c>undefined</c> is returned.</p>
+ <c>undefined</c> is returned. If <c>undefined</c> is returned and
+ the calling process was linked to a previously open port identified
+ by <c><anno>Port</anno></c>, an exit signal due to this link
+ was received by the process prior to the return from
+ <c>port_info/2</c>.</p>
<p>Failure: <c>badarg</c> if <c><anno>Port</anno></c> is not a local
port identifier, or an atom.</p>
</desc>
@@ -3261,7 +3446,11 @@ os_prompt% </pre>
<p><c><anno>Index</anno></c> is the internal index of the port. This
index may be used to separate ports.</p>
<p>If the port identified by <c><anno>Port</anno></c> is not open,
- <c>undefined</c> is returned.</p>
+ <c>undefined</c> is returned. If <c>undefined</c> is returned and
+ the calling process was linked to a previously open port identified
+ by <c><anno>Port</anno></c>, an exit signal due to this link
+ was received by the process prior to the return from
+ <c>port_info/2</c>.</p>
<p>Failure: <c>badarg</c> if <c><anno>Port</anno></c> is not a local
port identifier, or an atom.</p>
</desc>
@@ -3273,7 +3462,11 @@ os_prompt% </pre>
<p><c><anno>Bytes</anno></c> is the total number of bytes
read from the port.</p>
<p>If the port identified by <c><anno>Port</anno></c> is not open,
- <c>undefined</c> is returned.</p>
+ <c>undefined</c> is returned. If <c>undefined</c> is returned and
+ the calling process was linked to a previously open port identified
+ by <c><anno>Port</anno></c>, an exit signal due to this link
+ was received by the process prior to the return from
+ <c>port_info/2</c>.</p>
<p>Failure: <c>badarg</c> if <c><anno>Port</anno></c> is not a local
port identifier, or an atom.</p>
</desc>
@@ -3285,7 +3478,11 @@ os_prompt% </pre>
<p><c><anno>Pids</anno></c> is a list of the process identifiers
of the processes that the port is linked to.</p>
<p>If the port identified by <c><anno>Port</anno></c> is not open,
- <c>undefined</c> is returned.</p>
+ <c>undefined</c> is returned. If <c>undefined</c> is returned and
+ the calling process was linked to a previously open port identified
+ by <c><anno>Port</anno></c>, an exit signal due to this link
+ was received by the process prior to the return from
+ <c>port_info/2</c>.</p>
<p>Failure: <c>badarg</c> if <c><anno>Port</anno></c> is not a local
port identifier, or an atom.</p>
</desc>
@@ -3300,7 +3497,11 @@ os_prompt% </pre>
that these results are highly implementation specific and might
change in the future.</p>
<p>If the port identified by <c><anno>Port</anno></c> is not open,
- <c>undefined</c> is returned.</p>
+ <c>undefined</c> is returned. If <c>undefined</c> is returned and
+ the calling process was linked to a previously open port identified
+ by <c><anno>Port</anno></c>, an exit signal due to this link
+ was received by the process prior to the return from
+ <c>port_info/2</c>.</p>
<p>Failure: <c>badarg</c> if <c><anno>Port</anno></c> is not a local
port identifier, or an atom.</p>
</desc>
@@ -3314,7 +3515,11 @@ os_prompt% </pre>
that the port itself might have allocated memory which is not
included in <c><anno>Bytes</anno></c>.</p>
<p>If the port identified by <c><anno>Port</anno></c> is not open,
- <c>undefined</c> is returned.</p>
+ <c>undefined</c> is returned. If <c>undefined</c> is returned and
+ the calling process was linked to a previously open port identified
+ by <c><anno>Port</anno></c>, an exit signal due to this link
+ was received by the process prior to the return from
+ <c>port_info/2</c>.</p>
<p>Failure: <c>badarg</c> if <c><anno>Port</anno></c> is not a local
port identifier, or an atom.</p>
</desc>
@@ -3326,7 +3531,11 @@ os_prompt% </pre>
<p><c><anno>Monitors</anno></c> represent processes that this port
is monitoring.</p>
<p>If the port identified by <c><anno>Port</anno></c> is not open,
- <c>undefined</c> is returned.</p>
+ <c>undefined</c> is returned. If <c>undefined</c> is returned and
+ the calling process was linked to a previously open port identified
+ by <c><anno>Port</anno></c>, an exit signal due to this link
+ was received by the process prior to the return from
+ <c>port_info/2</c>.</p>
<p>Failure: <c>badarg</c> if <c><anno>Port</anno></c> is not a local
port identifier, or an atom.</p>
</desc>
@@ -3338,7 +3547,11 @@ os_prompt% </pre>
<p><c><anno>Name</anno></c> is the command name set by
<seealso marker="#open_port/2">open_port/2</seealso>.</p>
<p>If the port identified by <c><anno>Port</anno></c> is not open,
- <c>undefined</c> is returned.</p>
+ <c>undefined</c> is returned. If <c>undefined</c> is returned and
+ the calling process was linked to a previously open port identified
+ by <c><anno>Port</anno></c>, an exit signal due to this link
+ was received by the process prior to the return from
+ <c>port_info/2</c>.</p>
<p>Failure: <c>badarg</c> if <c><anno>Port</anno></c> is not a local
port identifier, or an atom.</p>
</desc>
@@ -3353,7 +3566,11 @@ os_prompt% </pre>
Command}, Options)</seealso>. If the port is not the result of spawning
an OS process, the value is <c>undefined</c>.</p>
<p>If the port identified by <c><anno>Port</anno></c> is not open,
- <c>undefined</c> is returned.</p>
+ <c>undefined</c> is returned. If <c>undefined</c> is returned and
+ the calling process was linked to a previously open port identified
+ by <c><anno>Port</anno></c>, an exit signal due to this link
+ was received by the process prior to the return from
+ <c>port_info/2</c>.</p>
<p>Failure: <c>badarg</c> if <c><anno>Port</anno></c> is not a local
port identifier, or an atom.</p>
</desc>
@@ -3369,7 +3586,11 @@ os_prompt% </pre>
or <c><anno>Port</anno> ! {Owner, {command, Data}</c>.
</p>
<p>If the port identified by <c><anno>Port</anno></c> is not open,
- <c>undefined</c> is returned.</p>
+ <c>undefined</c> is returned. If <c>undefined</c> is returned and
+ the calling process was linked to a previously open port identified
+ by <c><anno>Port</anno></c>, an exit signal due to this link
+ was received by the process prior to the return from
+ <c>port_info/2</c>.</p>
<p>Failure: <c>badarg</c> if <c><anno>Port</anno></c> is not a local
port identifier, or an atom.</p>
</desc>
@@ -3392,7 +3613,11 @@ os_prompt% </pre>
in bytes, queued by the port using the ERTS driver queue
implementation.</p>
<p>If the port identified by <c><anno>Port</anno></c> is not open,
- <c>undefined</c> is returned.</p>
+ <c>undefined</c> is returned. If <c>undefined</c> is returned and
+ the calling process was linked to a previously open port identified
+ by <c><anno>Port</anno></c>, an exit signal due to this link
+ was received by the process prior to the return from
+ <c>port_info/2</c>.</p>
<p>Failure: <c>badarg</c> if <c><anno>Port</anno></c> is not a local
port identifier, or an atom.</p>
</desc>
@@ -3404,7 +3629,11 @@ os_prompt% </pre>
<p><c><anno>RegisteredName</anno></c> is the registered name of
the port. If the port has no registered name, <c>[]</c> is returned.</p>
<p>If the port identified by <c><anno>Port</anno></c> is not open,
- <c>undefined</c> is returned.</p>
+ <c>undefined</c> is returned. If <c>undefined</c> is returned and
+ the calling process was linked to a previously open port identified
+ by <c><anno>Port</anno></c>, an exit signal due to this link
+ was received by the process prior to the return from
+ <c>port_info/2</c>.</p>
<p>Failure: <c>badarg</c> if <c><anno>Port</anno></c> is not a local
port identifier, or an atom.</p>
</desc>
@@ -4707,8 +4936,8 @@ true</pre>
<name name="statistics" arity="1" clause_i="6"/>
<fsummary>Information about the run-queue</fsummary>
<desc>
- <p>Returns the length of the run queue, that is, the number
- of processes that are ready to run.</p>
+ <p>Returns the total length of the run queues, that is, the number
+ of processes that are ready to run on all available run queues.</p>
</desc>
</func>
<func>
@@ -5296,7 +5525,11 @@ ok
As of erts version 5.6.1 the return value is a list
of <c>{instance, InstanceNo, InstanceInfo}</c> tuples
where <c>InstanceInfo</c> contains information about
- a specific instance of the allocator.
+ a specific instance of the allocator. As of erts version
+ 5.10.4 the returned list when calling
+ <c>erlang:system_info({allocator, mseg_alloc})</c> also
+ include an <c>{erts_mmap, _}</c> tuple as one element
+ in the list.
If <c><anno>Alloc</anno></c> is not a recognized allocator,
<c>undefined</c> is returned. If <c><anno>Alloc</anno></c> is disabled,
<c>false</c> is returned.</p>
diff --git a/erts/doc/src/erlc.xml b/erts/doc/src/erlc.xml
index 10cab344b0..c3fc3b1686 100644
--- a/erts/doc/src/erlc.xml
+++ b/erts/doc/src/erlc.xml
@@ -234,6 +234,16 @@ erlc +export_all file.erl</pre>
from the shell.</p>
<p>Supported options: -I, -o, -D, -v, -W, -b.</p>
</item>
+ <tag>.S</tag>
+ <item>
+ <p>Erlang assembler source code. It generates a <c><![CDATA[.beam]]></c> file.</p>
+ <p>Supported options: same as for .erl.</p>
+ </item>
+ <tag>.core</tag>
+ <item>
+ <p>Erlang core source code. It generates a <c><![CDATA[.beam]]></c> file.</p>
+ <p>Supported options: same as for .erl.</p>
+ </item>
<tag>.yrl</tag>
<item>
<p>Yecc source code. It generates an <c><![CDATA[.erl]]></c> file.</p>
diff --git a/erts/doc/src/erts_alloc.xml b/erts/doc/src/erts_alloc.xml
index 8dd9ed1398..fffa9f594c 100644
--- a/erts/doc/src/erts_alloc.xml
+++ b/erts/doc/src/erts_alloc.xml
@@ -271,22 +271,18 @@
memory segment cache is not reused if its size exceeds the
requested size with more than relative max cache bad fit
percent of the requested size. Default value is 20.</item>
- <tag><marker id="MMscmgc"><c><![CDATA[+MMscmgc <amount>]]></c></marker></tag>
- <item>
- Set <seealso marker="#MMscs">super carrier</seealso> max guaranteed
- no of carriers. This parameter defaults to <c>65536</c>. This
- parameter determines an amount of pre-allocated structures that is
- needed in order to keep track of different areas in the super carrier.
- When the system runs out of such structures it may crash due to an
- out of memory condition.
- </item>
<tag><marker id="MMsco"><c><![CDATA[+MMsco true|false]]></c></marker></tag>
<item>
Set <seealso marker="#MMscs">super carrier</seealso> only flag. This
flag defaults to <c>true</c>. When a super carrier is used and this
- flag is <c>true</c>, the system will crash when a carrier request
- cannot be satisfied by the super carrier. When the flag is <c>false</c>
- the system will try to create requested carrier by other means.
+ flag is <c>true</c>, <c>mseg_alloc</c> will only create carriers
+ in the super carrier. Note that the <c>alloc_util</c> framework may
+ create <c>sys_alloc</c> carriers, so if you want all carriers to
+ be created in the super carrier, you therefore want to disable use
+ of <c>sys_alloc</c> carriers by also passing
+ <seealso marker="#Musac"><c>+Musac false</c></seealso>. When the flag
+ is <c>false</c>, <c>mseg_alloc</c> will try to create carriers outside
+ of the super carrier when the super carrier is full.
<br/><br/>
<em>NOTE</em>: Setting this flag to <c>false</c> may not be supported
on all systems. This flag will in that case be ignored.
@@ -295,6 +291,19 @@
disabled on halfword heap systems. This flag will be
ignored on halfword heap systems.
</item>
+ <tag><marker id="MMscrfsd"><c><![CDATA[+MMscrfsd <amount>]]></c></marker></tag>
+ <item>
+ Set <seealso marker="#MMscs">super carrier</seealso> reserved
+ free segment descriptors. This parameter defaults to <c>65536</c>.
+ This parameter determines the amount of memory to reserve for
+ free segment descriptors used by the super carrier. If the system
+ runs out of reserved memory for free segment descriptors, other
+ memory will be used. This may however cause fragmentation issues,
+ so you want to ensure that this never happens. The maximum amount
+ of free segment descriptors used can be retrieved from the
+ <c>erts_mmap</c> tuple part of the result from calling
+ <seealso marker="erts:erlang#system_info_allocator_tuple">erlang:system_info({allocator, mseg_alloc})</seealso>.
+ </item>
<tag><marker id="MMscrpm"><c><![CDATA[+MMscrpm true|false]]></c></marker></tag>
<item>
Set <seealso marker="#MMscs">super carrier</seealso> reserve physical
@@ -323,8 +332,11 @@
Set super carrier size (in MB). The super carrier size defaults to
zero; i.e, the super carrier is by default disabled. The super
carrier is a large continuous area in the virtual address space.
- The system will always try to create new carriers in the super
- carrier.
+ <c>mseg_alloc</c> will always try to create new carriers in the super
+ carrier if it exists. Note that the <c>alloc_util</c> framework may
+ create <c>sys_alloc</c> carriers. For more information on this, see the
+ documentation of the <seealso marker="#MMsco"><c>+MMsco</c></seealso>
+ flag.
<br/><br/>
<em>NOTE</em>: The super carrier cannot be enabled nor
disabled on halfword heap systems. This flag will be
@@ -549,6 +561,11 @@
placed in separate memory segments. When this limit has been
reached, new carriers will be placed in memory retrieved from
<c>sys_alloc</c>.</item>
+ <tag><marker id="Musac"><c><![CDATA[+Musac <bool>]]></c></marker></tag>
+ <item>
+ Allow <c>sys_alloc</c> carriers. By default <c>true</c>. If
+ set to <c>false</c>, <c>sys_alloc</c> carriers will never be
+ created by allocators using the <c>alloc_util</c> framework.</item>
</taglist>
<p>Instrumentation flags:</p>
<taglist>
@@ -604,6 +621,16 @@
</item>
</taglist>
</item>
+ <tag><marker id="Mlpm"><c>+Mlpm all|no</c></marker></tag>
+ <item>Lock physical memory. The default value is <c>no</c>, i.e.,
+ no physical memory will be locked. If set to <c>all</c>, all
+ memory mappings made by the runtime system, will be locked into
+ physical memory. If set to <c>all</c>, the runtime system will fail
+ to start if this feature is not supported, the user has not got enough
+ privileges, or the user is not allowed to lock enough physical memory.
+ The runtime system will also fail with an out of memory condition
+ if the user limit on the amount of locked memory is reached.
+ </item>
</taglist>
<p>Only some default values have been presented
here.
diff --git a/erts/doc/src/notes.xml b/erts/doc/src/notes.xml
index b25e4ccbec..8c008c493e 100644
--- a/erts/doc/src/notes.xml
+++ b/erts/doc/src/notes.xml
@@ -30,6 +30,265 @@
</header>
<p>This document describes the changes made to the ERTS application.</p>
+<section><title>Erts 5.10.4</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ When normalizing paths, erl_prim_loader would always
+ convert backslash to forward slash. This is correct on
+ Windows, but not on other operating systems.
+ erl_prim_loader now checks which OS is running before
+ performing this conversion.</p>
+ <p>
+ Own Id: OTP-11170</p>
+ </item>
+ <item>
+ <p>
+ Fixed syslog defines and defined LOG_ERR for systems
+ without syslog.h. Thanks to Matt Lewandowsky.</p>
+ <p>
+ Own Id: OTP-11349</p>
+ </item>
+ <item>
+ <p>
+ Check all pattern arguments passed to binary:matches/2.
+ Thanks to Mike Sassak.</p>
+ <p>
+ Own Id: OTP-11350</p>
+ </item>
+ <item>
+ <p>
+ Fix two small silent rules omissions. Thanks to Anthony
+ Ramine.</p>
+ <p>
+ Own Id: OTP-11351</p>
+ </item>
+ <item>
+ <p>
+ Teach configure to detect if posix_memalign cannot align
+ to more than the system page size. </p>
+ <p>
+ For cross-compiled systems a new environment variable
+ called erl_xcomp_posix_memalign has been introduced to
+ indicate whether posix_memalign should be used.</p>
+ <p>
+ Own Id: OTP-11371</p>
+ </item>
+ <item>
+ <p>
+ Fix bsr bug occurring when shifting a huge number a huge
+ number of bits to the right. Thanks to Lars Hesel
+ Christensen.</p>
+ <p>
+ Own Id: OTP-11381</p>
+ </item>
+ <item>
+ <p>
+ Fix memory leak for distributed monitors</p>
+ <p>
+ Own Id: OTP-11410</p>
+ </item>
+ <item>
+ <p>
+ Fix various typos in erts, kernel and ssh. Thanks to
+ Martin Hässler.</p>
+ <p>
+ Own Id: OTP-11414</p>
+ </item>
+ <item>
+ <p>
+ Crashdumps initiated by out-of-memory on process spawn
+ could cause the beam to segfault during crashdump writing
+ due to invalid pointers.</p>
+ <p>
+ The pointers are invalid since the process creation never
+ finished. This fix removes these processes from the
+ printouts. Reported by Richard Carlsson.</p>
+ <p>
+ Own Id: OTP-11420</p>
+ </item>
+ <item>
+ <p>
+ Crash dumps from 64-bit Erlang machines would have all
+ memory addresses truncated to 32 bits, which could cause
+ trouble inspecting processes message queues and stacks in
+ the crashdump viewer.</p>
+ <p>
+ Own Id: OTP-11450</p>
+ </item>
+ <item>
+ <p>
+ Threads other than schedulers threads could make thread
+ unsafe accesses when support for migration of memory
+ carriers had been enabled, i.e., when the <seealso
+ marker="erts_alloc#M_acul"><c>+M&lt;S&gt;acul</c></seealso>
+ command line flag had been passed to <seealso
+ marker="erl"><c>erl</c></seealso>. This could cause
+ corruption of the VMs internal state.</p>
+ <p>
+ This bug was introduced in erts-5.10.2 when the support
+ for migration of memory carriers was introduced.</p>
+ <p>
+ Own Id: OTP-11456 Aux Id: OTP-10279 </p>
+ </item>
+ <item>
+ <p>
+ Fix bug in <c>binary_to_term</c> for invalid bitstrings
+ and very large binaries (>2Gb).</p>
+ <p>
+ Own Id: OTP-11479</p>
+ </item>
+ <item>
+ <p>
+ Under rare circumstances a process calling <seealso
+ marker="kernel:inet#close/1"><c>inet:close/1</c></seealso>,
+ <seealso
+ marker="kernel:gen_tcp#close/1"><c>gen_tcp:close/1</c></seealso>,
+ <seealso
+ marker="kernel:gen_udp#close/1"><c>gen_udp:close/1</c></seealso>,
+ or <seealso
+ marker="kernel:gen_sctp#close/1"><c>gen_sctp:close/1</c></seealso>
+ could hang in the call indefinitely.</p>
+ <p>
+ Own Id: OTP-11491</p>
+ </item>
+ <item>
+ <p>
+ Fix bug that could cause a 32-bit emulator to always
+ crash at start (since R16B01) depending on the alignment
+ of static data in the beam executable.</p>
+ <p>
+ Own Id: OTP-11496</p>
+ </item>
+ <item>
+ <p>
+ Fix benign bugs regarding bitstring compare. Only a
+ nuisance for debug and valgrind VM.</p>
+ <p>
+ Own Id: OTP-11501</p>
+ </item>
+ <item>
+ <p>
+ Silence warnings (Thanks to Anthony Ramine)</p>
+ <p>
+ Own Id: OTP-11517</p>
+ </item>
+ <item>
+ <p>
+ The default wordsize of the emulator (beam) is now
+ determined by compiler default on Mac OSX (Darwin). This
+ was previously forced to 32bits by the configure script
+ unless otherwise specified.</p>
+ <p>
+ Own Id: OTP-11521</p>
+ </item>
+ </list>
+ </section>
+
+
+ <section><title>Improvements and New Features</title>
+ <list>
+ <item>
+ <p>
+ A new memory allocation feature called "super carrier"
+ has been introduced. The super carrier feature can be
+ used in different ways. It can for example be used for
+ pre-allocation of all memory that the runtime system
+ should be able to use.</p>
+ <p>
+ By default the super carrier is disabled. It is enabled
+ by passing the <seealso
+ marker="erts:erts_alloc#MMscs"><c>+MMscs &lt;size in
+ MB&gt;</c></seealso> command line argument. For more
+ information see the documentation of the <seealso
+ marker="erts:erts_alloc#MMsco"><c>+MMsco</c></seealso>,
+ <seealso
+ marker="erts:erts_alloc#MMscrfsd"><c>+MMscrfsd</c></seealso>,
+ <seealso
+ marker="erts:erts_alloc#MMscrpm"><c>+MMscrpm</c></seealso>,
+ <seealso
+ marker="erts:erts_alloc#MMscs"><c>+MMscs</c></seealso>,
+ <seealso
+ marker="erts:erts_alloc#Musac"><c>+MMusac</c></seealso>,
+ and, <seealso
+ marker="erts:erts_alloc#Mlpm"><c>+Mlpm</c></seealso>
+ command line arguments in the <seealso
+ marker="erts:erts_alloc"><c>erts_alloc(3)</c></seealso>
+ documentation.</p>
+ <p>
+ Since it is disabled by default there should be no impact
+ on system characteristics if not used.</p>
+ <p>
+ This change has been marked as a potential
+ incompatibility since the returned list when calling
+ <seealso
+ marker="erts:erlang#system_info_allocator_tuple"><c>erlang:system_info({allocator,
+ mseg_alloc})</c></seealso> now also include an
+ <c>{erts_mmap, _}</c> tuple as one element in the list.</p>
+ <p>
+ *** POTENTIAL INCOMPATIBILITY ***</p>
+ <p>
+ Own Id: OTP-11149</p>
+ </item>
+ <item>
+ <p>
+ Added erlang:system_info(ets_limit) to provide a way to
+ retrieve the runtime's maximum number of ETS tables.
+ Thanks to Steve Vinoski</p>
+ <p>
+ Own Id: OTP-11362</p>
+ </item>
+ <item>
+ <p>
+ Add new BIF os:unsetenv/1 which deletes an environment
+ variable. Thanks to Martin Hässler.</p>
+ <p>
+ Own Id: OTP-11446</p>
+ </item>
+ <item>
+ <p> Introduced a new guarantee regarding exit signals
+ from ports: </p><p> If the process calling one of the
+ synchronous port BIFs listed below is linked to the port
+ identified by the first argument, and the port exits
+ before sending the result of the port operation, the exit
+ signal issued due to this link will be received by the
+ processes before the BIF returns, or fail with an
+ exception due to the port not being open. </p><p> The
+ synchronous port BIFs are: </p> <list> <item><seealso
+ marker="erlang#port_close/1/"><c>port_close/1</c></seealso></item>
+ <item><seealso
+ marker="erlang#port_command/2"><c>port_command/2</c></seealso></item>
+ <item><seealso
+ marker="erlang#port_command/3"><c>port_command/3</c></seealso></item>
+ <item><seealso
+ marker="erlang#port_connect/2"><c>port_connect/2</c></seealso></item>
+ <item><seealso
+ marker="erlang#port_control/3"><c>port_control/3</c></seealso></item>
+ <item><seealso
+ marker="erlang#port_call/3"><c>erlang:port_call/3</c></seealso></item>
+ <item><seealso
+ marker="erlang#port_info/1"><c>erlang:port_info/1</c></seealso></item>
+ <item><seealso
+ marker="erlang#port_info/2"><c>erlang:port_info/2</c></seealso></item>
+ </list> <p> Note that some ports under certain
+ circumstances unlink themselves from the calling process
+ before exiting, i.e. even though the process linked
+ itself to the port there might be no link triggering an
+ exit signal. </p> <p>Characteristics impact: The return
+ or exception from the synchronous port BIF will be
+ delayed if the port simultaneously exit due to some issue
+ unrelated to the outstanding synchronous port BIF call.
+ In all other cases characteristics are unchanged. </p>
+ <p>
+ Own Id: OTP-11489</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
<section><title>Erts 5.10.3.1</title>
<section><title>Improvements and New Features</title>
diff --git a/erts/emulator/beam/atom.names b/erts/emulator/beam/atom.names
index e108e706c3..96547ba743 100644
--- a/erts/emulator/beam/atom.names
+++ b/erts/emulator/beam/atom.names
@@ -79,6 +79,7 @@ atom allocated_areas
atom allocator
atom allocator_sizes
atom alloc_util_allocators
+atom allow_gc
atom allow_passive_connect
atom already_loaded
atom amd64
@@ -115,6 +116,7 @@ atom binary_longest_prefix_trap
atom binary_longest_suffix_trap
atom binary_match_trap
atom binary_matches_trap
+atom binary_to_term_trap
atom block
atom blocked
atom bm
diff --git a/erts/emulator/beam/beam_bif_load.c b/erts/emulator/beam/beam_bif_load.c
index 649594a334..3f92c5b025 100644
--- a/erts/emulator/beam/beam_bif_load.c
+++ b/erts/emulator/beam/beam_bif_load.c
@@ -36,7 +36,7 @@
#include "erl_thr_progress.h"
static void set_default_trace_pattern(Eterm module);
-static Eterm check_process_code(Process* rp, Module* modp);
+static Eterm check_process_code(Process* rp, Module* modp, int allow_gc, int *redsp);
static void delete_code(Module* modp);
static void decrement_refc(BeamInstr* code);
static int is_native(BeamInstr* code);
@@ -427,69 +427,82 @@ check_old_code_1(BIF_ALIST_1)
}
Eterm
-check_process_code_2(BIF_ALIST_2)
+erts_check_process_code(Process *c_p, Eterm module, int allow_gc, int *redsp)
{
- Process* rp;
Module* modp;
+ Eterm res;
+ ErtsCodeIndex code_ix;
- if (is_not_atom(BIF_ARG_2)) {
- goto error;
- }
- if (is_internal_pid(BIF_ARG_1)) {
- Eterm res;
- ErtsCodeIndex code_ix;
-
- code_ix = erts_active_code_ix();
- modp = erts_get_module(BIF_ARG_2, code_ix);
- if (modp == NULL) { /* Doesn't exist. */
- return am_false;
- }
- erts_rlock_old_code(code_ix);
- if (modp->old.code == NULL) { /* No old code. */
- erts_runlock_old_code(code_ix);
- return am_false;
- }
- erts_runlock_old_code(code_ix);
-
-#ifdef ERTS_SMP
- rp = erts_pid2proc_suspend(BIF_P, ERTS_PROC_LOCK_MAIN,
- BIF_ARG_1, ERTS_PROC_LOCK_MAIN);
-#else
- rp = erts_pid2proc(BIF_P, 0, BIF_ARG_1, 0);
-#endif
- if (!rp) {
- BIF_RET(am_false);
- }
- if (rp == ERTS_PROC_LOCK_BUSY) {
- ERTS_BIF_YIELD2(bif_export[BIF_check_process_code_2], BIF_P,
- BIF_ARG_1, BIF_ARG_2);
- }
- erts_rlock_old_code(code_ix);
- if (modp->old.code != NULL) { /* must check again */
- res = check_process_code(rp, modp);
- }
- else {
- res = am_false;
- }
- erts_runlock_old_code(code_ix);
-#ifdef ERTS_SMP
- if (BIF_P != rp) {
- erts_resume(rp, ERTS_PROC_LOCK_MAIN);
- erts_smp_proc_unlock(rp, ERTS_PROC_LOCK_MAIN);
+ (*redsp)++;
+
+ ASSERT(is_atom(module));
+
+ code_ix = erts_active_code_ix();
+ modp = erts_get_module(module, code_ix);
+ if (!modp)
+ return am_false;
+ erts_rlock_old_code(code_ix);
+ res = modp->old.code ? check_process_code(c_p, modp, allow_gc, redsp) : am_false;
+ erts_runlock_old_code(code_ix);
+
+ return res;
+}
+
+BIF_RETTYPE erts_internal_check_process_code_2(BIF_ALIST_2)
+{
+ int reds = 0;
+ Eterm res;
+ Eterm olist = BIF_ARG_2;
+ int allow_gc = 1;
+
+ if (is_not_atom(BIF_ARG_1))
+ goto badarg;
+
+ while (is_list(olist)) {
+ Eterm *lp = list_val(olist);
+ Eterm opt = CAR(lp);
+ if (is_tuple(opt)) {
+ Eterm* tp = tuple_val(opt);
+ switch (arityval(tp[0])) {
+ case 2:
+ switch (tp[1]) {
+ case am_allow_gc:
+ switch (tp[2]) {
+ case am_false:
+ allow_gc = 0;
+ break;
+ case am_true:
+ allow_gc = 1;
+ break;
+ default:
+ goto badarg;
+ }
+ break;
+ default:
+ goto badarg;
+ }
+ break;
+ default:
+ goto badarg;
+ }
}
-#endif
- BIF_RET(res);
- }
- else if (is_external_pid(BIF_ARG_1)
- && external_pid_dist_entry(BIF_ARG_1) == erts_this_dist_entry) {
- BIF_RET(am_false);
+ else
+ goto badarg;
+ olist = CDR(lp);
}
+ if (is_not_nil(olist))
+ goto badarg;
+
+ res = erts_check_process_code(BIF_P, BIF_ARG_1, allow_gc, &reds);
+
+ ASSERT(is_value(res));
+
+ BIF_RET2(res, reds);
- error:
+badarg:
BIF_ERROR(BIF_P, BADARG);
}
-
BIF_RETTYPE delete_module_1(BIF_ALIST_1)
{
ErtsCodeIndex code_ix;
@@ -710,7 +723,7 @@ set_default_trace_pattern(Eterm module)
}
static Eterm
-check_process_code(Process* rp, Module* modp)
+check_process_code(Process* rp, Module* modp, int allow_gc, int *redsp)
{
BeamInstr* start;
char* mod_start;
@@ -773,6 +786,16 @@ check_process_code(Process* rp, Module* modp)
}
}
+ if (rp->flags & F_DISABLE_GC) {
+ /*
+ * Cannot proceed. Process has disabled gc in order to
+ * safely leave inconsistent data on the heap and/or
+ * off heap lists. Need to wait for gc to be enabled
+ * again.
+ */
+ return THE_NON_VALUE;
+ }
+
/*
* See if there are funs that refer to the old version of the module.
*/
@@ -786,6 +809,8 @@ check_process_code(Process* rp, Module* modp)
if (done_gc) {
return am_true;
} else {
+ if (!allow_gc)
+ return am_aborted;
/*
* Try to get rid of this fun by garbage collecting.
* Clear both fvalue and ftrace to make sure they
@@ -796,7 +821,7 @@ check_process_code(Process* rp, Module* modp)
rp->ftrace = NIL;
done_gc = 1;
FLAGS(rp) |= F_NEED_FULLSWEEP;
- (void) erts_garbage_collect(rp, 0, rp->arg_reg, rp->arity);
+ *redsp += erts_garbage_collect(rp, 0, rp->arg_reg, rp->arity);
goto rescan;
}
}
@@ -850,6 +875,9 @@ check_process_code(Process* rp, Module* modp)
Uint lit_size;
struct erl_off_heap_header* oh;
+ if (!allow_gc)
+ return am_aborted;
+
/*
* Try to get rid of constants by by garbage collecting.
* Clear both fvalue and ftrace.
@@ -859,11 +887,12 @@ check_process_code(Process* rp, Module* modp)
rp->ftrace = NIL;
done_gc = 1;
FLAGS(rp) |= F_NEED_FULLSWEEP;
- (void) erts_garbage_collect(rp, 0, rp->arg_reg, rp->arity);
+ *redsp += erts_garbage_collect(rp, 0, rp->arg_reg, rp->arity);
literals = (Eterm *) modp->old.code[MI_LITERALS_START];
lit_size = (Eterm *) modp->old.code[MI_LITERALS_END] - literals;
oh = (struct erl_off_heap_header *)
modp->old.code[MI_LITERALS_OFF_HEAP];
+ *redsp += lit_size / 10; /* Need, better value... */
erts_garbage_collect_literals(rp, literals, lit_size, oh);
}
}
diff --git a/erts/emulator/beam/bif.c b/erts/emulator/beam/bif.c
index 755c5e6882..96666d98ed 100644
--- a/erts/emulator/beam/bif.c
+++ b/erts/emulator/beam/bif.c
@@ -160,7 +160,10 @@ BIF_RETTYPE link_1(BIF_ALIST_1)
if (is_internal_port(BIF_ARG_1)) {
int send_link_signal = 0;
- Port *prt = erts_port_lookup(BIF_ARG_1, ERTS_PORT_SFLGS_INVALID_LOOKUP);
+ Port *prt = erts_port_lookup(BIF_ARG_1,
+ (erts_port_synchronous_ops
+ ? ERTS_PORT_SFLGS_INVALID_DRIVER_LOOKUP
+ : ERTS_PORT_SFLGS_INVALID_LOOKUP));
if (!prt) {
goto res_no_proc;
}
@@ -1363,11 +1366,22 @@ BIF_RETTYPE exit_2(BIF_ALIST_2)
*/
if (is_internal_port(BIF_ARG_1)) {
- Port *prt = erts_port_lookup(BIF_ARG_1, ERTS_PORT_SFLGS_INVALID_LOOKUP);
+ Eterm ref, *refp;
+ Uint32 invalid_flags;
+ Port *prt;
+
+ if (erts_port_synchronous_ops) {
+ refp = &ref;
+ invalid_flags = ERTS_PORT_SFLGS_INVALID_DRIVER_LOOKUP;
+ }
+ else {
+ refp = NULL;
+ invalid_flags = ERTS_PORT_SFLGS_INVALID_LOOKUP;
+ }
+
+ prt = erts_port_lookup(BIF_ARG_1, invalid_flags);
if (prt) {
- Eterm ref;
- Eterm *refp = erts_port_synchronous_ops ? &ref : NULL;
ErtsPortOpResult res;
#ifdef DEBUG
@@ -1875,7 +1889,10 @@ do_send(Process *p, Eterm to, Eterm msg, int suspend, Eterm *refp) {
if (rp)
goto send_message;
- pt = erts_port_lookup(id, ERTS_PORT_SFLGS_INVALID_LOOKUP);
+ pt = erts_port_lookup(id,
+ (erts_port_synchronous_ops
+ ? ERTS_PORT_SFLGS_INVALID_DRIVER_LOOKUP
+ : ERTS_PORT_SFLGS_INVALID_LOOKUP));
if (pt) {
portid = id;
goto port_common;
@@ -1905,7 +1922,10 @@ do_send(Process *p, Eterm to, Eterm msg, int suspend, Eterm *refp) {
int ret_val;
portid = to;
- pt = erts_port_lookup(portid, ERTS_PORT_SFLGS_INVALID_LOOKUP);
+ pt = erts_port_lookup(portid,
+ (erts_port_synchronous_ops
+ ? ERTS_PORT_SFLGS_INVALID_DRIVER_LOOKUP
+ : ERTS_PORT_SFLGS_INVALID_LOOKUP));
port_common:
ret_val = 0;
@@ -1994,7 +2014,10 @@ do_send(Process *p, Eterm to, Eterm msg, int suspend, Eterm *refp) {
rp = erts_proc_lookup_raw(id);
if (rp)
goto send_message;
- pt = erts_port_lookup(id, ERTS_PORT_SFLGS_INVALID_LOOKUP);
+ pt = erts_port_lookup(id,
+ (erts_port_synchronous_ops
+ ? ERTS_PORT_SFLGS_INVALID_DRIVER_LOOKUP
+ : ERTS_PORT_SFLGS_INVALID_LOOKUP));
if (pt) {
portid = id;
goto port_common;
@@ -3741,45 +3764,6 @@ BIF_RETTYPE now_0(BIF_ALIST_0)
/**********************************************************************/
-BIF_RETTYPE garbage_collect_1(BIF_ALIST_1)
-{
- int reds;
- Process *rp;
-
- if (is_not_pid(BIF_ARG_1)) {
- BIF_ERROR(BIF_P, BADARG);
- }
-
- if (BIF_P->common.id == BIF_ARG_1)
- rp = BIF_P;
- else {
-#ifdef ERTS_SMP
- rp = erts_pid2proc_suspend(BIF_P, ERTS_PROC_LOCK_MAIN,
- BIF_ARG_1, ERTS_PROC_LOCK_MAIN);
- if (rp == ERTS_PROC_LOCK_BUSY)
- ERTS_BIF_YIELD1(bif_export[BIF_garbage_collect_1], BIF_P, BIF_ARG_1);
-#else
- rp = erts_proc_lookup(BIF_ARG_1);
-#endif
- if (!rp)
- BIF_RET(am_false);
- }
-
- /* The GC cost is taken for the process executing this BIF. */
-
- FLAGS(rp) |= F_NEED_FULLSWEEP;
- reds = erts_garbage_collect(rp, 0, rp->arg_reg, rp->arity);
-
-#ifdef ERTS_SMP
- if (BIF_P != rp) {
- erts_resume(rp, ERTS_PROC_LOCK_MAIN);
- erts_smp_proc_unlock(rp, ERTS_PROC_LOCK_MAIN);
- }
-#endif
-
- BIF_RET2(am_true, reds);
-}
-
BIF_RETTYPE garbage_collect_0(BIF_ALIST_0)
{
int reds;
diff --git a/erts/emulator/beam/bif.tab b/erts/emulator/beam/bif.tab
index 7c8e4b31cf..3ec534f0bc 100644
--- a/erts/emulator/beam/bif.tab
+++ b/erts/emulator/beam/bif.tab
@@ -45,8 +45,6 @@ bif erlang:apply/3
bif erlang:atom_to_list/1
bif erlang:binary_to_list/1
bif erlang:binary_to_list/3
-bif erlang:binary_to_term/1
-bif erlang:check_process_code/2
bif erlang:crc32/1
bif erlang:crc32/2
bif erlang:crc32_combine/3
@@ -67,7 +65,6 @@ bif erlang:float_to_list/1
bif erlang:float_to_list/2
bif erlang:fun_info/2
bif erlang:garbage_collect/0
-bif erlang:garbage_collect/1
bif erlang:get/0
bif erlang:get/1
bif erlang:get_keys/1
@@ -154,6 +151,12 @@ bif erts_internal:port_command/3
bif erts_internal:port_control/3
bif erts_internal:port_close/1
bif erts_internal:port_connect/2
+bif erts_internal:binary_to_term/1
+bif erts_internal:binary_to_term/2
+
+bif erts_internal:request_system_task/3
+bif erts_internal:check_process_code/2
+
# inet_db support
bif erlang:port_set_data/2
@@ -477,11 +480,6 @@ bif erlang:call_on_load_function/1
bif erlang:finish_after_on_load/2
#
-# New Bifs in R13B4
-#
-bif erlang:binary_to_term/2
-
-#
# The binary match bifs (New in R14A - EEP9)
#
@@ -572,6 +570,7 @@ bif erlang:float_to_binary/2
bif erlang:binary_to_float/1
bif io:printable_range/0
+bif os:unsetenv/1
#
# New in R17A
diff --git a/erts/emulator/beam/break.c b/erts/emulator/beam/break.c
index 99604fa3bc..7d4f52ee23 100644
--- a/erts/emulator/beam/break.c
+++ b/erts/emulator/beam/break.c
@@ -112,10 +112,12 @@ process_killer(void)
erts_smp_proc_lock(rp, rp_locks);
state = erts_smp_atomic32_read_acqb(&rp->state);
if (state & (ERTS_PSFLG_FREE
- | ERTS_PSFLG_EXITING
- | ERTS_PSFLG_ACTIVE
- | ERTS_PSFLG_IN_RUNQ
- | ERTS_PSFLG_RUNNING)) {
+ | ERTS_PSFLG_EXITING
+ | ERTS_PSFLG_ACTIVE
+ | ERTS_PSFLG_ACTIVE_SYS
+ | ERTS_PSFLG_IN_RUNQ
+ | ERTS_PSFLG_RUNNING
+ | ERTS_PSFLG_RUNNING_SYS)) {
erts_printf("Can only kill WAITING processes this way\n");
}
else {
@@ -757,7 +759,7 @@ erl_crash_dump_v(char *file, int line, char* fmt, va_list args)
return; /* Can't create the crash dump, skip it */
time(&now);
- erts_fdprintf(fd, "=erl_crash_dump:0.2\n%s", ctime(&now));
+ erts_fdprintf(fd, "=erl_crash_dump:0.3\n%s", ctime(&now));
if (file != NULL)
erts_fdprintf(fd, "The error occurred in file %s, line %d\n", file, line);
diff --git a/erts/emulator/beam/erl_alloc.c b/erts/emulator/beam/erl_alloc.c
index d8da616d05..b5ba9bb94a 100644
--- a/erts/emulator/beam/erl_alloc.c
+++ b/erts/emulator/beam/erl_alloc.c
@@ -100,6 +100,8 @@ static Uint install_debug_functions(void);
#endif
#endif
+static int lock_all_physical_memory = 0;
+
ErtsAllocatorFunctions_t erts_allctrs[ERTS_ALC_A_MAX+1];
ErtsAllocatorInfo_t erts_allctrs_info[ERTS_ALC_A_MAX+1];
ErtsAllocatorThrSpec_t erts_allctr_thr_spec[ERTS_ALC_A_MAX+1];
@@ -618,6 +620,8 @@ erts_alloc_init(int *argc, char **argv, ErtsAllocInitOpts *eaiop)
hdbg_init();
#endif
+ lock_all_physical_memory = 0;
+
ncpu = eaiop->ncpu;
if (ncpu < 1)
ncpu = 1;
@@ -641,6 +645,20 @@ erts_alloc_init(int *argc, char **argv, ErtsAllocInitOpts *eaiop)
if (argc && argv)
handle_args(argc, argv, &init);
+ if (lock_all_physical_memory) {
+#ifdef HAVE_MLOCKALL
+ errno = 0;
+ if (mlockall(MCL_CURRENT|MCL_FUTURE) != 0) {
+ int err = errno;
+ char *errstr = err ? strerror(err) : "unknown";
+ erl_exit(-1, "Failed to lock physical memory: %s (%d)\n",
+ errstr, err);
+ }
+#else
+ erl_exit(-1, "Failed to lock physical memory: Not supported\n");
+#endif
+ }
+
#ifndef ERTS_SMP
init.sl_alloc.thr_spec = 0;
init.std_alloc.thr_spec = 0;
@@ -1486,11 +1504,11 @@ handle_args(int *argc, char **argv, erts_alc_hndl_args_init_t *init)
#endif
get_bool_value(argv[i]+8, argv, &i);
}
- else if (has_prefix("scmgc", argv[i]+3)) {
+ else if (has_prefix("scrfsd", argv[i]+3)) {
#if HAVE_ERTS_MSEG
- init->mseg.mmap.scmgc =
+ init->mseg.mmap.scrfsd =
#endif
- get_amount_value(argv[i]+8, argv, &i);
+ get_amount_value(argv[i]+9, argv, &i);
}
else {
bad_param(param, param+2);
@@ -1630,6 +1648,19 @@ handle_args(int *argc, char **argv, erts_alc_hndl_args_init_t *init)
bad_param(param, param+2);
}
break;
+ case 'l':
+ if (has_prefix("pm", param+2)) {
+ arg = get_value(argv[i]+5, argv, &i);
+ if (strcmp("all", arg) == 0)
+ lock_all_physical_memory = 1;
+ else if (strcmp("no", arg) == 0)
+ lock_all_physical_memory = 0;
+ else
+ bad_value(param, param+4, arg);
+ break;
+ }
+ bad_param(param, param+2);
+ break;
case 'u':
if (has_prefix("ycs", argv[i]+3)) {
init->alloc_util.ycs
@@ -1639,6 +1670,10 @@ handle_args(int *argc, char **argv, erts_alc_hndl_args_init_t *init)
init->alloc_util.mmc
= get_amount_value(argv[i]+6, argv, &i);
}
+ else if (has_prefix("sac", argv[i]+3)) {
+ init->alloc_util.sac
+ = get_bool_value(argv[i]+6, argv, &i);
+ }
else {
int a;
int start = i;
@@ -2749,8 +2784,8 @@ erts_allocator_options(void *proc)
#endif
Uint sz, *szp, *hp, **hpp;
Eterm res, features, settings;
- Eterm atoms[ERTS_ALC_A_MAX-ERTS_ALC_A_MIN+6];
- Uint terms[ERTS_ALC_A_MAX-ERTS_ALC_A_MIN+6];
+ Eterm atoms[ERTS_ALC_A_MAX-ERTS_ALC_A_MIN+7];
+ Uint terms[ERTS_ALC_A_MAX-ERTS_ALC_A_MIN+7];
int a, length;
SysAllocStat sas;
Uint *endp = NULL;
@@ -2848,6 +2883,11 @@ erts_allocator_options(void *proc)
terms[length++] = erts_bld_2tup_list(hpp, szp, 3, o, v);
}
+ atoms[length] = am_atom_put("lock_physical_memory", 20);
+ terms[length++] = (lock_all_physical_memory
+ ? am_atom_put("all", 3)
+ : am_atom_put("no", 2));
+
settings = erts_bld_2tup_list(hpp, szp, length, atoms, terms);
length = 0;
diff --git a/erts/emulator/beam/erl_alloc.types b/erts/emulator/beam/erl_alloc.types
index bb5eba80be..32308fae9b 100644
--- a/erts/emulator/beam/erl_alloc.types
+++ b/erts/emulator/beam/erl_alloc.types
@@ -268,6 +268,8 @@ type PROC_INTERVAL LONG_LIVED SYSTEM process_interval
type BUSY_CALLER_TAB SHORT_LIVED SYSTEM busy_caller_table
type BUSY_CALLER SHORT_LIVED SYSTEM busy_caller
type PORT_DATA_HEAP STANDARD SYSTEM port_data_heap
+type PROC_SYS_TSK SHORT_LIVED PROCESSES proc_sys_task
+type PROC_SYS_TSK_QS SHORT_LIVED PROCESSES proc_sys_task_queues
+if threads_no_smp
# Need thread safe allocs, but std_alloc and fix_alloc are not;
diff --git a/erts/emulator/beam/erl_alloc_util.c b/erts/emulator/beam/erl_alloc_util.c
index 1fdee4db2c..c6cea0185f 100644
--- a/erts/emulator/beam/erl_alloc_util.c
+++ b/erts/emulator/beam/erl_alloc_util.c
@@ -98,6 +98,7 @@ static Uint sys_alloc_carrier_size;
#if HAVE_ERTS_MSEG
static Uint max_mseg_carriers;
#endif
+static int allow_sys_alloc_carriers;
#define ONE_GIGA (1000000000)
@@ -372,6 +373,8 @@ do { \
#define ERTS_CRR_ALCTR_FLG_IN_POOL (((erts_aint_t) 1) << 0)
#define ERTS_CRR_ALCTR_FLG_BUSY (((erts_aint_t) 1) << 1)
+#define ERTS_CRR_ALCTR_FLG_MASK (ERTS_CRR_ALCTR_FLG_IN_POOL | \
+ ERTS_CRR_ALCTR_FLG_BUSY)
#ifdef ERTS_SMP
#define SBC_HEADER_SIZE \
@@ -1404,14 +1407,14 @@ get_used_allctr(Allctr_t *pref_allctr, int pref_lock, void *p, UWord *sizep,
if (ERTS_ALC_TS_PREF_LOCK_IF_USED == pref_lock
&& pref_allctr->thread_safe) {
- used_allctr = (Allctr_t *) (iallctr & ~FLG_MASK);
+ used_allctr = (Allctr_t *) (iallctr & ~ERTS_CRR_ALCTR_FLG_MASK);
if (pref_allctr == used_allctr) {
erts_mtx_lock(&pref_allctr->mutex);
locked_pref_allctr = 1;
}
}
- while ((iallctr & ((~FLG_MASK)|ERTS_CRR_ALCTR_FLG_IN_POOL))
+ while ((iallctr & ((~ERTS_CRR_ALCTR_FLG_MASK)|ERTS_CRR_ALCTR_FLG_IN_POOL))
== (((erts_aint_t) pref_allctr)|ERTS_CRR_ALCTR_FLG_IN_POOL)) {
erts_aint_t act;
@@ -1426,7 +1429,7 @@ get_used_allctr(Allctr_t *pref_allctr, int pref_lock, void *p, UWord *sizep,
iallctr = act;
}
- used_allctr = (Allctr_t *) (iallctr & ~FLG_MASK);
+ used_allctr = (Allctr_t *) (iallctr & ~ERTS_CRR_ALCTR_FLG_MASK);
if (ERTS_ALC_TS_PREF_LOCK_IF_USED == pref_lock) {
if (locked_pref_allctr && used_allctr != pref_allctr) {
@@ -1436,16 +1439,16 @@ get_used_allctr(Allctr_t *pref_allctr, int pref_lock, void *p, UWord *sizep,
}
ERTS_ALC_CPOOL_ASSERT(
- (((iallctr & ~FLG_MASK) == (erts_aint_t) pref_allctr)
- ? (((iallctr & FLG_MASK) == ERTS_CRR_ALCTR_FLG_IN_POOL)
- || ((iallctr & FLG_MASK) == 0))
+ (((iallctr & ~ERTS_CRR_ALCTR_FLG_MASK) == (erts_aint_t) pref_allctr)
+ ? (((iallctr & ERTS_CRR_ALCTR_FLG_MASK) == ERTS_CRR_ALCTR_FLG_IN_POOL)
+ || ((iallctr & ERTS_CRR_ALCTR_FLG_MASK) == 0))
: 1));
return used_allctr;
}
}
- used_allctr = (Allctr_t *) (iallctr & ~FLG_MASK);
+ used_allctr = (Allctr_t *) (iallctr & ~ERTS_CRR_ALCTR_FLG_MASK);
if (ERTS_ALC_TS_PREF_LOCK_IF_USED == pref_lock
&& used_allctr == pref_allctr
@@ -1776,7 +1779,7 @@ handle_delayed_dealloc(Allctr_t *allctr,
ERTS_ALC_CPOOL_ASSERT(allctr == crr->cpool.orig_allctr);
ERTS_ALC_CPOOL_ASSERT(((erts_aint_t) allctr)
!= (erts_smp_atomic_read_nob(&crr->allctr)
- & ~FLG_MASK));
+ & ~ERTS_CRR_ALCTR_FLG_MASK));
erts_smp_atomic_set_nob(&crr->allctr, ((erts_aint_t) allctr));
@@ -2919,7 +2922,7 @@ cpool_fetch(Allctr_t *allctr, UWord size)
#ifdef ERTS_ALC_CPOOL_DEBUG
ERTS_ALC_CPOOL_ASSERT(erts_smp_atomic_xchg_nob(&crr->allctr,
((erts_aint_t) allctr))
- == (((erts_aint_t) allctr) & ~FLG_MASK));
+ == (((erts_aint_t) allctr) & ~ERTS_CRR_ALCTR_FLG_MASK));
#else
erts_smp_atomic_set_nob(&crr->allctr, ((erts_aint_t) allctr));
#endif
@@ -2961,7 +2964,7 @@ cpool_fetch(Allctr_t *allctr, UWord size)
(erts_aint_t) allctr,
exp);
if (act == exp) {
- cpool_delete(allctr, ((Allctr_t *) (act & ~FLG_MASK)), crr);
+ cpool_delete(allctr, ((Allctr_t *) (act & ~ERTS_CRR_ALCTR_FLG_MASK)), crr);
return crr;
}
}
@@ -3056,7 +3059,7 @@ schedule_dealloc_carrier(Allctr_t *allctr, Carrier_t *crr)
ERTS_ALC_CPOOL_ASSERT(crr == FIRST_BLK_TO_MBC(allctr, blk));
ERTS_ALC_CPOOL_ASSERT(((erts_aint_t) allctr)
== (erts_smp_atomic_read_nob(&crr->allctr)
- & ~FLG_MASK));
+ & ~ERTS_CRR_ALCTR_FLG_MASK));
if (ddq_enqueue(&orig_allctr->dd.q, BLK2UMEM(blk), cinit))
erts_alloc_notify_delayed_dealloc(orig_allctr->ix);
@@ -3256,13 +3259,15 @@ create_carrier(Allctr_t *allctr, Uint umem_sz, UWord flags)
int is_mseg = 0;
#endif
-#if HALFWORD_HEAP
- flags |= CFLG_FORCE_MSEG;
-#elif ERTS_SUPER_ALIGNED_MSEG_ONLY
- if (flags & CFLG_MBC) {
+ if (HALFWORD_HEAP
+ || (ERTS_SUPER_ALIGNED_MSEG_ONLY && (flags & CFLG_MBC))
+ || !allow_sys_alloc_carriers) {
flags |= CFLG_FORCE_MSEG;
- }
+ flags &= ~CFLG_FORCE_SYS_ALLOC;
+#if !HAVE_ERTS_MSEG
+ return NULL;
#endif
+ }
ASSERT((flags & CFLG_SBC && !(flags & CFLG_MBC))
|| (flags & CFLG_MBC && !(flags & CFLG_SBC)));
@@ -3565,7 +3570,6 @@ resize_carrier(Allctr_t *allctr, Block_t *old_blk, Uint umem_sz, UWord flags)
/* Old carrier unchanged; restore... */
STAT_SYS_ALLOC_SBC_ALLOC(allctr, old_crr_sz, old_blk_sz);
}
- DEBUG_SAVE_ALIGNMENT(new_crr);
return new_blk;
}
#endif
@@ -3697,6 +3701,7 @@ static struct {
Eterm mmc;
#endif
Eterm ycs;
+ Eterm sac;
Eterm fix_types;
@@ -3789,6 +3794,7 @@ init_atoms(Allctr_t *allctr)
AM_INIT(mmc);
#endif
AM_INIT(ycs);
+ AM_INIT(sac);
AM_INIT(fix_types);
@@ -4509,17 +4515,22 @@ erts_alcu_au_info_options(int *print_to_p, void *print_to_arg,
#if HAVE_ERTS_MSEG
"option mmc: %beu\n"
#endif
- "option ycs: %beu\n",
+ "option ycs: %beu\n"
+ "option sac: %s\n",
#if HAVE_ERTS_MSEG
max_mseg_carriers,
#endif
- sys_alloc_carrier_size);
+ sys_alloc_carrier_size,
+ allow_sys_alloc_carriers ? "true" : "false");
}
if (hpp || szp) {
res = NIL;
ensure_atoms_initialized(NULL);
add_2tup(hpp, szp, &res,
+ am.sac,
+ allow_sys_alloc_carriers ? am_true : am_false);
+ add_2tup(hpp, szp, &res,
am.ycs,
bld_uint(hpp, szp, sys_alloc_carrier_size));
#if HAVE_ERTS_MSEG
@@ -5422,6 +5433,11 @@ erts_alcu_start(Allctr_t *allctr, AllctrInit_t *init)
{
/* erts_alcu_start assumes that allctr has been zeroed */
+ if (((UWord)allctr & ERTS_CRR_ALCTR_FLG_MASK) != 0) {
+ erl_exit(ERTS_ABORT_EXIT, "%s:%d:erts_alcu_start: Alignment error\n",
+ __FILE__, __LINE__);
+ }
+
if (!initialized)
goto error;
@@ -5512,7 +5528,7 @@ erts_alcu_start(Allctr_t *allctr, AllctrInit_t *init)
erts_atomic_init_nob(&allctr->cpool.stat.carriers_size, 0);
erts_atomic_init_nob(&allctr->cpool.stat.no_carriers, 0);
allctr->cpool.check_limit_count = ERTS_ALC_CPOOL_CHECK_LIMIT_COUNT;
- allctr->cpool.util_limit = init->acul;
+ allctr->cpool.util_limit = init->ts ? 0 : init->acul;
#endif
allctr->sbc_threshold = init->sbct;
@@ -5593,8 +5609,15 @@ erts_alcu_start(Allctr_t *allctr, AllctrInit_t *init)
| CFLG_FORCE_SYS_ALLOC
#endif
| CFLG_MAIN_CARRIER);
- if (!blk)
- goto error;
+ if (!blk) {
+#ifdef USE_THREADS
+ if (allctr->thread_safe)
+ erts_mtx_destroy(&allctr->mutex);
+#endif
+ erl_exit(ERTS_ABORT_EXIT,
+ "Failed to create main carrier for %salloc\n",
+ init->name_prefix);
+ }
(*allctr->link_free_block)(allctr, blk);
@@ -5681,6 +5704,7 @@ erts_alcu_init(AlcUInit_t *init)
#else /* #if HAVE_ERTS_MSEG */
sys_alloc_carrier_size = ((init->ycs + 4095) / 4096) * 4096;
#endif
+ allow_sys_alloc_carriers = init->sac;
#ifdef DEBUG
carrier_alignment = sizeof(Unit_t);
diff --git a/erts/emulator/beam/erl_alloc_util.h b/erts/emulator/beam/erl_alloc_util.h
index 222f137024..7be6b1ed9d 100644
--- a/erts/emulator/beam/erl_alloc_util.h
+++ b/erts/emulator/beam/erl_alloc_util.h
@@ -32,6 +32,7 @@ typedef struct Allctr_t_ Allctr_t;
typedef struct {
UWord ycs;
UWord mmc;
+ int sac;
} AlcUInit_t;
typedef struct {
@@ -75,7 +76,8 @@ typedef struct {
#define ERTS_DEFAULT_ALCU_INIT { \
1024*1024, /* (bytes) ycs: sys_alloc carrier size */\
- ~((UWord) 0) /* (amount) mmc: max mseg carriers */ \
+ ~((UWord) 0), /* (amount) mmc: max mseg carriers */\
+ 1 /* (bool) sac: sys_alloc carriers */\
}
#define ERTS_DEFAULT_ALLCTR_INIT { \
@@ -109,7 +111,8 @@ typedef struct {
#define ERTS_DEFAULT_ALCU_INIT { \
128*1024, /* (bytes) ycs: sys_alloc carrier size */\
- 1024 /* (amount) mmc: max mseg carriers */\
+ 1024, /* (amount) mmc: max mseg carriers */\
+ 1 /* (bool) sac: sys_alloc carriers */\
}
#define ERTS_DEFAULT_ALLCTR_INIT { \
diff --git a/erts/emulator/beam/erl_bif_info.c b/erts/emulator/beam/erl_bif_info.c
index d7f1e2d971..414ae2f046 100755
--- a/erts/emulator/beam/erl_bif_info.c
+++ b/erts/emulator/beam/erl_bif_info.c
@@ -65,8 +65,8 @@ static Export *gather_gc_info_res_trap;
#define DECL_AM(S) Eterm AM_ ## S = am_atom_put(#S, sizeof(#S) - 1)
/* Keep erts_system_version as a global variable for easy access from a core */
-static char erts_system_version[] = ("Erlang " ERLANG_OTP_RELEASE
- " (erts-" ERLANG_VERSION ")"
+static char erts_system_version[] = ("Erlang/OTP " ERLANG_OTP_RELEASE
+ " [erts-" ERLANG_VERSION "]"
#if !HEAP_ON_C_STACK && !HALFWORD_HEAP
" [no-c-stack-objects]"
#endif
@@ -3603,6 +3603,20 @@ BIF_RETTYPE erts_debug_set_internal_state_2(BIF_ALIST_2)
BIF_RET(am_true);
}
}
+ else if (ERTS_IS_ATOM_STR("gc_state", BIF_ARG_1)) {
+ /* Used by process_SUITE (emulator) */
+ int res, enable;
+
+ switch (BIF_ARG_2) {
+ case am_true: enable = 1; break;
+ case am_false: enable = 0; break;
+ default: BIF_ERROR(BIF_P, BADARG); break;
+ }
+
+ res = (BIF_P->flags & F_DISABLE_GC) ? am_false : am_true;
+ erts_set_gc_state(BIF_P, enable);
+ BIF_RET(res);
+ }
else if (ERTS_IS_ATOM_STR("send_fake_exit_signal", BIF_ARG_1)) {
/* Used by signal_SUITE (emulator) */
diff --git a/erts/emulator/beam/erl_bif_os.c b/erts/emulator/beam/erl_bif_os.c
index 1062d4379b..e07c622928 100644
--- a/erts/emulator/beam/erl_bif_os.c
+++ b/erts/emulator/beam/erl_bif_os.c
@@ -180,3 +180,25 @@ BIF_RETTYPE os_putenv_2(BIF_ALIST_2)
BIF_RET(am_true);
}
+BIF_RETTYPE os_unsetenv_1(BIF_ALIST_1)
+{
+ char *key_buf;
+ char buf[STATIC_BUF_SIZE];
+
+ key_buf = erts_convert_filename_to_native(BIF_ARG_1,buf,STATIC_BUF_SIZE,
+ ERTS_ALC_T_TMP,0,0,NULL);
+ if (!key_buf) {
+ BIF_ERROR(BIF_P, BADARG);
+ }
+
+ if (erts_sys_unsetenv(key_buf)) {
+ if (key_buf != buf) {
+ erts_free(ERTS_ALC_T_TMP, key_buf);
+ }
+ BIF_ERROR(BIF_P, BADARG);
+ }
+ if (key_buf != buf) {
+ erts_free(ERTS_ALC_T_TMP, key_buf);
+ }
+ BIF_RET(am_true);
+}
diff --git a/erts/emulator/beam/erl_bif_port.c b/erts/emulator/beam/erl_bif_port.c
index 5b26e53c9f..864349491a 100644
--- a/erts/emulator/beam/erl_bif_port.c
+++ b/erts/emulator/beam/erl_bif_port.c
@@ -84,7 +84,7 @@ BIF_RETTYPE open_port_2(BIF_ALIST_2)
}
static ERTS_INLINE Port *
-lookup_port(Process *c_p, Eterm id_or_name)
+lookup_port(Process *c_p, Eterm id_or_name, Uint32 invalid_flags)
{
/* TODO: Implement nicer lookup in register... */
Eterm id;
@@ -92,7 +92,19 @@ lookup_port(Process *c_p, Eterm id_or_name)
id = erts_whereis_name_to_id(c_p, id_or_name);
else
id = id_or_name;
- return erts_port_lookup(id, ERTS_PORT_SFLGS_INVALID_LOOKUP);
+ return erts_port_lookup(id, invalid_flags);
+}
+
+static ERTS_INLINE Port *
+sig_lookup_port(Process *c_p, Eterm id_or_name)
+{
+ return lookup_port(c_p, id_or_name, ERTS_PORT_SFLGS_INVALID_DRIVER_LOOKUP);
+}
+
+static ERTS_INLINE Port *
+data_lookup_port(Process *c_p, Eterm id_or_name)
+{
+ return lookup_port(c_p, id_or_name, ERTS_PORT_SFLGS_INVALID_LOOKUP);
}
/*
@@ -125,7 +137,7 @@ BIF_RETTYPE erts_internal_port_command_3(BIF_ALIST_3)
BIF_RET(am_badarg);
}
- prt = lookup_port(BIF_P, BIF_ARG_1);
+ prt = sig_lookup_port(BIF_P, BIF_ARG_1);
if (!prt)
BIF_RET(am_badarg);
@@ -185,7 +197,7 @@ BIF_RETTYPE erts_internal_port_call_3(BIF_ALIST_3)
unsigned int op;
erts_aint32_t state;
- prt = lookup_port(BIF_P, BIF_ARG_1);
+ prt = sig_lookup_port(BIF_P, BIF_ARG_1);
if (!prt)
BIF_RET(am_badarg);
@@ -235,7 +247,7 @@ BIF_RETTYPE erts_internal_port_control_3(BIF_ALIST_3)
unsigned int op;
erts_aint32_t state;
- prt = lookup_port(BIF_P, BIF_ARG_1);
+ prt = sig_lookup_port(BIF_P, BIF_ARG_1);
if (!prt)
BIF_RET(am_badarg);
@@ -290,7 +302,7 @@ BIF_RETTYPE erts_internal_port_close_1(BIF_ALIST_1)
ref = NIL;
#endif
- prt = lookup_port(BIF_P, BIF_ARG_1);
+ prt = sig_lookup_port(BIF_P, BIF_ARG_1);
if (!prt)
BIF_RET(am_badarg);
@@ -320,7 +332,7 @@ BIF_RETTYPE erts_internal_port_connect_2(BIF_ALIST_2)
Eterm ref;
Port* prt;
- prt = lookup_port(BIF_P, BIF_ARG_1);
+ prt = sig_lookup_port(BIF_P, BIF_ARG_1);
if (!prt)
BIF_RET(am_badarg);
@@ -352,7 +364,7 @@ BIF_RETTYPE erts_internal_port_info_1(BIF_ALIST_1)
Port* prt;
if (is_internal_port(BIF_ARG_1) || is_atom(BIF_ARG_1)) {
- prt = lookup_port(BIF_P, BIF_ARG_1);
+ prt = sig_lookup_port(BIF_P, BIF_ARG_1);
if (!prt)
BIF_RET(am_undefined);
}
@@ -391,7 +403,7 @@ BIF_RETTYPE erts_internal_port_info_2(BIF_ALIST_2)
Port* prt;
if (is_internal_port(BIF_ARG_1) || is_atom(BIF_ARG_1)) {
- prt = lookup_port(BIF_P, BIF_ARG_1);
+ prt = sig_lookup_port(BIF_P, BIF_ARG_1);
if (!prt)
BIF_RET(am_undefined);
}
@@ -523,7 +535,7 @@ BIF_RETTYPE port_set_data_2(BIF_ALIST_2)
erts_aint_t data;
Port* prt;
- prt = lookup_port(BIF_P, BIF_ARG_1);
+ prt = data_lookup_port(BIF_P, BIF_ARG_1);
if (!prt)
BIF_ERROR(BIF_P, BADARG);
@@ -564,7 +576,7 @@ BIF_RETTYPE port_get_data_1(BIF_ALIST_1)
erts_aint_t data;
Port* prt;
- prt = lookup_port(BIF_P, BIF_ARG_1);
+ prt = data_lookup_port(BIF_P, BIF_ARG_1);
if (!prt)
BIF_ERROR(BIF_P, BADARG);
diff --git a/erts/emulator/beam/erl_binary.h b/erts/emulator/beam/erl_binary.h
index f7dc20f5e6..819b19e566 100644
--- a/erts/emulator/beam/erl_binary.h
+++ b/erts/emulator/beam/erl_binary.h
@@ -225,7 +225,7 @@ erts_free_aligned_binary_bytes(byte* buf)
** These extra bytes where earlier (< R13B04) added by an alignment-bug
** in this code. Do we dare remove this in some major release (R14?) maybe?
*/
-#ifdef DEBUG
+#if defined(DEBUG) || defined(VALGRIND)
# define CHICKEN_PAD 0
#else
# define CHICKEN_PAD (sizeof(void*) - 1)
diff --git a/erts/emulator/beam/erl_bits.c b/erts/emulator/beam/erl_bits.c
index 43eb691338..73765772c8 100644
--- a/erts/emulator/beam/erl_bits.c
+++ b/erts/emulator/beam/erl_bits.c
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 1999-2012. All Rights Reserved.
+ * Copyright Ericsson AB 1999-2013. All Rights Reserved.
*
* The contents of this file are subject to the Erlang Public License,
* Version 1.1, (the "License"); you may not use this file except in
@@ -1491,7 +1491,7 @@ erts_bs_private_append(Process* p, Eterm bin, Eterm build_size_term, Uint unit)
bptr->flags = 0;
bptr->orig_size = new_size;
erts_refc_init(&bptr->refc, 1);
- sys_memcpy(bptr->orig_bytes, binp->orig_bytes, pb->size);
+ sys_memcpy(bptr->orig_bytes, binp->orig_bytes, binp->orig_size);
pb->flags |= PB_IS_WRITABLE | PB_ACTIVE_WRITER;
pb->val = bptr;
pb->bytes = (byte *) bptr->orig_bytes;
@@ -1810,6 +1810,11 @@ erts_cmp_bits(byte* a_ptr, size_t a_offs, byte* b_ptr, size_t b_offs, size_t siz
Uint rshift;
int cmp;
+ ASSERT(a_offs < 8 && b_offs < 8);
+
+ if (size == 0)
+ return 0;
+
if (((a_offs | b_offs | size) & 7) == 0) {
int byte_size = size >> 3;
return sys_memcmp(a_ptr, b_ptr, byte_size);
@@ -1818,58 +1823,72 @@ erts_cmp_bits(byte* a_ptr, size_t a_offs, byte* b_ptr, size_t b_offs, size_t siz
/* Compare bit by bit until a_ptr is aligned on byte boundary */
a = *a_ptr++;
b = *b_ptr++;
- while (size > 0) {
- a_bit = get_bit(a, a_offs);
- b_bit = get_bit(b, b_offs);
- if ((cmp = (a_bit-b_bit)) != 0) {
- return cmp;
- }
- size--;
- b_offs++;
- if (b_offs == 8) {
- b_offs = 0;
- b = *b_ptr++;
- }
- a_offs++;
- if (a_offs == 8) {
- a_offs = 0;
- a = *a_ptr++;
- break;
+ if (a_offs) {
+ for (;;) {
+ a_bit = get_bit(a, a_offs);
+ b_bit = get_bit(b, b_offs);
+ if ((cmp = (a_bit-b_bit)) != 0) {
+ return cmp;
+ }
+ if (--size == 0)
+ return 0;
+
+ b_offs++;
+ if (b_offs == 8) {
+ b_offs = 0;
+ b = *b_ptr++;
+ }
+ a_offs++;
+ if (a_offs == 8) {
+ a_offs = 0;
+ a = *a_ptr++;
+ break;
+ }
}
}
/* Compare byte by byte as long as at least 8 bits remain */
- lshift = b_offs;
- rshift = 8 - lshift;
- while (size >= 8) {
- byte b_cmp = (b << lshift);
- b = *b_ptr++;
- b_cmp |= b >> rshift;
- if ((cmp = (a - b_cmp)) != 0) {
- return cmp;
- }
+ if (size >= 8) {
+ lshift = b_offs;
+ rshift = 8 - lshift;
+ for (;;) {
+ byte b_cmp = (b << lshift);
+ b = *b_ptr++;
+ b_cmp |= b >> rshift;
+ if ((cmp = (a - b_cmp)) != 0) {
+ return cmp;
+ }
+ size -= 8;
+ if (size < 8)
+ break;
+ a = *a_ptr++;
+ }
+
+ if (size == 0)
+ return 0;
a = *a_ptr++;
- size -= 8;
}
/* Compare the remaining bits bit by bit */
- while (size > 0) {
- a_bit = get_bit(a, a_offs);
- b_bit = get_bit(b, b_offs);
- if ((cmp = (a_bit-b_bit)) != 0) {
- return cmp;
- }
- a_offs++;
- if (a_offs == 8) {
- a_offs = 0;
- a = *a_ptr++;
- }
- b_offs++;
- if (b_offs == 8) {
- b_offs = 0;
- b = *b_ptr++;
- }
- size--;
+ if (size > 0) {
+ for (;;) {
+ a_bit = get_bit(a, a_offs);
+ b_bit = get_bit(b, b_offs);
+ if ((cmp = (a_bit-b_bit)) != 0) {
+ return cmp;
+ }
+ if (--size == 0)
+ return 0;
+
+ a_offs++;
+ ASSERT(a_offs < 8);
+
+ b_offs++;
+ if (b_offs == 8) {
+ b_offs = 0;
+ b = *b_ptr++;
+ }
+ }
}
return 0;
diff --git a/erts/emulator/beam/erl_debug.c b/erts/emulator/beam/erl_debug.c
index b90d00f236..873a9860da 100644
--- a/erts/emulator/beam/erl_debug.c
+++ b/erts/emulator/beam/erl_debug.c
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 1998-2012. All Rights Reserved.
+ * Copyright Ericsson AB 1998-2013. All Rights Reserved.
*
* The contents of this file are subject to the Erlang Public License,
* Version 1.1, (the "License"); you may not use this file except in
@@ -299,6 +299,9 @@ void erts_check_for_holes(Process* p)
ErlHeapFragment* hf;
Eterm* start;
+ if (p->flags & F_DISABLE_GC)
+ return;
+
start = p->last_htop ? p->last_htop : HEAP_START(p);
check_memory(start, HEAP_TOP(p));
p->last_htop = HEAP_TOP(p);
diff --git a/erts/emulator/beam/erl_gc.c b/erts/emulator/beam/erl_gc.c
index 8ba94d89e9..c5585d39e8 100644
--- a/erts/emulator/beam/erl_gc.c
+++ b/erts/emulator/beam/erl_gc.c
@@ -400,10 +400,16 @@ erts_garbage_collect(Process* p, int need, Eterm* objv, int nobj)
Uint reclaimed_now = 0;
int done = 0;
Uint ms1, s1, us1;
- ErtsSchedulerData *esdp = erts_get_scheduler_data();
+ ErtsSchedulerData *esdp;
#ifdef USE_VM_PROBES
DTRACE_CHARBUF(pidbuf, DTRACE_TERM_BUF_SIZE);
#endif
+
+ if (p->flags & F_DISABLE_GC)
+ return 1;
+
+ esdp = erts_get_scheduler_data();
+
if (IS_TRACED_FL(p, F_TRACE_GC)) {
trace_gc(p, am_gc_start);
}
@@ -532,6 +538,9 @@ erts_garbage_collect_hibernate(Process* p)
Uint area_size;
Sint offs;
+ if (p->flags & F_DISABLE_GC)
+ ERTS_INTERNAL_ERROR("GC disabled");
+
/*
* Preliminaries.
*/
@@ -667,6 +676,8 @@ erts_garbage_collect_literals(Process* p, Eterm* literals,
Uint n;
struct erl_off_heap_header** prev;
+ if (p->flags & F_DISABLE_GC)
+ return;
/*
* Set GC state.
*/
@@ -2770,7 +2781,7 @@ erts_check_off_heap2(Process *p, Eterm *htop)
refc = erts_refc_read(&u.ext->node->refc, 1);
break;
default:
- ASSERT(!!"erts_check_off_heap2: Invalid thing_word");
+ ASSERT(!"erts_check_off_heap2: Invalid thing_word");
}
ERTS_CHK_OFFHEAP_ASSERT(refc >= 1);
#ifdef ERTS_OFFHEAP_DEBUG_CHK_CIRCULAR_LIST
diff --git a/erts/emulator/beam/erl_message.c b/erts/emulator/beam/erl_message.c
index 325d77e911..6a9030fd99 100644
--- a/erts/emulator/beam/erl_message.c
+++ b/erts/emulator/beam/erl_message.c
@@ -46,10 +46,12 @@ ERTS_SCHED_PREF_QUICK_ALLOC_IMPL(message,
+#ifdef DEBUG
static ERTS_INLINE int in_heapfrag(const Eterm* ptr, const ErlHeapFragment *bp)
{
return ((unsigned)(ptr - bp->mem) < bp->used_size);
}
+#endif
void
diff --git a/erts/emulator/beam/erl_message.h b/erts/emulator/beam/erl_message.h
index 771eba431f..0f3bb8d281 100644
--- a/erts/emulator/beam/erl_message.h
+++ b/erts/emulator/beam/erl_message.h
@@ -46,6 +46,11 @@ typedef struct erl_off_heap {
Uint64 overhead; /* Administrative overhead (used to force GC). */
} ErlOffHeap;
+#define ERTS_INIT_OFF_HEAP(OHP) \
+ do { \
+ (OHP)->first = NULL; \
+ (OHP)->overhead = 0; \
+ } while (0)
#include "external.h"
#include "erl_process.h"
diff --git a/erts/emulator/beam/erl_port_task.h b/erts/emulator/beam/erl_port_task.h
index e4d964146e..123253a057 100644
--- a/erts/emulator/beam/erl_port_task.h
+++ b/erts/emulator/beam/erl_port_task.h
@@ -77,6 +77,7 @@ extern erts_smp_atomic_t erts_port_task_outstanding_io_tasks;
#define ERTS_PTS_FLG_HAVE_NS_TASKS (((erts_aint32_t) 1) << 8)
#define ERTS_PTS_FLG_PARALLELISM (((erts_aint32_t) 1) << 9)
#define ERTS_PTS_FLG_FORCE_SCHED (((erts_aint32_t) 1) << 10)
+#define ERTS_PTS_FLG_EXITING (((erts_aint32_t) 1) << 11)
#define ERTS_PTS_FLGS_BUSY \
(ERTS_PTS_FLG_BUSY_PORT | ERTS_PTS_FLG_BUSY_PORT_Q)
@@ -86,7 +87,8 @@ extern erts_smp_atomic_t erts_port_task_outstanding_io_tasks;
| ERTS_PTS_FLG_HAVE_BUSY_TASKS \
| ERTS_PTS_FLG_HAVE_TASKS \
| ERTS_PTS_FLG_EXEC \
- | ERTS_PTS_FLG_FORCE_SCHED)
+ | ERTS_PTS_FLG_FORCE_SCHED \
+ | ERTS_PTS_FLG_EXITING)
#define ERTS_PORT_TASK_DEFAULT_BUSY_PORT_Q_HIGH 8192
#define ERTS_PORT_TASK_DEFAULT_BUSY_PORT_Q_LOW 4096
@@ -135,6 +137,7 @@ ERTS_GLB_INLINE void erts_port_task_fini_sched(ErtsPortTaskSched *ptsp);
ERTS_GLB_INLINE void erts_port_task_sched_lock(ErtsPortTaskSched *ptsp);
ERTS_GLB_INLINE void erts_port_task_sched_unlock(ErtsPortTaskSched *ptsp);
ERTS_GLB_INLINE int erts_port_task_sched_lock_is_locked(ErtsPortTaskSched *ptsp);
+ERTS_GLB_INLINE void erts_port_task_sched_enter_exiting_state(ErtsPortTaskSched *ptsp);
#ifdef ERTS_INCLUDE_SCHEDULER_INTERNALS
ERTS_GLB_INLINE int erts_port_task_have_outstanding_io_tasks(void);
@@ -225,6 +228,12 @@ erts_port_task_fini_sched(ErtsPortTaskSched *ptsp)
#endif
}
+ERTS_GLB_INLINE void
+erts_port_task_sched_enter_exiting_state(ErtsPortTaskSched *ptsp)
+{
+ erts_smp_atomic32_read_bor_nob(&ptsp->flags, ERTS_PTS_FLG_EXITING);
+}
+
#ifdef ERTS_INCLUDE_SCHEDULER_INTERNALS
ERTS_GLB_INLINE int
diff --git a/erts/emulator/beam/erl_process.c b/erts/emulator/beam/erl_process.c
index 1efd070afd..21fd8dd50a 100644
--- a/erts/emulator/beam/erl_process.c
+++ b/erts/emulator/beam/erl_process.c
@@ -283,6 +283,40 @@ struct erts_system_profile_flags_t erts_system_profile_flags;
#error "Need to store process_count in another type"
#endif
+typedef enum {
+ ERTS_PSTT_GC, /* Garbage Collect */
+ ERTS_PSTT_CPC /* Check Process Code */
+} ErtsProcSysTaskType;
+
+#define ERTS_MAX_PROC_SYS_TASK_ARGS 2
+
+struct ErtsProcSysTask_ {
+ ErtsProcSysTask *next;
+ ErtsProcSysTask *prev;
+ ErtsProcSysTaskType type;
+ Eterm requester;
+ Eterm reply_tag;
+ Eterm req_id;
+ Uint req_id_sz;
+ Eterm arg[ERTS_MAX_PROC_SYS_TASK_ARGS];
+ ErlOffHeap off_heap;
+ Eterm heap[1];
+};
+
+#define ERTS_PROC_SYS_TASK_SIZE(HSz) \
+ (sizeof(ErtsProcSysTask) - sizeof(Eterm) + sizeof(Eterm)*(HSz))
+
+struct ErtsProcSysTaskQs_ {
+ int qmask;
+ int ncount;
+ ErtsProcSysTask *q[ERTS_NO_PROC_PRIO_LEVELS];
+};
+
+ERTS_SCHED_PREF_QUICK_ALLOC_IMPL(proc_sys_task_queues,
+ ErtsProcSysTaskQs,
+ 50,
+ ERTS_ALC_T_PROC_SYS_TSK_QS)
+
ERTS_SCHED_PREF_QUICK_ALLOC_IMPL(misc_op_list,
ErtsMiscOpList,
10,
@@ -353,6 +387,14 @@ static void aux_work_timeout_early_init(int no_schedulers);
static void aux_work_timeout_late_init(void);
static void setup_aux_work_timer(void);
+static int execute_sys_tasks(Process *c_p,
+ erts_aint32_t *statep,
+ int in_reds);
+static int cleanup_sys_tasks(Process *c_p,
+ erts_aint32_t in_state,
+ int in_reds);
+
+
#if defined(DEBUG) || 0
#define ERTS_DBG_CHK_AUX_WORK_VAL(V) dbg_chk_aux_work_val((V))
static void
@@ -471,6 +513,11 @@ erts_pre_init_process(void)
erts_psd_required_locks[ERTS_PSD_CALL_TIME_BP].set_locks
= ERTS_PSD_CALL_TIME_BP_SET_LOCKS;
+ erts_psd_required_locks[ERTS_PSD_DELAYED_GC_TASK_QS].get_locks
+ = ERTS_PSD_DELAYED_GC_TASK_QS_GET_LOCKS;
+ erts_psd_required_locks[ERTS_PSD_DELAYED_GC_TASK_QS].set_locks
+ = ERTS_PSD_DELAYED_GC_TASK_QS_SET_LOCKS;
+
/* Check that we have locks for all entries */
for (ix = 0; ix < ERTS_PSD_SIZE; ix++) {
ERTS_SMP_LC_ASSERT(erts_psd_required_locks[ix].get_locks);
@@ -2848,7 +2895,7 @@ dequeue_process(ErtsRunQueue *runq, int prio_q, erts_aint32_t *statep)
if (statep)
*statep = state;
- prio = (int) (ERTS_PSFLG_PRIO_MASK & state);
+ prio = (int) ERTS_PSFLGS_GET_PRQ_PRIO(state);
rqi = &runq->procs.prio_info[prio];
@@ -2997,7 +3044,7 @@ immigrate(ErtsRunQueue *c_rq, ErtsMigrationPath *mp)
erts_aint32_t state;
state = erts_smp_atomic32_read_acqb(&proc->state);
if (!(ERTS_PSFLG_BOUND & state)
- && (prio == (int) (ERTS_PSFLG_PRIO_MASK & state))) {
+ && (prio == (int) ERTS_PSFLGS_GET_PRQ_PRIO(state))) {
ErtsRunQueueInfo *rqi = &rq->procs.prio_info[prio];
unqueue_process(rq, rpq, rqi, prio, prev_proc, proc);
erts_smp_runq_unlock(rq);
@@ -3079,7 +3126,7 @@ schedule_bound_processes(ErtsRunQueue *rq,
while (proc) {
erts_aint32_t state = erts_smp_atomic32_read_acqb(&proc->state);
next = proc->next;
- enqueue_process(rq, (int) (ERTS_PSFLG_PRIO_MASK & state), proc);
+ enqueue_process(rq, (int) ERTS_PSFLGS_GET_PRQ_PRIO(state), proc);
proc = next;
}
}
@@ -3184,7 +3231,7 @@ evacuate_run_queue(ErtsRunQueue *rq,
sbpp->last = proc;
}
else {
- int prio = (int) (ERTS_PSFLG_PRIO_MASK & state);
+ int prio = (int) ERTS_PSFLGS_GET_PRQ_PRIO(state);
erts_smp_runq_unlock(rq);
to_rq = mp->prio[prio].runq;
@@ -3257,7 +3304,7 @@ try_steal_task_from_victim(ErtsRunQueue *rq, int *rq_lockedp, ErtsRunQueue *vrq,
erts_aint32_t state = erts_smp_atomic32_read_acqb(&proc->state);
if (!(ERTS_PSFLG_BOUND & state)) {
/* Steal process */
- int prio = (int) (ERTS_PSFLG_PRIO_MASK & state);
+ int prio = (int) ERTS_PSFLGS_GET_PRQ_PRIO(state);
ErtsRunQueueInfo *rqi = &vrq->procs.prio_info[prio];
unqueue_process(vrq, rpq, rqi, prio, prev_proc, proc);
erts_smp_runq_unlock(vrq);
@@ -4575,6 +4622,7 @@ erts_init_scheduling(int no_schedulers, int no_schedulers_online)
#endif
init_misc_op_list_alloc();
+ init_proc_sys_task_queues_alloc();
#ifdef ERTS_SMP
set_wakeup_other_data();
@@ -4858,46 +4906,166 @@ erts_get_scheduler_data(void)
#endif
+static Process *
+make_proxy_proc(Process *prev_proxy, Process *proc, erts_aint32_t prio)
+{
+ erts_aint32_t state;
+ Process *proxy;
+#ifdef ERTS_SMP
+ ErtsRunQueue *rq = RUNQ_READ_RQ(&proc->run_queue);
+#endif
+
+ state = (ERTS_PSFLG_PROXY
+ | ERTS_PSFLG_IN_RUNQ
+ | (((erts_aint32_t) 1) << (prio + ERTS_PSFLGS_IN_PRQ_MASK_OFFSET))
+ | (prio << ERTS_PSFLGS_PRQ_PRIO_OFFSET)
+ | (prio << ERTS_PSFLGS_USR_PRIO_OFFSET)
+ | (prio << ERTS_PSFLGS_ACT_PRIO_OFFSET));
+
+ if (prev_proxy) {
+ proxy = prev_proxy;
+ ASSERT(erts_smp_atomic32_read_nob(&proxy->state) & ERTS_PSFLG_PROXY);
+ erts_smp_atomic32_set_nob(&proxy->state, state);
+#ifdef ERTS_SMP
+ RUNQ_SET_RQ(&proc->run_queue, rq);
+#endif
+ }
+ else {
+ proxy = erts_alloc(ERTS_ALC_T_PROC, sizeof(Process));
+#ifdef DEBUG
+ {
+ int i;
+ Uint32 *ui32 = (Uint32 *) (char *) proxy;
+ for (i = 0; i < sizeof(Process)/sizeof(Uint32); i++)
+ ui32[i] = (Uint32) 0xdeadbeef;
+ }
+#endif
+ erts_smp_atomic32_init_nob(&proxy->state, state);
+#ifdef ERTS_SMP
+ erts_smp_atomic_init_nob(&proxy->run_queue,
+ erts_smp_atomic_read_nob(&proc->run_queue));
+#endif
+ }
+
+ proxy->common.id = proc->common.id;
+
+ return proxy;
+}
+
+static ERTS_INLINE void
+free_proxy_proc(Process *proxy)
+{
+ ASSERT(erts_smp_atomic32_read_nob(&proxy->state) & ERTS_PSFLG_PROXY);
+ erts_free(ERTS_ALC_T_PROC, proxy);
+}
+
+
+static ERTS_INLINE int
+check_enqueue_in_prio_queue(erts_aint32_t *prq_prio_p,
+ erts_aint32_t *newp,
+ erts_aint32_t actual)
+{
+ erts_aint32_t aprio, qbit, max_qbit;
+
+ aprio = (actual >> ERTS_PSFLGS_ACT_PRIO_OFFSET) & ERTS_PSFLGS_PRIO_MASK;
+ qbit = 1 << aprio;
+
+ *prq_prio_p = aprio;
+
+ max_qbit = (actual >> ERTS_PSFLGS_IN_PRQ_MASK_OFFSET) & ERTS_PSFLGS_QMASK;
+ max_qbit |= 1 << ERTS_PSFLGS_QMASK_BITS;
+ max_qbit &= -max_qbit;
+ /*
+ * max_qbit now either contain bit set for highest prio queue or a bit
+ * out of range (which will have a value larger than valid range).
+ */
+
+ if (qbit >= max_qbit)
+ return 0; /* Already queued in higher or equal prio */
+
+ /* Need to enqueue (if already enqueued, it is in lower prio) */
+ *newp |= qbit << ERTS_PSFLGS_IN_PRQ_MASK_OFFSET;
+
+ if ((actual & (ERTS_PSFLG_IN_RUNQ|ERTS_PSFLGS_USR_PRIO_MASK))
+ != (aprio << ERTS_PSFLGS_USR_PRIO_OFFSET)) {
+ /*
+ * Process struct already enqueued, or actual prio not
+ * equal to user prio, i.e., enqueue using proxy.
+ */
+ return -1;
+ }
+
+ /*
+ * Enqueue using process struct.
+ */
+ *newp &= ~ERTS_PSFLGS_PRQ_PRIO_MASK;
+ *newp |= ERTS_PSFLG_IN_RUNQ | (aprio << ERTS_PSFLGS_PRQ_PRIO_OFFSET);
+ return 1;
+}
+
/*
* scheduler_out_process() return with c_rq locked.
*/
static ERTS_INLINE int
-schedule_out_process(ErtsRunQueue *c_rq, erts_aint32_t state, Process *p)
+schedule_out_process(ErtsRunQueue *c_rq, erts_aint32_t state, Process *p, Process *proxy)
{
- erts_aint32_t a, e, n;
+ erts_aint32_t a, e, n, enq_prio = -1;
int res = 0;
+ int enqueue; /* < 0 -> use proxy */
a = state;
while (1) {
n = e = a;
- ASSERT(a & ERTS_PSFLG_RUNNING);
- ASSERT(!(a & ERTS_PSFLG_IN_RUNQ));
+ ASSERT(a & (ERTS_PSFLG_RUNNING|ERTS_PSFLG_RUNNING_SYS));
- n &= ~ERTS_PSFLG_RUNNING;
- if ((a & (ERTS_PSFLG_ACTIVE|ERTS_PSFLG_SUSPENDED)) == ERTS_PSFLG_ACTIVE)
- n |= ERTS_PSFLG_IN_RUNQ;
+ enqueue = 0;
+
+ n &= ~(ERTS_PSFLG_RUNNING|ERTS_PSFLG_RUNNING_SYS);
+ if (a & ERTS_PSFLG_ACTIVE_SYS
+ || (a & (ERTS_PSFLG_ACTIVE|ERTS_PSFLG_SUSPENDED)) == ERTS_PSFLG_ACTIVE) {
+ enqueue = check_enqueue_in_prio_queue(&enq_prio, &n, a);
+ }
a = erts_smp_atomic32_cmpxchg_mb(&p->state, n, e);
if (a == e)
break;
}
- if (!(n & ERTS_PSFLG_IN_RUNQ)) {
- if (erts_system_profile_flags.runnable_procs)
- profile_runnable_proc(p, am_inactive);
+ if (!enqueue) {
+
+ if (erts_system_profile_flags.runnable_procs) {
+
+ if (!(a & ERTS_PSFLG_ACTIVE_SYS)
+ && (!(a & ERTS_PSFLG_ACTIVE)
+ || (a & ERTS_PSFLG_SUSPENDED))) {
+ /* Process inactive */
+ profile_runnable_proc(p, am_inactive);
+ }
+ }
+
+ if (proxy)
+ free_proxy_proc(proxy);
}
else {
- int prio = (int) (ERTS_PSFLG_PRIO_MASK & n);
+ Process *sched_p;
ErtsRunQueue *runq = erts_get_runq_proc(p);
- ASSERT(!(n & ERTS_PSFLG_SUSPENDED));
+ ASSERT(!(n & ERTS_PSFLG_SUSPENDED) || (n & ERTS_PSFLG_ACTIVE_SYS));
+
+ if (enqueue < 0)
+ sched_p = make_proxy_proc(proxy, p, enq_prio);
+ else {
+ sched_p = p;
+ if (proxy)
+ free_proxy_proc(proxy);
+ }
#ifdef ERTS_SMP
if (!(ERTS_PSFLG_BOUND & n)) {
- ErtsRunQueue *new_runq = erts_check_emigration_need(runq, prio);
+ ErtsRunQueue *new_runq = erts_check_emigration_need(runq, enq_prio);
if (new_runq) {
- RUNQ_SET_RQ(&p->run_queue, new_runq);
+ RUNQ_SET_RQ(&sched_p->run_queue, new_runq);
runq = new_runq;
}
}
@@ -4908,7 +5076,7 @@ schedule_out_process(ErtsRunQueue *c_rq, erts_aint32_t state, Process *p)
erts_smp_runq_lock(runq);
/* Enqueue the process */
- enqueue_process(runq, prio, p);
+ enqueue_process(runq, (int) enq_prio, sched_p);
if (runq == c_rq)
return res;
@@ -4920,14 +5088,13 @@ schedule_out_process(ErtsRunQueue *c_rq, erts_aint32_t state, Process *p)
}
static ERTS_INLINE void
-add2runq(Process *p, erts_aint32_t state)
+add2runq(Process *p, erts_aint32_t state, erts_aint32_t prio)
{
- int prio = (int) (ERTS_PSFLG_PRIO_MASK & state);
ErtsRunQueue *runq = erts_get_runq_proc(p);
#ifdef ERTS_SMP
if (!(ERTS_PSFLG_BOUND & state)) {
- ErtsRunQueue *new_runq = erts_check_emigration_need(runq, prio);
+ ErtsRunQueue *new_runq = erts_check_emigration_need(runq, (int) prio);
if (new_runq) {
RUNQ_SET_RQ(&p->run_queue, new_runq);
runq = new_runq;
@@ -4939,101 +5106,236 @@ add2runq(Process *p, erts_aint32_t state)
erts_smp_runq_lock(runq);
/* Enqueue the process */
- enqueue_process(runq, prio, p);
+ enqueue_process(runq, (int) prio, p);
erts_smp_runq_unlock(runq);
smp_notify_inc_runq(runq);
}
-static ERTS_INLINE void
-schedule_process(Process *p, erts_aint32_t state, int active_enq)
+static ERTS_INLINE int
+change_proc_schedule_state(Process *p,
+ erts_aint32_t clear_state_flags,
+ erts_aint32_t set_state_flags,
+ erts_aint32_t *statep,
+ erts_aint32_t *enq_prio_p)
{
- erts_aint32_t a = state, n;
+ /*
+ * NOTE: ERTS_PSFLG_RUNNING, ERTS_PSFLG_RUNNING_SYS and
+ * ERTS_PSFLG_ACTIVE_SYS are not allowed to be
+ * altered by this function!
+ */
+ erts_aint32_t a = *statep, n;
+ int enqueue; /* < 0 -> use proxy */
+
+ ASSERT(!(a & ERTS_PSFLG_PROXY));
+ ASSERT((clear_state_flags & (ERTS_PSFLG_RUNNING
+ | ERTS_PSFLG_RUNNING_SYS
+ | ERTS_PSFLG_ACTIVE_SYS)) == 0);
+ ASSERT((set_state_flags & (ERTS_PSFLG_RUNNING
+ | ERTS_PSFLG_RUNNING_SYS
+ | ERTS_PSFLG_ACTIVE_SYS)) == 0);
while (1) {
erts_aint32_t e;
n = e = a;
+ enqueue = 0;
+
if (a & ERTS_PSFLG_FREE)
- return; /* We don't want to schedule free processes... */
- n |= ERTS_PSFLG_ACTIVE;
- if (!(a & (ERTS_PSFLG_SUSPENDED|ERTS_PSFLG_RUNNING)))
- n |= ERTS_PSFLG_IN_RUNQ;
+ break; /* We don't want to schedule free processes... */
+
+ if (clear_state_flags)
+ n &= ~clear_state_flags;
+
+ if (set_state_flags)
+ n |= set_state_flags;
+
+ if ((n & (ERTS_PSFLG_SUSPENDED
+ | ERTS_PSFLG_RUNNING
+ | ERTS_PSFLG_RUNNING_SYS
+ | ERTS_PSFLG_IN_RUNQ
+ | ERTS_PSFLG_ACTIVE)) == ERTS_PSFLG_ACTIVE) {
+ /*
+ * Active and seemingly need to be enqueued, but
+ * process may be in a run queue via proxy, need
+ * further inspection...
+ */
+ enqueue = check_enqueue_in_prio_queue(enq_prio_p, &n, a);
+ }
+
a = erts_smp_atomic32_cmpxchg_mb(&p->state, n, e);
if (a == e)
break;
- if (!active_enq && (a & ERTS_PSFLG_ACTIVE))
- return; /* Someone else activated process ... */
+ if (enqueue == 0 && n == a)
+ break;
}
- if (erts_system_profile_flags.runnable_procs
- && !(a & (ERTS_PSFLG_ACTIVE|ERTS_PSFLG_SUSPENDED))) {
- profile_runnable_proc(p, am_active);
+ if (erts_system_profile_flags.runnable_procs) {
+
+ if (((n & (ERTS_PSFLG_SUSPENDED
+ | ERTS_PSFLG_ACTIVE)) == ERTS_PSFLG_ACTIVE)
+ && (!(a & (ERTS_PSFLG_ACTIVE_SYS
+ | ERTS_PSFLG_RUNNING
+ | ERTS_PSFLG_RUNNING_SYS)
+ && (!(a & ERTS_PSFLG_ACTIVE)
+ || (a & ERTS_PSFLG_SUSPENDED))))) {
+ /* We activated a prevously inactive process */
+ profile_runnable_proc(p, am_active);
+ }
+
}
- if ((n & ERTS_PSFLG_IN_RUNQ) && !(a & ERTS_PSFLG_IN_RUNQ))
- add2runq(p, n);
+ *statep = a;
+
+ return enqueue;
+}
+
+static ERTS_INLINE void
+schedule_process(Process *p, erts_aint32_t in_state)
+{
+ erts_aint32_t enq_prio = -1;
+ erts_aint32_t state = in_state;
+ int enqueue = change_proc_schedule_state(p,
+ 0,
+ ERTS_PSFLG_ACTIVE,
+ &state,
+ &enq_prio);
+ if (enqueue)
+ add2runq(enqueue > 0 ? p : make_proxy_proc(NULL, p, enq_prio),
+ state,
+ enq_prio);
}
void
erts_schedule_process(Process *p, erts_aint32_t state)
{
- schedule_process(p, state, 0);
+ schedule_process(p, state);
+}
+
+static void
+schedule_process_sys_task(Process *p, erts_aint32_t state, Process *proxy)
+{
+ erts_aint32_t a = state, n, enq_prio = -1;
+ int enqueue; /* < 0 -> use proxy */
+
+ ASSERT(!(state & ERTS_PSFLG_PROXY));
+
+ while (1) {
+ erts_aint32_t e;
+ n = e = a;
+
+ if (a & ERTS_PSFLG_FREE)
+ return; /* We don't want to schedule free processes... */
+
+ enqueue = 0;
+ n |= ERTS_PSFLG_ACTIVE_SYS;
+ if (!(a & (ERTS_PSFLG_RUNNING|ERTS_PSFLG_RUNNING_SYS)))
+ enqueue = check_enqueue_in_prio_queue(&enq_prio, &n, a);
+ a = erts_smp_atomic32_cmpxchg_mb(&p->state, n, e);
+ if (a == e)
+ break;
+ if (a == n && !enqueue)
+ goto cleanup;
+ }
+
+ if (erts_system_profile_flags.runnable_procs) {
+
+ if (!(a & (ERTS_PSFLG_ACTIVE_SYS
+ | ERTS_PSFLG_RUNNING
+ | ERTS_PSFLG_RUNNING_SYS))
+ && (!(a & ERTS_PSFLG_ACTIVE) || (a & ERTS_PSFLG_SUSPENDED))) {
+ /* We activated a prevously inactive process */
+ profile_runnable_proc(p, am_active);
+ }
+
+ }
+
+ if (enqueue) {
+ Process *sched_p;
+ if (enqueue > 0)
+ sched_p = p;
+ else {
+ sched_p = make_proxy_proc(proxy, p, enq_prio);
+ proxy = NULL;
+ }
+ add2runq(sched_p, n, enq_prio);
+ }
+
+cleanup:
+ if (proxy)
+ free_proxy_proc(proxy);
}
static ERTS_INLINE int
suspend_process(Process *c_p, Process *p)
{
- erts_aint32_t state = erts_smp_atomic32_read_acqb(&p->state);
+ erts_aint32_t state;
int suspended = 0;
ERTS_SMP_LC_ASSERT(ERTS_PROC_LOCK_STATUS & erts_proc_lc_my_proc_locks(p));
+ state = erts_smp_atomic32_read_acqb(&p->state);
+
if ((state & ERTS_PSFLG_SUSPENDED))
suspended = -1;
else {
if (c_p == p) {
state = erts_smp_atomic32_read_bor_relb(&p->state,
ERTS_PSFLG_SUSPENDED);
- state |= ERTS_PSFLG_SUSPENDED;
ASSERT(state & ERTS_PSFLG_RUNNING);
- suspended = 1;
+ suspended = (state & ERTS_PSFLG_SUSPENDED) ? -1: 1;
}
else {
while (!(state & (ERTS_PSFLG_RUNNING|ERTS_PSFLG_EXITING))) {
- erts_aint32_t e, n;
+ erts_aint32_t n, e;
+
n = e = state;
n |= ERTS_PSFLG_SUSPENDED;
state = erts_smp_atomic32_cmpxchg_relb(&p->state, n, e);
if (state == e) {
- state = n;
suspended = 1;
break;
}
+ if (state & ERTS_PSFLG_SUSPENDED) {
+ suspended = -1;
+ break;
+ }
}
}
}
- if (state & ERTS_PSFLG_SUSPENDED) {
+ if (suspended) {
ASSERT(!(ERTS_PSFLG_RUNNING & state)
|| p == erts_get_current_process());
- if (erts_system_profile_flags.runnable_procs
- && (p->rcount == 0)
- && (state & ERTS_PSFLG_ACTIVE)) {
- profile_runnable_proc(p, am_inactive);
+ if (suspended > 0 && erts_system_profile_flags.runnable_procs) {
+
+ /* 'state' is before our change... */
+
+ if ((state & (ERTS_PSFLG_ACTIVE
+ | ERTS_PSFLG_ACTIVE_SYS
+ | ERTS_PSFLG_RUNNING
+ | ERTS_PSFLG_RUNNING_SYS
+ | ERTS_PSFLG_SUSPENDED)) == ERTS_PSFLG_ACTIVE) {
+ /* We made process inactive */
+ profile_runnable_proc(p, am_inactive);
+ }
+
}
p->rcount++; /* count number of suspend */
}
+
return suspended;
}
static ERTS_INLINE void
resume_process(Process *p)
{
- erts_aint32_t state;
+ erts_aint32_t state, enq_prio = -1;
+ int enqueue;
+
ERTS_SMP_LC_ASSERT(ERTS_PROC_LOCK_STATUS & erts_proc_lc_my_proc_locks(p));
ASSERT(p->rcount > 0);
@@ -5041,14 +5343,16 @@ resume_process(Process *p)
if (--p->rcount > 0) /* multiple suspend */
return;
- state = erts_smp_atomic32_read_band_mb(&p->state, ~ERTS_PSFLG_SUSPENDED);
- state &= ~ERTS_PSFLG_SUSPENDED;
- if ((state & (ERTS_PSFLG_EXITING
- | ERTS_PSFLG_ACTIVE
- | ERTS_PSFLG_IN_RUNQ
- | ERTS_PSFLG_RUNNING)) == ERTS_PSFLG_ACTIVE) {
- schedule_process(p, state, 1);
- }
+ state = erts_smp_atomic32_read_nob(&p->state);
+ enqueue = change_proc_schedule_state(p,
+ ERTS_PSFLG_SUSPENDED,
+ 0,
+ &state,
+ &enq_prio);
+ if (enqueue)
+ add2runq(enqueue > 0 ? p : make_proxy_proc(NULL, p, enq_prio),
+ state,
+ enq_prio);
}
int
@@ -6032,7 +6336,8 @@ pid2proc_not_running(Process *c_p, ErtsProcLocks c_p_locks,
goto done;
}
else {
- if (!(ERTS_PSFLG_RUNNING & erts_smp_atomic32_read_acqb(&rp->state)))
+ if (!((ERTS_PSFLG_RUNNING|ERTS_PSFLG_RUNNING_SYS)
+ & erts_smp_atomic32_read_acqb(&rp->state)))
goto done;
}
@@ -6695,7 +7000,7 @@ Eterm
erts_get_process_priority(Process *p)
{
erts_aint32_t state = erts_smp_atomic32_read_nob(&p->state);
- switch (state & ERTS_PSFLG_PRIO_MASK) {
+ switch (ERTS_PSFLGS_GET_USR_PRIO(state)) {
case PRIORITY_MAX: return am_max;
case PRIORITY_HIGH: return am_high;
case PRIORITY_NORMAL: return am_normal;
@@ -6718,18 +7023,68 @@ erts_set_process_priority(Process *p, Eterm value)
}
a = erts_smp_atomic32_read_nob(&p->state);
- if (nprio == (a & ERTS_PSFLG_PRIO_MASK))
+ if (nprio == ERTS_PSFLGS_GET_USR_PRIO(a))
oprio = nprio;
else {
- erts_aint32_t e, n;
+ int slocked = 0;
+ erts_aint32_t e, n, aprio;
+
+ if (a & ERTS_PSFLG_ACTIVE_SYS) {
+ erts_smp_proc_lock(p, ERTS_PROC_LOCK_STATUS);
+ slocked = 1;
+ }
+
do {
- oprio = a & ERTS_PSFLG_PRIO_MASK;
+ oprio = ERTS_PSFLGS_GET_USR_PRIO(a);
n = e = a;
- ASSERT(!(a & ERTS_PSFLG_IN_RUNQ));
+ if (!(a & (ERTS_PSFLG_ACTIVE_SYS|ERTS_PSFLG_DELAYED_SYS)))
+ aprio = nprio;
+ else {
+ int max_qbit;
+
+ if (!slocked) {
+ erts_smp_proc_lock(p, ERTS_PROC_LOCK_STATUS);
+ slocked = 1;
+ }
+
+ max_qbit = 0;
+ if (a & ERTS_PSFLG_ACTIVE_SYS)
+ max_qbit |= p->sys_task_qs->qmask;
+ if (a & ERTS_PSFLG_DELAYED_SYS) {
+ ErtsProcSysTaskQs *qs;
+ qs = ERTS_PROC_GET_DELAYED_GC_TASK_QS(p);
+ ASSERT(qs);
+ max_qbit |= qs->qmask;
+ }
+ max_qbit &= -max_qbit;
+ switch (max_qbit) {
+ case MAX_BIT:
+ aprio = PRIORITY_MAX;
+ break;
+ case HIGH_BIT:
+ aprio = PRIORITY_HIGH;
+ break;
+ case NORMAL_BIT:
+ aprio = PRIORITY_NORMAL;
+ break;
+ case LOW_BIT:
+ aprio = PRIORITY_LOW;
+ break;
+ default:
+ ERTS_INTERNAL_ERROR("Invalid qmask");
+ aprio = -1;
+ }
+
+ if (aprio > nprio) /* low value -> high prio */
+ aprio = nprio;
+ }
+
+ n &= ~(ERTS_PSFLGS_USR_PRIO_MASK
+ | ERTS_PSFLGS_ACT_PRIO_MASK);
+ n |= ((nprio << ERTS_PSFLGS_USR_PRIO_OFFSET)
+ | (aprio << ERTS_PSFLGS_ACT_PRIO_OFFSET));
- n &= ~ERTS_PSFLG_PRIO_MASK;
- n |= nprio;
a = erts_smp_atomic32_cmpxchg_mb(&p->state, n, e);
} while (a != e);
}
@@ -6763,6 +7118,7 @@ erts_set_process_priority(Process *p, Eterm value)
Process *schedule(Process *p, int calls)
{
+ Process *proxy_p = NULL;
ErtsRunQueue *rq;
erts_aint_t dt;
ErtsSchedulerData *esdp;
@@ -6805,6 +7161,8 @@ Process *schedule(Process *p, int calls)
actual_reds = reds = 0;
erts_smp_runq_lock(rq);
} else {
+ sched_out_proc:
+
#ifdef ERTS_SMP
ERTS_SMP_CHK_HAVE_ONLY_MAIN_PROC_LOCK(p);
esdp = p->scheduler_data;
@@ -6858,10 +7216,11 @@ Process *schedule(Process *p, int calls)
esdp->reductions += reds;
- schedule_out_process(rq, state, p); /* Returns with rq locked! */
+ schedule_out_process(rq, state, p, proxy_p); /* Returns with rq locked! */
+ proxy_p = NULL;
ERTS_PROC_REDUCTIONS_EXECUTED(rq,
- (int) (state & ERTS_PSFLG_PRIO_MASK),
+ (int) ERTS_PSFLGS_GET_USR_PRIO(state),
reds,
actual_reds);
@@ -6870,18 +7229,19 @@ Process *schedule(Process *p, int calls)
p->scheduler_data = NULL;
#endif
+ erts_smp_proc_unlock(p, ERTS_PROC_LOCK_MAIN|ERTS_PROC_LOCK_STATUS);
if (state & ERTS_PSFLG_FREE) {
#ifdef ERTS_SMP
ASSERT(esdp->free_process == p);
esdp->free_process = NULL;
-#else
- erts_free_proc(p);
+#else
+ state = erts_smp_atomic32_read_nob(&p->state);
+ if (!(state & ERTS_PSFLG_IN_RUNQ))
+ erts_free_proc(p);
#endif
}
- erts_smp_proc_unlock(p, ERTS_PROC_LOCK_MAIN|ERTS_PROC_LOCK_STATUS);
-
#ifdef ERTS_SMP
ASSERT(!esdp->free_process);
#endif
@@ -7088,6 +7448,8 @@ Process *schedule(Process *p, int calls)
* Find a new process to run.
*/
pick_next_process: {
+ erts_aint32_t psflg_band_mask;
+ erts_aint32_t running_flag;
int prio_q;
int qmask;
@@ -7121,18 +7483,62 @@ Process *schedule(Process *p, int calls)
ASSERT(p); /* Wrong qmask in rq->flags? */
+ psflg_band_mask = ~(((erts_aint32_t) 1) << (ERTS_PSFLGS_GET_PRQ_PRIO(state)
+ + ERTS_PSFLGS_IN_PRQ_MASK_OFFSET));
+
+ if (!(state & ERTS_PSFLG_PROXY))
+ psflg_band_mask &= ~ERTS_PSFLG_IN_RUNQ;
+ else {
+ proxy_p = p;
+ p = erts_proc_lookup_raw(proxy_p->common.id);
+ if (!p) {
+ free_proxy_proc(proxy_p);
+ proxy_p = NULL;
+ goto pick_next_process;
+ }
+ state = erts_smp_atomic32_read_nob(&p->state);
+ }
+
+
+ if (state & ERTS_PSFLG_ACTIVE_SYS)
+ running_flag = ERTS_PSFLG_RUNNING_SYS;
+ else
+ running_flag = ERTS_PSFLG_RUNNING;
+
while (1) {
erts_aint32_t exp, new, tmp;
tmp = new = exp = state;
- new &= ~ERTS_PSFLG_IN_RUNQ;
- tmp = state & (ERTS_PSFLG_SUSPENDED|ERTS_PSFLG_PENDING_EXIT);
- if (tmp != ERTS_PSFLG_SUSPENDED)
- new |= ERTS_PSFLG_RUNNING;
+ new &= psflg_band_mask;
+ if (!(state & (ERTS_PSFLG_RUNNING
+ | ERTS_PSFLG_RUNNING_SYS))) {
+ tmp = state & (ERTS_PSFLG_SUSPENDED
+ | ERTS_PSFLG_PENDING_EXIT
+ | ERTS_PSFLG_ACTIVE_SYS);
+ if (tmp != ERTS_PSFLG_SUSPENDED)
+ new |= running_flag;
+ }
state = erts_smp_atomic32_cmpxchg_relb(&p->state, new, exp);
if (state == exp) {
- tmp = state & (ERTS_PSFLG_SUSPENDED|ERTS_PSFLG_PENDING_EXIT);
- if (tmp == ERTS_PSFLG_SUSPENDED)
+ if ((state & (ERTS_PSFLG_RUNNING
+ | ERTS_PSFLG_RUNNING_SYS
+ | ERTS_PSFLG_FREE))
+ || ((state & (ERTS_PSFLG_SUSPENDED
+ | ERTS_PSFLG_PENDING_EXIT
+ | ERTS_PSFLG_ACTIVE_SYS))
+ == ERTS_PSFLG_SUSPENDED)) {
+ if (state & ERTS_PSFLG_FREE) {
+#ifdef ERTS_SMP
+ erts_smp_proc_dec_refc(p);
+#else
+ erts_free_proc(p);
+#endif
+ }
+ if (proxy_p) {
+ free_proxy_proc(proxy_p);
+ proxy_p = NULL;
+ }
goto pick_next_process;
+ }
state = new;
break;
}
@@ -7162,7 +7568,7 @@ Process *schedule(Process *p, int calls)
(UWord) esdp->no);
int migrated = old && old != esdp->no;
- prio = (int) (state & ERTS_PSFLG_PRIO_MASK);
+ prio = (int) ERTS_PSFLGS_GET_USR_PRIO(state);
erts_smp_spin_lock(&erts_sched_stat.lock);
erts_sched_stat.prio[prio].total_executed++;
@@ -7182,9 +7588,6 @@ Process *schedule(Process *p, int calls)
ASSERT(!p->scheduler_data);
p->scheduler_data = esdp;
#endif
- /* Never run a suspended process */
- ASSERT(!(ERTS_PSFLG_SUSPENDED & erts_smp_atomic32_read_nob(&p->state)));
-
reds = context_reds;
if (IS_TRACED(p)) {
@@ -7210,21 +7613,780 @@ Process *schedule(Process *p, int calls)
erts_check_my_tracer_proc(p);
#endif
+ if (state & ERTS_PSFLG_RUNNING_SYS) {
+ reds -= execute_sys_tasks(p, &state, reds);
+ if (reds <= 0) {
+ p->fcalls = reds;
+ goto sched_out_proc;
+ }
+
+ ASSERT(state & ERTS_PSFLG_RUNNING_SYS);
+ ASSERT(!(state & ERTS_PSFLG_RUNNING));
+
+ while (1) {
+ erts_aint32_t n, e;
+
+ if (((state & (ERTS_PSFLG_SUSPENDED
+ | ERTS_PSFLG_ACTIVE)) != ERTS_PSFLG_ACTIVE)
+ && !(state & ERTS_PSFLG_EXITING))
+ goto sched_out_proc;
+
+ n = e = state;
+ n &= ~ERTS_PSFLG_RUNNING_SYS;
+ n |= ERTS_PSFLG_RUNNING;
+
+ state = erts_smp_atomic32_cmpxchg_mb(&p->state, n, e);
+ if (state == e) {
+ state = n;
+ break;
+ }
+
+ ASSERT(state & ERTS_PSFLG_RUNNING_SYS);
+ ASSERT(!(state & ERTS_PSFLG_RUNNING));
+ }
+ }
+
if (!(state & ERTS_PSFLG_EXITING)
&& ((FLAGS(p) & F_FORCE_GC)
|| (MSO(p).overhead > BIN_VHEAP_SZ(p)))) {
reds -= erts_garbage_collect(p, 0, p->arg_reg, p->arity);
- if (reds < 0) {
- reds = 1;
+ if (reds <= 0) {
+ p->fcalls = reds;
+ goto sched_out_proc;
}
}
+
+ if (proxy_p) {
+ free_proxy_proc(proxy_p);
+ proxy_p = NULL;
+ }
p->fcalls = reds;
ERTS_SMP_CHK_HAVE_ONLY_MAIN_PROC_LOCK(p);
+
+ /* Never run a suspended process */
+ ASSERT(!(ERTS_PSFLG_SUSPENDED & erts_smp_atomic32_read_nob(&p->state)));
+
return p;
}
}
+static int
+notify_sys_task_executed(Process *c_p, ErtsProcSysTask *st, Eterm st_result)
+{
+ Process *rp = erts_proc_lookup(st->requester);
+ if (rp) {
+ ErtsProcLocks rp_locks;
+ ErlOffHeap *ohp;
+ ErlHeapFragment* bp;
+ Eterm *hp, msg, req_id, result;
+ Uint st_result_sz, hsz;
+#ifdef DEBUG
+ Eterm *hp_start;
+#endif
+
+ rp_locks = (c_p == rp) ? ERTS_PROC_LOCK_MAIN : 0;
+
+ st_result_sz = is_immed(st_result) ? 0 : size_object(st_result);
+ hsz = st->req_id_sz + st_result_sz + 4 /* 3-tuple */;
+
+ hp = erts_alloc_message_heap(hsz,
+ &bp,
+ &ohp,
+ rp,
+ &rp_locks);
+
+#ifdef DEBUG
+ hp_start = hp;
+#endif
+
+ req_id = st->req_id_sz == 0 ? st->req_id : copy_struct(st->req_id,
+ st->req_id_sz,
+ &hp,
+ ohp);
+
+ result = st_result_sz == 0 ? st_result : copy_struct(st_result,
+ st_result_sz,
+ &hp,
+ ohp);
+
+ ASSERT(is_immed(st->reply_tag));
+
+ msg = TUPLE3(hp, st->reply_tag, req_id, result);
+
+#ifdef DEBUG
+ hp += 4;
+ ASSERT(hp_start + hsz == hp);
+#endif
+
+ erts_queue_message(rp,
+ &rp_locks,
+ bp,
+ msg,
+ NIL
+#ifdef USE_VM_PROBES
+ , NIL
+#endif
+ );
+
+ if (c_p == rp)
+ rp_locks &= ~ERTS_PROC_LOCK_MAIN;
+
+ if (rp_locks)
+ erts_smp_proc_unlock(rp, rp_locks);
+ }
+
+ erts_cleanup_offheap(&st->off_heap);
+
+ erts_free(ERTS_ALC_T_PROC_SYS_TSK, st);
+
+ return rp ? 1 : 0;
+}
+
+static ERTS_INLINE ErtsProcSysTask *
+fetch_sys_task(Process *c_p, erts_aint32_t state, int *qmaskp, int *priop)
+{
+ ErtsProcSysTaskQs *unused_qs = NULL;
+ int qbit, qmask;
+ ErtsProcSysTask *st, **qp;
+
+ *priop = -1; /* Shut up annoying erroneous warning */
+
+ erts_smp_proc_lock(c_p, ERTS_PROC_LOCK_STATUS);
+
+ if (!c_p->sys_task_qs) {
+ qmask = 0;
+ st = NULL;
+ goto update_state;
+ }
+
+ qmask = c_p->sys_task_qs->qmask;
+
+ if ((state & (ERTS_PSFLG_ACTIVE
+ | ERTS_PSFLG_EXITING
+ | ERTS_PSFLG_SUSPENDED)) == ERTS_PSFLG_ACTIVE) {
+ /* No sys tasks if we got exclusively higher prio user work to do */
+ st = NULL;
+ switch (ERTS_PSFLGS_GET_USR_PRIO(state)) {
+ case PRIORITY_MAX:
+ if (!(qmask & MAX_BIT))
+ goto done;
+ break;
+ case PRIORITY_HIGH:
+ if (!(qmask & (MAX_BIT|HIGH_BIT)))
+ goto done;
+ break;
+ default:
+ break;
+ }
+ }
+
+ qbit = qmask & -qmask;
+ switch (qbit) {
+ case MAX_BIT:
+ qp = &c_p->sys_task_qs->q[PRIORITY_MAX];
+ *priop = PRIORITY_MAX;
+ break;
+ case HIGH_BIT:
+ qp = &c_p->sys_task_qs->q[PRIORITY_HIGH];
+ *priop = PRIORITY_HIGH;
+ break;
+ case NORMAL_BIT:
+ if (!(qmask & PRIORITY_LOW)
+ || ++c_p->sys_task_qs->ncount <= RESCHEDULE_LOW) {
+ qp = &c_p->sys_task_qs->q[PRIORITY_NORMAL];
+ *priop = PRIORITY_NORMAL;
+ break;
+ }
+ c_p->sys_task_qs->ncount = 0;
+ /* Fall through */
+ case LOW_BIT:
+ qp = &c_p->sys_task_qs->q[PRIORITY_LOW];
+ *priop = PRIORITY_LOW;
+ break;
+ default:
+ ERTS_INTERNAL_ERROR("Invalid qmask");
+ }
+
+ st = *qp;
+ ASSERT(st);
+ if (st->next != st) {
+ *qp = st->next;
+ st->next->prev = st->prev;
+ st->prev->next = st->next;
+ }
+ else {
+ erts_aint32_t a, e, n, st_prio, qmask2;
+
+ *qp = NULL;
+ qmask &= ~qbit;
+ c_p->sys_task_qs->qmask = qmask;
+
+ update_state:
+
+ qmask2 = qmask;
+
+ if (state & ERTS_PSFLG_DELAYED_SYS) {
+ ErtsProcSysTaskQs *qs = ERTS_PROC_GET_DELAYED_GC_TASK_QS(c_p);
+ ASSERT(qs);
+ qmask2 |= qs->qmask;
+ }
+
+ switch (qmask2 & -qmask2) {
+ case MAX_BIT:
+ st_prio = PRIORITY_MAX;
+ break;
+ case HIGH_BIT:
+ st_prio = PRIORITY_HIGH;
+ break;
+ case NORMAL_BIT:
+ st_prio = PRIORITY_NORMAL;
+ break;
+ case LOW_BIT:
+ case 0:
+ st_prio = PRIORITY_LOW;
+ break;
+ default:
+ ERTS_INTERNAL_ERROR("Invalid qmask");
+ }
+
+ if (!qmask) {
+ unused_qs = c_p->sys_task_qs;
+ c_p->sys_task_qs = NULL;
+ }
+
+ a = state;
+ do {
+ erts_aint32_t prio = ERTS_PSFLGS_GET_USR_PRIO(a);
+
+ if (prio > st_prio)
+ prio = st_prio;
+
+ n = e = a;
+
+ n &= ~ERTS_PSFLGS_ACT_PRIO_MASK;
+ n |= (prio << ERTS_PSFLGS_ACT_PRIO_OFFSET);
+
+ if (!qmask)
+ n &= ~ERTS_PSFLG_ACTIVE_SYS;
+
+ if (a == n)
+ break;
+ a = erts_smp_atomic32_cmpxchg_nob(&c_p->state, n, e);
+ } while (a != e);
+ }
+
+done:
+
+ erts_smp_proc_unlock(c_p, ERTS_PROC_LOCK_STATUS);
+
+ if (unused_qs)
+ proc_sys_task_queues_free(unused_qs);
+
+ *qmaskp = qmask;
+
+ return st;
+}
+
+static void save_gc_task(Process *c_p, ErtsProcSysTask *st, int prio);
+
+static int
+execute_sys_tasks(Process *c_p, erts_aint32_t *statep, int in_reds)
+{
+ int garbage_collected = 0;
+ erts_aint32_t state = *statep;
+ int max_reds = in_reds;
+ int reds = 0;
+ int qmask = 0;
+
+ ERTS_SMP_LC_ASSERT(erts_proc_lc_my_proc_locks(c_p) == ERTS_PROC_LOCK_MAIN);
+
+ do {
+ ErtsProcSysTask *st;
+ int st_prio;
+ Eterm st_res;
+
+ if (state & (ERTS_PSFLG_EXITING|ERTS_PSFLG_PENDING_EXIT)) {
+#ifdef ERTS_SMP
+ if (state & ERTS_PSFLG_PENDING_EXIT)
+ erts_handle_pending_exit(c_p, ERTS_PROC_LOCK_MAIN);
+#endif
+ ASSERT(ERTS_PROC_IS_EXITING(c_p));
+ break;
+ }
+
+ st = fetch_sys_task(c_p, state, &qmask, &st_prio);
+ if (!st)
+ break;
+
+ switch (st->type) {
+ case ERTS_PSTT_GC:
+ if (c_p->flags & F_DISABLE_GC) {
+ save_gc_task(c_p, st, st_prio);
+ st = NULL;
+ reds++;
+ }
+ else {
+ if (!garbage_collected) {
+ FLAGS(c_p) |= F_NEED_FULLSWEEP;
+ reds += erts_garbage_collect(c_p,
+ 0,
+ c_p->arg_reg,
+ c_p->arity);
+ garbage_collected = 1;
+ }
+ st_res = am_true;
+ }
+ break;
+ case ERTS_PSTT_CPC:
+ st_res = erts_check_process_code(c_p,
+ st->arg[0],
+ st->arg[1] == am_true,
+ &reds);
+ if (is_non_value(st_res)) {
+ /* Needed gc, but gc was disabled */
+ save_gc_task(c_p, st, st_prio);
+ st = NULL;
+ }
+ break;
+ default:
+ ERTS_INTERNAL_ERROR("Invalid process sys task type");
+ st_res = am_false;
+ }
+
+ if (st)
+ reds += notify_sys_task_executed(c_p, st, st_res);
+
+ state = erts_smp_atomic32_read_acqb(&c_p->state);
+ } while (qmask && reds < max_reds);
+
+ *statep = state;
+
+ return reds;
+}
+
+static int
+cleanup_sys_tasks(Process *c_p, erts_aint32_t in_state, int in_reds)
+{
+ erts_aint32_t state = in_state;
+ int max_reds = in_reds;
+ int reds = 0;
+ int qmask = 0;
+
+ ERTS_SMP_LC_ASSERT(erts_proc_lc_my_proc_locks(c_p) == ERTS_PROC_LOCK_MAIN);
+
+ do {
+ ErtsProcSysTask *st;
+ Eterm st_res;
+ int st_prio;
+
+ st = fetch_sys_task(c_p, state, &qmask, &st_prio);
+ if (!st)
+ break;
+
+ switch (st->type) {
+ case ERTS_PSTT_GC:
+ st_res = am_false;
+ break;
+ case ERTS_PSTT_CPC:
+ st_res = am_false;
+ break;
+ default:
+ ERTS_INTERNAL_ERROR("Invalid process sys task type");
+ st_res = am_false;
+ break;
+ }
+
+ reds += notify_sys_task_executed(c_p, st, st_res);
+
+ state = erts_smp_atomic32_read_acqb(&c_p->state);
+ } while (qmask && reds < max_reds);
+
+ return reds;
+}
+
+BIF_RETTYPE
+erts_internal_request_system_task_3(BIF_ALIST_3)
+{
+ Process *rp = erts_proc_lookup(BIF_ARG_1);
+ ErtsProcSysTaskQs *stqs, *free_stqs = NULL;
+ ErtsProcSysTask *st = NULL;
+ erts_aint32_t prio, rp_state;
+ int rp_locked;
+ Eterm noproc_res, req_type;
+
+ if (!rp && !is_internal_pid(BIF_ARG_1)) {
+ if (!is_external_pid(BIF_ARG_1))
+ goto badarg;
+ if (external_pid_dist_entry(BIF_ARG_1) != erts_this_dist_entry)
+ goto badarg;
+ }
+
+ switch (BIF_ARG_2) {
+ case am_max: prio = PRIORITY_MAX; break;
+ case am_high: prio = PRIORITY_HIGH; break;
+ case am_normal: prio = PRIORITY_NORMAL; break;
+ case am_low: prio = PRIORITY_LOW; break;
+ default: goto badarg;
+ }
+
+ if (is_not_tuple(BIF_ARG_3))
+ goto badarg;
+ else {
+ int i;
+ Eterm *tp = tuple_val(BIF_ARG_3);
+ Uint arity = arityval(*tp);
+ Eterm req_id;
+ Uint req_id_sz;
+ Eterm arg[ERTS_MAX_PROC_SYS_TASK_ARGS];
+ Uint arg_sz[ERTS_MAX_PROC_SYS_TASK_ARGS];
+ Uint tot_sz;
+ Eterm *hp;
+
+ if (arity < 2)
+ goto badarg;
+ if (arity > 2 + ERTS_MAX_PROC_SYS_TASK_ARGS)
+ goto badarg;
+ req_type = tp[1];
+ req_id = tp[2];
+ req_id_sz = is_immed(req_id) ? req_id : size_object(req_id);
+ tot_sz = req_id_sz;
+ for (i = 0; i < ERTS_MAX_PROC_SYS_TASK_ARGS; i++) {
+ int tix = 3 + i;
+ if (tix > arity) {
+ arg[i] = THE_NON_VALUE;
+ arg_sz[i] = 0;
+ }
+ else {
+ arg[i] = tp[tix];
+ if (is_immed(arg[i]))
+ arg_sz[i] = 0;
+ else {
+ arg_sz[i] = size_object(arg[i]);
+ tot_sz += arg_sz[i];
+ }
+ }
+ }
+ st = erts_alloc(ERTS_ALC_T_PROC_SYS_TSK,
+ ERTS_PROC_SYS_TASK_SIZE(tot_sz));
+ st->next = st->prev = st; /* Prep for empty prio queue */
+ ERTS_INIT_OFF_HEAP(&st->off_heap);
+ hp = &st->heap[0];
+
+ st->requester = BIF_P->common.id;
+ st->reply_tag = req_type;
+ st->req_id_sz = req_id_sz;
+ st->req_id = req_id_sz == 0 ? req_id : copy_struct(req_id,
+ req_id_sz,
+ &hp,
+ &st->off_heap);
+
+ for (i = 0; i < ERTS_MAX_PROC_SYS_TASK_ARGS; i++)
+ st->arg[i] = arg_sz[i] == 0 ? arg[i] : copy_struct(arg[i],
+ arg_sz[i],
+ &hp,
+ &st->off_heap);
+ ASSERT(&st->heap[0] + tot_sz == hp);
+ }
+
+ switch (req_type) {
+
+ case am_garbage_collect:
+ st->type = ERTS_PSTT_GC;
+ noproc_res = am_false;
+ if (!rp)
+ goto noproc;
+ break;
+
+ case am_check_process_code:
+ if (is_not_atom(st->arg[0]))
+ goto badarg;
+ if (st->arg[1] != am_true && st->arg[1] != am_false)
+ goto badarg;
+ noproc_res = am_false;
+ st->type = ERTS_PSTT_CPC;
+ if (!rp)
+ goto noproc;
+ break;
+
+ default:
+ goto badarg;
+ }
+
+ rp_state = erts_smp_atomic32_read_nob(&rp->state);
+
+ rp_locked = 0;
+
+ free_stqs = NULL;
+ if (rp_state & ERTS_PSFLG_ACTIVE_SYS)
+ stqs = NULL;
+ else {
+ alloc_qs:
+ stqs = proc_sys_task_queues_alloc();
+ stqs->qmask = 1 << prio;
+ stqs->ncount = 0;
+ stqs->q[PRIORITY_MAX] = NULL;
+ stqs->q[PRIORITY_HIGH] = NULL;
+ stqs->q[PRIORITY_NORMAL] = NULL;
+ stqs->q[PRIORITY_LOW] = NULL;
+ stqs->q[prio] = st;
+ }
+
+ if (!rp_locked) {
+ rp_locked = 1;
+ erts_smp_proc_lock(rp, ERTS_PROC_LOCK_STATUS);
+
+ rp_state = erts_smp_atomic32_read_nob(&rp->state);
+ if (rp_state & ERTS_PSFLG_EXITING) {
+ erts_smp_proc_unlock(rp, ERTS_PROC_LOCK_STATUS);
+ rp = NULL;
+ free_stqs = stqs;
+ goto noproc;
+ }
+ }
+
+ if (!rp->sys_task_qs) {
+ if (stqs)
+ rp->sys_task_qs = stqs;
+ else
+ goto alloc_qs;
+ }
+ else {
+ if (stqs)
+ free_stqs = stqs;
+ stqs = rp->sys_task_qs;
+ if (!stqs->q[prio]) {
+ stqs->q[prio] = st;
+ stqs->qmask |= 1 << prio;
+ }
+ else {
+ st->next = stqs->q[prio];
+ st->prev = stqs->q[prio]->prev;
+ st->next->prev = st;
+ st->prev->next = st;
+ ASSERT(stqs->qmask & (1 << prio));
+ }
+ }
+
+ if (ERTS_PSFLGS_GET_ACT_PRIO(rp_state) > prio) {
+ erts_aint32_t n, a, e;
+ /* Need to elevate actual prio */
+
+ a = rp_state;
+ do {
+ if (ERTS_PSFLGS_GET_ACT_PRIO(a) <= prio) {
+ n = a;
+ break;
+ }
+ n = e = a;
+ n &= ~ERTS_PSFLGS_ACT_PRIO_MASK;
+ n |= (prio << ERTS_PSFLGS_ACT_PRIO_OFFSET);
+ a = erts_smp_atomic32_cmpxchg_nob(&rp->state, n, e);
+ } while (a != e);
+ rp_state = n;
+ }
+
+ erts_smp_proc_unlock(rp, ERTS_PROC_LOCK_STATUS);
+
+ schedule_process_sys_task(rp, rp_state, NULL);
+
+ if (free_stqs)
+ proc_sys_task_queues_free(free_stqs);
+
+ BIF_RET(am_ok);
+
+noproc:
+
+ notify_sys_task_executed(BIF_P, st, noproc_res);
+ if (free_stqs)
+ proc_sys_task_queues_free(free_stqs);
+ BIF_RET(am_ok);
+
+badarg:
+
+ if (st) {
+ erts_cleanup_offheap(&st->off_heap);
+ erts_free(ERTS_ALC_T_PROC_SYS_TSK, st);
+ }
+ if (free_stqs)
+ proc_sys_task_queues_free(free_stqs);
+ BIF_ERROR(BIF_P, BADARG);
+}
+
+static void
+save_gc_task(Process *c_p, ErtsProcSysTask *st, int prio)
+{
+ erts_aint32_t state;
+ ErtsProcSysTaskQs *qs;
+
+ ERTS_SMP_LC_ASSERT(ERTS_PROC_LOCK_MAIN == erts_proc_lc_my_proc_locks(c_p));
+
+ qs = ERTS_PROC_GET_DELAYED_GC_TASK_QS(c_p);
+ if (!qs) {
+ st->next = st->prev = st;
+ qs = proc_sys_task_queues_alloc();
+ qs->qmask = 1 << prio;
+ qs->ncount = 0;
+ qs->q[PRIORITY_MAX] = NULL;
+ qs->q[PRIORITY_HIGH] = NULL;
+ qs->q[PRIORITY_NORMAL] = NULL;
+ qs->q[PRIORITY_LOW] = NULL;
+ qs->q[prio] = st;
+ (void) ERTS_PROC_SET_DELAYED_GC_TASK_QS(c_p, ERTS_PROC_LOCK_MAIN, qs);
+ }
+ else {
+ if (!qs->q[prio]) {
+ st->next = st->prev = st;
+ qs->q[prio] = st;
+ qs->qmask |= 1 << prio;
+ }
+ else {
+ st->next = qs->q[prio];
+ st->prev = qs->q[prio]->prev;
+ st->next->prev = st;
+ st->prev->next = st;
+ ASSERT(qs->qmask & (1 << prio));
+ }
+ }
+
+ state = erts_smp_atomic32_read_nob(&c_p->state);
+ ASSERT((ERTS_PSFLG_RUNNING|ERTS_PSFLG_RUNNING_SYS) & state);
+
+ while (!(state & ERTS_PSFLG_DELAYED_SYS)
+ || prio < ERTS_PSFLGS_GET_ACT_PRIO(state)) {
+ erts_aint32_t n, e;
+
+ n = e = state;
+ n |= ERTS_PSFLG_DELAYED_SYS;
+ if (prio < ERTS_PSFLGS_GET_ACT_PRIO(state)) {
+ n &= ~ERTS_PSFLGS_ACT_PRIO_MASK;
+ n |= prio << ERTS_PSFLGS_ACT_PRIO_OFFSET;
+ }
+ state = erts_smp_atomic32_cmpxchg_relb(&c_p->state, n, e);
+ if (state == e)
+ break;
+ }
+}
+
+int
+erts_set_gc_state(Process *c_p, int enable)
+{
+ ErtsProcSysTaskQs *dgc_tsk_qs;
+ ASSERT(c_p == erts_get_current_process());
+ ASSERT((ERTS_PSFLG_RUNNING|ERTS_PSFLG_RUNNING_SYS)
+ & erts_smp_atomic32_read_nob(&c_p->state));
+ ERTS_SMP_LC_ASSERT(ERTS_PROC_LOCK_MAIN == erts_proc_lc_my_proc_locks(c_p));
+
+ if (!enable) {
+ c_p->flags |= F_DISABLE_GC;
+ return 0;
+ }
+
+ c_p->flags &= ~F_DISABLE_GC;
+
+ dgc_tsk_qs = ERTS_PROC_GET_DELAYED_GC_TASK_QS(c_p);
+ if (!dgc_tsk_qs)
+ return 0;
+
+ /* Move delayed gc tasks into sys tasks queues. */
+
+ erts_smp_proc_lock(c_p, ERTS_PROC_LOCK_STATUS);
+
+ if (!c_p->sys_task_qs) {
+ c_p->sys_task_qs = dgc_tsk_qs;
+ dgc_tsk_qs = NULL;
+ }
+ else {
+ ErtsProcSysTaskQs *stsk_qs;
+ int prio;
+
+ /*
+ * We push delayed tasks to the front of the queue
+ * since they have already made it to the front
+ * once and then been delayed after that.
+ */
+
+ stsk_qs = c_p->sys_task_qs;
+
+ while (dgc_tsk_qs->qmask) {
+ int qbit = dgc_tsk_qs->qmask & -dgc_tsk_qs->qmask;
+ dgc_tsk_qs->qmask &= ~qbit;
+ switch (qbit) {
+ case MAX_BIT:
+ prio = PRIORITY_MAX;
+ break;
+ case HIGH_BIT:
+ prio = PRIORITY_HIGH;
+ break;
+ case NORMAL_BIT:
+ prio = PRIORITY_NORMAL;
+ break;
+ case LOW_BIT:
+ prio = PRIORITY_LOW;
+ break;
+ default:
+ ERTS_INTERNAL_ERROR("Invalid qmask");
+ prio = -1;
+ break;
+ }
+
+ ASSERT(dgc_tsk_qs->q[prio]);
+
+ if (!stsk_qs->q[prio]) {
+ stsk_qs->q[prio] = dgc_tsk_qs->q[prio];
+ stsk_qs->qmask |= 1 << prio;
+ }
+ else {
+ ErtsProcSysTask *first1, *last1, *first2, *last2;
+
+ ASSERT(stsk_qs->qmask & (1 << prio));
+ first1 = dgc_tsk_qs->q[prio];
+ last1 = first1->prev;
+ first2 = stsk_qs->q[prio];
+ last2 = first1->prev;
+
+ last1->next = first2;
+ first2->prev = last1;
+
+ first1->prev = last2;
+ last2->next = first1;
+
+ stsk_qs->q[prio] = first1;
+ }
+
+ }
+ }
+
+#ifdef DEBUG
+ {
+ int qmask;
+ erts_aint32_t aprio, state =
+#endif
+
+ erts_smp_atomic32_read_bset_nob(&c_p->state,
+ (ERTS_PSFLG_DELAYED_SYS
+ | ERTS_PSFLG_ACTIVE_SYS),
+ ERTS_PSFLG_ACTIVE_SYS);
+
+#ifdef DEBUG
+ ASSERT(state & ERTS_PSFLG_DELAYED_SYS);
+ qmask = c_p->sys_task_qs->qmask;
+ aprio = ERTS_PSFLGS_GET_ACT_PRIO(state);
+ ASSERT(ERTS_PSFLGS_GET_USR_PRIO(state) >= aprio);
+ ASSERT((qmask & -qmask) >= (1 << aprio));
+ }
+#endif
+
+ erts_smp_proc_unlock(c_p, ERTS_PROC_LOCK_STATUS);
+
+ (void) ERTS_PROC_SET_DELAYED_GC_TASK_QS(c_p, ERTS_PROC_LOCK_MAIN, NULL);
+
+ if (dgc_tsk_qs)
+ proc_sys_task_queues_free(dgc_tsk_qs);
+
+ return 1;
+}
+
void
erts_sched_stat_modify(int what)
{
@@ -7521,7 +8683,8 @@ erl_create_process(Process* parent, /* Parent of process (default group leader).
prio = (erts_aint32_t) so->priority;
}
- state |= (prio & ERTS_PSFLG_PRIO_MASK);
+ state |= (((prio & ERTS_PSFLGS_PRIO_MASK) << ERTS_PSFLGS_ACT_PRIO_OFFSET)
+ | ((prio & ERTS_PSFLGS_PRIO_MASK) << ERTS_PSFLGS_USR_PRIO_OFFSET));
if (!rq)
rq = erts_get_runq_proc(parent);
@@ -7599,6 +8762,8 @@ erl_create_process(Process* parent, /* Parent of process (default group leader).
p->bin_old_vheap = 0;
p->bin_vheap_mature = 0;
+ p->sys_task_qs = NULL;
+
/* No need to initialize p->fcalls. */
p->current = p->initial+INITIAL_MOD;
@@ -7764,7 +8929,7 @@ erl_create_process(Process* parent, /* Parent of process (default group leader).
* Schedule process for execution.
*/
- schedule_process(p, state, 0);
+ schedule_process(p, state);
VERBOSE(DEBUG_PROCESSES, ("Created a new process: %T\n",p->common.id));
@@ -7815,6 +8980,7 @@ void erts_init_empty_process(Process *p)
p->bin_vheap_sz = BIN_VH_MIN_SIZE;
p->bin_old_vheap_sz = BIN_VH_MIN_SIZE;
p->bin_old_vheap = 0;
+ p->sys_task_qs = NULL;
p->bin_vheap_mature = 0;
#ifdef ERTS_SMP
p->common.u.alive.ptimer = NULL;
@@ -8070,33 +9236,21 @@ delete_process(Process* p)
p->fvalue = NIL;
}
-static ERTS_INLINE erts_aint32_t
-set_proc_exiting_state(Process *p, erts_aint32_t state)
-{
- erts_aint32_t a, n, e;
- a = state;
- while (1) {
- n = e = a;
- n &= ~(ERTS_PSFLG_SUSPENDED|ERTS_PSFLG_PENDING_EXIT);
- n |= ERTS_PSFLG_EXITING|ERTS_PSFLG_ACTIVE;
- if (!(a & (ERTS_PSFLG_IN_RUNQ|ERTS_PSFLG_RUNNING)))
- n |= ERTS_PSFLG_IN_RUNQ;
- a = erts_smp_atomic32_cmpxchg_relb(&p->state, n, e);
- if (a == e)
- break;
- }
- return a;
-}
-
static ERTS_INLINE void
set_proc_exiting(Process *p,
- erts_aint32_t state,
+ erts_aint32_t in_state,
Eterm reason,
ErlHeapFragment *bp)
{
+ erts_aint32_t state = in_state, enq_prio = -1;
+ int enqueue;
ERTS_SMP_LC_ASSERT(erts_proc_lc_my_proc_locks(p) == ERTS_PROC_LOCKS_ALL);
- state = set_proc_exiting_state(p, state);
+ enqueue = change_proc_schedule_state(p,
+ ERTS_PSFLG_SUSPENDED|ERTS_PSFLG_PENDING_EXIT,
+ ERTS_PSFLG_EXITING|ERTS_PSFLG_ACTIVE,
+ &state,
+ &enq_prio);
p->fvalue = reason;
if (bp)
@@ -8111,15 +9265,37 @@ set_proc_exiting(Process *p,
cancel_timer(p);
p->i = (BeamInstr *) beam_exit;
- if (erts_system_profile_flags.runnable_procs
- && !(state & (ERTS_PSFLG_ACTIVE|ERTS_PSFLG_SUSPENDED))) {
- profile_runnable_proc(p, am_active);
- }
-
- if (!(state & (ERTS_PSFLG_IN_RUNQ|ERTS_PSFLG_RUNNING)))
- add2runq(p, state);
+ if (enqueue)
+ add2runq(enqueue > 0 ? p : make_proxy_proc(NULL, p, enq_prio),
+ state,
+ enq_prio);
}
+static ERTS_INLINE erts_aint32_t
+set_proc_self_exiting(Process *c_p)
+{
+#ifdef DEBUG
+ int enqueue;
+#endif
+ erts_aint32_t state, enq_prio = -1;
+
+ ERTS_SMP_LC_ASSERT(erts_proc_lc_my_proc_locks(c_p) == ERTS_PROC_LOCKS_ALL);
+
+ state = erts_smp_atomic32_read_nob(&c_p->state);
+ ASSERT(state & (ERTS_PSFLG_RUNNING|ERTS_PSFLG_RUNNING_SYS));
+
+#ifdef DEBUG
+ enqueue =
+#endif
+ change_proc_schedule_state(c_p,
+ ERTS_PSFLG_SUSPENDED|ERTS_PSFLG_PENDING_EXIT,
+ ERTS_PSFLG_EXITING|ERTS_PSFLG_ACTIVE,
+ &state,
+ &enq_prio);
+
+ ASSERT(!enqueue);
+ return state;
+}
#ifdef ERTS_SMP
@@ -8167,7 +9343,7 @@ handle_pending_exiters(ErtsProcList *pnd_xtrs)
if (p) {
if (erts_proclist_same(plp, p)) {
erts_aint32_t state = erts_smp_atomic32_read_acqb(&p->state);
- if (!(state & ERTS_PSFLG_RUNNING)) {
+ if (!(state & (ERTS_PSFLG_RUNNING|ERTS_PSFLG_RUNNING_SYS))) {
ASSERT(state & ERTS_PSFLG_PENDING_EXIT);
erts_handle_pending_exit(p, ERTS_PROC_LOCKS_ALL);
}
@@ -8388,7 +9564,7 @@ send_exit_signal(Process *c_p, /* current process if and only
}
set_proc_exiting(c_p, state, rsn, NULL);
}
- else if (!(state & ERTS_PSFLG_RUNNING)) {
+ else if (!(state & (ERTS_PSFLG_RUNNING|ERTS_PSFLG_RUNNING_SYS))) {
/* Process not running ... */
ErtsProcLocks need_locks = ~(*rp_locks) & ERTS_PROC_LOCKS_ALL;
if (need_locks
@@ -8765,9 +9941,6 @@ resume_suspend_monitor(ErtsSuspendMonitor *smon, void *vc_p)
void
erts_do_exit_process(Process* p, Eterm reason)
{
-#ifdef ERTS_SMP
- erts_aint32_t state;
-#endif
p->arity = 0; /* No live registers */
p->fvalue = reason;
@@ -8792,10 +9965,9 @@ erts_do_exit_process(Process* p, Eterm reason)
#endif
#ifndef ERTS_SMP
- set_proc_exiting_state(p, erts_smp_atomic32_read_nob(&p->state));
+ set_proc_self_exiting(p);
#else
- state = set_proc_exiting_state(p, erts_smp_atomic32_read_nob(&p->state));
- if (state & ERTS_PSFLG_PENDING_EXIT) {
+ if (ERTS_PSFLG_PENDING_EXIT & set_proc_self_exiting(p)) {
/* Process exited before pending exit was received... */
p->pending_exit.reason = THE_NON_VALUE;
if (p->pending_exit.bp) {
@@ -8849,6 +10021,7 @@ erts_continue_exit_process(Process *p)
DistEntry *dep;
struct saved_calls *scb;
process_breakpoint_time_t *pbt;
+ erts_aint32_t state;
#ifdef DEBUG
int yield_allowed = 1;
@@ -8885,6 +10058,13 @@ erts_continue_exit_process(Process *p)
p->flags &= ~F_USING_DB;
}
+ erts_set_gc_state(p, 1);
+ state = erts_smp_atomic32_read_acqb(&p->state);
+ if (state & ERTS_PSFLG_ACTIVE_SYS) {
+ if (cleanup_sys_tasks(p, state, CONTEXT_REDS) >= CONTEXT_REDS/2)
+ goto yield;
+ }
+
if (p->flags & F_USING_DDLL) {
erts_ddll_proc_dead(p, ERTS_PROC_LOCK_MAIN);
p->flags &= ~F_USING_DDLL;
@@ -8962,17 +10142,31 @@ erts_continue_exit_process(Process *p)
{
/* Inactivate and notify free */
erts_aint32_t n, e, a = erts_smp_atomic32_read_nob(&p->state);
+#ifdef ERTS_SMP
+ int refc_inced = 0;
+#endif
while (1) {
n = e = a;
ASSERT(a & ERTS_PSFLG_EXITING);
n |= ERTS_PSFLG_FREE;
n &= ~ERTS_PSFLG_ACTIVE;
+#ifdef ERTS_SMP
+ if ((n & ERTS_PSFLG_IN_RUNQ) && !refc_inced) {
+ erts_smp_proc_inc_refc(p);
+ refc_inced = 1;
+ }
+#endif
a = erts_smp_atomic32_cmpxchg_mb(&p->state, n, e);
if (a == e)
break;
}
- }
+#ifdef ERTS_SMP
+ if (refc_inced && !(n & ERTS_PSFLG_IN_RUNQ))
+ erts_smp_proc_dec_refc(p);
+#endif
+ }
+
dep = ((p->flags & F_DISTRIBUTION)
? ERTS_PROC_SET_DIST_ENTRY(p, ERTS_PROC_LOCKS_ALL, NULL)
: NULL);
@@ -9075,7 +10269,7 @@ timeout_proc(Process* p)
state = erts_smp_atomic32_read_acqb(&p->state);
if (!(state & ERTS_PSFLG_ACTIVE))
- schedule_process(p, state, 0);
+ schedule_process(p, state);
}
@@ -9153,7 +10347,9 @@ erts_program_counter_info(int to, void *to_arg, Process *p)
print_function_from_pc(to, to_arg, p->cp);
erts_print(to, to_arg, ")\n");
state = erts_smp_atomic32_read_acqb(&p->state);
- if (!(state & (ERTS_PSFLG_RUNNING|ERTS_PSFLG_GC))) {
+ if (!(state & (ERTS_PSFLG_RUNNING
+ | ERTS_PSFLG_RUNNING_SYS
+ | ERTS_PSFLG_GC))) {
erts_print(to, to_arg, "arity = %d\n",p->arity);
if (!ERTS_IS_CRASH_DUMPING) {
/*
diff --git a/erts/emulator/beam/erl_process.h b/erts/emulator/beam/erl_process.h
index 8d136f6e8b..043621125c 100644
--- a/erts/emulator/beam/erl_process.h
+++ b/erts/emulator/beam/erl_process.h
@@ -631,8 +631,9 @@ erts_smp_reset_max_len(ErtsRunQueue *rq, ErtsRunQueueInfo *rqi)
#define ERTS_PSD_SCHED_ID 2
#define ERTS_PSD_DIST_ENTRY 3
#define ERTS_PSD_CALL_TIME_BP 4
+#define ERTS_PSD_DELAYED_GC_TASK_QS 5
-#define ERTS_PSD_SIZE 5
+#define ERTS_PSD_SIZE 6
typedef struct {
void *data[ERTS_PSD_SIZE];
@@ -656,6 +657,9 @@ typedef struct {
#define ERTS_PSD_CALL_TIME_BP_GET_LOCKS ERTS_PROC_LOCK_MAIN
#define ERTS_PSD_CALL_TIME_BP_SET_LOCKS ERTS_PROC_LOCK_MAIN
+#define ERTS_PSD_DELAYED_GC_TASK_QS_GET_LOCKS ERTS_PROC_LOCK_MAIN
+#define ERTS_PSD_DELAYED_GC_TASK_QS_SET_LOCKS ERTS_PROC_LOCK_MAIN
+
typedef struct {
ErtsProcLocks get_locks;
ErtsProcLocks set_locks;
@@ -688,6 +692,9 @@ typedef struct {
ErlHeapFragment *bp;
} ErtsPendExit;
+typedef struct ErtsProcSysTask_ ErtsProcSysTask;
+typedef struct ErtsProcSysTaskQs_ ErtsProcSysTaskQs;
+
#ifdef ERTS_SMP
typedef struct ErtsPendingSuspend_ ErtsPendingSuspend;
@@ -855,6 +862,8 @@ struct process {
Uint64 bin_old_vheap_sz; /* Virtual old heap block size for binaries */
Uint64 bin_old_vheap; /* Virtual old heap size for binaries */
+ ErtsProcSysTaskQs *sys_task_qs;
+
erts_smp_atomic32_t state; /* Process state flags (see ERTS_PSFLG_*) */
#ifdef ERTS_SMP
@@ -924,24 +933,67 @@ void erts_check_for_holes(Process* p);
# error "Need to increase ERTS_PSFLG_PRIO_SHIFT"
#endif
-#define ERTS_PSFLG_PRIO_SHIFT 2
+#define ERTS_PSFLGS_PRIO_BITS 2
+#define ERTS_PSFLGS_PRIO_MASK \
+ ((((erts_aint32_t) 1) << ERTS_PSFLGS_PRIO_BITS) - 1)
-#define ERTS_PSFLG_BIT(N) \
- (((erts_aint32_t) 1) << (ERTS_PSFLG_PRIO_SHIFT + (N)))
+#define ERTS_PSFLGS_ACT_PRIO_OFFSET (0*ERTS_PSFLGS_PRIO_BITS)
+#define ERTS_PSFLGS_USR_PRIO_OFFSET (1*ERTS_PSFLGS_PRIO_BITS)
+#define ERTS_PSFLGS_PRQ_PRIO_OFFSET (2*ERTS_PSFLGS_PRIO_BITS)
+#define ERTS_PSFLGS_ZERO_BIT_OFFSET (3*ERTS_PSFLGS_PRIO_BITS)
-#define ERTS_PSFLG_PRIO_MASK (ERTS_PSFLG_BIT(0) - 1)
+#define ERTS_PSFLGS_QMASK_BITS 4
+#define ERTS_PSFLGS_QMASK \
+ ((((erts_aint32_t) 1) << ERTS_PSFLGS_QMASK_BITS) - 1)
+#define ERTS_PSFLGS_IN_PRQ_MASK_OFFSET \
+ ERTS_PSFLGS_ZERO_BIT_OFFSET
-#define ERTS_PSFLG_FREE ERTS_PSFLG_BIT(0)
-#define ERTS_PSFLG_EXITING ERTS_PSFLG_BIT(1)
-#define ERTS_PSFLG_PENDING_EXIT ERTS_PSFLG_BIT(2)
-#define ERTS_PSFLG_ACTIVE ERTS_PSFLG_BIT(3)
-#define ERTS_PSFLG_IN_RUNQ ERTS_PSFLG_BIT(4)
-#define ERTS_PSFLG_RUNNING ERTS_PSFLG_BIT(5)
-#define ERTS_PSFLG_SUSPENDED ERTS_PSFLG_BIT(6)
-#define ERTS_PSFLG_GC ERTS_PSFLG_BIT(7)
-#define ERTS_PSFLG_BOUND ERTS_PSFLG_BIT(8)
-#define ERTS_PSFLG_TRAP_EXIT ERTS_PSFLG_BIT(9)
+#define ERTS_PSFLG_BIT(N) \
+ (((erts_aint32_t) 1) << (ERTS_PSFLGS_ZERO_BIT_OFFSET + (N)))
+/*
+ * ACT_PRIO -> Active prio, i.e., currently active prio. This
+ * prio may be higher than user prio.
+ * USR_PRIO -> User prio. i.e., prio the user has set.
+ * PRQ_PRIO -> Prio queue prio, i.e., prio queue currently
+ * enqueued in.
+ */
+#define ERTS_PSFLGS_ACT_PRIO_MASK \
+ (ERTS_PSFLGS_PRIO_MASK << ERTS_PSFLGS_ACT_PRIO_OFFSET)
+#define ERTS_PSFLGS_USR_PRIO_MASK \
+ (ERTS_PSFLGS_PRIO_MASK << ERTS_PSFLGS_USR_PRIO_OFFSET)
+#define ERTS_PSFLGS_PRQ_PRIO_MASK \
+ (ERTS_PSFLGS_PRIO_MASK << ERTS_PSFLGS_PRQ_PRIO_OFFSET)
+#define ERTS_PSFLG_IN_PRQ_MAX ERTS_PSFLG_BIT(0)
+#define ERTS_PSFLG_IN_PRQ_HIGH ERTS_PSFLG_BIT(1)
+#define ERTS_PSFLG_IN_PRQ_NORMAL ERTS_PSFLG_BIT(2)
+#define ERTS_PSFLG_IN_PRQ_LOW ERTS_PSFLG_BIT(3)
+#define ERTS_PSFLG_FREE ERTS_PSFLG_BIT(4)
+#define ERTS_PSFLG_EXITING ERTS_PSFLG_BIT(5)
+#define ERTS_PSFLG_PENDING_EXIT ERTS_PSFLG_BIT(6)
+#define ERTS_PSFLG_ACTIVE ERTS_PSFLG_BIT(7)
+#define ERTS_PSFLG_IN_RUNQ ERTS_PSFLG_BIT(8)
+#define ERTS_PSFLG_RUNNING ERTS_PSFLG_BIT(9)
+#define ERTS_PSFLG_SUSPENDED ERTS_PSFLG_BIT(10)
+#define ERTS_PSFLG_GC ERTS_PSFLG_BIT(11)
+#define ERTS_PSFLG_BOUND ERTS_PSFLG_BIT(12)
+#define ERTS_PSFLG_TRAP_EXIT ERTS_PSFLG_BIT(13)
+#define ERTS_PSFLG_ACTIVE_SYS ERTS_PSFLG_BIT(14)
+#define ERTS_PSFLG_RUNNING_SYS ERTS_PSFLG_BIT(15)
+#define ERTS_PSFLG_PROXY ERTS_PSFLG_BIT(16)
+#define ERTS_PSFLG_DELAYED_SYS ERTS_PSFLG_BIT(17)
+
+#define ERTS_PSFLGS_IN_PRQ_MASK (ERTS_PSFLG_IN_PRQ_MAX \
+ | ERTS_PSFLG_IN_PRQ_HIGH \
+ | ERTS_PSFLG_IN_PRQ_NORMAL \
+ | ERTS_PSFLG_IN_PRQ_LOW)
+
+#define ERTS_PSFLGS_GET_ACT_PRIO(PSFLGS) \
+ (((PSFLGS) >> ERTS_PSFLGS_ACT_PRIO_OFFSET) & ERTS_PSFLGS_PRIO_MASK)
+#define ERTS_PSFLGS_GET_USR_PRIO(PSFLGS) \
+ (((PSFLGS) >> ERTS_PSFLGS_USR_PRIO_OFFSET) & ERTS_PSFLGS_PRIO_MASK)
+#define ERTS_PSFLGS_GET_PRQ_PRIO(PSFLGS) \
+ (((PSFLGS) >> ERTS_PSFLGS_USR_PRIO_OFFSET) & ERTS_PSFLGS_PRIO_MASK)
/* The sequential tracing token is a tuple of size 5:
*
@@ -1056,6 +1108,7 @@ extern struct erts_system_profile_flags_t erts_system_profile_flags;
#define F_HAVE_BLCKD_MSCHED (1 << 8) /* Process has blocked multi-scheduling */
#define F_P2PNR_RESCHED (1 << 9) /* Process has been rescheduled via erts_pid2proc_not_running() */
#define F_FORCE_GC (1 << 10) /* Force gc at process in-scheduling */
+#define F_DISABLE_GC (1 << 11) /* Disable GC */
/* process trace_flags */
#define F_SENSITIVE (1 << 0)
@@ -1146,6 +1199,7 @@ void erts_late_init_process(void);
void erts_early_init_scheduling(int);
void erts_init_scheduling(int, int);
+int erts_set_gc_state(Process *c_p, int enable);
Eterm erts_sched_wall_time_request(Process *c_p, int set, int enable);
Eterm erts_gc_info_request(Process *c_p);
Uint64 erts_get_proc_interval(void);
@@ -1591,6 +1645,11 @@ erts_psd_set(Process *p, ErtsProcLocks plocks, int ix, void *data)
#define ERTS_PROC_SET_CALL_TIME(P, L, PBT) \
((process_breakpoint_time_t *) erts_psd_set((P), (L), ERTS_PSD_CALL_TIME_BP, (void *) (PBT)))
+#define ERTS_PROC_GET_DELAYED_GC_TASK_QS(P) \
+ ((ErtsProcSysTaskQs *) erts_psd_get((P), ERTS_PSD_DELAYED_GC_TASK_QS))
+#define ERTS_PROC_SET_DELAYED_GC_TASK_QS(P, L, PBT) \
+ ((ErtsProcSysTaskQs *) erts_psd_set((P), (L), ERTS_PSD_DELAYED_GC_TASK_QS, (void *) (PBT)))
+
ERTS_GLB_INLINE Eterm erts_proc_get_error_handler(Process *p);
ERTS_GLB_INLINE Eterm erts_proc_set_error_handler(Process *p,
diff --git a/erts/emulator/beam/erl_process_dump.c b/erts/emulator/beam/erl_process_dump.c
index 6cd0d23b97..2f3cf23b00 100644
--- a/erts/emulator/beam/erl_process_dump.c
+++ b/erts/emulator/beam/erl_process_dump.c
@@ -34,8 +34,8 @@
#define ERTS_WANT_EXTERNAL_TAGS
#include "external.h"
-#define WORD_FMT "%X"
-#define ADDR_FMT "%X"
+#define PTR_FMT "%bpX"
+#define ETERM_FMT "%beX"
#define OUR_NIL _make_header(0,_TAG_HEADER_FLOAT)
@@ -210,9 +210,9 @@ static void
dump_element(int to, void *to_arg, Eterm x)
{
if (is_list(x)) {
- erts_print(to, to_arg, "H" WORD_FMT, list_val(x));
+ erts_print(to, to_arg, "H" PTR_FMT, list_val(x));
} else if (is_boxed(x)) {
- erts_print(to, to_arg, "H" WORD_FMT, boxed_val(x));
+ erts_print(to, to_arg, "H" PTR_FMT, boxed_val(x));
} else if (is_immed(x)) {
if (is_atom(x)) {
unsigned char* s = atom_tab(atom_val(x))->name;
@@ -311,7 +311,7 @@ heap_dump(int to, void *to_arg, Eterm x)
} else if (is_list(x)) {
ptr = list_val(x);
if (ptr[0] != OUR_NIL) {
- erts_print(to, to_arg, ADDR_FMT ":l", ptr);
+ erts_print(to, to_arg, PTR_FMT ":l", ptr);
dump_element(to, to_arg, ptr[0]);
erts_putc(to, to_arg, '|');
dump_element(to, to_arg, ptr[1]);
@@ -330,12 +330,12 @@ heap_dump(int to, void *to_arg, Eterm x)
ptr = boxed_val(x);
hdr = *ptr;
if (hdr != OUR_NIL) { /* If not visited */
- erts_print(to, to_arg, ADDR_FMT ":", ptr);
+ erts_print(to, to_arg, PTR_FMT ":", ptr);
if (is_arity_value(hdr)) {
Uint i;
Uint arity = arityval(hdr);
- erts_print(to, to_arg, "t" WORD_FMT ":", arity);
+ erts_print(to, to_arg, "t" ETERM_FMT ":", arity);
for (i = 1; i <= arity; i++) {
dump_element(to, to_arg, ptr[i]);
if (is_immed(ptr[i])) {
@@ -388,21 +388,43 @@ heap_dump(int to, void *to_arg, Eterm x)
val->flags = (UWord) all_binaries;
all_binaries = val;
}
- erts_print(to, to_arg, "Yc%X:%X:%X", 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(x);
- Eterm* real_bin = binary_val(Sb->orig);
+ Eterm* real_bin;
void* val;
+ /*
+ * Must use boxed_val() here, because the original
+ * binary may have been visited and have had its
+ * header word changed to OUR_NIL (in which case
+ * binary_val() will cause an assertion failure in
+ * the DEBUG emulator).
+ */
+
+ 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 */
+ } 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%X:%X:%X", val, Sb->offs, size);
+ erts_print(to, to_arg,
+ "Ys" PTR_FMT ":" PTR_FMT ":" PTR_FMT,
+ val, Sb->offs, size);
}
erts_putc(to, to_arg, '\n');
*ptr = OUR_NIL;
@@ -438,7 +460,7 @@ dump_binaries(int to, void *to_arg, Binary* current)
long size = current->orig_size;
byte* bytes = (byte*) current->orig_bytes;
- erts_print(to, to_arg, "=binary:%X\n", current);
+ 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]);
diff --git a/erts/emulator/beam/erl_zlib.c b/erts/emulator/beam/erl_zlib.c
index 47fd92988e..8e33144f96 100644
--- a/erts/emulator/beam/erl_zlib.c
+++ b/erts/emulator/beam/erl_zlib.c
@@ -87,6 +87,46 @@ int ZEXPORT erl_zlib_deflate_finish(z_stream *streamp)
return deflateEnd(streamp);
}
+int ZEXPORT erl_zlib_inflate_start(z_stream *streamp, const Bytef* source,
+ uLong sourceLen)
+{
+ streamp->next_in = (Bytef*)source;
+ streamp->avail_in = (uInt)sourceLen;
+ streamp->total_out = streamp->avail_out = 0;
+ streamp->next_out = NULL;
+ erl_zlib_alloc_init(streamp);
+ return inflateInit(streamp);
+}
+/*
+ * Inflate a chunk, The destination length is the limit.
+ * Returns Z_OK if more to process, Z_STREAM_END if we are done.
+ */
+int ZEXPORT erl_zlib_inflate_chunk(z_stream *streamp, Bytef* dest, uLongf* destLen)
+{
+ int err;
+ uLongf last_tot = streamp->total_out;
+
+ streamp->next_out = dest;
+ streamp->avail_out = (uInt)*destLen;
+
+ if ((uLong)streamp->avail_out != *destLen) return Z_BUF_ERROR;
+
+ err = inflate(streamp, Z_NO_FLUSH);
+ ASSERT(err != Z_STREAM_ERROR);
+ *destLen = streamp->total_out - last_tot;
+ return err;
+}
+
+/*
+ * When we are done, free up the inflate structure
+ * Retyurns Z_OK or Error
+ */
+int ZEXPORT erl_zlib_inflate_finish(z_stream *streamp)
+{
+ return inflateEnd(streamp);
+}
+
+
int ZEXPORT erl_zlib_compress2 (Bytef* dest, uLongf* destLen,
const Bytef* source, uLong sourceLen,
int level)
diff --git a/erts/emulator/beam/erl_zlib.h b/erts/emulator/beam/erl_zlib.h
index 5ac849d21c..160166c66b 100644
--- a/erts/emulator/beam/erl_zlib.h
+++ b/erts/emulator/beam/erl_zlib.h
@@ -39,6 +39,12 @@ int ZEXPORT erl_zlib_deflate_start(z_stream *streamp, const Bytef* source,
int ZEXPORT erl_zlib_deflate_chunk(z_stream *streamp, Bytef* dest, uLongf* destLen);
int ZEXPORT erl_zlib_deflate_finish(z_stream *streamp);
+int ZEXPORT erl_zlib_inflate_start(z_stream *streamp, const Bytef* source,
+ uLong sourceLen);
+int ZEXPORT erl_zlib_inflate_chunk(z_stream *streamp, Bytef* dest, uLongf* destLen);
+int ZEXPORT erl_zlib_inflate_finish(z_stream *streamp);
+
+
/* Use instead of compress
*/
#define erl_zlib_compress(dest,destLen,source,sourceLen) \
diff --git a/erts/emulator/beam/external.c b/erts/emulator/beam/external.c
index 1c88765381..2cb44a5b64 100644
--- a/erts/emulator/beam/external.c
+++ b/erts/emulator/beam/external.c
@@ -61,6 +61,9 @@
*/
# define ERTS_DEBUG_USE_DIST_SEP
# endif
+# define IF_DEBUG(X) X
+#else
+# define IF_DEBUG(X)
#endif
/* Does Sint fit in Sint32?
@@ -89,10 +92,11 @@ static int enc_term_int(Process *p,ErtsAtomCacheMap *acmp, Eterm obj, byte* ep,
static Uint is_external_string(Eterm obj, int* p_is_string);
static byte* enc_atom(ErtsAtomCacheMap *, Eterm, byte*, Uint32);
static byte* enc_pid(ErtsAtomCacheMap *, Eterm, byte*, Uint32);
-static byte* dec_term(ErtsDistExternal *, Eterm**, byte*, ErlOffHeap*, Eterm*);
+struct B2TContext_t;
+static byte* dec_term(ErtsDistExternal *, Eterm**, byte*, ErlOffHeap*, Eterm*, struct B2TContext_t*);
static byte* dec_atom(ErtsDistExternal *, byte*, Eterm*);
static byte* dec_pid(ErtsDistExternal *, Eterm**, byte*, ErlOffHeap*, Eterm*);
-static Sint decoded_size(byte *ep, byte* endp, int internal_tags);
+static Sint decoded_size(byte *ep, byte* endp, int internal_tags, struct B2TContext_t*);
static BIF_RETTYPE term_to_binary_trap_1(BIF_ALIST_1);
static Eterm erts_term_to_binary_int(Process* p, Eterm Term, int level, Uint flags,
@@ -102,11 +106,19 @@ static Uint encode_size_struct2(ErtsAtomCacheMap *, Eterm, unsigned);
static int encode_size_struct_int(Process *p, ErtsAtomCacheMap *acmp, Eterm obj,
unsigned dflags, Sint *reds, Uint *res);
+static Export binary_to_term_trap_export;
+static BIF_RETTYPE binary_to_term_trap_1(BIF_ALIST_1);
+static Eterm binary_to_term_int(Process* p, Uint32 flags, Eterm bin, Binary* context_b);
+
void erts_init_external(void) {
#if 1 /* In R16 */
erts_init_trap_export(&term_to_binary_trap_export,
am_erlang, am_term_to_binary_trap, 1,
&term_to_binary_trap_1);
+
+ erts_init_trap_export(&binary_to_term_trap_export,
+ am_erlang, am_binary_to_term_trap, 1,
+ &binary_to_term_trap_1);
#else
sys_memset((void *) &term_to_binary_trap_export, 0, sizeof(Export));
term_to_binary_trap_export.address = &term_to_binary_trap_export.code[3];
@@ -877,7 +889,7 @@ erts_decode_dist_ext_size(ErtsDistExternal *edep)
goto fail;
ep = edep->extp+1;
}
- res = decoded_size(ep, edep->ext_endp, 0);
+ res = decoded_size(ep, edep->ext_endp, 0, NULL);
if (res >= 0)
return res;
fail:
@@ -889,12 +901,12 @@ Sint erts_decode_ext_size(byte *ext, Uint size)
{
if (size == 0 || *ext != VERSION_MAGIC)
return -1;
- return decoded_size(ext+1, ext+size, 0);
+ return decoded_size(ext+1, ext+size, 0, NULL);
}
Sint erts_decode_ext_size_ets(byte *ext, Uint size)
{
- Sint sz = decoded_size(ext, ext+size, 1);
+ Sint sz = decoded_size(ext, ext+size, 1, NULL);
ASSERT(sz >= 0);
return sz;
}
@@ -927,7 +939,7 @@ erts_decode_dist_ext(Eterm** hpp,
goto error;
ep++;
}
- ep = dec_term(edep, hpp, ep, off_heap, &obj);
+ ep = dec_term(edep, hpp, ep, off_heap, &obj, NULL);
if (!ep)
goto error;
@@ -948,7 +960,7 @@ Eterm erts_decode_ext(Eterm **hpp, ErlOffHeap *off_heap, byte **ext)
byte *ep = *ext;
if (*ep++ != VERSION_MAGIC)
return THE_NON_VALUE;
- ep = dec_term(NULL, hpp, ep, off_heap, &obj);
+ ep = dec_term(NULL, hpp, ep, off_heap, &obj, NULL);
if (!ep) {
#ifdef DEBUG
bin_write(ERTS_PRINT_STDERR,NULL,*ext,500);
@@ -962,7 +974,7 @@ Eterm erts_decode_ext(Eterm **hpp, ErlOffHeap *off_heap, byte **ext)
Eterm erts_decode_ext_ets(Eterm **hpp, ErlOffHeap *off_heap, byte *ext)
{
Eterm obj;
- ext = dec_term(NULL, hpp, ext, off_heap, &obj);
+ ext = dec_term(NULL, hpp, ext, off_heap, &obj, NULL);
ASSERT(ext);
return obj;
}
@@ -1043,9 +1055,14 @@ static BIF_RETTYPE term_to_binary_trap_1(BIF_ALIST_1)
Binary *bin = ((ProcBin *) binary_val(bt))->val;
Eterm res = erts_term_to_binary_int(BIF_P, Term, 0, 0,bin);
if (is_tuple(res)) {
+ ASSERT(BIF_P->flags & F_DISABLE_GC);
BIF_TRAP1(&term_to_binary_trap_export,BIF_P,res);
} else {
- BIF_RET(res);
+ if (erts_set_gc_state(BIF_P, 1)
+ || MSO(BIF_P).overhead > BIN_VHEAP_SZ(BIF_P))
+ ERTS_BIF_YIELD_RETURN(BIF_P, res);
+ else
+ BIF_RET(res);
}
}
@@ -1053,8 +1070,10 @@ BIF_RETTYPE term_to_binary_1(BIF_ALIST_1)
{
Eterm res = erts_term_to_binary_int(BIF_P, BIF_ARG_1, 0, TERM_TO_BINARY_DFLAGS, NULL);
if (is_tuple(res)) {
+ erts_set_gc_state(BIF_P, 0);
BIF_TRAP1(&term_to_binary_trap_export,BIF_P,res);
} else {
+ ASSERT(!(BIF_P->flags & F_DISABLE_GC));
BIF_RET(res);
}
}
@@ -1106,12 +1125,72 @@ BIF_RETTYPE term_to_binary_2(BIF_ALIST_2)
res = erts_term_to_binary_int(p, Term, level, flags, bin);
if (is_tuple(res)) {
+ erts_set_gc_state(p, 0);
BIF_TRAP1(&term_to_binary_trap_export,BIF_P,res);
} else {
+ ASSERT(!(BIF_P->flags & F_DISABLE_GC));
BIF_RET(res);
}
}
+
+enum B2TState { /* order is somewhat significant */
+ B2TPrepare,
+ B2TUncompressChunk,
+ B2TSizeInit,
+ B2TSize,
+ B2TDecodeInit,
+ B2TDecode,
+ B2TDecodeList,
+ B2TDecodeTuple,
+ B2TDecodeString,
+ B2TDecodeBinary,
+
+ B2TDone,
+ B2TDecodeFail,
+ B2TBadArg
+};
+
+typedef struct {
+ int heap_size;
+ int terms;
+ byte* ep;
+ int atom_extra_skip;
+} B2TSizeContext;
+
+typedef struct {
+ byte* ep;
+ Eterm res;
+ Eterm* next;
+ Eterm* hp_start;
+ Eterm* hp;
+ Eterm* hp_end;
+ int remaining_n;
+ char* remaining_bytes;
+} B2TDecodeContext;
+
+typedef struct {
+ z_stream stream;
+ byte* dbytes;
+ Uint dleft;
+} B2TUncompressContext;
+
+typedef struct B2TContext_t {
+ Sint heap_size;
+ byte* aligned_alloc;
+ ErtsBinary2TermState b2ts;
+ Uint32 flags;
+ SWord reds;
+ Eterm trap_bin;
+ enum B2TState state;
+ union {
+ B2TSizeContext sc;
+ B2TDecodeContext dc;
+ B2TUncompressContext uc;
+ } u;
+} B2TContext;
+
+
static uLongf binary2term_uncomp_size(byte* data, Sint size)
{
z_stream stream;
@@ -1141,48 +1220,62 @@ static uLongf binary2term_uncomp_size(byte* data, Sint size)
return err == Z_STREAM_END ? uncomp_size : 0;
}
-static ERTS_INLINE Sint
-binary2term_prepare(ErtsBinary2TermState *state, byte *data, Sint data_size)
+static ERTS_INLINE int
+binary2term_prepare(ErtsBinary2TermState *state, byte *data, Sint data_size,
+ B2TContext* ctx)
{
- Sint res;
byte *bytes = data;
Sint size = data_size;
state->exttmp = 0;
if (size < 1 || *bytes != VERSION_MAGIC) {
- error:
- if (state->exttmp)
- erts_free(ERTS_ALC_T_TMP, state->extp);
- state->extp = NULL;
- state->exttmp = 0;
return -1;
}
bytes++;
size--;
if (size < 5 || *bytes != COMPRESSED) {
state->extp = bytes;
+ if (ctx)
+ ctx->state = B2TSizeInit;
}
else {
uLongf dest_len = (Uint32) get_int32(bytes+1);
bytes += 5;
size -= 5;
if (dest_len > 32*1024*1024
- || (state->extp = erts_alloc_fnf(ERTS_ALC_T_TMP, dest_len)) == NULL) {
+ || (state->extp = erts_alloc_fnf(ERTS_ALC_T_EXT_TERM_DATA, dest_len)) == NULL) {
+ /*
+ * Try avoid out-of-memory crash due to corrupted 'dest_len'
+ * by checking the actual length of the uncompressed data.
+ * The only way to do that is to uncompress it. Sad but true.
+ */
if (dest_len != binary2term_uncomp_size(bytes, size)) {
- goto error;
+ return -1;
}
- state->extp = erts_alloc(ERTS_ALC_T_TMP, dest_len);
+ state->extp = erts_alloc(ERTS_ALC_T_EXT_TERM_DATA, dest_len);
+ ctx->reds -= dest_len;
}
state->exttmp = 1;
- if (erl_zlib_uncompress(state->extp, &dest_len, bytes, size) != Z_OK)
- goto error;
+ if (ctx) {
+ if (erl_zlib_inflate_start(&ctx->u.uc.stream, bytes, size) != Z_OK)
+ return -1;
+
+ ctx->u.uc.dbytes = state->extp;
+ ctx->u.uc.dleft = dest_len;
+ ctx->state = B2TUncompressChunk;
+ }
+ else {
+ uLongf dlen = dest_len;
+ if (erl_zlib_uncompress(state->extp, &dlen, bytes, size) != Z_OK
+ || dlen != dest_len) {
+ return -1;
+ }
+ }
size = (Sint) dest_len;
}
- res = decoded_size(state->extp, state->extp + size, 0);
- if (res < 0)
- goto error;
- return res;
+ state->extsize = size;
+ return 0;
}
static ERTS_INLINE void
@@ -1190,7 +1283,7 @@ binary2term_abort(ErtsBinary2TermState *state)
{
if (state->exttmp) {
state->exttmp = 0;
- erts_free(ERTS_ALC_T_TMP, state->extp);
+ erts_free(ERTS_ALC_T_EXT_TERM_DATA, state->extp);
}
}
@@ -1198,11 +1291,11 @@ static ERTS_INLINE Eterm
binary2term_create(ErtsDistExternal *edep, ErtsBinary2TermState *state, Eterm **hpp, ErlOffHeap *ohp)
{
Eterm res;
- if (!dec_term(edep, hpp, state->extp, ohp, &res))
+ if (!dec_term(edep, hpp, state->extp, ohp, &res, NULL))
res = THE_NON_VALUE;
if (state->exttmp) {
state->exttmp = 0;
- erts_free(ERTS_ALC_T_TMP, state->extp);
+ erts_free(ERTS_ALC_T_EXT_TERM_DATA, state->extp);
}
return res;
}
@@ -1210,7 +1303,18 @@ binary2term_create(ErtsDistExternal *edep, ErtsBinary2TermState *state, Eterm **
Sint
erts_binary2term_prepare(ErtsBinary2TermState *state, byte *data, Sint data_size)
{
- return binary2term_prepare(state, data, data_size);
+ Sint res;
+
+ if (binary2term_prepare(state, data, data_size, NULL) < 0 ||
+ (res=decoded_size(state->extp, state->extp + state->extsize, 0, NULL)) < 0) {
+
+ if (state->exttmp)
+ erts_free(ERTS_ALC_T_EXT_TERM_DATA, state->extp);
+ state->extp = NULL;
+ state->exttmp = 0;
+ return -1;
+ }
+ return res;
}
void
@@ -1225,68 +1329,233 @@ erts_binary2term_create(ErtsBinary2TermState *state, Eterm **hpp, ErlOffHeap *oh
return binary2term_create(NULL,state, hpp, ohp);
}
-BIF_RETTYPE binary_to_term_1(BIF_ALIST_1)
+static void b2t_destroy_context(B2TContext* context)
{
- Sint heap_size;
- Eterm res;
+ erts_free_aligned_binary_bytes_extra(context->aligned_alloc,
+ ERTS_ALC_T_EXT_TERM_DATA);
+ context->aligned_alloc = NULL;
+ binary2term_abort(&context->b2ts);
+ if (context->state == B2TUncompressChunk) {
+ erl_zlib_inflate_finish(&context->u.uc.stream);
+ }
+}
+
+static void b2t_context_destructor(Binary *context_bin)
+{
+ B2TContext* ctx = (B2TContext*) ERTS_MAGIC_BIN_DATA(context_bin);
+ ASSERT(ERTS_MAGIC_BIN_DESTRUCTOR(context_bin) == b2t_context_destructor);
+
+ b2t_destroy_context(ctx);
+}
+
+static BIF_RETTYPE binary_to_term_trap_1(BIF_ALIST_1)
+{
+ Binary *context_bin = ((ProcBin *) binary_val(BIF_ARG_1))->val;
+ ASSERT(ERTS_MAGIC_BIN_DESTRUCTOR(context_bin) == b2t_context_destructor);
+
+ return binary_to_term_int(BIF_P, 0, THE_NON_VALUE, context_bin);
+}
+
+
+#define B2T_BYTES_PER_REDUCTION 128
+#define B2T_MEMCPY_FACTOR 8
+
+/* Define for testing */
+/*#define EXTREME_B2T_TRAPPING 1*/
+
+#ifdef EXTREME_B2T_TRAPPING
+static unsigned b2t_rand(void)
+{
+ static unsigned prev = 17;
+ prev = (prev * 214013 + 2531011);
+ return prev;
+}
+#endif
+
+
+static B2TContext* b2t_export_context(Process* p, B2TContext* src)
+{
+ Binary* context_b = erts_create_magic_binary(sizeof(B2TContext),
+ b2t_context_destructor);
+ B2TContext* ctx = ERTS_MAGIC_BIN_DATA(context_b);
Eterm* hp;
- Eterm* endp;
- Sint size;
- byte* bytes;
- byte* temp_alloc = NULL;
- ErtsBinary2TermState b2ts;
+ sys_memcpy(ctx, src, sizeof(B2TContext));
+ if (ctx->state >= B2TDecode && ctx->u.dc.next == &src->u.dc.res) {
+ ctx->u.dc.next = &ctx->u.dc.res;
+ }
+ hp = HAlloc(p, PROC_BIN_SIZE);
+ ctx->trap_bin = erts_mk_magic_binary_term(&hp, &MSO(p), context_b);
+ return ctx;
+}
- if ((bytes = erts_get_aligned_binary_bytes(BIF_ARG_1, &temp_alloc)) == NULL) {
- error:
- erts_free_aligned_binary_bytes(temp_alloc);
- BIF_ERROR(BIF_P, BADARG);
+static Eterm binary_to_term_int(Process* p, Uint32 flags, Eterm bin, Binary* context_b)
+{
+#ifdef EXTREME_B2T_TRAPPING
+ SWord initial_reds = 1 + b2t_rand() % 4;
+#else
+ SWord initial_reds = (Uint)(ERTS_BIF_REDS_LEFT(p) * B2T_BYTES_PER_REDUCTION);
+#endif
+ B2TContext c_buff;
+ B2TContext *ctx;
+ int is_first_call;
+
+ if (context_b == NULL) {
+ /* Setup enough to get started */
+ is_first_call = 1;
+ ctx = &c_buff;
+ ctx->state = B2TPrepare;
+ ctx->aligned_alloc = NULL;
+ ctx->flags = flags;
+ IF_DEBUG(ctx->trap_bin = THE_NON_VALUE;)
+ } else {
+ is_first_call = 0;
+ ctx = ERTS_MAGIC_BIN_DATA(context_b);
+ ASSERT(ctx->state != B2TPrepare);
}
- size = binary_size(BIF_ARG_1);
+ ctx->reds = initial_reds;
+
+ do {
+ switch (ctx->state) {
+ case B2TPrepare: {
+ byte* bytes;
+ Uint bin_size;
+ bytes = erts_get_aligned_binary_bytes_extra(bin,
+ &ctx->aligned_alloc,
+ ERTS_ALC_T_EXT_TERM_DATA,
+ 0);
+ if (bytes == NULL) {
+ ctx->b2ts.exttmp = 0;
+ ctx->state = B2TBadArg;
+ break;
+ }
+ bin_size = binary_size(bin);
+ if (ctx->aligned_alloc) {
+ ctx->reds -= bin_size / 8;
+ }
+ if (binary2term_prepare(&ctx->b2ts, bytes, bin_size, ctx) < 0) {
+ ctx->state = B2TBadArg;
+ }
+ break;
+ }
+ case B2TUncompressChunk: {
+ uLongf chunk = ctx->reds;
+ int zret;
+
+ if (chunk > ctx->u.uc.dleft)
+ chunk = ctx->u.uc.dleft;
+ zret = erl_zlib_inflate_chunk(&ctx->u.uc.stream,
+ ctx->u.uc.dbytes, &chunk);
+ ctx->u.uc.dbytes += chunk;
+ ctx->u.uc.dleft -= chunk;
+ if (zret == Z_OK && ctx->u.uc.dleft > 0) {
+ ctx->reds = 0;
+ }
+ else if (erl_zlib_inflate_finish(&ctx->u.uc.stream) == Z_OK
+ && zret == Z_STREAM_END
+ && ctx->u.uc.dleft == 0) {
+ ctx->reds -= chunk;
+ ctx->state = B2TSizeInit;
+ }
+ else {
+ ctx->state = B2TBadArg;
+ }
+ break;
+ }
+ case B2TSizeInit:
+ ctx->u.sc.ep = NULL;
+ ctx->state = B2TSize;
+ /*fall through*/
+ case B2TSize:
+ ctx->heap_size = decoded_size(ctx->b2ts.extp,
+ ctx->b2ts.extp + ctx->b2ts.extsize,
+ 0, ctx);
+ break;
+
+ case B2TDecodeInit:
+ if (ctx == &c_buff && ctx->b2ts.extsize > ctx->reds) {
+ /* dec_term will maybe trap, allocate space for magic bin
+ before result term to make it easy to trim with HRelease.
+ */
+ ctx = b2t_export_context(p, &c_buff);
+ }
+ ctx->u.dc.ep = ctx->b2ts.extp;
+ ctx->u.dc.res = (Eterm) (UWord) NULL;
+ ctx->u.dc.next = &ctx->u.dc.res;
+ ctx->u.dc.hp_start = HAlloc(p, ctx->heap_size);
+ ctx->u.dc.hp = ctx->u.dc.hp_start;
+ ctx->u.dc.hp_end = ctx->u.dc.hp_start + ctx->heap_size;
+ ctx->state = B2TDecode;
+ /*fall through*/
+ case B2TDecode:
+ case B2TDecodeList:
+ case B2TDecodeTuple:
+ case B2TDecodeString:
+ case B2TDecodeBinary: {
+ ErtsDistExternal fakedep;
+ fakedep.flags = ctx->flags;
+ dec_term(&fakedep, NULL, NULL, &MSO(p), NULL, ctx);
+ break;
+ }
+ case B2TDecodeFail:
+ HRelease(p, ctx->u.dc.hp_end, ctx->u.dc.hp_start);
+ /*fall through*/
+ case B2TBadArg:
+ b2t_destroy_context(ctx);
+ if (!is_first_call) {
+ erts_set_gc_state(p, 1);
+ }
+ BUMP_REDS(p, (initial_reds - ctx->reds) / B2T_BYTES_PER_REDUCTION);
+ BIF_ERROR(p, BADARG & ~EXF_SAVETRACE);
- heap_size = binary2term_prepare(&b2ts, bytes, size);
- if (heap_size < 0)
- goto error;
+ case B2TDone:
+ b2t_destroy_context(ctx);
- hp = HAlloc(BIF_P, heap_size);
- endp = hp + heap_size;
+ if (ctx->u.dc.hp > ctx->u.dc.hp_end) {
+ erl_exit(1, ":%s, line %d: heap overrun by %d words(s)\n",
+ __FILE__, __LINE__, ctx->u.dc.hp - ctx->u.dc.hp_end);
+ }
+ HRelease(p, ctx->u.dc.hp_end, ctx->u.dc.hp);
- res = binary2term_create(NULL, &b2ts, &hp, &MSO(BIF_P));
+ if (!is_first_call) {
+ erts_set_gc_state(p, 1);
+ }
+ BUMP_REDS(p, (initial_reds - ctx->reds) / B2T_BYTES_PER_REDUCTION);
+ return ctx->u.dc.res;
- erts_free_aligned_binary_bytes(temp_alloc);
+ default:
+ ASSERT(!"Unknown state in binary_to_term");
+ }
+ }while (ctx->reds > 0 || ctx->state >= B2TDone);
- if (hp > endp) {
- erl_exit(1, ":%s, line %d: heap overrun by %d words(s)\n",
- __FILE__, __LINE__, hp-endp);
+ if (ctx == &c_buff) {
+ ASSERT(ctx->trap_bin == THE_NON_VALUE);
+ ctx = b2t_export_context(p, &c_buff);
}
+ ASSERT(ctx->trap_bin != THE_NON_VALUE);
- HRelease(BIF_P, endp, hp);
-
- if (res == THE_NON_VALUE)
- goto error;
+ if (is_first_call) {
+ erts_set_gc_state(p, 0);
+ }
+ BUMP_ALL_REDS(p);
+ BIF_TRAP1(&binary_to_term_trap_export, p, ctx->trap_bin);
+}
- return res;
+BIF_RETTYPE erts_internal_binary_to_term_1(BIF_ALIST_1)
+{
+ return binary_to_term_int(BIF_P, 0, BIF_ARG_1, NULL);
}
-BIF_RETTYPE binary_to_term_2(BIF_ALIST_2)
+BIF_RETTYPE erts_internal_binary_to_term_2(BIF_ALIST_2)
{
- Sint heap_size;
- Eterm res;
Eterm opts;
Eterm opt;
- Eterm* hp;
- Eterm* endp;
- Sint size;
- byte* bytes;
- byte* temp_alloc = NULL;
- ErtsBinary2TermState b2ts;
- ErtsDistExternal fakedep;
+ Uint32 flags = 0;
- fakedep.flags = 0;
opts = BIF_ARG_2;
while (is_list(opts)) {
opt = CAR(list_val(opts));
if (opt == am_safe) {
- fakedep.flags |= ERTS_DIST_EXT_BTT_SAFE;
+ flags |= ERTS_DIST_EXT_BTT_SAFE;
}
else {
goto error;
@@ -1297,35 +1566,10 @@ BIF_RETTYPE binary_to_term_2(BIF_ALIST_2)
if (is_not_nil(opts))
goto error;
- if ((bytes = erts_get_aligned_binary_bytes(BIF_ARG_1, &temp_alloc)) == NULL) {
- error:
- erts_free_aligned_binary_bytes(temp_alloc);
- BIF_ERROR(BIF_P, BADARG);
- }
- size = binary_size(BIF_ARG_1);
-
- heap_size = binary2term_prepare(&b2ts, bytes, size);
- if (heap_size < 0)
- goto error;
-
- hp = HAlloc(BIF_P, heap_size);
- endp = hp + heap_size;
-
- res = binary2term_create(&fakedep, &b2ts, &hp, &MSO(BIF_P));
-
- erts_free_aligned_binary_bytes(temp_alloc);
-
- if (hp > endp) {
- erl_exit(1, ":%s, line %d: heap overrun by %d words(s)\n",
- __FILE__, __LINE__, hp-endp);
- }
-
- HRelease(BIF_P, endp, hp);
+ return binary_to_term_int(BIF_P, flags, BIF_ARG_1, NULL);
- if (res == THE_NON_VALUE)
- goto error;
-
- return res;
+error:
+ BIF_ERROR(BIF_P, BADARG);
}
Eterm
@@ -1473,12 +1717,10 @@ erts_term_to_binary(Process* p, Eterm Term, int level, Uint flags) {
/* #define EXTREME_TTB_TRAPPING 1 */
#ifndef EXTREME_TTB_TRAPPING
-#define TERM_TO_BINARY_LOOP_FACTOR 500
-#define TERM_TO_BINARY_SIZE_FACTOR 500000
-#define TERM_TO_BINARY_COMPRESS_CHUNK 500000
+#define TERM_TO_BINARY_LOOP_FACTOR 32
+#define TERM_TO_BINARY_COMPRESS_CHUNK (1 << 18)
#else
#define TERM_TO_BINARY_LOOP_FACTOR 1
-#define TERM_TO_BINARY_SIZE_FACTOR 10
#define TERM_TO_BINARY_COMPRESS_CHUNK 10
#endif
@@ -1514,7 +1756,7 @@ typedef struct {
} s;
} TTBContext;
-static void context_destructor(Binary *context_bin)
+static void ttb_context_destructor(Binary *context_bin)
{
TTBContext *context = ERTS_MAGIC_BIN_DATA(context_bin);
if (context->alive) {
@@ -1567,7 +1809,7 @@ static Eterm erts_term_to_binary_int(Process* p, Eterm Term, int level, Uint fla
do { \
if (context_b == NULL) { \
context_b = erts_create_magic_binary(sizeof(TTBContext), \
- context_destructor); \
+ ttb_context_destructor); \
context = ERTS_MAGIC_BIN_DATA(context_b); \
memcpy(context,&c_buff,sizeof(TTBContext)); \
} \
@@ -1615,7 +1857,7 @@ static Eterm erts_term_to_binary_int(Process* p, Eterm Term, int level, Uint fla
/* Finish in one go */
res = erts_term_to_binary_simple(p, Term, size,
level, flags);
- BUMP_REDS(p, size / TERM_TO_BINARY_SIZE_FACTOR);
+ BUMP_REDS(p, 1);
return res;
}
@@ -2604,21 +2846,112 @@ undo_offheap_in_area(ErlOffHeap* off_heap, Eterm* start, Eterm* end)
#endif /* DEBUG */
}
+
/* Decode term from external format into *objp.
** On failure return NULL and (R13B04) *hpp will be unchanged.
*/
static byte*
-dec_term(ErtsDistExternal *edep, Eterm** hpp, byte* ep, ErlOffHeap* off_heap, Eterm* objp)
+dec_term(ErtsDistExternal *edep, Eterm** hpp, byte* ep, ErlOffHeap* off_heap,
+ Eterm* objp, B2TContext* ctx)
{
- Eterm* hp_saved = *hpp;
+ Eterm* hp_saved;
int n;
ErtsAtomEncoding char_enc;
- register Eterm* hp = *hpp; /* Please don't take the address of hp */
- Eterm* next = objp;
+ register Eterm* hp; /* Please don't take the address of hp */
+ Eterm* next;
+ SWord reds;
+
+ if (ctx) {
+ hp_saved = ctx->u.dc.hp_start;
+ reds = ctx->reds;
+ next = ctx->u.dc.next;
+ ep = ctx->u.dc.ep;
+ hpp = &ctx->u.dc.hp;
+
+ if (ctx->state != B2TDecode) {
+ int n_limit = reds;
+
+ n = ctx->u.dc.remaining_n;
+ if (ctx->state == B2TDecodeBinary) {
+ n_limit *= B2T_MEMCPY_FACTOR;
+ ASSERT(n_limit >= reds);
+ reds -= n / B2T_MEMCPY_FACTOR;
+ }
+ else
+ reds -= n;
+
+ if (n > n_limit) {
+ ctx->u.dc.remaining_n -= n_limit;
+ n = n_limit;
+ reds = 0;
+ }
+ else {
+ ctx->u.dc.remaining_n = 0;
+ }
- *next = (Eterm) (UWord) NULL;
+ switch (ctx->state) {
+ case B2TDecodeList:
+ objp = next - 2;
+ while (n > 0) {
+ objp[0] = (Eterm) COMPRESS_POINTER(next);
+ objp[1] = make_list(next);
+ next = objp;
+ objp -= 2;
+ n--;
+ }
+ break;
+
+ case B2TDecodeTuple:
+ objp = next - 1;
+ while (n-- > 0) {
+ objp[0] = (Eterm) COMPRESS_POINTER(next);
+ next = objp;
+ objp--;
+ }
+ break;
+
+ case B2TDecodeString:
+ hp = *hpp;
+ hp[-1] = make_list(hp); /* overwrite the premature NIL */
+ while (n-- > 0) {
+ hp[0] = make_small(*ep++);
+ hp[1] = make_list(hp+2);
+ hp += 2;
+ }
+ hp[-1] = NIL;
+ *hpp = hp;
+ break;
+
+ case B2TDecodeBinary:
+ sys_memcpy(ctx->u.dc.remaining_bytes, ep, n);
+ ctx->u.dc.remaining_bytes += n;
+ ep += n;
+ break;
+
+ default:
+ ASSERT(!"Unknown state");
+ }
+ if (!ctx->u.dc.remaining_n) {
+ ctx->state = B2TDecode;
+ }
+ if (reds <= 0) {
+ ctx->u.dc.next = next;
+ ctx->u.dc.ep = ep;
+ ctx->reds = 0;
+ return NULL;
+ }
+ }
+ }
+ else {
+ hp_saved = *hpp;
+ reds = ERTS_SWORD_MAX;
+ next = objp;
+ *next = (Eterm) (UWord) NULL;
+ }
+ hp = *hpp;
while (next != NULL) {
+
objp = next;
next = (Eterm *) EXPAND_POINTER(*objp);
@@ -2738,7 +3071,16 @@ dec_term_atom_common:
*objp = make_tuple(hp);
*hp++ = make_arityval(n);
hp += n;
- objp = hp - 1;
+ objp = hp - 1;
+ if (ctx) {
+ if (reds < n) {
+ ASSERT(reds > 0);
+ ctx->state = B2TDecodeTuple;
+ ctx->u.dc.remaining_n = n - reds;
+ n = reds;
+ }
+ reds -= n;
+ }
while (n-- > 0) {
objp[0] = (Eterm) COMPRESS_POINTER(next);
next = objp;
@@ -2756,17 +3098,27 @@ dec_term_atom_common:
break;
}
*objp = make_list(hp);
- hp += 2*n;
+ hp += 2 * n;
objp = hp - 2;
objp[0] = (Eterm) COMPRESS_POINTER((objp+1));
objp[1] = (Eterm) COMPRESS_POINTER(next);
next = objp;
objp -= 2;
- while (--n > 0) {
+ n--;
+ if (ctx) {
+ if (reds < n) {
+ ctx->state = B2TDecodeList;
+ ctx->u.dc.remaining_n = n - reds;
+ n = reds;
+ }
+ reds -= n;
+ }
+ while (n > 0) {
objp[0] = (Eterm) COMPRESS_POINTER(next);
- objp[1] = make_list(objp + 2);
+ objp[1] = make_list(next);
next = objp;
objp -= 2;
+ n--;
}
break;
case STRING_EXT:
@@ -2777,6 +3129,14 @@ dec_term_atom_common:
break;
}
*objp = make_list(hp);
+ if (ctx) {
+ if (reds < n) {
+ ctx->state = B2TDecodeString;
+ ctx->u.dc.remaining_n = n - reds;
+ n = reds;
+ }
+ reds -= n;
+ }
while (n-- > 0) {
hp[0] = make_small(*ep++);
hp[1] = make_list(hp+2);
@@ -2970,7 +3330,7 @@ dec_term_atom_common:
n = get_int32(ep);
ep += 4;
- if (n <= ERL_ONHEAP_BIN_LIMIT) {
+ if ((unsigned)n <= ERL_ONHEAP_BIN_LIMIT) {
ErlHeapBin* hb = (ErlHeapBin *) hp;
hb->thing_word = header_heap_bin(n);
@@ -2984,7 +3344,6 @@ dec_term_atom_common:
dbin->flags = 0;
dbin->orig_size = n;
erts_refc_init(&dbin->refc, 1);
- sys_memcpy(dbin->orig_bytes, ep, n);
pb = (ProcBin *) hp;
hp += PROC_BIN_SIZE;
pb->thing_word = HEADER_PROC_BIN;
@@ -2995,7 +3354,20 @@ dec_term_atom_common:
pb->bytes = (byte*) dbin->orig_bytes;
pb->flags = 0;
*objp = make_binary(pb);
- }
+ if (ctx) {
+ int n_limit = reds * B2T_MEMCPY_FACTOR;
+ if (n > n_limit) {
+ ctx->state = B2TDecodeBinary;
+ ctx->u.dc.remaining_n = n - n_limit;
+ ctx->u.dc.remaining_bytes = dbin->orig_bytes + n_limit;
+ n = n_limit;
+ reds = 0;
+ }
+ else
+ reds -= n / B2T_MEMCPY_FACTOR;
+ }
+ sys_memcpy(dbin->orig_bytes, ep, n);
+ }
ep += n;
break;
}
@@ -3007,8 +3379,10 @@ dec_term_atom_common:
n = get_int32(ep);
bitsize = ep[4];
- ep += 5;
- if (n <= ERL_ONHEAP_BIN_LIMIT) {
+ if (((bitsize==0) != (n==0)) || bitsize > 8)
+ goto error;
+ ep += 5;
+ if ((unsigned)n <= ERL_ONHEAP_BIN_LIMIT) {
ErlHeapBin* hb = (ErlHeapBin *) hp;
hb->thing_word = header_heap_bin(n);
@@ -3016,13 +3390,14 @@ dec_term_atom_common:
sys_memcpy(hb->data, ep, n);
bin = make_binary(hb);
hp += heap_bin_size(n);
+ ep += n;
} else {
Binary* dbin = erts_bin_nrml_alloc(n);
ProcBin* pb;
+
dbin->flags = 0;
dbin->orig_size = n;
erts_refc_init(&dbin->refc, 1);
- sys_memcpy(dbin->orig_bytes, ep, n);
pb = (ProcBin *) hp;
pb->thing_word = HEADER_PROC_BIN;
pb->size = n;
@@ -3033,12 +3408,27 @@ dec_term_atom_common:
pb->flags = 0;
bin = make_binary(pb);
hp += PROC_BIN_SIZE;
- }
- ep += n;
- if (bitsize == 0) {
+ if (ctx) {
+ int n_limit = reds * B2T_MEMCPY_FACTOR;
+ if (n > n_limit) {
+ ctx->state = B2TDecodeBinary;
+ ctx->u.dc.remaining_n = n - n_limit;
+ ctx->u.dc.remaining_bytes = dbin->orig_bytes + n_limit;
+ n = n_limit;
+ reds = 0;
+ }
+ else
+ reds -= n / B2T_MEMCPY_FACTOR;
+ }
+ sys_memcpy(dbin->orig_bytes, ep, n);
+ ep += n;
+ n = pb->size;
+ }
+
+ if (bitsize == 8 || n == 0) {
*objp = bin;
} else {
- sb = (ErlSubBin *) hp;
+ sb = (ErlSubBin *)hp;
sb->thing_word = HEADER_SUB_BIN;
sb->orig = bin;
sb->size = n - 1;
@@ -3065,7 +3455,7 @@ dec_term_atom_common:
goto error;
}
*hpp = hp;
- ep = dec_term(edep, hpp, ep, off_heap, &temp);
+ ep = dec_term(edep, hpp, ep, off_heap, &temp, NULL);
hp = *hpp;
if (ep == NULL) {
goto error;
@@ -3125,7 +3515,7 @@ dec_term_atom_common:
}
*hpp = hp;
/* Index */
- if ((ep = dec_term(edep, hpp, ep, off_heap, &temp)) == NULL) {
+ if ((ep = dec_term(edep, hpp, ep, off_heap, &temp, NULL)) == NULL) {
goto error;
}
if (!is_small(temp)) {
@@ -3134,7 +3524,7 @@ dec_term_atom_common:
old_index = unsigned_val(temp);
/* Uniq */
- if ((ep = dec_term(edep, hpp, ep, off_heap, &temp)) == NULL) {
+ if ((ep = dec_term(edep, hpp, ep, off_heap, &temp, NULL)) == NULL) {
goto error;
}
if (!is_small(temp)) {
@@ -3202,7 +3592,7 @@ dec_term_atom_common:
}
/* Index */
- if ((ep = dec_term(edep, hpp, ep, off_heap, &temp)) == NULL) {
+ if ((ep = dec_term(edep, hpp, ep, off_heap, &temp, NULL)) == NULL) {
goto error;
}
if (!is_small(temp)) {
@@ -3211,7 +3601,7 @@ dec_term_atom_common:
old_index = unsigned_val(temp);
/* Uniq */
- if ((ep = dec_term(edep, hpp, ep, off_heap, &temp)) == NULL) {
+ if ((ep = dec_term(edep, hpp, ep, off_heap, &temp, NULL)) == NULL) {
goto error;
}
if (!is_small(temp)) {
@@ -3311,8 +3701,31 @@ dec_term_atom_common:
}
undo_offheap_in_area(off_heap, hp_saved, hp);
*hpp = hp_saved;
- return NULL;
+ if (ctx) {
+ ctx->state = B2TDecodeFail;
+ ctx->reds = reds;
+ }
+ return NULL;
}
+
+ if (--reds <= 0) {
+ if (ctx) {
+ if (next || ctx->state != B2TDecode) {
+ ctx->u.dc.ep = ep;
+ ctx->u.dc.next = next;
+ ctx->u.dc.hp = hp;
+ ctx->reds = 0;
+ return NULL;
+ }
+ }
+ else {
+ reds = ERTS_SWORD_MAX;
+ }
+ }
+ }
+ if (ctx) {
+ ctx->state = B2TDone;
+ ctx->reds = reds;
}
*hpp = hp;
return ep;
@@ -3600,18 +4013,37 @@ encode_size_struct_int(Process *p, ErtsAtomCacheMap *acmp, Eterm obj,
}
static Sint
-decoded_size(byte *ep, byte* endp, int internal_tags)
+decoded_size(byte *ep, byte* endp, int internal_tags, B2TContext* ctx)
{
- int heap_size = 0;
+ int heap_size;
int terms;
- int atom_extra_skip = 0;
+ int atom_extra_skip;
Uint n;
+ SWord reds;
+
+ if (ctx) {
+ reds = ctx->reds;
+ if (ctx->u.sc.ep) {
+ heap_size = ctx->u.sc.heap_size;
+ terms = ctx->u.sc.terms;
+ ep = ctx->u.sc.ep;
+ atom_extra_skip = ctx->u.sc.atom_extra_skip;
+ goto init_done;
+ }
+ }
+ else
+ reds = 0; /* not used but compiler warns anyway */
+
+ heap_size = 0;
+ terms = 1;
+ atom_extra_skip = 0;
+init_done:
#define SKIP(sz) \
do { \
if ((sz) <= endp-ep) { \
ep += (sz); \
- } else { return -1; }; \
+ } else { goto error; }; \
} while (0)
#define SKIP2(sz1, sz2) \
@@ -3619,25 +4051,24 @@ decoded_size(byte *ep, byte* endp, int internal_tags)
Uint sz = (sz1) + (sz2); \
if (sz1 < sz && (sz) <= endp-ep) { \
ep += (sz); \
- } else { return -1; } \
+ } else { goto error; } \
} while (0)
#define CHKSIZE(sz) \
do { \
- if ((sz) > endp-ep) { return -1; } \
+ if ((sz) > endp-ep) { goto error; } \
} while (0)
#define ADDTERMS(n) \
do { \
int before = terms; \
terms += (n); \
- if (terms < before) return -1; \
+ if (terms < before) goto error; \
} while (0)
-
- for (terms=1; terms > 0; terms--) {
- int tag;
-
+ ASSERT(terms > 0);
+ do {
+ int tag;
CHKSIZE(1);
tag = ep++[0];
switch (tag) {
@@ -3658,7 +4089,7 @@ decoded_size(byte *ep, byte* endp, int internal_tags)
CHKSIZE(4);
n = get_int32(ep);
if (n > BIG_ARITY_MAX*sizeof(ErtsDigit)) {
- return -1;
+ goto error;
}
SKIP2(n,4+1); /* skip, size,sign,digits */
heap_size += 1+1+(n+sizeof(Eterm)-1)/sizeof(Eterm); /* XXX: 1 too much? */
@@ -3667,7 +4098,7 @@ decoded_size(byte *ep, byte* endp, int internal_tags)
CHKSIZE(2);
n = get_int16(ep);
if (n > MAX_ATOM_CHARACTERS) {
- return -1;
+ goto error;
}
SKIP(n+2+atom_extra_skip);
atom_extra_skip = 0;
@@ -3677,7 +4108,7 @@ decoded_size(byte *ep, byte* endp, int internal_tags)
n = get_int16(ep);
ep += 2;
if (n > MAX_ATOM_SZ_LIMIT) {
- return -1;
+ goto error;
}
SKIP(n+atom_extra_skip);
atom_extra_skip = 0;
@@ -3686,7 +4117,7 @@ decoded_size(byte *ep, byte* endp, int internal_tags)
CHKSIZE(1);
n = get_int8(ep);
if (n > MAX_ATOM_CHARACTERS) {
- return -1;
+ goto error;
}
SKIP(n+1+atom_extra_skip);
atom_extra_skip = 0;
@@ -3696,7 +4127,7 @@ decoded_size(byte *ep, byte* endp, int internal_tags)
n = get_int8(ep);
ep++;
if (n > MAX_ATOM_SZ_LIMIT) {
- return -1;
+ goto error;
}
SKIP(n+atom_extra_skip);
atom_extra_skip = 0;
@@ -3725,7 +4156,7 @@ decoded_size(byte *ep, byte* endp, int internal_tags)
id_words = get_int16(ep);
if (id_words > ERTS_MAX_REF_NUMBERS)
- return -1;
+ goto error;
ep += 2;
atom_extra_skip = 1 + 4*id_words;
@@ -3827,7 +4258,7 @@ decoded_size(byte *ep, byte* endp, int internal_tags)
num_free = get_int32(ep);
ep += 4;
if (num_free > MAX_ARG) {
- return -1;
+ goto error;
}
terms += 4 + num_free;
heap_size += ERL_FUN_SIZE + num_free;
@@ -3844,24 +4275,47 @@ decoded_size(byte *ep, byte* endp, int internal_tags)
case BINARY_INTERNAL_REF:
if (!internal_tags) {
- return -1;
+ goto error;
}
SKIP(sizeof(ProcBin));
heap_size += PROC_BIN_SIZE;
break;
case BIT_BINARY_INTERNAL_REF:
if (!internal_tags) {
- return -1;
+ goto error;
}
SKIP(2+sizeof(ProcBin));
heap_size += PROC_BIN_SIZE + ERL_SUB_BIN_SIZE;
break;
default:
- return -1;
+ goto error;
}
- }
+ terms--;
+
+ if (ctx && --reds <= 0 && terms > 0) {
+ ctx->u.sc.heap_size = heap_size;
+ ctx->u.sc.terms = terms;
+ ctx->u.sc.ep = ep;
+ ctx->u.sc.atom_extra_skip = atom_extra_skip;
+ ctx->reds = 0;
+ return 0;
+ }
+ }while (terms > 0);
+
/* 'terms' may be non-zero if it has wrapped around */
- return terms==0 ? heap_size : -1;
+ if (terms == 0) {
+ if (ctx) {
+ ctx->state = B2TDecodeInit;
+ ctx->reds = reds;
+ }
+ return heap_size;
+ }
+
+error:
+ if (ctx) {
+ ctx->state = B2TBadArg;
+ }
+ return -1;
#undef SKIP
#undef SKIP2
#undef CHKSIZE
diff --git a/erts/emulator/beam/external.h b/erts/emulator/beam/external.h
index ff29e84972..83001b2c7e 100644
--- a/erts/emulator/beam/external.h
+++ b/erts/emulator/beam/external.h
@@ -146,6 +146,7 @@ typedef struct {
typedef struct {
byte *extp;
int exttmp;
+ Uint extsize;
} ErtsBinary2TermState;
/* -------------------------------------------------------------------------- */
diff --git a/erts/emulator/beam/global.h b/erts/emulator/beam/global.h
index c1fda3f96c..94bc1b172a 100755
--- a/erts/emulator/beam/global.h
+++ b/erts/emulator/beam/global.h
@@ -650,6 +650,10 @@ Eterm erl_send(Process *p, Eterm to, Eterm msg);
Eterm erl_is_function(Process* p, Eterm arg1, Eterm arg2);
+/* beam_bif_load.c */
+Eterm erts_check_process_code(Process *c_p, Eterm module, int allow_gc, int *redsp);
+
+
/* beam_load.c */
typedef struct {
BeamInstr* current; /* Pointer to: Mod, Name, Arity */
@@ -1121,7 +1125,12 @@ erts_alloc_message_heap_state(Uint size,
if (statep)
*statep = state;
if ((state & (ERTS_PSFLG_EXITING|ERTS_PSFLG_PENDING_EXIT))
+ || (receiver->flags & F_DISABLE_GC)
|| HEAP_LIMIT(receiver) - HEAP_TOP(receiver) <= size) {
+ /*
+ * The heap is either potentially in an inconsistent
+ * state, or not large enough.
+ */
#ifdef ERTS_SMP
if (locked_main) {
*receiver_locks &= ~ERTS_PROC_LOCK_MAIN;
diff --git a/erts/emulator/beam/io.c b/erts/emulator/beam/io.c
index b2803747eb..d4623c0450 100644
--- a/erts/emulator/beam/io.c
+++ b/erts/emulator/beam/io.c
@@ -3602,6 +3602,8 @@ erts_deliver_port_exit(Port *p, Eterm from, Eterm reason, int send_closed)
if (send_closed)
set_state_flags |= ERTS_PORT_SFLG_SEND_CLOSED;
+ erts_port_task_sched_enter_exiting_state(&p->sched);
+
state = erts_atomic32_read_bor_mb(&p->state, set_state_flags);
state |= set_state_flags;
@@ -4079,7 +4081,7 @@ erts_port_control(Process* c_p,
copy = 1;
else {
binp = ((ProcBin *) ebinp)->val;
- ASSERT(bufp < bufp + size);
+ ASSERT(bufp <= bufp + size);
ASSERT(binp->orig_bytes <= bufp
&& bufp + size <= binp->orig_bytes + binp->orig_size);
erts_refc_inc(&binp->refc, 1);
diff --git a/erts/emulator/beam/ops.tab b/erts/emulator/beam/ops.tab
index 1e5ae46bfa..c29f3f9b1b 100644
--- a/erts/emulator/beam/ops.tab
+++ b/erts/emulator/beam/ops.tab
@@ -763,17 +763,17 @@ allocate_init t I y
#################################################################
#
-# The BIFs erlang:check_process_code/2 must be called like a function,
+# The BIFs erts_internal:check_process_code/2 must be called like a function,
# to ensure that c_p->i (program counter) is set correctly (an ordinary
# BIF call doesn't set it).
#
-call_ext u==2 Bif=u$bif:erlang:check_process_code/2 => i_call_ext Bif
-call_ext_last u==2 Bif=u$bif:erlang:check_process_code/2 D => i_call_ext_last Bif D
-call_ext_only u==2 Bif=u$bif:erlang:check_process_code/2 => i_call_ext_only Bif
+call_ext u==2 Bif=u$bif:erts_internal:check_process_code/2 => i_call_ext Bif
+call_ext_last u==2 Bif=u$bif:erts_internal:check_process_code/2 D => i_call_ext_last Bif D
+call_ext_only u==2 Bif=u$bif:erts_internal:check_process_code/2 => i_call_ext_only Bif
#
-# The BIFs erlang:garbage_collect/0,1 must be called like functions,
+# The BIFs erlang:garbage_collect/0 must be called like a function,
# to allow them to invoke the garbage collector. (The stack pointer must
# be saved and p->arity must be zeroed, which is not done on ordinary BIF calls.)
#
@@ -782,10 +782,6 @@ call_ext u==0 Bif=u$bif:erlang:garbage_collect/0 => i_call_ext Bif
call_ext_last u==0 Bif=u$bif:erlang:garbage_collect/0 D => i_call_ext_last Bif D
call_ext_only u==0 Bif=u$bif:erlang:garbage_collect/0 => i_call_ext_only Bif
-call_ext u==1 Bif=u$bif:erlang:garbage_collect/1 => i_call_ext Bif
-call_ext_last u==1 Bif=u$bif:erlang:garbage_collect/1 D => i_call_ext_last Bif D
-call_ext_only u==1 Bif=u$bif:erlang:garbage_collect/1 => i_call_ext_only Bif
-
#
# put/2 and erase/1 must be able to do garbage collection, so we must call
# them like functions.
diff --git a/erts/emulator/beam/sys.h b/erts/emulator/beam/sys.h
index 9561c0be96..d0ccf8a2fc 100644
--- a/erts/emulator/beam/sys.h
+++ b/erts/emulator/beam/sys.h
@@ -149,9 +149,28 @@ typedef ERTS_SYS_FD_TYPE ErtsSysFdType;
# define ERTS_EXIT_AFTER_DUMP exit
#endif
+/* In VC++, noreturn is a declspec that has to be before the types,
+ * but in GNUC it is an att ribute to be placed between return type
+ * and function name, hence __decl_noreturn <types> __noreturn <function name>
+ */
+#if __GNUC__
+# define __decl_noreturn
+# define __noreturn __attribute__((noreturn))
+#else
+# if defined(__WIN32__) && defined(_MSC_VER)
+# define __noreturn
+# define __decl_noreturn __declspec(noreturn)
+# else
+# define __noreturn
+# define __decl_noreturn
+# endif
+#endif
+
#define ERTS_ASSERT(e) \
((void) ((e) ? 1 : (erl_assert_error(#e, __func__, __FILE__, __LINE__), 0)))
-void erl_assert_error(const char* expr, const char *func, const char* file, int line);
+
+__decl_noreturn void __noreturn erl_assert_error(const char* expr, const char *func,
+ const char* file, int line);
#ifdef DEBUG
# define ASSERT(e) ERTS_ASSERT(e)
@@ -192,23 +211,6 @@ void erl_assert_error(const char* expr, const char *func, const char* file, int
# define erts_align_attribute(SZ)
#endif
-/* In VC++, noreturn is a declspec that has to be before the types,
- * but in GNUC it is an att ribute to be placed between return type
- * and function name, hence __decl_noreturn <types> __noreturn <function name>
- */
-#if __GNUC__
-# define __decl_noreturn
-# define __noreturn __attribute__((noreturn))
-#else
-# if defined(__WIN32__) && defined(_MSC_VER)
-# define __noreturn
-# define __decl_noreturn __declspec(noreturn)
-# else
-# define __noreturn
-# define __decl_noreturn
-# endif
-#endif
-
/*
** Data types:
**
@@ -277,18 +279,21 @@ typedef unsigned long UWord;
typedef long SWord;
#define SWORD_CONSTANT(Const) Const##L
#define UWORD_CONSTANT(Const) Const##UL
+#define ERTS_UWORD_MAX ULONG_MAX
#define ERTS_SWORD_MAX LONG_MAX
#elif SIZEOF_VOID_P == SIZEOF_INT
typedef unsigned int UWord;
typedef int SWord;
#define SWORD_CONSTANT(Const) Const
#define UWORD_CONSTANT(Const) Const##U
+#define ERTS_UWORD_MAX UINT_MAX
#define ERTS_SWORD_MAX INT_MAX
#elif SIZEOF_VOID_P == SIZEOF_LONG_LONG
typedef unsigned long long UWord;
typedef long long SWord;
#define SWORD_CONSTANT(Const) Const##LL
#define UWORD_CONSTANT(Const) Const##ULL
+#define ERTS_UWORD_MAX ULLONG_MAX
#define ERTS_SWORD_MAX LLONG_MAX
#else
#error Found no appropriate type to use for 'Eterm', 'Uint' and 'Sint'
@@ -302,6 +307,7 @@ typedef unsigned long Uint;
typedef long Sint;
#define SWORD_CONSTANT(Const) Const##L
#define UWORD_CONSTANT(Const) Const##UL
+#define ERTS_UWORD_MAX ULONG_MAX
#define ERTS_SWORD_MAX LONG_MAX
#define ERTS_SIZEOF_ETERM SIZEOF_LONG
#define ErtsStrToSint strtol
@@ -311,6 +317,7 @@ typedef unsigned int Uint;
typedef int Sint;
#define SWORD_CONSTANT(Const) Const
#define UWORD_CONSTANT(Const) Const##U
+#define ERTS_UWORD_MAX UINT_MAX
#define ERTS_SWORD_MAX INT_MAX
#define ERTS_SIZEOF_ETERM SIZEOF_INT
#define ErtsStrToSint strtol
@@ -320,6 +327,7 @@ typedef unsigned long long Uint;
typedef long long Sint;
#define SWORD_CONSTANT(Const) Const##LL
#define UWORD_CONSTANT(Const) Const##ULL
+#define ERTS_UWORD_MAX ULLONG_MAX
#define ERTS_SWORD_MAX LLONG_MAX
#define ERTS_SIZEOF_ETERM SIZEOF_LONG_LONG
#if defined(__WIN32__)
@@ -750,6 +758,8 @@ int erts_sys_getenv(char *key, char *value, size_t *size);
int erts_sys_getenv_raw(char *key, char *value, size_t *size);
/* erts_sys_getenv__() is only allowed to be used in early init phase */
int erts_sys_getenv__(char *key, char *value, size_t *size);
+/* erst_sys_unsetenv() returns 0 on success and a value != 0 on failure. */
+int erts_sys_unsetenv(char *key);
/* Easier to use, but not as efficient, environment functions */
char *erts_read_env(char *key);
diff --git a/erts/emulator/beam/utils.c b/erts/emulator/beam/utils.c
index 605a625282..297c4bf439 100644
--- a/erts/emulator/beam/utils.c
+++ b/erts/emulator/beam/utils.c
@@ -1675,7 +1675,7 @@ static int do_send_to_logger(Eterm tag, Eterm gleader, char *buf, int len)
p = erts_whereis_process(NULL, 0, am_error_logger, 0, 0);
if (p) {
erts_aint32_t state = erts_smp_atomic32_read_acqb(&p->state);
- if (state & ERTS_PSFLG_RUNNING)
+ if (state & (ERTS_PSFLG_RUNNING|ERTS_PSFLG_RUNNING_SYS))
p = NULL;
}
}
diff --git a/erts/emulator/drivers/common/erl_efile.h b/erts/emulator/drivers/common/erl_efile.h
index 5387f75efc..95c036db8f 100644
--- a/erts/emulator/drivers/common/erl_efile.h
+++ b/erts/emulator/drivers/common/erl_efile.h
@@ -34,6 +34,7 @@
#define EFILE_COMPRESSED 8
#define EFILE_MODE_EXCL 16
#define EFILE_NO_TRUNCATE 32 /* Special for reopening on VxWorks */
+#define EFILE_MODE_SYNC 64
/*
* Seek modes for efile_seek().
diff --git a/erts/emulator/drivers/common/inet_drv.c b/erts/emulator/drivers/common/inet_drv.c
index 4fb20bf1b0..978a766de9 100644
--- a/erts/emulator/drivers/common/inet_drv.c
+++ b/erts/emulator/drivers/common/inet_drv.c
@@ -424,13 +424,44 @@ static unsigned long one_value = 1;
# define sctp_adaptation_layer_event sctp_adaption_layer_event
#endif
-#ifdef __GNUC__
+#if defined(__GNUC__) && defined(HAVE_SCTP_BINDX)
static typeof(sctp_bindx) *p_sctp_bindx = NULL;
+#else
+static int (*p_sctp_bindx)
+ (int sd, struct sockaddr *addrs, int addrcnt, int flags) = NULL;
+#endif
+
+#if defined(__GNUC__) && defined(HAVE_SCTP_PEELOFF)
static typeof(sctp_peeloff) *p_sctp_peeloff = NULL;
#else
-static int (*p_sctp_bindx)(int sd, struct sockaddr *addrs,
- int addrcnt, int flags) = NULL;
-static int (*p_sctp_peeloff)(int sd, sctp_assoc_t assoc_id) = NULL;
+static int (*p_sctp_peeloff)
+ (int sd, sctp_assoc_t assoc_id) = NULL;
+#endif
+
+#if defined(__GNUC__) && defined(HAVE_SCTP_GETLADDRS)
+static typeof(sctp_getladdrs) *p_sctp_getladdrs = NULL;
+#else
+static int (*p_sctp_getladdrs)
+ (int sd, sctp_assoc_t assoc_id, struct sockaddr **ss) = NULL;
+#endif
+
+#if defined(__GNUC__) && defined(HAVE_SCTP_FREELADDRS)
+static typeof(sctp_freeladdrs) *p_sctp_freeladdrs = NULL;
+#else
+static void (*p_sctp_freeladdrs)(struct sockaddr *addrs) = NULL;
+#endif
+
+#if defined(__GNUC__) && defined(HAVE_SCTP_GETPADDRS)
+static typeof(sctp_getpaddrs) *p_sctp_getpaddrs = NULL;
+#else
+static int (*p_sctp_getpaddrs)
+ (int sd, sctp_assoc_t assoc_id, struct sockaddr **ss) = NULL;
+#endif
+
+#if defined(__GNUC__) && defined(HAVE_SCTP_FREEPADDRS)
+static typeof(sctp_freepaddrs) *p_sctp_freepaddrs = NULL;
+#else
+static void (*p_sctp_freepaddrs)(struct sockaddr *addrs) = NULL;
#endif
#endif /* #if defined(HAVE_SCTP_H) */
@@ -601,7 +632,7 @@ static int my_strncasecmp(const char *s1, const char *s2, size_t n)
#define INET_F_BUSY 0x0080
#define INET_F_MULTI_CLIENT 0x0100 /* Multiple clients for one descriptor, i.e. multi-accept */
-/* One numberspace for *_REC_* so if an e.g UDP request is issued
+/* One numberspace for *_REQ_* so if an e.g UDP request is issued
** for a TCP socket, the driver can protest.
*/
#define INET_REQ_OPEN 1
@@ -632,6 +663,8 @@ static int my_strncasecmp(const char *s1, const char *s2, size_t n)
#define INET_REQ_ACCEPT 26
#define INET_REQ_LISTEN 27
#define INET_REQ_IGNOREFD 28
+#define INET_REQ_GETLADDRS 29
+#define INET_REQ_GETPADDRS 30
/* TCP requests */
/* #define TCP_REQ_ACCEPT 40 MOVED */
@@ -1441,8 +1474,7 @@ static int load_ip_address(ErlDrvTermData* spec, int i, int family, char* buf)
#ifdef HAVE_SCTP
/* For SCTP, we often need to return {IP, Port} tuples: */
-static int inet_get_address
- (int family, char* dst, inet_address* src, unsigned int* len);
+static int inet_get_address(char* dst, inet_address* src, unsigned int* len);
#define LOAD_IP_AND_PORT_CNT \
(8*LOAD_INT_CNT + LOAD_TUPLE_CNT + LOAD_INT_CNT + LOAD_TUPLE_CNT)
@@ -1457,8 +1489,7 @@ static int load_ip_and_port
unsigned int len = sizeof(struct sockaddr_storage);
unsigned int alen = len;
char abuf [len];
- int res =
- inet_get_address(desc->sfamily, abuf, (inet_address*) addr, &alen);
+ int res = inet_get_address(abuf, (inet_address*) addr, &alen);
ASSERT(res==0);
res = 0;
/* Now "abuf" contains: Family(1b), Port(2b), IP(4|16b) */
@@ -3712,9 +3743,27 @@ static int inet_init()
/* Check the size of SCTP AssocID -- currently both this driver and the
Erlang part require 32 bit: */
ASSERT(sizeof(sctp_assoc_t)==ASSOC_ID_LEN);
-# if defined(HAVE_SCTP_BINDX) && defined (HAVE_SCTP_PEELOFF)
+# if defined(HAVE_SCTP_BINDX)
p_sctp_bindx = sctp_bindx;
+# if defined(HAVE_SCTP_PEELOFF)
p_sctp_peeloff = sctp_peeloff;
+# else
+ p_sctp_peeloff = NULL;
+# endif
+# if defined(HAVE_SCTP_GETLADDRS) && defined(HAVE_SCTP_FREELADDRS)
+ p_sctp_getladdrs = sctp_getladdrs;
+ p_sctp_freeladdrs = sctp_freeladdrs;
+# else
+ p_sctp_getladdrs = NULL;
+ p_sctp_freeladdrs = NULL;
+# endif
+# if defined(HAVE_SCTP_GETPADDRS) && defined(HAVE_SCTP_FREEPADDRS)
+ p_sctp_getpaddrs = sctp_getpaddrs;
+ p_sctp_freepaddrs = sctp_freepaddrs;
+# else
+ p_sctp_getpaddrs = NULL;
+ p_sctp_freepaddrs = NULL;
+# endif
inet_init_sctp();
add_driver_entry(&sctp_inet_driver_entry);
# else
@@ -3729,12 +3778,36 @@ static int inet_init()
void *ptr;
if (erts_sys_ddll_sym(h_libsctp, "sctp_bindx", &ptr) == 0) {
p_sctp_bindx = ptr;
- inet_init_sctp();
- add_driver_entry(&sctp_inet_driver_entry);
if (erts_sys_ddll_sym(h_libsctp, "sctp_peeloff", &ptr) == 0) {
p_sctp_peeloff = ptr;
}
+ else p_sctp_peeloff = NULL;
+ if (erts_sys_ddll_sym(h_libsctp, "sctp_getladdrs", &ptr) == 0) {
+ p_sctp_getladdrs = ptr;
+ }
+ else p_sctp_getladdrs = NULL;
+ if (erts_sys_ddll_sym(h_libsctp, "sctp_freeladdrs", &ptr) == 0) {
+ p_sctp_freeladdrs = ptr;
+ }
+ else {
+ p_sctp_freeladdrs = NULL;
+ p_sctp_getladdrs = NULL;
+ }
+ if (erts_sys_ddll_sym(h_libsctp, "sctp_getpaddrs", &ptr) == 0) {
+ p_sctp_getpaddrs = ptr;
+ }
+ else p_sctp_getpaddrs = NULL;
+ if (erts_sys_ddll_sym(h_libsctp, "sctp_freepaddrs", &ptr) == 0) {
+ p_sctp_freepaddrs = ptr;
+ }
+ else {
+ p_sctp_freepaddrs = NULL;
+ p_sctp_getpaddrs = NULL;
+ }
+ inet_init_sctp();
+ add_driver_entry(&sctp_inet_driver_entry);
}
+ else p_sctp_bindx = NULL;
}
}
# endif
@@ -3889,10 +3962,12 @@ static char *inet_set_faddress(int family, inet_address* dst,
** and *len is the length of dst on return
** (suitable to deliver to erlang)
*/
-static int inet_get_address(int family, char* dst, inet_address* src, unsigned int* len)
+static int inet_get_address(char* dst, inet_address* src, unsigned int* len)
{
+ int family;
short port;
+ family = src->sa.sa_family;
if ((family == AF_INET) && (*len >= sizeof(struct sockaddr_in))) {
dst[0] = INET_AF_INET;
port = sock_ntohs(src->sai.sin_port);
@@ -3914,6 +3989,75 @@ static int inet_get_address(int family, char* dst, inet_address* src, unsigned i
return -1;
}
+/* Same as the above, but take family from the address structure,
+** and advance the address pointer to the next address
+** according to the size of the current,
+** and return the resulting encoded size
+*/
+static int inet_address_to_erlang(char *dst, inet_address **src) {
+ short port;
+
+ switch ((*src)->sa.sa_family) {
+ case AF_INET:
+ if (dst) {
+ dst[0] = INET_AF_INET;
+ port = sock_ntohs((*src)->sai.sin_port);
+ put_int16(port, dst+1);
+ sys_memcpy(dst+1+2, (char *) &(*src)->sai.sin_addr, 4);
+ }
+ (*src) = (inet_address *) (&(*src)->sai + 1);
+ return 1 + 2 + 4;
+#if defined(HAVE_IN6) && defined(AF_INET6)
+ case AF_INET6:
+ if (dst) {
+ dst[0] = INET_AF_INET6;
+ port = sock_ntohs((*src)->sai6.sin6_port);
+ put_int16(port, dst+1);
+ VALGRIND_MAKE_MEM_DEFINED(&(*src)->sai6.sin6_addr,16); /* false undefs from syscall sctp_get[lp]addrs */
+ sys_memcpy(dst+1+2, (char *) &(*src)->sai6.sin6_addr, 16);
+ }
+ (*src) = (inet_address *) (&(*src)->sai6 + 1);
+ return 1 + 2 + 16;
+#endif
+ default:
+ return -1;
+ }
+}
+
+/* Encode n encoded addresses from addrs in the result buffer
+*/
+static ErlDrvSizeT reply_inet_addrs
+(int n, inet_address *addrs, char **rbuf, ErlDrvSizeT rsize) {
+ inet_address *ia;
+ int i, s;
+ ErlDrvSizeT rlen;
+
+ if (IS_SOCKET_ERROR(n)) return ctl_error(sock_errno(), rbuf, rsize);
+ if (n == 0) return ctl_reply(INET_REP_OK, NULL, 0, rbuf, rsize);
+
+ /* Calculate result length */
+ rlen = 1;
+ ia = addrs;
+ for (i = 0; i < n; i++) {
+ s = inet_address_to_erlang(NULL, &ia);
+ if (s < 0) break;
+ rlen += s;
+ }
+
+ if (rlen > rsize) (*rbuf) = ALLOC(rlen);
+
+ (*rbuf)[0] = INET_REP_OK;
+ rlen = 1;
+ ia = addrs;
+ for (i = 0; i < n; i++) {
+ s = inet_address_to_erlang((*rbuf)+rlen, &ia);
+ if (s < 0) break;
+ rlen += s;
+ }
+
+ return rlen;
+}
+
static void desc_close(inet_descriptor* desc)
{
if (desc->s != INVALID_SOCKET) {
@@ -7978,6 +8122,39 @@ static ErlDrvSSizeT inet_ctl(inet_descriptor* desc, int cmd, char* buf,
return ctl_reply(INET_REP_OK, tbuf, strlen(tbuf), rbuf, rsize);
}
+ case INET_REQ_GETPADDRS: {
+ DEBUGF(("inet_ctl(%ld): INET_GETPADDRS\r\n", (long)desc->port));
+
+ if (len != 4) return ctl_error(EINVAL, rbuf, rsize);
+
+ if (! IS_OPEN(desc)) return ctl_xerror(EXBADPORT, rbuf, rsize);
+ if (! IS_BOUND(desc)) return ctl_xerror(EXBADSEQ, rbuf, rsize);
+
+#ifdef HAVE_SCTP
+ if (IS_SCTP(desc) && p_sctp_getpaddrs) {
+ struct sockaddr *sa;
+ Uint32 assoc_id;
+ int n;
+ ErlDrvSizeT rlen;
+
+ assoc_id = get_int32(buf);
+ n = p_sctp_getpaddrs(desc->s, assoc_id, &sa);
+ rlen = reply_inet_addrs(n, (inet_address *) sa, rbuf, rsize);
+ if (n > 0) p_sctp_freepaddrs(sa);
+ return rlen;
+ }
+#endif
+ { /* Fallback to sock_peer */
+ inet_address addr;
+ unsigned int sz;
+ int i;
+
+ sz = sizeof(addr);
+ i = sock_peer(desc->s, (struct sockaddr *) &addr, &sz);
+ return reply_inet_addrs(i >= 0 ? 1 : i, &addr, rbuf, rsize);
+ }
+ }
+
case INET_REQ_PEER: { /* get peername */
char tbuf[sizeof(inet_address)];
inet_address peer;
@@ -7993,7 +8170,7 @@ static ErlDrvSSizeT inet_ctl(inet_descriptor* desc, int cmd, char* buf,
if (IS_SOCKET_ERROR(sock_peer(desc->s, (struct sockaddr*)ptr,&sz)))
return ctl_error(sock_errno(), rbuf, rsize);
}
- if (inet_get_address(desc->sfamily, tbuf, ptr, &sz) < 0)
+ if (inet_get_address(tbuf, ptr, &sz) < 0)
return ctl_error(EINVAL, rbuf, rsize);
return ctl_reply(INET_REP_OK, tbuf, sz, rbuf, rsize);
}
@@ -8014,6 +8191,39 @@ static ErlDrvSSizeT inet_ctl(inet_descriptor* desc, int cmd, char* buf,
}
}
+ case INET_REQ_GETLADDRS: {
+ DEBUGF(("inet_ctl(%ld): INET_GETLADDRS\r\n", (long)desc->port));
+
+ if (len != 4) return ctl_error(EINVAL, rbuf, rsize);
+
+ if (! IS_OPEN(desc)) return ctl_xerror(EXBADPORT, rbuf, rsize);
+ if (! IS_BOUND(desc)) return ctl_xerror(EXBADSEQ, rbuf, rsize);
+
+#ifdef HAVE_SCTP
+ if (IS_SCTP(desc) && p_sctp_getladdrs) {
+ struct sockaddr *sa;
+ Uint32 assoc_id;
+ int n;
+ ErlDrvSizeT rlen;
+
+ assoc_id = get_int32(buf);
+ n = p_sctp_getladdrs(desc->s, assoc_id, &sa);
+ rlen = reply_inet_addrs(n, (inet_address *) sa, rbuf, rsize);
+ if (n > 0) p_sctp_freeladdrs(sa);
+ return rlen;
+ }
+#endif
+ { /* Fallback to sock_name */
+ inet_address addr;
+ unsigned int sz;
+ int i;
+
+ sz = sizeof(addr);
+ i = sock_name(desc->s, (struct sockaddr *) &addr, &sz);
+ return reply_inet_addrs(i >= 0 ? 1 : i, &addr, rbuf, rsize);
+ }
+ }
+
case INET_REQ_NAME: { /* get sockname */
char tbuf[sizeof(inet_address)];
inet_address name;
@@ -8030,7 +8240,7 @@ static ErlDrvSSizeT inet_ctl(inet_descriptor* desc, int cmd, char* buf,
if (IS_SOCKET_ERROR(sock_name(desc->s, (struct sockaddr*)ptr, &sz)))
return ctl_error(sock_errno(), rbuf, rsize);
}
- if (inet_get_address(desc->sfamily, tbuf, ptr, &sz) < 0)
+ if (inet_get_address(tbuf, ptr, &sz) < 0)
return ctl_error(EINVAL, rbuf, rsize);
return ctl_reply(INET_REP_OK, tbuf, sz, rbuf, rsize);
}
@@ -10869,7 +11079,7 @@ static int packet_inet_input(udp_descriptor* udesc, HANDLE event)
inet_input_count(desc, n);
udesc->i_ptr += n;
- inet_get_address(desc->sfamily, abuf, &other, &len);
+ inet_get_address(abuf, &other, &len);
/* Copy formatted address to the buffer allocated; "len" is the
actual length which must be <= than the original reserved.
This means that the addr + data in the buffer are contiguous,
diff --git a/erts/emulator/drivers/unix/unix_efile.c b/erts/emulator/drivers/unix/unix_efile.c
index 55539b44dd..8ffc05da99 100644
--- a/erts/emulator/drivers/unix/unix_efile.c
+++ b/erts/emulator/drivers/unix/unix_efile.c
@@ -405,6 +405,15 @@ efile_openfile(Efile_error* errInfo, /* Where to return error codes. */
mode |= O_EXCL;
}
+ if (flags & EFILE_MODE_SYNC) {
+#ifdef O_SYNC
+ mode |= O_SYNC;
+#else
+ errno = ENOTSUP;
+ return check_error(-1, errInfo);
+#endif
+ }
+
fd = open(name, mode, FILE_MODE);
if (!check_error(fd, errInfo))
diff --git a/erts/emulator/drivers/win32/win_efile.c b/erts/emulator/drivers/win32/win_efile.c
index 319065f57b..d693d7d593 100644
--- a/erts/emulator/drivers/win32/win_efile.c
+++ b/erts/emulator/drivers/win32/win_efile.c
@@ -698,6 +698,7 @@ efile_openfile(Efile_error* errInfo, /* Where to return error codes. */
HANDLE fd; /* Handle to open file. */
DWORD access; /* Access mode: GENERIC_READ, GENERIC_WRITE. */
DWORD crFlags;
+ DWORD flagsAndAttrs = FILE_ATTRIBUTE_NORMAL;
WCHAR *wname = (WCHAR *) name;
switch (flags & (EFILE_MODE_READ|EFILE_MODE_WRITE)) {
@@ -719,6 +720,10 @@ efile_openfile(Efile_error* errInfo, /* Where to return error codes. */
return 0;
}
+ if (flags & EFILE_MODE_SYNC) {
+ flagsAndAttrs = FILE_FLAG_WRITE_THROUGH;
+ }
+
if (flags & EFILE_MODE_APPEND) {
crFlags = OPEN_ALWAYS;
}
@@ -727,7 +732,7 @@ efile_openfile(Efile_error* errInfo, /* Where to return error codes. */
}
fd = CreateFileW(wname, access,
FILE_SHARE_FLAGS,
- NULL, crFlags, FILE_ATTRIBUTE_NORMAL, NULL);
+ NULL, crFlags, flagsAndAttrs, NULL);
/*
* Check for errors.
diff --git a/erts/emulator/drivers/win32/winsock_func.h b/erts/emulator/drivers/win32/winsock_func.h
deleted file mode 100644
index 9d2c099c4d..0000000000
--- a/erts/emulator/drivers/win32/winsock_func.h
+++ /dev/null
@@ -1,102 +0,0 @@
-/*
- * %CopyrightBegin%
- *
- * Copyright Ericsson AB 1997-2009. All Rights Reserved.
- *
- * The contents of this file are subject to the Erlang Public License,
- * Version 1.1, (the "License"); you may not use this file except in
- * compliance with the License. You should have received a copy of the
- * Erlang Public License along with this software. If not, it can be
- * retrieved online at http://www.erlang.org/.
- *
- * Software distributed under the License is distributed on an "AS IS"
- * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
- * the License for the specific language governing rights and limitations
- * under the License.
- *
- * %CopyrightEnd%
- */
-
-typedef struct _WinSockFuncs {
- int (WSAAPI *WSAStartup)(WORD wVersionRequired, LPWSADATA lpWSAData);
- int (WSAAPI *WSACleanup)(void);
- int (WSAAPI *WSAGetLastError)(void);
- DWORD (WSAAPI *WSAWaitForMultipleEvents) (DWORD cEvents,
- const WSAEVENT FAR * lphEvents,
- BOOL fWaitAll,
- DWORD dwTimeout,
- BOOL fAlertable);
- WSAEVENT (WSAAPI *WSACreateEvent)(void);
- BOOL (WSAAPI *WSACloseEvent)(WSAEVENT hEvent);
-
- BOOL (WSAAPI *WSASetEvent)(WSAEVENT hEvent);
- BOOL (WSAAPI *WSAResetEvent)(WSAEVENT hEvent);
- int (WSAAPI *WSAEventSelect)(SOCKET s, WSAEVENT hEventObject,
- long lNetworkEvents);
- int (WSAAPI *WSAEnumNetworkEvents)(SOCKET s,
- WSAEVENT hEventObject,
- LPWSANETWORKEVENTS lpNetworkEvents);
- int (WSAAPI *WSAIoctl)(SOCKET s,
- DWORD dwIoControlCode,
- LPVOID lpvInBuffer,
- DWORD cbInBuffer,
- LPVOID lpvOUTBuffer,
- DWORD cbOUTBuffer,
- LPDWORD lpcbBytesReturned,
- LPWSAOVERLAPPED lpOverlapped,
- LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionROUTINE
- );
- SOCKET (WSAAPI *accept)(SOCKET s, struct sockaddr FAR *addr,
- int FAR *addrlen);
- int (WSAAPI *bind)(SOCKET s, const struct sockaddr FAR *addr,
- int namelen);
- int (WSAAPI *closesocket)(SOCKET s);
- int (WSAAPI *connect)(SOCKET s, const struct sockaddr FAR *name,
- int namelen);
- int (WSAAPI *ioctlsocket)(SOCKET s, long cmd, u_long FAR *argp);
- int (WSAAPI *getsockopt)(SOCKET s, int level, int optname,
- char FAR * optval, int FAR *optlen);
- u_long (WSAAPI *htonl)(u_long hostlong);
- u_short (WSAAPI *htons)(u_short hostshort);
- unsigned long (WSAAPI *inet_addr)(const char FAR * cp);
- char FAR * (WSAAPI *inet_ntoa)(struct in_addr in);
- int (WSAAPI *listen)(SOCKET s, int backlog);
- u_short (WSAAPI *ntohs)(u_short netshort);
- int (WSAAPI *recv)(SOCKET s, char FAR * buf, int len, int flags);
- int (WSAAPI *send)(SOCKET s, const char FAR * buf, int len, int flags);
- int (WSAAPI *setsockopt)(SOCKET s, int level, int optname,
- const char FAR * optval, int optlen);
- int (WSAAPI *shutdown)(SOCKET s, int how);
- SOCKET (WSAAPI *socket)(int af, int type, int protocol);
- struct hostent FAR * (WSAAPI *gethostbyname)(const char FAR * name);
- struct hostent FAR * (WSAAPI *gethostbyaddr)(const char FAR *addr,
- int addrlen, int addrtype);
- int (WSAAPI *gethostname)(char FAR * name, int namelen);
- struct servent FAR * (WSAAPI *getservbyname)(const char FAR * name,
- const char FAR * proto);
- struct servent FAR * (WSAAPI *getservbyport)(int port,
- const char FAR * proto);
- int (WSAAPI *getsockname)(SOCKET sock, struct sockaddr FAR *name,
- int FAR *namelen);
-
- /*
- * New, added for inet_drv.
- */
-
- int (WSAAPI *getpeername)(SOCKET s, struct sockaddr FAR * name,
- int FAR * namelen);
- u_long (WSAAPI *ntohl)(u_long netlong);
- int (WSAAPI *WSASend)(SOCKET s, LPWSABUF lpBuffers, DWORD dwBufferCount,
- LPDWORD lpNumberOfBytesSent, DWORD dwFlags,
- LPWSAOVERLAPPED lpOverlapped,
- LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine);
- int (WSAAPI *sendto)(SOCKET s, const char FAR * buf, int len,
- int flags, const struct sockaddr FAR * to, int tolen);
- int (WSAAPI *recvfrom)(SOCKET s, char FAR * buf, int len, int flags,
- struct sockaddr FAR * from, int FAR * fromlen);
-} WinSockFuncs;
-
-
-extern WinSockFuncs winSock;
-
-extern int tcp_lookup_functions(void);
diff --git a/erts/emulator/hipe/hipe_bif_list.m4 b/erts/emulator/hipe/hipe_bif_list.m4
index 764b8d180c..b1fedf4838 100644
--- a/erts/emulator/hipe/hipe_bif_list.m4
+++ b/erts/emulator/hipe/hipe_bif_list.m4
@@ -151,10 +151,9 @@ standard_bif_interface_0(nbif_ports_0, ports_0)
* BIFs and primops that may do a GC (change heap limit and walk the native stack).
* XXX: erase/1 and put/2 cannot fail
*/
-gc_bif_interface_2(nbif_check_process_code_2, hipe_check_process_code_2)
+gc_bif_interface_2(nbif_erts_internal_check_process_code_2, hipe_erts_internal_check_process_code_2)
gc_bif_interface_1(nbif_erase_1, erase_1)
gc_bif_interface_0(nbif_garbage_collect_0, garbage_collect_0)
-gc_bif_interface_1(nbif_garbage_collect_1, hipe_garbage_collect_1)
gc_nofail_primop_interface_1(nbif_gc_1, hipe_gc)
gc_bif_interface_2(nbif_put_2, put_2)
diff --git a/erts/emulator/hipe/hipe_native_bif.c b/erts/emulator/hipe/hipe_native_bif.c
index 1f76268934..7d343dd91e 100644
--- a/erts/emulator/hipe/hipe_native_bif.c
+++ b/erts/emulator/hipe/hipe_native_bif.c
@@ -41,8 +41,7 @@
*/
/* for -Wmissing-prototypes :-( */
-extern Eterm hipe_check_process_code_2(BIF_ALIST_2);
-extern Eterm hipe_garbage_collect_1(BIF_ALIST_1);
+extern Eterm hipe_erts_internal_check_process_code_2(BIF_ALIST_2);
extern Eterm hipe_show_nstack_1(BIF_ALIST_1);
/* Used when a BIF can trigger a stack walk. */
@@ -51,22 +50,12 @@ static __inline__ void hipe_set_narity(Process *p, unsigned int arity)
p->hipe.narity = arity;
}
-Eterm hipe_check_process_code_2(BIF_ALIST_2)
+Eterm hipe_erts_internal_check_process_code_2(BIF_ALIST_2)
{
Eterm ret;
hipe_set_narity(BIF_P, 2);
- ret = check_process_code_2(BIF_P, BIF__ARGS);
- hipe_set_narity(BIF_P, 0);
- return ret;
-}
-
-Eterm hipe_garbage_collect_1(BIF_ALIST_1)
-{
- Eterm ret;
-
- hipe_set_narity(BIF_P, 1);
- ret = garbage_collect_1(BIF_P, BIF__ARGS);
+ ret = erts_internal_check_process_code_2(BIF_P, BIF__ARGS);
hipe_set_narity(BIF_P, 0);
return ret;
}
diff --git a/erts/emulator/sys/common/erl_mmap.c b/erts/emulator/sys/common/erl_mmap.c
index a9da7430fb..3f6813e1a5 100644
--- a/erts/emulator/sys/common/erl_mmap.c
+++ b/erts/emulator/sys/common/erl_mmap.c
@@ -2057,7 +2057,7 @@ static struct {
Eterm scs;
Eterm sco;
Eterm scrpm;
- Eterm scmgc;
+ Eterm scrfsd;
int is_initialized;
erts_mtx_t init_mutex;
@@ -2090,7 +2090,7 @@ static void init_atoms(void)
AM_INIT(scs);
AM_INIT(sco);
AM_INIT(scrpm);
- AM_INIT(scmgc);
+ AM_INIT(scrfsd);
am.is_initialized = 1;
}
erts_mtx_unlock(&am.init_mutex);
@@ -2121,7 +2121,7 @@ erts_mmap_init(ErtsMMapInit *init)
#if defined(HARD_DEBUG) || 0
erts_fprintf(stderr, "erts_mmap: scs = %bpu\n", init->scs);
erts_fprintf(stderr, "erts_mmap: sco = %i\n", init->sco);
- erts_fprintf(stderr, "erts_mmap: scmgc = %i\n", init->scmgc);
+ erts_fprintf(stderr, "erts_mmap: scrfsd = %i\n", init->scrfsd);
#endif
erts_page_inv_mask = pagesize - 1;
if (pagesize & erts_page_inv_mask)
@@ -2234,7 +2234,7 @@ erts_mmap_init(ErtsMMapInit *init)
mmap_state.no_os_mmap = init->sco;
- desc_size = init->scmgc;
+ desc_size = init->scrfsd;
if (desc_size < 100)
desc_size = 100;
desc_size *= sizeof(ErtsFreeSegDesc);
@@ -2418,7 +2418,7 @@ Eterm erts_mmap_info_options(char *prefix,
if (mmap_state.supercarrier) {
erts_print(to, arg, "%ssco: %T\n", prefix, sco);
erts_print(to, arg, "%sscrpm: %T\n", prefix, scrpm);
- erts_print(to, arg, "%sscmgc: %beu\n", prefix, mmap_state.desc.reserved);
+ erts_print(to, arg, "%sscrfsd: %beu\n", prefix, mmap_state.desc.reserved);
}
}
@@ -2429,7 +2429,7 @@ Eterm erts_mmap_info_options(char *prefix,
res = NIL;
if (mmap_state.supercarrier) {
- add_2tup(hpp, szp, &res, am.scmgc,
+ add_2tup(hpp, szp, &res, am.scrfsd,
erts_bld_uint(hpp,szp, mmap_state.desc.reserved));
add_2tup(hpp, szp, &res, am.scrpm, scrpm);
add_2tup(hpp, szp, &res, am.sco, sco);
diff --git a/erts/emulator/sys/common/erl_mmap.h b/erts/emulator/sys/common/erl_mmap.h
index e6934dbb26..778a8e0e80 100644
--- a/erts/emulator/sys/common/erl_mmap.h
+++ b/erts/emulator/sys/common/erl_mmap.h
@@ -45,8 +45,8 @@ typedef struct {
} predefined_area;
UWord scs; /* super carrier size */
int sco; /* super carrier only? */
- Uint scmgc; /* super carrier: max guaranteed (number of) carriers */
- int scrpm;
+ UWord scrfsd; /* super carrier reserved free segment descriptors */
+ int scrpm; /* super carrier reserve physical memory */
}ErtsMMapInit;
#define ERTS_MMAP_INIT_DEFAULT_INITER \
diff --git a/erts/emulator/sys/common/erl_poll.c b/erts/emulator/sys/common/erl_poll.c
index 7676d8872a..0a58a625b2 100644
--- a/erts/emulator/sys/common/erl_poll.c
+++ b/erts/emulator/sys/common/erl_poll.c
@@ -2510,7 +2510,8 @@ ERTS_POLL_EXPORT(erts_poll_destroy_pollset)(ErtsPollSet ps)
pollsets = pollsets->next;
else {
ErtsPollSet prev_ps;
- for (prev_ps = pollsets; ps != prev_ps->next; prev_ps = prev_ps->next);
+ for (prev_ps = pollsets; ps != prev_ps->next; prev_ps = prev_ps->next)
+ ;
ASSERT(ps == prev_ps->next);
prev_ps->next = ps->next;
}
diff --git a/erts/emulator/sys/unix/sys.c b/erts/emulator/sys/unix/sys.c
index 401b37b9d2..61f9f6a59a 100644
--- a/erts/emulator/sys/unix/sys.c
+++ b/erts/emulator/sys/unix/sys.c
@@ -2489,6 +2489,16 @@ erts_sys_getenv(char *key, char *value, size_t *size)
return res;
}
+int
+erts_sys_unsetenv(char *key)
+{
+ int res;
+ erts_smp_rwmtx_rwlock(&environ_rwmtx);
+ res = unsetenv(key);
+ erts_smp_rwmtx_rwunlock(&environ_rwmtx);
+ return res;
+}
+
void
sys_init_io(void)
{
diff --git a/erts/emulator/sys/win32/sys_env.c b/erts/emulator/sys/win32/sys_env.c
index 754f4c6e4c..9f977ad6c8 100644
--- a/erts/emulator/sys/win32/sys_env.c
+++ b/erts/emulator/sys/win32/sys_env.c
@@ -141,6 +141,24 @@ void fini_getenv_state(GETENV_STATE *state)
erts_smp_rwmtx_runlock(&environ_rwmtx);
}
+int erts_sys_unsetenv(char *key)
+{
+ int res = 0;
+ WCHAR *wkey = (WCHAR *) key;
+
+ SetLastError(0);
+ erts_smp_rwmtx_rlock(&environ_rwmtx);
+ GetEnvironmentVariableW(wkey,
+ NULL,
+ 0);
+ if (GetLastError() != ERROR_ENVVAR_NOT_FOUND) {
+ res = (SetEnvironmentVariableW(wkey,
+ NULL) ? 0 : 1);
+ }
+ erts_smp_rwmtx_runlock(&environ_rwmtx);
+ return res;
+}
+
char*
win_build_environment(char* new_env)
{
diff --git a/erts/emulator/test/alloc_SUITE.erl b/erts/emulator/test/alloc_SUITE.erl
index f6ff6bb813..35c44c229a 100644
--- a/erts/emulator/test/alloc_SUITE.erl
+++ b/erts/emulator/test/alloc_SUITE.erl
@@ -114,8 +114,8 @@ cpool(Cfg) -> ?line drv_case(Cfg).
erts_mmap(Config) when is_list(Config) ->
case {?t:os_type(), is_halfword_vm()} of
{{unix, _}, false} ->
- [erts_mmap_do(Config, SCO, SCRPM, SCMGC)
- || SCO <-[true,false], SCMGC <-[1234,0], SCRPM <- [true,false]];
+ [erts_mmap_do(Config, SCO, SCRPM, SCRFSD)
+ || SCO <-[true,false], SCRFSD <-[1234,0], SCRPM <- [true,false]];
{_,true} ->
{skipped, "No supercarrier support on halfword vm"};
@@ -126,14 +126,19 @@ erts_mmap(Config) when is_list(Config) ->
end.
-erts_mmap_do(Config, SCO, SCRPM, SCMGC) ->
- SCS = 100, % Mb
+erts_mmap_do(Config, SCO, SCRPM, SCRFSD) ->
+ %% We use the number of schedulers + 1 * approx main carriers size
+ %% to calculate how large the super carrier has to be
+ %% and then use a minimum of 100 for systems with a low amount of
+ %% schedulers
+ Schldr = erlang:system_info(schedulers_online)+1,
+ SCS = max(round((262144 * 6 + 3 * 1048576) * Schldr / 1024 / 1024),100),
O1 = "+MMscs" ++ integer_to_list(SCS)
++ " +MMsco" ++ atom_to_list(SCO)
++ " +MMscrpm" ++ atom_to_list(SCRPM),
- Opts = case SCMGC of
+ Opts = case SCRFSD of
0 -> O1;
- _ -> O1 ++ " +MMscmgc"++integer_to_list(SCMGC)
+ _ -> O1 ++ " +MMscrfsd"++integer_to_list(SCRFSD)
end,
{ok, Node} = start_node(Config, Opts),
Self = self(),
@@ -148,7 +153,7 @@ erts_mmap_do(Config, SCO, SCRPM, SCMGC) ->
Total = SCS*1024*1024,
{reserved,Reserved} = lists:keyfind(reserved,1,Segs),
- true = (Reserved >= SCMGC),
+ true = (Reserved >= SCRFSD),
case {SCO,lists:keyfind(os,1,EM)} of
{true, false} -> ok;
diff --git a/erts/emulator/test/bif_SUITE.erl b/erts/emulator/test/bif_SUITE.erl
index 02c6de8cb1..fbc229bc53 100644
--- a/erts/emulator/test/bif_SUITE.erl
+++ b/erts/emulator/test/bif_SUITE.erl
@@ -388,8 +388,12 @@ os_env(Config) when is_list(Config) ->
false -> ?line ok;
BadVal -> ?line ?t:fail(BadVal)
end,
- %% os:putenv and os:getenv currently uses a temp buf of size 1024
- %% for storing key+value
+ true = os:putenv(EnvVar1, "mors"),
+ true = os:unsetenv(EnvVar1),
+ false = os:getenv(EnvVar1),
+ true = os:unsetenv(EnvVar1), % unset unset variable
+ %% os:putenv, os:getenv and os:unsetenv currently use a temp
+ %% buffer of size 1024 for storing key+value
?line os_env_long(1010, 1030, "hej hopp").
os_env_long(Min, Max, _Value) when Min > Max ->
@@ -398,7 +402,7 @@ os_env_long(Min, Max, Value) ->
?line EnvVar = lists:duplicate(Min, $X),
?line true = os:putenv(EnvVar, Value),
?line Value = os:getenv(EnvVar),
- ?line true = os:putenv(EnvVar, ""),
+ true = os:unsetenv(EnvVar),
?line os_env_long(Min+1, Max, Value).
otp_7526(doc) ->
diff --git a/erts/emulator/test/binary_SUITE.erl b/erts/emulator/test/binary_SUITE.erl
index 08ab094019..bce4278337 100644
--- a/erts/emulator/test/binary_SUITE.erl
+++ b/erts/emulator/test/binary_SUITE.erl
@@ -447,26 +447,26 @@ terms(Config) when is_list(Config) ->
Sz1 when is_integer(Sz1), size(Bin1) =< Sz1 ->
ok
end,
- Term = binary_to_term(Bin),
- Term = binary_to_term(Bin, [safe]),
+ Term = binary_to_term_stress(Bin),
+ Term = binary_to_term_stress(Bin, [safe]),
Unaligned = make_unaligned_sub_binary(Bin),
- Term = binary_to_term(Unaligned),
- Term = binary_to_term(Unaligned, []),
- Term = binary_to_term(Bin, [safe]),
+ Term = binary_to_term_stress(Unaligned),
+ Term = binary_to_term_stress(Unaligned, []),
+ Term = binary_to_term_stress(Bin, [safe]),
BinC = erlang:term_to_binary(Term, [compressed]),
- Term = binary_to_term(BinC),
+ Term = binary_to_term_stress(BinC),
true = size(BinC) =< size(Bin),
Bin = term_to_binary(Term, [{compressed,0}]),
terms_compression_levels(Term, size(Bin), 1),
UnalignedC = make_unaligned_sub_binary(BinC),
- Term = binary_to_term(UnalignedC)
+ Term = binary_to_term_stress(UnalignedC)
end,
?line test_terms(TestFun),
ok.
terms_compression_levels(Term, UncompressedSz, Level) when Level < 10 ->
BinC = erlang:term_to_binary(Term, [{compressed,Level}]),
- Term = binary_to_term(BinC),
+ Term = binary_to_term_stress(BinC),
Sz = byte_size(BinC),
true = Sz =< UncompressedSz,
terms_compression_levels(Term, UncompressedSz, Level+1);
@@ -476,9 +476,9 @@ terms_float(Config) when is_list(Config) ->
?line test_floats(fun(Term) ->
Bin0 = term_to_binary(Term),
Bin0 = term_to_binary(Term, [{minor_version,0}]),
- Term = binary_to_term(Bin0),
+ Term = binary_to_term_stress(Bin0),
Bin1 = term_to_binary(Term, [{minor_version,1}]),
- Term = binary_to_term(Bin1),
+ Term = binary_to_term_stress(Bin1),
true = size(Bin1) < size(Bin0),
Size0 = erlang:external_size(Term),
Size00 = erlang:external_size(Term, [{minor_version, 0}]),
@@ -490,7 +490,7 @@ terms_float(Config) when is_list(Config) ->
float_middle_endian(Config) when is_list(Config) ->
%% Testing for roundtrip is not enough.
?line <<131,70,63,240,0,0,0,0,0,0>> = term_to_binary(1.0, [{minor_version,1}]),
- ?line 1.0 = binary_to_term(<<131,70,63,240,0,0,0,0,0,0>>).
+ ?line 1.0 = binary_to_term_stress(<<131,70,63,240,0,0,0,0,0,0>>).
external_size(Config) when is_list(Config) ->
%% Build a term whose external size only fits in a big num (on 32-bit CPU).
@@ -608,10 +608,10 @@ bad_binary_to_term(Config) when is_list(Config) ->
ok.
bad_bin_to_term(BadBin) ->
- {'EXIT',{badarg,_}} = (catch binary_to_term(BadBin)).
+ {'EXIT',{badarg,_}} = (catch binary_to_term_stress(BadBin)).
bad_bin_to_term(BadBin,Opts) ->
- {'EXIT',{badarg,_}} = (catch binary_to_term(BadBin,Opts)).
+ {'EXIT',{badarg,_}} = (catch binary_to_term_stress(BadBin,Opts)).
safe_binary_to_term2(doc) -> "Test safety options for binary_to_term/2";
safe_binary_to_term2(Config) when is_list(Config) ->
@@ -622,7 +622,7 @@ safe_binary_to_term2(Config) when is_list(Config) ->
BadRef = <<131,114,0,3,BadHostAtom/binary,0,<<0,0,0,255>>/binary,
Empty/binary,Empty/binary>>,
?line bad_bin_to_term(BadRef, [safe]), % good ref, with a bad atom
- ?line fullsweep_after = binary_to_term(<<131,100,0,15,"fullsweep_after">>, [safe]), % should be a good atom
+ ?line fullsweep_after = binary_to_term_stress(<<131,100,0,15,"fullsweep_after">>, [safe]), % should be a good atom
BadExtFun = <<131,113,100,0,4,98,108,117,101,100,0,4,109,111,111,110,97,3>>,
?line bad_bin_to_term(BadExtFun, [safe]),
ok.
@@ -631,7 +631,13 @@ safe_binary_to_term2(Config) when is_list(Config) ->
bad_terms(suite) -> [];
bad_terms(Config) when is_list(Config) ->
- ?line test_terms(fun corrupter/1).
+ ?line test_terms(fun corrupter/1),
+ {'EXIT',{badarg,_}} = (catch binary_to_term(<<131,$M,3:32,0,11,22,33>>)),
+ {'EXIT',{badarg,_}} = (catch binary_to_term(<<131,$M,3:32,9,11,22,33>>)),
+ {'EXIT',{badarg,_}} = (catch binary_to_term(<<131,$M,0:32,1,11,22,33>>)),
+ {'EXIT',{badarg,_}} = (catch binary_to_term(<<131,$M,-1:32,1,11,22,33>>)),
+ ok.
+
corrupter(Term) when is_function(Term);
is_function(hd(Term));
@@ -673,14 +679,14 @@ corrupter0(Term) ->
corrupter(Bin, Pos) when Pos >= 0 ->
?line {ShorterBin, Rest} = split_binary(Bin, Pos),
- ?line catch binary_to_term(ShorterBin), %% emulator shouldn't crash
+ ?line catch binary_to_term_stress(ShorterBin), %% emulator shouldn't crash
?line MovedBin = list_to_binary([ShorterBin]),
- ?line catch binary_to_term(MovedBin), %% emulator shouldn't crash
+ ?line catch binary_to_term_stress(MovedBin), %% emulator shouldn't crash
%% Bit faults, shouldn't crash
<<Byte,Tail/binary>> = Rest,
Fun = fun(M) -> FaultyByte = Byte bxor M,
- catch binary_to_term(<<ShorterBin/binary,
+ catch binary_to_term_stress(<<ShorterBin/binary,
FaultyByte, Tail/binary>>) end,
?line lists:foreach(Fun,[1,2,4,8,16,32,64,128,255]),
?line corrupter(Bin, Pos-1);
@@ -694,7 +700,7 @@ more_bad_terms(Config) when is_list(Config) ->
?line ok = io:format("File: ~s\n", [BadFile]),
?line case file:read_file(BadFile) of
{ok,Bin} ->
- ?line {'EXIT',{badarg,_}} = (catch binary_to_term(Bin)),
+ ?line {'EXIT',{badarg,_}} = (catch binary_to_term_stress(Bin)),
ok;
Other ->
?line ?t:fail(Other)
@@ -703,7 +709,7 @@ more_bad_terms(Config) when is_list(Config) ->
otp_5484(Config) when is_list(Config) ->
?line {'EXIT',_} =
(catch
- binary_to_term(
+ binary_to_term_stress(
<<131,
104,2, %Tuple, 2 elements
103, %Pid
@@ -716,7 +722,7 @@ otp_5484(Config) when is_list(Config) ->
?line {'EXIT',_} =
(catch
- binary_to_term(
+ binary_to_term_stress(
<<131,
104,2, %Tuple, 2 elements
103, %Pid
@@ -728,13 +734,13 @@ otp_5484(Config) when is_list(Config) ->
?line {'EXIT',_} =
(catch
- binary_to_term(
+ binary_to_term_stress(
%% A old-type fun in a list containing a bad creator pid.
<<131,108,0,0,0,1,117,0,0,0,0,103,100,0,13,110,111,110,111,100,101,64,110,111,104,111,115,116,255,255,0,25,255,0,0,0,0,100,0,1,116,97,0,98,6,142,121,72,106>>)),
?line {'EXIT',_} =
(catch
- binary_to_term(
+ binary_to_term_stress(
%% A new-type fun in a list containing a bad creator pid.
%%
<<131,
@@ -746,7 +752,7 @@ otp_5484(Config) when is_list(Config) ->
?line {'EXIT',_} =
(catch
- binary_to_term(
+ binary_to_term_stress(
%% A new-type fun in a list containing a bad module.
<<131,
108,0,0,0,1, %List, 1 element
@@ -757,7 +763,7 @@ otp_5484(Config) when is_list(Config) ->
?line {'EXIT',_} =
(catch
- binary_to_term(
+ binary_to_term_stress(
%% A new-type fun in a list containing a bad index.
<<131,
108,0,0,0,1, %List, 1 element
@@ -769,7 +775,7 @@ otp_5484(Config) when is_list(Config) ->
?line {'EXIT',_} =
(catch
- binary_to_term(
+ binary_to_term_stress(
%% A new-type fun in a list containing a bad unique value.
<<131,
108,0,0,0,1, %List, 1 element
@@ -782,46 +788,46 @@ otp_5484(Config) when is_list(Config) ->
%% An absurdly large atom.
?line {'EXIT',_} =
- (catch binary_to_term(iolist_to_binary([<<131,100,65000:16>>|
+ (catch binary_to_term_stress(iolist_to_binary([<<131,100,65000:16>>|
lists:duplicate(65000, 42)]))),
%% Longer than 255 characters.
?line {'EXIT',_} =
- (catch binary_to_term(iolist_to_binary([<<131,100,256:16>>|
+ (catch binary_to_term_stress(iolist_to_binary([<<131,100,256:16>>|
lists:duplicate(256, 42)]))),
%% OTP-7218. Thanks to Matthew Dempsky. Also make sure that we
%% cover the other error cases for external funs (EXPORT_EXT).
?line {'EXIT',_} =
- (catch binary_to_term(
+ (catch binary_to_term_stress(
<<131,
113, %EXPORT_EXP
97,13, %Integer: 13
97,13, %Integer: 13
97,13>>)), %Integer: 13
?line {'EXIT',_} =
- (catch binary_to_term(
+ (catch binary_to_term_stress(
<<131,
113, %EXPORT_EXP
100,0,1,64, %Atom: '@'
97,13, %Integer: 13
97,13>>)), %Integer: 13
?line {'EXIT',_} =
- (catch binary_to_term(
+ (catch binary_to_term_stress(
<<131,
113, %EXPORT_EXP
100,0,1,64, %Atom: '@'
100,0,1,64, %Atom: '@'
106>>)), %NIL
?line {'EXIT',_} =
- (catch binary_to_term(
+ (catch binary_to_term_stress(
<<131,
113, %EXPORT_EXP
100,0,1,64, %Atom: '@'
100,0,1,64, %Atom: '@'
98,255,255,255,255>>)), %Integer: -1
?line {'EXIT',_} =
- (catch binary_to_term(
+ (catch binary_to_term_stress(
<<131,
113, %EXPORT_EXP
100,0,1,64, %Atom: '@'
@@ -829,7 +835,7 @@ otp_5484(Config) when is_list(Config) ->
113,97,13,97,13,97,13>>)), %fun 13:13/13
%% Bad funs.
- ?line {'EXIT',_} = (catch binary_to_term(fake_fun(0, lists:seq(0, 256)))),
+ ?line {'EXIT',_} = (catch binary_to_term_stress(fake_fun(0, lists:seq(0, 256)))),
ok.
fake_fun(Arity, Env0) ->
@@ -863,7 +869,7 @@ try_bad_lengths(B) ->
try_bad_lengths(B, L) when L > 16#FFFFFFF0 ->
Bin = <<B/binary,L:32>>,
io:format("~p\n", [Bin]),
- {'EXIT',_} = (catch binary_to_term(Bin)),
+ {'EXIT',_} = (catch binary_to_term_stress(Bin)),
try_bad_lengths(B, L-1);
try_bad_lengths(_, _) -> ok.
@@ -917,7 +923,7 @@ otp_6817_try_bin(Bin) ->
%% If the bug is present, the heap pointer will moved when the invalid term
%% is found and we will have a linked list passing through the limbo area
%% between the heap top and the stack pointer.
- catch binary_to_term(Bin),
+ catch binary_to_term_stress(Bin),
%% If the bug is present, we will overwrite the pointers in the limbo area.
Filler = erlang:make_tuple(1024, 16#3FA),
@@ -929,7 +935,7 @@ otp_6817_try_bin(Bin) ->
otp_8117(doc) -> "Some bugs in binary_to_term when 32-bit integers are negative.";
otp_8117(suite) -> [];
otp_8117(Config) when is_list(Config) ->
- [otp_8117_do(Op,-(1 bsl N)) || Op <- ['fun',list,tuple],
+ [otp_8117_do(Op,-(1 bsl N)) || Op <- ['fun',named_fun,list,tuple],
N <- lists:seq(0,31)],
ok.
@@ -938,6 +944,11 @@ otp_8117_do('fun',Neg) ->
FunBin = term_to_binary(fun() -> ok end),
?line <<B1:27/binary,_NumFree:32,Rest/binary>> = FunBin,
?line bad_bin_to_term(<<B1/binary,Neg:32,Rest/binary>>);
+otp_8117_do(named_fun,Neg) ->
+ % Named fun with negative num_free
+ FunBin = term_to_binary(fun F() -> F end),
+ ?line <<B1:27/binary,_NumFree:32,Rest/binary>> = FunBin,
+ ?line bad_bin_to_term(<<B1/binary,Neg:32,Rest/binary>>);
otp_8117_do(list,Neg) ->
%% List with negative length
?line bad_bin_to_term(<<131,104,2,108,Neg:32,97,11,104,1,97,12,97,13,106,97,14>>);
@@ -1221,18 +1232,13 @@ gc() ->
gc1() -> ok.
bit_sized_binary_sizes(Config) when is_list(Config) ->
- ?line [bsbs_1(A) || A <- lists:seq(0, 7)],
+ ?line [bsbs_1(A) || A <- lists:seq(1, 8)],
ok.
-bsbs_1(0) ->
- BinSize = 32+8,
- io:format("A: ~p BinSize: ~p", [0,BinSize]),
- Bin = binary_to_term(<<131,$M,5:32,0,0,0,0,0,0>>),
- BinSize = bit_size(Bin);
bsbs_1(A) ->
BinSize = 32+A,
io:format("A: ~p BinSize: ~p", [A,BinSize]),
- Bin = binary_to_term(<<131,$M,5:32,A,0,0,0,0,0>>),
+ Bin = binary_to_term_stress(<<131,$M,5:32,A,0,0,0,0,0>>),
BinSize = bit_size(Bin).
deep(Config) when is_list(Config) ->
@@ -1249,7 +1255,7 @@ deep(Config) when is_list(Config) ->
deep_roundtrip(T) ->
B = term_to_binary(T),
- T = binary_to_term(B).
+ T = binary_to_term_stress(B).
obsolete_funs(Config) when is_list(Config) ->
erts_debug:set_internal_state(available_internal_state, true),
@@ -1284,29 +1290,29 @@ obsolete_fun(Fun) ->
Tuple = no_fun_roundtrip(Fun).
no_fun_roundtrip(Term) ->
- binary_to_term(erts_debug:get_internal_state({term_to_binary_no_funs,Term})).
+ binary_to_term_stress(erts_debug:get_internal_state({term_to_binary_no_funs,Term})).
%% Test non-standard encodings never generated by term_to_binary/1
%% but recognized by binary_to_term/1.
robustness(Config) when is_list(Config) ->
- ?line [] = binary_to_term(<<131,107,0,0>>), %Empty string.
- ?line [] = binary_to_term(<<131,108,0,0,0,0,106>>), %Zero-length list.
+ ?line [] = binary_to_term_stress(<<131,107,0,0>>), %Empty string.
+ ?line [] = binary_to_term_stress(<<131,108,0,0,0,0,106>>), %Zero-length list.
%% {[],a} where [] is a zero-length list.
- ?line {[],a} = binary_to_term(<<131,104,2,108,0,0,0,0,106,100,0,1,97>>),
+ ?line {[],a} = binary_to_term_stress(<<131,104,2,108,0,0,0,0,106,100,0,1,97>>),
%% {42,a} where 42 is a zero-length list with 42 in the tail.
- ?line {42,a} = binary_to_term(<<131,104,2,108,0,0,0,0,97,42,100,0,1,97>>),
+ ?line {42,a} = binary_to_term_stress(<<131,104,2,108,0,0,0,0,97,42,100,0,1,97>>),
%% {{x,y},a} where {x,y} is a zero-length list with {x,y} in the tail.
- ?line {{x,y},a} = binary_to_term(<<131,104,2,108,0,0,0,0,
+ ?line {{x,y},a} = binary_to_term_stress(<<131,104,2,108,0,0,0,0,
104,2,100,0,1,120,100,0,1,
121,100,0,1,97>>),
%% Bignums fitting in 32 bits.
- ?line 16#7FFFFFFF = binary_to_term(<<131,98,127,255,255,255>>),
- ?line -1 = binary_to_term(<<131,98,255,255,255,255>>),
+ ?line 16#7FFFFFFF = binary_to_term_stress(<<131,98,127,255,255,255>>),
+ ?line -1 = binary_to_term_stress(<<131,98,255,255,255,255>>),
ok.
@@ -1324,7 +1330,7 @@ run_otp_8180(Name) ->
?line {ok,Bins} = file:consult(Name),
[begin
io:format("~p\n", [Bin]),
- ?line {'EXIT',{badarg,_}} = (catch binary_to_term(Bin))
+ ?line {'EXIT',{badarg,_}} = (catch binary_to_term_stress(Bin))
end || Bin <- Bins],
ok.
@@ -1393,3 +1399,52 @@ unaligned_sub_bin(Bin0, Offs) ->
Bin.
id(I) -> I.
+
+
+%% Stress binary_to_term with different initial reductions
+binary_to_term_stress(Bin) ->
+ binary_to_term_stress(Bin, no_opts).
+
+binary_to_term_stress(Bin, Opts) ->
+ Reds = get_reds(),
+ T = b2t(erlang:system_info(context_reductions),
+ Bin, Opts, catch_binary_to_term(Bin, Opts)),
+ set_reds(Reds),
+ T = case Opts of
+ no_opts -> binary_to_term(Bin);
+ _ -> binary_to_term(Bin,Opts)
+ end.
+
+catch_binary_to_term(Bin, no_opts) ->
+ try binary_to_term(Bin)
+ catch
+ error:badarg -> binary_to_term_throws_badarg
+ end;
+catch_binary_to_term(Bin, Opts) ->
+ try binary_to_term(Bin, Opts)
+ catch
+ error:badarg -> binary_to_term_throws_badarg
+ end.
+
+b2t(0, _Bin, _Opts, Term) ->
+ Term;
+b2t(Reds, Bin, Opts, Term) ->
+ set_reds(Reds),
+ Term = catch_binary_to_term(Bin,Opts),
+ b2t(Reds div 3, Bin, Opts, Term).
+
+set_reds(Reds) ->
+ try erts_debug:set_internal_state(reds_left, Reds)
+ catch
+ error:undef ->
+ erts_debug:set_internal_state(available_internal_state, true),
+ set_reds(Reds)
+ end.
+
+get_reds() ->
+ try erts_debug:get_internal_state(reds_left)
+ catch
+ error:undef ->
+ erts_debug:set_internal_state(available_internal_state, true),
+ get_reds()
+ end.
diff --git a/erts/emulator/test/code_parallel_load_SUITE.erl b/erts/emulator/test/code_parallel_load_SUITE.erl
index 1cfe015ea6..428f1242ab 100644
--- a/erts/emulator/test/code_parallel_load_SUITE.erl
+++ b/erts/emulator/test/code_parallel_load_SUITE.erl
@@ -159,22 +159,34 @@ setup_checkers(_,0) -> [];
setup_checkers(T,N) -> [spawn_link(fun() -> ?model:check(T) end) | setup_checkers(T, N-1)].
check_and_purge_processes_code(Pids, M) ->
- check_and_purge_processes_code(Pids, M, []).
-check_and_purge_processes_code([], M, []) ->
+ Tag = make_ref(),
+ N = request_cpc(Pids, M, Tag),
+ ok = handle_cpc_responses(N, Tag, M),
erlang:purge_module(M),
+ ok.
+
+request_cpc(Pid, M, Tag) when is_pid(Pid) ->
+ erlang:check_process_code(Pid, M, [{async, {Tag, Pid}}]),
+ 1;
+request_cpc(Pids, M, Tag) when is_list(Pids) ->
+ request_cpc(Pids, M, Tag, 0).
+
+request_cpc([], _M, _Tag, N) ->
+ N;
+request_cpc([Pid|Pids], M, Tag, N) ->
+ request_cpc(Pids, M, Tag, N + request_cpc(Pid, M, Tag)).
+
+handle_cpc_responses(0, _Tag, _Module) ->
ok;
-check_and_purge_processes_code([], M, Pending) ->
- io:format("Processes ~w are still executing old code - retrying.~n", [Pending]),
- check_and_purge_processes_code(Pending, M, []);
-check_and_purge_processes_code([Pid|Pids], M, Pending) ->
- case erlang:check_process_code(Pid, M) of
- false ->
- check_and_purge_processes_code(Pids, M, Pending);
- true ->
- check_and_purge_processes_code(Pids, M, [Pid|Pending])
+handle_cpc_responses(N, Tag, Module) ->
+ receive
+ {check_process_code, {Tag, _Pid}, false} ->
+ handle_cpc_responses(N-1, Tag, Module);
+ {check_process_code, {Tag, Pid}, true} ->
+ 1 = request_cpc(Pid, Module, Tag),
+ handle_cpc_responses(N, Tag, Module)
end.
-
generate(Module, Attributes, FunStrings) ->
FunForms = function_forms(FunStrings),
Forms = [
diff --git a/erts/emulator/test/fun_SUITE.erl b/erts/emulator/test/fun_SUITE.erl
index 36ba4e0f48..8ad5f290ed 100644
--- a/erts/emulator/test/fun_SUITE.erl
+++ b/erts/emulator/test/fun_SUITE.erl
@@ -262,6 +262,16 @@ equality(Config) when is_list(Config) ->
?line false = eq(FF2, FF4),
?line false = eq(FF3, FF4),
+ %% EEP37
+ H1 = fun Fact(N) when N > 0 -> N * Fact(N - 1); Fact(0) -> 1 end,
+ H2 = fun Pow(N, M) when M > 0 -> N * Pow(N, M - 1); Pow(_, 0) -> 1 end,
+ H1_copy = copy_term(H1),
+
+ true = eq(H1, H1),
+ true = eq(H1, H1_copy),
+ true = eq(H2, H2),
+ false = eq(H1, H2),
+
ok.
eq(X, X) -> true;
diff --git a/erts/emulator/test/hash_SUITE.erl b/erts/emulator/test/hash_SUITE.erl
index 50667d98ed..647bb45049 100644
--- a/erts/emulator/test/hash_SUITE.erl
+++ b/erts/emulator/test/hash_SUITE.erl
@@ -31,7 +31,7 @@
%%
-module(hash_SUITE).
-export([basic_test/0,cmp_test/1,range_test/0,spread_test/1,
- phash2_test/0, otp_5292_test/0, bit_level_binaries/0,
+ phash2_test/0, otp_5292_test/0,
otp_7127_test/0]).
-compile({nowarn_deprecated_function, {erlang,hash,2}}).
@@ -151,7 +151,7 @@ otp_5292(Config) when is_list(Config) ->
%% Test hashing bit-level binaries.
bit_level_binaries(Config) when is_list(Config) ->
- bit_level_binaries().
+ bit_level_binaries_do().
otp_7127(suite) ->
[];
@@ -536,7 +536,7 @@ hash_int(Start, End, F) ->
md5(T) ->
erlang:md5(term_to_binary(T)).
-bit_level_binaries() ->
+bit_level_binaries_do() ->
[3511317,7022633,14044578,28087749,56173436,112344123,90467083|_] =
bit_level_all_different(fun erlang:hash/2),
[3511317,7022633,14044578,28087749,56173436,112344123,90467083|_] =
diff --git a/erts/emulator/test/match_spec_SUITE.erl b/erts/emulator/test/match_spec_SUITE.erl
index b56b7ce525..bcc46d78ba 100644
--- a/erts/emulator/test/match_spec_SUITE.erl
+++ b/erts/emulator/test/match_spec_SUITE.erl
@@ -213,7 +213,7 @@ test_3(Config) when is_list(Config) ->
otp_9422(doc) -> [];
otp_9422(Config) when is_list(Config) ->
- Laps = 1000,
+ Laps = 10000,
?line Fun1 = fun() -> otp_9422_tracee() end,
?line P1 = spawn_link(?MODULE, loop_runner, [self(), Fun1, Laps]),
io:format("spawned ~p as tracee\n", [P1]),
@@ -230,7 +230,7 @@ otp_9422(Config) when is_list(Config) ->
%%receive after 10*1000 -> ok end,
stop_collect(P1),
- stop_collect(P2),
+ stop_collect(P2, abort),
ok.
otp_9422_tracee() ->
@@ -975,7 +975,9 @@ start_collect(P) ->
P ! {go, self()}.
stop_collect(P) ->
- P ! {done, self()},
+ stop_collect(P, done).
+stop_collect(P, Order) ->
+ P ! {Order, self()},
receive
{gone, P} ->
ok
@@ -1008,7 +1010,13 @@ loop_runner_cont(_Collector, _Fun, Laps, Laps) ->
end;
loop_runner_cont(Collector, Fun, N, Laps) ->
Fun(),
- loop_runner_cont(Collector, Fun, N+1, Laps).
+ receive
+ {abort, Collector} ->
+ io:format("loop_runner ~p aborted after ~p of ~p laps\n", [self(), N+1, Laps]),
+ Collector ! {gone, self()}
+ after 0 ->
+ loop_runner_cont(Collector, Fun, N+1, Laps)
+ end.
f1(X) ->
diff --git a/erts/emulator/test/process_SUITE.erl b/erts/emulator/test/process_SUITE.erl
index e3aae17df4..bf31655066 100644
--- a/erts/emulator/test/process_SUITE.erl
+++ b/erts/emulator/test/process_SUITE.erl
@@ -51,7 +51,13 @@
processes_term_proc_list/1,
otp_7738_waiting/1, otp_7738_suspended/1,
otp_7738_resume/1,
- garb_other_running/1]).
+ garb_other_running/1,
+ no_priority_inversion/1,
+ no_priority_inversion2/1,
+ system_task_blast/1,
+ system_task_on_suspended/1,
+ gc_request_when_gc_disabled/1,
+ gc_request_blast_when_gc_disabled/1]).
-export([prio_server/2, prio_client/2]).
-export([init_per_testcase/2, end_per_testcase/2]).
@@ -73,7 +79,8 @@ all() ->
bad_register, garbage_collect, process_info_messages,
process_flag_badarg, process_flag_heap_size,
spawn_opt_heap_size, otp_6237, {group, processes_bif},
- {group, otp_7738}, garb_other_running].
+ {group, otp_7738}, garb_other_running,
+ {group, system_task}].
groups() ->
[{t_exit_2, [],
@@ -87,7 +94,11 @@ groups() ->
processes_gc_trap, processes_term_proc_list]},
{otp_7738, [],
[otp_7738_waiting, otp_7738_suspended,
- otp_7738_resume]}].
+ otp_7738_resume]},
+ {system_task, [],
+ [no_priority_inversion, no_priority_inversion2,
+ system_task_blast, system_task_on_suspended,
+ gc_request_when_gc_disabled, gc_request_blast_when_gc_disabled]}].
init_per_suite(Config) ->
A0 = case application:start(sasl) of
@@ -2214,6 +2225,208 @@ garb_other_running(Config) when is_list(Config) ->
receive {'DOWN', Mon, process, Pid, normal} -> ok end,
ok.
+no_priority_inversion(Config) when is_list(Config) ->
+ Prio = process_flag(priority, max),
+ HTLs = lists:map(fun (_) ->
+ spawn_opt(fun () ->
+ tok_loop()
+ end,
+ [{priority, high}, monitor, link])
+ end,
+ lists:seq(1, 2*erlang:system_info(schedulers))),
+ receive after 500 -> ok end,
+ LTL = spawn_opt(fun () ->
+ tok_loop()
+ end,
+ [{priority, low}, monitor, link]),
+ false = erlang:check_process_code(element(1, LTL), nonexisting_module),
+ true = erlang:garbage_collect(element(1, LTL)),
+ lists:foreach(fun ({P, _}) ->
+ unlink(P),
+ exit(P, kill)
+ end, [LTL | HTLs]),
+ lists:foreach(fun ({P, M}) ->
+ receive
+ {'DOWN', M, process, P, killed} ->
+ ok
+ end
+ end, [LTL | HTLs]),
+ process_flag(priority, Prio),
+ ok.
+
+no_priority_inversion2(Config) when is_list(Config) ->
+ Prio = process_flag(priority, max),
+ MTLs = lists:map(fun (_) ->
+ spawn_opt(fun () ->
+ tok_loop()
+ end,
+ [{priority, max}, monitor, link])
+ end,
+ lists:seq(1, 2*erlang:system_info(schedulers))),
+ receive after 500 -> ok end,
+ {PL, ML} = spawn_opt(fun () ->
+ tok_loop()
+ end,
+ [{priority, low}, monitor, link]),
+ RL = request_gc(PL, low),
+ RN = request_gc(PL, normal),
+ RH = request_gc(PL, high),
+ receive
+ {garbage_collect, _, _} ->
+ ?t:fail(unexpected_gc)
+ after 1000 ->
+ ok
+ end,
+ RM = request_gc(PL, max),
+ receive
+ {garbage_collect, RM, true} ->
+ ok
+ end,
+ lists:foreach(fun ({P, _}) ->
+ unlink(P),
+ exit(P, kill)
+ end, MTLs),
+ lists:foreach(fun ({P, M}) ->
+ receive
+ {'DOWN', M, process, P, killed} ->
+ ok
+ end
+ end, MTLs),
+ receive
+ {garbage_collect, RH, true} ->
+ ok
+ end,
+ receive
+ {garbage_collect, RN, true} ->
+ ok
+ end,
+ receive
+ {garbage_collect, RL, true} ->
+ ok
+ end,
+ unlink(PL),
+ exit(PL, kill),
+ receive
+ {'DOWN', ML, process, PL, killed} ->
+ ok
+ end,
+ process_flag(priority, Prio),
+ ok.
+
+request_gc(Pid, Prio) ->
+ Ref = make_ref(),
+ erts_internal:request_system_task(Pid, Prio, {garbage_collect, Ref}),
+ Ref.
+
+system_task_blast(Config) when is_list(Config) ->
+ Me = self(),
+ GCReq = fun () ->
+ RL = gc_req(Me, 100),
+ lists:foreach(fun (R) ->
+ receive
+ {garbage_collect, R, true} ->
+ ok
+ end
+ end, RL),
+ exit(it_worked)
+ end,
+ HTLs = lists:map(fun (_) -> spawn_monitor(GCReq) end, lists:seq(1, 1000)),
+ lists:foreach(fun ({P, M}) ->
+ receive
+ {'DOWN', M, process, P, it_worked} ->
+ ok
+ end
+ end, HTLs),
+ ok.
+
+gc_req(_Pid, 0) ->
+ [];
+gc_req(Pid, N) ->
+ R0 = request_gc(Pid, low),
+ R1 = request_gc(Pid, normal),
+ R2 = request_gc(Pid, high),
+ R3 = request_gc(Pid, max),
+ [R0, R1, R2, R3 | gc_req(Pid, N-1)].
+
+system_task_on_suspended(Config) when is_list(Config) ->
+ {P, M} = spawn_monitor(fun () ->
+ tok_loop()
+ end),
+ true = erlang:suspend_process(P),
+ {status, suspended} = process_info(P, status),
+ true = erlang:garbage_collect(P),
+ {status, suspended} = process_info(P, status),
+ true = erlang:resume_process(P),
+ false = ({status, suspended} == process_info(P, status)),
+ exit(P, kill),
+ receive
+ {'DOWN', M, process, P, killed} ->
+ ok
+ end.
+
+gc_request_when_gc_disabled(Config) when is_list(Config) ->
+ Master = self(),
+ AIS = erts_debug:set_internal_state(available_internal_state, true),
+ {P, M} = spawn_opt(fun () ->
+ true = erts_debug:set_internal_state(gc_state,
+ false),
+ Master ! {self(), gc_state, false},
+ receive after 1000 -> ok end,
+ Master ! {self(), gc_state, true},
+ false = erts_debug:set_internal_state(gc_state,
+ true),
+ receive after 100 -> ok end
+ end, [monitor, link]),
+ receive {P, gc_state, false} -> ok end,
+ ReqId = make_ref(),
+ async = garbage_collect(P, [{async, ReqId}]),
+ receive
+ {garbage_collect, ReqId, Result} ->
+ ?t:fail({unexpected_gc, Result});
+ {P, gc_state, true} ->
+ 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.
+
+gc_request_blast_when_gc_disabled(Config) when is_list(Config) ->
+ Master = self(),
+ AIS = erts_debug:set_internal_state(available_internal_state, true),
+ {P, M} = spawn_opt(fun () ->
+ true = erts_debug:set_internal_state(gc_state,
+ false),
+ Master ! {self(), gc_state, false},
+ receive after 1000 -> ok end,
+ false = erts_debug:set_internal_state(gc_state,
+ true),
+ receive after 100 -> ok end
+ end, [monitor, link]),
+ receive {P, gc_state, false} -> ok end,
+ PMs = lists:map(fun (N) ->
+ Prio = case N rem 4 of
+ 0 -> max;
+ 1 -> high;
+ 2 -> normal;
+ 3 -> low
+ end,
+ spawn_opt(fun () ->
+ erlang:garbage_collect(P)
+ end, [monitor, link, {priority, Prio}])
+ end, lists:seq(1, 10000)),
+ lists:foreach(fun ({Proc, Mon}) ->
+ receive
+ {'DOWN', Mon, process, Proc, normal} ->
+ ok
+ end
+ end,
+ PMs),
+ erts_debug:set_internal_state(available_internal_state, AIS),
+ receive {'DOWN', M, process, P, _Reason} -> ok end,
+ ok.
+
+
%% Internal functions
wait_until(Fun) ->
diff --git a/erts/etc/common/erlexec.c b/erts/etc/common/erlexec.c
index f212502bb0..1d7811d570 100644
--- a/erts/etc/common/erlexec.c
+++ b/erts/etc/common/erlexec.c
@@ -103,14 +103,16 @@ static char *plusM_other_switches[] = {
"ea",
"ummc",
"uycs",
+ "usac",
"im",
"is",
"it",
+ "lpm",
"Mamcbf",
"Mrmcbf",
"Mmcs",
"Mscs",
- "Mscmgc",
+ "Mscrfsd",
"Msco",
"Mscrpm",
"Ye",
@@ -1970,8 +1972,35 @@ get_file_args(char *filename, argv_buf *abp, argv_buf *xabp)
}
static void
+write_erl_otp_flags(char *bufp)
+{
+ /* ERL_OTP<MAJOR-VSN>_FLAGS */
+ int ix = 0;
+ char *otp_p;
+ char otp[] = OTP_SYSTEM_VERSION;
+
+ bufp[ix++] = 'E';
+ bufp[ix++] = 'R';
+ bufp[ix++] = 'L';
+ bufp[ix++] = '_';
+ bufp[ix++] = 'O';
+ bufp[ix++] = 'T';
+ bufp[ix++] = 'P';
+ for (otp_p = &otp[0]; '0' <= *otp_p && *otp_p <= '9'; otp_p++)
+ bufp[ix++] = *otp_p;
+ bufp[ix++] = '_';
+ bufp[ix++] = 'F';
+ bufp[ix++] = 'L';
+ bufp[ix++] = 'A';
+ bufp[ix++] = 'G';
+ bufp[ix++] = 'S';
+ bufp[ix] = '\0';
+}
+
+static void
initial_argv_massage(int *argc, char ***argv)
{
+ char erl_otp_flags_buf[] = "ERL_OTP" OTP_SYSTEM_VERSION "_FLAGS";
argv_buf ab = {0}, xab = {0};
int ix, vix, ac;
char **av;
@@ -1987,7 +2016,8 @@ initial_argv_massage(int *argc, char ***argv)
vix = 0;
- av = build_args_from_env("ERL_" OTP_SYSTEM_VERSION "_FLAGS");
+ write_erl_otp_flags(erl_otp_flags_buf);
+ av = build_args_from_env(erl_otp_flags_buf);
if (av)
avv[vix++].argv = av;
diff --git a/erts/etc/unix/Install.src b/erts/etc/unix/Install.src
index 0f33258a28..8eb1db75bd 100644
--- a/erts/etc/unix/Install.src
+++ b/erts/etc/unix/Install.src
@@ -137,9 +137,9 @@ case $start_option in
esac
cp -p ../releases/%I_SYSTEM_VSN%/start_*.boot .
+cp -p ../releases/%I_SYSTEM_VSN%/no_dot_erlang.boot .
cp -p $Name.boot start.boot
cp -p ../releases/%I_SYSTEM_VSN%/$Name.script start.script
-
#
# Fixing the man pages
#
diff --git a/erts/etc/unix/cerl.src b/erts/etc/unix/cerl.src
index 38c6dd037f..be8343e87e 100644
--- a/erts/etc/unix/cerl.src
+++ b/erts/etc/unix/cerl.src
@@ -346,7 +346,7 @@ elif [ "x$GDB" = "xegdb" ]; then
case "x$core" in
x)
# Get emu args to use from erlexec...
- beam_args=`$EXEC -emu_args_exit ${1+"$@"}`
+ beam_args=`$EXEC -emu_args_exit ${1+"$@"} | tr '\n' ' '`
gdbcmd="(insert-string \"set args $beam_args\") \
(comint-send-input)"
;;
diff --git a/erts/etc/unix/etp-commands.in b/erts/etc/unix/etp-commands.in
index 54ff7b3e3a..73887931cc 100644
--- a/erts/etc/unix/etp-commands.in
+++ b/erts/etc/unix/etp-commands.in
@@ -1316,49 +1316,102 @@ end
define etp-proc-state-int
# Args: int
#
- if ($arg0 & 0xfffff000)
+ if ($arg0 & 0xff000000)
printf "GARBAGE | "
end
- if ($arg0 & 0x800)
+ if ($arg0 & 0x800000)
+ printf "delayed-sys | "
+ end
+ if ($arg0 & 0x400000)
+ printf "proxy | "
+ set $proxy_process = 1
+ else
+ set $proxy_process = 0
+ end
+ if ($arg0 & 0x200000)
+ printf "running-sys | "
+ end
+ if ($arg0 & 0x100000)
+ printf "active-sys | "
+ end
+ if ($arg0 & 0x80000)
printf "trapping-exit | "
end
- if ($arg0 & 0x400)
+ if ($arg0 & 0x40000)
printf "bound | "
end
- if ($arg0 & 0x200)
+ if ($arg0 & 0x20000)
printf "garbage-collecting | "
end
- if ($arg0 & 0x100)
+ if ($arg0 & 0x10000)
printf "suspended | "
end
- if ($arg0 & 0x80)
+ if ($arg0 & 0x8000)
printf "running | "
end
- if ($arg0 & 0x40)
+ if ($arg0 & 0x4000)
printf "in-run-queue | "
end
- if ($arg0 & 0x20)
+ if ($arg0 & 0x2000)
printf "active | "
end
- if ($arg0 & 0x10)
+ if ($arg0 & 0x1000)
printf "pending-exit | "
end
- if ($arg0 & 0x8)
+ if ($arg0 & 0x800)
printf "exiting | "
end
- if ($arg0 & 0x4)
+ if ($arg0 & 0x400)
printf "free | "
end
- if ($arg0 & 0x3) == 0
- printf "prio-max\n"
+ if ($arg0 & 0x200)
+ printf "in-prq-low | "
+ end
+ if ($arg0 & 0x100)
+ printf "in-prq-normal | "
+ end
+ if ($arg0 & 0x80)
+ printf "in-prq-high | "
+ end
+ if ($arg0 & 0x40)
+ printf "in-prq-max | "
+ end
+ if ($arg0 & 0x30) == 0x0
+ printf "prq-prio-max | "
+ else
+ if ($arg0 & 0x30) == 0x10
+ printf "prq-prio-high | "
+ else
+ if ($arg0 & 0x30) == 0x20
+ printf "prq-prio-normal | "
+ else
+ printf "prq-prio-low | "
+ end
+ end
+ end
+ if ($arg0 & 0xc) == 0x0
+ printf "usr-prio-max | "
+ else
+ if ($arg0 & 0xc) == 0x4
+ printf "usr-prio-high | "
+ else
+ if ($arg0 & 0xc) == 0x8
+ printf "usr-prio-normal | "
+ else
+ printf "usr-prio-low | "
+ end
+ end
+ end
+ if ($arg0 & 0x3) == 0x0
+ printf "act-prio-max\n"
else
- if ($arg0 & 0x3) == 1
- printf "prio-high\n"
+ if ($arg0 & 0x3) == 0x1
+ printf "act-prio-high\n"
else
- if ($arg0 & 0x3) == 2
- printf "prio-normal\n"
+ if ($arg0 & 0x3) == 0x2
+ printf "act-prio-normal\n"
else
- printf "prio-low\n"
+ printf "act-prio-low\n"
end
end
end
@@ -1395,6 +1448,12 @@ define etp-process-info
etp-1 $arg0->common.id
printf "\n State: "
etp-proc-state $arg0
+ if $proxy_process != 0
+ printf " Pointer: (Process *) %p\n", $arg0
+ printf " *** PROXY process struct *** refer to: \n"
+ etp-pid2proc-1 $arg0->common.id
+ etp-process-info $proc
+ else
if (*(((Uint32 *) &(((Process *) $arg0)->state))) & 0x4) == 0
if ($arg0->common.u.alive.reg)
printf " Registered name: "
@@ -1432,6 +1491,7 @@ define etp-process-info
printf " Parent: "
etp-1 $arg0->parent
printf "\n Pointer: (Process *) %p\n", $arg0
+ end
end
document etp-process-info
diff --git a/erts/etc/win32/Install.c b/erts/etc/win32/Install.c
index 59a5004662..500fd166f8 100644
--- a/erts/etc/win32/Install.c
+++ b/erts/etc/win32/Install.c
@@ -49,7 +49,7 @@ int wmain(int argc, wchar_t **argv)
wchar_t *binaries[] = { L"erl.exe", L"werl.exe", L"erlc.exe",
L"dialyzer.exe", L"typer.exe",
L"escript.exe", L"ct_run.exe", NULL };
- wchar_t *scripts[] = { L"start_clean.boot", L"start_sasl.boot", NULL };
+ wchar_t *scripts[] = { L"start_clean.boot", L"start_sasl.boot", L"no_dot_erlang.boot", NULL };
wchar_t fromname[MAX_PATH];
wchar_t toname[MAX_PATH];
size_t converted;
diff --git a/erts/preloaded/ebin/erl_prim_loader.beam b/erts/preloaded/ebin/erl_prim_loader.beam
index bfadc3c583..6b132dc38b 100644
--- a/erts/preloaded/ebin/erl_prim_loader.beam
+++ b/erts/preloaded/ebin/erl_prim_loader.beam
Binary files differ
diff --git a/erts/preloaded/ebin/erlang.beam b/erts/preloaded/ebin/erlang.beam
index 425effe7cd..73fac27161 100644
--- a/erts/preloaded/ebin/erlang.beam
+++ b/erts/preloaded/ebin/erlang.beam
Binary files differ
diff --git a/erts/preloaded/ebin/erts_internal.beam b/erts/preloaded/ebin/erts_internal.beam
index 9f92349803..12b36913a9 100644
--- a/erts/preloaded/ebin/erts_internal.beam
+++ b/erts/preloaded/ebin/erts_internal.beam
Binary files differ
diff --git a/erts/preloaded/ebin/init.beam b/erts/preloaded/ebin/init.beam
index 089f40de5b..758fe2cc23 100644
--- a/erts/preloaded/ebin/init.beam
+++ b/erts/preloaded/ebin/init.beam
Binary files differ
diff --git a/erts/preloaded/ebin/otp_ring0.beam b/erts/preloaded/ebin/otp_ring0.beam
index 4dbe6cc406..3fede5f0d9 100644
--- a/erts/preloaded/ebin/otp_ring0.beam
+++ b/erts/preloaded/ebin/otp_ring0.beam
Binary files differ
diff --git a/erts/preloaded/ebin/prim_eval.beam b/erts/preloaded/ebin/prim_eval.beam
index 6c7b7e5262..42c15f681f 100644
--- a/erts/preloaded/ebin/prim_eval.beam
+++ b/erts/preloaded/ebin/prim_eval.beam
Binary files differ
diff --git a/erts/preloaded/ebin/prim_file.beam b/erts/preloaded/ebin/prim_file.beam
index a1028c5480..d5a1ec766d 100644
--- a/erts/preloaded/ebin/prim_file.beam
+++ b/erts/preloaded/ebin/prim_file.beam
Binary files differ
diff --git a/erts/preloaded/ebin/prim_inet.beam b/erts/preloaded/ebin/prim_inet.beam
index deed86816e..90395a7564 100644
--- a/erts/preloaded/ebin/prim_inet.beam
+++ b/erts/preloaded/ebin/prim_inet.beam
Binary files differ
diff --git a/erts/preloaded/ebin/prim_zip.beam b/erts/preloaded/ebin/prim_zip.beam
index 7421599da0..e1aaa0f451 100644
--- a/erts/preloaded/ebin/prim_zip.beam
+++ b/erts/preloaded/ebin/prim_zip.beam
Binary files differ
diff --git a/erts/preloaded/ebin/zlib.beam b/erts/preloaded/ebin/zlib.beam
index 690b90adb5..5b51280838 100644
--- a/erts/preloaded/ebin/zlib.beam
+++ b/erts/preloaded/ebin/zlib.beam
Binary files differ
diff --git a/erts/preloaded/src/Makefile b/erts/preloaded/src/Makefile
index c1580b1495..4ea2d41075 100644
--- a/erts/preloaded/src/Makefile
+++ b/erts/preloaded/src/Makefile
@@ -68,7 +68,7 @@ KERNEL_SRC=$(ERL_TOP)/lib/kernel/src
KERNEL_INCLUDE=$(ERL_TOP)/lib/kernel/include
STDLIB_INCLUDE=$(ERL_TOP)/lib/stdlib/include
-ERL_COMPILE_FLAGS += +warn_obsolete_guard -I$(KERNEL_SRC) -I$(KERNEL_INCLUDE)
+ERL_COMPILE_FLAGS += +warn_obsolete_guard +debug_info -I$(KERNEL_SRC) -I$(KERNEL_INCLUDE)
debug opt: $(TARGET_FILES)
diff --git a/erts/preloaded/src/erl_prim_loader.erl b/erts/preloaded/src/erl_prim_loader.erl
index 81522e293a..4b9e901c6d 100644
--- a/erts/preloaded/src/erl_prim_loader.erl
+++ b/erts/preloaded/src/erl_prim_loader.erl
@@ -1439,7 +1439,12 @@ normalize(Name, Acc) ->
[Atom | Rest] when is_atom(Atom) ->
normalize(atom_to_list(Atom) ++ Rest, Acc);
[$\\ | Chars] ->
- normalize(Chars, [$/ | Acc]);
+ case erlang:system_info(os_type) of
+ {win32, _} ->
+ normalize(Chars, [$/ | Acc]);
+ _ ->
+ normalize(Chars, [$\\ | Acc])
+ end;
[Char | Chars] ->
normalize(Chars, [Char | Acc]);
[] ->
diff --git a/erts/preloaded/src/erlang.erl b/erts/preloaded/src/erlang.erl
index aae7048fce..0ed677c3d8 100644
--- a/erts/preloaded/src/erlang.erl
+++ b/erts/preloaded/src/erlang.erl
@@ -81,7 +81,8 @@
-export([binary_to_list/3, binary_to_term/1, binary_to_term/2]).
-export([bit_size/1, bitsize/1, bitstr_to_list/1, bitstring_to_list/1]).
-export([bump_reductions/1, byte_size/1, call_on_load_function/1]).
--export([cancel_timer/1, check_old_code/1, check_process_code/2, crc32/1]).
+-export([cancel_timer/1, check_old_code/1, check_process_code/2,
+ check_process_code/3, crc32/1]).
-export([crc32/2, crc32_combine/3, date/0, decode_packet/3]).
-export([delete_element/2]).
-export([delete_module/1, demonitor/1, demonitor/2, display/1]).
@@ -91,7 +92,7 @@
-export([float_to_binary/1, float_to_binary/2,
float_to_list/1, float_to_list/2]).
-export([fun_info/2, fun_to_list/1, function_exported/3]).
--export([garbage_collect/0, garbage_collect/1]).
+-export([garbage_collect/0, garbage_collect/1, garbage_collect/2]).
-export([garbage_collect_message_area/0, get/0, get/1, get_keys/1]).
-export([get_module_info/1, get_stacktrace/0, group_leader/0]).
-export([group_leader/2, halt/0, halt/1, halt/2, hash/2, hibernate/3]).
@@ -361,15 +362,25 @@ binary_to_list(_Binary, _Start, _Stop) ->
%% binary_to_term/1
-spec binary_to_term(Binary) -> term() when
Binary :: ext_binary().
-binary_to_term(_Binary) ->
- erlang:nif_error(undefined).
+binary_to_term(Binary) ->
+ %% This BIF may throw badarg while trapping
+ try
+ erts_internal:binary_to_term(Binary)
+ catch
+ error:Reason -> erlang:error(Reason,[Binary])
+ end.
%% binary_to_term/2
-spec binary_to_term(Binary, Opts) -> term() when
Binary :: ext_binary(),
Opts :: [safe].
-binary_to_term(_Binary, _Opts) ->
- erlang:nif_error(undefined).
+binary_to_term(Binary, Opts) ->
+ %% This BIF may throw badarg while trapping
+ try
+ erts_internal:binary_to_term(Binary,Opts)
+ catch
+ error:Reason -> erlang:error(Reason,[Binary,Opts])
+ end.
%% bit_size/1
%% Shadowed by erl_bif_types: erlang:bit_size/1
@@ -429,11 +440,71 @@ check_old_code(_Module) ->
erlang:nif_error(undefined).
%% check_process_code/2
--spec check_process_code(Pid, Module) -> boolean() when
+-spec check_process_code(Pid, Module) -> CheckResult when
Pid :: pid(),
- Module :: module().
-check_process_code(_Pid, _Module) ->
- erlang:nif_error(undefined).
+ Module :: module(),
+ CheckResult :: boolean().
+check_process_code(Pid, Module) ->
+ try
+ erlang:check_process_code(Pid, Module, [{allow_gc, true}])
+ catch
+ error:Error -> erlang:error(Error, [Pid, Module])
+ end.
+
+%% check_process_code/3
+-spec check_process_code(Pid, Module, OptionList) -> CheckResult | async when
+ Pid :: pid(),
+ Module :: module(),
+ RequestId :: term(),
+ Option :: {async, RequestId} | {allow_gc, boolean()},
+ OptionList :: [Option],
+ CheckResult :: boolean() | aborted.
+check_process_code(Pid, Module, OptionList) ->
+ try
+ {Async, AllowGC} = get_cpc_opts(OptionList, sync, true),
+ case Async of
+ {async, ReqId} ->
+ {priority, Prio} = erlang:process_info(erlang:self(),
+ priority),
+ erts_internal:request_system_task(Pid,
+ Prio,
+ {check_process_code,
+ ReqId,
+ Module,
+ AllowGC}),
+ async;
+ sync ->
+ case Pid == erlang:self() of
+ true ->
+ erts_internal:check_process_code(Module,
+ [{allow_gc, AllowGC}]);
+ false ->
+ {priority, Prio} = erlang:process_info(erlang:self(),
+ priority),
+ ReqId = erlang:make_ref(),
+ erts_internal:request_system_task(Pid,
+ Prio,
+ {check_process_code,
+ ReqId,
+ Module,
+ AllowGC}),
+ receive
+ {check_process_code, ReqId, CheckResult} ->
+ CheckResult
+ end
+ end
+ end
+ catch
+ error:Error -> erlang:error(Error, [Pid, Module, OptionList])
+ end.
+
+% gets async and allow_gc opts and verify valid option list
+get_cpc_opts([{async, _ReqId} = AsyncTuple | Options], _OldAsync, AllowGC) ->
+ get_cpc_opts(Options, AsyncTuple, AllowGC);
+get_cpc_opts([{allow_gc, AllowGC} | Options], Async, _OldAllowGC) ->
+ get_cpc_opts(Options, Async, AllowGC);
+get_cpc_opts([], Async, AllowGC) ->
+ {Async, AllowGC}.
%% crc32/1
-spec erlang:crc32(Data) -> non_neg_integer() when
@@ -793,10 +864,61 @@ garbage_collect() ->
erlang:nif_error(undefined).
%% garbage_collect/1
--spec garbage_collect(Pid) -> boolean() when
- Pid :: pid().
-garbage_collect(_Pid) ->
- erlang:nif_error(undefined).
+-spec garbage_collect(Pid) -> GCResult when
+ Pid :: pid(),
+ GCResult :: boolean().
+garbage_collect(Pid) ->
+ try
+ erlang:garbage_collect(Pid, [])
+ catch
+ error:Error -> erlang:error(Error, [Pid])
+ end.
+
+%% garbage_collect/2
+-spec garbage_collect(Pid, OptionList) -> GCResult | async when
+ Pid :: pid(),
+ RequestId :: term(),
+ Option :: {async, RequestId},
+ OptionList :: [Option],
+ GCResult :: boolean().
+garbage_collect(Pid, OptionList) ->
+ try
+ Async = get_gc_opts(OptionList, sync),
+ case Async of
+ {async, ReqId} ->
+ {priority, Prio} = erlang:process_info(erlang:self(),
+ priority),
+ erts_internal:request_system_task(Pid,
+ Prio,
+ {garbage_collect, ReqId}),
+ async;
+ sync ->
+ case Pid == erlang:self() of
+ true ->
+ erlang:garbage_collect();
+ false ->
+ {priority, Prio} = erlang:process_info(erlang:self(),
+ priority),
+ ReqId = erlang:make_ref(),
+ erts_internal:request_system_task(Pid,
+ Prio,
+ {garbage_collect,
+ ReqId}),
+ receive
+ {garbage_collect, ReqId, GCResult} ->
+ GCResult
+ end
+ end
+ end
+ catch
+ error:Error -> erlang:error(Error, [Pid, OptionList])
+ end.
+
+% gets async opt and verify valid option list
+get_gc_opts([{async, _ReqId} = AsyncTuple | Options], _OldAsync) ->
+ get_gc_opts(Options, AsyncTuple);
+get_gc_opts([], Async) ->
+ Async.
%% garbage_collect_message_area/0
-spec erlang:garbage_collect_message_area() -> boolean().
@@ -1073,8 +1195,8 @@ module_loaded(_Module) ->
%% monitor/2
-spec monitor(Type, Item) -> MonitorRef when
Type :: process,
- Item :: pid() | Module | {Module, Node},
- Module :: module(),
+ Item :: pid() | RegName | {RegName, Node},
+ RegName :: module(),
Node :: node(),
MonitorRef :: reference().
monitor(_Type, _Item) ->
diff --git a/erts/preloaded/src/erts_internal.erl b/erts/preloaded/src/erts_internal.erl
index 8a8cd52d64..d6a185482e 100644
--- a/erts/preloaded/src/erts_internal.erl
+++ b/erts/preloaded/src/erts_internal.erl
@@ -29,10 +29,14 @@
-module(erts_internal).
-export([await_port_send_result/3]).
-
+-export([binary_to_term/1, binary_to_term/2]).
-export([port_command/3, port_connect/2, port_close/1,
port_control/3, port_call/3, port_info/1, port_info/2]).
+-export([request_system_task/3]).
+
+-export([check_process_code/2]).
+
%%
%% Await result of send to port
%%
@@ -139,3 +143,30 @@ port_info(_Result) ->
port_info(_Result, _Item) ->
erlang:nif_error(undefined).
+
+-spec request_system_task(Pid, Prio, Request) -> 'ok' when
+ Prio :: 'max' | 'high' | 'normal' | 'low',
+ Request :: {'garbage_collect', term()}
+ | {'check_process_code', term(), module(), boolean()},
+ Pid :: pid().
+
+request_system_task(_Pid, _Prio, _Request) ->
+ erlang:nif_error(undefined).
+
+-spec check_process_code(Module, OptionList) -> boolean() when
+ Module :: module(),
+ Option :: {allow_gc, boolean()},
+ OptionList :: [Option].
+check_process_code(_Module, _OptionList) ->
+ erlang:nif_error(undefined).
+
+-spec binary_to_term(Binary) -> term() when
+ Binary :: binary().
+binary_to_term(_Binary) ->
+ erlang:nif_error(undefined).
+
+-spec binary_to_term(Binary, Opts) -> term() when
+ Binary :: binary(),
+ Opts :: [safe].
+binary_to_term(_Binary, _Opts) ->
+ erlang:nif_error(undefined).
diff --git a/erts/preloaded/src/prim_file.erl b/erts/preloaded/src/prim_file.erl
index 489e8ca4ea..5999e98340 100644
--- a/erts/preloaded/src/prim_file.erl
+++ b/erts/preloaded/src/prim_file.erl
@@ -123,9 +123,11 @@
-define(EFILE_MODE_APPEND, 4).
-define(EFILE_COMPRESSED, 8).
-define(EFILE_MODE_EXCL, 16).
+%% Note: bit 5 (32) is used internally for VxWorks
+-define(EFILE_MODE_SYNC, 64).
%% Use this mask to get just the mode bits to be passed to the driver.
--define(EFILE_MODE_MASK, 31).
+-define(EFILE_MODE_MASK, 127).
%% Seek modes for the driver's seek function.
-define(EFILE_SEEK_SET, 0).
@@ -1197,6 +1199,8 @@ open_mode([append|Rest], Mode, Portopts, Setopts) ->
Portopts, Setopts);
open_mode([exclusive|Rest], Mode, Portopts, Setopts) ->
open_mode(Rest, Mode bor ?EFILE_MODE_EXCL, Portopts, Setopts);
+open_mode([sync|Rest], Mode, Portopts, Setopts) ->
+ open_mode(Rest, Mode bor ?EFILE_MODE_SYNC, Portopts, Setopts);
open_mode([delayed_write|Rest], Mode, Portopts, Setopts) ->
open_mode([{delayed_write, 64*1024, 2000}|Rest], Mode,
Portopts, Setopts);
diff --git a/erts/preloaded/src/prim_inet.erl b/erts/preloaded/src/prim_inet.erl
index 69eed716ff..143c718130 100644
--- a/erts/preloaded/src/prim_inet.erl
+++ b/erts/preloaded/src/prim_inet.erl
@@ -41,8 +41,8 @@
getifaddrs/1, getiflist/1, ifget/3, ifset/3,
gethostname/1]).
-export([getservbyname/3, getservbyport/3]).
--export([peername/1, setpeername/2]).
--export([sockname/1, setsockname/2]).
+-export([peername/1, setpeername/2, peernames/1, peernames/2]).
+-export([sockname/1, setsockname/2, socknames/1, socknames/2]).
-export([attach/1, detach/1]).
-include("inet_sctp.hrl").
@@ -186,32 +186,8 @@ close_pend_loop(S, N) ->
end.
close_port(S) ->
- case erlang:process_info(self(), trap_exit) of
- {trap_exit,true} ->
- %% Ensure exit message and consume it
- link(S),
- %% This is still not a perfect solution.
- %%
- %% The problem is to close the port and consume any exit
- %% message while not knowing if this process traps exit
- %% nor if this process has a link to the port. Here we
- %% just knows that this process traps exit.
- %%
- %% If we right here get killed for some reason that exit
- %% signal will propagate to the port and onwards to anyone
- %% that is linked to the port. E.g when we close a socket
- %% that is not ours.
- %%
- %% The problem can be solved with lists:member on our link
- %% list but we deem that as potentially too expensive. We
- %% need an is_linked/1 function or guard, or we need
- %% a port_close function that can atomically unlink...
- catch erlang:port_close(S),
- receive {'EXIT',S,_} -> ok end;
- {trap_exit,false} ->
- catch erlang:port_close(S),
- ok
- end.
+ catch erlang:port_close(S),
+ receive {'EXIT',S,_} -> ok after 0 -> ok end.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%
@@ -576,6 +552,36 @@ setpeername(S, undefined) when is_port(S) ->
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%
+%% PEERNAMES(insock()) -> {ok, [{IP, Port}, ...]} | {error, Reason}
+%%
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+peernames(S) when is_port(S) ->
+ peernames(S, undefined).
+
+peernames(S, #sctp_assoc_change{assoc_id=AssocId}) when is_port(S) ->
+ peernames(S, AssocId);
+peernames(S, AssocId)
+ when is_port(S), is_integer(AssocId);
+ is_port(S), AssocId =:= undefined ->
+ Q = get,
+ Type = [[sctp_assoc_id,0]],
+ case type_value(Q, Type, AssocId) of
+ true ->
+ case ctl_cmd
+ (S, ?INET_REQ_GETPADDRS,
+ enc_value(Q, Type, AssocId)) of
+ {ok,Addrs} ->
+ {ok,get_addrs(Addrs)};
+ Error ->
+ Error
+ end;
+ false ->
+ {error,einval}
+ end.
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%%
%% SOCKNAME(insock()) -> {ok, {IP, Port}} | {error, Reason}
%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
@@ -601,6 +607,36 @@ setsockname(S, undefined) when is_port(S) ->
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%
+%% SOCKNAMES(insock()) -> {ok, [{IP, Port}, ...]} | {error, Reason}
+%%
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+socknames(S) when is_port(S) ->
+ socknames(S, undefined).
+
+socknames(S, #sctp_assoc_change{assoc_id=AssocId}) when is_port(S) ->
+ socknames(S, AssocId);
+socknames(S, AssocId)
+ when is_port(S), is_integer(AssocId);
+ is_port(S), AssocId =:= undefined ->
+ Q = get,
+ Type = [[sctp_assoc_id,0]],
+ case type_value(Q, Type, AssocId) of
+ true ->
+ case ctl_cmd
+ (S, ?INET_REQ_GETLADDRS,
+ enc_value(Q, Type, AssocId)) of
+ {ok,Addrs} ->
+ {ok,get_addrs(Addrs)};
+ Error ->
+ Error
+ end;
+ false ->
+ {error,einval}
+ end.
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%%
%% SETOPT(insock(), Opt, Value) -> ok | {error, Reason}
%% SETOPTS(insock(), [{Opt,Value}]) -> ok | {error, Reason}
%%
@@ -2225,6 +2261,12 @@ ip6_to_bytes({A,B,C,D,E,F,G,H}) ->
[?int16(A), ?int16(B), ?int16(C), ?int16(D),
?int16(E), ?int16(F), ?int16(G), ?int16(H)].
+get_addrs([]) ->
+ [];
+get_addrs([F,P1,P0|Addr]) ->
+ {IP,Addrs} = get_ip(F, Addr),
+ [{IP,?u16(P1, P0)}|get_addrs(Addrs)].
+
get_ip(?INET_AF_INET, Addr) -> get_ip4(Addr);
get_ip(?INET_AF_INET6, Addr) -> get_ip6(Addr).
diff --git a/erts/start_scripts/Makefile b/erts/start_scripts/Makefile
index 3bf233cbb6..32e65a227f 100644
--- a/erts/start_scripts/Makefile
+++ b/erts/start_scripts/Makefile
@@ -1,7 +1,7 @@
#
# %CopyrightBegin%
#
-# Copyright Ericsson AB 1997-2012. All Rights Reserved.
+# Copyright Ericsson AB 1997-2013. All Rights Reserved.
#
# The contents of this file are subject to the Erlang Public License,
# Version 1.1, (the "License"); you may not use this file except in
@@ -34,12 +34,16 @@ INSTALL_SCRIPTS = \
$(SS_ROOT)/start_clean.script \
$(SS_ROOT)/start_clean.boot \
$(SS_ROOT)/start_sasl.boot \
- $(SS_ROOT)/start_sasl.script
+ $(SS_ROOT)/start_sasl.script \
+ $(SS_ROOT)/no_dot_erlang.boot \
+ $(SS_ROOT)/no_dot_erlang.script
+
REL_SCRIPTS = \
$(SS_ROOT)/start_clean.rel \
$(SS_ROOT)/start_sasl.rel \
- $(SS_ROOT)/start_all_example.rel
+ $(SS_ROOT)/start_all_example.rel \
+ $(SS_ROOT)/no_dot_erlang.rel \
ifneq ($(findstring win32,$(TARGET)),win32)
RELEASES_SRC = RELEASES.src
@@ -82,6 +86,13 @@ $(SS_ROOT)/start_sasl.boot: $(SS_ROOT)/start_sasl.rel
$(V_at)( cd $(SS_TMP) && \
$(ERLC) $(SASL_FLAGS) $(SCRIPT_PATH) -o $(SS_ROOT) $< )
+$(SS_ROOT)/no_dot_erlang.script \
+$(SS_ROOT)/no_dot_erlang.boot: $(SS_ROOT)/no_dot_erlang.rel
+ $(gen_verbose)$(INSTALL_DIR) $(SS_TMP)
+ $(V_at)( cd $(SS_TMP) && \
+ $(ERLC) $(SASL_FLAGS) $(SCRIPT_PATH) +no_warn_sasl +no_dot_erlang -o $(SS_ROOT) $< )
+
+
$(SS_ROOT)/start_clean.rel: $(SS_ROOT)/start_clean.rel.src \
../vsn.mk \
$(LIBPATH)/kernel/vsn.mk \
@@ -104,6 +115,16 @@ $(SS_ROOT)/start_sasl.rel: $(SS_ROOT)/start_sasl.rel.src \
-e 's;%SASL_VSN%;$(SASL_VSN);' \
$(SS_ROOT)/start_sasl.rel.src > $(SS_ROOT)/start_sasl.rel
+$(SS_ROOT)/no_dot_erlang.rel: $(SS_ROOT)/no_dot_erlang.rel.src \
+ ../vsn.mk \
+ $(LIBPATH)/kernel/vsn.mk \
+ $(LIBPATH)/stdlib/vsn.mk
+ $(gen_verbose)sed -e 's;%SYS_VSN%;$(SYSTEM_VSN);' \
+ -e 's;%ERTS_VSN%;$(VSN);' \
+ -e 's;%KERNEL_VSN%;$(KERNEL_VSN);' \
+ -e 's;%STDLIB_VSN%;$(STDLIB_VSN);' \
+ $(SS_ROOT)/no_dot_erlang.rel.src > $(SS_ROOT)/no_dot_erlang.rel
+
$(SS_ROOT)/start_all_example.rel: $(SS_ROOT)/start_all_example.rel.src \
../vsn.mk \
$(LIBPATH)/kernel/vsn.mk \
@@ -140,7 +161,13 @@ $(ERL_TOP)/bin/start_clean.script:
$(V_at)( cd $(SS_TMP) && \
$(ERLC) $(SCRIPT_PATH) +no_warn_sasl +otp_build -o $@ $(SS_ROOT)/start_clean.rel )
+$(ERL_TOP)/bin/no_dot_erlang.script:
+ $(gen_verbose)$(INSTALL_DIR) $(SS_TMP)
+ $(V_at)( cd $(SS_TMP) && \
+ $(ERLC) $(SCRIPT_PATH) +no_warn_sasl +otp_build +no_dot_erlang -o $@ $(SS_ROOT)/no_dot_erlang.rel )
+
## Special target used from system/build/Makefile for source code release bootstrap.
+## Add no_dot_erlang after next release
bootstrap_scripts: $(SS_ROOT)/start_clean.rel
$(V_at)$(INSTALL_DIR) $(TESTROOT)/bin
$(V_at)$(INSTALL_DIR) $(SS_TMP)
diff --git a/erts/start_scripts/no_dot_erlang.rel.src b/erts/start_scripts/no_dot_erlang.rel.src
new file mode 100644
index 0000000000..03b64ebf1a
--- /dev/null
+++ b/erts/start_scripts/no_dot_erlang.rel.src
@@ -0,0 +1,21 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2013. All Rights Reserved.
+%%
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+%%
+{release, {"OTP APN 181 01","%SYS_VSN%"}, {erts, "%ERTS_VSN%"},
+ [{kernel,"%KERNEL_VSN%"},
+ {stdlib,"%STDLIB_VSN%"}]}.
diff --git a/erts/vsn.mk b/erts/vsn.mk
index 8baf169d6f..30aa870144 100644
--- a/erts/vsn.mk
+++ b/erts/vsn.mk
@@ -17,8 +17,8 @@
# %CopyrightEnd%
#
-VSN = 5.11
-SYSTEM_VSN = R17A
+VSN = 6.0
+SYSTEM_VSN = 17.0-rc0
# Port number 4365 in 4.2
# Port number 4366 in 4.3