summaryrefslogtreecommitdiff
path: root/erts
diff options
context:
space:
mode:
Diffstat (limited to 'erts')
-rw-r--r--erts/configure.in3
-rw-r--r--erts/doc/src/erl_cmd.xml7
-rw-r--r--erts/doc/src/erl_nif.xml58
-rw-r--r--erts/doc/src/escript_cmd.xml4
-rw-r--r--erts/doc/src/inet_cfg.xml13
-rw-r--r--erts/doc/src/notes.xml352
-rw-r--r--erts/emulator/beam/bif.c12
-rw-r--r--erts/emulator/beam/dist.c74
-rw-r--r--erts/emulator/beam/erl_alloc.types22
-rw-r--r--erts/emulator/beam/erl_map.c5
-rw-r--r--erts/emulator/beam/erl_monitor_link.c20
-rw-r--r--erts/emulator/beam/erl_monitor_link.h26
-rw-r--r--erts/emulator/beam/erl_nif.c9
-rw-r--r--erts/emulator/beam/erl_process.c50
-rw-r--r--erts/emulator/beam/erl_process.h1
-rw-r--r--erts/emulator/beam/erl_process_dict.c2
-rw-r--r--erts/emulator/beam/external.c8
-rw-r--r--erts/emulator/beam/external.h1
-rw-r--r--erts/emulator/beam/ops.tab3
-rw-r--r--erts/emulator/nifs/common/prim_file_nif.c8
-rw-r--r--erts/emulator/sys/common/erl_poll.c18
-rw-r--r--erts/emulator/sys/win32/erl_win_sys.h4
-rw-r--r--erts/emulator/test/bs_bincomp_SUITE.erl14
-rw-r--r--erts/emulator/test/distribution_SUITE.erl86
-rw-r--r--erts/emulator/test/driver_SUITE.erl79
-rw-r--r--erts/emulator/test/driver_SUITE_data/Makefile.src14
-rw-r--r--erts/emulator/test/driver_SUITE_data/lots_of_fds_used_wrapper.c61
-rw-r--r--erts/emulator/test/driver_SUITE_data/peek_non_existing_queue_drv.c4
-rw-r--r--erts/emulator/test/driver_SUITE_data/thr_msg_blast_drv.c4
-rw-r--r--erts/emulator/test/esock_misc/esock_iow_client.erl94
-rw-r--r--erts/emulator/test/esock_misc/esock_iow_lib.erl123
-rw-r--r--erts/emulator/test/esock_misc/esock_iow_server.erl83
-rw-r--r--erts/emulator/test/esock_misc/socket_client.erl538
-rw-r--r--erts/emulator/test/esock_misc/socket_lib.erl133
-rw-r--r--erts/emulator/test/esock_misc/socket_server.erl954
-rw-r--r--erts/emulator/test/esock_ttest/.gitignore0
-rwxr-xr-xerts/emulator/test/esock_ttest/esock-ttest382
-rwxr-xr-xerts/emulator/test/esock_ttest/esock-ttest-client92
-rwxr-xr-xerts/emulator/test/esock_ttest/esock-ttest-server-gen32
-rwxr-xr-xerts/emulator/test/esock_ttest/esock-ttest-server-sock56
-rw-r--r--erts/emulator/test/estone_SUITE_data/estone_cat.c8
-rw-r--r--erts/emulator/test/mtx_SUITE_data/mtx_SUITE.c1
-rw-r--r--erts/emulator/test/nif_SUITE.erl15
-rw-r--r--erts/emulator/test/nif_SUITE_data/nif_SUITE.c58
-rw-r--r--erts/emulator/test/num_bif_SUITE.erl45
-rw-r--r--erts/emulator/test/port_bif_SUITE_data/port_test.c3
-rw-r--r--erts/emulator/test/trace_SUITE_data/slow_drv.c6
-rwxr-xr-xerts/emulator/utils/make_driver_tab1
-rw-r--r--erts/emulator/valgrind/suppress.standard31
-rw-r--r--erts/etc/common/erlexec.c6
-rw-r--r--erts/etc/unix/etp-commands.in147
-rw-r--r--erts/etc/win32/erl.c5
-rw-r--r--erts/etc/win32/manifest.xml17
-rw-r--r--erts/etc/win32/nsis/erlang20.nsi14
-rw-r--r--erts/etc/win32/win_erlexec.c5
-rwxr-xr-xerts/etc/win32/wsl_tools/vc/ld.sh10
-rw-r--r--erts/lib_src/Makefile.in1
-rw-r--r--erts/vsn.mk2
58 files changed, 1131 insertions, 2693 deletions
diff --git a/erts/configure.in b/erts/configure.in
index 308e1288ba..12dfb9b19b 100644
--- a/erts/configure.in
+++ b/erts/configure.in
@@ -1903,8 +1903,9 @@ fi
if test "x$ac_compiler_gnu" = "xyes"; then
AC_MSG_CHECKING([if we should add -fno-tree-copyrename to CFLAGS for computed gotos to work properly])
+## tree-copyrename was broken in gcc 4.3 and then removed in gcc 6
AC_TRY_COMPILE([],[
- #if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 3)
+ #if (__GNUC__ > 4 && __GNUC__ < 6) || (__GNUC__ == 4 && __GNUC_MINOR__ >= 3)
;
#else
#error old and ok
diff --git a/erts/doc/src/erl_cmd.xml b/erts/doc/src/erl_cmd.xml
index 91954b9e7a..eb1e9e2de7 100644
--- a/erts/doc/src/erl_cmd.xml
+++ b/erts/doc/src/erl_cmd.xml
@@ -678,7 +678,7 @@
produces a crash dump. On Unix systems, sending an emulator process
a <c>SIGUSR1</c> signal also forces a crash dump.</p>
</item>
- <tag><marker id="+dcg"/><c><![CDATA[+rg DecentralizedCounterGroupsLimit]]></c></tag>
+ <tag><marker id="+dcg"/><c><![CDATA[+dcg DecentralizedCounterGroupsLimit]]></c></tag>
<item>
<p>Limits the number of decentralized counter groups used by
decentralized counters optimized for update operations in the
@@ -865,11 +865,6 @@
<c>+IOt</c> are used, <c>+IOPt</c> is ignored.
</p>
</item>
- <tag><c><![CDATA[+l]]></c></tag>
- <item>
- <p>Enables autoload tracing, displaying information while loading
- code.</p>
- </item>
<tag><c><![CDATA[+L]]></c></tag>
<item>
<p>Prevents loading information about source filenames and line
diff --git a/erts/doc/src/erl_nif.xml b/erts/doc/src/erl_nif.xml
index bcc7bc3e93..d2a1581e35 100644
--- a/erts/doc/src/erl_nif.xml
+++ b/erts/doc/src/erl_nif.xml
@@ -660,7 +660,7 @@ int writeiovec(ErlNifEnv *env, ERL_NIF_TERM term, ERL_NIF_TERM *tail,
it can only be passed on to API functions. Three types of environments
exist:</p>
<taglist>
- <tag>Process bound environment</tag>
+ <tag><marker id="proc_bound_env"/>Process bound environment</tag>
<item>
<p>Passed as the first argument to all NIFs. All function arguments
passed to a NIF belong to that environment. The return value from
@@ -671,7 +671,7 @@ int writeiovec(ErlNifEnv *env, ERL_NIF_TERM term, ERL_NIF_TERM *tail,
returns. It is thus useless and dangerous to store pointers to
process bound environments between NIF calls.</p>
</item>
- <tag>Callback environment</tag>
+ <tag><marker id="callback_env"/>Callback environment</tag>
<item>
<p>Passed as the first argument to all the non-NIF callback functions
(<seecref marker="#load"><c>load</c></seecref>,
@@ -685,7 +685,7 @@ int writeiovec(ErlNifEnv *env, ERL_NIF_TERM term, ERL_NIF_TERM *tail,
returned. Terms may be created in this environment but they will
only be accessible during the callback.</p>
</item>
- <tag>Process independent environment</tag>
+ <tag><marker id="proc_indep_env"/>Process independent environment</tag>
<item>
<p>Created by calling <seecref marker="#enif_alloc_env">
<c>enif_alloc_env</c></seecref>. This environment can be
@@ -1006,7 +1006,9 @@ typedef struct {
<name since="OTP R14B"><ret>ErlNifEnv *</ret><nametext>enif_alloc_env()</nametext></name>
<fsummary>Create a new environment.</fsummary>
<desc>
- <p>Allocates a new process independent environment. The environment can
+ <p>
+ Allocates a new <seecref marker="#proc_indep_env">process
+ independent environment</seecref>. The environment can
be used to hold terms that are not bound to any process. Such terms
can later be copied to a process environment with
<seecref marker="#enif_make_copy"><c>enif_make_copy</c></seecref> or
@@ -1253,8 +1255,12 @@ typedef struct {
<c>enif_monitor_process</c></seecref>. Argument <c>obj</c> is a pointer
to the resource holding the monitor and <c>*mon</c> identifies the
monitor.</p>
- <p>Argument <c>caller_env</c> is the environment of the calling process
- or callback. Must only be NULL if calling from a custom thread.</p>
+ <p>
+ Argument <c>caller_env</c> is the environment of the calling thread
+ (<seecref marker="#proc_bound_env">process bound</seecref> or
+ <seecref marker="#callback_env">callback</seecref> environment) or
+ <c>NULL</c> if calling from a custom thread not spawned by ERTS.
+ </p>
<p>Returns <c>0</c> if the monitor was successfully identified and removed.
Returns a non-zero value if the monitor could not be identified, which means
it was either</p>
@@ -2659,8 +2665,12 @@ enif_map_iterator_destroy(env, &amp;iter);</code>
<seecref marker="#enif_compare_monitors"><c>enif_compare_monitors</c></seecref>.
A monitor is automatically removed when it triggers or when
the resource is deallocated.</p>
- <p>Argument <c>caller_env</c> is the environment of the calling process
- or callback. Must only be NULL if calling from a custom thread.</p>
+ <p>
+ Argument <c>caller_env</c> is the environment of the calling thread
+ (<seecref marker="#proc_bound_env">process bound</seecref> or
+ <seecref marker="#callback_env">callback</seecref> environment) or
+ <c>NULL</c> if calling from a custom thread not spawned by ERTS.
+ </p>
<p>Returns <c>0</c> on success, &lt; 0 if no <c>down</c> callback is
provided, and &gt; 0 if the process is no longer alive or if
<c>target_pid</c> is <seecref marker="#enif_set_pid_undefined">
@@ -3263,7 +3273,7 @@ if (retval &amp; ERL_NIF_SELECT_STOP_CALLED) {
<p>Initializes the <seecref marker="#ErlNifPid"><c>ErlNifPid</c></seecref>
variable at <c>*pid</c> to represent the calling process.</p>
<p>Returns <c>pid</c> if successful, or NULL if <c>caller_env</c> is not
- a <seecref marker="#ErlNifEnv">process bound environment</seecref>.</p>
+ a <seecref marker="#proc_bound_env">process bound environment</seecref>.</p>
</desc>
</func>
@@ -3275,8 +3285,12 @@ if (retval &amp; ERL_NIF_SELECT_STOP_CALLED) {
<p>Sends a message to a process.</p>
<taglist>
<tag><c>caller_env</c></tag>
- <item>The environment of the calling process or callback. Must be <c>NULL</c>
- only if calling from a custom thread not spawned by ERTS.</item>
+ <item>
+ The environment of the calling thread
+ (<seecref marker="#proc_bound_env">process bound</seecref> or
+ <seecref marker="#callback_env">callback</seecref> environment) or
+ <c>NULL</c> if calling from a custom thread not spawned by ERTS.
+ </item>
<tag><c>*to_pid</c></tag>
<item>The pid of the receiving process. The pid is to refer to a
process on the local node.</item>
@@ -3604,15 +3618,18 @@ if (retval &amp; ERL_NIF_SELECT_STOP_CALLED) {
<func>
<name since="OTP 20.0"><ret>int</ret>
- <nametext>enif_whereis_pid(ErlNifEnv *env,
+ <nametext>enif_whereis_pid(ErlNifEnv *caller_env,
ERL_NIF_TERM name, ErlNifPid *pid)</nametext></name>
<fsummary>Looks up a process by its registered name.</fsummary>
<desc>
<p>Looks up a process by its registered name.</p>
<taglist>
- <tag><c>env</c></tag>
- <item>The environment of the calling process. Must be <c>NULL</c>
- only if calling from a created thread.</item>
+ <tag><c>caller_env</c></tag>
+ <item>The environment of the calling thread
+ (<seecref marker="#proc_bound_env">process bound</seecref> or
+ <seecref marker="#callback_env">callback</seecref> environment) or
+ <c>NULL</c> if calling from a custom thread not spawned by
+ ERTS.</item>
<tag><c>name</c></tag>
<item>The name of a registered process, as an atom.</item>
<tag><c>*pid</c></tag>
@@ -3632,15 +3649,18 @@ if (retval &amp; ERL_NIF_SELECT_STOP_CALLED) {
<func>
<name since="OTP 20.0"><ret>int</ret>
- <nametext>enif_whereis_port(ErlNifEnv *env,
+ <nametext>enif_whereis_port(ErlNifEnv *caller_env,
ERL_NIF_TERM name, ErlNifPort *port)</nametext></name>
<fsummary>Looks up a port by its registered name.</fsummary>
<desc>
<p>Looks up a port by its registered name.</p>
<taglist>
- <tag><c>env</c></tag>
- <item>The environment of the calling process. Must be <c>NULL</c>
- only if calling from a created thread.</item>
+ <tag><c>caller_env</c></tag>
+ <item>The environment of the calling thread
+ (<seecref marker="#proc_bound_env">process bound</seecref> or
+ <seecref marker="#callback_env">callback</seecref> environment) or
+ <c>NULL</c> if calling from a custom thread not spawned by
+ ERTS.</item>
<tag><c>name</c></tag>
<item>The name of a registered port, as an atom.</item>
<tag><c>*port</c></tag>
diff --git a/erts/doc/src/escript_cmd.xml b/erts/doc/src/escript_cmd.xml
index 47d18c0872..b234b6752c 100644
--- a/erts/doc/src/escript_cmd.xml
+++ b/erts/doc/src/escript_cmd.xml
@@ -42,7 +42,7 @@
the top <c>bin</c> directory of the standalone system and given
<c>.escript</c> as file extension. Further the (built-in)
<c>escript</c> program should be copied to the same directory and
- given the scripts original name (without the <c>.escript</c>
+ given the script's original name (without the <c>.escript</c>
extension). This will enable use of the bundled Erlang runtime
system.</p>
@@ -101,7 +101,7 @@ usage: factorial integer</pre>
a normal Erlang module. The first line is intended to be the
interpreter line, which invokes <c>escript</c>.</p>
<p>However, if you invoke the <c>escript</c> as follows,
- the contents of the first line does not matter, but it
+ the contents of the first line do not matter, but it
cannot contain Erlang code as it will be ignored:</p>
<pre>
$ <input>escript factorial 5</input></pre>
diff --git a/erts/doc/src/inet_cfg.xml b/erts/doc/src/inet_cfg.xml
index 0e2437e33c..7934a6df86 100644
--- a/erts/doc/src/inet_cfg.xml
+++ b/erts/doc/src/inet_cfg.xml
@@ -4,7 +4,7 @@
<chapter>
<header>
<copyright>
- <year>2004</year><year>2016</year>
+ <year>2004</year><year>2020</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -268,6 +268,17 @@
<seeerl marker="kernel:inet_res"><c>inet_res(3)</c></seeerl>
will try before giving up. Defaults to 3.</p>
</item>
+
+ <tag><c><![CDATA[{servfail_retry_timeout, Time}.]]></c></tag>
+ <item>
+ <p><c><![CDATA[Time = non_neg_integer()]]></c></p>
+ <p>After all name servers have been tried, there is a timeout
+ before the name servers are tried again. This is to prevent
+ the server from answering the query with what's in the servfail cache,
+ <seeerl marker="kernel:inet_res#servfail_retry_timeout"><c>inet_res(3)</c></seeerl>.
+ Defaults to 1500 milli seconds .</p>
+ </item>
+
<tag><c><![CDATA[{inet6, Bool}.]]></c></tag>
<item>
<p><c><![CDATA[Bool = true | false]]></c></p>
diff --git a/erts/doc/src/notes.xml b/erts/doc/src/notes.xml
index 25b16d6681..29f33ba2d8 100644
--- a/erts/doc/src/notes.xml
+++ b/erts/doc/src/notes.xml
@@ -31,6 +31,199 @@
</header>
<p>This document describes the changes made to the ERTS application.</p>
+<section><title>Erts 11.1.8</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>Fixed a bug that could cause some work scheduled for
+ execution on scheduler threads to be delayed until other
+ similar work appeared. Beside delaying various cleanup of
+ internal data structures also the following could be
+ delayed:</p> <list> <item>Termination of a distribution
+ controller process</item> <item>Disabling of the
+ distribution on a node</item> <item>Gathering of memory
+ allocator information using the <c>instrument</c>
+ module</item> <item>Enabling, disabling, and gathering of
+ <c>msacc</c> information</item> <item>Delivery of
+ <c>'CHANGE'</c> messages when time offset is
+ monitored</item> <item>A call to
+ <c>erlang:cancel_timer()</c></item> <item>A call to
+ <c>erlang:read_timer()</c></item> <item>A call to
+ <c>erlang:statistics(io | garbage_collection |
+ scheduler_wall_time)</c></item> <item>A call to
+ <c>ets:all()</c></item> <item>A call to
+ <c>erlang:memory()</c></item> <item>A call to
+ <c>erlang:system_info({allocator | allocator_sizes,
+ _})</c></item> <item>A call to
+ <c>erlang:trace_delivered()</c></item> </list> <p>The bug
+ existed on runtime systems running on all types of
+ hardware except for x86/x86_64.</p>
+ <p>
+ Own Id: OTP-17185</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>Erts 11.1.7</title>
+
+ <section><title>Improvements and New Features</title>
+ <list>
+ <item>
+ <p>
+ Make windows installer remove write access rights for non
+ admin users when installing to a non default directory.
+ Reduces the risk for DLL sideloading, but the user should
+ always be aware of the access rights for the
+ installation.</p>
+ <p>
+ Own Id: OTP-17097</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>Erts 11.1.6</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ The <c>suspend_process()</c> and <c>resume_process()</c>
+ BIFs did not check their arguments properly which could
+ cause an emulator crash.</p>
+ <p>
+ Own Id: OTP-17080</p>
+ </item>
+ <item>
+ <p>
+ The runtime system would get into an infinite loop if the
+ runtime system was started with more than 1023 file
+ descriptors already open.</p>
+ <p>
+ Own Id: OTP-17088 Aux Id: ERIERL-580 </p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>Erts 11.1.5</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ Fix emulator crash when sending small bit-strings over
+ Erlang distribution while the connection is being setup.</p>
+ <p>
+ The fault was introduced in OTP-23.0</p>
+ <p>
+ Own Id: OTP-17083 Aux Id: ERIERL-572 </p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>Erts 11.1.4</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ Fixed bug which could cause VM crash when a NIF is loaded
+ at the same time as the Erlang implementation of the NIF
+ is called. Bug exists since OTP 23.0.</p>
+ <p>
+ Own Id: OTP-16859</p>
+ </item>
+ <item>
+ <p>
+ Fixed <c>enif_make_map_*</c> functions in debug build
+ when given environment from <c>enif_alloc_env</c>.</p>
+ <p>
+ Own Id: OTP-16863 Aux Id: ERL-1352 </p>
+ </item>
+ <item>
+ <p>
+ Fixed broken configuration option <c>--disable-pie</c>.</p>
+ <p>
+ Own Id: OTP-16864</p>
+ </item>
+ <item>
+ <p>
+ Fixed rare distribution bug in race between received
+ signal (link/monitor/spawn_request/spawn_reply) and
+ disconnection. Symptom: VM crash. Since: OTP 21.0.</p>
+ <p>
+ Own Id: OTP-16869 Aux Id: ERL-1337 </p>
+ </item>
+ <item>
+ <p>Fixed a performance issue when extremely many items
+ were stored in the process dictionary. (Fixing this bug
+ also eliminates a compiler warning emitted by the latest
+ version of Clang.)</p>
+ <p>
+ Own Id: OTP-16888</p>
+ </item>
+ <item>
+ <p>
+ Remove <c>-ftree-copyrename</c> from flags passed to
+ compiler when building erts. The flag is not used by
+ modern gcc's and is not supported by clang.</p>
+ <p>
+ Own Id: OTP-16894</p>
+ </item>
+ <item>
+ <p>Modules using complicated nested binary comprehensions
+ could fail to load.</p>
+ <p>
+ Own Id: OTP-16899</p>
+ </item>
+ <item>
+ <p>Fixed a race in <c>file:read_file/1</c> were an
+ incomplete file could be returned if another OS process
+ swapped the file out while reading.</p>
+ <p>
+ Own Id: OTP-16948 Aux Id: PR-2792 </p>
+ </item>
+ <item>
+ <p>The call <c>list_to_integer("10", true)</c> would
+ return <c>4</c> instead of raising an exception. Certain
+ other atoms would also be interpreted as a number
+ base.</p>
+ <p>
+ Own Id: OTP-17030</p>
+ </item>
+ <item>
+ <p>
+ On macOS 11 (Big Sur), erl would not start if the maximum
+ number of file descriptors were unlimited (<c>ulimit -n
+ unlimited</c>).</p>
+ <p>
+ Own Id: OTP-17055 Aux Id: ERL-1417 </p>
+ </item>
+ </list>
+ </section>
+
+
+ <section><title>Improvements and New Features</title>
+ <list>
+ <item>
+ <p>
+ Add manifest to all executables and dynamic libraries.</p>
+ <p>
+ Own Id: OTP-17067 Aux Id: PR-2907 </p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
<section><title>Erts 11.1.3</title>
<section><title>Fixed Bugs and Malfunctions</title>
@@ -1023,6 +1216,118 @@
</section>
+<section><title>Erts 10.7.2.6</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ Fixed rare distribution bug in race between received
+ signal (link/monitor/spawn_request/spawn_reply) and
+ disconnection. Symptom: VM crash. Since: OTP 21.0.</p>
+ <p>
+ Own Id: OTP-16869 Aux Id: ERL-1337 </p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>Erts 10.7.2.5</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ Fixed bugs causing issues when enabling the ERTS internal
+ allocators on a system built with the undocumented and
+ unsupported <c>SMALL_MEMORY</c> feature.</p>
+ <p>
+ Own Id: OTP-16939</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>Erts 10.7.2.4</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ inet:setopts([{active,once}]) wakes up IO polling thread
+ unnecessarily, leading to lock contention and visibly
+ higher CPU utilization.</p>
+ <p>
+ Own Id: OTP-16847 Aux Id: ERL-1301 </p>
+ </item>
+ <item>
+ <p>
+ The documentation of <c>statistics(run_queue)</c>
+ erroneously stated that it returns the total length of
+ all normal run queues when it is the total length of all
+ normal and dirty CPU run queues that is returned. The
+ documentation has been updated to reflect the actual
+ behavior.</p>
+ <p>
+ Own Id: OTP-16866 Aux Id: ERL-1355 </p>
+ </item>
+ <item>
+ <p>
+ Two bugs in the ERTS internal thread wakeup functionality
+ have been fixed. These bugs mainly hit when all threads
+ in the system tried to go to sleep. When the bugs were
+ triggered, certain operations were delayed until a thread
+ woke up due to some other reason. Most important
+ operations effected were code loading, persistent term
+ updates, and memory deallocation.</p>
+ <p>
+ Own Id: OTP-16870</p>
+ </item>
+ <item>
+ <p>
+ Fixed bug in <c>ets:select_replace/2</c> on
+ <c>compressed</c> tables that could produce faulty
+ results or VM crash. Bug exists since OTP 20.</p>
+ <p>
+ Own Id: OTP-16874 Aux Id: ERL-1356, PR-2763 </p>
+ </item>
+ </list>
+ </section>
+
+
+ <section><title>Improvements and New Features</title>
+ <list>
+ <item>
+ <p>
+ As of OTP 22, the allocator specific memory carrier pools
+ were replaced by a node global carrier pool. This
+ unfortunately caused substantial memory fragmentation in
+ some cases due to long lived data being spread into
+ carriers used by allocators mainly handling short lived
+ data.</p>
+ <p>
+ A new command line argument <c>+M&lt;S&gt;cp</c> has been
+ introduced with which one can enable the old behavior as
+ well as configuring other behaviors for the carrier
+ pools. In order to configure the old behavior, with
+ allocator specific carrier pools for all allocators, pass
+ <c>+Mucp :</c> (including the colon character) as a
+ command line argument to <c>erl</c> when starting the
+ Erlang system.</p>
+ <p>
+ The default configuration for carrier pools will be
+ changed to <c>+Mucp :</c> some time in the future, but
+ not in this patch.</p>
+ <p>
+ Own Id: OTP-16856</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
<section><title>Erts 10.7.2.3</title>
<section><title>Fixed Bugs and Malfunctions</title>
@@ -2870,6 +3175,53 @@
</section>
+<section><title>Erts 10.3.5.14</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ The ERTS internal I/O poll implementation could get into
+ an inconsistent state causing input events to be ignored.</p>
+ <p>
+ Own Id: OTP-16780 Aux Id: PR-2701 </p>
+ </item>
+ <item>
+ <p>
+ The documentation of <c>statistics(run_queue)</c>
+ erroneously stated that it returns the total length of
+ all normal run queues when it is the total length of all
+ normal and dirty CPU run queues that is returned. The
+ documentation has been updated to reflect the actual
+ behavior.</p>
+ <p>
+ Own Id: OTP-16866 Aux Id: ERL-1355 </p>
+ </item>
+ <item>
+ <p>
+ Two bugs in the ERTS internal thread wakeup functionality
+ have been fixed. These bugs mainly hit when all threads
+ in the system tried to go to sleep. When the bugs were
+ triggered, certain operations were delayed until a thread
+ woke up due to some other reason. Most important
+ operations effected were code loading, persistent term
+ updates, and memory deallocation.</p>
+ <p>
+ Own Id: OTP-16870</p>
+ </item>
+ <item>
+ <p>
+ Fixed bug in <c>ets:select_replace/2</c> on
+ <c>compressed</c> tables that could produce faulty
+ results or VM crash. Bug exists since OTP 20.</p>
+ <p>
+ Own Id: OTP-16874 Aux Id: ERL-1356, PR-2763 </p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
<section><title>Erts 10.3.5.13</title>
<section><title>Fixed Bugs and Malfunctions</title>
diff --git a/erts/emulator/beam/bif.c b/erts/emulator/beam/bif.c
index 5beab81b98..4f1f114eba 100644
--- a/erts/emulator/beam/bif.c
+++ b/erts/emulator/beam/bif.c
@@ -3105,13 +3105,15 @@ BIF_RETTYPE list_to_integer_2(BIF_ALIST_2)
int base;
i = erts_list_length(BIF_ARG_1);
- if (i < 0)
- BIF_ERROR(BIF_P, BADARG);
-
+ if (i < 0 || is_not_small(BIF_ARG_2)) {
+ BIF_ERROR(BIF_P, BADARG);
+ }
+
base = signed_val(BIF_ARG_2);
- if (base < 2 || base > 36)
- BIF_ERROR(BIF_P, BADARG);
+ if (base < 2 || base > 36) {
+ BIF_ERROR(BIF_P, BADARG);
+ }
if (erts_list_to_integer(BIF_P, BIF_ARG_1, base,
&res, &dummy) != LTI_ALL_INTEGER) {
diff --git a/erts/emulator/beam/dist.c b/erts/emulator/beam/dist.c
index 3261fbb5b8..945764d552 100644
--- a/erts/emulator/beam/dist.c
+++ b/erts/emulator/beam/dist.c
@@ -2016,21 +2016,27 @@ int erts_net_message(Port *prt,
from, to);
ASSERT(ldp->a.other.item == to);
ASSERT(eq(ldp->b.other.item, from));
- code = erts_link_dist_insert(&ldp->a, dep->mld);
- ASSERT(code);
- if (erts_proc_sig_send_link(NULL, to, &ldp->b))
- break; /* done */
+ code = erts_link_dist_insert(&ldp->a, ede.mld);
+ if (erts_proc_sig_send_link(NULL, to, &ldp->b)) {
+ if (!code) {
+ /* Race: connection already down => send link exit */
+ erts_proc_sig_send_link_exit(NULL, THE_NON_VALUE, &ldp->a,
+ am_noconnection, NIL);
+ }
+ break; /* Done */
+ }
/* Failed to send signal; cleanup and reply noproc... */
-
- code = erts_link_dist_delete(&ldp->a);
- ASSERT(code);
+ if (code) {
+ code = erts_link_dist_delete(&ldp->a);
+ ASSERT(code);
+ }
erts_link_release_both(ldp);
}
code = erts_dsig_prepare(&ctx, dep, NULL, 0, ERTS_DSP_NO_LOCK, 1, 1, 0);
- if (code == ERTS_DSIG_PREP_CONNECTED) {
+ if (code == ERTS_DSIG_PREP_CONNECTED && ctx.connection_id == conn_id) {
code = erts_dsig_send_exit(&ctx, to, from, am_noproc);
ASSERT(code == ERTS_DSIG_SEND_OK);
}
@@ -2105,8 +2111,11 @@ int erts_net_message(Port *prt,
mdp = erts_monitor_create(ERTS_MON_TYPE_DIST_PROC,
ref, watcher, pid, name);
- code = erts_monitor_dist_insert(&mdp->origin, dep->mld);
- ASSERT(code); (void)code;
+ if (!erts_monitor_dist_insert(&mdp->origin, ede.mld)) {
+ /* Race: connection down => do nothing */
+ erts_monitor_release_both(mdp);
+ break;
+ }
if (erts_proc_sig_send_monitor(&mdp->target, pid))
break; /* done */
@@ -2120,7 +2129,7 @@ int erts_net_message(Port *prt,
}
code = erts_dsig_prepare(&ctx, dep, NULL, 0, ERTS_DSP_NO_LOCK, 1, 1, 0);
- if (code == ERTS_DSIG_PREP_CONNECTED) {
+ if (code == ERTS_DSIG_PREP_CONNECTED && ctx.connection_id == conn_id) {
code = erts_dsig_send_m_exit(&ctx, watcher, watched, ref, am_noproc);
ASSERT(code == ERTS_DSIG_SEND_OK);
}
@@ -2156,16 +2165,17 @@ int erts_net_message(Port *prt,
;
}
else if (is_atom(watched)) {
- ErtsMonLnkDist *mld = dep->mld;
ErtsMonitor *mon;
- erts_mtx_lock(&mld->mtx);
-
- mon = erts_monitor_tree_lookup(mld->orig_name_monitors, ref);
- if (mon)
- erts_monitor_tree_delete(&mld->orig_name_monitors, mon);
-
- erts_mtx_unlock(&mld->mtx);
+ erts_mtx_lock(&ede.mld->mtx);
+ if (ede.mld->alive) {
+ mon = erts_monitor_tree_lookup(ede.mld->orig_name_monitors, ref);
+ if (mon)
+ erts_monitor_tree_delete(&ede.mld->orig_name_monitors, mon);
+ }
+ else
+ mon = NULL;
+ erts_mtx_unlock(&ede.mld->mtx);
if (mon)
erts_proc_sig_send_demonitor(mon);
@@ -2554,7 +2564,8 @@ int erts_net_message(Port *prt,
}
code = erts_dsig_prepare(&ctx, dep, NULL, 0,
ERTS_DSP_NO_LOCK, 1, 1, 0);
- if (code == ERTS_DSIG_PREP_CONNECTED) {
+ if (code == ERTS_DSIG_PREP_CONNECTED
+ && ctx.connection_id == conn_id) {
code = erts_dsig_send_spawn_reply(&ctx,
tuple[2],
tuple[3],
@@ -2572,6 +2583,7 @@ int erts_net_message(Port *prt,
so.group_leader = gl;
so.mfa = mfa;
so.dist_entry = dep;
+ so.mld = ede.mld;
so.edep = edep;
so.ede_hfrag = ede_hfrag;
so.token = token;
@@ -2598,6 +2610,7 @@ int erts_net_message(Port *prt,
ErtsLinkData *ldp;
ErtsLink *lnk;
int monitor;
+ int link_inserted;
Eterm ref, result, flags_term, parent, token;
Uint flags;
@@ -2619,6 +2632,7 @@ int erts_net_message(Port *prt,
ldp = NULL;
lnk = NULL;
+ link_inserted = 0;
monitor = 0;
ref = tuple[2];
@@ -2660,15 +2674,11 @@ int erts_net_message(Port *prt,
if (flags & ERTS_DIST_SPAWN_FLAG_LINK) {
/* Successful spawn-link... */
- int code;
-
ldp = erts_link_create(ERTS_LNK_TYPE_DIST_PROC,
result, parent);
ASSERT(ldp->a.other.item == parent);
ASSERT(eq(ldp->b.other.item, result));
- code = erts_link_dist_insert(&ldp->a, dep->mld);
- ASSERT(code); (void)code;
-
+ link_inserted = erts_link_dist_insert(&ldp->a, ede.mld);
lnk = &ldp->b;
}
}
@@ -2682,7 +2692,8 @@ int erts_net_message(Port *prt,
if (monitor) {
code = erts_dsig_prepare(&ctx, dep, NULL, 0,
ERTS_DSP_NO_LOCK, 1, 1, 0);
- if (code == ERTS_DSIG_PREP_CONNECTED) {
+ if (code == ERTS_DSIG_PREP_CONNECTED
+ && ctx.connection_id == conn_id) {
code = erts_dsig_send_demonitor(&ctx, parent,
result, ref);
ASSERT(code == ERTS_DSIG_SEND_OK);
@@ -2690,9 +2701,10 @@ int erts_net_message(Port *prt,
}
if (lnk) {
-
- code = erts_link_dist_delete(&ldp->a);
- ASSERT(code);
+ if (link_inserted) {
+ code = erts_link_dist_delete(&ldp->a);
+ ASSERT(code);
+ }
erts_link_release_both(ldp);
}
@@ -2706,6 +2718,10 @@ int erts_net_message(Port *prt,
dep->mld);
}
}
+ else if (lnk && !link_inserted) {
+ erts_proc_sig_send_link_exit(NULL, THE_NON_VALUE, &ldp->a,
+ am_noconnection, NIL);
+ }
break;
}
diff --git a/erts/emulator/beam/erl_alloc.types b/erts/emulator/beam/erl_alloc.types
index 48afa71583..7adab91440 100644
--- a/erts/emulator/beam/erl_alloc.types
+++ b/erts/emulator/beam/erl_alloc.types
@@ -354,18 +354,18 @@ type COUNTERS STANDARD SYSTEM erl_bif_counters
# Types used by system specific code
#
-type TEMP_TERM TEMPORARY SYSTEM temp_term
-type SHORT_LIVED_TERM SHORT_LIVED SYSTEM short_lived_term
-type DRV_TAB LONG_LIVED SYSTEM drv_tab
-type DRV_EV_STATE LONG_LIVED SYSTEM driver_event_state
-type DRV_SEL_D_STATE FIXED_SIZE SYSTEM driver_select_data_state
-type NIF_SEL_D_STATE FIXED_SIZE SYSTEM enif_select_data_state
-type POLLSET LONG_LIVED SYSTEM pollset
-type POLLSET_UPDREQ SHORT_LIVED SYSTEM pollset_update_req
-type POLL_FDS LONG_LIVED SYSTEM poll_fds
+type TEMP_TERM TEMPORARY SYSTEM temp_term
+type SHORT_LIVED_TERM SHORT_LIVED SYSTEM short_lived_term
+type DRV_TAB LONG_LIVED SYSTEM drv_tab
+type DRV_EV_STATE LONG_LIVED SYSTEM driver_event_state
+type DRV_SEL_D_STATE FIXED_SIZE SYSTEM driver_select_data_state
+type NIF_SEL_D_STATE FIXED_SIZE SYSTEM enif_select_data_state
+type POLLSET LONG_LIVED SYSTEM pollset
+type POLLSET_UPDREQ SHORT_LIVED SYSTEM pollset_update_req
+type POLL_FDS LONG_LIVED SYSTEM poll_fds
type BLOCK_PTHR_DATA LONG_LIVED SYSTEM block_poll_thread_data
-type FD_STATUS LONG_LIVED SYSTEM fd_status
-type SELECT_FDS LONG_LIVED SYSTEM select_fds
+type FD_STATUS LONG_LIVED SYSTEM fd_status
+type SELECT_FDS LONG_LIVED SYSTEM select_fds
+if unix
diff --git a/erts/emulator/beam/erl_map.c b/erts/emulator/beam/erl_map.c
index aac1ff7bfd..e7c649c5a7 100644
--- a/erts/emulator/beam/erl_map.c
+++ b/erts/emulator/beam/erl_map.c
@@ -2071,10 +2071,7 @@ Eterm erts_hashmap_insert(Process *p, Uint32 hx, Eterm key, Eterm value,
hp = HAlloc(p, size);
res = erts_hashmap_insert_up(hp, key, value, &upsz, &stack);
}
-
DESTROY_ESTACK(stack);
- ERTS_VERIFY_UNUSED_TEMP_ALLOC(p);
- ERTS_HOLE_CHECK(p);
return res;
}
@@ -2612,8 +2609,6 @@ unroll:
HRelease(p, hp_end, hp);
not_found:
DESTROY_ESTACK(stack);
- ERTS_VERIFY_UNUSED_TEMP_ALLOC(p);
- ERTS_HOLE_CHECK(p);
UnUseTmpHeapNoproc(2);
return res;
}
diff --git a/erts/emulator/beam/erl_monitor_link.c b/erts/emulator/beam/erl_monitor_link.c
index 432e895116..a1c5170386 100644
--- a/erts/emulator/beam/erl_monitor_link.c
+++ b/erts/emulator/beam/erl_monitor_link.c
@@ -544,9 +544,10 @@ erts_mon_link_dist_create(Eterm nodename)
return mld;
}
-void
-erts_mon_link_dist_destroy__(ErtsMonLnkDist *mld)
+static void
+mon_link_dist_destroy(void* vmld)
{
+ ErtsMonLnkDist *mld = (ErtsMonLnkDist*)vmld;
ERTS_ML_ASSERT(erts_atomic_read_nob(&mld->refc) == 0);
ERTS_ML_ASSERT(!mld->alive);
ERTS_ML_ASSERT(!mld->links);
@@ -558,6 +559,21 @@ erts_mon_link_dist_destroy__(ErtsMonLnkDist *mld)
erts_free(ERTS_ALC_T_ML_DIST, mld);
}
+void
+erts_schedule_mon_link_dist_destruction__(ErtsMonLnkDist *mld)
+{
+ ERTS_ML_ASSERT(erts_atomic_read_nob(&mld->refc) == 0);
+ ERTS_ML_ASSERT(!mld->alive);
+ ERTS_ML_ASSERT(!mld->links);
+ ERTS_ML_ASSERT(!mld->monitors);
+ ERTS_ML_ASSERT(!mld->orig_name_monitors);
+
+ erts_schedule_thr_prgr_later_cleanup_op(mon_link_dist_destroy,
+ mld,
+ &mld->cleanup_lop,
+ sizeof(ErtsMonLnkDist));
+}
+
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\
* Monitor Operations *
\* */
diff --git a/erts/emulator/beam/erl_monitor_link.h b/erts/emulator/beam/erl_monitor_link.h
index 15c0676988..d75bc7999b 100644
--- a/erts/emulator/beam/erl_monitor_link.h
+++ b/erts/emulator/beam/erl_monitor_link.h
@@ -396,6 +396,11 @@
#include "erl_proc_sig_queue.h"
#undef ERTS_PROC_SIG_QUEUE_TYPE_ONLY
+#define ERL_THR_PROGRESS_TSD_TYPE_ONLY
+#include "erl_thr_progress.h"
+#undef ERL_THR_PROGRESS_TSD_TYPE_ONLY
+
+
#if defined(DEBUG) || 0
# define ERTS_ML_DEBUG
#else
@@ -481,7 +486,7 @@ struct ErtsMonLnkNode__ {
Uint16 type;
};
-typedef struct {
+typedef struct ErtsMonLnkDist__ {
Eterm nodename;
Uint32 connection_id;
erts_atomic_t refc;
@@ -492,6 +497,7 @@ typedef struct {
ErtsMonLnkNode *orig_name_monitors; /* Origin named monitors
read-black tree */
ErtsMonLnkNode *dist_pend_spawn_exit;
+ ErtsThrPrgrLaterOp cleanup_lop;
} ErtsMonLnkDist;
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\
@@ -544,7 +550,7 @@ ERTS_GLB_INLINE void erts_ml_dl_list_delete__(ErtsMonLnkNode **list,
ErtsMonLnkNode *ml);
ERTS_GLB_INLINE ErtsMonLnkNode *erts_ml_dl_list_first__(ErtsMonLnkNode *list);
ERTS_GLB_INLINE ErtsMonLnkNode *erts_ml_dl_list_last__(ErtsMonLnkNode *list);
-void erts_mon_link_dist_destroy__(ErtsMonLnkDist *mld);
+void erts_schedule_mon_link_dist_destruction__(ErtsMonLnkDist *mld);
ERTS_GLB_INLINE void *erts_ml_node_to_main_struct__(ErtsMonLnkNode *mln);
/* implementations for globally inlined misc functions... */
@@ -562,7 +568,7 @@ erts_mon_link_dist_dec_refc(ErtsMonLnkDist *mld)
{
ERTS_ML_ASSERT(erts_atomic_read_nob(&mld->refc) > 0);
if (erts_atomic_dec_read_nob(&mld->refc) == 0)
- erts_mon_link_dist_destroy__(mld);
+ erts_schedule_mon_link_dist_destruction__(mld);
}
ERTS_GLB_INLINE void *
@@ -1448,14 +1454,14 @@ erts_monitor_dist_insert(ErtsMonitor *mon, ErtsMonLnkDist *dist)
ERTS_ML_ASSERT(!mdep->dist);
ERTS_ML_ASSERT(dist);
- mdep->dist = dist;
-
- erts_mon_link_dist_inc_refc(dist);
erts_mtx_lock(&dist->mtx);
insert = dist->alive;
if (insert) {
+ mdep->dist = dist;
+ erts_mon_link_dist_inc_refc(dist);
+
if ((mon->flags & (ERTS_ML_FLG_NAME
| ERTS_ML_FLG_TARGET)) == ERTS_ML_FLG_NAME)
erts_monitor_tree_insert(&dist->orig_name_monitors, mon);
@@ -2346,15 +2352,15 @@ erts_link_dist_insert(ErtsLink *lnk, ErtsMonLnkDist *dist)
ERTS_ML_ASSERT(!ldep->dist);
ERTS_ML_ASSERT(dist);
- ldep->dist = dist;
-
- erts_mon_link_dist_inc_refc(dist);
erts_mtx_lock(&dist->mtx);
insert = dist->alive;
- if (insert)
+ if (insert) {
+ ldep->dist = dist;
+ erts_mon_link_dist_inc_refc(dist);
erts_link_list_insert(&dist->links, lnk);
+ }
erts_mtx_unlock(&dist->mtx);
diff --git a/erts/emulator/beam/erl_nif.c b/erts/emulator/beam/erl_nif.c
index 83bed11164..3f03243747 100644
--- a/erts/emulator/beam/erl_nif.c
+++ b/erts/emulator/beam/erl_nif.c
@@ -4605,6 +4605,7 @@ Eterm erts_load_nif(Process *c_p, BeamInstr *I, Eterm filename, Eterm args)
static void patch_call_nif_early(ErlNifEntry* entry,
struct erl_module_instance* this_mi)
{
+ const BeamInstr call_nif_early = BeamOpCodeAddr(op_call_nif_early);
int i;
ERTS_LC_ASSERT(erts_has_code_write_permission());
@@ -4627,13 +4628,13 @@ static void patch_call_nif_early(ErlNifEntry* entry,
* Code write permission protects against racing breakpoint writes.
*/
GenericBp* g = ci->u.gen_bp;
- g->orig_instr = BeamOpCodeAddr(op_call_nif_early);
+ g->orig_instr = BeamSetCodeAddr(g->orig_instr, call_nif_early);
if (BeamIsOpCode(code_ptr[0], op_i_generic_breakpoint))
continue;
}
else
ASSERT(!BeamIsOpCode(code_ptr[0], op_i_generic_breakpoint));
- code_ptr[0] = BeamOpCodeAddr(op_call_nif_early);
+ code_ptr[0] = BeamSetCodeAddr(code_ptr[0], call_nif_early);
}
}
@@ -4712,12 +4713,12 @@ static void load_nif_2nd_finisher(void* vlib)
* Function traced, patch the original instruction word
*/
GenericBp* g = ci->u.gen_bp;
- ASSERT(g->orig_instr == BeamOpCodeAddr(op_call_nif_early));
+ ASSERT(BeamIsOpCode(g->orig_instr, op_call_nif_early));
g->orig_instr = BeamOpCodeAddr(op_call_nif_WWW);
if (BeamIsOpCode(code_ptr[0], op_i_generic_breakpoint))
continue;
}
- ASSERT(code_ptr[0] == BeamOpCodeAddr(op_call_nif_early));
+ ASSERT(BeamIsOpCode(code_ptr[0], op_call_nif_early));
code_ptr[0] = BeamOpCodeAddr(op_call_nif_WWW);
}
}
diff --git a/erts/emulator/beam/erl_process.c b/erts/emulator/beam/erl_process.c
index ea3b369be2..3c8b1631b4 100644
--- a/erts/emulator/beam/erl_process.c
+++ b/erts/emulator/beam/erl_process.c
@@ -1634,6 +1634,11 @@ unset_aux_work_flags(ErtsSchedulerSleepInfo *ssi, erts_aint32_t flgs)
return erts_atomic32_read_band_nob(&ssi->aux_work, ~flgs);
}
+static ERTS_INLINE erts_aint32_t
+unset_aux_work_flags_mb(ErtsSchedulerSleepInfo *ssi, erts_aint32_t flgs)
+{
+ return erts_atomic32_read_band_mb(&ssi->aux_work, ~flgs);
+}
static ERTS_INLINE void
haw_chk_later_cleanup_op_wakeup(ErtsAuxWorkData *awdp, ErtsThrPrgrVal val)
@@ -1729,9 +1734,7 @@ handle_delayed_aux_work_wakeup(ErtsAuxWorkData *awdp, erts_aint32_t aux_work, in
if (!waiting && awdp->delayed_wakeup.next > awdp->esdp->reductions)
return aux_work;
- unset_aux_work_flags(awdp->ssi, ERTS_SSI_AUX_WORK_DELAYED_AW_WAKEUP);
-
- ERTS_THR_MEMORY_BARRIER;
+ unset_aux_work_flags_mb(awdp->ssi, ERTS_SSI_AUX_WORK_DELAYED_AW_WAKEUP);
max_jix = awdp->delayed_wakeup.jix;
awdp->delayed_wakeup.jix = -1;
@@ -1855,7 +1858,7 @@ handle_misc_aux_work(ErtsAuxWorkData *awdp,
{
ErtsThrQ_t *q = &misc_aux_work_queues[awdp->sched_id].q;
- unset_aux_work_flags(awdp->ssi, ERTS_SSI_AUX_WORK_MISC);
+ unset_aux_work_flags_mb(awdp->ssi, ERTS_SSI_AUX_WORK_MISC);
while (1) {
erts_misc_aux_work_t *mawp = erts_thr_q_dequeue(q);
if (!mawp)
@@ -1957,7 +1960,7 @@ handle_async_ready(ErtsAuxWorkData *awdp,
ASSERT(!awdp->esdp || !ERTS_SCHEDULER_IS_DIRTY(awdp->esdp));
- unset_aux_work_flags(ssi, ERTS_SSI_AUX_WORK_ASYNC_READY);
+ unset_aux_work_flags_mb(ssi, ERTS_SSI_AUX_WORK_ASYNC_READY);
if (erts_check_async_ready(awdp->async_ready.queue)) {
if (set_aux_work_flags(ssi, ERTS_SSI_AUX_WORK_ASYNC_READY)
& ERTS_SSI_AUX_WORK_ASYNC_READY_CLEAN) {
@@ -2013,8 +2016,8 @@ handle_fix_alloc(ErtsAuxWorkData *awdp, erts_aint32_t aux_work, int waiting)
ASSERT(!awdp->esdp || !ERTS_SCHEDULER_IS_DIRTY(awdp->esdp));
- unset_aux_work_flags(ssi, (ERTS_SSI_AUX_WORK_FIX_ALLOC_LOWER_LIM
- | ERTS_SSI_AUX_WORK_FIX_ALLOC_DEALLOC));
+ unset_aux_work_flags_mb(ssi, (ERTS_SSI_AUX_WORK_FIX_ALLOC_LOWER_LIM
+ | ERTS_SSI_AUX_WORK_FIX_ALLOC_DEALLOC));
aux_work &= ~(ERTS_SSI_AUX_WORK_FIX_ALLOC_LOWER_LIM
| ERTS_SSI_AUX_WORK_FIX_ALLOC_DEALLOC);
res = erts_alloc_fix_alloc_shrink(awdp->sched_id, aux_work);
@@ -2062,7 +2065,7 @@ handle_delayed_dealloc(ErtsAuxWorkData *awdp, erts_aint32_t aux_work, int waitin
ASSERT(!awdp->esdp || !ERTS_SCHEDULER_IS_DIRTY(awdp->esdp));
- unset_aux_work_flags(ssi, ERTS_SSI_AUX_WORK_DD);
+ unset_aux_work_flags_mb(ssi, ERTS_SSI_AUX_WORK_DD);
ERTS_MSACC_SET_STATE_CACHED_M_X(ERTS_MSACC_STATE_ALLOC);
erts_alloc_scheduler_handle_delayed_dealloc((void *) awdp->esdp,
&need_thr_progress,
@@ -2158,7 +2161,7 @@ handle_canceled_timers(ErtsAuxWorkData *awdp, erts_aint32_t aux_work, int waitin
ASSERT(!awdp->esdp || !ERTS_SCHEDULER_IS_DIRTY(awdp->esdp));
- unset_aux_work_flags(ssi, ERTS_SSI_AUX_WORK_CNCLD_TMRS);
+ unset_aux_work_flags_mb(ssi, ERTS_SSI_AUX_WORK_CNCLD_TMRS);
erts_handle_canceled_timers((void *) awdp->esdp,
&need_thr_progress,
&wakeup,
@@ -2328,7 +2331,7 @@ handle_debug_wait_completed(ErtsAuxWorkData *awdp, erts_aint32_t aux_work, int w
awdp->debug.wait_completed.callback = NULL;
awdp->debug.wait_completed.arg = NULL;
- unset_aux_work_flags(ssi, ERTS_SSI_AUX_WORK_DEBUG_WAIT_COMPLETED);
+ unset_aux_work_flags_mb(ssi, ERTS_SSI_AUX_WORK_DEBUG_WAIT_COMPLETED);
return aux_work & ~ERTS_SSI_AUX_WORK_DEBUG_WAIT_COMPLETED;
}
@@ -2464,7 +2467,7 @@ int erts_halt_code;
static ERTS_INLINE erts_aint32_t
handle_reap_ports(ErtsAuxWorkData *awdp, erts_aint32_t aux_work, int waiting)
{
- unset_aux_work_flags(awdp->ssi, ERTS_SSI_AUX_WORK_REAP_PORTS);
+ unset_aux_work_flags_mb(awdp->ssi, ERTS_SSI_AUX_WORK_REAP_PORTS);
ERTS_RUNQ_FLGS_SET(awdp->esdp->run_queue, ERTS_RUNQ_FLG_HALTING);
if (erts_atomic32_dec_read_acqb(&erts_halt_progress) == 0) {
@@ -2559,7 +2562,7 @@ handle_yield(ErtsAuxWorkData *awdp, erts_aint32_t aux_work, int waiting)
static ERTS_INLINE erts_aint32_t
handle_mseg_cache_check(ErtsAuxWorkData *awdp, erts_aint32_t aux_work, int waiting)
{
- unset_aux_work_flags(awdp->ssi, ERTS_SSI_AUX_WORK_MSEG_CACHE_CHECK);
+ unset_aux_work_flags_mb(awdp->ssi, ERTS_SSI_AUX_WORK_MSEG_CACHE_CHECK);
erts_mseg_cache_check();
return aux_work & ~ERTS_SSI_AUX_WORK_MSEG_CACHE_CHECK;
}
@@ -2570,7 +2573,7 @@ handle_mseg_cache_check(ErtsAuxWorkData *awdp, erts_aint32_t aux_work, int waiti
static ERTS_INLINE erts_aint32_t
handle_setup_aux_work_timer(ErtsAuxWorkData *awdp, erts_aint32_t aux_work, int waiting)
{
- unset_aux_work_flags(awdp->ssi, ERTS_SSI_AUX_WORK_SET_TMO);
+ unset_aux_work_flags_mb(awdp->ssi, ERTS_SSI_AUX_WORK_SET_TMO);
setup_aux_work_timer(awdp->esdp);
return aux_work & ~ERTS_SSI_AUX_WORK_SET_TMO;
}
@@ -8699,6 +8702,9 @@ erts_internal_suspend_process_2(BIF_ALIST_2)
if (BIF_P->common.id == BIF_ARG_1)
BIF_RET(am_badarg); /* We are not allowed to suspend ourselves */
+ if (!is_internal_pid(BIF_ARG_1))
+ BIF_RET(am_badarg);
+
if (is_not_nil(BIF_ARG_2)) {
/* Parse option list */
Eterm arg = BIF_ARG_2;
@@ -8847,6 +8853,9 @@ resume_process_1(BIF_ALIST_1)
if (BIF_P->common.id == BIF_ARG_1)
BIF_ERROR(BIF_P, BADARG);
+ if (!is_internal_pid(BIF_ARG_1))
+ BIF_ERROR(BIF_P, BADARG);
+
mon = erts_monitor_tree_lookup(ERTS_P_MONITORS(BIF_P),
BIF_ARG_1);
if (!mon) {
@@ -12209,9 +12218,11 @@ erl_create_process(Process* parent, /* Parent of process (default group leader).
ErtsLinkData *ldp;
ldp = erts_link_create(ERTS_LNK_TYPE_DIST_PROC,
parent_id, p->common.id);
- code = erts_link_dist_insert(&ldp->a, so->dist_entry->mld);
- ASSERT(code);
erts_link_tree_insert(&ERTS_P_LINKS(p), &ldp->b);
+ if (!erts_link_dist_insert(&ldp->a, so->mld)) {
+ erts_proc_sig_send_link_exit(NULL, THE_NON_VALUE, &ldp->a,
+ am_noconnection, NIL);
+ }
}
if (so->flags & SPO_MONITOR) {
@@ -12219,9 +12230,12 @@ erl_create_process(Process* parent, /* Parent of process (default group leader).
mdp = erts_monitor_create(ERTS_MON_TYPE_DIST_PROC,
spawn_ref, parent_id,
p->common.id, NIL);
- code = erts_monitor_dist_insert(&mdp->origin, so->dist_entry->mld);
- ASSERT(code); (void)code;
- erts_monitor_tree_insert(&ERTS_P_MONITORS(p), &mdp->target);
+ if (erts_monitor_dist_insert(&mdp->origin, so->mld)) {
+ erts_monitor_tree_insert(&ERTS_P_MONITORS(p), &mdp->target);
+ }
+ else {
+ erts_monitor_release_both(mdp);
+ }
}
if (have_seqtrace(token)) {
diff --git a/erts/emulator/beam/erl_process.h b/erts/emulator/beam/erl_process.h
index 8dfa5b1bbb..d89a00714f 100644
--- a/erts/emulator/beam/erl_process.h
+++ b/erts/emulator/beam/erl_process.h
@@ -1387,6 +1387,7 @@ typedef struct {
Eterm group_leader;
Eterm mfa;
DistEntry *dist_entry;
+ ErtsMonLnkDist *mld; /* copied from dist_entry->mld */
ErtsDistExternal *edep;
ErlHeapFragment *ede_hfrag;
Eterm token;
diff --git a/erts/emulator/beam/erl_process_dict.c b/erts/emulator/beam/erl_process_dict.c
index 64ee483079..248da52db5 100644
--- a/erts/emulator/beam/erl_process_dict.c
+++ b/erts/emulator/beam/erl_process_dict.c
@@ -1052,7 +1052,7 @@ static unsigned int next_array_size(unsigned int need)
1342177280UL,
2684354560UL
};
- int hi = sizeof(tab) / sizeof(Uint) - 1;
+ int hi = sizeof(tab) / sizeof(tab[0]) - 1;
int lo = 1;
int cur = 4;
diff --git a/erts/emulator/beam/external.c b/erts/emulator/beam/external.c
index 1a29904f5e..72edff0c22 100644
--- a/erts/emulator/beam/external.c
+++ b/erts/emulator/beam/external.c
@@ -883,6 +883,7 @@ erts_prepare_dist_ext(ErtsDistExternal *edep,
edep->heap_size = -1;
edep->flags = 0;
edep->dep = dep;
+ edep->mld = dep->mld;
edep->connection_id = conn_id;
edep->data->ext_endp = ext+size;
edep->data->binp = binp;
@@ -3838,7 +3839,7 @@ hopefull_bit_binary(TTBEncodeContext* ctx, byte **epp, Binary *pb_val, Eterm pb_
/* copy trailing bits into new hopefull data element */
ep = begin_hopefull_data(ctx, ep);
- *ep = 0;
+ *ep = 0; /* Clear the bit in the byte */
copy_binary_to_buffer(ep, 0, bytes + sz, bitoffs, bitsize);
ep++;
@@ -5241,10 +5242,13 @@ encode_size_struct_int(TTBSizeContext* ctx, ErtsAtomCacheMap *acmp, Eterm obj,
+ bin_size);
}
else if (dflags & DFLAG_PENDING_CONNECT) {
+ /* This is the odd case when we have an un-aligned bit-string
+ during a pending connect. */
Uint csz = result - ctx->last_result;
ASSERT(dflags & DFLAG_BIT_BINARIES);
/* potentially multiple elements leading up to binary */
- vlen += csz/MAX_SYSIOVEC_IOVLEN;
+ vlen += (csz + MAX_SYSIOVEC_IOVLEN - 1)/MAX_SYSIOVEC_IOVLEN;
+
vlen++; /* hopefull prolog */
/*
* Size for hopefull prolog is max of
diff --git a/erts/emulator/beam/external.h b/erts/emulator/beam/external.h
index 4d8f0bdd29..937dc532f6 100644
--- a/erts/emulator/beam/external.h
+++ b/erts/emulator/beam/external.h
@@ -144,6 +144,7 @@ typedef struct erl_dist_external {
Uint32 flags;
Uint32 connection_id;
ErtsDistExternalData *data;
+ struct ErtsMonLnkDist__ *mld; /* copied from DistEntry.mld */
ErtsAtomTranslationTable attab;
} ErtsDistExternal;
diff --git a/erts/emulator/beam/ops.tab b/erts/emulator/beam/ops.tab
index ed0b240d8a..14afdd8553 100644
--- a/erts/emulator/beam/ops.tab
+++ b/erts/emulator/beam/ops.tab
@@ -1356,6 +1356,9 @@ bs_append Fail Size Extra Live Unit Bin Flags Dst => \
bs_private_append Fail Size Unit Bin Flags Dst => \
i_bs_private_append Fail Unit Size Bin Dst
+i_bs_private_append Fail Unit Size Bin Dst=y => \
+ i_bs_private_append Fail Unit Size Bin x | move x Dst
+
bs_init_writable
i_bs_append j? I t? t s xy
diff --git a/erts/emulator/nifs/common/prim_file_nif.c b/erts/emulator/nifs/common/prim_file_nif.c
index fce4fc3c90..d26be2bc3e 100644
--- a/erts/emulator/nifs/common/prim_file_nif.c
+++ b/erts/emulator/nifs/common/prim_file_nif.c
@@ -1266,12 +1266,16 @@ static ERL_NIF_TERM read_file_nif(ErlNifEnv *env, int argc, const ERL_NIF_TERM a
if((posix_errno = efile_marshal_path(env, argv[0], &path))) {
return posix_error_to_tuple(env, posix_errno);
- } else if((posix_errno = efile_read_info(&path, 1, &info))) {
- return posix_error_to_tuple(env, posix_errno);
} else if((posix_errno = efile_open(&path, EFILE_MODE_READ, efile_resource_type, &d))) {
return posix_error_to_tuple(env, posix_errno);
}
+ /* read_file() wants to know the file size, so retrieve it now from the
+ open file handle. In theory, efile_read_handle_info() may fail with
+ ENOTSUP, fall back to the "unknown size" logic if that happens. */
+ if (efile_read_handle_info(d, &info) != 0) {
+ info.size = 0;
+ }
posix_errno = read_file(d, info.size, &result);
erts_atomic32_set_acqb(&d->state, EFILE_STATE_CLOSED);
diff --git a/erts/emulator/sys/common/erl_poll.c b/erts/emulator/sys/common/erl_poll.c
index 4e5918d1be..9f0c82dc4b 100644
--- a/erts/emulator/sys/common/erl_poll.c
+++ b/erts/emulator/sys/common/erl_poll.c
@@ -646,12 +646,13 @@ int erts_poll_new_table_len(int old_len, int need_len)
}
else {
new_len = old_len;
+ if (new_len < ERTS_FD_TABLE_MIN_LENGTH)
+ new_len = ERTS_FD_TABLE_MIN_LENGTH;
do {
if (new_len < ERTS_FD_TABLE_EXP_THRESHOLD)
new_len *= 2;
else
new_len += ERTS_FD_TABLE_EXP_THRESHOLD;
-
} while (new_len < need_len);
}
ASSERT(new_len >= need_len);
@@ -2062,6 +2063,21 @@ ERTS_POLL_EXPORT(erts_poll_init)(int *concurrent_updates)
max_fds = OPEN_MAX;
#endif
+ if (max_fds < 0 && errno == 0) {
+ /* On macOS 11 and higher, it possible to have an unlimited
+ * number of open files per process. ERTS will need an actual
+ * limit, though, so we will set it to a largish value. The
+ * number below is the hard number of file descriptors per
+ * process as returned by `sysctl kern.maxfilesperproc`, which
+ * seems to be the limit in practice.
+ *
+ * Note: The size of the port table will be based on max_fds,
+ * so we don't want to set it to a huge value such as
+ * MAX_INT.
+ */
+ max_fds = 24576;
+ }
+
#if ERTS_POLL_USE_SELECT && defined(FD_SETSIZE) && \
!defined(_DARWIN_UNLIMITED_SELECT)
if (max_fds > FD_SETSIZE)
diff --git a/erts/emulator/sys/win32/erl_win_sys.h b/erts/emulator/sys/win32/erl_win_sys.h
index b00ba287e2..4c64494ac0 100644
--- a/erts/emulator/sys/win32/erl_win_sys.h
+++ b/erts/emulator/sys/win32/erl_win_sys.h
@@ -52,10 +52,6 @@
#include <fcntl.h>
#include <time.h>
#include <sys/timeb.h>
-#pragma comment(linker,"/manifestdependency:\"type='win32' "\
- "name='Microsoft.Windows.Common-Controls' "\
- "version='6.0.0.0' processorArchitecture='*' "\
- "publicKeyToken='6595b64144ccf1df' language='*'\"")
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
diff --git a/erts/emulator/test/bs_bincomp_SUITE.erl b/erts/emulator/test/bs_bincomp_SUITE.erl
index c481e93e41..2dcebc2ef9 100644
--- a/erts/emulator/test/bs_bincomp_SUITE.erl
+++ b/erts/emulator/test/bs_bincomp_SUITE.erl
@@ -112,7 +112,14 @@ mixed(Config) when is_list(Config) ->
[(X+Y) || <<X:3>> <= <<1:3,2:3,3:3,4:3>>, <<Y:3>> <= <<1:3,2:3>>],
[2,3,3,4,4,5,5,6] =
[(X+Y) || <<X:3>> <= <<1:3,2:3,3:3,4:3>>, Y <- [1,2]],
- ok.
+
+ %% OTP-16899: Nested binary comprehensions would fail to load.
+ <<0,1,0,2,0,3,99>> = mixed_nested([1,2,3]),
+
+ ok.
+
+mixed_nested(L) ->
+ << << << << E:16 >> || E <- L >> || true >>/binary, 99:(id(8))>>.
%% OTP-8179: Call tracing on binary comprehensions would cause a crash.
tracing(Config) when is_list(Config) ->
@@ -148,3 +155,8 @@ tracer(Parent, N) ->
tracer(Parent, N+1)
end
end.
+
+%%% Common utilities.
+
+id(I) ->
+ I.
diff --git a/erts/emulator/test/distribution_SUITE.erl b/erts/emulator/test/distribution_SUITE.erl
index d945023f61..4982d979ec 100644
--- a/erts/emulator/test/distribution_SUITE.erl
+++ b/erts/emulator/test/distribution_SUITE.erl
@@ -75,7 +75,6 @@
system_limit/1,
hopefull_data_encoding/1,
hopefull_export_fun_bug/1,
- mk_hopefull_data/0,
huge_iovec/1]).
%% Internal exports.
@@ -2604,7 +2603,6 @@ test_hopefull_data_encoding(Config, Fallback) when is_list(Config) ->
false = rpc:call(BouncerNode, erts_debug, set_internal_state,
[remove_hopefull_dflags, true])
end,
- HData = mk_hopefull_data(),
Tester = self(),
R1 = make_ref(),
R2 = make_ref(),
@@ -2613,10 +2611,13 @@ test_hopefull_data_encoding(Config, Fallback) when is_list(Config) ->
Proxy = spawn_link(ProxyNode,
fun () ->
register(bouncer, self()),
+ %% We create the data on the proxy node in order
+ %% to create the correct sub binaries
+ HData = mk_hopefull_data(R1, Tester),
%% Verify same result between this node and tester
Tester ! [R1, HData],
%% Test when connection has not been setup yet
- Bouncer ! {Tester, [R2, HData]},
+ Bouncer ! {Tester, [R2, HData]},
Sync = make_ref(),
Bouncer ! {self(), Sync},
receive Sync -> ok end,
@@ -2624,17 +2625,18 @@ test_hopefull_data_encoding(Config, Fallback) when is_list(Config) ->
Bouncer ! {Tester, [R3, HData]},
receive after infinity -> ok end
end),
- receive
- [R1, HData1] ->
- Hdata = HData1
- end,
+ HData =
+ receive
+ [R1, HData1] ->
+ HData1
+ end,
receive
[R2, HData2] ->
case Fallback of
false ->
HData = HData2;
true ->
- check_hopefull_fallback_data(Hdata, HData2)
+ check_hopefull_fallback_data(HData, HData2)
end
end,
receive
@@ -2643,7 +2645,7 @@ test_hopefull_data_encoding(Config, Fallback) when is_list(Config) ->
false ->
HData = HData3;
true ->
- check_hopefull_fallback_data(Hdata, HData3)
+ check_hopefull_fallback_data(HData, HData3)
end
end,
unlink(Proxy),
@@ -2661,32 +2663,54 @@ bounce_loop() ->
end,
bounce_loop().
-mk_hopefull_data() ->
+mk_hopefull_data(RemoteRef, RemotePid) ->
HugeBs = list_to_bitstring([lists:duplicate(12*1024*1024, 85), <<6:6>>]),
<<_:1/bitstring,HugeBs2/bitstring>> = HugeBs,
- lists:flatten([mk_hopefull_data(list_to_binary(lists:seq(1,255))),
- 1234567890, HugeBs, fun gurka:banan/3, fun erlang:node/1,
- self(), fun erlang:self/0,
- mk_hopefull_data(list_to_binary(lists:seq(1,32))), an_atom,
- fun lists:reverse/1, make_ref(), HugeBs2,
- fun blipp:blapp/7]).
+ mk_hopefull_data(list_to_binary(lists:seq(1,255))) ++
+ [1234567890, HugeBs, fun gurka:banan/3, fun erlang:node/1,
+ RemotePid, self(), fun erlang:self/0] ++
+ mk_hopefull_data(list_to_binary(lists:seq(1,32))) ++
+ [an_atom,
+ fun lists:reverse/1, RemoteRef, make_ref(), HugeBs2,
+ fun blipp:blapp/7].
mk_hopefull_data(BS) ->
BSsz = bit_size(BS),
- [lists:map(fun (Offset) ->
- <<_:Offset/bitstring, NewBs/bitstring>> = BS,
- NewBs
- end, lists:seq(1, 16)),
- lists:map(fun (Offset) ->
- <<NewBs:Offset/bitstring, _/bitstring>> = BS,
- NewBs
- end, lists:seq(BSsz-16, BSsz-1)),
- lists:map(fun (Offset) ->
- PreOffset = Offset rem 16,
- <<_:PreOffset/bitstring, NewBs:Offset/bitstring, _/bitstring>> = BS,
- NewBs
- end, lists:seq(BSsz-32, BSsz-17))].
-
+ lists:concat(
+ [lists:map(fun (Offset) ->
+ <<NewBs:Offset/bitstring, _/bitstring>> = BS,
+ NewBs
+ end, lists:seq(1, 16)),
+ lists:map(fun (Offset) ->
+ <<_:Offset/bitstring, NewBs/bitstring>> = BS,
+ NewBs
+ end, lists:seq(1, 16)),
+ lists:map(fun (Offset) ->
+ <<NewBs:Offset/bitstring, _/bitstring>> = BS,
+ NewBs
+ end, lists:seq(BSsz-16, BSsz-1)),
+ lists:map(fun (Offset) ->
+ PreOffset = Offset rem 16,
+ <<_:PreOffset/bitstring, NewBs:Offset/bitstring, _/bitstring>> = BS,
+ NewBs
+ end, lists:seq(BSsz-32, BSsz-17)),
+ lists:map(fun (Offset) ->
+ <<NewBs:Offset/bitstring, _/bitstring>> = BS,
+ [NewBs]
+ end, lists:seq(1, 16)),
+ lists:map(fun (Offset) ->
+ <<_:Offset/bitstring, NewBs/bitstring>> = BS,
+ [NewBs]
+ end, lists:seq(1, 16)),
+ lists:map(fun (Offset) ->
+ <<NewBs:Offset/bitstring, _/bitstring>> = BS,
+ [NewBs]
+ end, lists:seq(BSsz-16, BSsz-1)),
+ lists:map(fun (Offset) ->
+ PreOffset = Offset rem 16,
+ <<_:PreOffset/bitstring, NewBs:Offset/bitstring, _/bitstring>> = BS,
+ [NewBs]
+ end, lists:seq(BSsz-32, BSsz-17))]).
check_hopefull_fallback_data([], []) ->
ok;
@@ -2696,6 +2720,8 @@ check_hopefull_fallback_data([X|Xs],[Y|Ys]) ->
chk_hopefull_fallback(Binary, FallbackBinary) when is_binary(Binary) ->
Binary = FallbackBinary;
+chk_hopefull_fallback([BitStr], [{Bin, BitSize}]) when is_bitstring(BitStr) ->
+ chk_hopefull_fallback(BitStr, {Bin, BitSize});
chk_hopefull_fallback(BitStr, {Bin, BitSize}) when is_bitstring(BitStr) ->
true = is_binary(Bin),
true = is_integer(BitSize),
diff --git a/erts/emulator/test/driver_SUITE.erl b/erts/emulator/test/driver_SUITE.erl
index 95cae93225..ddbade85c5 100644
--- a/erts/emulator/test/driver_SUITE.erl
+++ b/erts/emulator/test/driver_SUITE.erl
@@ -82,6 +82,8 @@
consume_timeslice/1,
env/1,
poll_pipe/1,
+ lots_of_used_fds_on_boot/1,
+ lots_of_used_fds_on_boot_slave/1,
z_test/1]).
-export([bin_prefix/2]).
@@ -159,7 +161,9 @@ groups() ->
[a_test, use_fallback_pollset,
bad_fd_in_pollset, fd_change,
steal_control, smp_select,
- driver_select_use, z_test]},
+ driver_select_use,
+ lots_of_used_fds_on_boot,
+ z_test]},
{ioq_exit, [],
[ioq_exit_ready_input, ioq_exit_ready_output,
ioq_exit_timeout, ioq_exit_ready_async,
@@ -1859,6 +1863,79 @@ driver_select_use0(Config) ->
ok = erl_ddll:stop(),
ok.
+lots_of_used_fds_on_boot(Config) ->
+ case os:type() of
+ {unix, _} -> lots_of_used_fds_on_boot_test(Config);
+ _ -> {skipped, "Unix only test"}
+ end.
+
+lots_of_used_fds_on_boot_test(Config) ->
+ %% Start a node in a wrapper which have lots of fds
+ %% open. This used to hang the whole VM at boot in
+ %% an eternal loop trying to figure out how to size
+ %% arrays in erts_poll() implementation.
+ Name = lots_of_used_fds_on_boot,
+ HostSuffix = lists:dropwhile(fun ($@) -> false; (_) -> true end,
+ atom_to_list(node())),
+ FullName = list_to_atom(atom_to_list(Name) ++ HostSuffix),
+ Pa = filename:dirname(code:which(?MODULE)),
+ Prog = case catch init:get_argument(progname) of
+ {ok,[[P]]} -> P;
+ _ -> exit(no_progname_argument_found)
+ end,
+ NameSw = case net_kernel:longnames() of
+ false -> "-sname ";
+ true -> "-name ";
+ _ -> exit(not_distributed_node)
+ end,
+ {ok, Pwd} = file:get_cwd(),
+ NameStr = atom_to_list(Name),
+ DataDir = proplists:get_value(data_dir, Config),
+ Wrapper = filename:join(DataDir, "lots_of_fds_used_wrapper"),
+ CmdLine = Wrapper ++ " " ++ Prog ++ " -noshell -noinput "
+ ++ NameSw ++ " " ++ NameStr ++ " "
+ ++ "-pa " ++ Pa ++ " "
+ ++ "-env ERL_CRASH_DUMP " ++ Pwd ++ "/erl_crash_dump." ++ NameStr ++ " "
+ ++ "-setcookie " ++ atom_to_list(erlang:get_cookie()) ++ " "
+ ++ "-s " ++ atom_to_list(?MODULE) ++ " lots_of_used_fds_on_boot_slave "
+ ++ atom_to_list(node()),
+ io:format("Starting node ~p: ~s~n", [FullName, CmdLine]),
+ net_kernel:monitor_nodes(true),
+ Port = case open_port({spawn, CmdLine}, [exit_status]) of
+ Prt when is_port(Prt) ->
+ Prt;
+ OPError ->
+ exit({failed_to_start_node, {open_port_error, OPError}})
+ end,
+ receive
+ {Port, {exit_status, 17}} ->
+ {skip, "Cannot open enough fds to test this"};
+ {Port, {exit_status, Error}} ->
+ exit({failed_to_start_node, {exit_status, Error}});
+ {nodeup, FullName} ->
+ io:format("~p connected!~n", [FullName]),
+ FullName = rpc:call(FullName, erlang, node, []),
+ rpc:cast(FullName, erlang, halt, []),
+ receive
+ {Port, {exit_status, 0}} ->
+ ok;
+ {Port, {exit_status, Error}} ->
+ exit({unexpected_exit_status, Error})
+ after 5000 ->
+ exit(missing_exit_status)
+ end
+ after 5000 ->
+ exit(connection_timeout)
+ end.
+
+lots_of_used_fds_on_boot_slave([Master]) ->
+ erlang:monitor_node(Master, true),
+ receive
+ {nodedown, Master} ->
+ erlang:halt()
+ end,
+ ok.
+
thread_mseg_alloc_cache_clean(Config) when is_list(Config) ->
case {erlang:system_info(threads),
erlang:system_info({allocator,mseg_alloc}),
diff --git a/erts/emulator/test/driver_SUITE_data/Makefile.src b/erts/emulator/test/driver_SUITE_data/Makefile.src
index bcabaa689d..77cbd34fb1 100644
--- a/erts/emulator/test/driver_SUITE_data/Makefile.src
+++ b/erts/emulator/test/driver_SUITE_data/Makefile.src
@@ -1,3 +1,7 @@
+CC = @CC@
+LD = @LD@
+CFLAGS = @CFLAGS@ @DEFS@
+CROSSLDFLAGS = @CROSSLDFLAGS@
MISC_DRVS = outputv_drv@dll@ \
timer_drv@dll@ \
@@ -30,7 +34,15 @@ VSN_MISMATCH_DRVS = zero_extended_marker_garb_drv@dll@ \
smaller_major_vsn_drv@dll@ \
smaller_minor_vsn_drv@dll@
-all: $(MISC_DRVS) $(SYS_INFO_DRVS) $(VSN_MISMATCH_DRVS)
+PROGS = lots_of_fds_used_wrapper@exe@
+
+all: $(MISC_DRVS) $(SYS_INFO_DRVS) $(VSN_MISMATCH_DRVS) $(PROGS)
+
+lots_of_fds_used_wrapper@exe@: lots_of_fds_used_wrapper@obj@
+ $(LD) $(CROSSLDFLAGS) -o lots_of_fds_used_wrapper lots_of_fds_used_wrapper@obj@ @LIBS@
+
+lots_of_fds_used_wrapper@obj@: lots_of_fds_used_wrapper.c
+ $(CC) -c -o lots_of_fds_used_wrapper@obj@ $(CFLAGS) lots_of_fds_used_wrapper.c
@SHLIB_RULES@
diff --git a/erts/emulator/test/driver_SUITE_data/lots_of_fds_used_wrapper.c b/erts/emulator/test/driver_SUITE_data/lots_of_fds_used_wrapper.c
new file mode 100644
index 0000000000..34d84827d5
--- /dev/null
+++ b/erts/emulator/test/driver_SUITE_data/lots_of_fds_used_wrapper.c
@@ -0,0 +1,61 @@
+#if !defined(__WIN32__)
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdio.h>
+#endif
+
+int
+main(int argc, char *argv[])
+{
+#if !defined(__WIN32__)
+
+ char **exec_argv;
+ int fds[12000];
+ int max = sizeof(fds)/sizeof(fds[0]);
+ int i;
+
+ /* Open a bit more than 1024 file descriptors... */
+ for (i = 0; i < max; i++) {
+ fds[i] = open("/dev/null", 0, O_WRONLY);
+ if (fds[i] < 0) {
+ if (i < 1200)
+ return 17; /* Not enough fds for the test... */
+ max = i;
+ break;
+ }
+ }
+
+ /*
+ * Close some of the latest fds to give room for
+ * the emulators usage...
+ */
+ for (i = max-150; i < max; i++)
+ close(fds[i]);
+
+ if (argc < 2)
+ return 1;
+
+ /*
+ * Ensure NULL pointer after last argument...
+ */
+ exec_argv = malloc(sizeof(char *)*argc);
+ if (!exec_argv)
+ return 2;
+
+ for (i = 0; i < argc-1; i++) {
+ /* printf("arg=%d: %s\n", i, argv[i+1]); */
+ exec_argv[i] = argv[i+1];
+ }
+ exec_argv[i] = NULL;
+
+ execvp(exec_argv[0], exec_argv);
+
+ perror("Failed to exec");
+
+#endif
+
+ return 3;
+}
diff --git a/erts/emulator/test/driver_SUITE_data/peek_non_existing_queue_drv.c b/erts/emulator/test/driver_SUITE_data/peek_non_existing_queue_drv.c
index 685cda3e07..b69d75c31d 100644
--- a/erts/emulator/test/driver_SUITE_data/peek_non_existing_queue_drv.c
+++ b/erts/emulator/test/driver_SUITE_data/peek_non_existing_queue_drv.c
@@ -47,6 +47,10 @@
#include <windows.h>
#endif
+#ifdef HAVE_UNISTD_H
+# include <unistd.h>
+#endif
+
#include <errno.h>
#include "erl_driver.h"
diff --git a/erts/emulator/test/driver_SUITE_data/thr_msg_blast_drv.c b/erts/emulator/test/driver_SUITE_data/thr_msg_blast_drv.c
index 56183c9484..503d8b902c 100644
--- a/erts/emulator/test/driver_SUITE_data/thr_msg_blast_drv.c
+++ b/erts/emulator/test/driver_SUITE_data/thr_msg_blast_drv.c
@@ -18,6 +18,10 @@
* %CopyrightEnd%
*/
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+
#include "erl_driver.h"
#define THR_MSG_BLAST_NO_PROCS 10
diff --git a/erts/emulator/test/esock_misc/esock_iow_client.erl b/erts/emulator/test/esock_misc/esock_iow_client.erl
deleted file mode 100644
index 3e48a8f300..0000000000
--- a/erts/emulator/test/esock_misc/esock_iow_client.erl
+++ /dev/null
@@ -1,94 +0,0 @@
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 2020-2020. All Rights Reserved.
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%% %CopyrightEnd%
-%%
-
-%% ---------------------------------------------------------------------
-%%
-%% Writes small messages to a socket, until counters wrap!
-%%
-%% ---------------------------------------------------------------------
-
--module(esock_iow_client).
-
--export([start/1]).
-
--define(LIB, esock_iow_lib).
--define(LIMIT, 100000).
-
--define(MSG, <<"abcdefghijklmnopqrstuvxyz"
- "abcdefghijklmnopqrstuvxyz"
- "abcdefghijklmnopqrstuvxyz"
- "abcdefghijklmnopqrstuvxyz"
- "abcdefghijklmnopqrstuvxyz"
- "abcdefghijklmnopqrstuvxyz"
- "abcdefghijklmnopqrstuvxyz"
- "abcdefghijklmnopqrstuvxyz"
- "abcdefghijklmnopqrstuvxyz"
- "abcdefghijklmnopqrstuvxyz">>).
-
-
-%% ---------------------------------------------------------------------
-
-start(ServerPort) ->
- Domain = inet,
- ?LIB:iprint("open"),
- {ok, S} = socket:open(Domain, stream, tcp),
- ?LIB:iprint("iow"),
- ok = socket:setopt(S, otp, iow, true),
- ?LIB:iprint("bind"),
- LocalSA = #{family => Domain,
- addr => {147,214,93,147}},
- {ok, _} = socket:bind(S, LocalSA),
- ?LIB:iprint("connect (to ~w)", [ServerPort]),
- ServerSA = LocalSA#{port => ServerPort},
- ok = socket:connect(S, ServerSA),
- ?LIB:iprint("connected - now await begin"),
- case socket:recv(S, 0, infinity) of
- {ok, <<"begin">>} ->
- ?LIB:iprint("begin"),
- loop(S, 0);
- {error, Reason} ->
- ?LIB:eprint("failed receive begin: ~p", [Reason])
- end.
-
-loop(S, N) ->
- ok = socket:send(S, ?MSG),
- NextN = receive
- {'$socket', S, counter_wrap, Cnt} ->
- ?LIB:iprint("Counter ~w wrapped", [Cnt]),
- N + 1;
- Any ->
- ?LIB:iprint("Received: ~n ~p~n", [Any]),
- N + 1
- after 1 ->
- if (N < ?LIMIT) ->
- N+1;
- true ->
- ?LIB:iprint("Counters:"
- "~s", [?LIB:format_counters(cnts(S))]),
- 0
- end
- end,
- loop(S, NextN).
-
-
-cnts(S) ->
- #{counters := Cnts} = socket:info(S),
- Cnts.
-
diff --git a/erts/emulator/test/esock_misc/esock_iow_lib.erl b/erts/emulator/test/esock_misc/esock_iow_lib.erl
deleted file mode 100644
index 6fc1365dca..0000000000
--- a/erts/emulator/test/esock_misc/esock_iow_lib.erl
+++ /dev/null
@@ -1,123 +0,0 @@
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 2020-2020. All Rights Reserved.
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%% %CopyrightEnd%
-%%
-
--module(esock_iow_lib).
-
--export([
- format_counters/1, format_counters/2, format_counters/3,
- iprint/1, iprint/2,
- eprint/1, eprint/2,
- f/2,
- fts/0, fts/1
- ]).
-
-
-%% ---------------------------------------------------------------------
-
-format_counters(Counters) ->
- format_counters(traffic, Counters).
-
-format_counters(Type, Counters) when (Type =:= listen) orelse (Type =:= traffic) ->
- format_counters(" ", Type, Counters).
-
-format_counters(Prefix, traffic, Counters) ->
- ReadByte = proplists:get_value(read_byte, Counters, -1),
- ReadFails = proplists:get_value(read_fails, Counters, -1),
- ReadPkg = proplists:get_value(read_pkg, Counters, -1),
- ReadPkgMax = proplists:get_value(read_pkg_max, Counters, -1),
- ReadTries = proplists:get_value(read_tries, Counters, -1),
- ReadWaits = proplists:get_value(read_waits, Counters, -1),
- WriteByte = proplists:get_value(write_byte, Counters, -1),
- WriteFails = proplists:get_value(write_fails, Counters, -1),
- WritePkg = proplists:get_value(write_pkg, Counters, -1),
- WritePkgMax = proplists:get_value(write_pkg_max, Counters, -1),
- WriteTries = proplists:get_value(write_tries, Counters, -1),
- WriteWaits = proplists:get_value(write_waits, Counters, -1),
- f("~n~sNumber Of Read Bytes: ~p"
- "~n~sNumber Of Read Fails: ~p"
- "~n~sNumber Of Read Packages: ~p"
- "~n~sNumber Of Read Tries: ~p"
- "~n~sNumber Of Read Waits: ~p"
- "~n~sMax Read Package Size: ~p"
- "~n~sNumber Of Write Bytes: ~p"
- "~n~sNumber Of Write Fails: ~p"
- "~n~sNumber Of Write Packages: ~p"
- "~n~sNumber Of Write Tries: ~p"
- "~n~sNumber Of Write Waits: ~p"
- "~n~sMax Write Package Size: ~p",
- [Prefix, ReadByte,
- Prefix, ReadFails,
- Prefix, ReadPkg,
- Prefix, ReadTries,
- Prefix, ReadWaits,
- Prefix, ReadPkgMax,
- Prefix, WriteByte,
- Prefix, WriteFails,
- Prefix, WritePkg,
- Prefix, WriteTries,
- Prefix, WriteWaits,
- Prefix, WritePkgMax]);
-
-format_counters(Prefix, listen, Counters) ->
- AccSuccess = proplists:get_value(acc_success, Counters, -1),
- AccFails = proplists:get_value(acc_fails, Counters, -1),
- AccTries = proplists:get_value(acc_tries, Counters, -1),
- AccWaits = proplists:get_value(acc_waits, Counters, -1),
- f("~n~sNumber Of Successful Accepts: ~p"
- "~n~sNumber Of Failed Accepts: ~p"
- "~n~sNumber Of Accept Attempts: ~p"
- "~n~sNumber Of Accept Waits: ~p",
- [Prefix, AccSuccess,
- Prefix, AccFails,
- Prefix, AccTries,
- Prefix, AccWaits]).
-
-%% ---------------------------------------------------------------------
-
-iprint(F) ->
- iprint(F, []).
-
-iprint(F, A) ->
- print("INFO", F, A).
-
-eprint(F) ->
- iprint(F, []).
-
-eprint(F, A) ->
- print("ERROR", F, A).
-
-print(Pre, F, A) ->
- io:format("*** ~s *** ~s ~n" ++ F ++ "~n~n", [Pre, fts() | A]).
-
-
-f(F, A) ->
- lists:flatten(io_lib:format(F, A)).
-
-
-ts() ->
- os:timestamp().
-
-fts() ->
- fts(ts()).
-
-fts({_N1, _N2, N3} = TS) ->
- {_Date, Time} = calendar:now_to_local_time(TS),
- {Hour,Min,Sec} = Time,
- f("~.2.0w:~.2.0w:~.2.0w.4~w", [Hour, Min, Sec, round(N3/1000)]).
diff --git a/erts/emulator/test/esock_misc/esock_iow_server.erl b/erts/emulator/test/esock_misc/esock_iow_server.erl
deleted file mode 100644
index 4b364a6ca6..0000000000
--- a/erts/emulator/test/esock_misc/esock_iow_server.erl
+++ /dev/null
@@ -1,83 +0,0 @@
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 2020-2020. All Rights Reserved.
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%% %CopyrightEnd%
-%%
-
-%% ---------------------------------------------------------------------
-%%
-%% Reads small messages to a socket, until counters wrap!
-%%
-%% ---------------------------------------------------------------------
-
--module(esock_iow_server).
-
--export([start/0]).
-
--define(LIB, esock_iow_lib).
--define(LIMIT, 100000).
-
-
-%% ---------------------------------------------------------------------
-
-start() ->
- Domain = inet,
- ?LIB:iprint("open"),
- {ok, LSock} = socket:open(Domain, stream, tcp),
- ?LIB:iprint("iow"),
- ok = socket:setopt(LSock, otp, iow, true),
- ?LIB:iprint("bind"),
- LocalSA = #{family => Domain,
- addr => {147,214,93,147}},
- {ok, LPort} = socket:bind(LSock, LocalSA),
- ?LIB:iprint("listen port: ~p", [LPort]),
- ?LIB:iprint("make listen socket"),
- ok = socket:listen(LSock),
- ?LIB:iprint("accept"),
- {ok, CSock} = socket:accept(LSock),
- ok = socket:send(CSock, <<"begin">>),
- loop(CSock, 0).
-
-loop(S, N) ->
- case socket:recv(S) of
- {ok, _} when (N < ?LIMIT) ->
- flush(S),
- loop(S, N+1);
- {ok, _} ->
- ?LIB:iprint("Counters:"
- "~s", [?LIB:format_counters(cnts(S))]),
- flush(S),
- loop(S, 0);
- {error, Reason} ->
- ?LIB:eprint("failed receive: ~p", [Reason])
- end.
-
-
-cnts(S) ->
- #{counters := Cnts} = socket:info(S),
- Cnts.
-
-flush(S) ->
- receive
- {'$socket', S, counter_wrap, Cnt} ->
- ?LIB:iprint("Counter ~w wrapped", [Cnt]);
- Any ->
- ?LIB:iprint("Received: ~n ~p~n", [Any])
- after 0 ->
- ok
- end.
-
diff --git a/erts/emulator/test/esock_misc/socket_client.erl b/erts/emulator/test/esock_misc/socket_client.erl
deleted file mode 100644
index 891f7e67ab..0000000000
--- a/erts/emulator/test/esock_misc/socket_client.erl
+++ /dev/null
@@ -1,538 +0,0 @@
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 2018-2020. All Rights Reserved.
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%% %CopyrightEnd%
-%%
-
--module(socket_client).
-
--export([
- start/1, start/2, start/5, start/6,
- start_tcp/1, start_tcp/2, start_tcp/3,
- start_tcp4/1, start_tcp4/2, start_tcp6/1, start_tcp6/2,
- start_udp/1, start_udp/2, start_udp/3,
- start_udp4/1, start_udp4/2, start_udp6/1, start_udp6/2
- ]).
-
--define(LIB, socket_lib).
-
--record(client, {socket, verbose = true, msg = true, type, dest, msg_id = 1}).
-
-start(Port) ->
- start(Port, 1).
-
-start(Port, Num) ->
- start_tcp(Port, Num).
-
-start_tcp(Port) ->
- start_tcp(Port, 1).
-
-start_tcp(Port, Num) ->
- start_tcp4(Port, Num).
-
-start_tcp4(Port) ->
- start_tcp4(Port, 1).
-
-start_tcp4(Port, Num) ->
- start(inet, stream, tcp, Port, Num).
-
-start_tcp6(Port) ->
- start_tcp6(Port, 1).
-
-start_tcp6(Port, Num) ->
- start(inet6, stream, tcp, Port, Num).
-
-start_tcp(Addr, Port, Num) when (size(Addr) =:= 4) andalso
- is_integer(Num) andalso
- (Num > 0) ->
- start(inet, stream, tcp, Addr, Port, Num);
-start_tcp(Addr, Port, Num) when (size(Addr) =:= 8) andalso
- is_integer(Num) andalso
- (Num > 0) ->
- start(inet6, stream, tcp, Addr, Port, Num).
-
-
-start_udp(Port) ->
- start_udp(Port, 1).
-
-start_udp(Port, Num) ->
- start_udp4(Port, Num).
-
-start_udp4(Port) ->
- start_udp4(Port, 1).
-
-start_udp4(Port, Num) ->
- start(inet, dgram, udp, Port, Num).
-
-start_udp6(Port) ->
- start_udp6(Port, 1).
-
-start_udp6(Port, Num) ->
- start(inet6, dgram, udp, Port, Num).
-
-start_udp(Addr, Port, Num) when (size(Addr) =:= 4) ->
- start(inet, dgram, udp, Addr, Port, Num);
-start_udp(Addr, Port, Num) when (size(Addr) =:= 8) ->
- start(inet6, dgram, udp, Addr, Port, Num).
-
-
-start(Domain, Type, Proto, Port, Num)
- when is_integer(Port) andalso is_integer(Num) ->
- start(Domain, Type, Proto, which_addr(Domain), Port, Num);
-
-start(Domain, Type, Proto, Addr, Port) ->
- start(Domain, Type, Proto, Addr, Port, 1).
-
-start(Domain, Type, Proto, Addr, Port, 1 = Num) ->
- start(Domain, Type, Proto, Addr, Port, Num, true);
-start(Domain, Type, Proto, Addr, Port, Num)
- when is_integer(Num) andalso (Num > 1) ->
- start(Domain, Type, Proto, Addr, Port, Num, false).
-
-start(Domain, Type, Proto, Addr, Port, Num, Verbose) ->
- put(sname, "starter"),
- Clients = start_clients(Num, Domain, Type, Proto, Addr, Port, Verbose),
- await_clients(Clients).
-
-start_clients(Num, Domain, Type, Proto, Addr, Port, Verbose) ->
- start_clients(Num, 1, Domain, Type, Proto, Addr, Port, Verbose, []).
-
-start_clients(Num, ID, Domain, Type, Proto, Addr, Port, Verbose, Acc)
- when (Num > 0) ->
- StartClient = fun() ->
- start_client(ID, Domain, Type, Proto, Addr, Port, Verbose)
- end,
- {Pid, _} = spawn_monitor(StartClient),
- ?LIB:sleep(500),
- i("start client ~w", [ID]),
- start_clients(Num-1, ID+1, Domain, Type, Proto, Addr, Port, Verbose, [Pid|Acc]);
-start_clients(_, _, _, _, _, _, _, _, Acc) ->
- i("all client(s) started"),
- lists:reverse(Acc).
-
-await_clients([]) ->
- i("all clients done");
-await_clients(Clients) ->
- receive
- {'DOWN', _MRef, process, Pid, _Reason} ->
- case lists:delete(Pid, Clients) of
- Clients2 when (Clients2 =/= Clients) ->
- i("client ~p done", [Pid]),
- await_clients(Clients2);
- _ ->
- await_clients(Clients)
- end
- end.
-
-
-start_client(ID, Domain, Type, Proto, Addr, Port, Verbose) ->
- put(sname, ?LIB:f("client[~w]", [ID])),
- SA = #{family => Domain,
- addr => Addr,
- port => Port},
- %% The way we use tos only works because we
- %% send so few messages (a new value for every
- %% message).
- tos_init(),
- do_start(Domain, Type, Proto, SA, Verbose).
-
-do_start(Domain, stream = Type, Proto, SA, Verbose) ->
- try do_init(Domain, Type, Proto) of
- Sock ->
- connect(Sock, SA),
- maybe_print_start_info(Verbose, Sock, Type),
- %% Give the server some time...
- ?LIB:sleep(5000),
- %% ok = socket:close(Sock),
- send_loop(#client{socket = Sock,
- type = Type,
- verbose = Verbose})
- catch
- throw:E ->
- e("Failed initiate: "
- "~n Error: ~p", [E])
- end;
-do_start(Domain, dgram = Type, Proto, SA, Verbose) ->
- try do_init(Domain, Type, Proto) of
- Sock ->
- maybe_print_start_info(Verbose, Sock, Type),
- %% Give the server some time...
- ?LIB:sleep(5000),
- %% ok = socket:close(Sock),
- send_loop(#client{socket = Sock,
- type = Type,
- dest = SA,
- verbose = Verbose})
- catch
- throw:E ->
- e("Failed initiate: "
- "~n Error: ~p", [E])
- end.
-
-maybe_print_start_info(true = _Verbose, Sock, stream = _Type) ->
- {ok, Name} = socket:sockname(Sock),
- {ok, Peer} = socket:peername(Sock),
- {ok, Domain} = socket:getopt(Sock, socket, domain),
- {ok, Type} = socket:getopt(Sock, socket, type),
- {ok, Proto} = socket:getopt(Sock, socket, protocol),
- {ok, OOBI} = socket:getopt(Sock, socket, oobinline),
- {ok, SndBuf} = socket:getopt(Sock, socket, sndbuf),
- {ok, RcvBuf} = socket:getopt(Sock, socket, rcvbuf),
- {ok, Linger} = socket:getopt(Sock, socket, linger),
- {ok, MTU} = socket:getopt(Sock, ip, mtu),
- {ok, MTUDisc} = socket:getopt(Sock, ip, mtu_discover),
- {ok, MALL} = socket:getopt(Sock, ip, multicast_all),
- {ok, MIF} = socket:getopt(Sock, ip, multicast_if),
- {ok, MLoop} = socket:getopt(Sock, ip, multicast_loop),
- {ok, MTTL} = socket:getopt(Sock, ip, multicast_ttl),
- {ok, RecvTOS} = socket:getopt(Sock, ip, recvtos),
- i("connected: "
- "~n From: ~p"
- "~n To: ~p"
- "~nwhen"
- "~n (socket) Domain: ~p"
- "~n (socket) Type: ~p"
- "~n (socket) Protocol: ~p"
- "~n (socket) OOBInline: ~p"
- "~n (socket) SndBuf: ~p"
- "~n (socket) RcvBuf: ~p"
- "~n (socket) Linger: ~p"
- "~n (ip) MTU: ~p"
- "~n (ip) MTU Discovery: ~p"
- "~n (ip) Multicast ALL: ~p"
- "~n (ip) Multicast IF: ~p"
- "~n (ip) Multicast Loop: ~p"
- "~n (ip) Multicast TTL: ~p"
- "~n (ip) RecvTOS: ~p"
- "~n => wait some",
- [Name, Peer,
- Domain, Type, Proto,
- OOBI, SndBuf, RcvBuf, Linger,
- MTU, MTUDisc, MALL, MIF, MLoop, MTTL,
- RecvTOS]);
-maybe_print_start_info(true = _Verbose, Sock, dgram = _Type) ->
- {ok, Domain} = socket:getopt(Sock, socket, domain),
- {ok, Type} = socket:getopt(Sock, socket, type),
- {ok, Proto} = socket:getopt(Sock, socket, protocol),
- {ok, OOBI} = socket:getopt(Sock, socket, oobinline),
- {ok, SndBuf} = socket:getopt(Sock, socket, sndbuf),
- {ok, RcvBuf} = socket:getopt(Sock, socket, rcvbuf),
- {ok, Linger} = socket:getopt(Sock, socket, linger),
- {ok, MALL} = socket:getopt(Sock, ip, multicast_all),
- {ok, MIF} = socket:getopt(Sock, ip, multicast_if),
- {ok, MLoop} = socket:getopt(Sock, ip, multicast_loop),
- {ok, MTTL} = socket:getopt(Sock, ip, multicast_ttl),
- {ok, RecvTOS} = socket:getopt(Sock, ip, recvtos),
- {ok, RecvTTL} = socket:getopt(Sock, ip, recvttl),
- i("initiated when: "
- "~n (socket) Domain: ~p"
- "~n (socket) Type: ~p"
- "~n (socket) Protocol: ~p"
- "~n (socket) OOBInline: ~p"
- "~n (socket) SndBuf: ~p"
- "~n (socket) RcvBuf: ~p"
- "~n (socket) Linger: ~p"
- "~n (ip) Multicast ALL: ~p"
- "~n (ip) Multicast IF: ~p"
- "~n (ip) Multicast Loop: ~p"
- "~n (ip) Multicast TTL: ~p"
- "~n (ip) RecvTOS: ~p"
- "~n (ip) RecvTTL: ~p"
- "~n => wait some",
- [Domain, Type, Proto,
- OOBI, SndBuf, RcvBuf, Linger,
- MALL, MIF, MLoop, MTTL,
- RecvTOS, RecvTTL]);
-maybe_print_start_info(_Verbose, _Sock, _Type) ->
- ok.
-
-
-do_init(Domain, stream = Type, Proto) ->
- i("try (socket) open"),
- Sock = case socket:open(Domain, Type, Proto) of
- {ok, S} ->
- S;
- {error, OReason} ->
- throw({open, OReason})
- end,
- i("try (socket) bind"),
- case socket:bind(Sock, any) of
- {ok, _P} ->
- ok = socket:setopt(Sock, socket, timestamp, true),
- ok = socket:setopt(Sock, ip, tos, mincost),
- ok = socket:setopt(Sock, ip, recvtos, true),
- Sock;
- {error, BReason} ->
- throw({bind, BReason})
- end;
-do_init(Domain, dgram = Type, Proto) ->
- i("try (socket) open"),
- Sock = case socket:open(Domain, Type, Proto) of
- {ok, S} ->
- S;
- {error, OReason} ->
- throw({open, OReason})
- end,
- case socket:bind(Sock, any) of
- {ok, _} ->
- ok = socket:setopt(Sock, socket, timestamp, true),
- ok = socket:setopt(Sock, ip, tos, mincost),
- ok = socket:setopt(Sock, ip, recvtos, true),
- ok = socket:setopt(Sock, ip, recvttl, true),
- Sock;
- {error, BReason} ->
- throw({bind, BReason})
- end.
-
-
-which_addr(Domain) ->
- Iflist = case inet:getifaddrs() of
- {ok, IFL} ->
- IFL;
- {error, Reason} ->
- throw({inet,getifaddrs,Reason})
- end,
- which_addr(Domain, Iflist).
-
-
-connect(Sock, SA) ->
- i("try (socket) connect to:"
- "~n ~p", [SA]),
- case socket:connect(Sock, SA) of
- ok ->
- ok;
- {error, Reason} ->
- e("connect failure: "
- "~n ~p", [Reason]),
- exit({connect, Reason})
- end.
-
-
-send_loop(#client{msg_id = N} = C) when (N =< 10) ->
- i("try send request ~w", [N]),
- Req = ?LIB:enc_req_msg(N, "hejsan"),
- case send(C, Req) of
- ok ->
- i("request ~w sent - now try read answer", [N]),
- case recv(C) of
- {ok, {Source, Msg}} ->
- if
- (C#client.verbose =:= true) ->
- i("received ~w bytes of data~s",
- [size(Msg), case Source of
- undefined -> "";
- _ -> ?LIB:f(" from:~n ~p", [Source])
- end]);
- true ->
- i("received ~w bytes", [size(Msg)])
- end,
- case ?LIB:dec_msg(Msg) of
- {reply, N, Reply} ->
- if
- (C#client.verbose =:= true) ->
- i("received reply ~w: ~p", [N, Reply]);
- true ->
- i("received reply ~w", [N])
- end,
- ?LIB:sleep(500), % Just to spread it out a bit
- send_loop(C#client{msg_id = N+1})
- end;
- {error, RReason} ->
- e("Failed recv response for request ~w: "
- "~n ~p", [N, RReason]),
- exit({failed_recv, RReason})
- end;
- {error, SReason} ->
- e("Failed send request ~w: "
- "~n ~p", [N, SReason]),
- exit({failed_send, SReason})
- end;
-send_loop(Client) ->
- sock_close(Client).
-
-sock_close(#client{socket = Sock, verbose = true}) ->
- i("we are done - close the socket when: "
- "~n ~p", [socket:info()]),
- ok = socket:close(Sock),
- i("we are done - socket closed when: "
- "~n ~p", [socket:info()]);
-sock_close(#client{socket = Sock}) ->
- i("we are done"),
- ok = socket:close(Sock).
-
-
-
-send(#client{socket = Sock, type = stream}, Msg) ->
- socket:send(Sock, Msg);
-send(#client{socket = Sock, type = dgram, dest = Dest}, Msg) ->
- %% i("try send to: "
- %% "~n ~p", [Dest]),
- %% ok = socket:setopt(Sock, otp, debug, true),
- TOS = tos_next(),
- ok = socket:setopt(Sock, ip, tos, TOS),
- case socket:sendto(Sock, Msg, Dest) of
- ok = OK ->
- OK;
- {error, _} = ERROR ->
- ERROR
- end.
-
-recv(#client{socket = Sock, type = stream, msg = false}) ->
- case socket:recv(Sock) of
- {ok, Msg} ->
- {ok, {undefined, Msg}};
- {error, _} = ERROR ->
- ERROR
- end;
-recv(#client{socket = Sock, verbose = Verbose, type = stream, msg = true}) ->
- case socket:recvmsg(Sock) of
- %% An iov of length 1 is an simplification...
- {ok, #{addr := undefined = Source,
- iov := [Msg],
- ctrl := CMsgHdrs,
- flags := Flags}} ->
- if
- (Verbose =:= true) ->
- i("received message: "
- "~n CMsgHdr: ~p"
- "~n Flags: ~p", [CMsgHdrs, Flags]);
- true ->
- ok
- end,
- {ok, {Source, Msg}};
- {error, _} = ERROR ->
- ERROR
- end;
-recv(#client{socket = Sock, type = dgram, msg = false}) ->
- socket:recvfrom(Sock);
-recv(#client{socket = Sock, verbose = Verbose, type = dgram, msg = true}) ->
- case socket:recvmsg(Sock) of
- {ok, #{addr := Source,
- iov := [Msg],
- ctrl := CMsgHdrs,
- flags := Flags}} ->
- if
- (Verbose =:= true) ->
- i("received message: "
- "~n CMsgHdr: ~p"
- "~n Flags: ~p", [CMsgHdrs, Flags]);
- true ->
- ok
- end,
- {ok, {Source, Msg}};
- {error, _} = ERROR ->
- ERROR
- end.
-
-
-
-which_addr(_Domain, []) ->
- throw(no_address);
-which_addr(Domain, [{Name, IFO}|_IFL]) when (Name =/= "lo") ->
- which_addr2(Domain, IFO);
-which_addr(Domain, [_|IFL]) ->
- which_addr(Domain, IFL).
-
-which_addr2(inet = _Domain, [{addr, Addr}|_IFO]) when (size(Addr) =:= 4) ->
- Addr;
-which_addr2(inet6 = _Domain, [{addr, Addr}|_IFO]) when (size(Addr) =:= 8) ->
- Addr;
-which_addr2(Domain, [_|IFO]) ->
- which_addr2(Domain, IFO).
-
-
-%% ---
-
-%% enc_req_msg(N, Data) ->
-%% enc_msg(?REQ, N, Data).
-
-%% enc_rep_msg(N, Data) ->
-%% enc_msg(?REP, N, Data).
-
-%% enc_msg(Type, N, Data) when is_list(Data) ->
-%% enc_msg(Type, N, list_to_binary(Data));
-%% enc_msg(Type, N, Data)
-%% when is_integer(Type) andalso is_integer(N) andalso is_binary(Data) ->
-%% <<Type:32/integer, N:32/integer, Data/binary>>.
-
-%% dec_msg(<<?REQ:32/integer, N:32/integer, Data/binary>>) ->
-%% {request, N, Data};
-%% dec_msg(<<?REP:32/integer, N:32/integer, Data/binary>>) ->
-%% {reply, N, Data}.
-
-
-%% ---
-
-%% sleep(T) ->
-%% receive after T -> ok end.
-
-
-%% ---
-
-%% formated_timestamp() ->
-%% format_timestamp(os:timestamp()).
-
-%% format_timestamp(Now) ->
-%% N2T = fun(N) -> calendar:now_to_local_time(N) end,
-%% format_timestamp(Now, N2T, true).
-
-%% format_timestamp({_N1, _N2, N3} = N, N2T, true) ->
-%% FormatExtra = ".~.2.0w",
-%% ArgsExtra = [N3 div 10000],
-%% format_timestamp(N, N2T, FormatExtra, ArgsExtra);
-%% format_timestamp({_N1, _N2, _N3} = N, N2T, false) ->
-%% FormatExtra = "",
-%% ArgsExtra = [],
-%% format_timestamp(N, N2T, FormatExtra, ArgsExtra).
-
-%% format_timestamp(N, N2T, FormatExtra, ArgsExtra) ->
-%% {Date, Time} = N2T(N),
-%% {YYYY,MM,DD} = Date,
-%% {Hour,Min,Sec} = Time,
-%% FormatDate =
-%% io_lib:format("~.4w-~.2.0w-~.2.0w ~.2.0w:~.2.0w:~.2.0w" ++ FormatExtra,
-%% [YYYY, MM, DD, Hour, Min, Sec] ++ ArgsExtra),
-%% lists:flatten(FormatDate).
-
-
-%% ---
-
-tos_init() ->
- put(tos, 1).
-
-tos_next() ->
- case get(tos) of
- TOS when (TOS < 100) ->
- put(tos, TOS + 1),
- TOS;
- _ ->
- put(tos, 1),
- 1
- end.
-
-
-%% ---
-
-e(F, A) ->
- ?LIB:e(F, A).
-
-i(F) ->
- ?LIB:i(F).
-
-i(F, A) ->
- ?LIB:i(F, A).
-
diff --git a/erts/emulator/test/esock_misc/socket_lib.erl b/erts/emulator/test/esock_misc/socket_lib.erl
deleted file mode 100644
index e401a3195c..0000000000
--- a/erts/emulator/test/esock_misc/socket_lib.erl
+++ /dev/null
@@ -1,133 +0,0 @@
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 2018-2020. All Rights Reserved.
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%% %CopyrightEnd%
-%%
-
--module(socket_lib).
-
--export([
- sleep/1,
- req/0, rep/0,
- enc_req_msg/2, enc_rep_msg/2,
- enc_msg/3, dec_msg/1,
- request/3, reply/4,
- f/2,
- i/1, i/2,
- e/2
- ]).
-
-
--define(REQ, 0).
--define(REP, 1).
-
-
-%% ---
-
-sleep(T) ->
- receive after T -> ok end.
-
-
-%% ---
-
-req() -> ?REQ.
-rep() -> ?REP.
-
-enc_req_msg(N, Data) ->
- enc_msg(?REQ, N, Data).
-
-enc_rep_msg(N, Data) ->
- enc_msg(?REP, N, Data).
-
-enc_msg(Type, N, Data) when is_list(Data) ->
- enc_msg(Type, N, list_to_binary(Data));
-enc_msg(Type, N, Data)
- when is_integer(Type) andalso is_integer(N) andalso is_binary(Data) ->
- <<Type:32/integer, N:32/integer, Data/binary>>.
-
-dec_msg(<<?REQ:32/integer, N:32/integer, Data/binary>>) ->
- {request, N, Data};
-dec_msg(<<?REP:32/integer, N:32/integer, Data/binary>>) ->
- {reply, N, Data}.
-
-
-%% ---
-
-request(Tag, Pid, Request) ->
- Ref = make_ref(),
- Pid ! {Tag, self(), Ref, Request},
- receive
- {Tag, Pid, Ref, Reply} ->
- Reply
- end.
-
-reply(Tag, Pid, Ref, Reply) ->
- Pid ! {Tag, self(), Ref, Reply}.
-
-
-%% ---
-
-f(F, A) ->
- lists:flatten(io_lib:format(F, A)).
-
-
-%% ---
-
-e(F, A) ->
- p("<ERROR> " ++ F, A).
-
-i(F) ->
- i(F, []).
-i(F, A) ->
- p("*** " ++ F, A).
-
-p(F, A) ->
- p(get(sname), F, A).
-
-p(SName, F, A) ->
- io:format("[~s,~p][~s] " ++ F ++ "~n",
- [SName,self(),formated_timestamp()|A]).
-
-
-%% ---
-
-formated_timestamp() ->
- format_timestamp(os:timestamp()).
-
-format_timestamp(Now) ->
- N2T = fun(N) -> calendar:now_to_local_time(N) end,
- format_timestamp(Now, N2T, true).
-
-format_timestamp({_N1, _N2, N3} = N, N2T, true) ->
- FormatExtra = ".~.2.0w",
- ArgsExtra = [N3 div 10000],
- format_timestamp(N, N2T, FormatExtra, ArgsExtra);
-format_timestamp({_N1, _N2, _N3} = N, N2T, false) ->
- FormatExtra = "",
- ArgsExtra = [],
- format_timestamp(N, N2T, FormatExtra, ArgsExtra).
-
-format_timestamp(N, N2T, FormatExtra, ArgsExtra) ->
- {Date, Time} = N2T(N),
- {YYYY,MM,DD} = Date,
- {Hour,Min,Sec} = Time,
- FormatDate =
- io_lib:format("~.4w-~.2.0w-~.2.0w ~.2.0w:~.2.0w:~.2.0w" ++ FormatExtra,
- [YYYY, MM, DD, Hour, Min, Sec] ++ ArgsExtra),
- lists:flatten(FormatDate).
-
-
diff --git a/erts/emulator/test/esock_misc/socket_server.erl b/erts/emulator/test/esock_misc/socket_server.erl
deleted file mode 100644
index 161ea17027..0000000000
--- a/erts/emulator/test/esock_misc/socket_server.erl
+++ /dev/null
@@ -1,954 +0,0 @@
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 2018-2020. All Rights Reserved.
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%% %CopyrightEnd%
-%%
-
--module(socket_server).
-
--export([
- start/0, start/5,
- start_tcp/0, start_tcp/1, start_tcp/3,
- start_tcp4/0, start_tcp4/1, start_tcp4/2,
- start_tcp6/0, start_tcp6/1, start_tcp6/2,
- start_udp/0, start_udp/1, start_udp/3,
- start_udp4/0, start_udp4/1, start_udp4/2,
- start_udp6/0, start_udp6/1, start_udp6/2,
- start_sctp/0, start_sctp/1
- ]).
-
--define(LIB, socket_lib).
-
--record(manager, {socket, msg, peek, acceptors, handler_id, handlers}).
--record(acceptor, {id, socket, manager,
- atimeout = 5000}).
--record(handler, {socket, peek, msg, type, manager,
- stimeout = 5000, rtimeout = 5000}).
-
--define(NUM_ACCEPTORS, 5).
-
-start() ->
- start_tcp().
-
-start_tcp() ->
- start_tcp4().
-
-start_tcp(Peek) ->
- start_tcp4(Peek).
-
-start_tcp4() ->
- start_tcp4(false).
-
-start_tcp4(Peek) ->
- start_tcp4(false, Peek).
-
-start_tcp4(UseMsg, Peek) ->
- start_tcp(inet, UseMsg, Peek).
-
-start_tcp6() ->
- start_tcp6(false).
-
-start_tcp6(Peek) ->
- start_tcp6(false, Peek).
-
-start_tcp6(UseMsg, Peek) ->
- start_tcp(inet6, UseMsg, Peek).
-
-start_tcp(Domain, UseMsg, Peek) when is_boolean(UseMsg) andalso is_boolean(Peek) ->
- start(Domain, stream, tcp, UseMsg, Peek).
-
-start_udp() ->
- start_udp4().
-
-start_udp(Peek) ->
- start_udp4(Peek).
-
-start_udp4() ->
- start_udp4(false).
-
-start_udp4(Peek) ->
- start_udp4(false, Peek).
-
-start_udp4(UseMsg, Peek) ->
- start_udp(inet, UseMsg, Peek).
-
-start_udp6() ->
- start_udp6(false, false).
-
-start_udp6(Peek) ->
- start_udp6(false, Peek).
-
-start_udp6(UseMsg, Peek) ->
- start_udp(inet6, UseMsg, Peek).
-
-start_udp(Domain, UseMsg, Peek) when is_boolean(UseMsg) andalso is_boolean(Peek) ->
- start(Domain, dgram, udp, UseMsg, Peek).
-
-
-start_sctp() ->
- start_sctp(inet).
-
-start_sctp(Domain) when ((Domain =:= inet) orelse (Domain =:= inet6)) ->
- start(Domain, seqpacket, sctp, true, false).
-
-start(Domain, Type, Proto, UseMsg, Peek) ->
- put(sname, "starter"),
- i("try start manager"),
- {Pid, MRef} = manager_start(Domain, Type, Proto, UseMsg, Peek),
- i("manager (~p) started", [Pid]),
- loop(Pid, MRef).
-
-loop(Pid, MRef) ->
- receive
- {'DOWN', MRef, process, Pid, Reason} ->
- i("manager process exited: "
- "~n ~p", [Reason]),
- ok
- end.
-
-
-%% =========================================================================
-
-manager_start(Domain, Type, Proto, UseMsg, Peek) ->
- spawn_monitor(fun() -> manager_init(Domain, Type, Proto, UseMsg, Peek) end).
-
-manager_start_handler(Pid, Sock) ->
- manager_request(Pid, {start_handler, Sock}).
-
-manager_stop(Pid, Reason) ->
- manager_request(Pid, {stop, Reason}).
-
-manager_request(Pid, Request) ->
- ?LIB:request(manager, Pid, Request).
-
-manager_reply(Pid, Ref, Reply) ->
- ?LIB:reply(manager, Pid, Ref, Reply).
-
-
-manager_init(Domain, Type, Proto, UseMsg, Peek) ->
- put(sname, "manager"),
- do_manager_init(Domain, Type, Proto, UseMsg, Peek).
-
-do_manager_init(Domain, stream = Type, Proto, UseMsg, Peek) ->
- i("try start acceptor(s)"),
- {Sock, Acceptors} = manager_stream_init(Domain, Type, Proto),
- manager_loop(#manager{socket = Sock,
- msg = UseMsg,
- peek = Peek,
- acceptors = Acceptors,
- handler_id = 1,
- handlers = []});
-do_manager_init(Domain, dgram = Type, Proto, UseMsg, Peek) ->
- i("try open socket"),
- case socket:open(Domain, Type, Proto) of
- {ok, Sock} ->
- F = fun(X) -> case socket:getopt(Sock, socket, X) of
- {ok, V} -> f("~p", [V]);
- {error, R} -> f("error: ~p", [R])
- end
- end,
- i("socket opened (~s,~s,~s): "
- "~n broadcast: ~s"
- "~n dontroute: ~s"
- "~n keepalive: ~s"
- "~n reuseaddr: ~s"
- "~n linger: ~s"
- "~n debug: ~s"
- "~n prio: ~s"
- "~n rcvbuf: ~s"
- "~n rcvtimeo: ~s"
- "~n sndbuf: ~s"
- "~n sndtimeo: ~s"
- "~n => try find (local) address",
- [F(domain), F(type), F(protocol),
- F(broadcast), F(dontroute), F(keepalive), F(reuseaddr), F(linger),
- F(debug), F(priority),
- F(rcvbuf), F(rcvtimeo), F(sndbuf), F(sndtimeo)]),
- Addr = which_addr(Domain),
- SA = #{family => Domain,
- addr => Addr},
- i("try bind to: "
- "~n ~p", [Addr]),
- case socket:bind(Sock, SA) of
- {ok, _P} ->
- ok;
- {error, BReason} ->
- throw({bind, BReason})
- end,
- i("bound to: "
- "~n ~s"
- "~n => try start handler",
- [case socket:sockname(Sock) of
- {ok, Name} -> f("~p", [Name]);
- {error, R} -> f("error: ~p", [R])
- end]),
- case handler_start(1, Sock, UseMsg, Peek) of
- {ok, {Pid, MRef}} ->
- i("handler (~p) started", [Pid]),
- handler_continue(Pid),
- manager_loop(#manager{peek = Peek,
- msg = UseMsg,
- handler_id = 2, % Just in case
- handlers = [{1, Pid, MRef}]});
- {error, SReason} ->
- e("Failed starting handler: "
- "~n ~p", [SReason]),
- exit({failed_start_handler, SReason})
- end;
- {error, OReason} ->
- e("Failed open socket: "
- "~n ~p", [OReason]),
- exit({failed_open_socket, OReason})
- end;
-do_manager_init(Domain, seqpacket = Type, sctp = Proto, _UseMsg, _Peek) ->
- %% This is as far as I have got with SCTP at the moment...
- case socket:open(Domain, Type, Proto) of
- {ok, Sock} ->
- i("(sctp) socket opened: "
- "~n ~p", [Sock]),
- EXP = fun(_Desc, Expect, Expect) ->
- Expect;
- (Desc, Expect, Actual) ->
- e("Unexpected result ~w: "
- "~n Expect: ~p"
- "~n Actual: ~p", [Desc, Expect, Actual]),
- exit({Desc, Expect, Actual})
- end,
- GO = fun(O) -> case socket:getopt(Sock, sctp, O) of
- {ok, V} -> f("~p", [V]);
- {error, R} -> f("error: ~p", [R])
- end
- end,
- %% ok = socket:setopt(Sock, otp, debug, true),
-
- i("Miscellaneous options: "
- "~n associnfo: ~s"
- "~n autoclose: ~s"
- "~n disable-fragments: ~s"
- "~n initmsg: ~s"
- "~n maxseg: ~s"
- "~n nodelay: ~s"
- "~n rtoinfo: ~s",
- [GO(associnfo),
- GO(autoclose),
- GO(disable_fragments),
- GO(initmsg),
- GO(maxseg),
- GO(nodelay),
- GO(rtoinfo)]),
-
- Events = #{data_in => true,
- association => true,
- address => true,
- send_failure => true,
- peer_error => true,
- shutdown => true,
- partial_delivery => true,
- adaptation_layer => true,
- authentication => true,
- sender_dry => true},
- EXP(set_sctp_events, ok, socket:setopt(Sock, sctp, events, Events)),
- EXP(close_socket, ok, socket:close(Sock));
- {error, Reason} ->
- exit({failed_open, Reason})
- end;
-do_manager_init(Domain, raw = Type, Proto, UseMsg, Peek) when is_integer(Proto) ->
- do_manager_init(Domain, Type, {raw, Proto}, UseMsg, Peek);
-do_manager_init(Domain, raw = Type, Proto, _UseMsg, _Peek) ->
- case socket:open(Domain, Type, Proto) of
- {ok, Sock} ->
- i("(sctp) socket opened: "
- "~n ~p", [Sock]),
- socket:close(Sock);
- {error, Reason} ->
- exit({failed_open, Reason})
- end.
-
-
-
-manager_stream_init(Domain, Type, Proto) ->
- i("try (socket) open"),
- Sock = case socket:open(Domain, Type, Proto) of
- {ok, S} ->
- S;
- {error, OReason} ->
- throw({open, OReason})
- end,
- F = fun(X) -> case socket:getopt(Sock, socket, X) of
- {ok, V} -> f("~p", [V]);
- {error, R} -> f("error: ~p", [R])
- end
- end,
- i("(socket) open (~s,~s,~s): "
- "~n debug: ~s"
- "~n prio: ~s"
- "~n => try find (local) address",
- [F(domain), F(type), F(protocol), F(debug), F(priority)]),
- Addr = which_addr(Domain),
- SA = #{family => Domain,
- addr => Addr},
- i("found: "
- "~n ~p"
- "~n => try (socket) bind", [Addr]),
- %% ok = socket:setopt(Sock, otp, debug, true),
- %% ok = socket:setopt(Sock, socket, debug, 1), %% must have rights!!
- Port = case socket:bind(Sock, SA) of
- {ok, P} ->
- %% ok = socket:setopt(Sock, socket, debug, 0), %% must have rights!!
- %% ok = socket:setopt(Sock, otp, debug, false),
- P;
- {error, BReason} ->
- throw({bind, BReason})
- end,
- i("bound to: "
- "~n ~p"
- "~n => try (socket) listen (acceptconn: ~s)",
- [Port, F(acceptconn)]),
- case socket:listen(Sock) of
- ok ->
- i("listening (acceptconn: ~s)",
- [F(acceptconn)]),
- manager_stream_init(Sock, 1, ?NUM_ACCEPTORS, []);
- {error, LReason} ->
- throw({listen, LReason})
- end.
-
-which_addr(Domain) ->
- Iflist = case inet:getifaddrs() of
- {ok, IFL} ->
- IFL;
- {error, Reason} ->
- throw({inet,getifaddrs,Reason})
- end,
- which_addr(Domain, Iflist).
-
-which_addr(_Domain, []) ->
- throw(no_address);
-which_addr(Domain, [{Name, IFO}|_IFL]) when (Name =/= "lo") ->
- which_addr2(Domain, IFO);
-which_addr(Domain, [_|IFL]) ->
- which_addr(Domain, IFL).
-
-which_addr2(_, []) ->
- throw(no_address);
-which_addr2(inet = _Domain, [{addr, Addr}|_IFO]) when (size(Addr) =:= 4) ->
- Addr;
-which_addr2(inet6 = _Domain, [{addr, Addr}|_IFO]) when (size(Addr) =:= 8) ->
- Addr;
-which_addr2(Domain, [_|IFO]) ->
- which_addr2(Domain, IFO).
-
-
-manager_stream_init(Sock, ID, NumAcceptors, Acc)
- when (NumAcceptors > 0) ->
- i("try start acceptor"),
- case acceptor_start(Sock, ID) of
- {ok, {Pid, MRef}} ->
- i("acceptor ~w (~p) started", [ID, Pid]),
- ?LIB:sleep(2000),
- manager_stream_init(Sock, ID+1, NumAcceptors-1,
- [{ID, Pid, MRef}|Acc]);
- {error, Reason} ->
- exit({failed_starting_acceptor, Reason})
- end;
-manager_stream_init(Sock, _ID, 0, Acc) ->
- %% Req = {kill_acceptor, length(Acc)}, % Last in the queue
- %% Req = {kill_acceptor, 3}, % In the "middle" of the queue
- %% Req = {kill_acceptor, 2}, % The first in the queue
- %% Req = {kill_acceptor, 1}, % Current acceptor
- %% Msg = {manager, self(), make_ref(), Req},
- %% erlang:send_after(timer:seconds(10), self(), Msg),
- {Sock, lists:reverse(Acc)}.
-
-
-manager_loop(M) ->
- receive
- {'DOWN', MRef, process, Pid, Reason} ->
- M2 = manager_handle_down(M, MRef, Pid, Reason),
- manager_loop(M2);
-
- {manager, Pid, Ref, Request} ->
- M2 = manager_handle_request(M, Pid, Ref, Request),
- manager_loop(M2)
- end.
-
-
-manager_handle_down(#manager{acceptors = Acceptors,
- handlers = Handlers} = M, MRef, Pid, Reason) ->
- case lists:keysearch(Pid, 2, Acceptors) of
- {value, {ID, Pid, MRef}} when (Reason =:= normal) ->
- i("acceptor ~w exited (normally)", [ID]),
- case lists:keydelete(Pid, 2, Acceptors) of
- [] ->
- %% We are done
- i("the last acceptor - we are done"),
- exit(normal);
- Acceptors2 ->
- M#manager{acceptors = Acceptors2}
- end;
- {value, {ID, Pid, MRef}} ->
- e("acceptor ~w crashed: "
- "~n ~p", [ID, Reason]),
- exit({acceptor_died, Reason});
-
- false -> %% handler!
- if
- (Reason =/= normal) ->
- e("handler ~p died: "
- "~n ~p", [Pid, Reason]);
- true ->
- i("handler ~p terminated", [Pid])
- end,
- Handlers2 = lists:keydelete(Pid, 2, Handlers),
- M#manager{handlers = Handlers2}
- end.
-
-
-manager_handle_request(#manager{peek = Peek,
- msg = UseMsg,
- handler_id = HID,
- handlers = Handlers} = M, Pid, Ref,
- {start_handler, Sock}) ->
- i("try start handler (~w)", [HID]),
- case handler_start(HID, Sock, UseMsg, Peek) of
- {ok, {HPid, HMRef}} ->
- i("handler ~w started", [HID]),
- manager_reply(Pid, Ref, {ok, HPid}),
- M#manager{handler_id = HID+1,
- handlers = [{HID, HPid, HMRef}|Handlers]};
- {error, Reason} = ERROR ->
- e("Failed starting new handler: "
- "~n Sock: ~p"
- "~n Reason: ~p", [Sock, Reason]),
- manager_reply(Pid, Ref, ERROR),
- M
- end;
-manager_handle_request(#manager{socket = Sock,
- acceptors = [{AID, APid, AMRef}]} = M, _Pid, _Ref,
- {kill_acceptor, AID}) ->
- i("try kill (only remeining) acceptor ~w", [AID]),
- socket:setopt(Sock, otp, debug, true),
- manager_stop_acceptor(APid, AMRef, AID, kill),
- M#manager{acceptors = []};
-manager_handle_request(#manager{socket = Sock,
- acceptors = Acceptors} = M, _Pid, _Ref,
- {kill_acceptor, AID}) ->
- i("try kill acceptor ~w", [AID]),
- case lists:keysearch(AID, 1, Acceptors) of
- {value, {AID, APid, AMRef}} ->
- socket:setopt(Sock, otp, debug, true),
- manager_stop_acceptor(APid, AMRef, AID, kill),
- Acceptors2 = lists:keydelete(AID, 1, Acceptors),
- M#manager{acceptors = Acceptors2};
- false ->
- e("no such acceptor"),
- M
- end;
-manager_handle_request(#manager{acceptors = Acceptors,
- handlers = Handlers}, Pid, Ref,
- {stop, Reason}) ->
- i("stop"),
- manager_reply(Pid, Ref, ok),
- manager_stop_handlers(Handlers, Reason),
- manager_stop_acceptors(Acceptors, Reason),
- i("stopped", []),
- exit(Reason).
-
-manager_stop_acceptors(Acceptors, Reason) ->
- lists:foreach(fun({ID,P,M}) ->
- manager_stop_acceptor(P, M, ID, Reason)
- end, Acceptors).
-
-manager_stop_acceptor(Pid, MRef, ID, Reason) ->
- i("try stop acceptor ~w (~p): ~p", [ID, Pid, Reason]),
- erlang:demonitor(MRef, [flush]),
- acceptor_stop(Pid, Reason),
- ok.
-
-manager_stop_handlers(Handlers, Reason) ->
- lists:foreach(fun({ID,P,M}) ->
- manager_stop_handler(P, M, ID, Reason)
- end, Handlers).
-
-manager_stop_handler(Pid, MRef, ID, Reason) ->
- i("try stop handler ~w (~p): ~p", [ID, Pid, Reason]),
- erlang:demonitor(MRef, [flush]),
- handler_stop(Pid, Reason),
- ok.
-
-
-
-%% =========================================================================
-
-acceptor_start(Sock, ID) ->
- Self = self(),
- A = {Pid, _} = spawn_monitor(fun() ->
- acceptor_init(Self, Sock, ID)
- end),
- receive
- {acceptor, Pid, ok} ->
- {ok, A};
- {acceptor, Pid, {error, _} = Error} ->
- exit(Pid, kill), % Just in case
- Error;
- {'DOWN', _MRef, process, Pid, Reason} ->
- {error, {crashed, Reason}}
- end.
-
-acceptor_stop(Pid, _Reason) ->
- %% acceptor_request(Pid, {stop, Reason}).
- exit(Pid, kill).
-
-%% acceptor_request(Pid, Request) ->
-%% request(acceptor, Pid, Request).
-
-%% acceptor_reply(Pid, Ref, Reply) ->
-%% reply(acceptor, Pid, Ref, Reply).
-
-
-acceptor_init(Manager, Sock, ID) ->
- put(sname, f("acceptor[~w]", [ID])),
- Manager ! {acceptor, self(), ok},
- %% ok = socket:setopt(Sock, otp, debug, true),
- acceptor_loop(#acceptor{id = ID,
- manager = Manager,
- socket = Sock}).
-
-acceptor_loop(#acceptor{socket = LSock, atimeout = Timeout} = A) ->
- i("try accept"),
- case socket:accept(LSock, Timeout) of
- {ok, Sock} ->
- i("accepted: "
- "~n ~p"
- "~nwhen"
- "~n ~p", [Sock, socket:info()]),
- case acceptor_handle_accept_success(A, Sock) of
- ok ->
- acceptor_loop(A);
- {error, Reason} ->
- e("Failed starting handler: "
- "~n ~p", [Reason]),
- socket:close(Sock),
- exit({failed_starting_handler, Reason})
- end;
- {error, timeout} ->
- i("timeout"),
- acceptor_loop(A);
- {error, Reason} ->
- e("accept failure: "
- "~n ~p", [Reason]),
- exit({accept, Reason})
- end.
-
-acceptor_handle_accept_success(#acceptor{manager = Manager}, Sock) ->
- i("try start handler for peer"
- "~n ~p", [case socket:peername(Sock) of
- {ok, Peer} -> Peer;
- {error, _} = E -> E
- end]),
- case manager_start_handler(Manager, Sock) of
- {ok, Pid} ->
- i("handler (~p) started - now change 'ownership'", [Pid]),
- case socket:setopt(Sock, otp, controlling_process, Pid) of
- ok ->
- %% Normally we should have a msgs collection here
- %% (of messages we receive before the control was
- %% handled over to Handler), but since we don't
- %% have active implemented yet...
- i("new handler (~p) now controlling process", [Pid]),
- handler_continue(Pid),
- ok;
- {error, _} = ERROR ->
- exit(Pid, kill),
- ERROR
- end;
- {error, Reason2} ->
- e("failed starting handler: "
- "~n (new) Socket: ~p"
- "~n Reason: ~p", [Sock, Reason2]),
- exit({failed_starting_handler, Reason2})
- end.
-
-
-
-%% =========================================================================
-
-handler_start(ID, Sock, UseMsg, Peek) ->
- Self = self(),
- H = {Pid, _} = spawn_monitor(fun() ->
- handler_init(Self, ID, UseMsg, Peek, Sock)
- end),
- receive
- {handler, Pid, ok} ->
- {ok, H};
- {handler, Pid, {error, _} = ERROR} ->
- exit(Pid, kill), % Just in case
- ERROR
- end.
-
-handler_stop(Pid, _Reason) ->
- %% handler_request(Pid, {stop, Reason}).
- exit(Pid, kill).
-
-handler_continue(Pid) ->
- handler_request(Pid, continue).
-
-handler_request(Pid, Request) ->
- ?LIB:request(handler, Pid, Request).
-
-handler_reply(Pid, Ref, Reply) ->
- ?LIB:reply(handler, Pid, Ref, Reply).
-
-
-handler_init(Manager, ID, Msg, Peek, Sock) ->
- put(sname, f("handler:~w", [ID])),
- i("starting"),
- Manager ! {handler, self(), ok},
- receive
- {handler, Pid, Ref, continue} ->
- i("got continue"),
- handler_reply(Pid, Ref, ok),
- G = fun(L, O) -> case socket:getopt(Sock, L, O) of
- {ok, Val} ->
- f("~p", [Val]);
- {error, R} when is_atom(R) ->
- f("error: ~w", [R]);
- {error, {T, R}} when is_atom(T) ->
- f("error: ~w, ~p", [T, R]);
- {error, R} ->
- f("error: ~p", [R])
- end
- end,
- GSO = fun(O) -> G(socket, O) end,
- GIP4 = fun(O) -> G(ip, O) end,
- GIP6 = fun(O) -> G(ipv6, O) end,
- {ok, Domain} = socket:getopt(Sock, socket, domain),
- {ok, Type} = socket:getopt(Sock, socket, type),
- {ok, Proto} = socket:getopt(Sock, socket, protocol),
- B2D = GSO(bindtodevice),
- RA = GSO(reuseaddr),
- RP = GSO(reuseport),
- OOBI = GSO(oobinline),
- RcvBuf = GSO(rcvbuf),
- RcvLW = GSO(rcvlowat),
- RcvTO = GSO(rcvtimeo),
- SndBuf = GSO(sndbuf),
- SndLW = GSO(sndlowat),
- SndTO = GSO(sndtimeo),
- Linger = GSO(linger),
- Timestamp = GSO(timestamp),
- FreeBind = GIP4(freebind),
- MTU = GIP4(mtu),
- MTUDisc = GIP4(mtu_discover),
- MALL = GIP4(multicast_all),
- MIF4 = GIP4(multicast_if),
- MLoop4 = GIP4(multicast_loop),
- MTTL = GIP4(multicast_ttl),
- NF = GIP4(nodefrag), % raw only
- PktInfo = GIP4(pktinfo), % dgram only
- RecvErr4 = GIP4(recverr),
- RecvIF = GIP4(recvif), % Only dgram and raw (and FreeBSD)
- RecvOPTS = GIP4(recvopts), % Not stream
- RecvOrigDstAddr = GIP4(recvorigdstaddr),
- RecvTOS = GIP4(recvtos),
- RecvTTL = GIP4(recvttl), % not stream
- RetOpts = GIP4(retopts), % not stream
- SendSrcAddr = GIP4(sendsrcaddr),
- TOS = GIP4(tos),
- Transparent = GIP4(transparent),
- TTL = GIP4(ttl),
- MHops = GIP6(multicast_hops),
- MIF6 = GIP6(multicast_if), % Only dgram and raw
- MLoop6 = GIP6(multicast_loop),
- RecvErr6 = GIP6(recverr),
- RecvPktInfo = GIP6(recvpktinfo),
- RtHdr = GIP6(rthdr),
- AuthHdr = GIP6(authhdr),
- HopLimit = GIP6(hoplimit),
- HopOpts = GIP6(hopopts),
- DstOpts = GIP6(dstopts),
- FlowInfo = GIP6(flowinfo),
- UHops = GIP6(unicast_hops),
- i("got continue when: "
- "~n (socket) Domain: ~p"
- "~n (socket) Type: ~p"
- "~n (socket) Protocol: ~p"
- "~n (socket) Reuse Address: ~s"
- "~n (socket) Reuse Port: ~s"
- "~n (socket) Bind To Device: ~s"
- "~n (socket) OOBInline: ~s"
- "~n (socket) RcvBuf: ~s"
- "~n (socket) RcvLW: ~s"
- "~n (socket) RcvTO: ~s"
- "~n (socket) SndBuf: ~s"
- "~n (socket) SndLW: ~s"
- "~n (socket) SndTO: ~s"
- "~n (socket) Linger: ~s"
- "~n (socket) Timestamp: ~s"
- "~n (ip) FreeBind: ~s"
- "~n (ip) MTU: ~s"
- "~n (ip) MTU Discovery: ~s"
- "~n (ip) Multicast ALL: ~s"
- "~n (ip) Multicast IF: ~s"
- "~n (ip) Multicast Loop: ~s"
- "~n (ip) Multicast TTL: ~s"
- "~n (ip) Node Frag: ~s"
- "~n (ip) Pkt Info: ~s"
- "~n (ip) Recv Err: ~s"
- "~n (ip) Recv IF: ~s"
- "~n (ip) Recv OPTS: ~s"
- "~n (ip) Recv Orig Dst Addr: ~s"
- "~n (ip) Recv TOS: ~s"
- "~n (ip) Recv TTL: ~s"
- "~n (ip) Ret Opts: ~s"
- "~n (ip) Send Src Addr: ~s"
- "~n (ip) TOS: ~s"
- "~n (ip) Transparent: ~s"
- "~n (ip) TTL: ~s"
- "~n (ipv6) Multicast Hops: ~s"
- "~n (ipv6) Multicast IF: ~s"
- "~n (ipv6) Multicast Loop: ~s"
- "~n (ipv6) Recv Err: ~s"
- "~n (ipv6) Recv Pkt Info: ~s"
- "~n (ipv6) RT Hdr: ~s"
- "~n (ipv6) Auth Hdr: ~s"
- "~n (ipv6) Hop Limit: ~s"
- "~n (ipv6) Hop Opts: ~s"
- "~n (ipv6) Dst Opts: ~s"
- "~n (ipv6) Flow Info: ~s"
- "~n (ipv6) Unicast Hops: ~s",
- [Domain, Type, Proto,
- RA, RP, B2D, OOBI,
- RcvBuf, RcvLW, RcvTO, SndBuf, SndLW, SndTO,
- Linger, Timestamp,
- FreeBind, MTU, MTUDisc, MALL, MIF4, MLoop4, MTTL,
- NF, PktInfo,RecvErr4,
- RecvIF, RecvOPTS, RecvOrigDstAddr, RecvTOS, RecvTTL, RetOpts,
- SendSrcAddr, TOS, Transparent, TTL,
- MHops, MIF6, MLoop6, RecvErr6, RecvPktInfo,
- RtHdr, AuthHdr, HopLimit, HopOpts, DstOpts, FlowInfo,
- UHops]),
-
- %% ok = socket:setopt(Sock, otp, debug, true),
- %% case socket:getopt(Sock, 0, {13, int}) of
- %% {ok, Val} ->
- %% i("PktOpts ok: ~p", [Val]);
- %% {error, Reason} ->
- %% e("PktOpts err: ~p", [Reason])
- %% end,
- %% ok = socket:setopt(Sock, otp, debug, false),
- SSO = fun(O, V) -> soso(Sock, O, V) end,
- SIP4 =
- fun(O, V) ->
- if
- (Type =:= dgram) ->
- ok = soip(Sock, O, V);
- true ->
- ok
- end
- end,
- SSO(timestamp, true),
- SIP4(pktinfo, true),
- ok = soip(Sock, recvtos, true),
- SIP4(recvttl, true),
- ok = soip(Sock, recvorigdstaddr, true),
-
- handler_loop(#handler{msg = Msg,
- peek = Peek,
- manager = Manager,
- type = Type,
- socket = Sock})
- end.
-
-so(Sock, Lvl, Opt, Val) ->
- ok = socket:setopt(Sock, Lvl, Opt, Val).
-
-soso(Sock, Opt, Val) ->
- so(Sock, socket, Opt, Val).
-
-soip(Sock, Opt, Val) ->
- so(Sock, ip, Opt, Val).
-
-%% soipv6(Sock, Opt, Val) ->
-%% so(Sock, ipv6, Opt, Val).
-
-handler_loop(H) ->
- i("try read message"),
- case recv(H) of
- {ok, {Source, Msg}} ->
- i("received ~w bytes of data~s",
- [size(Msg), case Source of
- undefined -> "";
- _ -> f(" from:~n ~p", [Source])
- end]),
- case ?LIB:dec_msg(Msg) of
- {request, N, Req} ->
- i("received request ~w: "
- "~n ~p", [N, Req]),
- Reply = ?LIB:enc_rep_msg(N, "hoppsan"),
- case send(H, Reply, Source) of
- ok ->
- i("successfully sent reply ~w", [N]),
- handler_loop(H);
- {error, SReason} ->
- e("failed sending reply ~w:"
- "~n ~p", [N, SReason]),
- exit({failed_sending_reply, SReason})
- end
- end;
-
- {error, closed} ->
- i("closed when"
- "~n ~p", [socket:info()]),
- exit(normal);
-
- {error, RReason} ->
- e("failed reading request: "
- "~n ~p", [RReason]),
- exit({failed_reading_request, RReason})
- end.
-
-
-recv(#handler{peek = true, socket = Sock, type = stream}) ->
- peek_recv(Sock);
-recv(#handler{socket = Sock, msg = true, type = stream}) ->
- case socket:recvmsg(Sock) of
- {ok, #{addr := undefined = Source,
- iov := [Data],
- ctrl := CMsgHdrs,
- flags := Flags}} ->
- i("received message: "
- "~n CMsgHdrs: ~p"
- "~n Flags: ~p", [CMsgHdrs, Flags]),
- {ok, {Source, Data}};
- {ok, X} ->
- e("received *unexpected* message: "
- "~n ~p", [X]),
- {error, {unexpected, X}};
- {error, _} = ERROR ->
- ERROR
- end;
-recv(#handler{socket = Sock, msg = true, type = dgram}) ->
- case socket:recvmsg(Sock) of
- {ok, #{addr := Source,
- iov := [Data],
- ctrl := CMsgHdrs,
- flags := Flags}} ->
- i("received message: "
- "~n CMsgHdrs: ~p"
- "~n Flags: ~p", [CMsgHdrs, Flags]),
- {ok, {Source, Data}};
- {ok, X} ->
- {error, {unexpected, X}};
- {error, _} = ERROR ->
- ERROR
- end;
-recv(#handler{peek = false, socket = Sock, type = stream}) ->
- do_recv(Sock);
-recv(#handler{peek = Peek, socket = Sock, type = dgram})
- when (Peek =:= true) ->
- %% ok = socket:setopt(Sock, otp, debug, true),
- RES = peek_recvfrom(Sock, 5),
- %% ok = socket:setopt(Sock, otp, debug, false),
- RES;
-recv(#handler{peek = Peek, socket = Sock, type = dgram})
- when (Peek =:= false) ->
- %% ok = socket:setopt(Sock, otp, debug, true),
- socket:recvfrom(Sock).
-
-do_recv(Sock) ->
- case socket:recv(Sock) of
- {ok, Msg} ->
- {ok, {undefined, Msg}};
- {error, _} = ERROR ->
- ERROR
- end.
-
-peek_recv(Sock) ->
- i("try peek on the message type (expect request)"),
- Type = ?LIB:req(),
- case socket:recv(Sock, 4, [peek]) of
- {ok, <<Type:32>>} ->
- i("was request - do proper recv"),
- do_recv(Sock);
- {error, _} = ERROR ->
- ERROR
- end.
-
-peek_recvfrom(Sock, BufSz) ->
- i("try peek recvfrom with buffer size ~w", [BufSz]),
- case socket:recvfrom(Sock, BufSz, [peek]) of
- {ok, {_Source, Msg}} when (BufSz =:= size(Msg)) ->
- %% i("we filled the buffer: "
- %% "~n ~p", [Msg]),
- %% It *may not* fit => try again with double size
- peek_recvfrom(Sock, BufSz*2);
- {ok, _} ->
- %% It fits => read for real
- i("we did *not* fill the buffer - do the 'real' read"),
- socket:recvfrom(Sock);
- {error, _} = ERROR ->
- ERROR
- end.
-
-
-send(#handler{socket = Sock, msg = true, type = stream, stimeout = Timeout},
- Msg, _) ->
- CMsgHdr = #{level => ip, type => tos, data => reliability},
- CMsgHdrs = [CMsgHdr],
- MsgHdr = #{iov => [Msg], ctrl => CMsgHdrs},
- %% socket:setopt(Sock, otp, debug, true),
- Res = socket:sendmsg(Sock, MsgHdr, Timeout),
- %% socket:setopt(Sock, otp, debug, false),
- Res;
-send(#handler{socket = Sock, type = stream, stimeout = Timeout}, Msg, _) ->
- socket:send(Sock, Msg, Timeout);
-send(#handler{socket = Sock, msg = true, type = dgram, stimeout = Timeout},
- Msg, Dest) ->
- CMsgHdr = #{level => ip, type => tos, data => reliability},
- CMsgHdrs = [CMsgHdr],
- MsgHdr = #{addr => Dest,
- ctrl => CMsgHdrs,
- iov => [Msg]},
- %% ok = socket:setopt(Sock, otp, debug, true),
- Res = socket:sendmsg(Sock, MsgHdr, Timeout),
- %% ok = socket:setopt(Sock, otp, debug, false),
- Res;
-send(#handler{socket = Sock, type = dgram, stimeout = Timeout}, Msg, Dest) ->
- socket:sendto(Sock, Msg, Dest, Timeout).
-
-%% filler() ->
-%% list_to_binary(lists:duplicate(2048, " FILLER ")).
-
-
-
-%% =========================================================================
-
-f(F, A) ->
- ?LIB:f(F, A).
-
-e(F) ->
- e(F, []).
-e(F, A) ->
- ?LIB:e(F, A).
-
-i(F) ->
- ?LIB:i(F).
-
-i(F, A) ->
- ?LIB:i(F, A).
-
diff --git a/erts/emulator/test/esock_ttest/.gitignore b/erts/emulator/test/esock_ttest/.gitignore
deleted file mode 100644
index e69de29bb2..0000000000
--- a/erts/emulator/test/esock_ttest/.gitignore
+++ /dev/null
diff --git a/erts/emulator/test/esock_ttest/esock-ttest b/erts/emulator/test/esock_ttest/esock-ttest
deleted file mode 100755
index 2ded557484..0000000000
--- a/erts/emulator/test/esock_ttest/esock-ttest
+++ /dev/null
@@ -1,382 +0,0 @@
-#!/usr/bin/env escript
-
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 2018-2019. All Rights Reserved.
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%% %CopyrightEnd%
-%%
-
-%% ==========================================================================
-%%
-%% This is a simple wrapper escript on top of the socket ttest program(s).
-%% The idea is to make it simple to run in a normal shell (bash).
-%%
-%% ==========================================================================
-
--define(SECS(I), timer:seconds(I)).
-
--define(CLIENT_MSG_1_MAX_OUTSTANDING, 100).
--define(CLIENT_MSG_2_MAX_OUTSTANDING, 10).
--define(CLIENT_MSG_3_MAX_OUTSTANDING, 1).
-
-main(Args) ->
- State = process_args(Args),
- exec(State),
- ok.
-
-usage(ErrorString) when is_list(ErrorString) ->
- eprint(ErrorString),
- usage(),
- erlang:halt(0).
-
-usage() ->
- io:format("usage: ~s [options]"
- "~n"
- "~n This erlang script is used to start the (e)socket ttest "
- "~n units (server or client)."
- "~n"
- "~n options: "
- "~n --help Display this info and exit. "
- "~n --server [server-options] Start a server. "
- "~n There are no mandatory server options."
- "~n --client client-options Start a client"
- "~n Some client options are mandatory and"
- "~n others optional."
- "~n --domain <domain> local | inet | inet6"
- "~n Which domain to use."
- "~n Only valid for server."
- "~n Defaults to: inet"
- "~n --async Asynchronous mode (Timeout = nowait)"
- "~n This option is only valid for transport = sock."
- "~n Also, its only used when active =/= false."
- "~n --active <active> boolean() | once."
- "~n Valid for both client and server."
- "~n Defaults to: false"
- "~n --transport <transport> Which transport to use: gen|sock[:plain|msg]"
- "~n gen: gen_tcp"
- "~n sock: socket"
- "~n plain: recv/send (default)"
- "~n msg: recvmsg/sendmsg"
- "~n Defaults to: sock:plain"
- "~n --scon <addr>:<port>|<path> Server info."
- "~n The address part is in the standard form:"
- "~n \"a.b.c.d\"."
- "~n <path> is used for Unix Domain sockets (local)."
- "~n Only valid, and mandatory, for client."
- "~n --msg-id <1|2|3> Choose which message to use during the test."
- "~n Basically: "
- "~n 1: small"
- "~n 2: medium"
- "~n 3: large"
- "~n Defaults to: 1"
- "~n --max-outstanding <Num> How many messages to send before waiting for"
- "~n a reply."
- "~n Valid only for client."
- "~n Defaults to: "
- "~n MsgID 1: 100"
- "~n MsgID 2: 10"
- "~n MsgID 3: 1"
- "~n --runtime <Time> Time of the test in seconds."
- "~n Only valid for client."
- "~n Mandatory."
- "~n Defaults to: 60 (seconds)"
- "~n"
- "~n"
- "~n",
- [scriptname()]),
- ok.
-
-process_args(["--help"|_]) ->
- usage();
-process_args(["--server"|ServerArgs]) ->
- process_server_args(ServerArgs);
-process_args(["--client"|ClientArgs]) ->
- process_client_args(ClientArgs);
-process_args(Args) ->
- usage(f("Invalid Args: "
- "~n ~p", [Args])).
-
-
-process_server_args(Args) ->
- Defaults = #{role => server,
- domain => inet,
- async => false,
- active => false,
- transport => {sock, plain}},
- process_server_args(Args, Defaults).
-
-process_server_args([], State) ->
- State;
-
-process_server_args(["--domain", Domain|Args], State)
- when ((Domain =:= "local") orelse
- (Domain =:= "inet") orelse
- (Domain =:= "inet6")) ->
- process_server_args(Args, State#{domain => list_to_atom(Domain)});
-
-process_server_args(["--async"|Args], State) ->
- process_server_args(Args, State#{async => true});
-
-process_server_args(["--active", Active|Args], State)
- when ((Active =:= "false") orelse
- (Active =:= "once") orelse
- (Active =:= "true")) ->
- process_server_args(Args, State#{active => list_to_atom(Active)});
-
-process_server_args(["--transport", "gen" | Args], State) ->
- process_server_args(Args, State#{transport => gen});
-process_server_args(["--transport", "sock" | Args], State) ->
- process_server_args(Args, State#{transport => {sock, plain}});
-process_server_args(["--transport", "sock:plain" | Args], State) ->
- process_server_args(Args, State#{transport => {sock, plain}});
-process_server_args(["--transport", "sock:msg" | Args], State) ->
- process_server_args(Args, State#{transport => {sock, msg}});
-
-process_server_args([Arg|_], _State) ->
- usage(f("Invalid Server arg: ~s", [Arg])).
-
-
-process_client_args(Args) ->
- Defaults = #{role => client,
- async => false,
- active => false,
- transport => {sock, plain},
- %% Will cause error if not provided
- %% Should be "addr:port or string()
- server => undefined,
- msg_id => 1,
- %% Will be filled in based on msg_id if not provided
- max_outstanding => undefined,
- runtime => ?SECS(60)},
- process_client_args(Args, Defaults).
-
-process_client_args([], State) ->
- process_client_args_ensure_max_outstanding(State);
-
-process_client_args(["--async"|Args], State) ->
- process_client_args(Args, State#{async => true});
-
-process_client_args(["--active", Active|Args], State)
- when (Active =:= "false") orelse
- (Active =:= "once") orelse
- (Active =:= "true") ->
- process_client_args(Args, State#{active => list_to_atom(Active)});
-
-process_client_args(["--transport", "gen" | Args], State) ->
- process_client_args(Args, State#{transport => gen});
-process_client_args(["--transport", "sock" | Args], State) ->
- process_client_args(Args, State#{transport => {sock, plain}});
-process_client_args(["--transport", "sock:plain" | Args], State) ->
- process_client_args(Args, State#{transport => {sock, plain}});
-process_client_args(["--transport", "sock:msg" | Args], State) ->
- process_client_args(Args, State#{transport => {sock, msg}});
-
-process_client_args(["--msg-id", MsgID|Args], State)
- when ((MsgID =:= "1") orelse
- (MsgID =:= "2") orelse
- (MsgID =:= "3")) ->
- process_client_args(Args, State#{msg_id => list_to_integer(MsgID)});
-
-process_client_args(["--max-outstanding", Max|Args], State) ->
- try list_to_integer(Max) of
- I when (I > 0) ->
- process_client_args(Args, State#{max_outstanding => I});
- _ ->
- usage(f("Invalid Max Outstanding: ~s", [Max]))
- catch
- _:_:_ ->
- usage(f("Invalid Max Outstanding: ~s", [Max]))
- end;
-
-process_client_args(["--scon", Server|Args], State) ->
- case string:split(Server, ":", trailing) of
- [AddrStr,PortStr] ->
- Addr = case inet:parse_address(AddrStr) of
- {ok, A} ->
- A;
- {error, _} ->
- usage(f("Invalid Server Address: ~s", [AddrStr]))
- end,
- Port = try list_to_integer(PortStr) of
- I when (I > 0) ->
- I;
- _ ->
- usage(f("Invalid Server Port: ~s", [PortStr]))
- catch
- _:_:_ ->
- usage(f("Invalid Server Port: ~s", [PortStr]))
- end,
- process_client_args(Args, State#{server => {Addr, Port}});
- [Path] ->
- process_client_args(Args, State#{server => Path});
- _ ->
- usage(f("Invalid Server: ~s", [Server]))
- end;
-
-process_client_args(["--runtime", T|Args], State) ->
- try list_to_integer(T) of
- I when (I > 0) ->
- process_client_args(Args, State#{runtime => ?SECS(I)});
- _ ->
- usage(f("Invalid Run Time: ~s", [T]))
- catch
- _:_:_ ->
- usage(f("Invalid Run Time: ~s", [T]))
- end;
-
-process_client_args([Arg|_], _State) ->
- usage(f("Invalid Client arg: ~s", [Arg])).
-
-
-process_client_args_ensure_max_outstanding(
- #{msg_id := 1,
- max_outstanding := undefined} = State) ->
- State#{max_outstanding => ?CLIENT_MSG_1_MAX_OUTSTANDING};
-process_client_args_ensure_max_outstanding(
- #{msg_id := 2,
- max_outstanding := undefined} = State) ->
- State#{max_outstanding => ?CLIENT_MSG_2_MAX_OUTSTANDING};
-process_client_args_ensure_max_outstanding(
- #{msg_id := 3,
- max_outstanding := undefined} = State) ->
- State#{max_outstanding => ?CLIENT_MSG_3_MAX_OUTSTANDING};
-process_client_args_ensure_max_outstanding(
- #{msg_id := MsgID,
- max_outstanding := MaxOutstanding} = State)
- when ((MsgID =:= 1) orelse
- (MsgID =:= 2) orelse
- (MsgID =:= 3)) andalso
- (is_integer(MaxOutstanding) andalso (MaxOutstanding > 0)) ->
- State;
-process_client_args_ensure_max_outstanding(
- #{msg_id := MsgID,
- max_outstanding := MaxOutstanding}) ->
- usage(f("Invalid Msg ID (~w) and Max Outstanding (~w)",
- [MsgID, MaxOutstanding])).
-
-
-
-%% ==========================================================================
-
-exec(#{role := server,
- domain := Domain,
- active := Active,
- transport := gen})
- when (Domain =:= inet) orelse (Domain =:= inet6) ->
- case socket_test_ttest_tcp_server_gen:start(Domain, Active) of
- {ok, {Pid, _}} ->
- MRef = erlang:monitor(process, Pid),
- receive
- {'DOWN', MRef, process, Pid, Info} ->
- Info
- end;
- {error, Reason} ->
- eprint(f("Failed starting server: "
- "~n ~p", [Reason])),
- error
- end;
-exec(#{role := server,
- domain := Domain,
- async := Async,
- active := Active,
- transport := {sock, Method}}) ->
- case socket_test_ttest_tcp_server_socket:start(Method, Domain, Async, Active) of
- {ok, {Pid, _}} ->
- MRef = erlang:monitor(process, Pid),
- receive
- {'DOWN', MRef, process, Pid, Info} ->
- Info
- end;
- {error, Reason} ->
- eprint(f("Failed starting server: "
- "~n ~p", [Reason])),
- error
- end;
-
-exec(#{role := client,
- server := undefined}) ->
- usage("Mandatory option 'server' not provided");
-exec(#{role := client,
- server := {_Addr, _Port} = ServerInfo,
- active := Active,
- transport := gen,
- msg_id := MsgID,
- max_outstanding := MaxOutstanding,
- runtime := RunTime}) ->
- case socket_test_ttest_tcp_client_gen:start(true,
- ServerInfo,
- Active,
- MsgID, MaxOutstanding,
- RunTime) of
- {ok, Pid} ->
- MRef = erlang:monitor(process, Pid),
- receive
- {'DOWN', MRef, process, Pid, Info} ->
- Info
- end;
- {error, Reason} ->
- eprint(f("Failed starting server: "
- "~n ~p", [Reason])),
- error
- end;
-exec(#{role := client,
- server := ServerInfo,
- async := Async,
- active := Active,
- transport := {sock, Method},
- msg_id := MsgID,
- max_outstanding := MaxOutstanding,
- runtime := RunTime}) ->
- case socket_test_ttest_tcp_client_socket:start(true,
- Async,
- Active,
- Method,
- ServerInfo,
- MsgID, MaxOutstanding,
- RunTime) of
- {ok, Pid} ->
- MRef = erlang:monitor(process, Pid),
- receive
- {'DOWN', MRef, process, Pid, Info} ->
- Info
- end;
- {error, Reason} ->
- eprint(f("Failed starting server: "
- "~n ~p", [Reason])),
- error
- end;
-exec(_) ->
- usage("Unexpected option combo"),
- ok.
-
-
-
-%% ==========================================================================
-
-f(F, A) ->
- socket_test_ttest_lib:format(F, A).
-
-eprint(ErrorString) when is_list(ErrorString) ->
- print("<ERROR> " ++ ErrorString ++ "~n", []).
-
-print(F, A) ->
- io:format(F ++ "~n", A).
-
-scriptname() ->
- FullName = escript:script_name(),
- filename:basename(FullName).
-
diff --git a/erts/emulator/test/esock_ttest/esock-ttest-client b/erts/emulator/test/esock_ttest/esock-ttest-client
deleted file mode 100755
index 5ae05d03b8..0000000000
--- a/erts/emulator/test/esock_ttest/esock-ttest-client
+++ /dev/null
@@ -1,92 +0,0 @@
-#!/bin/sh
-
-#
-# %CopyrightBegin%
-#
-# Copyright Ericsson AB 2019-2019. All Rights Reserved.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-# %CopyrightEnd%
-#
-
-#
-# This is just a simple convenience wrapper to the esock-ttest.
-# That means that there are some options not available here.
-#
-
-EMU=$ERL_TOP/erts/emulator
-EMU_TEST=$EMU/test
-ESOCK_TTEST=$EMU_TEST/esock_ttest
-
-RUNTIME=30
-# RUNTIME=60
-# RUNTIME=600
-
-if [ $# = 3 ]; then
- MSGID=$1
- SERVER_INFO=$2:$3
-
- ITERATIONS="\
- gen false $MSGID
- gen true $MSGID
- gen once $MSGID
- sock false $MSGID --async
- sock true $MSGID --async
- sock once $MSGID --async"
-
-else
- if [ $# = 2 ]; then
- MSGID=$1
- SERVER_INFO=$2
-
- ITERATIONS="\
- sock false $MSGID --async
- sock true $MSGID --async
- sock once $MSGID --async"
-
- else
- echo "Invalid number of args"
- exit 1;
- fi
-fi
-
-
-# ---------------------------------------------------------------------------
-
-# For when we have figured out how to configure local for gen_tcp...
-
-#ITERATIONS="\
-# gen false $MSGID
-# gen true $MSGID
-# gen once $MSGID
-# sock false $MSGID
-# sock true $MSGID
-# sock once $MSGID"
-
-# ---------------------------------------------------------------------------
-
-echo "$ITERATIONS" |
- while read TRANSPORT ACTIVE MSG_ID ASYNC; do
-
- echo ""
- echo "=========== transport = $TRANSPORT, active = $ACTIVE, msg-id = $MSG_ID ==========="
- # The /dev/null at the end is necessary because erlang "does things" with stdin
- # and this case would cause the 'while read' to "fail" so that we only would
- # loop one time
- $ESOCK_TTEST/esock-ttest --client --transport $TRANSPORT $ASYNC --active $ACTIVE --msg-id $MSG_ID --scon $SERVER_INFO --runtime $RUNTIME </dev/null
- echo ""
-
- done
-
-
diff --git a/erts/emulator/test/esock_ttest/esock-ttest-server-gen b/erts/emulator/test/esock_ttest/esock-ttest-server-gen
deleted file mode 100755
index c29184772e..0000000000
--- a/erts/emulator/test/esock_ttest/esock-ttest-server-gen
+++ /dev/null
@@ -1,32 +0,0 @@
-#!/bin/sh
-
-#
-# %CopyrightBegin%
-#
-# Copyright Ericsson AB 2019-2019. All Rights Reserved.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-# %CopyrightEnd%
-#
-
-EMU=$ERL_TOP/erts/emulator
-EMU_TEST=$EMU/test
-ESOCK_TTEST=$EMU_TEST/esock_ttest
-
-if [ $# = 1 ]; then
- ACTIVE="--active $1"
-fi
-
-$ESOCK_TTEST/esock-ttest --server --transport gen $ACTIVE
-
diff --git a/erts/emulator/test/esock_ttest/esock-ttest-server-sock b/erts/emulator/test/esock_ttest/esock-ttest-server-sock
deleted file mode 100755
index c443d42e64..0000000000
--- a/erts/emulator/test/esock_ttest/esock-ttest-server-sock
+++ /dev/null
@@ -1,56 +0,0 @@
-#!/bin/sh
-
-#
-# %CopyrightBegin%
-#
-# Copyright Ericsson AB 2019-2019. All Rights Reserved.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-# %CopyrightEnd%
-#
-
-EMU=$ERL_TOP/erts/emulator
-EMU_TEST=$EMU/test
-ESOCK_TTEST=$EMU_TEST/esock_ttest
-
-# $1 - async - boolean()
-# $2 - active - once | boolean()
-# [$3 - domain - inet (default) | inet6 | local]
-if [ $# -ge 2 ]; then
-
- async=$1
- active=$2
-
- if [ $async = true ]; then
- ASYNC="--async"
- else
- ASYNC=
- fi
-
- ACTIVE="--active $active"
-
- if [ $# = 3 ]; then
- DOMAIN="--domain $3"
- fi
-
-
-else
- echo "<ERROR> Missing args: async and active"
- echo ""
- exit 1
-fi
-
-
-$ESOCK_TTEST/esock-ttest --server $DOMAIN $ASYNC --transport sock $ACTIVE
-
diff --git a/erts/emulator/test/estone_SUITE_data/estone_cat.c b/erts/emulator/test/estone_SUITE_data/estone_cat.c
index a34bda4384..cbdf3db6c9 100644
--- a/erts/emulator/test/estone_SUITE_data/estone_cat.c
+++ b/erts/emulator/test/estone_SUITE_data/estone_cat.c
@@ -12,9 +12,11 @@
#include <fcntl.h>
#include <errno.h>
-main(argc, argv)
-int argc;
-char *argv[];
+#ifdef HAVE_UNISTD_H
+# include <unistd.h>
+#endif
+
+int main(int argc, char* argv[])
{
char buf[16384];
int n;
diff --git a/erts/emulator/test/mtx_SUITE_data/mtx_SUITE.c b/erts/emulator/test/mtx_SUITE_data/mtx_SUITE.c
index 46ee8b5540..6f662ae514 100644
--- a/erts/emulator/test/mtx_SUITE_data/mtx_SUITE.c
+++ b/erts/emulator/test/mtx_SUITE_data/mtx_SUITE.c
@@ -39,6 +39,7 @@
#include <errno.h>
#include <stdio.h>
+#include <string.h>
static int
fail(const char *file, int line, const char *function, const char *assertion);
diff --git a/erts/emulator/test/nif_SUITE.erl b/erts/emulator/test/nif_SUITE.erl
index 273d9b1543..2cc3b8db32 100644
--- a/erts/emulator/test/nif_SUITE.erl
+++ b/erts/emulator/test/nif_SUITE.erl
@@ -1434,6 +1434,21 @@ maps(Config) when is_list(Config) ->
end,
{1,#{}}),
+ M5 = lists:foldl(fun(N, MapIn) ->
+ {1, #{N := value}=MapOut} = make_map_put_nif(MapIn, N, value),
+ MapOut
+ end,
+ #{},
+ lists:seq(1,40)),
+ M6 = lists:foldl(fun(N, MapIn) ->
+ {1, MapOut} = make_map_remove_nif(MapIn, N),
+ ok = maps:get(N, MapOut, ok),
+ MapOut
+ end,
+ M5,
+ lists:seq(1,40)),
+ true = (M6 =:= #{}),
+
has_duplicate_keys = maps_from_list_nif([{1,1},{1,1}]),
verify_tmpmem(TmpMem),
diff --git a/erts/emulator/test/nif_SUITE_data/nif_SUITE.c b/erts/emulator/test/nif_SUITE_data/nif_SUITE.c
index a6ed6ae15f..93708fa99c 100644
--- a/erts/emulator/test/nif_SUITE_data/nif_SUITE.c
+++ b/erts/emulator/test/nif_SUITE_data/nif_SUITE.c
@@ -2123,6 +2123,19 @@ static ERL_NIF_TERM make_map_put_nif(ErlNifEnv* env, int argc, const ERL_NIF_TER
{
ERL_NIF_TERM map_out = enif_make_atom(env, "undefined");
int ret = enif_make_map_put(env, argv[0], argv[1], argv[2], &map_out);
+
+ /* build same map in dynamic env */
+ ErlNifEnv* dynenv = enif_alloc_env();
+ ERL_NIF_TERM map_out2 = enif_make_atom(env, "undefined");
+ int ret2 = enif_make_map_put(dynenv,
+ enif_make_copy(dynenv, argv[0]),
+ enif_make_copy(dynenv, argv[1]),
+ enif_make_copy(dynenv, argv[2]),
+ &map_out2);
+ if (ret != ret2 || !enif_is_identical(map_out, map_out2))
+ map_out = enif_make_string(env, "dynenv failure", ERL_NIF_LATIN1);
+ enif_free_env(dynenv);
+
return enif_make_tuple2(env, enif_make_int(env,ret), map_out);
}
static ERL_NIF_TERM get_map_value_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
@@ -2136,12 +2149,37 @@ static ERL_NIF_TERM make_map_update_nif(ErlNifEnv* env, int argc, const ERL_NIF_
{
ERL_NIF_TERM map_out = enif_make_atom(env, "undefined");
int ret = enif_make_map_update(env, argv[0], argv[1], argv[2], &map_out);
+
+ /* build same map in dynamic env */
+ ErlNifEnv* dynenv = enif_alloc_env();
+ ERL_NIF_TERM map_out2 = enif_make_atom(env, "undefined");
+ int ret2 = enif_make_map_update(dynenv,
+ enif_make_copy(dynenv, argv[0]),
+ enif_make_copy(dynenv, argv[1]),
+ enif_make_copy(dynenv, argv[2]),
+ &map_out2);
+ if (ret != ret2 || !enif_is_identical(map_out, map_out2))
+ map_out = enif_make_string(env, "dynenv failure", ERL_NIF_LATIN1);
+ enif_free_env(dynenv);
+
return enif_make_tuple2(env, enif_make_int(env,ret), map_out);
}
static ERL_NIF_TERM make_map_remove_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
{
ERL_NIF_TERM map_out = enif_make_atom(env, "undefined");
int ret = enif_make_map_remove(env, argv[0], argv[1], &map_out);
+
+ /* build same map in dynamic env */
+ ErlNifEnv* dynenv = enif_alloc_env();
+ ERL_NIF_TERM map_out2 = enif_make_atom(env, "undefined");
+ int ret2 = enif_make_map_remove(dynenv,
+ enif_make_copy(dynenv, argv[0]),
+ enif_make_copy(dynenv, argv[1]),
+ &map_out2);
+ if (ret != ret2 || !enif_is_identical(map_out, map_out2))
+ map_out = enif_make_string(env, "dynenv failure", ERL_NIF_LATIN1);
+ enif_free_env(dynenv);
+
return enif_make_tuple2(env, enif_make_int(env,ret), map_out);
}
@@ -3345,15 +3383,15 @@ static ERL_NIF_TERM ioq(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
ret = enif_make_resource(env, ioq);
enif_release_resource(ioq);
return ret;
- } else if (enif_is_identical(argv[0], enif_make_atom(env, "inspect"))) {
+ } else if (argc >= 2 && enif_is_identical(argv[0], enif_make_atom(env, "inspect"))) {
ErlNifIOVec vec, *iovec = NULL;
int i, iovcnt;
ERL_NIF_TERM *elems, tail, list;
ErlNifEnv *myenv = NULL;
- if (enif_is_identical(argv[2], enif_make_atom(env, "use_stack")))
+ if (argv >= 3 && enif_is_identical(argv[2], enif_make_atom(env, "use_stack")))
iovec = &vec;
- if (enif_is_identical(argv[3], enif_make_atom(env, "use_env")))
+ if (argc >= 4 && enif_is_identical(argv[3], enif_make_atom(env, "use_env")))
myenv = env;
if (!enif_inspect_iovec(myenv, ~(size_t)0, argv[1], &tail, &iovec))
return enif_make_badarg(env);
@@ -3378,13 +3416,13 @@ static ERL_NIF_TERM ioq(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
list = enif_make_list_from_array(env, elems, iovcnt);
enif_free(elems);
return list;
- } else {
+ } else if (argc >= 2) {
unsigned skip;
if (!enif_get_resource(env, argv[1], ioq_resource_type, (void**)&ioq)
|| !ioq->q)
return enif_make_badarg(env);
- if (enif_is_identical(argv[0], enif_make_atom(env, "example"))) {
+ if (argc == 3 && enif_is_identical(argv[0], enif_make_atom(env, "example"))) {
#ifndef __WIN32__
int fd[2], res = 0, cnt = 0;
ERL_NIF_TERM tail;
@@ -3434,7 +3472,7 @@ static ERL_NIF_TERM ioq(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
enif_ioq_destroy(ioq->q);
ioq->q = NULL;
return enif_make_atom(env, "false");
- } else if (enif_is_identical(argv[0], enif_make_atom(env, "enqv"))) {
+ } else if (argc >= 4 && enif_is_identical(argv[0], enif_make_atom(env, "enqv"))) {
ErlNifIOVec vec, *iovec = &vec;
ERL_NIF_TERM tail;
@@ -3446,7 +3484,7 @@ static ERL_NIF_TERM ioq(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
return enif_make_badarg(env);
return enif_make_atom(env, "true");
- } else if (enif_is_identical(argv[0], enif_make_atom(env, "enqb"))) {
+ } else if (argc >= 4 && enif_is_identical(argv[0], enif_make_atom(env, "enqb"))) {
ErlNifBinary bin;
if (!enif_get_uint(env, argv[3], &skip) ||
!enif_inspect_binary(env, argv[2], &bin))
@@ -3456,7 +3494,7 @@ static ERL_NIF_TERM ioq(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
return enif_make_badarg(env);
return enif_make_atom(env, "true");
- } else if (enif_is_identical(argv[0], enif_make_atom(env, "enqbraw"))) {
+ } else if (argc >= 4 && enif_is_identical(argv[0], enif_make_atom(env, "enqbraw"))) {
ErlNifBinary bin;
ErlNifBinary localbin;
int i;
@@ -3480,7 +3518,7 @@ static ERL_NIF_TERM ioq(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
}
return enif_make_atom(env, "false");
- } else if (enif_is_identical(argv[0], enif_make_atom(env, "peek"))) {
+ } else if (argc >= 3 && enif_is_identical(argv[0], enif_make_atom(env, "peek"))) {
int iovlen, num, i, off = 0;
SysIOVec *iov = enif_ioq_peek(ioq->q, &iovlen);
ErlNifBinary bin;
@@ -3496,7 +3534,7 @@ static ERL_NIF_TERM ioq(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
}
return enif_make_binary(env, &bin);
- } else if (enif_is_identical(argv[0], enif_make_atom(env, "deq"))) {
+ } else if (argc >= 3 && enif_is_identical(argv[0], enif_make_atom(env, "deq"))) {
int num;
size_t sz;
ErlNifUInt64 sz64;
diff --git a/erts/emulator/test/num_bif_SUITE.erl b/erts/emulator/test/num_bif_SUITE.erl
index 6b834705cf..fded36431e 100644
--- a/erts/emulator/test/num_bif_SUITE.erl
+++ b/erts/emulator/test/num_bif_SUITE.erl
@@ -544,7 +544,7 @@ t_string_to_integer(Config) when is_list(Config) ->
test_sti(268435455),
test_sti(-268435455),
- % Interesting values around 2-pows, such as MIN_SMALL and MAX_SMALL.
+ %% Interesting values around 2-pows, such as MIN_SMALL and MAX_SMALL.
lists:foreach(fun(Bits) ->
N = 1 bsl Bits,
test_sti(N - 1),
@@ -553,11 +553,11 @@ t_string_to_integer(Config) when is_list(Config) ->
end,
lists:seq(16, 130)),
- %% Bignums.
+ %% Bignums
test_sti(123456932798748738738,16),
test_sti(list_to_integer(lists:duplicate(2000, $1))),
- %% unalign string
+ %% Unaligned string
Str = <<"10">>,
UnalignStr = <<0:3, (id(Str))/binary, 0:5>>,
<<_:3, SomeStr:2/binary, _:5>> = id(UnalignStr),
@@ -568,32 +568,39 @@ t_string_to_integer(Config) when is_list(Config) ->
{'EXIT', {badarg, _}} =
(catch binary_to_integer(Value)),
{'EXIT', {badarg, _}} =
- (catch erlang:list_to_integer(Value))
+ (catch list_to_integer(Value))
end,[atom,1.2,0.0,[$1,[$2]]]),
- % Default base error cases
+ %% Default base error cases
lists:foreach(fun(Value) ->
{'EXIT', {badarg, _}} =
- (catch erlang:binary_to_integer(
- list_to_binary(Value))),
+ (catch binary_to_integer(list_to_binary(Value))),
{'EXIT', {badarg, _}} =
- (catch erlang:list_to_integer(Value))
+ (catch list_to_integer(Value))
end,["1.0"," 1"," -1","","+"]),
- % Custom base error cases
+ %% Custom base error cases
lists:foreach(fun({Value,Base}) ->
{'EXIT', {badarg, _}} =
- (catch binary_to_integer(
- list_to_binary(Value),Base)),
+ (catch binary_to_integer(list_to_binary(Value), Base)),
{'EXIT', {badarg, _}} =
- (catch erlang:list_to_integer(Value,Base))
- end,[{" 1",1},{" 1",37},{"2",2},{"B",11},{"b",11},{":", 16},
- {"1111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111z",16},
- {"1z111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111",16},
- {"111z11111111",16}]),
-
- %% log2 calculation overflow bug in do_integer_to_list (OTP-12624)
- %% Would crash with segv
+ (catch list_to_integer(Value, Base))
+ end,
+ [{" 1",1},{" 1",37},{"2",2},{"B",11},{"b",11},{":", 16},
+ {"1111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111z",16},
+ {"1z111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111",16},
+ {"111z11111111",16},
+ %% Untagging atoms at the beginning of atom.names
+ %% would produce a base in the valid range.
+ {"10",true}, %Base 4
+ {"10",'_'}, %Base 8
+ {"10",nonode@nohost}, %Base 12
+ {"10",'$end_of_table'}, %Base 16
+ {"10",''} %Base 20
+ ]),
+
+ %% log2 calculation overflow bug in do_integer_to_list (OTP-12624).
+ %% Would crash with segementation fault.
0 = list_to_integer(lists:duplicate(10000000,$0)),
ok.
diff --git a/erts/emulator/test/port_bif_SUITE_data/port_test.c b/erts/emulator/test/port_bif_SUITE_data/port_test.c
index 923ab99ccc..ef6d12dc93 100644
--- a/erts/emulator/test/port_bif_SUITE_data/port_test.c
+++ b/erts/emulator/test/port_bif_SUITE_data/port_test.c
@@ -10,6 +10,7 @@
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
+#include <ctype.h>
#ifndef __WIN32__
#include <unistd.h>
@@ -32,7 +33,7 @@
exit(1); \
}
-#define MAIN(argc, argv) main(argc, argv)
+#define MAIN(argc, argv) int main(argc, argv)
extern int errno;
diff --git a/erts/emulator/test/trace_SUITE_data/slow_drv.c b/erts/emulator/test/trace_SUITE_data/slow_drv.c
index 4f7c93a69e..e7c1eb2125 100644
--- a/erts/emulator/test/trace_SUITE_data/slow_drv.c
+++ b/erts/emulator/test/trace_SUITE_data/slow_drv.c
@@ -3,6 +3,12 @@
#endif
#include <stdio.h>
+#include <string.h>
+
+#ifdef HAVE_UNISTD_H
+# include <unistd.h>
+#endif
+
#include "erl_driver.h"
typedef struct _erl_drv_data {
diff --git a/erts/emulator/utils/make_driver_tab b/erts/emulator/utils/make_driver_tab
index a000b9d415..78b6fba254 100755
--- a/erts/emulator/utils/make_driver_tab
+++ b/erts/emulator/utils/make_driver_tab
@@ -52,6 +52,7 @@ while (@ARGV) {
if ( $d =~ /^.*\.a$/ ) {
$d = basename $d;
$d =~ s/\.a$//; # strip .a
+ $d =~ s/\.gprof$//; # strip .gprof
if ($mode == 1) {
push(@static_drivers, $d);
}
diff --git a/erts/emulator/valgrind/suppress.standard b/erts/emulator/valgrind/suppress.standard
index 3d6b4b50d3..a029ea7d37 100644
--- a/erts/emulator/valgrind/suppress.standard
+++ b/erts/emulator/valgrind/suppress.standard
@@ -277,7 +277,36 @@ obj:*/ssleay.*
Memcheck:Addr8
fun:RC4
}
-
+{
+Crypto internal... loading gives expected errors when curves are tried. But including <openssl/err.h> and removing them triggers compiler errors on Windows
+Memcheck:Leak
+fun:malloc
+...
+fun:valid_curve
+fun:init_curves
+fun:init_curve_types
+fun:init_algorithms_types
+fun:initialize
+fun:load
+fun:erts_load_nif
+fun:process_main
+fun:sched_thread_func
+}
+{
+Crypto internal.. loading pecularities revisited
+Memcheck:Leak
+fun:malloc
+fun:CRYPTO_malloc
+fun:lh_new
+...
+fun:ecdh_check
+fun:ECDH_compute_key
+fun:ecdh_compute_key_nif
+fun:process_main
+fun:sched_thread_func
+fun:thr_wrapper
+fun:start_thread
+}
{
Prebuilt constant terms in os_info_init (PossiblyLost)
Memcheck:Leak
diff --git a/erts/etc/common/erlexec.c b/erts/etc/common/erlexec.c
index 59dcf700d7..9dba684cbb 100644
--- a/erts/etc/common/erlexec.c
+++ b/erts/etc/common/erlexec.c
@@ -1199,10 +1199,10 @@ usage_aux(void)
#endif
"[-make] [-man [manopts] MANPAGE] [-x] [-emu_args] [-start_epmd BOOLEAN] "
"[-args_file FILENAME] [+A THREADS] [+a SIZE] [+B[c|d|i]] [+c [BOOLEAN]] "
- "[+C MODE] [+h HEAP_SIZE_OPTION] [+K BOOLEAN] "
- "[+l] [+M<SUBSWITCH> <ARGUMENT>] [+P MAX_PROCS] [+Q MAX_PORTS] "
+ "[+C MODE] [+dcg DECENTRALIZED_COUNTER_GROUPS_LIMIT] [+h HEAP_SIZE_OPTION] "
+ "[+M<SUBSWITCH> <ARGUMENT>] [+P MAX_PROCS] [+Q MAX_PORTS] "
"[+R COMPAT_REL] "
- "[+r] [+rg READER_GROUPS_LIMIT] [+s SCHEDULER_OPTION] "
+ "[+r] [+rg READER_GROUPS_LIMIT] [+s<SUBSWITCH> SCHEDULER_OPTION] "
"[+S NO_SCHEDULERS:NO_SCHEDULERS_ONLINE] "
"[+SP PERCENTAGE_SCHEDULERS:PERCENTAGE_SCHEDULERS_ONLINE] "
"[+T LEVEL] [+V] [+v] "
diff --git a/erts/etc/unix/etp-commands.in b/erts/etc/unix/etp-commands.in
index 9ed887c3d4..f440b6a882 100644
--- a/erts/etc/unix/etp-commands.in
+++ b/erts/etc/unix/etp-commands.in
@@ -646,6 +646,67 @@ define etp-atom-1
end
+define etp-string-to-atom
+# Args: (char*) null-terminated
+#
+# Non-reentrant
+
+ set $etp_i = 0
+ set $etp_h = ((UWord)0)
+ while (($arg0)[$etp_i]) != 0
+ set $etp_c = (unsigned char)(($arg0)[$etp_i])
+
+ if $etp_c & 0x80
+ printf "Non ASCII atoms not implemented\n"
+ loop_break
+ end
+
+ set $etp_h = ($etp_h << 4) + $etp_c
+ set $etp_g = $etp_h & 0xf0000000
+ if $etp_g != 0
+ set $etp_h ^= ($etp_g >> 24)
+ set $etp_h ^= $etp_g
+ end
+ set $etp_i++
+ end
+
+ # hash_get_slot
+ set $etp_h ^= $etp_h >> erts_atom_table.htable.shift
+ if $etp_arch64
+ set $etp_h = (11400714819323198485UL * $etp_h) >> erts_atom_table.htable.shift
+ else
+ set $etp_h = (2654435769UL * $etp_h) >> erts_atom_table.htable.shift
+ end
+ set $etp_p = (Atom*)erts_atom_table.htable.bucket[$etp_h]
+
+ # search hash bucket list
+ while $etp_p
+ set $etp_i = 0
+ while $etp_i < $etp_p->len && ($arg0)[$etp_i]
+ if $etp_p->name[$etp_i] != ($arg0)[$etp_i]
+ loop_break
+ end
+ set $etp_i++
+ end
+ if $etp_i == $etp_p->len && ($arg0)[$etp_i] == 0
+ loop_break
+ end
+ set $etp_p = (Atom*)$etp_p->slot.bucket.next
+ end
+ if $etp_p
+ print ($etp_p->slot.index << 6) | (2 << 2) | 3
+ else
+ printf "Can't find atom\n"
+ end
+end
+
+document etp-string-to-atom
+%----------------------------------------
+% etp-string-to-atom (char*)
+%
+% Ex: etp-string-to-atom "erlang"
+%----------------------------------------
+end
define etp-char-1
# Args: int char, int quote_char
@@ -1093,6 +1154,92 @@ document etp-mfa
%---------------------------------------------------------------------------
end
+define etp-export-get
+ # Args: Eterm Eterm Uint
+
+ set $etp_h = (((Eterm)$arg0 >> 6) * ((Eterm)$arg1 >> 6)) ^ (Uint)$arg2
+
+ #hash_get_slot
+ set $etp_t = &export_tables[the_active_code_index.counter].htable
+ set $etp_h ^= $etp_h >> $etp_t->shift
+ if $etp_arch64
+ set $etp_h = (11400714819323198485UL * $etp_h) >> $etp_t->shift
+ else
+ set $etp_h = (2654435769UL * $etp_h) >> $etp_t->shift
+ end
+
+ set $etp_p = (struct export_entry*) $etp_t->bucket[$etp_h]
+ while $etp_p
+ if $etp_p->ep->info.mfa.module == $arg0 && $etp_p->ep->info.mfa.function == $arg1 && $etp_p->ep->info.mfa.arity == $arg2
+ loop_break
+ end
+ set $etp_p = (struct export_entry*) $etp_p->slot.bucket.next
+ end
+ if $etp_p
+ print $etp_p->ep
+ else
+ printf "Can't find export entry\n"
+ end
+end
+
+document etp-export-get
+%---------------------------------------------------------
+% etp-export-get module function arity
+%
+% Lookup and print pointer to Export entry.
+% Example:
+% (gdb) etp-string-to-atom "erlang"
+% $1 = 13323
+% (gdb) etp-string-to-atom "self"
+% $2 = 47115
+% (gdb) etp-export-get 13323 47115 0
+% $3 = (Export *) 0x7f53caf1f358
+%---------------------------------------------------------
+end
+
+define etp-module-get
+ # Args: Eterm
+
+ set $etp_ix = ((Eterm)$arg0 >> 6)
+ set $etp_h = $etp_ix
+
+ #hash_get_slot
+ set $etp_t = &module_tables[the_active_code_index.counter].htable
+ set $etp_h ^= $etp_h >> $etp_t->shift
+ if $etp_arch64
+ set $etp_h = (11400714819323198485UL * $etp_h) >> $etp_t->shift
+ else
+ set $etp_h = (2654435769UL * $etp_h) >> $etp_t->shift
+ end
+
+ set $etp_p = (Module*) $etp_t->bucket[$etp_h]
+ while $etp_p
+ if $etp_p->module == $etp_ix
+ loop_break
+ end
+ set $etp_p = (Module*) $etp_p->slot.bucket.next
+ end
+ if $etp_p
+ print $etp_p
+ else
+ printf "Can't find module entry\n"
+ end
+end
+
+document etp-module-get
+%---------------------------------------------------------
+% etp-module-get module
+%
+% Lookup and print pointer to Module entry.
+% Example:
+% (gdb) etp-string-to-atom "erlang"
+% $1 = 13323
+% (gdb) etp-module-get 13323
+% $2 = (Module *) 0x7f53caf1f358
+%---------------------------------------------------------
+end
+
+
define etp-cp-func-info-1
# Args: Eterm cp
#
diff --git a/erts/etc/win32/erl.c b/erts/etc/win32/erl.c
index 7cbd0d027c..e960fb1238 100644
--- a/erts/etc/win32/erl.c
+++ b/erts/etc/win32/erl.c
@@ -17,10 +17,7 @@
*
* %CopyrightEnd%
*/
-#pragma comment(linker,"/manifestdependency:\"type='win32' "\
- "name='Microsoft.Windows.Common-Controls' "\
- "version='6.0.0.0' processorArchitecture='*' "\
- "publicKeyToken='6595b64144ccf1df' language='*'\"")
+
#include <windows.h>
#include <stdio.h>
#include <stdlib.h>
diff --git a/erts/etc/win32/manifest.xml b/erts/etc/win32/manifest.xml
new file mode 100644
index 0000000000..eea364c9e9
--- /dev/null
+++ b/erts/etc/win32/manifest.xml
@@ -0,0 +1,17 @@
+<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
+ <dependency>
+ <dependentAssembly>
+ <assemblyIdentity
+ type="win32" name="Microsoft.Windows.Common-Controls" version="6.0.0.0"
+ processorArchitecture="*" publicKeyToken="6595b64144ccf1df" language="*">
+ </assemblyIdentity>
+ </dependentAssembly>
+ </dependency>
+ <ms_asmv2:trustInfo xmlns:ms_asmv2="urn:schemas-microsoft-com:asm.v2">
+ <ms_asmv2:security>
+ <ms_asmv2:requestedPrivileges>
+ <ms_asmv2:requestedExecutionLevel level="AsInvoker" uiAccess="false"></ms_asmv2:requestedExecutionLevel>
+ </ms_asmv2:requestedPrivileges>
+ </ms_asmv2:security>
+ </ms_asmv2:trustInfo>
+</assembly>
diff --git a/erts/etc/win32/nsis/erlang20.nsi b/erts/etc/win32/nsis/erlang20.nsi
index 5a79101b5d..907a64b89c 100644
--- a/erts/etc/win32/nsis/erlang20.nsi
+++ b/erts/etc/win32/nsis/erlang20.nsi
@@ -144,7 +144,21 @@ SubSection /e "Erlang" SecErlang
Section "Development" SecErlangDev
SectionIn 1 RO
+
SetOutPath "$INSTDIR"
+
+; Don't let Users nor Autenticated Users group create new files
+; Avoid dll injection when installing to non /Program Files/ dirs
+
+ StrCmp $INSTDIR $InstallDir cp_files
+ ; Remove ANY inherited access control
+ ExecShellWait "open" "$SYSDIR\icacls.exe" '"$INSTDIR" /inheritance:r' SW_HIDE
+ ; Grant Admin full control
+ ExecShellWait "open" "$SYSDIR\icacls.exe" '"$INSTDIR" /grant:r *S-1-5-32-544:(OI)(CI)F' SW_HIDE
+ ; Grant Normal Users read+execute control
+ ExecShellWait "open" "$SYSDIR\icacls.exe" '"$INSTDIR" /grant:r *S-1-1-0:(OI)(CI)RX' SW_HIDE
+
+cp_files:
File "${TESTROOT}\Install.ini"
File "${TESTROOT}\Install.exe"
SetOutPath "$INSTDIR\releases"
diff --git a/erts/etc/win32/win_erlexec.c b/erts/etc/win32/win_erlexec.c
index c0bb92793e..defa654ad8 100644
--- a/erts/etc/win32/win_erlexec.c
+++ b/erts/etc/win32/win_erlexec.c
@@ -22,11 +22,6 @@
* Most of this only used when beam is run as a separate process.
*/
-#pragma comment(linker,"/manifestdependency:\"type='win32' "\
- "name='Microsoft.Windows.Common-Controls' "\
- "version='6.0.0.0' processorArchitecture='*' "\
- "publicKeyToken='6595b64144ccf1df' language='*'\"")
-
#include <windows.h>
#include <winuser.h>
#include <wincon.h>
diff --git a/erts/etc/win32/wsl_tools/vc/ld.sh b/erts/etc/win32/wsl_tools/vc/ld.sh
index fc115bec8c..a16c502cea 100755
--- a/erts/etc/win32/wsl_tools/vc/ld.sh
+++ b/erts/etc/win32/wsl_tools/vc/ld.sh
@@ -177,11 +177,16 @@ RES=$?
CMANIFEST=`w32_path.sh -u $MANIFEST`
-if [ "$RES" = "0" -a -f "$CMANIFEST" ]; then
- # Add stuff to manifest to turn off "virtualization"
+if [ -f "$CMANIFEST" ]; then
+ ## Add stuff to manifest to turn off "virtualization"
sed -n -i '1h;1!H;${;g;s,<trustInfo.*</trustInfo>.,,g;p;}' $CMANIFEST 2>/dev/null
sed -i "s/<\/assembly>/ <ms_asmv2:trustInfo xmlns:ms_asmv2=\"urn:schemas-microsoft-com:asm.v2\">\n <ms_asmv2:security>\n <ms_asmv2:requestedPrivileges>\n <ms_asmv2:requestedExecutionLevel level=\"AsInvoker\" uiAccess=\"false\"\/>\n <\/ms_asmv2:requestedPrivileges>\n <\/ms_asmv2:security>\n <\/ms_asmv2:trustInfo>\n<\/assembly>/" $CMANIFEST 2>/dev/null
+else
+ CMANIFEST=$ERL_TOP/erts/etc/win32/manifest.xml
+ MANIFEST=`w32_path.sh -d $CMANIFEST`
+fi
+if [ "$RES" = "0" ]; then
eval mt.exe -nologo -manifest "$MANIFEST" -outputresource:"$OUTPUTRES" >>/tmp/link.exe.${p}.1 2>>/tmp/link.exe.${p}.2
RES=$?
if [ "$RES" != "0" ]; then
@@ -192,7 +197,6 @@ if [ "$RES" = "0" -a -f "$CMANIFEST" ]; then
echo "If you get this error, make sure Windows Defender AND Windows Search is disabled">>/tmp/link.exe.${p}.1
rm -f "$CREMOVE"
fi
- rm -f "$CMANIFEST"
fi
# This works around some strange behaviour
diff --git a/erts/lib_src/Makefile.in b/erts/lib_src/Makefile.in
index 70ff666ed3..bb43d51d97 100644
--- a/erts/lib_src/Makefile.in
+++ b/erts/lib_src/Makefile.in
@@ -44,6 +44,7 @@ ERLANG_OSTYPE=@ERLANG_OSTYPE@
OMIT_FP=false
CFLAGS=$(subst O2,O3, @CFLAGS@)
+LDFLAGS=@LDFLAGS@
ifeq ($(TYPE),debug)
CFLAGS=@DEBUG_CFLAGS@ -DDEBUG
diff --git a/erts/vsn.mk b/erts/vsn.mk
index 7582350755..cc7958578f 100644
--- a/erts/vsn.mk
+++ b/erts/vsn.mk
@@ -18,7 +18,7 @@
# %CopyrightEnd%
#
-VSN = 11.1.3
+VSN = 11.1.8
# Port number 4365 in 4.2
# Port number 4366 in 4.3