aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.gitignore1
-rw-r--r--bootstrap/bin/no_dot_erlang.bootbin6544 -> 6542 bytes
-rw-r--r--bootstrap/bin/start.bootbin6544 -> 6542 bytes
-rw-r--r--bootstrap/bin/start_clean.bootbin6544 -> 6542 bytes
-rw-r--r--bootstrap/lib/compiler/ebin/beam_asm.beambin10988 -> 10988 bytes
-rw-r--r--bootstrap/lib/compiler/ebin/beam_ssa_opt.beambin39916 -> 39972 bytes
-rw-r--r--bootstrap/lib/compiler/ebin/beam_validator.beambin46224 -> 50132 bytes
-rw-r--r--bootstrap/lib/compiler/ebin/compile.beambin41208 -> 41388 bytes
-rw-r--r--bootstrap/lib/compiler/ebin/compiler.app2
-rw-r--r--bootstrap/lib/compiler/ebin/compiler.appup2
-rw-r--r--bootstrap/lib/kernel/ebin/application.beambin3684 -> 3852 bytes
-rw-r--r--bootstrap/lib/kernel/ebin/application_controller.beambin29612 -> 30036 bytes
-rw-r--r--bootstrap/lib/kernel/ebin/code_server.beambin22552 -> 22552 bytes
-rw-r--r--bootstrap/lib/kernel/ebin/global.beambin29188 -> 28704 bytes
-rw-r--r--bootstrap/lib/kernel/ebin/hipe_unified_loader.beambin12348 -> 12348 bytes
-rw-r--r--bootstrap/lib/kernel/ebin/inet_db.beambin25300 -> 25360 bytes
-rw-r--r--bootstrap/lib/kernel/ebin/kernel.app4
-rw-r--r--bootstrap/lib/kernel/ebin/kernel.appup12
-rw-r--r--bootstrap/lib/kernel/ebin/kernel.beambin3532 -> 3628 bytes
-rw-r--r--bootstrap/lib/kernel/ebin/logger.beambin15012 -> 15060 bytes
-rw-r--r--bootstrap/lib/kernel/ebin/logger_formatter.beambin8552 -> 9060 bytes
-rw-r--r--bootstrap/lib/kernel/ebin/logger_h_common.beambin7644 -> 7696 bytes
-rw-r--r--bootstrap/lib/kernel/ebin/logger_simple_h.beambin4236 -> 4212 bytes
-rw-r--r--bootstrap/lib/kernel/ebin/logger_std_h.beambin5168 -> 9544 bytes
-rw-r--r--bootstrap/lib/stdlib/ebin/array.beambin11640 -> 11568 bytes
-rw-r--r--bootstrap/lib/stdlib/ebin/beam_lib.beambin18660 -> 18820 bytes
-rw-r--r--bootstrap/lib/stdlib/ebin/calendar.beambin7632 -> 8104 bytes
-rw-r--r--bootstrap/lib/stdlib/ebin/io_lib_pretty.beambin20996 -> 21280 bytes
-rw-r--r--bootstrap/lib/stdlib/ebin/stdlib.app2
-rw-r--r--bootstrap/lib/stdlib/ebin/stdlib.appup8
-rw-r--r--bootstrap/lib/stdlib/ebin/string.beambin35032 -> 35136 bytes
-rw-r--r--bootstrap/lib/stdlib/ebin/unicode_util.beambin198636 -> 200156 bytes
-rw-r--r--erts/configure.in26
-rw-r--r--erts/doc/src/erlang.xml85
-rw-r--r--erts/doc/src/notes.xml32
-rw-r--r--erts/emulator/beam/atom.names1
-rw-r--r--erts/emulator/beam/beam_debug.c15
-rw-r--r--erts/emulator/beam/beam_load.c285
-rw-r--r--erts/emulator/beam/bif.tab2
-rw-r--r--erts/emulator/beam/dist.c114
-rw-r--r--erts/emulator/beam/dist.h3
-rw-r--r--erts/emulator/beam/erl_bif_info.c23
-rw-r--r--erts/emulator/beam/erl_binary.h11
-rw-r--r--erts/emulator/beam/erl_nif.c28
-rw-r--r--erts/emulator/beam/erl_node_tables.c2
-rw-r--r--erts/emulator/beam/erl_node_tables.h1
-rw-r--r--erts/emulator/beam/erl_proc_sig_queue.c10
-rw-r--r--erts/emulator/beam/erl_process.c35
-rw-r--r--erts/emulator/beam/erl_process.h1
-rw-r--r--erts/emulator/beam/instrs.tab62
-rw-r--r--erts/emulator/beam/map_instrs.tab28
-rw-r--r--erts/emulator/beam/ops.tab193
-rw-r--r--erts/emulator/nifs/common/socket_dbg.c40
-rw-r--r--erts/emulator/nifs/common/socket_nif.c33
-rw-r--r--erts/emulator/nifs/common/socket_util.c40
-rw-r--r--erts/emulator/test/dirty_bif_SUITE.erl54
-rw-r--r--erts/emulator/test/nif_SUITE.erl44
-rw-r--r--erts/emulator/test/nif_SUITE_data/nif_SUITE.c176
-rw-r--r--erts/emulator/test/socket_SUITE.erl181
-rwxr-xr-xerts/emulator/utils/beam_makeops2
-rw-r--r--erts/preloaded/ebin/erlang.beambin99948 -> 100196 bytes
-rw-r--r--erts/preloaded/src/erlang.erl20
-rw-r--r--erts/vsn.mk2
-rw-r--r--lib/compiler/scripts/smoke-mix.exs8
-rw-r--r--lib/compiler/src/Makefile3
-rw-r--r--lib/compiler/src/compile.erl12
-rw-r--r--lib/crypto/c_src/algorithms.c6
-rw-r--r--lib/crypto/c_src/api_ng.c7
-rw-r--r--lib/crypto/c_src/cipher.c4
-rw-r--r--lib/crypto/c_src/digest.c37
-rw-r--r--lib/crypto/c_src/engine.c10
-rw-r--r--lib/crypto/c_src/hash.c32
-rw-r--r--lib/crypto/c_src/hmac.c4
-rw-r--r--lib/crypto/c_src/openssl_config.h38
-rw-r--r--lib/crypto/test/crypto_SUITE.erl9
-rw-r--r--lib/dialyzer/src/Makefile4
-rw-r--r--lib/hipe/cerl/Makefile5
-rw-r--r--lib/hipe/icode/hipe_beam_to_icode.erl18
-rw-r--r--lib/hipe/llvm/Makefile5
-rw-r--r--lib/hipe/main/hipe.erl12
-rw-r--r--lib/hipe/rtl/Makefile5
-rw-r--r--lib/kernel/examples/gen_tcp_dist/Makefile4
-rw-r--r--lib/kernel/examples/gen_tcp_dist/src/gen_tcp_dist.erl15
-rw-r--r--lib/kernel/src/Makefile4
-rw-r--r--lib/kernel/src/application_controller.erl27
-rw-r--r--lib/kernel/src/global.erl85
-rw-r--r--lib/kernel/test/Makefile6
-rw-r--r--lib/kernel/test/application_SUITE.erl17
-rw-r--r--lib/kernel/test/erl_distribution_SUITE.erl317
-rw-r--r--lib/kernel/test/gen_sctp_SUITE.erl10
-rw-r--r--lib/kernel/test/gen_tcp_api_SUITE_data/gen_tcp_api_SUITE.c1
-rw-r--r--lib/kernel/test/gen_tcp_misc_SUITE.erl37
-rw-r--r--lib/ssl/src/ssl_record.erl7
-rw-r--r--lib/ssl/src/tls_handshake_1_3.erl3
-rw-r--r--lib/ssl/src/tls_record_1_3.erl7
-rw-r--r--lib/ssl/test/ssl_basic_SUITE.erl26
-rw-r--r--lib/stdlib/src/Makefile4
-rw-r--r--lib/tools/emacs/erlang.el2
-rw-r--r--lib/xmerl/doc/src/notes.xml22
-rw-r--r--lib/xmerl/src/xmerl_scan.erl15
-rw-r--r--lib/xmerl/vsn.mk2
-rw-r--r--make/otp_patch_solve_forward_merge_version2
-rw-r--r--otp_versions.table1
103 files changed, 1725 insertions, 688 deletions
diff --git a/.gitignore b/.gitignore
index 9497169cde..4a6aaab6f3 100644
--- a/.gitignore
+++ b/.gitignore
@@ -323,6 +323,7 @@ JAVADOC-GENERATED
# kernel
/lib/kernel/src/inet_dns_record_adts.hrl
+/lib/kernel/test/gen_tcp_dist.erl
# kernel
diff --git a/bootstrap/bin/no_dot_erlang.boot b/bootstrap/bin/no_dot_erlang.boot
index b48d22fe41..5428e202e7 100644
--- a/bootstrap/bin/no_dot_erlang.boot
+++ b/bootstrap/bin/no_dot_erlang.boot
Binary files differ
diff --git a/bootstrap/bin/start.boot b/bootstrap/bin/start.boot
index b48d22fe41..5428e202e7 100644
--- a/bootstrap/bin/start.boot
+++ b/bootstrap/bin/start.boot
Binary files differ
diff --git a/bootstrap/bin/start_clean.boot b/bootstrap/bin/start_clean.boot
index b48d22fe41..5428e202e7 100644
--- a/bootstrap/bin/start_clean.boot
+++ b/bootstrap/bin/start_clean.boot
Binary files differ
diff --git a/bootstrap/lib/compiler/ebin/beam_asm.beam b/bootstrap/lib/compiler/ebin/beam_asm.beam
index 5c91f09b30..5dafb89f68 100644
--- a/bootstrap/lib/compiler/ebin/beam_asm.beam
+++ b/bootstrap/lib/compiler/ebin/beam_asm.beam
Binary files differ
diff --git a/bootstrap/lib/compiler/ebin/beam_ssa_opt.beam b/bootstrap/lib/compiler/ebin/beam_ssa_opt.beam
index 7b34cc5906..b1bd549a8a 100644
--- a/bootstrap/lib/compiler/ebin/beam_ssa_opt.beam
+++ b/bootstrap/lib/compiler/ebin/beam_ssa_opt.beam
Binary files differ
diff --git a/bootstrap/lib/compiler/ebin/beam_validator.beam b/bootstrap/lib/compiler/ebin/beam_validator.beam
index a5db96bdaf..71186a12cd 100644
--- a/bootstrap/lib/compiler/ebin/beam_validator.beam
+++ b/bootstrap/lib/compiler/ebin/beam_validator.beam
Binary files differ
diff --git a/bootstrap/lib/compiler/ebin/compile.beam b/bootstrap/lib/compiler/ebin/compile.beam
index 5829ab4867..57cfc6b932 100644
--- a/bootstrap/lib/compiler/ebin/compile.beam
+++ b/bootstrap/lib/compiler/ebin/compile.beam
Binary files differ
diff --git a/bootstrap/lib/compiler/ebin/compiler.app b/bootstrap/lib/compiler/ebin/compiler.app
index 0a5e6de039..c0483e7801 100644
--- a/bootstrap/lib/compiler/ebin/compiler.app
+++ b/bootstrap/lib/compiler/ebin/compiler.app
@@ -19,7 +19,7 @@
{application, compiler,
[{description, "ERTS CXC 138 10"},
- {vsn, "7.3.1"},
+ {vsn, "7.3.2"},
{modules, [
beam_a,
beam_asm,
diff --git a/bootstrap/lib/compiler/ebin/compiler.appup b/bootstrap/lib/compiler/ebin/compiler.appup
index 8370664167..3d4fe9c021 100644
--- a/bootstrap/lib/compiler/ebin/compiler.appup
+++ b/bootstrap/lib/compiler/ebin/compiler.appup
@@ -16,7 +16,7 @@
%% limitations under the License.
%%
%% %CopyrightEnd%
-{"7.3.1",
+{"7.3.2",
[{<<".*">>,[{restart_application, compiler}]}],
[{<<".*">>,[{restart_application, compiler}]}]
}.
diff --git a/bootstrap/lib/kernel/ebin/application.beam b/bootstrap/lib/kernel/ebin/application.beam
index 9db02f55fd..84c5b7636e 100644
--- a/bootstrap/lib/kernel/ebin/application.beam
+++ b/bootstrap/lib/kernel/ebin/application.beam
Binary files differ
diff --git a/bootstrap/lib/kernel/ebin/application_controller.beam b/bootstrap/lib/kernel/ebin/application_controller.beam
index 32612f1bf6..c33895a44e 100644
--- a/bootstrap/lib/kernel/ebin/application_controller.beam
+++ b/bootstrap/lib/kernel/ebin/application_controller.beam
Binary files differ
diff --git a/bootstrap/lib/kernel/ebin/code_server.beam b/bootstrap/lib/kernel/ebin/code_server.beam
index 6add687cf2..6cbda0c9bb 100644
--- a/bootstrap/lib/kernel/ebin/code_server.beam
+++ b/bootstrap/lib/kernel/ebin/code_server.beam
Binary files differ
diff --git a/bootstrap/lib/kernel/ebin/global.beam b/bootstrap/lib/kernel/ebin/global.beam
index f57cf03afd..f4ca5b8620 100644
--- a/bootstrap/lib/kernel/ebin/global.beam
+++ b/bootstrap/lib/kernel/ebin/global.beam
Binary files differ
diff --git a/bootstrap/lib/kernel/ebin/hipe_unified_loader.beam b/bootstrap/lib/kernel/ebin/hipe_unified_loader.beam
index fc80f2d1bd..9270358896 100644
--- a/bootstrap/lib/kernel/ebin/hipe_unified_loader.beam
+++ b/bootstrap/lib/kernel/ebin/hipe_unified_loader.beam
Binary files differ
diff --git a/bootstrap/lib/kernel/ebin/inet_db.beam b/bootstrap/lib/kernel/ebin/inet_db.beam
index 76d7ac2adb..e53e183312 100644
--- a/bootstrap/lib/kernel/ebin/inet_db.beam
+++ b/bootstrap/lib/kernel/ebin/inet_db.beam
Binary files differ
diff --git a/bootstrap/lib/kernel/ebin/kernel.app b/bootstrap/lib/kernel/ebin/kernel.app
index ab106113c2..c3f4e2b892 100644
--- a/bootstrap/lib/kernel/ebin/kernel.app
+++ b/bootstrap/lib/kernel/ebin/kernel.app
@@ -22,7 +22,7 @@
{application, kernel,
[
{description, "ERTS CXC 138 10"},
- {vsn, "6.2"},
+ {vsn, "6.3"},
{modules, [application,
application_controller,
application_master,
@@ -147,6 +147,6 @@
{logger_sasl_compatible, false}
]},
{mod, {kernel, []}},
- {runtime_dependencies, ["erts-10.1", "stdlib-3.5", "sasl-3.0"]}
+ {runtime_dependencies, ["erts-10.2.5", "stdlib-3.5", "sasl-3.0"]}
]
}.
diff --git a/bootstrap/lib/kernel/ebin/kernel.appup b/bootstrap/lib/kernel/ebin/kernel.appup
index 59e716b2d0..e126f18b35 100644
--- a/bootstrap/lib/kernel/ebin/kernel.appup
+++ b/bootstrap/lib/kernel/ebin/kernel.appup
@@ -26,7 +26,7 @@
%% versions that have branched off from the above
%% stated previous versions.
%%
-{"6.2",
+{"6.3",
[{<<"^5\\.3$">>,[restart_new_emulator]},
{<<"^5\\.3\\.0(?:\\.[0-9]+)+$">>,[restart_new_emulator]},
{<<"^5\\.3\\.1(?:\\.[0-9]+)*$">>,[restart_new_emulator]},
@@ -40,7 +40,10 @@
{<<"^6\\.0\\.1(?:\\.[0-9]+)*$">>,[restart_new_emulator]},
{<<"^6\\.1$">>,[restart_new_emulator]},
{<<"^6\\.1\\.0(?:\\.[0-9]+)+$">>,[restart_new_emulator]},
- {<<"^6\\.1\\.1(?:\\.[0-9]+)*$">>,[restart_new_emulator]}],
+ {<<"^6\\.1\\.1(?:\\.[0-9]+)*$">>,[restart_new_emulator]},
+ {<<"^6\\.2$">>,[restart_new_emulator]},
+ {<<"^6\\.2\\.0(?:\\.[0-9]+)+$">>,[restart_new_emulator]},
+ {<<"^6\\.2\\.1(?:\\.[0-9]+)*$">>,[restart_new_emulator]}],
[{<<"^5\\.3$">>,[restart_new_emulator]},
{<<"^5\\.3\\.0(?:\\.[0-9]+)+$">>,[restart_new_emulator]},
{<<"^5\\.3\\.1(?:\\.[0-9]+)*$">>,[restart_new_emulator]},
@@ -54,4 +57,7 @@
{<<"^6\\.0\\.1(?:\\.[0-9]+)*$">>,[restart_new_emulator]},
{<<"^6\\.1$">>,[restart_new_emulator]},
{<<"^6\\.1\\.0(?:\\.[0-9]+)+$">>,[restart_new_emulator]},
- {<<"^6\\.1\\.1(?:\\.[0-9]+)*$">>,[restart_new_emulator]}]}.
+ {<<"^6\\.1\\.1(?:\\.[0-9]+)*$">>,[restart_new_emulator]},
+ {<<"^6\\.2$">>,[restart_new_emulator]},
+ {<<"^6\\.2\\.0(?:\\.[0-9]+)+$">>,[restart_new_emulator]},
+ {<<"^6\\.2\\.1(?:\\.[0-9]+)*$">>,[restart_new_emulator]}]}.
diff --git a/bootstrap/lib/kernel/ebin/kernel.beam b/bootstrap/lib/kernel/ebin/kernel.beam
index 8f75029c0f..11be83a49e 100644
--- a/bootstrap/lib/kernel/ebin/kernel.beam
+++ b/bootstrap/lib/kernel/ebin/kernel.beam
Binary files differ
diff --git a/bootstrap/lib/kernel/ebin/logger.beam b/bootstrap/lib/kernel/ebin/logger.beam
index bd17885e22..1dc1c4fef4 100644
--- a/bootstrap/lib/kernel/ebin/logger.beam
+++ b/bootstrap/lib/kernel/ebin/logger.beam
Binary files differ
diff --git a/bootstrap/lib/kernel/ebin/logger_formatter.beam b/bootstrap/lib/kernel/ebin/logger_formatter.beam
index 83df11e66f..e3e40460f0 100644
--- a/bootstrap/lib/kernel/ebin/logger_formatter.beam
+++ b/bootstrap/lib/kernel/ebin/logger_formatter.beam
Binary files differ
diff --git a/bootstrap/lib/kernel/ebin/logger_h_common.beam b/bootstrap/lib/kernel/ebin/logger_h_common.beam
index 5e14216b5d..9e8c25b6b9 100644
--- a/bootstrap/lib/kernel/ebin/logger_h_common.beam
+++ b/bootstrap/lib/kernel/ebin/logger_h_common.beam
Binary files differ
diff --git a/bootstrap/lib/kernel/ebin/logger_simple_h.beam b/bootstrap/lib/kernel/ebin/logger_simple_h.beam
index 954bbdc071..583c77b290 100644
--- a/bootstrap/lib/kernel/ebin/logger_simple_h.beam
+++ b/bootstrap/lib/kernel/ebin/logger_simple_h.beam
Binary files differ
diff --git a/bootstrap/lib/kernel/ebin/logger_std_h.beam b/bootstrap/lib/kernel/ebin/logger_std_h.beam
index 3b5d3cd9f8..b0f56d9a62 100644
--- a/bootstrap/lib/kernel/ebin/logger_std_h.beam
+++ b/bootstrap/lib/kernel/ebin/logger_std_h.beam
Binary files differ
diff --git a/bootstrap/lib/stdlib/ebin/array.beam b/bootstrap/lib/stdlib/ebin/array.beam
index ac3193515c..9e783452f5 100644
--- a/bootstrap/lib/stdlib/ebin/array.beam
+++ b/bootstrap/lib/stdlib/ebin/array.beam
Binary files differ
diff --git a/bootstrap/lib/stdlib/ebin/beam_lib.beam b/bootstrap/lib/stdlib/ebin/beam_lib.beam
index c13a82a074..44d783a6d0 100644
--- a/bootstrap/lib/stdlib/ebin/beam_lib.beam
+++ b/bootstrap/lib/stdlib/ebin/beam_lib.beam
Binary files differ
diff --git a/bootstrap/lib/stdlib/ebin/calendar.beam b/bootstrap/lib/stdlib/ebin/calendar.beam
index d0abc17e48..89102adda8 100644
--- a/bootstrap/lib/stdlib/ebin/calendar.beam
+++ b/bootstrap/lib/stdlib/ebin/calendar.beam
Binary files differ
diff --git a/bootstrap/lib/stdlib/ebin/io_lib_pretty.beam b/bootstrap/lib/stdlib/ebin/io_lib_pretty.beam
index 7ffe569c60..ba644430da 100644
--- a/bootstrap/lib/stdlib/ebin/io_lib_pretty.beam
+++ b/bootstrap/lib/stdlib/ebin/io_lib_pretty.beam
Binary files differ
diff --git a/bootstrap/lib/stdlib/ebin/stdlib.app b/bootstrap/lib/stdlib/ebin/stdlib.app
index 2bb0b06f12..9f6ff2942b 100644
--- a/bootstrap/lib/stdlib/ebin/stdlib.app
+++ b/bootstrap/lib/stdlib/ebin/stdlib.app
@@ -20,7 +20,7 @@
%%
{application, stdlib,
[{description, "ERTS CXC 138 10"},
- {vsn, "3.7.1"},
+ {vsn, "3.8"},
{modules, [array,
base64,
beam_lib,
diff --git a/bootstrap/lib/stdlib/ebin/stdlib.appup b/bootstrap/lib/stdlib/ebin/stdlib.appup
index d22e917574..76372566d5 100644
--- a/bootstrap/lib/stdlib/ebin/stdlib.appup
+++ b/bootstrap/lib/stdlib/ebin/stdlib.appup
@@ -26,7 +26,7 @@
%% versions that have branched off from the above
%% stated previous versions.
%%
-{"3.7.1",
+{"3.8",
[{<<"^3\\.4$">>,[restart_new_emulator]},
{<<"^3\\.4\\.0(?:\\.[0-9]+)+$">>,[restart_new_emulator]},
{<<"^3\\.4\\.1(?:\\.[0-9]+)*$">>,[restart_new_emulator]},
@@ -40,7 +40,8 @@
{<<"^3\\.6$">>,[restart_new_emulator]},
{<<"^3\\.6\\.0(?:\\.[0-9]+)+$">>,[restart_new_emulator]},
{<<"^3\\.7$">>,[restart_new_emulator]},
- {<<"^3\\.7\\.0(?:\\.[0-9]+)+$">>,[restart_new_emulator]}],
+ {<<"^3\\.7\\.0(?:\\.[0-9]+)+$">>,[restart_new_emulator]},
+ {<<"^3\\.7\\.1(?:\\.[0-9]+)*$">>,[restart_new_emulator]}],
[{<<"^3\\.4$">>,[restart_new_emulator]},
{<<"^3\\.4\\.0(?:\\.[0-9]+)+$">>,[restart_new_emulator]},
{<<"^3\\.4\\.1(?:\\.[0-9]+)*$">>,[restart_new_emulator]},
@@ -54,4 +55,5 @@
{<<"^3\\.6$">>,[restart_new_emulator]},
{<<"^3\\.6\\.0(?:\\.[0-9]+)+$">>,[restart_new_emulator]},
{<<"^3\\.7$">>,[restart_new_emulator]},
- {<<"^3\\.7\\.0(?:\\.[0-9]+)+$">>,[restart_new_emulator]}]}.
+ {<<"^3\\.7\\.0(?:\\.[0-9]+)+$">>,[restart_new_emulator]},
+ {<<"^3\\.7\\.1(?:\\.[0-9]+)*$">>,[restart_new_emulator]}]}.
diff --git a/bootstrap/lib/stdlib/ebin/string.beam b/bootstrap/lib/stdlib/ebin/string.beam
index da647da3ca..437f63357c 100644
--- a/bootstrap/lib/stdlib/ebin/string.beam
+++ b/bootstrap/lib/stdlib/ebin/string.beam
Binary files differ
diff --git a/bootstrap/lib/stdlib/ebin/unicode_util.beam b/bootstrap/lib/stdlib/ebin/unicode_util.beam
index 8ddf73ca26..c9db0483ca 100644
--- a/bootstrap/lib/stdlib/ebin/unicode_util.beam
+++ b/bootstrap/lib/stdlib/ebin/unicode_util.beam
Binary files differ
diff --git a/erts/configure.in b/erts/configure.in
index b070ad0649..5f969a0a8b 100644
--- a/erts/configure.in
+++ b/erts/configure.in
@@ -2783,6 +2783,32 @@ AC_SUBST(HIPE_ENABLED)
NATIVE_LIBS_ENABLED=
if test X${enable_native_libs} = Xyes -a X${HIPE_ENABLED} = Xyes; then
NATIVE_LIBS_ENABLED=yes
+ cat >> $ERL_TOP/erts/CONF_INFO <<EOF
+
+ WARNING: In OTP 22, HiPE (the native code compiler) is
+ not fully functional. The reasons for this are:
+
+ 1. There are new BEAM instructions for binary
+ matching that the HiPE native code compiler does not
+ support.
+
+ 2. The new optimizations in the Erlang compiler create
+ new combination of instructions that HiPE currently
+ does not handle correctly.
+
+ If erlc is invoked like so:
+
+ erlc +native some_file.erl
+
+ or like so:
+
+ erlc +native some_file.beam
+
+ and if any of the new binary matching instructions
+ are used, the compiler will issue a warning and
+ produce a BEAM file without native code.
+
+EOF
fi
AC_SUBST(NATIVE_LIBS_ENABLED)
diff --git a/erts/doc/src/erlang.xml b/erts/doc/src/erlang.xml
index e78ded4ae1..0d94f83493 100644
--- a/erts/doc/src/erlang.xml
+++ b/erts/doc/src/erlang.xml
@@ -1269,6 +1269,42 @@ end</code>
data is available by calling
<seealso marker="erlang#dist_ctrl_get_data_notification/1"><c>erlang:dist_ctrl_get_data_notification(DHandle)</c></seealso>.
</p>
+ <p>The returned value when there are data available depends
+ on the value of the <c>get_size</c> option configured on the
+ distribution channel identified by <c><anno>DHandle</anno></c>.
+ For more information see the documentation of the <c>get_size</c>
+ option for the
+ <seealso marker="#dist_ctrl_set_opt/3"><c>erlang:dist_ctrl_set_opt/3</c></seealso>
+ function.</p>
+ <note><p>
+ Only the process registered as distribution
+ controller for the distribution channel identified by
+ <c><anno>DHandle</anno></c> is allowed to call this
+ function.
+ </p></note>
+ <p>
+ This function is used when implementing an alternative
+ distribution carrier using processes as distribution
+ controllers. <c><anno>DHandle</anno></c> is retrived
+ via the callback
+ <seealso marker="erts:alt_dist#hs_data_f_handshake_complete"><c>f_handshake_complete</c></seealso>.
+ More information can be found in the documentation of
+ <seealso marker="erts:alt_dist#distribution_module">ERTS
+ User's Guide ➜ How to implement an Alternative Carrier
+ for the Erlang Distribution ➜ Distribution Module</seealso>.
+ </p>
+ </desc>
+ </func>
+
+ <func>
+ <name name="dist_ctrl_get_opt" arity="2" clause_i="1" since="OTP @OTP-15617@"/>
+ <fsummary>Get value of the get_size option on a distribution channel</fsummary>
+ <desc>
+ <p>Returns the value of the <c>get_size</c> option on the distribution channel
+ identified by <c><anno>DHandle</anno></c>. For more information see the
+ documentation of the <c>get_size</c> option for the
+ <seealso marker="#dist_ctrl_set_opt/3"><c>erlang:dist_ctrl_set_opt/3</c></seealso>
+ function.</p>
<note><p>
Only the process registered as distribution
controller for the distribution channel identified by
@@ -1392,6 +1428,55 @@ end</code>
</func>
<func>
+ <name name="dist_ctrl_set_opt" arity="3" clause_i="1" since="OTP @OTP-15617@"/>
+ <fsummary>Set value of the get_size option on a distribution channel</fsummary>
+ <desc>
+ <p>Sets the value of the <c>get_size</c> option on the distribution channel
+ identified by <c><anno>DHandle</anno></c>. This option controls the return
+ value of calls to
+ <seealso marker="#dist_ctrl_get_data/1">erlang:dist_ctrl_get_data(<anno>DHandle</anno>)</seealso>
+ where <c><anno>DHandle</anno></c> equals <c><anno>DHandle</anno></c> used
+ when setting this option.
+ When the <c>get_size</c> option is:</p>
+ <taglist>
+ <tag><c>false</c></tag>
+ <item>
+ and there are distribution data available, a call to
+ <c>erlang:dist_ctrl_get_data(<anno>DHandle</anno>)</c>
+ will just return <c>Data</c> to pass over the channel.
+ This is the default value of the <c>get_size</c> option.
+ </item>
+ <tag><c>true</c></tag>
+ <item>
+ and there are distribution data available, a call to
+ <c>erlang:dist_ctrl_get_data(<anno>DHandle</anno>)</c>
+ will return <c>Data</c> to pass over the channel as well as
+ the <c>Size</c> of <c>Data</c> in bytes. This is returned as
+ a tuple on the form <c>{Size, Data}</c>.
+ </item>
+ </taglist>
+ <p>All options are set to default when a channel is closed.</p>
+ <note><p>
+ Only the process registered as distribution
+ controller for the distribution channel identified by
+ <c><anno>DHandle</anno></c> is allowed to call this
+ function.
+ </p></note>
+ <p>
+ This function is used when implementing an alternative
+ distribution carrier using processes as distribution
+ controllers. <c><anno>DHandle</anno></c> is retrived
+ via the callback
+ <seealso marker="erts:alt_dist#hs_data_f_handshake_complete"><c>f_handshake_complete</c></seealso>.
+ More information can be found in the documentation of
+ <seealso marker="erts:alt_dist#distribution_module">ERTS
+ User's Guide ➜ How to implement an Alternative Carrier
+ for the Erlang Distribution ➜ Distribution Module</seealso>.
+ </p>
+ </desc>
+ </func>
+
+ <func>
<name name="element" arity="2" since=""/>
<fsummary>Return the Nth element of a tuple.</fsummary>
<type_desc variable="N">1..tuple_size(<anno>Tuple</anno>)</type_desc>
diff --git a/erts/doc/src/notes.xml b/erts/doc/src/notes.xml
index bdae994d06..248b871ca0 100644
--- a/erts/doc/src/notes.xml
+++ b/erts/doc/src/notes.xml
@@ -31,6 +31,38 @@
</header>
<p>This document describes the changes made to the ERTS application.</p>
+<section><title>Erts 10.3.1</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>If a suspend/resume signal pair was sent to a process
+ while it was executing dirty, the receiving process could
+ later end up in a suspended state indefinitely. This bug
+ was introduced in ERTS version 10.0 (OTP 21.0).</p>
+ <p>Suspend/resume signals are sent from <seealso
+ marker="erts:erlang#suspend_process/1"><c>erlang:suspend_process()</c></seealso>/<seealso
+ marker="erts:erlang#resume_process/1"><c>erlang:resume_process()</c></seealso>.
+ The <seealso
+ marker="runtime_tools:dbg"><c>dbg</c></seealso> trace
+ tool utilize this functionality and could thus trigger
+ this bug.</p>
+ <p>
+ Own Id: OTP-15688</p>
+ </item>
+ <item>
+ <p>
+ Fix a possible deadlock when terminating the ERTS caused
+ by a dirty scheduler not releasing it's run-queue lock
+ when terminating.</p>
+ <p>
+ Own Id: OTP-15690 Aux Id: PR-2172 </p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
<section><title>Erts 10.3</title>
<section><title>Fixed Bugs and Malfunctions</title>
diff --git a/erts/emulator/beam/atom.names b/erts/emulator/beam/atom.names
index f81082a698..412d689246 100644
--- a/erts/emulator/beam/atom.names
+++ b/erts/emulator/beam/atom.names
@@ -290,6 +290,7 @@ atom Ge='>='
atom generational
atom get_all_trap
atom get_seq_token
+atom get_size
atom get_tcw
atom gather_gc_info_result
atom gather_io_bytes
diff --git a/erts/emulator/beam/beam_debug.c b/erts/emulator/beam/beam_debug.c
index f71efd708f..762c5da9be 100644
--- a/erts/emulator/beam/beam_debug.c
+++ b/erts/emulator/beam/beam_debug.c
@@ -332,6 +332,13 @@ erts_debug_disassemble_1(BIF_ALIST_1)
"unknown " HEXF "\n", instr);
code_ptr++;
}
+ if (i == op_call_nif) {
+ /*
+ * The rest of the code will not be executed. Don't disassemble any
+ * more code in this function.
+ */
+ code_ptr = 0;
+ }
bin = new_binary(p, (byte *) dsbufp->str, dsbufp->str_len);
erts_destroy_tmp_dsbuf(dsbufp);
hsz = 4+4;
@@ -569,6 +576,7 @@ print_op(fmtfn_t to, void *to_arg, int op, int size, BeamInstr* addr)
}
break;
case op_i_bs_match_string_xfWW:
+ case op_i_bs_match_string_yfWW:
if (ap - first_arg < 3) {
erts_print(to, to_arg, "%d", *ap);
} else {
@@ -772,8 +780,11 @@ print_op(fmtfn_t to, void *to_arg, int op, int size, BeamInstr* addr)
case op_put_tuple2_xI:
case op_put_tuple2_yI:
case op_new_map_dtI:
- case op_update_map_assoc_sdtI:
- case op_update_map_exact_jsdtI:
+ case op_update_map_assoc_xdtI:
+ case op_update_map_assoc_ydtI:
+ case op_update_map_assoc_cdtI:
+ case op_update_map_exact_xjdtI:
+ case op_update_map_exact_yjdtI:
{
int n = unpacked[-1];
diff --git a/erts/emulator/beam/beam_load.c b/erts/emulator/beam/beam_load.c
index 0ad5329b2f..21740caa2c 100644
--- a/erts/emulator/beam/beam_load.c
+++ b/erts/emulator/beam/beam_load.c
@@ -492,6 +492,11 @@ typedef struct LoaderState {
(Genop)->arity * sizeof(GenOpArg)); \
} while (0)
+#define GENOP_NAME_ARITY(Genop, Name, Arity) \
+ do { \
+ (Genop)->op = genop_##Name##_##Arity; \
+ (Genop)->arity = Arity; \
+ } while (0)
static void free_loader_state(Binary* magic);
static ErlHeapFragment* new_literal_fragment(Uint size);
@@ -3141,6 +3146,35 @@ is_killed(LoaderState* stp, GenOpArg Reg, GenOpArg Live)
}
/*
+ * Test whether register Reg is killed by make_fun instruction that
+ * creates the fun given by index idx.
+ */
+
+static int
+is_killed_by_make_fun(LoaderState* stp, GenOpArg Reg, GenOpArg idx)
+{
+ Uint num_free;
+
+ if (idx.val >= stp->num_lambdas) {
+ /* Invalid index. Ignore the error for now. */
+ return 0;
+ } else {
+ num_free = stp->lambdas[idx.val].num_free;
+ return Reg.type == TAG_x && num_free <= Reg.val;
+ }
+}
+
+/*
+ * Test whether register Reg is killed by the send instruction that follows.
+ */
+
+static int
+is_killed_by_send(LoaderState* stp, GenOpArg Reg)
+{
+ return Reg.type == TAG_x && 2 <= Reg.val;
+}
+
+/*
* Generate an instruction for element/2.
*/
@@ -3151,20 +3185,19 @@ gen_element(LoaderState* stp, GenOpArg Fail, GenOpArg Index,
GenOp* op;
NEW_GENOP(stp, op);
- op->arity = 4;
op->next = NULL;
if (Index.type == TAG_i && Index.val > 0 &&
Index.val <= ERTS_MAX_TUPLE_SIZE &&
(Tuple.type == TAG_x || Tuple.type == TAG_y)) {
- op->op = genop_i_fast_element_4;
+ GENOP_NAME_ARITY(op, i_fast_element, 4);
op->a[0] = Tuple;
op->a[1] = Fail;
op->a[2].type = TAG_u;
op->a[2].val = Index.val;
op->a[3] = Dst;
} else {
- op->op = genop_i_element_4;
+ GENOP_NAME_ARITY(op, i_element, 4);
op->a[0] = Tuple;
op->a[1] = Fail;
op->a[2] = Index;
@@ -3180,8 +3213,7 @@ gen_bs_save(LoaderState* stp, GenOpArg Reg, GenOpArg Index)
GenOp* op;
NEW_GENOP(stp, op);
- op->op = genop_i_bs_save2_2;
- op->arity = 2;
+ GENOP_NAME_ARITY(op, i_bs_save2, 2);
op->a[0] = Reg;
op->a[1] = Index;
if (Index.type == TAG_u) {
@@ -3200,8 +3232,7 @@ gen_bs_restore(LoaderState* stp, GenOpArg Reg, GenOpArg Index)
GenOp* op;
NEW_GENOP(stp, op);
- op->op = genop_i_bs_restore2_2;
- op->arity = 2;
+ GENOP_NAME_ARITY(op, i_bs_restore2, 2);
op->a[0] = Reg;
op->a[1] = Index;
if (Index.type == TAG_u) {
@@ -3235,21 +3266,18 @@ gen_get_integer2(LoaderState* stp, GenOpArg Fail, GenOpArg Ms, GenOpArg Live,
} else if ((Flags.val & BSF_SIGNED) != 0) {
goto generic;
} else if (bits == 8) {
- op->op = genop_i_bs_get_integer_8_3;
- op->arity = 3;
- op->a[0] = Ms;
+ GENOP_NAME_ARITY(op, i_bs_get_integer_8, 3);
+ op->a[0] = Ms;
op->a[1] = Fail;
op->a[2] = Dst;
} else if (bits == 16 && (Flags.val & BSF_LITTLE) == 0) {
- op->op = genop_i_bs_get_integer_16_3;
- op->arity = 3;
+ GENOP_NAME_ARITY(op, i_bs_get_integer_16, 3);
op->a[0] = Ms;
op->a[1] = Fail;
op->a[2] = Dst;
#ifdef ARCH_64
} else if (bits == 32 && (Flags.val & BSF_LITTLE) == 0) {
- op->op = genop_i_bs_get_integer_32_3;
- op->arity = 3;
+ GENOP_NAME_ARITY(op, i_bs_get_integer_32, 3);
op->a[0] = Ms;
op->a[1] = Fail;
op->a[2] = Dst;
@@ -3257,8 +3285,7 @@ gen_get_integer2(LoaderState* stp, GenOpArg Fail, GenOpArg Ms, GenOpArg Live,
} else {
generic:
if (bits < SMALL_BITS) {
- op->op = genop_i_bs_get_integer_small_imm_5;
- op->arity = 5;
+ GENOP_NAME_ARITY(op, i_bs_get_integer_small_imm, 5);
op->a[0] = Ms;
op->a[1].type = TAG_u;
op->a[1].val = bits;
@@ -3266,8 +3293,7 @@ gen_get_integer2(LoaderState* stp, GenOpArg Fail, GenOpArg Ms, GenOpArg Live,
op->a[3] = Flags;
op->a[4] = Dst;
} else {
- op->op = genop_i_bs_get_integer_imm_6;
- op->arity = 6;
+ GENOP_NAME_ARITY(op, i_bs_get_integer_imm, 6);
op->a[0] = Ms;
op->a[1].type = TAG_u;
op->a[1].val = bits;
@@ -3283,8 +3309,7 @@ gen_get_integer2(LoaderState* stp, GenOpArg Fail, GenOpArg Ms, GenOpArg Live,
if (!term_to_Uint(big, &bigval)) {
error:
- op->op = genop_jump_1;
- op->arity = 1;
+ GENOP_NAME_ARITY(op, jump, 1);
op->a[0] = Fail;
} else {
if (!safe_mul(bigval, Unit.val, &bits)) {
@@ -3293,8 +3318,7 @@ gen_get_integer2(LoaderState* stp, GenOpArg Fail, GenOpArg Ms, GenOpArg Live,
goto generic;
}
} else {
- op->op = genop_i_bs_get_integer_6;
- op->arity = 6;
+ GENOP_NAME_ARITY(op, i_bs_get_integer, 6);
op->a[0] = Ms;
op->a[1] = Fail;
op->a[2] = Live;
@@ -3324,23 +3348,20 @@ gen_get_binary2(LoaderState* stp, GenOpArg Fail, GenOpArg Ms, GenOpArg Live,
NATIVE_ENDIAN(Flags);
if (Size.type == TAG_a && Size.val == am_all) {
if (Ms.type == Dst.type && Ms.val == Dst.val) {
- op->op = genop_i_bs_get_binary_all_reuse_3;
- op->arity = 3;
+ GENOP_NAME_ARITY(op, i_bs_get_binary_all_reuse, 3);
op->a[0] = Ms;
op->a[1] = Fail;
op->a[2] = Unit;
} else {
- op->op = genop_i_bs_get_binary_all2_5;
- op->arity = 5;
+ GENOP_NAME_ARITY(op, i_bs_get_binary_all2, 5);
op->a[0] = Ms;
op->a[1] = Fail;
- op->a[2] = Live;
+ op->a[2] = Live;
op->a[3] = Unit;
op->a[4] = Dst;
}
} else if (Size.type == TAG_i) {
- op->op = genop_i_bs_get_binary_imm2_6;
- op->arity = 6;
+ GENOP_NAME_ARITY(op, i_bs_get_binary_imm2, 6);
op->a[0] = Ms;
op->a[1] = Fail;
op->a[2] = Live;
@@ -3356,12 +3377,10 @@ gen_get_binary2(LoaderState* stp, GenOpArg Fail, GenOpArg Ms, GenOpArg Live,
if (!term_to_Uint(big, &bigval)) {
error:
- op->op = genop_jump_1;
- op->arity = 1;
+ GENOP_NAME_ARITY(op, jump, 1);
op->a[0] = Fail;
} else {
- op->op = genop_i_bs_get_binary_imm2_6;
- op->arity = 6;
+ GENOP_NAME_ARITY(op, i_bs_get_binary_imm2, 6);
op->a[0] = Ms;
op->a[1] = Fail;
op->a[2] = Live;
@@ -3373,8 +3392,7 @@ gen_get_binary2(LoaderState* stp, GenOpArg Fail, GenOpArg Ms, GenOpArg Live,
op->a[5] = Dst;
}
} else {
- op->op = genop_i_bs_get_binary2_6;
- op->arity = 6;
+ GENOP_NAME_ARITY(op, i_bs_get_binary2, 6);
op->a[0] = Ms;
op->a[1] = Fail;
op->a[2] = Live;
@@ -3407,22 +3425,19 @@ gen_put_binary(LoaderState* stp, GenOpArg Fail,GenOpArg Size,
NATIVE_ENDIAN(Flags);
if (Size.type == TAG_a && Size.val == am_all) {
- op->op = genop_i_new_bs_put_binary_all_3;
- op->arity = 3;
+ GENOP_NAME_ARITY(op, i_new_bs_put_binary_all, 3);
op->a[0] = Src;
op->a[1] = Fail;
op->a[2] = Unit;
} else if (Size.type == TAG_i) {
- op->op = genop_i_new_bs_put_binary_imm_3;
- op->arity = 3;
+ GENOP_NAME_ARITY(op, i_new_bs_put_binary_imm, 3);
op->a[0] = Fail;
op->a[1].type = TAG_u;
if (safe_mul(Size.val, Unit.val, &op->a[1].val)) {
op->a[2] = Src;
} else {
error:
- op->op = genop_badarg_1;
- op->arity = 1;
+ GENOP_NAME_ARITY(op, badarg, 1);
op->a[0] = Fail;
}
} else if (Size.type == TAG_q) {
@@ -3440,16 +3455,14 @@ gen_put_binary(LoaderState* stp, GenOpArg Fail,GenOpArg Size,
!safe_mul(bigval, Unit.val, &size)) {
goto error;
}
- op->op = genop_i_new_bs_put_binary_imm_3;
- op->arity = 3;
+ GENOP_NAME_ARITY(op, i_new_bs_put_binary_imm, 3);
op->a[0] = Fail;
op->a[1].type = TAG_u;
op->a[1].val = size;
op->a[2] = Src;
#endif
} else {
- op->op = genop_i_new_bs_put_binary_4;
- op->arity = 4;
+ GENOP_NAME_ARITY(op, i_new_bs_put_binary, 4);
op->a[0] = Fail;
op->a[1] = Size;
op->a[2].type = TAG_u;
@@ -3474,14 +3487,12 @@ gen_put_integer(LoaderState* stp, GenOpArg Fail, GenOpArg Size,
Uint size;
if (!safe_mul(Size.val, Unit.val, &size)) {
error:
- op->op = genop_badarg_1;
- op->arity = 1;
+ GENOP_NAME_ARITY(op, badarg, 1);
op->a[0] = Fail;
op->next = NULL;
return op;
}
- op->op = genop_i_new_bs_put_integer_imm_4;
- op->arity = 4;
+ GENOP_NAME_ARITY(op, i_new_bs_put_integer_imm, 4);
op->a[0] = Src;
op->a[1] = Fail;
op->a[2].type = TAG_u;
@@ -3497,8 +3508,7 @@ gen_put_integer(LoaderState* stp, GenOpArg Fail, GenOpArg Size,
!safe_mul(bigval, Unit.val, &size)) {
goto error;
}
- op->op = genop_i_new_bs_put_integer_imm_4;
- op->arity = 4;
+ GENOP_NAME_ARITY(op, i_new_bs_put_integer_imm, 4);
op->a[0] = Src;
op->a[1] = Fail;
op->a[2].type = TAG_u;
@@ -3506,8 +3516,7 @@ gen_put_integer(LoaderState* stp, GenOpArg Fail, GenOpArg Size,
op->a[3].type = Flags.type;
op->a[3].val = (Flags.val & 7);
} else {
- op->op = genop_i_new_bs_put_integer_4;
- op->arity = 4;
+ GENOP_NAME_ARITY(op, i_new_bs_put_integer, 4);
op->a[0] = Fail;
op->a[1] = Size;
op->a[2].type = TAG_u;
@@ -3527,21 +3536,18 @@ gen_put_float(LoaderState* stp, GenOpArg Fail, GenOpArg Size,
NATIVE_ENDIAN(Flags);
if (Size.type == TAG_i) {
- op->op = genop_i_new_bs_put_float_imm_4;
- op->arity = 4;
+ GENOP_NAME_ARITY(op, i_new_bs_put_float_imm, 4);
op->a[0] = Fail;
op->a[1].type = TAG_u;
if (!safe_mul(Size.val, Unit.val, &op->a[1].val)) {
- op->op = genop_badarg_1;
- op->arity = 1;
+ GENOP_NAME_ARITY(op, badarg, 1);
op->a[0] = Fail;
} else {
op->a[2] = Flags;
op->a[3] = Src;
}
} else {
- op->op = genop_i_new_bs_put_float_4;
- op->arity = 4;
+ GENOP_NAME_ARITY(op, i_new_bs_put_float, 4);
op->a[0] = Fail;
op->a[1] = Size;
op->a[2].type = TAG_u;
@@ -3564,8 +3570,7 @@ gen_get_float2(LoaderState* stp, GenOpArg Fail, GenOpArg Ms, GenOpArg Live,
NEW_GENOP(stp, op);
NATIVE_ENDIAN(Flags);
- op->op = genop_i_bs_get_float2_6;
- op->arity = 6;
+ GENOP_NAME_ARITY(op, i_bs_get_float2, 6);
op->a[0] = Ms;
op->a[1] = Fail;
op->a[2] = Live;
@@ -3582,7 +3587,7 @@ gen_get_float2(LoaderState* stp, GenOpArg Fail, GenOpArg Ms, GenOpArg Live,
*/
static GenOp*
-gen_skip_bits2(LoaderState* stp, GenOpArg Fail, GenOpArg Ms,
+gen_skip_bits2(LoaderState* stp, GenOpArg Fail, GenOpArg Ms,
GenOpArg Size, GenOpArg Unit, GenOpArg Flags)
{
GenOp* op;
@@ -3602,16 +3607,14 @@ gen_skip_bits2(LoaderState* stp, GenOpArg Fail, GenOpArg Ms,
* a bs_restore2 instruction which will overwrite the position
* by one of the stored positions.
*/
- op->op = genop_bs_test_unit_3;
- op->arity = 3;
+ GENOP_NAME_ARITY(op, bs_test_unit, 3);
op->a[0] = Fail;
op->a[1] = Ms;
op->a[2] = Unit;
} else if (Size.type == TAG_i) {
- op->op = genop_i_bs_skip_bits_imm2_3;
- op->arity = 3;
+ GENOP_NAME_ARITY(op, i_bs_skip_bits_imm2, 3);
op->a[0] = Fail;
- op->a[1] = Ms;
+ op->a[1] = Ms;
op->a[2].type = TAG_u;
if (!safe_mul(Size.val, Unit.val, &op->a[2].val)) {
goto error;
@@ -3622,22 +3625,19 @@ gen_skip_bits2(LoaderState* stp, GenOpArg Fail, GenOpArg Ms,
if (!term_to_Uint(big, &bigval)) {
error:
- op->op = genop_jump_1;
- op->arity = 1;
+ GENOP_NAME_ARITY(op, jump, 1);
op->a[0] = Fail;
} else {
- op->op = genop_i_bs_skip_bits_imm2_3;
- op->arity = 3;
+ GENOP_NAME_ARITY(op, i_bs_skip_bits_imm2, 3);
op->a[0] = Fail;
- op->a[1] = Ms;
+ op->a[1] = Ms;
op->a[2].type = TAG_u;
if (!safe_mul(bigval, Unit.val, &op->a[2].val)) {
goto error;
}
}
} else {
- op->op = genop_i_bs_skip_bits2_4;
- op->arity = 4;
+ GENOP_NAME_ARITY(op, i_bs_skip_bits2, 4);
op->a[0] = Ms;
op->a[1] = Size;
op->a[2] = Fail;
@@ -3654,8 +3654,7 @@ gen_increment(LoaderState* stp, GenOpArg Reg,
GenOp* op;
NEW_GENOP(stp, op);
- op->op = genop_i_increment_3;
- op->arity = 3;
+ GENOP_NAME_ARITY(op, i_increment, 3);
op->next = NULL;
op->a[0] = Reg;
op->a[1].type = TAG_u;
@@ -3671,8 +3670,7 @@ gen_increment_from_minus(LoaderState* stp, GenOpArg Reg,
GenOp* op;
NEW_GENOP(stp, op);
- op->op = genop_i_increment_3;
- op->arity = 3;
+ GENOP_NAME_ARITY(op, i_increment, 3);
op->next = NULL;
op->a[0] = Reg;
op->a[1].type = TAG_u;
@@ -3681,6 +3679,24 @@ gen_increment_from_minus(LoaderState* stp, GenOpArg Reg,
return op;
}
+static GenOp*
+gen_plus_from_minus(LoaderState* stp, GenOpArg Fail, GenOpArg Live,
+ GenOpArg Src, GenOpArg Integer, GenOpArg Dst)
+{
+ GenOp* op;
+
+ NEW_GENOP(stp, op);
+ GENOP_NAME_ARITY(op, gen_plus, 5);
+ op->next = NULL;
+ op->a[0] = Fail;
+ op->a[1] = Live;
+ op->a[2] = Src;
+ op->a[3].type = TAG_i;
+ op->a[3].val = -Integer.val;
+ op->a[4] = Dst;
+ return op;
+}
+
/*
* Test whether the negation of the given number is small.
*/
@@ -3727,12 +3743,11 @@ gen_literal_timeout(LoaderState* stp, GenOpArg Fail, GenOpArg Time)
Sint timeout;
NEW_GENOP(stp, op);
- op->op = genop_wait_timeout_unlocked_int_2;
+ GENOP_NAME_ARITY(op, wait_timeout_unlocked_int, 2);
op->next = NULL;
- op->arity = 2;
op->a[0].type = TAG_u;
op->a[1] = Fail;
-
+
if (Time.type == TAG_i && (timeout = Time.val) >= 0 &&
#if defined(ARCH_64)
(timeout >> 32) == 0
@@ -3761,8 +3776,7 @@ gen_literal_timeout(LoaderState* stp, GenOpArg Fail, GenOpArg Time)
#if !defined(ARCH_64)
error:
#endif
- op->op = genop_i_wait_error_0;
- op->arity = 0;
+ GENOP_NAME_ARITY(op, i_wait_error, 0);
}
return op;
}
@@ -3774,9 +3788,8 @@ gen_literal_timeout_locked(LoaderState* stp, GenOpArg Fail, GenOpArg Time)
Sint timeout;
NEW_GENOP(stp, op);
- op->op = genop_wait_timeout_locked_int_2;
+ GENOP_NAME_ARITY(op, wait_timeout_locked_int, 2);
op->next = NULL;
- op->arity = 2;
op->a[0].type = TAG_u;
op->a[1] = Fail;
@@ -3808,8 +3821,7 @@ gen_literal_timeout_locked(LoaderState* stp, GenOpArg Fail, GenOpArg Time)
#if !defined(ARCH_64)
error:
#endif
- op->op = genop_i_wait_error_locked_0;
- op->arity = 0;
+ GENOP_NAME_ARITY(op, i_wait_error_locked, 0);
}
return op;
}
@@ -3846,9 +3858,9 @@ gen_select_tuple_arity(LoaderState* stp, GenOpArg S, GenOpArg Fail,
*/
if (size == 2) {
NEW_GENOP(stp, op);
- op->next = NULL;
- op->op = genop_i_select_tuple_arity2_4;
+ GENOP_NAME_ARITY(op, i_select_tuple_arity2, 4);
GENOP_ARITY(op, arity - 1);
+ op->next = NULL;
op->a[0] = S;
op->a[1] = Fail;
op->a[2].type = TAG_u;
@@ -3874,9 +3886,9 @@ gen_select_tuple_arity(LoaderState* stp, GenOpArg S, GenOpArg Fail,
size += align;
NEW_GENOP(stp, op);
- op->next = NULL;
- op->op = genop_i_select_tuple_arity_3;
+ GENOP_NAME_ARITY(op, i_select_tuple_arity, 3);
GENOP_ARITY(op, arity);
+ op->next = NULL;
op->a[0] = S;
op->a[1] = Fail;
op->a[2].type = TAG_u;
@@ -3932,21 +3944,18 @@ gen_split_values(LoaderState* stp, GenOpArg S, GenOpArg TypeFail,
ASSERT(Size.val >= 2 && Size.val % 2 == 0);
NEW_GENOP(stp, is_integer);
- is_integer->op = genop_is_integer_2;
- is_integer->arity = 2;
+ GENOP_NAME_ARITY(is_integer, is_integer, 2);
is_integer->a[0] = TypeFail;
is_integer->a[1] = S;
NEW_GENOP(stp, label);
- label->op = genop_label_1;
- label->arity = 1;
+ GENOP_NAME_ARITY(label, label, 1);
label->a[0].type = TAG_u;
label->a[0].val = new_label(stp);
NEW_GENOP(stp, op1);
- op1->op = genop_select_val_3;
+ GENOP_NAME_ARITY(op1, select_val, 3);
GENOP_ARITY(op1, 3 + Size.val);
- op1->arity = 3;
op1->a[0] = S;
op1->a[1].type = TAG_f;
op1->a[1].val = label->a[0].val;
@@ -3954,9 +3963,8 @@ gen_split_values(LoaderState* stp, GenOpArg S, GenOpArg TypeFail,
op1->a[2].val = 0;
NEW_GENOP(stp, op2);
- op2->op = genop_select_val_3;
+ GENOP_NAME_ARITY(op2, select_val, 3);
GENOP_ARITY(op2, 3 + Size.val);
- op2->arity = 3;
op2->a[0] = S;
op2->a[1] = Fail;
op2->a[2].type = TAG_u;
@@ -4034,19 +4042,17 @@ gen_jump_tab(LoaderState* stp, GenOpArg S, GenOpArg Fail, GenOpArg Size, GenOpAr
GenOp* jump;
NEW_GENOP(stp, op);
- op->arity = 3;
- op->op = genop_is_ne_exact_3;
+ GENOP_NAME_ARITY(op, is_ne_exact, 3);
op->a[0] = Rest[1];
op->a[1] = S;
op->a[2] = Rest[0];
NEW_GENOP(stp, jump);
- jump->next = NULL;
- jump->arity = 1;
- jump->op = genop_jump_1;
+ GENOP_NAME_ARITY(jump, jump, 1);
jump->a[0] = Fail;
op->next = jump;
+ jump->next = NULL;
return op;
}
@@ -4073,12 +4079,11 @@ gen_jump_tab(LoaderState* stp, GenOpArg S, GenOpArg Fail, GenOpArg Size, GenOpAr
NEW_GENOP(stp, op);
op->next = NULL;
if (min == 0) {
- op->op = genop_i_jump_on_val_zero_3;
- fixed_args = 3;
+ GENOP_NAME_ARITY(op, i_jump_on_val_zero, 3);
} else {
- op->op = genop_i_jump_on_val_4;
- fixed_args = 4;
+ GENOP_NAME_ARITY(op, i_jump_on_val, 4);
}
+ fixed_args = op->arity;
arity = fixed_args + size;
GENOP_ARITY(op, arity);
op->a[0] = S;
@@ -4143,7 +4148,7 @@ gen_select_val(LoaderState* stp, GenOpArg S, GenOpArg Fail,
NEW_GENOP(stp, op);
op->next = NULL;
- op->op = genop_i_select_val2_4;
+ GENOP_NAME_ARITY(op, i_select_val2, 4);
GENOP_ARITY(op, arity - 1);
op->a[0] = S;
op->a[1] = Fail;
@@ -4165,7 +4170,11 @@ gen_select_val(LoaderState* stp, GenOpArg S, GenOpArg Fail,
NEW_GENOP(stp, op);
op->next = NULL;
- op->op = (align == 0) ? genop_i_select_val_bins_3 : genop_i_select_val_lins_3;
+ if (align == 0) {
+ GENOP_NAME_ARITY(op, i_select_val_bins, 3);
+ } else {
+ GENOP_NAME_ARITY(op, i_select_val_lins, 3);
+ }
GENOP_ARITY(op, arity);
op->a[0] = S;
op->a[1] = Fail;
@@ -4229,8 +4238,7 @@ gen_select_literals(LoaderState* stp, GenOpArg S, GenOpArg Fail,
ASSERT(Rest[i].type == TAG_q);
NEW_GENOP(stp, op);
- op->op = genop_is_ne_exact_3;
- op->arity = 3;
+ GENOP_NAME_ARITY(op, is_ne_exact, 3);
op->a[0] = Rest[i+1];
op->a[1] = S;
op->a[2] = Rest[i];
@@ -4239,9 +4247,8 @@ gen_select_literals(LoaderState* stp, GenOpArg S, GenOpArg Fail,
}
NEW_GENOP(stp, jump);
+ GENOP_NAME_ARITY(jump, jump, 1);
jump->next = NULL;
- jump->op = genop_jump_1;
- jump->arity = 1;
jump->a[0] = Fail;
*prev_next = jump;
return op;
@@ -4263,9 +4270,8 @@ const_select_val(LoaderState* stp, GenOpArg S, GenOpArg Fail,
ASSERT(Size.type == TAG_u);
NEW_GENOP(stp, op);
+ GENOP_NAME_ARITY(op, jump, 1);
op->next = NULL;
- op->op = genop_jump_1;
- op->arity = 1;
/*
* Search for a literal matching the controlling expression.
@@ -4346,15 +4352,17 @@ gen_make_fun2(LoaderState* stp, GenOpArg idx)
funp->creator = erts_init_process_id;
funp->arity = arity;
- op->op = genop_move_2;
- op->arity = 2;
+ /*
+ * Use a move_fun/2 instruction to load the fun to enable
+ * further optimizations.
+ */
+ GENOP_NAME_ARITY(op, move_fun, 2);
op->a[0].type = TAG_q;
op->a[0].val = lit;
op->a[1].type = TAG_x;
op->a[1].val = 0;
} else {
- op->op = genop_i_make_fun_2;
- op->arity = 2;
+ GENOP_NAME_ARITY(op, i_make_fun, 2);
op->a[0].type = TAG_u;
op->a[0].val = (BeamInstr) fe;
op->a[1].type = TAG_u;
@@ -4382,13 +4390,11 @@ gen_is_function2(LoaderState* stp, GenOpArg Fail, GenOpArg Fun, GenOpArg Arity)
*/
if (Arity.val > MAX_ARG) {
/* Arity is negative or too big. */
- op->op = genop_jump_1;
- op->arity = 1;
+ GENOP_NAME_ARITY(op, jump, 1);
op->a[0] = Fail;
return op;
} else {
- op->op = genop_hot_is_function2_3;
- op->arity = 3;
+ GENOP_NAME_ARITY(op, hot_is_function2, 3);
op->a[0] = Fail;
op->a[1] = Fun;
op->a[2].type = TAG_u;
@@ -4408,20 +4414,17 @@ gen_is_function2(LoaderState* stp, GenOpArg Fail, GenOpArg Fun, GenOpArg Arity)
move_fun->next = move_arity;
move_arity->next = op;
- move_fun->arity = 2;
- move_fun->op = genop_move_2;
+ GENOP_NAME_ARITY(move_fun, move, 2);
move_fun->a[0] = Fun;
move_fun->a[1].type = TAG_x;
move_fun->a[1].val = 1022;
- move_arity->arity = 2;
- move_arity->op = genop_move_2;
+ GENOP_NAME_ARITY(move_arity, move, 2);
move_arity->a[0] = Arity;
move_arity->a[1].type = TAG_x;
move_arity->a[1].val = 1023;
- op->op = genop_cold_is_function2_3;
- op->arity = 3;
+ GENOP_NAME_ARITY(op, cold_is_function2, 3);
op->a[0] = Fail;
op->a[1].type = TAG_x;
op->a[1].val = 1022;
@@ -4442,8 +4445,8 @@ tuple_append_put5(LoaderState* stp, GenOpArg Arity, GenOpArg Dst,
NEW_GENOP(stp, op);
op->next = NULL;
+ GENOP_NAME_ARITY(op, i_put_tuple, 2);
GENOP_ARITY(op, arity+2+5);
- op->op = genop_i_put_tuple_2;
op->a[0] = Dst;
op->a[1].type = TAG_u;
op->a[1].val = arity + 5;
@@ -4468,8 +4471,8 @@ tuple_append_put(LoaderState* stp, GenOpArg Arity, GenOpArg Dst,
NEW_GENOP(stp, op);
op->next = NULL;
+ GENOP_NAME_ARITY(op, i_put_tuple, 2);
GENOP_ARITY(op, arity+2+1);
- op->op = genop_i_put_tuple_2;
op->a[0] = Dst;
op->a[1].type = TAG_u;
op->a[1].val = arity + 1;
@@ -4537,9 +4540,9 @@ gen_new_small_map_lit(LoaderState* stp, GenOpArg Dst, GenOpArg Live,
Eterm keys;
NEW_GENOP(stp, op);
+ GENOP_NAME_ARITY(op, i_new_small_map_lit, 3);
GENOP_ARITY(op, 3 + size/2);
op->next = NULL;
- op->op = genop_i_new_small_map_lit_3;
tmp = thp = erts_alloc(ERTS_ALC_T_LOADER_TMP, (1 + size/2) * sizeof(*tmp));
keys = make_tuple(thp);
@@ -4720,14 +4723,12 @@ gen_get_map_element(LoaderState* stp, GenOpArg Fail, GenOpArg Src,
Key = Rest[0];
if (hash_genop_arg(stp, Key, &hx)) {
- op->arity = 5;
- op->op = genop_i_get_map_element_hash_5;
+ GENOP_NAME_ARITY(op, i_get_map_element_hash, 5);
op->a[3].type = TAG_u;
op->a[3].val = (BeamInstr) hx;
op->a[4] = Rest[1];
} else {
- op->arity = 4;
- op->op = genop_i_get_map_element_4;
+ GENOP_NAME_ARITY(op, i_get_map_element, 4);
op->a[3] = Rest[1];
}
return op;
@@ -4767,15 +4768,13 @@ gen_get(LoaderState* stp, GenOpArg Src, GenOpArg Dst)
NEW_GENOP(stp, op);
op->next = NULL;
if (hash_internal_genop_arg(stp, Src, &hx)) {
- op->arity = 3;
- op->op = genop_i_get_hash_3;
+ GENOP_NAME_ARITY(op, i_get_hash, 3);
op->a[0] = Src;
op->a[1].type = TAG_u;
op->a[1].val = (BeamInstr) hx;
op->a[2] = Dst;
} else {
- op->arity = 2;
- op->op = genop_i_get_2;
+ GENOP_NAME_ARITY(op, i_get, 2);
op->a[0] = Src;
op->a[1] = Dst;
}
@@ -4799,7 +4798,7 @@ gen_get_map_elements(LoaderState* stp, GenOpArg Fail, GenOpArg Src,
ASSERT(Size.type == TAG_u);
NEW_GENOP(stp, op);
- op->op = genop_i_get_map_elements_3;
+ GENOP_NAME_ARITY(op, i_get_map_elements, 3);
GENOP_ARITY(op, 3 + 3*(Size.val/2));
op->next = NULL;
op->a[0] = Fail;
@@ -4837,9 +4836,9 @@ gen_has_map_fields(LoaderState* stp, GenOpArg Fail, GenOpArg Src,
n = Size.val;
NEW_GENOP(stp, op);
+ GENOP_NAME_ARITY(op, get_map_elements, 3);
GENOP_ARITY(op, 3 + 2*n);
op->next = NULL;
- op->op = genop_get_map_elements_3;
op->a[0] = Fail;
op->a[1] = Src;
diff --git a/erts/emulator/beam/bif.tab b/erts/emulator/beam/bif.tab
index 11941db8cd..34a0be4f2d 100644
--- a/erts/emulator/beam/bif.tab
+++ b/erts/emulator/beam/bif.tab
@@ -160,6 +160,8 @@ bif erlang:dist_ctrl_input_handler/2
bif erlang:dist_ctrl_put_data/2
bif erlang:dist_ctrl_get_data/1
bif erlang:dist_ctrl_get_data_notification/1
+bif erlang:dist_ctrl_get_opt/2
+bif erlang:dist_ctrl_set_opt/3
# Static native functions in erts_internal
bif erts_internal:port_info/1
diff --git a/erts/emulator/beam/dist.c b/erts/emulator/beam/dist.c
index b50c8273b1..ff5f766de7 100644
--- a/erts/emulator/beam/dist.c
+++ b/erts/emulator/beam/dist.c
@@ -3253,6 +3253,86 @@ dist_ctrl_put_data_2(BIF_ALIST_2)
}
BIF_RETTYPE
+dist_ctrl_set_opt_3(BIF_ALIST_3)
+{
+ DistEntry *dep = ERTS_PROC_GET_DIST_ENTRY(BIF_P);
+ Uint32 conn_id;
+ BIF_RETTYPE ret;
+
+ if (!dep)
+ BIF_ERROR(BIF_P, EXC_NOTSUP);
+
+ if (erts_dhandle_to_dist_entry(BIF_ARG_1, &conn_id) != dep)
+ BIF_ERROR(BIF_P, BADARG);
+
+ erts_de_rlock(dep);
+
+ if (dep->connection_id != conn_id)
+ ERTS_BIF_PREP_ERROR(ret, BIF_P, BADARG);
+ else {
+
+ switch (BIF_ARG_2) {
+ case am_get_size:
+ ERTS_BIF_PREP_RET(ret, (dep->opts & ERTS_DIST_CTRL_OPT_GET_SIZE
+ ? am_true
+ : am_false));
+ if (BIF_ARG_3 == am_true)
+ dep->opts |= ERTS_DIST_CTRL_OPT_GET_SIZE;
+ else if (BIF_ARG_3 == am_false)
+ dep->opts &= ~ERTS_DIST_CTRL_OPT_GET_SIZE;
+ else
+ ERTS_BIF_PREP_ERROR(ret, BIF_P, BADARG);
+ break;
+ default:
+ ERTS_BIF_PREP_ERROR(ret, BIF_P, BADARG);
+ break;
+ }
+
+ }
+
+ erts_de_runlock(dep);
+
+ return ret;
+}
+
+BIF_RETTYPE
+dist_ctrl_get_opt_2(BIF_ALIST_2)
+{
+ DistEntry *dep = ERTS_PROC_GET_DIST_ENTRY(BIF_P);
+ Uint32 conn_id;
+ BIF_RETTYPE ret;
+
+ if (!dep)
+ BIF_ERROR(BIF_P, EXC_NOTSUP);
+
+ if (erts_dhandle_to_dist_entry(BIF_ARG_1, &conn_id) != dep)
+ BIF_ERROR(BIF_P, BADARG);
+
+ erts_de_rlock(dep);
+
+ if (dep->connection_id != conn_id)
+ ERTS_BIF_PREP_ERROR(ret, BIF_P, BADARG);
+ else {
+
+ switch (BIF_ARG_2) {
+ case am_get_size:
+ ERTS_BIF_PREP_RET(ret, (dep->opts & ERTS_DIST_CTRL_OPT_GET_SIZE
+ ? am_true
+ : am_false));
+ break;
+ default:
+ ERTS_BIF_PREP_ERROR(ret, BIF_P, BADARG);
+ break;
+ }
+
+ }
+
+ erts_de_runlock(dep);
+
+ return ret;
+}
+
+BIF_RETTYPE
dist_get_stat_1(BIF_ALIST_1)
{
Sint64 read, write, pend;
@@ -3332,7 +3412,9 @@ dist_ctrl_get_data_1(BIF_ALIST_1)
Eterm *hp;
ProcBin *pb;
erts_aint_t qsize;
- Uint32 conn_id;
+ Uint32 conn_id, get_size;
+ Eterm res;
+ Uint hsz, bin_sz;
if (!dep)
BIF_ERROR(BIF_P, EXC_NOTSUP);
@@ -3400,15 +3482,26 @@ dist_ctrl_get_data_1(BIF_ALIST_1)
erts_de_runlock(dep);
- hp = HAlloc(BIF_P, PROC_BIN_SIZE);
+ bin_sz = obuf->ext_endp - obuf->extp;
+ hsz = PROC_BIN_SIZE;
+
+ get_size = dep->opts & ERTS_DIST_CTRL_OPT_GET_SIZE;
+ if (get_size) {
+ hsz += 3; /* 2 tuple */
+ if (!IS_USMALL(0, bin_sz))
+ hsz += BIG_UINT_HEAP_SIZE;
+ }
+
+ hp = HAlloc(BIF_P, hsz);
pb = (ProcBin *) (char *) hp;
pb->thing_word = HEADER_PROC_BIN;
- pb->size = obuf->ext_endp - obuf->extp;
+ pb->size = bin_sz;
pb->next = MSO(BIF_P).first;
MSO(BIF_P).first = (struct erl_off_heap_header*) pb;
pb->val = ErtsDistOutputBuf2Binary(obuf);
pb->bytes = (byte*) obuf->extp;
pb->flags = 0;
+ hp += PROC_BIN_SIZE;
qsize = erts_atomic_add_read_nob(&dep->qsize, -size_obuf(obuf));
ASSERT(qsize >= 0);
@@ -3425,7 +3518,20 @@ dist_ctrl_get_data_1(BIF_ALIST_1)
}
}
- BIF_RET2(make_binary(pb), (initial_reds - reds));
+ res = make_binary(pb);
+
+ if (get_size) {
+ Eterm sz_term;
+ if (IS_USMALL(0, bin_sz))
+ sz_term = make_small(bin_sz);
+ else {
+ sz_term = uint_to_big(bin_sz, hp);
+ hp += BIG_UINT_HEAP_SIZE;
+ }
+ res = TUPLE2(hp, sz_term, res);
+ }
+
+ BIF_RET2(res, (initial_reds - reds));
}
void
diff --git a/erts/emulator/beam/dist.h b/erts/emulator/beam/dist.h
index c4bb967592..5bd22cc31f 100644
--- a/erts/emulator/beam/dist.h
+++ b/erts/emulator/beam/dist.h
@@ -172,6 +172,9 @@ extern int erts_is_alive;
/* Pending connection; signals can be enqueued */
#define ERTS_DSIG_PREP_PENDING 4
+/* dist_ctrl_{g,s}et_option/2 */
+#define ERTS_DIST_CTRL_OPT_GET_SIZE ((Uint32) (1 << 0))
+
#ifdef DEBUG
#define ERTS_DBG_CHK_NO_DIST_LNK(D, R, L) \
erts_dbg_chk_no_dist_proc_link((D), (R), (L))
diff --git a/erts/emulator/beam/erl_bif_info.c b/erts/emulator/beam/erl_bif_info.c
index 8c51bdb630..de64f09a02 100644
--- a/erts/emulator/beam/erl_bif_info.c
+++ b/erts/emulator/beam/erl_bif_info.c
@@ -4603,18 +4603,17 @@ BIF_RETTYPE erts_debug_set_internal_state_2(BIF_ALIST_2)
}
}
else if (ERTS_IS_ATOM_STR("wait", BIF_ARG_1)) {
- if (ERTS_IS_ATOM_STR("deallocations", BIF_ARG_2)) {
- int flag = ERTS_DEBUG_WAIT_COMPLETED_DEALLOCATIONS;
- if (erts_debug_wait_completed(BIF_P, flag)) {
- ERTS_BIF_YIELD_RETURN(BIF_P, am_ok);
- }
- }
- if (ERTS_IS_ATOM_STR("timer_cancellations", BIF_ARG_2)) {
- int flag = ERTS_DEBUG_WAIT_COMPLETED_TIMER_CANCELLATIONS;
- if (erts_debug_wait_completed(BIF_P, flag)) {
- ERTS_BIF_YIELD_RETURN(BIF_P, am_ok);
- }
- }
+ int flag = 0;
+ if (ERTS_IS_ATOM_STR("deallocations", BIF_ARG_2))
+ flag = ERTS_DEBUG_WAIT_COMPLETED_DEALLOCATIONS;
+ else if (ERTS_IS_ATOM_STR("timer_cancellations", BIF_ARG_2))
+ flag = ERTS_DEBUG_WAIT_COMPLETED_TIMER_CANCELLATIONS;
+ else if (ERTS_IS_ATOM_STR("aux_work", BIF_ARG_2))
+ flag = ERTS_DEBUG_WAIT_COMPLETED_AUX_WORK;
+
+ if (flag && erts_debug_wait_completed(BIF_P, flag)) {
+ ERTS_BIF_YIELD_RETURN(BIF_P, am_ok);
+ }
}
else if (ERTS_IS_ATOM_STR("broken_halt", BIF_ARG_1)) {
erts_proc_unlock(BIF_P, ERTS_PROC_LOCK_MAIN);
diff --git a/erts/emulator/beam/erl_binary.h b/erts/emulator/beam/erl_binary.h
index 4bf77988f7..c9c047255a 100644
--- a/erts/emulator/beam/erl_binary.h
+++ b/erts/emulator/beam/erl_binary.h
@@ -314,6 +314,7 @@ ERTS_GLB_INLINE Binary *erts_bin_drv_alloc(Uint size);
ERTS_GLB_INLINE Binary *erts_bin_nrml_alloc(Uint size);
ERTS_GLB_INLINE Binary *erts_bin_realloc_fnf(Binary *bp, Uint size);
ERTS_GLB_INLINE Binary *erts_bin_realloc(Binary *bp, Uint size);
+ERTS_GLB_INLINE void erts_magic_binary_free(Binary *bp);
ERTS_GLB_INLINE void erts_bin_free(Binary *bp);
ERTS_GLB_INLINE void erts_bin_release(Binary *bp);
ERTS_GLB_INLINE Binary *erts_create_magic_binary_x(Uint size,
@@ -446,6 +447,13 @@ erts_bin_realloc(Binary *bp, Uint size)
}
ERTS_GLB_INLINE void
+erts_magic_binary_free(Binary *bp)
+{
+ erts_magic_ref_remove_bin(ERTS_MAGIC_BIN_REFN(bp));
+ erts_free(ERTS_MAGIC_BIN_ATYPE(bp), (void *) bp);
+}
+
+ERTS_GLB_INLINE void
erts_bin_free(Binary *bp)
{
if (bp->intern.flags & BIN_FLAG_MAGIC) {
@@ -453,8 +461,7 @@ erts_bin_free(Binary *bp)
/* Destructor took control of the deallocation */
return;
}
- erts_magic_ref_remove_bin(ERTS_MAGIC_BIN_REFN(bp));
- erts_free(ERTS_MAGIC_BIN_ATYPE(bp), (void *) bp);
+ erts_magic_binary_free(bp);
}
else if (bp->intern.flags & BIN_FLAG_DRV)
erts_free(ERTS_ALC_T_DRV_BINARY, (void *) bp);
diff --git a/erts/emulator/beam/erl_nif.c b/erts/emulator/beam/erl_nif.c
index af1acbfc90..deaf35c2a1 100644
--- a/erts/emulator/beam/erl_nif.c
+++ b/erts/emulator/beam/erl_nif.c
@@ -1024,7 +1024,7 @@ static Eterm call_whereis(ErlNifEnv *env, Eterm name)
int scheduler;
execution_state(env, &c_p, &scheduler);
- ASSERT((c_p && scheduler) || (!c_p && !scheduler));
+ ASSERT(scheduler || !c_p);
if (scheduler < 0) {
/* dirty scheduler */
@@ -2442,10 +2442,26 @@ int erts_dbg_is_resource_dying(ErtsResource* resource)
}
#endif
-# define NIF_RESOURCE_DTOR &nif_resource_dtor
+#define NIF_RESOURCE_DTOR &nif_resource_dtor_prologue
-static int nif_resource_dtor(Binary* bin)
+static void run_resource_dtor(void* vbin);
+
+static int nif_resource_dtor_prologue(Binary* bin)
{
+ /*
+ * Schedule user resource destructor as aux work to get a context
+ * where we know what locks we have for example.
+ */
+ Uint sched_id = erts_get_scheduler_id();
+ if (!sched_id)
+ sched_id = 1;
+ erts_schedule_misc_aux_work(sched_id, run_resource_dtor, bin);
+ return 0; /* don't free */
+}
+
+static void run_resource_dtor(void* vbin)
+{
+ Binary* bin = (Binary*) vbin;
ErtsResource* resource = (ErtsResource*) ERTS_MAGIC_BIN_UNALIGNED_DATA(bin);
ErlNifResourceType* type = resource->type;
ASSERT(ERTS_MAGIC_BIN_DESTRUCTOR(bin) == NIF_RESOURCE_DTOR);
@@ -2477,11 +2493,11 @@ static int nif_resource_dtor(Binary* bin)
* If resource->monitors->refc != 0 there are
* outstanding references to the resource from
* monitors that has not been removed yet.
- * nif_resource_dtor() will be called again this
+ * nif_resource_dtor_prologue() will be called again when this
* reference count reach zero.
*/
if (refc != 0)
- return 0; /* we'll be back... */
+ return; /* we'll be back... */
erts_mtx_destroy(&rm->lock);
}
@@ -2498,7 +2514,7 @@ static int nif_resource_dtor(Binary* bin)
steal_resource_type(type);
erts_free(ERTS_ALC_T_NIF, type);
}
- return 1;
+ erts_magic_binary_free((Binary*)vbin);
}
void erts_resource_stop(ErtsResource* resource, ErlNifEvent e,
diff --git a/erts/emulator/beam/erl_node_tables.c b/erts/emulator/beam/erl_node_tables.c
index afafaf48dc..1adb101e30 100644
--- a/erts/emulator/beam/erl_node_tables.c
+++ b/erts/emulator/beam/erl_node_tables.c
@@ -177,6 +177,7 @@ dist_table_alloc(void *dep_tmpl)
dep->connection_id = 0;
dep->state = ERTS_DE_STATE_IDLE;
dep->flags = 0;
+ dep->opts = 0;
dep->version = 0;
dep->mld = NULL;
@@ -659,6 +660,7 @@ erts_set_dist_entry_not_connected(DistEntry *dep)
dep->state = ERTS_DE_STATE_IDLE;
dep->flags = 0;
+ dep->opts = 0;
dep->prev = NULL;
dep->cid = NIL;
diff --git a/erts/emulator/beam/erl_node_tables.h b/erts/emulator/beam/erl_node_tables.h
index d5daf0c2df..8153699596 100644
--- a/erts/emulator/beam/erl_node_tables.h
+++ b/erts/emulator/beam/erl_node_tables.h
@@ -148,6 +148,7 @@ struct dist_entry_ {
enum dist_entry_state state;
Uint32 flags; /* Distribution flags, like hidden,
atom cache etc. */
+ Uint32 opts;
unsigned long version; /* Protocol version */
ErtsMonLnkDist *mld; /* Monitors and links */
diff --git a/erts/emulator/beam/erl_proc_sig_queue.c b/erts/emulator/beam/erl_proc_sig_queue.c
index 9c74a2c355..bd59c4afa3 100644
--- a/erts/emulator/beam/erl_proc_sig_queue.c
+++ b/erts/emulator/beam/erl_proc_sig_queue.c
@@ -3429,9 +3429,15 @@ erts_proc_sig_handle_incoming(Process *c_p, erts_aint32_t *statep,
erts_nif_demonitored((ErtsResource *) tmon->other.ptr);
cnt++;
break;
- case ERTS_MON_TYPE_SUSPEND:
- erts_resume(c_p, ERTS_PROC_LOCK_MAIN);
+ case ERTS_MON_TYPE_SUSPEND: {
+ ErtsMonitorSuspend *msp;
+ erts_aint_t mstate;
+ msp = (ErtsMonitorSuspend *) erts_monitor_to_data(tmon);
+ mstate = erts_atomic_read_acqb(&msp->state);
+ if (mstate & ERTS_MSUSPEND_STATE_FLG_ACTIVE)
+ erts_resume(c_p, ERTS_PROC_LOCK_MAIN);
break;
+ }
default:
break;
}
diff --git a/erts/emulator/beam/erl_process.c b/erts/emulator/beam/erl_process.c
index 0a099e69bb..f34289339f 100644
--- a/erts/emulator/beam/erl_process.c
+++ b/erts/emulator/beam/erl_process.c
@@ -2375,9 +2375,12 @@ struct debug_lop {
static void later_thr_debug_wait_completed(void *vlop)
{
struct debug_lop *lop = vlop;
- erts_aint32_t count = (erts_aint32_t) erts_no_schedulers;
- count += 1; /* aux thread */
- if (erts_atomic32_dec_read_mb(&debug_wait_completed_count) == count) {
+
+ if (erts_atomic32_dec_read_mb(&debug_wait_completed_count) == 1) {
+ erts_aint32_t count = (erts_aint32_t) erts_no_schedulers;
+ count += 1; /* aux thread */
+ erts_atomic32_set_nob(&debug_wait_completed_count, count);
+
/* scheduler threads */
erts_schedule_multi_misc_aux_work(0,
erts_no_schedulers,
@@ -2395,19 +2398,28 @@ static void later_thr_debug_wait_completed(void *vlop)
static void
init_thr_debug_wait_completed(void *vproc)
{
- struct debug_lop* lop = erts_alloc(ERTS_ALC_T_DEBUG,
- sizeof(struct debug_lop));
- lop->proc = vproc;
- erts_schedule_thr_prgr_later_op(later_thr_debug_wait_completed, lop, &lop->lop);
+ if (debug_wait_completed_flags == ERTS_DEBUG_WAIT_COMPLETED_AUX_WORK) {
+ if (erts_atomic32_dec_read_mb(&debug_wait_completed_count) == 1) {
+ erts_atomic32_set_nob(&debug_wait_completed_count, 0);
+ erts_resume((Process *) vproc, (ErtsProcLocks) 0);
+ erts_proc_dec_refc((Process *) vproc);
+ }
+ }
+ else {
+ struct debug_lop* lop = erts_alloc(ERTS_ALC_T_DEBUG,
+ sizeof(struct debug_lop));
+ lop->proc = vproc;
+ erts_schedule_thr_prgr_later_op(later_thr_debug_wait_completed, lop, &lop->lop);
+ }
}
int
erts_debug_wait_completed(Process *c_p, int flags)
{
- /* Only one process at a time can do this */
- erts_aint32_t count = (erts_aint32_t) (2*erts_no_schedulers);
- count += 1; /* aux thread */
+ /* Only one process at a time can do this, +1 to mark as busy */
+ erts_aint32_t count = (erts_aint32_t) (erts_no_schedulers + 1);
+
if (0 == erts_atomic32_cmpxchg_mb(&debug_wait_completed_count,
count,
0)) {
@@ -9460,6 +9472,7 @@ Process *erts_schedule(ErtsSchedulerData *esdp, Process *p, int calls)
if (!is_normal_sched & !!(flags & ERTS_RUNQ_FLG_HALTING)) {
/* Wait for emulator to terminate... */
+ erts_runq_unlock(rq);
while (1)
erts_milli_sleep(1000*1000);
}
@@ -13403,10 +13416,10 @@ void erts_halt(int code)
if (-1 == erts_atomic32_cmpxchg_acqb(&erts_halt_progress,
erts_no_schedulers,
-1)) {
+ notify_reap_ports_relb();
ERTS_RUNQ_FLGS_SET(ERTS_DIRTY_CPU_RUNQ, ERTS_RUNQ_FLG_HALTING);
ERTS_RUNQ_FLGS_SET(ERTS_DIRTY_IO_RUNQ, ERTS_RUNQ_FLG_HALTING);
erts_halt_code = code;
- notify_reap_ports_relb();
}
}
diff --git a/erts/emulator/beam/erl_process.h b/erts/emulator/beam/erl_process.h
index 3b593bce02..4ffa022d5c 100644
--- a/erts/emulator/beam/erl_process.h
+++ b/erts/emulator/beam/erl_process.h
@@ -1856,6 +1856,7 @@ Uint erts_debug_nbalance(void);
#define ERTS_DEBUG_WAIT_COMPLETED_DEALLOCATIONS (1 << 0)
#define ERTS_DEBUG_WAIT_COMPLETED_TIMER_CANCELLATIONS (1 << 1)
+#define ERTS_DEBUG_WAIT_COMPLETED_AUX_WORK (1 << 2)
int erts_debug_wait_completed(Process *c_p, int flags);
diff --git a/erts/emulator/beam/instrs.tab b/erts/emulator/beam/instrs.tab
index 1eb83b61f2..692408e212 100644
--- a/erts/emulator/beam/instrs.tab
+++ b/erts/emulator/beam/instrs.tab
@@ -477,6 +477,13 @@ i_make_fun(FunP, NumFree) {
HEAVY_SWAPIN;
}
+move_trim(Src, Dst, Words) {
+ Uint cp = E[0];
+ $Dst = $Src;
+ E += $Words;
+ E[0] = cp;
+}
+
i_trim(Words) {
Uint cp = E[0];
E += $Words;
@@ -493,10 +500,6 @@ move3(S1, D1, S2, D2, S3, D3) {
$D3 = $S3;
}
-move_dup(Src, D1, D2) {
- $D1 = $D2 = $Src;
-}
-
move2_par(S1, D1, S2, D2) {
Eterm V1, V2;
V1 = $S1;
@@ -512,6 +515,39 @@ move_shift(Src, SD, D) {
$SD = V;
}
+move_src_window2(Src, D1, D2) {
+ Eterm* src = &$Src;
+ Eterm s1, s2;
+ s1 = src[0];
+ s2 = src[1];
+ $D1 = s1;
+ $D2 = s2;
+}
+
+move_src_window3(Src, D1, D2, D3) {
+ Eterm* src = &$Src;
+ Eterm s1, s2, s3;
+ s1 = src[0];
+ s2 = src[1];
+ s3 = src[2];
+ $D1 = s1;
+ $D2 = s2;
+ $D3 = s3;
+}
+
+move_src_window4(Src, D1, D2, D3, D4) {
+ Eterm* src = &$Src;
+ Eterm s1, s2, s3, s4;
+ s1 = src[0];
+ s2 = src[1];
+ s3 = src[2];
+ s4 = src[3];
+ $D1 = s1;
+ $D2 = s2;
+ $D3 = s3;
+ $D4 = s4;
+}
+
move_window2(S1, S2, D) {
Eterm xt0, xt1;
Eterm* y = &$D;
@@ -703,9 +739,11 @@ jump(Fail) {
$JUMP($Fail);
}
-move_jump(Fail, Src) {
- x(0) = $Src;
- $jump($Fail);
+move_jump(Lbl, Src, Dst) {
+ Eterm lbl = $Lbl;
+ Eterm src = $Src;
+ $Dst = src;
+ $JUMP(lbl);
}
//
@@ -817,6 +855,16 @@ is_tagged_tuple(Fail, Src, Arityval, Tag) {
}
}
+is_tagged_tuple_ff(NotTupleFail, WrongRecordFail, Src, Arityval, Tag) {
+ Eterm term = $Src;
+ if (is_not_tuple(term)) {
+ $FAIL($NotTupleFail);
+ } else if (ERTS_UNLIKELY((tuple_val(term))[0] != $Arityval ||
+ (tuple_val(term))[1] != $Tag)) {
+ $FAIL($WrongRecordFail);
+ }
+}
+
is_tuple(Fail, Src) {
if (is_not_tuple($Src)) {
$FAIL($Fail);
diff --git a/erts/emulator/beam/map_instrs.tab b/erts/emulator/beam/map_instrs.tab
index c594a87298..5620d5a2d1 100644
--- a/erts/emulator/beam/map_instrs.tab
+++ b/erts/emulator/beam/map_instrs.tab
@@ -127,11 +127,21 @@ i_get_map_elements(Fail, Src, N) {
}
}
-update_map_assoc(Src, Dst, Live, N) {
+update_map_assoc := update_map_assoc.fetch.execute;
+
+update_map_assoc.head() {
+ Eterm map;
+}
+
+update_map_assoc.fetch(Src) {
+ map = $Src;
+}
+
+update_map_assoc.execute(Dst, Live, N) {
Eterm res;
Uint live = $Live;
- reg[live] = $Src;
+ reg[live] = map;
HEAVY_SWAPOUT;
res = erts_gc_update_map_assoc(c_p, reg, live, $N, $NEXT_INSTRUCTION);
HEAVY_SWAPIN;
@@ -141,11 +151,21 @@ update_map_assoc(Src, Dst, Live, N) {
$NEXT($NEXT_INSTRUCTION+$N);
}
-update_map_exact(Fail, Src, Dst, Live, N) {
+update_map_exact := update_map_exact.fetch.execute;
+
+update_map_exact.head() {
+ Eterm map;
+}
+
+update_map_exact.fetch(Src) {
+ map = $Src;
+}
+
+update_map_exact.execute(Fail, Dst, Live, N) {
Eterm res;
Uint live = $Live;
- reg[live] = $Src;
+ reg[live] = map;
HEAVY_SWAPOUT;
res = erts_gc_update_map_exact(c_p, reg, live, $N, $NEXT_INSTRUCTION);
HEAVY_SWAPIN;
diff --git a/erts/emulator/beam/ops.tab b/erts/emulator/beam/ops.tab
index da5364183c..6832e65b1b 100644
--- a/erts/emulator/beam/ops.tab
+++ b/erts/emulator/beam/ops.tab
@@ -106,7 +106,10 @@ init y
allocate_zero t t?
allocate_heap_zero t I t?
+move Src=y Dst=x | trim N Remaining => move_trim Src Dst N
trim N Remaining => i_trim N
+
+move_trim y x t
i_trim t
test_heap I t?
@@ -261,12 +264,14 @@ system_limit j
# Move instructions.
#
-move C=cxy x==0 | jump Lbl => move_jump Lbl C
+move Src=cxy Dst=xy | jump Lbl => move_jump Lbl Src Dst
+
+move_jump f cxy xy
+move_jump f c r
-move_jump f ncxy
-# Movement to and from the stack is common
-# Try to pack as much as we can into one instruction
+# Movement to and from the stack is common.
+# Try to pack as much as we can into one instruction.
# Window move
move_window/5
@@ -294,11 +299,49 @@ move_window3 x x x y
move_window4 x x x x y
move_window5 x x x x x y
+# y -> x
+
+move_src_window/4
+move_src_window/5
+
+move Y1=y X1=x | move Y2=y X2=x | succ(Y1, Y2) => \
+ move_src_window Y1 Y2 X1 X2
+
+move_src_window Y1 Y2 X1 X2 | move Y3=y X3=x | succ(Y2, Y3) => \
+ move_src_window Y1 Y3 X1 X2 X3
+move_src_window Y1 Y2 X1 X2 | move Y3=y X3=x | move Y4=y X4=x | succ(Y3, Y4) => \
+ move_src_window2 Y1 X1 X2 | move_src_window Y3 Y4 X3 X4
+move_src_window Y1 Y2 X1 X2 | move Y3=y X3=x => \
+ move3 Y1 X1 Y2 X2 Y3 X3
+
+move_src_window Y1 Y3 X1 X2 X3 | move Y4=y X4=x | succ(Y3, Y4) => \
+ move_src_window4 Y1 X1 X2 X3 X4
+
+move_src_window Y1 y X1 X2 => move_src_window2 Y1 X1 X2
+move_src_window Y1 y X1 X2 X3 => move_src_window3 Y1 X1 X2 X3
+
+move_src_window2 y x x
+move_src_window3 y x x x
+move_src_window4 y x x x x
+
# Swap registers.
-move R1=x Tmp=x | move R2=x R1 | move Tmp R2 => swap_temp R1 R2 Tmp
+move R1=xy Tmp=x | move R2=xy R1 | move Tmp R2 => swap_temp R1 R2 Tmp
+
+# The compiler uses x(1022) when swapping registers. It will definitely
+# not be used again.
+swap_temp R1 R2 Tmp=x==1022 => swap R1 R2
+
+swap_temp R1 R2 Tmp | move Src Tmp => swap R1 R2 | move Src Tmp
swap_temp R1 R2 Tmp | line Loc | apply Live | is_killed_apply(Tmp, Live) => \
swap R1 R2 | line Loc | apply Live
+swap_temp R1 R2 Tmp | line Loc | apply_last Live D | is_killed_apply(Tmp, Live) => \
+ swap R1 R2 | line Loc | apply_last Live D
+
+swap_temp R1 R2 Tmp | line Loc | call_fun Live | is_killed(Tmp, Live) => \
+ swap R1 R2 | line Loc | call_fun Live
+swap_temp R1 R2 Tmp | make_fun2 OldIndex=u | is_killed_by_make_fun(Tmp, OldIndex) => \
+ swap R1 R2 | make_fun2 OldIndex
swap_temp R1 R2 Tmp | line Loc | call Live Addr | is_killed(Tmp, Live) => \
swap R1 R2 | line Loc | call Live Addr
@@ -314,27 +357,55 @@ swap_temp R1 R2 Tmp | line Loc | call_ext_only Live Addr | \
swap_temp R1 R2 Tmp | line Loc | call_ext_last Live Addr D | \
is_killed(Tmp, Live) => swap R1 R2 | line Loc | call_ext_last Live Addr D
-swap_temp x x x
-
-swap x x
+swap_temp R1 R2 Tmp | call_ext Live Addr | is_killed(Tmp, Live) => \
+ swap R1 R2 | call_ext Live Addr
+swap_temp R1 R2 Tmp | call_ext_only Live Addr | is_killed(Tmp, Live) => \
+ swap R1 R2 | call_ext_only Live Addr
+swap_temp R1 R2 Tmp | call_ext_last Live Addr D | is_killed(Tmp, Live) => \
+ swap R1 R2 | call_ext_last Live Addr D
+
+swap_temp R1 R2 Tmp | move Src Any | line Loc | call Live Addr | \
+ is_killed(Tmp, Live) | distinct(Tmp, Src) => \
+ swap R1 R2 | move Src Any | line Loc | call Live Addr
+swap_temp R1 R2 Tmp | move Src Any | line Loc | call_ext Live Addr | \
+ is_killed(Tmp, Live) | distinct(Tmp, Src) => \
+ swap R1 R2 | move Src Any | line Loc | call_ext Live Addr
+swap_temp R1 R2 Tmp | move Src Any | call_only Live Addr | \
+ is_killed(Tmp, Live) | distinct(Tmp, Src) => \
+ swap R1 R2 | move Src Any | call_only Live Addr
+swap_temp R1 R2 Tmp | move Src Any | line Loc | call_ext_only Live Addr | \
+ is_killed(Tmp, Live) | distinct(Tmp, Src) => \
+ swap R1 R2 | move Src Any | line Loc | call_ext_only Live Addr
+swap_temp R1 R2 Tmp | move Src Any | line Loc | call_fun Live | \
+ is_killed(Tmp, Live) | distinct(Tmp, Src) => \
+ swap R1 R2 | move Src Any | line Loc | call_fun Live
+
+swap_temp R1 R2 Tmp | line Loc | send | is_killed_by_send(Tmp) => \
+ swap R1 R2 | line Loc | send
+
+# swap_temp/3 with Y register operands are rare.
+swap_temp R1 R2=y Tmp => swap R1 R2 | move R2 Tmp
+swap_temp R1=y R2 Tmp => swap R1 R2 | move R2 Tmp
+
+swap R1=x R2=y => swap R2 R1
-# move_dup
-
-move Src=x D1=x | move Src=x D2=x => move_dup Src D1 D2
-move Src=x SD=x | move SD=x D=x => move_dup Src SD D
+swap_temp x x x
-move_dup x x x
+swap xy x
+swap y y
# move_shift
-move SD=x D=x | move Src=xy SD=x | distinct(D, Src) => move_shift Src SD D
-move SD=y D=x | move Src=x SD=y | distinct(D, Src) => move_shift Src SD D
-move SD=x D=y | move Src=x SD=x | distinct(D, Src) => move_shift Src SD D
+move SD=x D=x | move Src=cxy SD=x | distinct(D, Src) => move_shift Src SD D
+move SD=y D=x | move Src=x SD=y | distinct(D, Src) => move_shift Src SD D
+move SD=y D=x | init SD | => move_shift n SD D
+move SD=x D=y | move Src=x SD=x | distinct(D, Src) => move_shift Src SD D
+move SD=x==0 D=y | move Src=y SD=x==0 | distinct(D, Src) => move_shift Src SD D
-move_shift x x x
-move_shift y x x
-move_shift x y x
+move_shift cxy x x
+move_shift nx y x
move_shift x x y
+move_shift y r y
# move2_par x x x x
@@ -530,32 +601,26 @@ put_list Src Dst=x Dst => update_list Src Dst
update_list xyc x
-put_list x n x
-put_list y n x
-put_list x x x
-put_list y x x
+# put_list SrcReg1 SrcReg2 => Dst
-put_list y y x
-put_list x y x
+put_list xy xy x
-# put_list SrcReg Constant Dst
+# put_list SrcReg [] => Dst
-put_list x c x
-put_list x c y
+put_list xy n xy
-put_list y c x
+# put_list SrcReg Constant => x
-# put_list Constant SrcReg Dst
+put_list xy c x
-put_list c x x
-put_list c y x
+# put_list Constant SrcReg => Dst
+
+put_list c xy x
# The following put_list instructions using x(0) are frequently used.
-put_list r n r
-put_list r n x
-put_list r x x
-put_list r x r
+put_list r n rx
+put_list r x rx
put_list x x r
%cold
@@ -629,6 +694,11 @@ test_arity f? xy A
test_arity_get_tuple_element f? x A P x
+is_tuple NotTupleFail Tuple=x | is_tagged_tuple WrongRecordFail Tuple Arity Atom => \
+ is_tagged_tuple_ff NotTupleFail WrongRecordFail Tuple Arity Atom
+
+is_tagged_tuple_ff f? f? rx A a
+
get_tuple_element Reg=x P1 D1=x | get_tuple_element Reg=x P2 D2=x | \
get_tuple_element Reg=x P3 D3=x | \
succ(P1, P2) | succ(P2, P3) | \
@@ -1103,8 +1173,25 @@ call_fun Arity => i_call_fun Arity
i_call_fun t
i_call_fun_last t Q
+
+#
+# A fun with an empty environment can be converted to a literal.
+# As a further optimization, the we try to move the fun to its
+# final destination directly.
+
make_fun2 OldIndex=u => gen_make_fun2(OldIndex)
+move_fun/2
+move_fun Fun X0 | move X0 Dst | move Src X0 => move Fun Dst | move Src X0
+move_fun Fun X0 | move A B | move X0 Dst | move Src X0 | \
+ independent_moves(Fun, X0, A, B) | distinct(Dst, A) => \
+ move Fun Dst | move A B | move Src X0
+move_fun Fun X0 | move X0 Dst | make_fun2 OldIndex | \
+ is_killed_by_make_fun(X0, OldIndex)=> \
+ move Fun Dst | make_fun2 OldIndex
+
+move_fun Fun Dst => move Fun Dst
+
%cold
i_make_fun W t
%hot
@@ -1484,23 +1571,22 @@ put_map_exact F Map Dst Live Size Rest=* | map_key_sort(Size, Rest) => \
sorted_put_map_assoc Map Dst Live Size Rest=* | is_empty_map(Map) => \
new_map Dst Live Size Rest
-sorted_put_map_assoc Src=s Dst Live Size Rest=* => \
- update_map_assoc Src Dst Live Size Rest
-sorted_put_map_assoc Src Dst Live Size Rest=* => \
- move Src x | update_map_assoc x Dst Live Size Rest
+sorted_put_map_assoc Src=xyc Dst Live Size Rest=* => \
+ update_map_assoc Src Dst Live Size Rest
-sorted_put_map_exact F Src=s Dst Live Size Rest=* => \
- update_map_exact F Src Dst Live Size Rest
-sorted_put_map_exact F Src Dst Live Size Rest=* => \
- move Src x | update_map_exact F x Dst Live Size Rest
+sorted_put_map_exact Fail Src=xy Dst Live Size Rest=* => \
+ update_map_exact Src Fail Dst Live Size Rest
+# Literal map arguments for an exact update operation are extremely rare.
+sorted_put_map_exact Fail Src Dst Live Size Rest=* => \
+ move Src x | update_map_exact x Fail Dst Live Size Rest
new_map Dst Live Size Rest=* | is_small_map_literal_keys(Size, Rest) => \
gen_new_small_map_lit(Dst, Live, Size, Rest)
new_map d t I
i_new_small_map_lit d t q
-update_map_assoc s d t I
-update_map_exact j? s d t I
+update_map_assoc xyc d t I
+update_map_exact xy j? d t I
is_map Fail Lit=q | literal_is_map(Lit) =>
is_map Fail cq => jump Fail
@@ -1562,6 +1648,11 @@ gen_minus p Live Reg=d Int=i Dst | negation_is_small(Int) => \
# Arithmetic instructions.
#
+# It is OK to swap arguments for '+' in a guard. It is also
+# OK to turn minus into plus in a guard.
+gen_plus Fail=f Live S1=c S2 Dst => i_plus S2 S1 Fail Dst
+gen_minus Fail=f Live S1 S2=i Dst => gen_plus_from_minus(Fail, Live, S1, S2, Dst)
+
gen_plus Fail Live S1 S2 Dst => i_plus S1 S2 Fail Dst
gen_minus Fail Live S1 S2 Dst => i_minus S1 S2 Fail Dst
@@ -1595,10 +1686,13 @@ gc_bif1 Fail Live u$bif:erlang:bnot/1 Src Dst=d => i_int_bnot Fail Src Dst
i_increment rxy W d
-i_plus x xy j? d
-i_plus s s j? d
+# Handle unoptimized code.
+i_plus S1=c S2=c Fail Dst => move S1 x | i_plus x S2 Fail Dst
+
+i_plus xy xyc j? d
i_minus x x j? d
+i_minus c x j? d
i_minus s s j? d
i_times j? s s d
@@ -1639,8 +1733,9 @@ bif1 Fail u$bif:erlang:trunc/1 s d => too_old_compiler
gc_bif1 Fail=j Live u$bif:erlang:length/1 Src Dst => \
i_length_setup Live Src | i_length Fail Live Dst
-i_length_setup t xyc
+i_length_setup Live Src=c => move Src x | i_length_setup Live x
+i_length_setup t xy
i_length j? t d
#
diff --git a/erts/emulator/nifs/common/socket_dbg.c b/erts/emulator/nifs/common/socket_dbg.c
index fe9135e5a0..96f75a328f 100644
--- a/erts/emulator/nifs/common/socket_dbg.c
+++ b/erts/emulator/nifs/common/socket_dbg.c
@@ -38,8 +38,10 @@
static FILE* dbgout = NULL;
+#if defined(CLOCK_REALTIME)
static int realtime(struct timespec* tsP);
static int timespec2str(char *buf, unsigned int len, struct timespec *ts);
+#endif
extern
@@ -71,41 +73,48 @@ void esock_dbg_printf( const char* prefix, const char* format, ... )
{
va_list args;
char f[512 + sizeof(format)]; // This has to suffice...
+#if defined(CLOCK_REALTIME)
char stamp[30];
struct timespec ts;
+#endif
int res;
/*
- * We should really include self in the printout, so we can se which process
- * are executing the code. But then I must change the API....
- * ....something for later.
+ * We should really include self in the printout,
+ * so we can se which process are executing the code.
+ * But then I must change the API....something for later.
*/
- if (!realtime(&ts)) {
- if (timespec2str(stamp, sizeof(stamp), &ts) != 0) {
- res = enif_snprintf(f, sizeof(f), "%s [%s] %s", prefix, TSNAME(), format);
- // res = enif_snprintf(f, sizeof(f), "%s [%s]", prefix, format);
- } else {
- res = enif_snprintf(f, sizeof(f), "%s [%s] [%s] %s", prefix, stamp, TSNAME(), format);
- // res = enif_snprintf(f, sizeof(f), "%s [%s] %s", prefix, stamp, format);
- }
-
- if (res > 0) {
+#if defined(CLOCK_REALTIME)
+ if (!realtime(&ts) &&
+ (timespec2str(stamp, sizeof(stamp), &ts) == 0)) {
+ res = enif_snprintf(f, sizeof(f), "%s [%s] [%s] %s",
+ prefix, stamp, TSNAME(), format);
+ } else {
+ res = enif_snprintf(f, sizeof(f), "%s [%s] %s",
+ prefix, TSNAME(), format);
+ }
+#else
+ res = enif_snprintf(f, sizeof(f), "%s [%s] %s",
+ prefix, TSNAME(), format);
+#endif
+
+ if (res > 0) {
va_start (args, format);
enif_vfprintf (dbgout, f, args);
va_end (args);
fflush(stdout);
- }
}
return;
}
+#if defined(CLOCK_REALTIME)
static
int realtime(struct timespec* tsP)
{
- return clock_gettime(CLOCK_REALTIME, tsP);
+ return clock_gettime(CLOCK_REALTIME, tsP);
}
@@ -136,3 +145,4 @@ int timespec2str(char *buf, unsigned int len, struct timespec *ts)
return 0;
}
+#endif
diff --git a/erts/emulator/nifs/common/socket_nif.c b/erts/emulator/nifs/common/socket_nif.c
index 052c585032..870ab63bdf 100644
--- a/erts/emulator/nifs/common/socket_nif.c
+++ b/erts/emulator/nifs/common/socket_nif.c
@@ -2410,7 +2410,8 @@ static void socket_down_reader(ErlNifEnv* env,
const ErlNifPid* pid);
static char* esock_send_close_msg(ErlNifEnv* env,
- SocketDescriptor* descP);
+ SocketDescriptor* descP,
+ ERL_NIF_TERM sockRef);
static char* esock_send_abort_msg(ErlNifEnv* env,
ERL_NIF_TERM sockRef,
ERL_NIF_TERM recvRef,
@@ -16896,15 +16897,18 @@ char* send_msg_error(ErlNifEnv* env,
*/
static
char* esock_send_close_msg(ErlNifEnv* env,
- SocketDescriptor* descP)
-{
- ERL_NIF_TERM sockRef = enif_make_resource(descP->closeEnv, descP);
- char* res = esock_send_socket_msg(env,
- sockRef,
- esock_atom_close,
- descP->closeRef,
- &descP->closerPid,
- descP->closeEnv);
+ SocketDescriptor* descP,
+ ERL_NIF_TERM sockRef)
+{
+ ERL_NIF_TERM sr = ((descP->closeEnv != NULL) ?
+ enif_make_copy(descP->closeEnv, sockRef) :
+ sockRef);
+ char* res = esock_send_socket_msg(env,
+ sr,
+ esock_atom_close,
+ descP->closeRef,
+ &descP->closerPid,
+ descP->closeEnv);
descP->closeEnv = NULL;
@@ -17754,11 +17758,12 @@ void socket_stop(ErlNifEnv* env, void* obj, int fd, int is_direct_call)
if (descP->sock != INVALID_SOCKET) {
if (descP->closeLocal) {
+
if (!is_direct_call) {
/* +++ send close message to the waiting process +++ */
- esock_send_close_msg(env, descP);
+ esock_send_close_msg(env, descP, sockRef);
DEMONP("socket_stop -> closer", env, descP, &descP->closerMon);
@@ -17768,7 +17773,11 @@ void socket_stop(ErlNifEnv* env, void* obj, int fd, int is_direct_call)
* since the message send takes care of it if scheduled.
*/
- if (descP->closeEnv != NULL) enif_free_env(descP->closeEnv);
+ if (descP->closeEnv != NULL) {
+ enif_clear_env(descP->closeEnv);
+ enif_free_env(descP->closeEnv);
+ descP->closeEnv = NULL;
+ }
}
}
diff --git a/erts/emulator/nifs/common/socket_util.c b/erts/emulator/nifs/common/socket_util.c
index b817ae7636..5e18355308 100644
--- a/erts/emulator/nifs/common/socket_util.c
+++ b/erts/emulator/nifs/common/socket_util.c
@@ -51,8 +51,12 @@
extern char* erl_errno_id(int error); /* THIS IS JUST TEMPORARY??? */
+#if defined(CLOCK_REALTIME)
static int realtime(struct timespec* tsP);
-static int timespec2str(char *buf, unsigned int len, struct timespec *ts);
+static int timespec2str(char *buf,
+ unsigned int len,
+ struct timespec *ts);
+#endif
static char* make_sockaddr_in4(ErlNifEnv* env,
ERL_NIF_TERM port,
@@ -1506,39 +1510,46 @@ void esock_warning_msg( const char* format, ... )
{
va_list args;
char f[512 + sizeof(format)]; // This has to suffice...
+#if defined(CLOCK_REALTIME)
char stamp[64]; // Just in case...
struct timespec ts;
+#endif
int res;
/*
- * We should really include self in the printout, so we can se which process
- * are executing the code. But then I must change the API....
- * ....something for later.
+ * We should really include self in the printout,
+ * so we can se which process are executing the code.
+ * But then I must change the API....something for later.
*/
// 2018-06-29 12:13:21.232089
// 29-Jun-2018::13:47:25.097097
-
- if (!realtime(&ts)) {
- if (timespec2str(stamp, sizeof(stamp), &ts) != 0) {
- res = enif_snprintf(f, sizeof(f), "=WARNING MSG==== %s", format);
- } else {
- res = enif_snprintf(f, sizeof(f),
- "=WARNING MSG==== %s ===\r\n%s" , stamp, format);
- }
- if (res > 0) {
+#if defined(CLOCK_REALTIME)
+ if (!realtime(&ts) &&
+ (timespec2str(stamp, sizeof(stamp), &ts) == 0)) {
+ res = enif_snprintf(f, sizeof(f),
+ "=WARNING MSG==== %s ===\r\n%s",
+ stamp, format);
+ } else {
+ res = enif_snprintf(f, sizeof(f), "=WARNING MSG==== %s", format);
+ }
+#else
+ res = enif_snprintf(f, sizeof(f), "=WARNING MSG==== %s", format);
+#endif
+
+ if (res > 0) {
va_start (args, format);
enif_vfprintf (stdout, f, args);
va_end (args);
fflush(stdout);
- }
}
return;
}
+#if defined(CLOCK_REALTIME)
static
int realtime(struct timespec* tsP)
{
@@ -1574,6 +1585,7 @@ int timespec2str(char *buf, unsigned int len, struct timespec *ts)
return 0;
}
+#endif
/* =================================================================== *
diff --git a/erts/emulator/test/dirty_bif_SUITE.erl b/erts/emulator/test/dirty_bif_SUITE.erl
index 46eb0cba58..4f5ad0295a 100644
--- a/erts/emulator/test/dirty_bif_SUITE.erl
+++ b/erts/emulator/test/dirty_bif_SUITE.erl
@@ -38,7 +38,8 @@
dirty_process_info/1,
dirty_process_register/1,
dirty_process_trace/1,
- code_purge/1]).
+ code_purge/1,
+ otp_15688/1]).
suite() -> [{ct_hooks,[ts_install_cth]}].
@@ -64,7 +65,8 @@ all() ->
dirty_process_info,
dirty_process_register,
dirty_process_trace,
- code_purge].
+ code_purge,
+ otp_15688].
init_per_suite(Config) ->
case erlang:system_info(dirty_cpu_schedulers) of
@@ -498,10 +500,58 @@ code_purge(Config) when is_list(Config) ->
true = Time =< 1000,
ok.
+otp_15688(Config) when is_list(Config) ->
+ ImBack = make_ref(),
+ {See, SeeMon} = spawn_monitor(fun () ->
+ erts_debug:dirty_io(wait, 2000),
+ exit(ImBack)
+ end),
+ wait_until(fun () ->
+ [{current_function, {erts_debug, dirty_io, 2}},
+ {status, running}]
+ == process_info(See,
+ [current_function, status])
+ end),
+ {Ser1, Ser1Mon} = spawn_monitor(fun () ->
+ erlang:suspend_process(See,
+ [asynchronous])
+ end),
+ erlang:suspend_process(See, [asynchronous]),
+ receive {'DOWN', Ser1Mon, process, Ser1, normal} -> ok end,
+
+ %% Verify that we sent the suspend request while it was executing dirty...
+ [{current_function, {erts_debug, dirty_io, 2}},
+ {status, running}] = process_info(See, [current_function, status]),
+
+ wait_until(fun () ->
+ {status, suspended} == process_info(See, status)
+ end),
+ erlang:resume_process(See),
+
+ receive
+ {'DOWN', SeeMon, process, See, Reason} ->
+ ImBack = Reason
+ after 4000 ->
+ %% Resume bug seems to have hit us...
+ PI = process_info(See),
+ exit(See, kill),
+ ct:fail({suspendee_stuck, PI})
+ end.
+
+
%%
%% Internal...
%%
+wait_until(Fun) ->
+ case Fun() of
+ true ->
+ ok;
+ _ ->
+ receive after 100 -> ok end,
+ wait_until(Fun)
+ end.
+
access_dirty_process(Config, Start, Test, Finish) ->
{ok, Node} = start_node(Config, ""),
[ok] = mcall(Node,
diff --git a/erts/emulator/test/nif_SUITE.erl b/erts/emulator/test/nif_SUITE.erl
index 62b7f77a52..b824daea67 100644
--- a/erts/emulator/test/nif_SUITE.erl
+++ b/erts/emulator/test/nif_SUITE.erl
@@ -28,6 +28,7 @@
-include_lib("stdlib/include/assert.hrl").
-export([all/0, suite/0, groups/0,
+ init_per_suite/1, end_per_suite/1,
init_per_group/2, end_per_group/2,
init_per_testcase/2, end_per_testcase/2,
basic/1, reload_error/1, upgrade/1, heap_frag/1,
@@ -109,6 +110,14 @@ all() ->
pid,
nif_term_type].
+init_per_suite(Config) ->
+ erts_debug:set_internal_state(available_internal_state, true),
+ Config.
+
+end_per_suite(_Config) ->
+ catch erts_debug:set_internal_state(available_internal_state, false),
+ ok.
+
groups() ->
[{G, [], api_repeaters()} || G <- api_groups()]
++
@@ -118,7 +127,6 @@ groups() ->
monitor_process_d,
demonitor_process]}].
-
api_groups() -> [api_latest, api_2_4, api_2_0].
api_repeaters() -> [upgrade, resource_takeover, t_on_load].
@@ -1760,6 +1768,7 @@ read_resource(Type, {Holder,Id}) ->
forget_resource({Holder,Id}) ->
Holder ! {self(), forget, Id},
{Holder, forget_ok, Id} = receive_any(),
+ erts_debug:set_internal_state(wait, aux_work),
ok.
@@ -3105,22 +3114,31 @@ nif_whereis_threaded(Config) when is_list(Config) ->
RegName = nif_whereis_test_threaded,
undefined = erlang:whereis(RegName),
- Ref = make_ref(),
- {Pid, Mon} = spawn_monitor(?MODULE, nif_whereis_proxy, [Ref]),
- true = register(RegName, Pid),
+ Self = self(),
+ true = register(RegName, Self),
- {ok, ProcThr} = whereis_thd_lookup(pid, RegName),
- {ok, Pid} = whereis_thd_result(ProcThr),
+ {ok, ProcThr} = whereis_thd_lookup(pid, RegName, "dtor to proc"),
+ {ok, Self} = whereis_thd_result(ProcThr),
- Pid ! {Ref, quit},
- ok = receive {'DOWN', Mon, process, Pid, normal} -> ok end,
+ nif_whereis_threaded_2(RegName).
+
+nif_whereis_threaded_2(RegName) ->
+ erlang:garbage_collect(),
+ "dtor to proc" = receive_any(1000),
+ true = unregister(RegName),
Port = open_port({spawn, echo_drv}, [eof]),
true = register(RegName, Port),
- {ok, PortThr} = whereis_thd_lookup(port, RegName),
+ {ok, PortThr} = whereis_thd_lookup(port, RegName, "dtor to port"),
{ok, Port} = whereis_thd_result(PortThr),
+ nif_whereis_threaded_3(Port).
+
+nif_whereis_threaded_3(Port) ->
+ erlang:garbage_collect(),
+ {Port, {data, "dtor to port"}} = receive_any(1000),
+
port_close(Port),
ok.
@@ -3435,6 +3453,10 @@ nif_term_type(Config) ->
ok.
+last_resource_dtor_call() ->
+ erts_debug:set_internal_state(wait, aux_work),
+ last_resource_dtor_call_nif().
+
id(I) -> I.
%% The NIFs:
@@ -3462,7 +3484,7 @@ make_resource(_) -> ?nif_stub.
get_resource(_,_) -> ?nif_stub.
release_resource(_) -> ?nif_stub.
release_resource_from_thread(_) -> ?nif_stub.
-last_resource_dtor_call() -> ?nif_stub.
+last_resource_dtor_call_nif() -> ?nif_stub.
make_new_resource(_,_) -> ?nif_stub.
check_is(_,_,_,_,_,_,_,_,_,_,_) -> ?nif_stub.
check_is_exception() -> ?nif_stub.
@@ -3522,7 +3544,7 @@ ioq_nif(_,_,_,_) -> ?nif_stub.
%% whereis
whereis_send(_Type,_Name,_Msg) -> ?nif_stub.
whereis_term(_Type,_Name) -> ?nif_stub.
-whereis_thd_lookup(_Type,_Name) -> ?nif_stub.
+whereis_thd_lookup(_Type,_Name, _Msg) -> ?nif_stub.
whereis_thd_result(_Thd) -> ?nif_stub.
%% maps
diff --git a/erts/emulator/test/nif_SUITE_data/nif_SUITE.c b/erts/emulator/test/nif_SUITE_data/nif_SUITE.c
index 1906384af4..ff47cfe500 100644
--- a/erts/emulator/test/nif_SUITE_data/nif_SUITE.c
+++ b/erts/emulator/test/nif_SUITE_data/nif_SUITE.c
@@ -27,6 +27,7 @@
#ifndef __WIN32__
#include <unistd.h>
#include <fcntl.h>
+#include <sys/uio.h>
#endif
#include "nif_mod.h"
@@ -707,28 +708,23 @@ static ERL_NIF_TERM tuple_2_list(ErlNifEnv* env, int argc, const ERL_NIF_TERM ar
static ERL_NIF_TERM is_identical(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
{
- if (argc != 2) {
- return enif_make_badarg(env);
- }
+ assert(argc == 2);
return enif_make_atom(env, (enif_is_identical(argv[0],argv[1]) ?
"true" : "false"));
}
static ERL_NIF_TERM compare(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
{
- if (argc != 2) {
- return enif_make_badarg(env);
- }
+ assert(argc == 2);
return enif_make_int(env, enif_compare(argv[0],argv[1]));
}
static ERL_NIF_TERM hash_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
{
- if (argc != 3) {
- return enif_make_badarg(env);
- }
-
ErlNifHash type;
+ ErlNifUInt64 salt;
+
+ assert(argc == 3);
if (enif_is_identical(argv[0], enif_make_atom(env, "internal"))) {
type = ERL_NIF_INTERNAL_HASH;
}
@@ -739,7 +735,6 @@ static ERL_NIF_TERM hash_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]
return enif_make_badarg(env);
}
- ErlNifUInt64 salt;
if (! enif_get_uint64(env, argv[2], &salt)) {
return enif_make_badarg(env);
}
@@ -866,7 +861,7 @@ static ERL_NIF_TERM iolist_2_bin(ErlNifEnv* env, int argc, const ERL_NIF_TERM ar
return enif_make_binary(env,&obin);
}
-static ERL_NIF_TERM last_resource_dtor_call(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
+static ERL_NIF_TERM last_resource_dtor_call_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
{
ERL_NIF_TERM ret;
if (resource_dtor_last != NULL) {
@@ -1010,6 +1005,7 @@ static ERL_NIF_TERM release_resource(ErlNifEnv* env, int argc, const ERL_NIF_TER
static void* threaded_release_resource(void* resource)
{
enif_release_resource(resource);
+ return NULL;
}
static ERL_NIF_TERM release_resource_from_thread(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
@@ -1201,7 +1197,6 @@ static void fill(void* dst, unsigned bytes, int seed)
enum {
/* results */
WHEREIS_SUCCESS,
- WHEREIS_ERROR_TYPE,
WHEREIS_ERROR_LOOKUP,
WHEREIS_ERROR_SEND,
/* types */
@@ -1221,6 +1216,8 @@ typedef struct {
whereis_term_data_t res;
ErlNifTid tid;
int type;
+ int rc;
+ ERL_NIF_TERM dtor_msg;
} whereis_thread_resource_t;
static whereis_thread_resource_t* whereis_thread_resource_create(void)
@@ -1233,21 +1230,35 @@ static whereis_thread_resource_t* whereis_thread_resource_create(void)
return rp;
}
+static int whereis_lookup_internal(ErlNifEnv*, int type, ERL_NIF_TERM name,
+ whereis_term_data_t* out);
+static int whereis_send_internal(ErlNifEnv*, int type, whereis_term_data_t* to,
+ ERL_NIF_TERM msg);
+
+
static void whereis_thread_resource_dtor(ErlNifEnv* env, void* obj)
{
whereis_thread_resource_t* rp = (whereis_thread_resource_t*) obj;
+ whereis_term_data_t to;
+
+ if (whereis_lookup_internal(env, rp->type, rp->name, &to)
+ == WHEREIS_SUCCESS) {
+ whereis_send_internal(env, rp->type, &to, rp->dtor_msg);
+ }
enif_free_env(rp->env);
}
-static int whereis_type(ERL_NIF_TERM type)
+static int whereis_type(ERL_NIF_TERM type_term, int* type_p)
{
- if (enif_is_identical(type, atom_pid))
- return WHEREIS_LOOKUP_PID;
-
- if (enif_is_identical(type, atom_port))
- return WHEREIS_LOOKUP_PORT;
-
- return WHEREIS_ERROR_TYPE;
+ if (enif_is_identical(type_term, atom_pid)) {
+ *type_p = WHEREIS_LOOKUP_PID;
+ return 1;
+ }
+ if (enif_is_identical(type_term, atom_port)) {
+ *type_p = WHEREIS_LOOKUP_PORT;
+ return 1;
+ }
+ return 0;
}
static int whereis_lookup_internal(
@@ -1261,7 +1272,7 @@ static int whereis_lookup_internal(
return enif_whereis_port(env, name, & out->port)
? WHEREIS_SUCCESS : WHEREIS_ERROR_LOOKUP;
- return WHEREIS_ERROR_TYPE;
+ abort();
}
static int whereis_send_internal(
@@ -1275,23 +1286,20 @@ static int whereis_send_internal(
return enif_port_command(env, & to->port, NULL, msg)
? WHEREIS_SUCCESS : WHEREIS_ERROR_SEND;
- return WHEREIS_ERROR_TYPE;
+ abort();
}
-static int whereis_resolved_term(
- ErlNifEnv* env, int type, whereis_term_data_t* res, ERL_NIF_TERM* out)
+static ERL_NIF_TERM whereis_resolved_term(
+ ErlNifEnv* env, int type, whereis_term_data_t* res)
{
switch (type) {
case WHEREIS_LOOKUP_PID:
- *out = enif_make_pid(env, & res->pid);
- break;
+ return enif_make_pid(env, &res->pid);
case WHEREIS_LOOKUP_PORT:
- *out = enif_make_port(env, & res->port);
- break;
+ return enif_make_port(env, &res->port);
default:
- return WHEREIS_ERROR_TYPE;
+ abort();
}
- return WHEREIS_SUCCESS;
}
static ERL_NIF_TERM whereis_result_term(ErlNifEnv* env, int result)
@@ -1307,9 +1315,6 @@ static ERL_NIF_TERM whereis_result_term(ErlNifEnv* env, int result)
case WHEREIS_ERROR_SEND:
err = atom_send;
break;
- case WHEREIS_ERROR_TYPE:
- err = atom_badarg;
- break;
default:
err = enif_make_int(env, -result);
break;
@@ -1320,14 +1325,10 @@ static ERL_NIF_TERM whereis_result_term(ErlNifEnv* env, int result)
static void* whereis_lookup_thread(void* arg)
{
whereis_thread_resource_t* rp = (whereis_thread_resource_t*) arg;
- int rc;
- /* enif_whereis_xxx should work with allocated or null env */
- rc = whereis_lookup_internal(
- ((rp->type == WHEREIS_LOOKUP_PID) ? NULL : rp->env),
- rp->type, rp->name, & rp->res);
+ rp->rc = whereis_lookup_internal(NULL, rp->type, rp->name, &rp->res);
- return (((char*) NULL) + rc);
+ return NULL;
}
/* whereis_term(Type, Name) -> pid() | port() | false */
@@ -1335,20 +1336,16 @@ static ERL_NIF_TERM
whereis_term(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
{
whereis_term_data_t res;
- ERL_NIF_TERM ret;
int type, rc;
- if (argc != 2) /* allow non-atom name for testing */
- return enif_make_badarg(env);
-
- if ((type = whereis_type(argv[0])) == WHEREIS_ERROR_TYPE)
+ assert(argc == 2);
+ if (!whereis_type(argv[0], &type))
return enif_make_badarg(env);
rc = whereis_lookup_internal(env, type, argv[1], & res);
- if (rc == WHEREIS_SUCCESS) {
- rc = whereis_resolved_term(env, type, & res, & ret);
- }
- return (rc == WHEREIS_SUCCESS) ? ret : atom_false;
+ return (rc == WHEREIS_SUCCESS ?
+ whereis_resolved_term(env, type, &res) :
+ atom_false);
}
/* whereis_send(Type, Name, Message) -> ok | {error, Reason} */
@@ -1358,10 +1355,11 @@ whereis_send(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
whereis_term_data_t to;
int type, rc;
- if (argc != 3 || !enif_is_atom(env, argv[1]))
+ assert(argc == 3);
+ if (!enif_is_atom(env, argv[1]))
return enif_make_badarg(env);
- if ((type = whereis_type(argv[0])) == WHEREIS_ERROR_TYPE)
+ if (!whereis_type(argv[0], &type))
return enif_make_badarg(env);
rc = whereis_lookup_internal(env, type, argv[1], & to);
@@ -1371,33 +1369,35 @@ whereis_send(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
return whereis_result_term(env, rc);
}
-/* whereis_thd_lookup(Type, Name) -> {ok, Resource} | {error, SysErrno} */
+/* whereis_thd_lookup(Type, Name, DtorMsg) -> {ok, Resource} | {error, SysErrno} */
static ERL_NIF_TERM
whereis_thd_lookup(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
{
whereis_thread_resource_t* rp;
int type, rc;
+ ERL_NIF_TERM ret;
- if (argc != 2 || !enif_is_atom(env, argv[1]))
+ assert(argc == 3);
+ if (!enif_is_atom(env, argv[1]))
return enif_make_badarg(env);
- if ((type = whereis_type(argv[0])) == WHEREIS_ERROR_TYPE)
+ if (!whereis_type(argv[0], &type))
return enif_make_badarg(env);
rp = whereis_thread_resource_create();
rp->type = type;
rp->name = enif_make_copy(rp->env, argv[1]);
+ rp->dtor_msg = enif_make_copy(rp->env, argv[2]);
rc = enif_thread_create(
"nif_SUITE:whereis_thd", & rp->tid, whereis_lookup_thread, rp, NULL);
- if (rc == 0) {
- return enif_make_tuple2(env, atom_ok, enif_make_resource(env, rp));
- }
- else {
- enif_release_resource(rp);
- return enif_make_tuple2(env, atom_error, enif_make_int(env, rc));
- }
+ if (rc == 0)
+ ret = enif_make_tuple2(env, atom_ok, enif_make_resource(env, rp));
+ else
+ ret = enif_make_tuple2(env, atom_error, enif_make_int(env, rc));
+ enif_release_resource(rp);
+ return ret;
}
/* whereis_thd_result(Resource) -> {ok, pid() | port()} | {error, ErrNum} */
@@ -1406,24 +1406,22 @@ whereis_thd_result(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
{
whereis_thread_resource_t* rp;
ERL_NIF_TERM ret;
- char* thdret; /* so we can keep compilers happy converting to int */
- int rc;
+ int join_rc;
- if (argc != 1
- || !enif_get_resource(env, argv[0], whereis_resource_type, (void**) & rp))
+ assert(argc == 1);
+ if (!enif_get_resource(env, argv[0], whereis_resource_type, (void**) & rp))
return enif_make_badarg(env);
- if ((rc = enif_thread_join(rp->tid, (void**) & thdret)) != 0)
- return enif_make_tuple2(env, atom_error, enif_make_int(env, rc));
+ if ((join_rc = enif_thread_join(rp->tid, NULL)) != 0)
+ return enif_make_tuple2(env, atom_error, enif_make_int(env, join_rc));
- rc = (int)(thdret - ((char*) NULL));
- if (rc == WHEREIS_SUCCESS) {
- rc = whereis_resolved_term(env, rp->type, & rp->res, & ret);
+ if (rp->rc == WHEREIS_SUCCESS) {
+ ret = enif_make_tuple2(env, atom_ok,
+ whereis_resolved_term(env, rp->type, &rp->res));
}
- ret = (rc == WHEREIS_SUCCESS)
- ? enif_make_tuple2(env, atom_ok, ret) : whereis_result_term(env, rc);
+ else
+ ret = whereis_result_term(env, rp->rc);
- enif_release_resource(rp);
return ret;
}
@@ -2007,8 +2005,7 @@ static ERL_NIF_TERM nif_sched1(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv
static ERL_NIF_TERM call_nif_schedule(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
{
ERL_NIF_TERM result;
- if (argc != 2)
- return enif_make_atom(env, "false");
+ assert(argc == 2);
result = enif_schedule_nif(env, "nif_sched1", 0, nif_sched1, argc, argv);
assert(!enif_is_exception(env, result));
return result;
@@ -2155,7 +2152,8 @@ static ERL_NIF_TERM maps_from_list_nif(ErlNifEnv* env, int argc, const ERL_NIF_T
ERL_NIF_TERM result, cell;
unsigned count;
- if (argc != 1 || !enif_get_list_length(env, argv[0], &count)) {
+ assert(argc == 1);
+ if (!enif_get_list_length(env, argv[0], &count)) {
return enif_make_badarg(env);
}
@@ -2202,7 +2200,8 @@ static ERL_NIF_TERM sorted_list_from_maps_nif(ErlNifEnv* env, int argc, const ER
ErlNifMapIterator iter_b;
int cnt, next_ret, prev_ret;
- if (argc != 1 && !enif_is_map(env, map))
+ assert(argc == 1);
+ if (!enif_is_map(env, map))
return enif_make_int(env, __LINE__);
if(!enif_map_iterator_create(env, map, &iter_f, ERL_NIF_MAP_ITERATOR_FIRST))
@@ -2263,9 +2262,7 @@ static ERL_NIF_TERM monotonic_time(ErlNifEnv* env, int argc, const ERL_NIF_TERM
{
ErlNifTimeUnit time_unit;
- if (argc != 1)
- return atom_false;
-
+ assert(argc == 1);
if (enif_compare(argv[0], atom_second) == 0)
time_unit = ERL_NIF_SEC;
else if (enif_compare(argv[0], atom_millisecond) == 0)
@@ -2284,9 +2281,7 @@ static ERL_NIF_TERM time_offset(ErlNifEnv* env, int argc, const ERL_NIF_TERM arg
{
ErlNifTimeUnit time_unit;
- if (argc != 1)
- return atom_false;
-
+ assert(argc == 1);
if (enif_compare(argv[0], atom_second) == 0)
time_unit = ERL_NIF_SEC;
else if (enif_compare(argv[0], atom_millisecond) == 0)
@@ -2306,9 +2301,7 @@ static ERL_NIF_TERM convert_time_unit(ErlNifEnv* env, int argc, const ERL_NIF_TE
ErlNifTime val;
ErlNifTimeUnit from, to;
- if (argc != 3)
- return atom_false;
-
+ assert(argc == 3);
if (!enif_get_int64(env, argv[0], &i64))
return enif_make_badarg(env);
@@ -3319,7 +3312,7 @@ static int writeiovec(ErlNifEnv *env, ERL_NIF_TERM term, ERL_NIF_TERM *tail, Erl
}
/* Attempt to write the data */
- n = writev(fd, sysiovec, iovcnt);
+ n = writev(fd, (struct iovec*)sysiovec, iovcnt);
saved_errno = errno;
if (enif_ioq_size(q) == 0) {
@@ -3393,10 +3386,11 @@ static ERL_NIF_TERM ioq(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
if (enif_is_identical(argv[0], enif_make_atom(env, "example"))) {
#ifndef __WIN32__
- int fd[2], res = 0, cnt = 0, queue_cnt;
+ int fd[2], res = 0, cnt = 0;
ERL_NIF_TERM tail;
char buff[255];
- pipe(fd);
+ res = pipe(fd);
+ assert(res == 0);
fcntl(fd[0], F_SETFL, fcntl(fd[0], F_GETFL) | O_NONBLOCK);
fcntl(fd[1], F_SETFL, fcntl(fd[1], F_GETFL) | O_NONBLOCK);
@@ -3639,7 +3633,7 @@ static ErlNifFunc nif_funcs[] =
{"get_resource", 2, get_resource},
{"release_resource", 1, release_resource},
{"release_resource_from_thread", 1, release_resource_from_thread},
- {"last_resource_dtor_call", 0, last_resource_dtor_call},
+ {"last_resource_dtor_call_nif", 0, last_resource_dtor_call_nif},
{"make_new_resource", 2, make_new_resource},
{"check_is", 11, check_is},
{"check_is_exception", 0, check_is_exception},
@@ -3710,7 +3704,7 @@ static ErlNifFunc nif_funcs[] =
{"monitor_frenzy_nif", 4, monitor_frenzy_nif},
{"whereis_send", 3, whereis_send},
{"whereis_term", 2, whereis_term},
- {"whereis_thd_lookup", 2, whereis_thd_lookup},
+ {"whereis_thd_lookup", 3, whereis_thd_lookup},
{"whereis_thd_result", 1, whereis_thd_result},
{"ioq_nif", 1, ioq},
{"ioq_nif", 2, ioq},
diff --git a/erts/emulator/test/socket_SUITE.erl b/erts/emulator/test/socket_SUITE.erl
index 8a32efcd85..2e3f40a350 100644
--- a/erts/emulator/test/socket_SUITE.erl
+++ b/erts/emulator/test/socket_SUITE.erl
@@ -3404,7 +3404,9 @@ api_to_connect_tcp4(suite) ->
api_to_connect_tcp4(doc) ->
[];
api_to_connect_tcp4(_Config) when is_list(_Config) ->
+ Cond = fun() -> api_to_connect_cond() end,
tc_try(api_to_connect_tcp4,
+ Cond,
fun() ->
?TT(?SECS(10)),
InitState = #{domain => inet,
@@ -3414,6 +3416,41 @@ api_to_connect_tcp4(_Config) when is_list(_Config) ->
ok = api_to_connect_tcp(InitState)
end).
+api_to_connect_cond() ->
+ api_to_connect_cond(os:type(), os:version()).
+
+%% I don't know exactly at which version this starts to work.
+%% I know it does not work for 4.4.*, but is does for 4.15.
+%% So, just to simplify, we require atleast 4.15
+api_to_connect_cond({unix, linux}, {Maj, Min, _Rev}) ->
+ if
+ ((Maj >= 4) andalso (Min >= 15)) ->
+ ok;
+ true ->
+ skip("TC does not work")
+ end;
+%% Only test on one machine, which has version 6.3, and there it does
+%% not work, so disable for all.
+api_to_connect_cond({unix, openbsd}, _) ->
+ skip("TC does not work");
+api_to_connect_cond({unix, freebsd}, {Maj, Min, _Rev}) ->
+ if
+ ((Maj >= 10) andalso (Min >= 4)) ->
+ ok;
+ true ->
+ skip("TC may not work")
+ end;
+api_to_connect_cond({unix, sunos}, {Maj, Min, _Rev}) ->
+ if
+ ((Maj >= 5) andalso (Min >= 10)) ->
+ ok;
+ true ->
+ skip("TC may not work")
+ end;
+api_to_connect_cond(_, _) ->
+ skip("TC may not work").
+
+
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
@@ -3425,8 +3462,8 @@ api_to_connect_tcp6(doc) ->
[];
api_to_connect_tcp6(_Config) when is_list(_Config) ->
tc_try(api_to_connect_tcp6,
+ fun() -> has_support_ipv6(), api_to_connect_cond() end,
fun() ->
- not_yet_implemented(),
?TT(?SECS(10)),
InitState = #{domain => inet6,
backlog => 1,
@@ -3937,8 +3974,8 @@ api_to_accept_tcp6(doc) ->
[];
api_to_accept_tcp6(_Config) when is_list(_Config) ->
tc_try(api_to_accept_tcp4,
+ fun() -> has_support_ipv6() end,
fun() ->
- not_yet_implemented(),
?TT(?SECS(10)),
InitState = #{domain => inet6, timeout => 5000},
ok = api_to_accept_tcp(InitState)
@@ -4053,8 +4090,8 @@ api_to_maccept_tcp6(doc) ->
api_to_maccept_tcp6(_Config) when is_list(_Config) ->
?TT(?SECS(20)),
tc_try(api_to_maccept_tcp4,
+ fun() -> has_support_ipv6() end,
fun() ->
- not_yet_implemented(),
InitState = #{domain => inet6, timeout => 5000},
ok = api_to_maccept_tcp(InitState)
end).
@@ -4556,8 +4593,8 @@ api_to_recv_tcp6(doc) ->
[];
api_to_recv_tcp6(_Config) when is_list(_Config) ->
tc_try(api_to_recv_tcp6,
+ fun() -> has_support_ipv6() end,
fun() ->
- not_yet_implemented(),
case socket:supports(ipv6) of
true ->
?TT(?SECS(10)),
@@ -4915,8 +4952,8 @@ api_to_recvfrom_udp6(doc) ->
[];
api_to_recvfrom_udp6(_Config) when is_list(_Config) ->
tc_try(api_to_recvfrom_udp6,
+ fun() -> has_support_ipv6() end,
fun() ->
- not_yet_implemented(),
?TT(?SECS(10)),
Recv = fun(Sock, To) -> socket:recvfrom(Sock, 0, To) end,
InitState = #{domain => inet6,
@@ -5031,8 +5068,8 @@ api_to_recvmsg_udp6(doc) ->
[];
api_to_recvmsg_udp6(_Config) when is_list(_Config) ->
tc_try(api_to_recvmsg_udp6,
+ fun() -> has_support_ipv6() end,
fun() ->
- not_yet_implemented(),
?TT(?SECS(10)),
Recv = fun(Sock, To) -> socket:recvmsg(Sock, To) end,
InitState = #{domain => inet6,
@@ -5072,8 +5109,8 @@ api_to_recvmsg_tcp6(doc) ->
[];
api_to_recvmsg_tcp6(_Config) when is_list(_Config) ->
tc_try(api_to_recvmsg_tcp6,
+ fun() -> has_support_ipv6() end,
fun() ->
- not_yet_implemented(),
?TT(?SECS(10)),
Recv = fun(Sock, To) -> socket:recvmsg(Sock, To) end,
InitState = #{domain => inet6,
@@ -5104,7 +5141,6 @@ sc_cpe_socket_cleanup_tcp4(doc) ->
sc_cpe_socket_cleanup_tcp4(_Config) when is_list(_Config) ->
tc_try(sc_cpe_socket_cleanup_tcp4,
fun() ->
- %% not_yet_implemented(),
?TT(?SECS(5)),
InitState = #{domain => inet,
type => stream,
@@ -5124,8 +5160,8 @@ sc_cpe_socket_cleanup_tcp6(doc) ->
[];
sc_cpe_socket_cleanup_tcp6(_Config) when is_list(_Config) ->
tc_try(sc_cpe_socket_cleanup_tcp6,
+ fun() -> has_support_ipv6() end,
fun() ->
- not_yet_implemented(),
?TT(?SECS(5)),
InitState = #{domain => inet6,
type => stream,
@@ -5166,8 +5202,8 @@ sc_cpe_socket_cleanup_udp6(doc) ->
[];
sc_cpe_socket_cleanup_udp6(_Config) when is_list(_Config) ->
tc_try(sc_cpe_socket_cleanup_udp6,
+ fun() -> has_support_ipv6() end,
fun() ->
- not_yet_implemented(),
?TT(?SECS(5)),
InitState = #{domain => inet6,
type => dgram,
@@ -5342,8 +5378,8 @@ sc_lc_recv_response_tcp6(doc) ->
[];
sc_lc_recv_response_tcp6(_Config) when is_list(_Config) ->
tc_try(sc_lc_recv_response_tcp6,
+ fun() -> has_support_ipv6() end,
fun() ->
- not_yet_implemented(),
?TT(?SECS(10)),
Recv = fun(Sock) -> socket:recv(Sock) end,
InitState = #{domain => inet6,
@@ -5958,8 +5994,8 @@ sc_lc_recvfrom_response_udp6(doc) ->
[];
sc_lc_recvfrom_response_udp6(_Config) when is_list(_Config) ->
tc_try(sc_lc_recvfrom_response_udp6,
+ fun() -> has_support_ipv6() end,
fun() ->
- not_yet_implemented(),
?TT(?SECS(30)),
Recv = fun(Sock, To) -> socket:recvfrom(Sock, [], To) end,
InitState = #{domain => inet6,
@@ -6378,8 +6414,8 @@ sc_lc_recvmsg_response_tcp6(doc) ->
[];
sc_lc_recvmsg_response_tcp6(_Config) when is_list(_Config) ->
tc_try(sc_recvmsg_response_tcp6,
+ fun() -> has_support_ipv6() end,
fun() ->
- not_yet_implemented(),
?TT(?SECS(10)),
Recv = fun(Sock) -> socket:recvmsg(Sock) end,
InitState = #{domain => inet6,
@@ -6421,8 +6457,8 @@ sc_lc_recvmsg_response_udp6(doc) ->
[];
sc_lc_recvmsg_response_udp6(_Config) when is_list(_Config) ->
tc_try(sc_recvmsg_response_udp6,
+ fun() -> has_support_ipv6() end,
fun() ->
- not_yet_implemented(),
?TT(?SECS(10)),
Recv = fun(Sock, To) -> socket:recvmsg(Sock, To) end,
InitState = #{domain => inet6,
@@ -6467,8 +6503,8 @@ sc_lc_acceptor_response_tcp6(doc) ->
[];
sc_lc_acceptor_response_tcp6(_Config) when is_list(_Config) ->
tc_try(sc_lc_acceptor_response_tcp6,
+ fun() -> has_support_ipv6() end,
fun() ->
- not_yet_implemented(),
?TT(?SECS(10)),
InitState = #{domain => inet,
type => stream,
@@ -6902,8 +6938,8 @@ sc_rc_recv_response_tcp6(doc) ->
[];
sc_rc_recv_response_tcp6(_Config) when is_list(_Config) ->
tc_try(sc_rc_recv_response_tcp6,
+ fun() -> has_support_ipv6() end,
fun() ->
- not_yet_implemented(),
?TT(?SECS(10)),
Recv = fun(Sock) -> socket:recv(Sock) end,
InitState = #{domain => inet6,
@@ -7783,8 +7819,8 @@ sc_rc_recvmsg_response_tcp6(doc) ->
[];
sc_rc_recvmsg_response_tcp6(_Config) when is_list(_Config) ->
tc_try(sc_rc_recvmsg_response_tcp6,
+ fun() -> has_support_ipv6() end,
fun() ->
- not_yet_implemented(),
?TT(?SECS(10)),
Recv = fun(Sock) -> socket:recvmsg(Sock) end,
InitState = #{domain => inet6,
@@ -7843,8 +7879,8 @@ sc_rs_recv_send_shutdown_receive_tcp6(doc) ->
[];
sc_rs_recv_send_shutdown_receive_tcp6(_Config) when is_list(_Config) ->
tc_try(sc_rs_recv_send_shutdown_receive_tcp6,
+ fun() -> has_support_ipv6() end,
fun() ->
- not_yet_implemented(),
?TT(?SECS(10)),
MsgData = ?DATA,
Recv = fun(Sock) ->
@@ -8667,8 +8703,8 @@ sc_rs_recvmsg_send_shutdown_receive_tcp6(doc) ->
[];
sc_rs_recvmsg_send_shutdown_receive_tcp6(_Config) when is_list(_Config) ->
tc_try(sc_rs_recvmsg_send_shutdown_receive_tcp6,
+ fun() -> has_support_ipv6() end,
fun() ->
- not_yet_implemented(),
?TT(?SECS(10)),
MsgData = ?DATA,
Recv = fun(Sock) ->
@@ -8728,8 +8764,8 @@ traffic_send_and_recv_chunks_tcp6(doc) ->
[];
traffic_send_and_recv_chunks_tcp6(_Config) when is_list(_Config) ->
tc_try(traffic_send_and_recv_chunks_tcp6,
+ fun() -> has_support_ipv6() end,
fun() ->
- not_yet_implemented(),
?TT(?SECS(30)),
InitState = #{domain => inet6},
ok = traffic_send_and_recv_chunks_tcp(InitState)
@@ -9730,8 +9766,8 @@ traffic_ping_pong_small_send_and_recv_tcp6(_Config) when is_list(_Config) ->
Msg = l2b(?TPP_SMALL),
Num = ?TPP_SMALL_NUM,
tc_try(traffic_ping_pong_small_send_and_recv_tcp6,
+ fun() -> has_support_ipv6() end,
fun() ->
- not_yet_implemented(),
?TT(?SECS(15)),
InitState = #{domain => inet6,
msg => Msg,
@@ -9783,8 +9819,8 @@ traffic_ping_pong_medium_send_and_recv_tcp6(_Config) when is_list(_Config) ->
Msg = l2b(?TPP_MEDIUM),
Num = ?TPP_MEDIUM_NUM,
tc_try(traffic_ping_pong_medium_send_and_recv_tcp6,
+ fun() -> has_support_ipv6() end,
fun() ->
- not_yet_implemented(),
?TT(?SECS(30)),
InitState = #{domain => inet6,
msg => Msg,
@@ -9837,8 +9873,8 @@ traffic_ping_pong_large_send_and_recv_tcp6(_Config) when is_list(_Config) ->
Msg = l2b(?TPP_LARGE),
Num = ?TPP_LARGE_NUM,
tc_try(traffic_ping_pong_large_send_and_recv_tcp6,
+ fun() -> has_support_ipv6() end,
fun() ->
- not_yet_implemented(),
?TT(?SECS(45)),
InitState = #{domain => inet6,
msg => Msg,
@@ -9944,8 +9980,8 @@ traffic_ping_pong_medium_sendto_and_recvfrom_udp6(_Config) when is_list(_Config)
Msg = l2b(?TPP_MEDIUM),
Num = ?TPP_MEDIUM_NUM,
tc_try(traffic_ping_pong_medium_sendto_and_recvfrom_udp6,
+ fun() -> has_support_ipv6() end,
fun() ->
- not_yet_implemented(),
?TT(?SECS(45)),
InitState = #{domain => inet6,
msg => Msg,
@@ -9998,8 +10034,8 @@ traffic_ping_pong_small_sendmsg_and_recvmsg_tcp6(_Config) when is_list(_Config)
Msg = l2b(?TPP_SMALL),
Num = ?TPP_SMALL_NUM,
tc_try(traffic_ping_pong_small_sendmsg_and_recvmsg_tcp6,
+ fun() -> has_support_ipv6() end,
fun() ->
- not_yet_implemented(),
?TT(?SECS(20)),
InitState = #{domain => inet6,
msg => Msg,
@@ -10051,8 +10087,8 @@ traffic_ping_pong_medium_sendmsg_and_recvmsg_tcp6(_Config) when is_list(_Config)
Msg = l2b(?TPP_MEDIUM),
Num = ?TPP_MEDIUM_NUM,
tc_try(traffic_ping_pong_medium_sendmsg_and_recvmsg_tcp6,
+ fun() -> has_support_ipv6() end,
fun() ->
- not_yet_implemented(),
?TT(?SECS(20)),
InitState = #{domain => ine6,
msg => Msg,
@@ -10104,8 +10140,8 @@ traffic_ping_pong_large_sendmsg_and_recvmsg_tcp6(_Config) when is_list(_Config)
Msg = l2b(?TPP_LARGE),
Num = ?TPP_LARGE_NUM,
tc_try(traffic_ping_pong_large_sendmsg_and_recvmsg_tcp6,
+ fun() -> has_support_ipv6() end,
fun() ->
- not_yet_implemented(),
?TT(?SECS(30)),
InitState = #{domain => inet6,
msg => Msg,
@@ -10158,8 +10194,8 @@ traffic_ping_pong_small_sendmsg_and_recvmsg_udp6(_Config) when is_list(_Config)
Msg = l2b(?TPP_SMALL),
Num = ?TPP_SMALL_NUM,
tc_try(traffic_ping_pong_small_sendmsg_and_recvmsg_udp6,
+ fun() -> has_support_ipv6() end,
fun() ->
- not_yet_implemented(),
?TT(?SECS(20)),
InitState = #{domain => inet,
msg => Msg,
@@ -10211,8 +10247,8 @@ traffic_ping_pong_medium_sendmsg_and_recvmsg_udp6(_Config) when is_list(_Config)
Msg = l2b(?TPP_MEDIUM),
Num = ?TPP_MEDIUM_NUM,
tc_try(traffic_ping_pong_medium_sendmsg_and_recvmsg_udp6,
+ fun() -> has_support_ipv6() end,
fun() ->
- not_yet_implemented(),
?TT(?SECS(20)),
InitState = #{domain => ine6,
msg => Msg,
@@ -17172,17 +17208,17 @@ convert_time(TStrRev, Convert) ->
?TTEST_RUNTIME
end.
-ttest_tcp(TC,
- Domain,
- ServerMod, ServerActive,
- ClientMod, ClientActive,
- MsgID, MaxOutstanding) ->
- ttest_tcp(TC,
- ?TTEST_RUNTIME,
- Domain,
- ServerMod, ServerActive,
- ClientMod, ClientActive,
- MsgID, MaxOutstanding).
+%% ttest_tcp(TC,
+%% Domain,
+%% ServerMod, ServerActive,
+%% ClientMod, ClientActive,
+%% MsgID, MaxOutstanding) ->
+%% ttest_tcp(TC,
+%% ?TTEST_RUNTIME,
+%% Domain,
+%% ServerMod, ServerActive,
+%% ClientMod, ClientActive,
+%% MsgID, MaxOutstanding).
ttest_tcp(TC,
Runtime,
Domain,
@@ -17191,7 +17227,12 @@ ttest_tcp(TC,
MsgID, MaxOutstanding) ->
tc_try(TC,
fun() ->
- if (Domain =/= inet) -> not_yet_implemented(); true -> ok end,
+ if
+ (Domain =/= inet) -> has_support_ipv6();
+ true -> ok
+ end
+ end,
+ fun() ->
%% This may be overkill, depending on the runtime,
%% but better safe then sorry...
?TT(Runtime + ?SECS(60)),
@@ -17833,6 +17874,18 @@ which_addr2(Domain, [_|IFO]) ->
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% Here are all the *general* test vase condition functions.
+
+%% The idea is that this function shall test if the test host has
+%% support for IPv6. If not there is no point in running IPv6 tests.
+%% Currently we just skip.
+has_support_ipv6() ->
+ not_yet_implemented().
+
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
not_yet_implemented() ->
skip("not yet implemented").
@@ -17886,15 +17939,45 @@ tc_end(Result) when is_list(Result) ->
"", "----------------------------------------------------~n~n"),
ok.
-
-tc_try(Case, Fun) when is_atom(Case) andalso is_function(Fun, 0) ->
+%% *** tc_try/2,3 ***
+%% Case: Basically the test case name
+%% TCCondFun: A fun that is evaluated before the actual test case
+%% The point of this is that it can performs checks to
+%% see if we shall run the test case at all.
+%% For instance, the test case may only work in specific
+%% conditions.
+%% FCFun: The test case fun
+tc_try(Case, TCFun) ->
+ TCCondFun = fun() -> ok end,
+ tc_try(Case, TCCondFun, TCFun).
+
+tc_try(Case, TCCondFun, TCFun)
+ when is_atom(Case) andalso
+ is_function(TCCondFun, 0) andalso
+ is_function(TCFun, 0) ->
tc_begin(Case),
- try
- begin
- Fun(),
- ?SLEEP(?SECS(1)),
- tc_end("ok")
- end
+ try TCCondFun() of
+ ok ->
+ try
+ begin
+ TCFun(),
+ ?SLEEP(?SECS(1)),
+ tc_end("ok")
+ end
+ catch
+ throw:{skip, _} = SKIP ->
+ tc_end("skipping"),
+ SKIP;
+ Class:Error:Stack ->
+ tc_end("failed"),
+ erlang:raise(Class, Error, Stack)
+ end;
+ {skip, _} = SKIP ->
+ tc_end("skipping"),
+ SKIP;
+ {error, Reason} ->
+ tc_end("failed"),
+ exit({tc_cond_failed, Reason})
catch
throw:{skip, _} = SKIP ->
tc_end("skipping"),
diff --git a/erts/emulator/utils/beam_makeops b/erts/emulator/utils/beam_makeops
index 1625b2cc65..605a402f2a 100755
--- a/erts/emulator/utils/beam_makeops
+++ b/erts/emulator/utils/beam_makeops
@@ -2737,7 +2737,7 @@ sub tr_maybe_keep {
return;
}
} elsif ($op eq 'store_var_next_arg') {
- return unless shift(@last_instr) eq $args[0];
+ return unless @last_instr and shift(@last_instr) eq $args[0];
} elsif (defined $pos) {
return;
}
diff --git a/erts/preloaded/ebin/erlang.beam b/erts/preloaded/ebin/erlang.beam
index 1b0cb5b50c..62dc8702e7 100644
--- a/erts/preloaded/ebin/erlang.beam
+++ b/erts/preloaded/ebin/erlang.beam
Binary files differ
diff --git a/erts/preloaded/src/erlang.erl b/erts/preloaded/src/erlang.erl
index a5b60cc845..ac73946dc0 100644
--- a/erts/preloaded/src/erlang.erl
+++ b/erts/preloaded/src/erlang.erl
@@ -48,6 +48,8 @@
dist_ctrl_put_data/2,
dist_ctrl_get_data/1,
dist_ctrl_get_data_notification/1,
+ dist_ctrl_get_opt/2,
+ dist_ctrl_set_opt/3,
dist_get_stat/1]).
-deprecated([get_stacktrace/0,now/0]).
@@ -3326,7 +3328,8 @@ dist_ctrl_input_handler(_DHandle, _InputHandler) ->
dist_ctrl_put_data(_DHandle, _Data) ->
erlang:nif_error(undefined).
--spec erlang:dist_ctrl_get_data(DHandle) -> Data | 'none' when
+-spec erlang:dist_ctrl_get_data(DHandle) -> {Size, Data} | Data | 'none' when
+ Size :: non_neg_integer(),
DHandle :: dist_handle(),
Data :: iodata().
@@ -3339,6 +3342,21 @@ dist_ctrl_get_data(_DHandle) ->
dist_ctrl_get_data_notification(_DHandle) ->
erlang:nif_error(undefined).
+-spec erlang:dist_ctrl_set_opt(DHandle, 'get_size', Value) -> OldValue when
+ DHandle :: dist_handle(),
+ Value :: boolean(),
+ OldValue :: boolean().
+
+dist_ctrl_set_opt(_DHandle, _Opt, _Val) ->
+ erlang:nif_error(undefined).
+
+-spec erlang:dist_ctrl_get_opt(DHandle, 'get_size') -> Value when
+ DHandle :: dist_handle(),
+ Value :: boolean().
+
+dist_ctrl_get_opt(_DHandle, _Opt) ->
+ erlang:nif_error(undefined).
+
-spec erlang:dist_get_stat(DHandle) -> Res when
DHandle :: dist_handle(),
InputPackets :: non_neg_integer(),
diff --git a/erts/vsn.mk b/erts/vsn.mk
index fac608ed4e..3942af7f78 100644
--- a/erts/vsn.mk
+++ b/erts/vsn.mk
@@ -18,7 +18,7 @@
# %CopyrightEnd%
#
-VSN = 10.3
+VSN = 10.3.1
# Port number 4365 in 4.2
# Port number 4366 in 4.3
diff --git a/lib/compiler/scripts/smoke-mix.exs b/lib/compiler/scripts/smoke-mix.exs
index 82ae3370fe..ba0815e465 100644
--- a/lib/compiler/scripts/smoke-mix.exs
+++ b/lib/compiler/scripts/smoke-mix.exs
@@ -25,6 +25,14 @@ defmodule Smoke.MixProject do
[
{:bear, "~> 0.8.7"},
{:cloudi_core, "~> 1.7"},
+ {:cloudi_service_monitoring, "~> 1.7"},
+ {:cloudi_service_tcp, "~> 1.7"},
+ {:cloudi_service_queue, "~> 1.7"},
+ {:cloudi_service_udp, "~> 1.7"},
+ {:cloudi_service_map_reduce, "~> 1.7"},
+ {:cloudi_service_api_requests, "~> 1.7"},
+ {:cloudi_service_router, "~> 1.7"},
+ {:cloudi_service_request_rate, "~> 1.7"},
{:concuerror, "~> 0.20.0"},
{:cowboy, "~> 2.6.1"},
{:ecto, "~> 3.0.6"},
diff --git a/lib/compiler/src/Makefile b/lib/compiler/src/Makefile
index c971e8844d..9f8d63baa1 100644
--- a/lib/compiler/src/Makefile
+++ b/lib/compiler/src/Makefile
@@ -129,9 +129,10 @@ APPUP_TARGET= $(EBIN)/$(APPUP_FILE)
ifeq ($(NATIVE_LIBS_ENABLED),yes)
ERL_COMPILE_FLAGS += +native
+else
+ERL_COMPILE_FLAGS += -Werror
endif
ERL_COMPILE_FLAGS += +inline +warn_unused_import \
- -Werror \
-I../../stdlib/include -I$(EGEN) -W +warn_missing_spec
# ----------------------------------------------------
diff --git a/lib/compiler/src/compile.erl b/lib/compiler/src/compile.erl
index 11dea9524b..28db8986ff 100644
--- a/lib/compiler/src/compile.erl
+++ b/lib/compiler/src/compile.erl
@@ -290,6 +290,10 @@ format_error(bad_crypto_key) ->
"invalid crypto key.";
format_error(no_crypto_key) ->
"no crypto key supplied.";
+format_error({unimplemented_instruction,Instruction}) ->
+ io_lib:fwrite("native-code compilation failed because of an "
+ "unimplemented instruction (~s).",
+ [Instruction]);
format_error({native, E}) ->
io_lib:fwrite("native-code compilation failed with reason: ~tP.",
[E, 25]);
@@ -1651,18 +1655,22 @@ native_compile_1(Code, St) ->
case IgnoreErrors of
true ->
Ws = [{St#compile.ifile,[{none,?MODULE,{native,R}}]}],
- {ok,St#compile{warnings=St#compile.warnings ++ Ws}};
+ {ok,Code,St#compile{warnings=St#compile.warnings ++ Ws}};
false ->
Es = [{St#compile.ifile,[{none,?MODULE,{native,R}}]}],
{error,St#compile{errors=St#compile.errors ++ Es}}
end
catch
+ exit:{unimplemented_instruction,_}=Unimplemented ->
+ Ws = [{St#compile.ifile,
+ [{none,?MODULE,Unimplemented}]}],
+ {ok,Code,St#compile{warnings=St#compile.warnings ++ Ws}};
Class:R:Stack ->
case IgnoreErrors of
true ->
Ws = [{St#compile.ifile,
[{none,?MODULE,{native_crash,R,Stack}}]}],
- {ok,St#compile{warnings=St#compile.warnings ++ Ws}};
+ {ok,Code,St#compile{warnings=St#compile.warnings ++ Ws}};
false ->
erlang:raise(Class, R, Stack)
end
diff --git a/lib/crypto/c_src/algorithms.c b/lib/crypto/c_src/algorithms.c
index 06cd109fc1..1d45ed9df2 100644
--- a/lib/crypto/c_src/algorithms.c
+++ b/lib/crypto/c_src/algorithms.c
@@ -68,9 +68,15 @@ void init_algorithms_types(ErlNifEnv* env)
// Non-validated algorithms follow
algo_hash_fips_cnt = algo_hash_cnt;
+#ifdef HAVE_MD4
algo_hash[algo_hash_cnt++] = enif_make_atom(env, "md4");
+#endif
+#ifdef HAVE_MD5
algo_hash[algo_hash_cnt++] = enif_make_atom(env, "md5");
+#endif
+#ifdef HAVE_RIPEMD160
algo_hash[algo_hash_cnt++] = enif_make_atom(env, "ripemd160");
+#endif
algo_pubkey_cnt = 0;
algo_pubkey[algo_pubkey_cnt++] = enif_make_atom(env, "rsa");
diff --git a/lib/crypto/c_src/api_ng.c b/lib/crypto/c_src/api_ng.c
index 6a833a0984..f4312114ed 100644
--- a/lib/crypto/c_src/api_ng.c
+++ b/lib/crypto/c_src/api_ng.c
@@ -207,7 +207,7 @@ static int get_init_args(ErlNifEnv* env,
goto err;
}
-
+#ifdef HAVE_RC2
if (EVP_CIPHER_type((*cipherp)->cipher.p) == NID_rc2_cbc) {
if (key_bin.size > INT_MAX / 8) {
*return_term = EXCP_BADARG(env, "To large rc2_cbc key");
@@ -218,6 +218,7 @@ static int get_init_args(ErlNifEnv* env,
goto err;
}
}
+#endif
if (ivec_arg == atom_undefined || ivec_len == 0)
{
@@ -346,7 +347,7 @@ ERL_NIF_TERM ng_crypto_init_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM arg
ret = enif_make_resource(env, ctx_res);
if(ctx_res) enif_release_resource(ctx_res);
- } else if (enif_get_resource(env, argv[0], evp_cipher_ctx_rtype, (void**)&ctx_res)) {
+ } else if (enif_get_resource(env, argv[0], (ErlNifResourceType*)evp_cipher_ctx_rtype, (void**)&ctx_res)) {
/* Fetch the flag telling if we are going to encrypt (=true) or decrypt (=false) */
if (argv[3] == atom_true)
encflg = 1;
@@ -426,7 +427,7 @@ ERL_NIF_TERM ng_crypto_update(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[
struct evp_cipher_ctx *ctx_res;
ERL_NIF_TERM ret;
- if (!enif_get_resource(env, argv[0], evp_cipher_ctx_rtype, (void**)&ctx_res))
+ if (!enif_get_resource(env, argv[0], (ErlNifResourceType*)evp_cipher_ctx_rtype, (void**)&ctx_res))
return EXCP_BADARG(env, "Bad 1:st arg");
if (argc == 3) {
diff --git a/lib/crypto/c_src/cipher.c b/lib/crypto/c_src/cipher.c
index 5c57898c50..9d60254a3c 100644
--- a/lib/crypto/c_src/cipher.c
+++ b/lib/crypto/c_src/cipher.c
@@ -28,12 +28,12 @@
static struct cipher_type_t cipher_types[] =
{
-#ifndef OPENSSL_NO_RC2
+#ifdef HAVE_RC2
{{"rc2_cbc"}, {&EVP_rc2_cbc}, 0, NO_FIPS_CIPHER},
#else
{{"rc2_cbc"}, {NULL}, 0, NO_FIPS_CIPHER},
#endif
-#ifndef OPENSSL_NO_RC4
+#ifdef HAVE_RC4
{{"rc4"}, {&EVP_rc4}, 0, NO_FIPS_CIPHER},
#else
{{"rc4"}, {NULL}, 0, NO_FIPS_CIPHER},
diff --git a/lib/crypto/c_src/digest.c b/lib/crypto/c_src/digest.c
index fec286c000..c987a664d5 100644
--- a/lib/crypto/c_src/digest.c
+++ b/lib/crypto/c_src/digest.c
@@ -22,10 +22,32 @@
static struct digest_type_t digest_types[] =
{
- {{"md4"}, {&EVP_md4}},
- {{"md5"}, {&EVP_md5}},
- {{"ripemd160"}, {&EVP_ripemd160}},
+ {{"md4"},
+#ifdef HAVE_MD4
+ {&EVP_md4}
+#else
+ {NULL}
+#endif
+ },
+
+ {{"md5"},
+#ifdef HAVE_MD5
+ {&EVP_md5}
+#else
+ {NULL}
+#endif
+ },
+
+ {{"ripemd160"},
+#ifdef HAVE_RIPEMD160
+ {&EVP_ripemd160}
+#else
+ {NULL}
+#endif
+ },
+
{{"sha"}, {&EVP_sha1}},
+
{{"sha224"},
#ifdef HAVE_SHA224
{&EVP_sha224}
@@ -33,6 +55,7 @@ static struct digest_type_t digest_types[] =
{NULL}
#endif
},
+
{{"sha256"},
#ifdef HAVE_SHA256
{&EVP_sha256}
@@ -40,6 +63,7 @@ static struct digest_type_t digest_types[] =
{NULL}
#endif
},
+
{{"sha384"},
#ifdef HAVE_SHA384
{&EVP_sha384}
@@ -47,6 +71,7 @@ static struct digest_type_t digest_types[] =
{NULL}
#endif
},
+
{{"sha512"},
#ifdef HAVE_SHA512
{&EVP_sha512}
@@ -54,6 +79,7 @@ static struct digest_type_t digest_types[] =
{NULL}
#endif
},
+
{{"sha3_224"},
#ifdef HAVE_SHA3_224
{&EVP_sha3_224}
@@ -61,6 +87,7 @@ static struct digest_type_t digest_types[] =
{NULL}
#endif
},
+
{{"sha3_256"},
#ifdef HAVE_SHA3_256
{&EVP_sha3_256}
@@ -68,6 +95,7 @@ static struct digest_type_t digest_types[] =
{NULL}
#endif
},
+
{{"sha3_384"},
#ifdef HAVE_SHA3_384
{&EVP_sha3_384}
@@ -75,6 +103,7 @@ static struct digest_type_t digest_types[] =
{NULL}
#endif
},
+
{{"sha3_512"},
#ifdef HAVE_SHA3_512
{&EVP_sha3_512}
@@ -82,6 +111,7 @@ static struct digest_type_t digest_types[] =
{NULL}
#endif
},
+
{{"blake2b"},
#ifdef HAVE_BLAKE2
{&EVP_blake2b512}
@@ -89,6 +119,7 @@ static struct digest_type_t digest_types[] =
{NULL}
#endif
},
+
{{"blake2s"},
#ifdef HAVE_BLAKE2
{&EVP_blake2s256}
diff --git a/lib/crypto/c_src/engine.c b/lib/crypto/c_src/engine.c
index 7ffbb9e70d..ea5d9a588f 100644
--- a/lib/crypto/c_src/engine.c
+++ b/lib/crypto/c_src/engine.c
@@ -106,15 +106,13 @@ int init_engine_ctx(ErlNifEnv *env) {
(ErlNifResourceDtor*) engine_ctx_dtor,
ERL_NIF_RT_CREATE|ERL_NIF_RT_TAKEOVER,
NULL);
- if (engine_ctx_rtype == NULL)
- goto err;
+ if (engine_ctx_rtype == NULL) {
+ PRINTF_ERR0("CRYPTO: Could not open resource type 'ENGINE_CTX'");
+ return 0;
+ }
#endif
return 1;
-
- err:
- PRINTF_ERR0("CRYPTO: Could not open resource type 'ENGINE_CTX'");
- return 0;
}
ERL_NIF_TERM engine_by_id_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
diff --git a/lib/crypto/c_src/hash.c b/lib/crypto/c_src/hash.c
index 0a9f64acef..9b79258585 100644
--- a/lib/crypto/c_src/hash.c
+++ b/lib/crypto/c_src/hash.c
@@ -21,9 +21,15 @@
#include "hash.h"
#include "digest.h"
-#define MD5_CTX_LEN (sizeof(MD5_CTX))
-#define MD4_CTX_LEN (sizeof(MD4_CTX))
-#define RIPEMD160_CTX_LEN (sizeof(RIPEMD160_CTX))
+#ifdef HAVE_MD5
+# define MD5_CTX_LEN (sizeof(MD5_CTX))
+#endif
+#ifdef HAVE_MD4
+# define MD4_CTX_LEN (sizeof(MD4_CTX))
+#endif
+#ifdef HAVE_RIPEMD160
+# define RIPEMD160_CTX_LEN (sizeof(RIPEMD160_CTX))
+#endif
#if OPENSSL_VERSION_NUMBER >= PACKED_OPENSSL_VERSION_PLAIN(1,0,0)
struct evp_md_ctx {
@@ -261,18 +267,24 @@ ERL_NIF_TERM hash_init_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
switch (EVP_MD_type(digp->md.p))
{
+#ifdef HAVE_MD4
case NID_md4:
ctx_size = MD4_CTX_LEN;
ctx_init = (init_fun)(&MD4_Init);
break;
+#endif
+#ifdef HAVE_MD5
case NID_md5:
ctx_size = MD5_CTX_LEN;
ctx_init = (init_fun)(&MD5_Init);
break;
+#endif
+#ifdef HAVE_RIPEMD160
case NID_ripemd160:
ctx_size = RIPEMD160_CTX_LEN;
ctx_init = (init_fun)(&RIPEMD160_Init);
break;
+#endif
case NID_sha1:
ctx_size = sizeof(SHA_CTX);
ctx_init = (init_fun)(&SHA1_Init);
@@ -352,18 +364,24 @@ ERL_NIF_TERM hash_update_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]
switch (EVP_MD_type(digp->md.p))
{
+#ifdef HAVE_MD4
case NID_md4:
ctx_size = MD4_CTX_LEN;
ctx_update = (update_fun)(&MD4_Update);
break;
+#endif
+#ifdef HAVE_MD5
case NID_md5:
ctx_size = MD5_CTX_LEN;
ctx_update = (update_fun)(&MD5_Update);
break;
+#endif
+#ifdef HAVE_RIPEMD160
case NID_ripemd160:
ctx_size = RIPEMD160_CTX_LEN;
ctx_update = (update_fun)(&RIPEMD160_Update);
break;
+#endif
case NID_sha1:
ctx_size = sizeof(SHA_CTX);
ctx_update = (update_fun)(&SHA1_Update);
@@ -448,18 +466,24 @@ ERL_NIF_TERM hash_final_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
switch (EVP_MD_type(md))
{
+#ifdef HAVE_MD4
case NID_md4:
ctx_size = MD4_CTX_LEN;
ctx_final = (final_fun)(&MD4_Final);
break;
+#endif
+#ifdef HAVE_MD5
case NID_md5:
ctx_size = MD5_CTX_LEN;
ctx_final = (final_fun)(&MD5_Final);
break;
- case NID_ripemd160:
+#endif
+#ifdef HAVE_RIPEMD160
+ case NID_ripemd160:
ctx_size = RIPEMD160_CTX_LEN;
ctx_final = (final_fun)(&RIPEMD160_Final);
break;
+#endif
case NID_sha1:
ctx_size = sizeof(SHA_CTX);
ctx_final = (final_fun)(&SHA1_Final);
diff --git a/lib/crypto/c_src/hmac.c b/lib/crypto/c_src/hmac.c
index c41e50eb35..ff7005d75e 100644
--- a/lib/crypto/c_src/hmac.c
+++ b/lib/crypto/c_src/hmac.c
@@ -181,7 +181,7 @@ ERL_NIF_TERM hmac_update_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]
ASSERT(argc == 2);
- if (!enif_get_resource(env, argv[0], hmac_context_rtype, (void**)&obj))
+ if (!enif_get_resource(env, argv[0], (ErlNifResourceType*)hmac_context_rtype, (void**)&obj))
goto bad_arg;
if (!enif_inspect_iolist_as_binary(env, argv[1], &data))
goto bad_arg;
@@ -224,7 +224,7 @@ ERL_NIF_TERM hmac_final_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
ASSERT(argc == 1 || argc == 2);
- if (!enif_get_resource(env, argv[0], hmac_context_rtype, (void**)&obj))
+ if (!enif_get_resource(env, argv[0], (ErlNifResourceType*)hmac_context_rtype, (void**)&obj))
goto bad_arg;
if (argc == 2) {
if (!enif_get_uint(env, argv[1], &req_len))
diff --git a/lib/crypto/c_src/openssl_config.h b/lib/crypto/c_src/openssl_config.h
index 46868cb987..f926f8af13 100644
--- a/lib/crypto/c_src/openssl_config.h
+++ b/lib/crypto/c_src/openssl_config.h
@@ -166,6 +166,28 @@
# define HAVE_BLAKE2
#endif
+#ifndef OPENSSL_NO_MD4
+# define HAVE_MD4
+#endif
+
+#ifndef OPENSSL_NO_MD5
+# define HAVE_MD5
+#endif
+
+#ifndef OPENSSL_NO_RC2
+# define HAVE_RC2
+#endif
+
+#ifndef OPENSSL_NO_RC4
+# define HAVE_RC4
+#endif
+
+#ifndef OPENSSL_NO_RMD160
+/* Note RMD160 vs RIPEMD160 */
+# define HAVE_RIPEMD160
+#endif
+
+
#if OPENSSL_VERSION_NUMBER >= PACKED_OPENSSL_VERSION(0,9,8,'o') \
&& !defined(OPENSSL_NO_EC) \
&& !defined(OPENSSL_NO_ECDH) \
@@ -192,7 +214,9 @@
# define HAVE_AEAD
# define HAVE_GCM
# define HAVE_CCM
-# define HAVE_CMAC
+# ifndef OPENSSL_NO_CMAC
+# define HAVE_CMAC
+# endif
# if defined(RSA_PKCS1_OAEP_PADDING)
# define HAVE_RSA_OAEP_PADDING
# endif
@@ -204,21 +228,27 @@
#if OPENSSL_VERSION_NUMBER >= PACKED_OPENSSL_VERSION_PLAIN(1,1,0)
# ifndef HAS_LIBRESSL
-# define HAVE_CHACHA20_POLY1305
+# if !defined(OPENSSL_NO_CHACHA) && !defined(OPENSSL_NO_POLY1305)
+# define HAVE_CHACHA20_POLY1305
+# endif
# define HAVE_RSA_OAEP_MD
# endif
#endif
#if OPENSSL_VERSION_NUMBER >= PACKED_OPENSSL_VERSION(1,1,0,'d')
# ifndef HAS_LIBRESSL
-# define HAVE_CHACHA20
+# ifndef OPENSSL_NO_CHACHA
+# define HAVE_CHACHA20
+# endif
# endif
#endif
// OPENSSL_VERSION_NUMBER >= 1.1.1-pre8
#if OPENSSL_VERSION_NUMBER >= (PACKED_OPENSSL_VERSION_PLAIN(1,1,1)-7)
# ifndef HAS_LIBRESSL
-# define HAVE_POLY1305
+# if !defined(OPENSSL_NO_POLY1305)
+# define HAVE_POLY1305
+# endif
# endif
#endif
diff --git a/lib/crypto/test/crypto_SUITE.erl b/lib/crypto/test/crypto_SUITE.erl
index 7dbbde68e9..5aa19a6ae0 100644
--- a/lib/crypto/test/crypto_SUITE.erl
+++ b/lib/crypto/test/crypto_SUITE.erl
@@ -323,12 +323,11 @@ end_per_group(_GroupName, Config) ->
init_per_testcase(info, Config) ->
Config;
init_per_testcase(cmac, Config) ->
- case crypto:info_lib() of
- [{<<"OpenSSL">>,LibVer,_}] when is_integer(LibVer), LibVer > 16#10001000 ->
+ case is_supported(cmac) of
+ true ->
Config;
- _Else ->
- % The CMAC functionality was introduced in OpenSSL 1.0.1
- {skip, "OpenSSL is too old"}
+ false ->
+ {skip, "CMAC is not supported"}
end;
init_per_testcase(generate, Config) ->
case proplists:get_value(type, Config) of
diff --git a/lib/dialyzer/src/Makefile b/lib/dialyzer/src/Makefile
index fc08e7ca2f..bddd761705 100644
--- a/lib/dialyzer/src/Makefile
+++ b/lib/dialyzer/src/Makefile
@@ -90,8 +90,10 @@ APPUP_TARGET= $(EBIN)/$(APPUP_FILE)
ifeq ($(NATIVE_LIBS_ENABLED),yes)
ERL_COMPILE_FLAGS += +native
+else
+ERL_COMPILE_FLAGS += -Werror
endif
-ERL_COMPILE_FLAGS += +warn_export_vars +warn_unused_import +warn_untyped_record +warn_missing_spec +warnings_as_errors
+ERL_COMPILE_FLAGS += +warn_export_vars +warn_unused_import +warn_untyped_record +warn_missing_spec
# ----------------------------------------------------
# Targets
diff --git a/lib/hipe/cerl/Makefile b/lib/hipe/cerl/Makefile
index f653dce36f..5c367b5b77 100644
--- a/lib/hipe/cerl/Makefile
+++ b/lib/hipe/cerl/Makefile
@@ -66,7 +66,10 @@ DOC_FILES= $(MODULES:%=$(DOCS)/%.html)
include ../native.mk
-ERL_COMPILE_FLAGS += +inline -Werror +warn_export_vars +warn_unused_import +warn_missing_spec #+warn_untyped_record
+ERL_COMPILE_FLAGS += +inline +warn_export_vars +warn_unused_import +warn_missing_spec #+warn_untyped_record
+ifneq ($(NATIVE_LIBS_ENABLED),yes)
+ERL_COMPILE_FLAGS += -Werror
+endif
# ----------------------------------------------------
# Targets
diff --git a/lib/hipe/icode/hipe_beam_to_icode.erl b/lib/hipe/icode/hipe_beam_to_icode.erl
index ffe81ef9b8..8e7e56b6c4 100644
--- a/lib/hipe/icode/hipe_beam_to_icode.erl
+++ b/lib/hipe/icode/hipe_beam_to_icode.erl
@@ -1189,6 +1189,21 @@ trans_fun([raw_raise|Instructions], Env) ->
[hipe_icode:mk_primop(Dst,raw_raise,Vars) |
trans_fun(Instructions, Env)];
%%--------------------------------------------------------------------
+%% New binary matching added in OTP 22.
+%%--------------------------------------------------------------------
+%%--- bs_get_tail ---
+trans_fun([{bs_get_tail=Name,_,_,_}|_Instructions], _Env) ->
+ nyi(Name);
+%%--- bs_start_match3 ---
+trans_fun([{bs_start_match3=Name,_,_,_,_}|_Instructions], _Env) ->
+ nyi(Name);
+%%--- bs_get_position ---
+trans_fun([{bs_get_position=Name,_,_,_}|_Instructions], _Env) ->
+ nyi(Name);
+%%--- bs_set_position ---
+trans_fun([{bs_set_position=Name,_,_}|_Instructions], _Env) ->
+ nyi(Name);
+%%--------------------------------------------------------------------
%%--- ERROR HANDLING ---
%%--------------------------------------------------------------------
trans_fun([X|_], _) ->
@@ -1196,6 +1211,9 @@ trans_fun([X|_], _) ->
trans_fun([], _) ->
[].
+nyi(Name) ->
+ throw({unimplemented_instruction,Name}).
+
%%--------------------------------------------------------------------
%% trans_call and trans_enter generate correct Icode calls/tail-calls,
%% recognizing explicit fails.
diff --git a/lib/hipe/llvm/Makefile b/lib/hipe/llvm/Makefile
index 817ff67dcd..9f7a2def6d 100644
--- a/lib/hipe/llvm/Makefile
+++ b/lib/hipe/llvm/Makefile
@@ -70,7 +70,10 @@ TARGET_FILES= $(MODULES:%=$(EBIN)/%.$(EMULATOR))
include ../native.mk
-ERL_COMPILE_FLAGS += -Werror +inline +warn_export_vars #+warn_missing_spec
+ERL_COMPILE_FLAGS += +inline +warn_export_vars #+warn_missing_spec
+ifneq ($(NATIVE_LIBS_ENABLED),yes)
+ERL_COMPILE_FLAGS += -Werror
+endif
# if in 32 bit backend define BIT32 symbol
ifneq ($(BITS64),yes)
diff --git a/lib/hipe/main/hipe.erl b/lib/hipe/main/hipe.erl
index 2348e9b1f6..094b7bc508 100644
--- a/lib/hipe/main/hipe.erl
+++ b/lib/hipe/main/hipe.erl
@@ -583,9 +583,8 @@ fix_beam_exports([], Exports) ->
Exports.
get_beam_icode(Mod, {BeamCode, Exports}, File, Options) ->
- {ok, Icode} =
- ?option_time((catch {ok, hipe_beam_to_icode:module(BeamCode, Options)}),
- "BEAM-to-Icode", Options),
+ Icode = ?option_time(hipe_beam_to_icode:module(BeamCode, Options),
+ "BEAM-to-Icode", Options),
BeamBin = get_beam_code(File),
{{Mod, Exports, Icode}, BeamBin}.
@@ -662,9 +661,12 @@ run_compiler_1(Name, DisasmFun, IcodeFun, Options) ->
{Icode, WholeModule} = IcodeFun(Code, Opts),
CompRes = compile_finish(Icode, WholeModule, Opts),
compiler_return(CompRes, Parent)
- catch error:Error:StackTrace ->
+ catch
+ error:Error:StackTrace ->
print_crash_message(Name, Error, StackTrace),
- exit(Error)
+ exit(Error);
+ throw:{unimplemented_instruction,_Instruction}=Error ->
+ exit(Error)
end
end),
Timeout = case proplists:get_value(timeout, Options) of
diff --git a/lib/hipe/rtl/Makefile b/lib/hipe/rtl/Makefile
index becdd0b7d8..0c0f6e24f5 100644
--- a/lib/hipe/rtl/Makefile
+++ b/lib/hipe/rtl/Makefile
@@ -75,7 +75,10 @@ TARGET_FILES= $(MODULES:%=$(EBIN)/%.$(EMULATOR))
include ../native.mk
-ERL_COMPILE_FLAGS += -Werror +inline +warn_unused_import +warn_export_vars
+ERL_COMPILE_FLAGS += +inline +warn_unused_import +warn_export_vars
+ifneq ($(NATIVE_LIBS_ENABLED),yes)
+ERL_COMPILE_FLAGS += -Werror
+endif
# ----------------------------------------------------
# Targets
diff --git a/lib/kernel/examples/gen_tcp_dist/Makefile b/lib/kernel/examples/gen_tcp_dist/Makefile
index 65513a1729..0c916835ea 100644
--- a/lib/kernel/examples/gen_tcp_dist/Makefile
+++ b/lib/kernel/examples/gen_tcp_dist/Makefile
@@ -2,9 +2,7 @@ RM=rm -f
CP=cp
EBIN=ebin
ERLC=erlc
-# Works if building in open source source tree
-KERNEL_INCLUDE=$(ERL_TOP)/lib/kernel/include
-ERLCFLAGS+= -W -I$(KERNEL_INCLUDE)
+ERLCFLAGS+= -W
MODULES=gen_tcp_dist
diff --git a/lib/kernel/examples/gen_tcp_dist/src/gen_tcp_dist.erl b/lib/kernel/examples/gen_tcp_dist/src/gen_tcp_dist.erl
index 98554ed805..cda4c470f9 100644
--- a/lib/kernel/examples/gen_tcp_dist/src/gen_tcp_dist.erl
+++ b/lib/kernel/examples/gen_tcp_dist/src/gen_tcp_dist.erl
@@ -53,10 +53,10 @@
-import(error_logger,[error_msg/2]).
--include("net_address.hrl").
+-include_lib("kernel/include/net_address.hrl").
--include("dist.hrl").
--include("dist_util.hrl").
+-include_lib("kernel/include/dist.hrl").
+-include_lib("kernel/include/dist_util.hrl").
%% ------------------------------------------------------------
%% Select this protocol based on node name
@@ -679,7 +679,14 @@ dist_cntrlr_setup_loop(Socket, TickHandler, Sup) ->
%% From now on we execute on normal priority
process_flag(priority, normal),
erlang:dist_ctrl_get_data_notification(DHandle),
- dist_cntrlr_output_loop(DHandle, Socket)
+ case init:get_argument(gen_tcp_dist_output_loop) of
+ error ->
+ dist_cntrlr_output_loop(DHandle, Socket);
+ {ok, [[ModStr, FuncStr]]} -> % For testing...
+ apply(list_to_atom(ModStr),
+ list_to_atom(FuncStr),
+ [DHandle, Socket])
+ end
end.
%% We use active 10 for good throughput while still
diff --git a/lib/kernel/src/Makefile b/lib/kernel/src/Makefile
index 43b776f37e..fcb599859b 100644
--- a/lib/kernel/src/Makefile
+++ b/lib/kernel/src/Makefile
@@ -175,8 +175,10 @@ APPUP_TARGET= $(EBIN)/$(APPUP_FILE)
ifeq ($(NATIVE_LIBS_ENABLED),yes)
ERL_COMPILE_FLAGS += +native
+else
+ERL_COMPILE_FLAGS += -Werror
endif
-ERL_COMPILE_FLAGS += -I../include -Werror
+ERL_COMPILE_FLAGS += -I../include
# ----------------------------------------------------
# Targets
diff --git a/lib/kernel/src/application_controller.erl b/lib/kernel/src/application_controller.erl
index 9a8091fb2e..7715dca7c6 100644
--- a/lib/kernel/src/application_controller.erl
+++ b/lib/kernel/src/application_controller.erl
@@ -537,14 +537,12 @@ check_conf_data(ConfData) when is_list(ConfData) ->
{AppName, List} when is_atom(AppName), is_list(List) ->
case lists:keymember(AppName, 1, ConfDataRem) of
true ->
- ?LOG_WARNING("duplicate application config: " ++ atom_to_list(AppName));
+ {error, "duplicate application config: " ++ atom_to_list(AppName)};
false ->
- ok
- end,
-
- case check_para(List, AppName) of
- ok -> check_conf_data(ConfDataRem);
- Error -> Error
+ case check_para(List, AppName) of
+ ok -> check_conf_data(ConfDataRem);
+ Error -> Error
+ end
end;
{AppName, List} when is_list(List) ->
ErrMsg = "application: "
@@ -570,15 +568,14 @@ check_para([], _AppName) ->
check_para([{Para, Val} | ParaList], AppName) when is_atom(Para) ->
case lists:keymember(Para, 1, ParaList) of
true ->
- ?LOG_WARNING("application: " ++ atom_to_list(AppName) ++
- "; duplicate parameter: " ++ atom_to_list(Para));
+ ErrMsg = "application: " ++ atom_to_list(AppName)
+ ++ "; duplicate parameter: " ++ atom_to_list(Para),
+ {error, ErrMsg};
false ->
- ok
- end,
-
- case check_para_value(Para, Val, AppName) of
- ok -> check_para(ParaList, AppName);
- {error, _} = Error -> Error
+ case check_para_value(Para, Val, AppName) of
+ ok -> check_para(ParaList, AppName);
+ {error, _} = Error -> Error
+ end
end;
check_para([{Para, _Val} | _ParaList], AppName) ->
{error, "application: " ++ atom_to_list(AppName) ++ "; invalid parameter name: " ++
diff --git a/lib/kernel/src/global.erl b/lib/kernel/src/global.erl
index a38522eb5c..3875074d74 100644
--- a/lib/kernel/src/global.erl
+++ b/lib/kernel/src/global.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2017. All Rights Reserved.
+%% Copyright Ericsson AB 1996-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.
@@ -50,10 +50,9 @@
%% This is for backward compatibility only; the functionality is broken.
-define(WARN_DUPLICATED_NAME, global_multi_name_action).
-%% Undocumented Kernel variable. Set this to 0 (zero) to get the old
-%% behaviour.
+%% Undocumented Kernel variable.
-define(N_CONNECT_RETRIES, global_connect_retries).
--define(DEFAULT_N_CONNECT_RETRIES, 5).
+-define(DEFAULT_N_CONNECT_RETRIES, 0).
%%% In certain places in the server, calling io:format hangs everything,
%%% so we'd better use erlang:display/1.
@@ -125,16 +124,12 @@
%%% There are also ETS tables used for bookkeeping of locks and names
%%% (the first position is the key):
%%%
-%%% global_locks (set): {ResourceId, LockRequesterId, [{Pid,RPid,ref()]}
+%%% global_locks (set): {ResourceId, LockRequesterId, [{Pid,ref()]}
%%% Pid is locking ResourceId, ref() is the monitor ref.
-%%% RPid =/= Pid if there is an extra process calling erlang:monitor().
-%%% global_names (set): {Name, Pid, Method, RPid, ref()}
+%%% global_names (set): {Name, Pid, Method, ref()}
%%% Registered names. ref() is the monitor ref.
-%%% RPid =/= Pid if there is an extra process calling erlang:monitor().
%%% global_names_ext (set): {Name, Pid, RegNode}
%%% External registered names (C-nodes).
-%%% (The RPid:s can be removed when/if erlang:monitor() returns before
-%%% trying to connect to the other node.)
%%%
%%% Helper tables:
%%% global_pid_names (bag): {Pid, Name} | {ref(), Name}
@@ -310,7 +305,7 @@ re_register_name(Name, Pid, Method0) when is_pid(Pid) ->
-spec registered_names() -> [Name] when
Name :: term().
registered_names() ->
- MS = ets:fun2ms(fun({Name,_Pid,_M,_RP,_R}) -> Name end),
+ MS = ets:fun2ms(fun({Name,_Pid,_M,_R}) -> Name end),
ets:select(global_names, MS).
%%-----------------------------------------------------------------
@@ -1235,7 +1230,7 @@ ins_name_ext(Name, Pid, Method, RegNode, FromPidOrNode, ExtraInfo, S0) ->
where(Name) ->
case ets:lookup(global_names, Name) of
- [{_Name, Pid, _Method, _RPid, _Ref}] ->
+ [{_Name, Pid, _Method, _Ref}] ->
if node(Pid) == node() ->
case is_process_alive(Pid) of
true -> Pid;
@@ -1272,10 +1267,10 @@ can_set_lock({ResourceId, LockRequesterId}) ->
end.
insert_lock({ResourceId, LockRequesterId}=Id, Pid, PidRefs, S) ->
- {RPid, Ref} = do_monitor(Pid),
+ Ref = erlang:monitor(process, Pid),
true = ets:insert(global_pid_ids, {Pid, ResourceId}),
true = ets:insert(global_pid_ids, {Ref, ResourceId}),
- Lock = {ResourceId, LockRequesterId, [{Pid,RPid,Ref} | PidRefs]},
+ Lock = {ResourceId, LockRequesterId, [{Pid,Ref} | PidRefs]},
true = ets:insert(global_locks, Lock),
trace_message(S, {ins_lock, node(Pid)}, [Id, Pid]).
@@ -1293,10 +1288,9 @@ handle_del_lock({ResourceId, LockReqId}, Pid, S0) ->
_ -> S0
end.
-remove_lock(ResourceId, LockRequesterId, Pid, [{Pid,RPid,Ref}], Down, S0) ->
+remove_lock(ResourceId, LockRequesterId, Pid, [{Pid,Ref}], Down, S0) ->
?trace({remove_lock_1, {id,ResourceId},{pid,Pid}}),
true = erlang:demonitor(Ref, [flush]),
- kill_monitor_proc(RPid, Pid),
true = ets:delete(global_locks, ResourceId),
true = ets:delete_object(global_pid_ids, {Pid, ResourceId}),
true = ets:delete_object(global_pid_ids, {Ref, ResourceId}),
@@ -1309,9 +1303,8 @@ remove_lock(ResourceId, LockRequesterId, Pid, [{Pid,RPid,Ref}], Down, S0) ->
remove_lock(ResourceId, LockRequesterId, Pid, PidRefs0, _Down, S) ->
?trace({remove_lock_2, {id,ResourceId},{pid,Pid}}),
PidRefs = case lists:keyfind(Pid, 1, PidRefs0) of
- {Pid, RPid, Ref} ->
+ {Pid, Ref} ->
true = erlang:demonitor(Ref, [flush]),
- kill_monitor_proc(RPid, Pid),
true = ets:delete_object(global_pid_ids,
{Ref, ResourceId}),
lists:keydelete(Pid, 1, PidRefs0);
@@ -1324,11 +1317,6 @@ remove_lock(ResourceId, LockRequesterId, Pid, PidRefs0, _Down, S) ->
trace_message(S, {rem_lock, node(Pid)},
[{ResourceId, LockRequesterId}, Pid]).
-kill_monitor_proc(Pid, Pid) ->
- ok;
-kill_monitor_proc(RPid, _Pid) ->
- exit(RPid, kill).
-
do_ops(Ops, ConnNode, Names_ext, ExtraInfo, S0) ->
?trace({do_ops, {ops,Ops}}),
@@ -1394,8 +1382,8 @@ sync_other(Node, N) ->
% exit(normal).
insert_global_name(Name, Pid, Method, FromPidOrNode, ExtraInfo, S) ->
- {RPid, Ref} = do_monitor(Pid),
- true = ets:insert(global_names, {Name, Pid, Method, RPid, Ref}),
+ Ref = erlang:monitor(process, Pid),
+ true = ets:insert(global_names, {Name, Pid, Method, Ref}),
true = ets:insert(global_pid_names, {Pid, Name}),
true = ets:insert(global_pid_names, {Ref, Name}),
case lock_still_set(FromPidOrNode, ExtraInfo, S) of
@@ -1437,7 +1425,7 @@ extra_info(Tag, ExtraInfo) ->
del_name(Ref, S) ->
NameL = [Name ||
{_, Name} <- ets:lookup(global_pid_names, Ref),
- {_, _Pid, _Method, _RPid, Ref1} <-
+ {_, _Pid, _Method, Ref1} <-
ets:lookup(global_names, Name),
Ref1 =:= Ref],
case NameL of
@@ -1450,24 +1438,23 @@ del_name(Ref, S) ->
%% Keeps the entry in global_names for whereis_name/1.
delete_global_name_keep_pid(Name, S) ->
case ets:lookup(global_names, Name) of
- [{Name, Pid, _Method, RPid, Ref}] ->
- delete_global_name2(Name, Pid, RPid, Ref, S);
+ [{Name, Pid, _Method, Ref}] ->
+ delete_global_name2(Name, Pid, Ref, S);
[] ->
S
end.
delete_global_name2(Name, S) ->
case ets:lookup(global_names, Name) of
- [{Name, Pid, _Method, RPid, Ref}] ->
+ [{Name, Pid, _Method, Ref}] ->
true = ets:delete(global_names, Name),
- delete_global_name2(Name, Pid, RPid, Ref, S);
+ delete_global_name2(Name, Pid, Ref, S);
[] ->
S
end.
-delete_global_name2(Name, Pid, RPid, Ref, S) ->
+delete_global_name2(Name, Pid, Ref, S) ->
true = erlang:demonitor(Ref, [flush]),
- kill_monitor_proc(RPid, Pid),
delete_global_name(Name, Pid),
?trace({delete_global_name,{item,Name},{pid,Pid}}),
true = ets:delete_object(global_pid_names, {Pid, Name}),
@@ -1929,9 +1916,9 @@ reset_node_state(Node) ->
%% from the same partition.
exchange_names([{Name, Pid, Method} | Tail], Node, Ops, Res) ->
case ets:lookup(global_names, Name) of
- [{Name, Pid, _Method, _RPid2, _Ref2}] ->
+ [{Name, Pid, _Method, _Ref2}] ->
exchange_names(Tail, Node, Ops, Res);
- [{Name, Pid2, Method2, _RPid2, _Ref2}] when node() < Node ->
+ [{Name, Pid2, Method2, _Ref2}] when node() < Node ->
%% Name clash! Add the result of resolving to Res(olved).
%% We know that node(Pid) =/= node(), so we don't
%% need to link/unlink to Pid.
@@ -1960,7 +1947,7 @@ exchange_names([{Name, Pid, Method} | Tail], Node, Ops, Res) ->
Op = {delete, Name},
exchange_names(Tail, Node, [Op | Ops], [Op | Res])
end;
- [{Name, _Pid2, _Method, _RPid, _Ref}] ->
+ [{Name, _Pid2, _Method, _Ref}] ->
%% The other node will solve the conflict.
exchange_names(Tail, Node, Ops, Res);
_ ->
@@ -2036,7 +2023,7 @@ pid_is_locking(Pid, PidRefs) ->
delete_lock(Ref, S0) ->
Locks = pid_locks(Ref),
F = fun({ResourceId, LockRequesterId, PidRefs}, S) ->
- {Pid, _RPid, Ref} = lists:keyfind(Ref, 3, PidRefs),
+ {Pid, Ref} = lists:keyfind(Ref, 2, PidRefs),
remove_lock(ResourceId, LockRequesterId, Pid, PidRefs, true, S)
end,
lists:foldl(F, S0, Locks).
@@ -2046,10 +2033,10 @@ pid_locks(Ref) ->
ets:lookup(global_locks, ResourceId)
end, ets:lookup(global_pid_ids, Ref)),
[Lock || Lock = {_Id, _Req, PidRefs} <- L,
- rpid_is_locking(Ref, PidRefs)].
+ ref_is_locking(Ref, PidRefs)].
-rpid_is_locking(Ref, PidRefs) ->
- lists:keyfind(Ref, 3, PidRefs) =/= false.
+ref_is_locking(Ref, PidRefs) ->
+ lists:keyfind(Ref, 2, PidRefs) =/= false.
handle_nodedown(Node, S) ->
%% DOWN signals from monitors have removed locks and registered names.
@@ -2062,7 +2049,7 @@ handle_nodedown(Node, S) ->
get_names() ->
ets:select(global_names,
- ets:fun2ms(fun({Name, Pid, Method, _RPid, _Ref}) ->
+ ets:fun2ms(fun({Name, Pid, Method, _Ref}) ->
{Name, Pid, Method}
end)).
@@ -2205,24 +2192,6 @@ unexpected_message(Message, What) ->
%%% Utilities
-%% When/if erlang:monitor() returns before trying to connect to the
-%% other node this function can be removed.
-do_monitor(Pid) ->
- case (node(Pid) =:= node()) orelse lists:member(node(Pid), nodes()) of
- true ->
- %% Assume the node is still up
- {Pid, erlang:monitor(process, Pid)};
- false ->
- F = fun() ->
- Ref = erlang:monitor(process, Pid),
- receive
- {'DOWN', Ref, process, Pid, _Info} ->
- exit(normal)
- end
- end,
- erlang:spawn_monitor(F)
- end.
-
intersection(_, []) ->
[];
intersection(L1, L2) ->
diff --git a/lib/kernel/test/Makefile b/lib/kernel/test/Makefile
index d203597fc2..6763a04d9f 100644
--- a/lib/kernel/test/Makefile
+++ b/lib/kernel/test/Makefile
@@ -57,6 +57,7 @@ MODULES= \
prim_file_SUITE \
ram_file_SUITE \
gen_tcp_api_SUITE \
+ gen_tcp_dist \
gen_tcp_echo_SUITE \
gen_tcp_misc_SUITE \
gen_udp_SUITE \
@@ -137,7 +138,10 @@ TARGETS = $(MODULES:%=$(EBIN)/%.$(EMULATOR))
# Targets
# ----------------------------------------------------
-make_emakefile:
+gen_tcp_dist.erl: ../examples/gen_tcp_dist/src/gen_tcp_dist.erl
+ cp $< $@
+
+make_emakefile: $(ERL_FILES)
$(ERL_TOP)/make/make_emakefile $(ERL_COMPILE_FLAGS) -o$(EBIN) '*_SUITE_make' \
> $(EMAKEFILE)
$(ERL_TOP)/make/make_emakefile $(ERL_COMPILE_FLAGS) -o$(EBIN) $(MODULES) \
diff --git a/lib/kernel/test/application_SUITE.erl b/lib/kernel/test/application_SUITE.erl
index 94d7c17712..1ab554db7c 100644
--- a/lib/kernel/test/application_SUITE.erl
+++ b/lib/kernel/test/application_SUITE.erl
@@ -2020,18 +2020,11 @@ set_env_errors(Conf) when is_list(Conf) ->
"application: kernel; erroneous parameter: distributed" =
badarg_msg(fun() -> application:set_env([{kernel, [{distributed, config}]}]) end),
- %% This will raise in the future
- ct:capture_start(),
- _ = application:set_env([{foo, []}, {foo, []}]),
- timer:sleep(100),
- ct:capture_stop(),
- [_ | _] = string:find(ct:capture_get(), "duplicate application config: foo"),
-
- ct:capture_start(),
- _ = application:set_env([{foo, [{bar, baz}, {bar, bat}]}]),
- timer:sleep(100),
- ct:capture_stop(),
- [_ | _] = string:find(ct:capture_get(), "application: foo; duplicate parameter: bar"),
+ "duplicate application config: foo" =
+ badarg_msg(fun() -> application:set_env([{foo, []}, {foo, []}]) end),
+
+ "application: foo; duplicate parameter: bar" =
+ badarg_msg(fun() -> application:set_env([{foo, [{bar, baz}, {bar, bat}]}]) end),
ok.
diff --git a/lib/kernel/test/erl_distribution_SUITE.erl b/lib/kernel/test/erl_distribution_SUITE.erl
index 5a8bbd56c4..8dd4ef1987 100644
--- a/lib/kernel/test/erl_distribution_SUITE.erl
+++ b/lib/kernel/test/erl_distribution_SUITE.erl
@@ -40,7 +40,8 @@
monitor_nodes_errors/1,
monitor_nodes_combinations/1,
monitor_nodes_cleanup/1,
- monitor_nodes_many/1]).
+ monitor_nodes_many/1,
+ dist_ctrl_proc_smoke/1]).
%% Performs the test at another node.
-export([get_socket_priorities/0,
@@ -52,7 +53,7 @@
-export([init_per_testcase/2, end_per_testcase/2]).
--export([start_node/2]).
+-export([dist_cntrlr_output_test/2]).
-export([pinger/1]).
@@ -67,10 +68,11 @@
suite() ->
[{ct_hooks,[ts_install_cth]},
- {timetrap,{minutes,4}}].
+ {timetrap,{minutes,12}}].
all() ->
- [tick, tick_change, nodenames, hostnames, illegal_nodenames,
+ [dist_ctrl_proc_smoke,
+ tick, tick_change, nodenames, hostnames, illegal_nodenames,
connect_node,
hidden_node, setopts,
table_waste, net_setuptime, inet_dist_options_options,
@@ -116,10 +118,12 @@ connect_node(Config) when is_list(Config) ->
ok.
tick(Config) when is_list(Config) ->
- PaDir = filename:dirname(code:which(erl_distribution_SUITE)),
+ run_dist_configs(fun tick/2, Config).
+tick(DCfg, _Config) ->
%% First check that the normal case is OK!
- {ok, Node} = start_node(dist_test, "-pa " ++ PaDir),
+ [Name1, Name2] = get_nodenames(2, dist_test),
+ {ok, Node} = start_node(DCfg, Name1),
rpc:call(Node, erl_distribution_SUITE, tick_cli_test, [node()]),
erlang:monitor_node(Node, true),
@@ -143,14 +147,12 @@ tick(Config) when is_list(Config) ->
%% Set the ticktime on the server node to 100 secs so the server
%% node doesn't tick the client node within the interval ...
- {ok, ServNode} = start_node(dist_test_server,
- "-kernel net_ticktime 100 "
- "-pa " ++ PaDir),
+ {ok, ServNode} = start_node(DCfg, Name2,
+ "-kernel net_ticktime 100"),
rpc:call(ServNode, erl_distribution_SUITE, tick_serv_test, [Node, node()]),
- {ok, _} = start_node(dist_test,
- "-kernel net_ticktime 12 "
- "-pa " ++ PaDir),
+ {ok, Node} = start_node(DCfg, Name1,
+ "-kernel net_ticktime 12"),
rpc:call(Node, erl_distribution_SUITE, tick_cli_test, [ServNode]),
spawn_link(erl_distribution_SUITE, keep_conn, [Node]),
@@ -180,6 +182,9 @@ tick(Config) when is_list(Config) ->
%% Checks that pinging nonexistyent nodes does not waste space in distribution table.
table_waste(Config) when is_list(Config) ->
+ run_dist_configs(fun table_waste/2, Config).
+
+table_waste(DCfg, _Config) ->
{ok, HName} = inet:gethostname(),
F = fun(0,_F) -> [];
(N,F) ->
@@ -189,7 +194,7 @@ table_waste(Config) when is_list(Config) ->
F(N-1,F)
end,
F(256,F),
- {ok, N} = start_node(erl_distribution_300,""),
+ {ok, N} = start_node(DCfg, erl_distribution_300),
stop_node(N),
ok.
@@ -295,13 +300,16 @@ gethostname() ->
%% Test that pinging an illegal nodename does not kill the node.
illegal_nodenames(Config) when is_list(Config) ->
- PaDir = filename:dirname(code:which(erl_distribution_SUITE)),
- {ok, Node}=start_node(illegal_nodenames, "-pa " ++ PaDir),
+ run_dist_configs(fun illegal_nodenames/2, Config).
+
+illegal_nodenames(DCfg, _Config) ->
+ {ok, Node}=start_node(DCfg, illegal_nodenames),
monitor_node(Node, true),
RPid=rpc:call(Node, erlang, spawn,
[?MODULE, pinger, [self()]]),
receive
{RPid, pinged} ->
+ monitor_node(Node, false),
ok;
{nodedown, Node} ->
ct:fail("Remote node died.")
@@ -318,22 +326,25 @@ pinger(Starter) ->
%% Test that you can set the net_setuptime properly.
net_setuptime(Config) when is_list(Config) ->
+ run_dist_configs(fun net_setuptime/2, Config).
+
+net_setuptime(DCfg, _Config) ->
+
%% In this test case, we reluctantly accept shorter times than the given
%% setup time, because the connection attempt can end in a
%% "Host unreachable" error before the timeout fires.
- Res0 = do_test_setuptime("2"),
+ Res0 = do_test_setuptime(DCfg, "2"),
io:format("Res0 = ~p", [Res0]),
true = (Res0 =< 4000),
- Res1 = do_test_setuptime("0.3"),
+ Res1 = do_test_setuptime(DCfg, "0.3"),
io:format("Res1 = ~p", [Res1]),
true = (Res1 =< 500),
ok.
-do_test_setuptime(Setuptime) when is_list(Setuptime) ->
- PaDir = filename:dirname(code:which(?MODULE)),
- {ok, Node} = start_node(dist_setuptime_test, "-pa " ++ PaDir ++
- " -kernel net_setuptime " ++ Setuptime),
+do_test_setuptime(DCfg, Setuptime) when is_list(Setuptime) ->
+ {ok, Node} = start_node(DCfg, dist_setuptime_test,
+ "-kernel net_setuptime " ++ Setuptime),
Res = rpc:call(Node,?MODULE,time_ping,[?DUMMY_NODE]),
stop_node(Node),
Res.
@@ -399,32 +410,36 @@ tick_cli_test1(Node) ->
end.
setopts(Config) when is_list(Config) ->
+ run_dist_configs(fun setopts/2, Config).
+
+setopts(DCfg, _Config) ->
register(setopts_regname, self()),
[N1,N2,N3,N4] = get_nodenames(4, setopts),
- {_N1F,Port1} = start_node_unconnected(N1, ?MODULE, run_remote_test,
+ {_N1F,Port1} = start_node_unconnected(DCfg, N1, ?MODULE, run_remote_test,
["setopts_do", atom_to_list(node()), "1", "ping"]),
0 = wait_for_port_exit(Port1),
- {_N2F,Port2} = start_node_unconnected(N2, ?MODULE, run_remote_test,
+ {_N2F,Port2} = start_node_unconnected(DCfg, N2, ?MODULE, run_remote_test,
["setopts_do", atom_to_list(node()), "2", "ping"]),
0 = wait_for_port_exit(Port2),
{ok, LSock} = gen_tcp:listen(0, [{packet,2}, {active,false}]),
{ok, LTcpPort} = inet:port(LSock),
- {N3F,Port3} = start_node_unconnected(N3, ?MODULE, run_remote_test,
+ {N3F,Port3} = start_node_unconnected(DCfg, N3, ?MODULE, run_remote_test,
["setopts_do", atom_to_list(node()),
"1", integer_to_list(LTcpPort)]),
wait_and_connect(LSock, N3F, Port3),
0 = wait_for_port_exit(Port3),
- {N4F,Port4} = start_node_unconnected(N4, ?MODULE, run_remote_test,
+ {N4F,Port4} = start_node_unconnected(DCfg, N4, ?MODULE, run_remote_test,
["setopts_do", atom_to_list(node()),
"2", integer_to_list(LTcpPort)]),
wait_and_connect(LSock, N4F, Port4),
0 = wait_for_port_exit(Port4),
+ unregister(setopts_regname),
ok.
wait_and_connect(LSock, NodeName, NodePort) ->
@@ -518,9 +533,9 @@ opt_from_nr("2") -> {nodelay, false}.
change_val(true) -> false;
change_val(false) -> true.
-start_node_unconnected(Name, Mod, Func, Args) ->
+start_node_unconnected(DCfg, Name, Mod, Func, Args) ->
FullName = full_node_name(Name),
- CmdLine = mk_node_cmdline(Name,Mod,Func,Args),
+ CmdLine = mk_node_cmdline(DCfg, Name,Mod,Func,Args),
io:format("Starting node ~p: ~s~n", [FullName, CmdLine]),
case open_port({spawn, CmdLine}, [exit_status]) of
Port when is_port(Port) ->
@@ -534,7 +549,7 @@ full_node_name(PreName) ->
atom_to_list(node())),
list_to_atom(atom_to_list(PreName) ++ HostSuffix).
-mk_node_cmdline(Name,Mod,Func,Args) ->
+mk_node_cmdline(DCfg, Name,Mod,Func,Args) ->
Static = "-noinput",
Pa = filename:dirname(code:which(?MODULE)),
Prog = case catch init:get_argument(progname) of
@@ -551,6 +566,7 @@ mk_node_cmdline(Name,Mod,Func,Args) ->
Prog ++ " "
++ Static ++ " "
++ NameSw ++ " " ++ NameStr
+ ++ " " ++ DCfg
++ " -pa " ++ Pa
++ " -env ERL_CRASH_DUMP " ++ Pwd ++ "/erl_crash_dump." ++ NameStr
++ " -setcookie " ++ atom_to_list(erlang:get_cookie())
@@ -560,7 +576,9 @@ mk_node_cmdline(Name,Mod,Func,Args) ->
%% OTP-4255.
tick_change(Config) when is_list(Config) ->
- PaDir = filename:dirname(code:which(?MODULE)),
+ run_dist_configs(fun tick_change/2, Config).
+
+tick_change(DCfg, _Config) ->
[BN, CN] = get_nodenames(2, tick_change),
DefaultTT = net_kernel:get_net_ticktime(),
unchanged = net_kernel:set_net_ticktime(DefaultTT, 60),
@@ -577,14 +595,13 @@ tick_change(Config) when is_list(Config) ->
end,
wait_until(fun () -> 10 == net_kernel:get_net_ticktime() end),
- {ok, B} = start_node(BN, "-kernel net_ticktime 10 -pa " ++ PaDir),
- {ok, C} = start_node(CN, "-kernel net_ticktime 10 -hidden -pa "
- ++ PaDir),
+ {ok, B} = start_node(DCfg, BN, "-kernel net_ticktime 10"),
+ {ok, C} = start_node(DCfg, CN, "-kernel net_ticktime 10 -hidden"),
OTE = process_flag(trap_exit, true),
case catch begin
- run_tick_change_test(B, C, 10, 1, PaDir),
- run_tick_change_test(B, C, 1, 10, PaDir)
+ run_tick_change_test(DCfg, B, C, 10, 1),
+ run_tick_change_test(DCfg, B, C, 1, 10)
end of
{'EXIT', Reason} ->
stop_node(B),
@@ -626,7 +643,7 @@ wait_for_nodedowns(Tester, Ref) ->
end,
wait_for_nodedowns(Tester, Ref).
-run_tick_change_test(B, C, PrevTT, TT, PaDir) ->
+run_tick_change_test(DCfg, B, C, PrevTT, TT) ->
[DN, EN] = get_nodenames(2, tick_change),
Tester = self(),
@@ -640,8 +657,8 @@ run_tick_change_test(B, C, PrevTT, TT, PaDir) ->
wait_for_nodedowns(Tester, Ref)
end,
- {ok, D} = start_node(DN, "-kernel net_ticktime "
- ++ integer_to_list(PrevTT) ++ " -pa " ++ PaDir),
+ {ok, D} = start_node(DCfg, DN, "-kernel net_ticktime "
+ ++ integer_to_list(PrevTT)),
NMA = spawn_link(fun () -> MonitorNodes([B, C, D]) end),
NMB = spawn_link(B, fun () -> MonitorNodes([node(), C, D]) end),
@@ -674,8 +691,8 @@ run_tick_change_test(B, C, PrevTT, TT, PaDir) ->
sleep(7),
change_initiated = rpc:call(C,net_kernel,set_net_ticktime,[TT,10]),
- {ok, E} = start_node(EN, "-kernel net_ticktime "
- ++ integer_to_list(TT) ++ " -pa " ++ PaDir),
+ {ok, E} = start_node(DCfg, EN, "-kernel net_ticktime "
+ ++ integer_to_list(TT)),
NME = spawn_link(E, fun () -> MonitorNodes([node(), B, C, D]) end),
NMA2 = spawn_link(fun () -> MonitorNodes([E]) end),
NMB2 = spawn_link(B, fun () -> MonitorNodes([E]) end),
@@ -735,12 +752,13 @@ run_tick_change_test(B, C, PrevTT, TT, PaDir) ->
%%
%% Basic test of hidden node.
hidden_node(Config) when is_list(Config) ->
- PaDir = filename:dirname(code:which(?MODULE)),
- VArgs = "-pa " ++ PaDir,
- HArgs = "-hidden -pa " ++ PaDir,
- {ok, V} = start_node(visible_node, VArgs),
+ run_dist_configs(fun hidden_node/2, Config).
+
+hidden_node(DCfg, _Config) ->
+ HArgs = "-hidden",
+ {ok, V} = start_node(DCfg, visible_node),
VMN = start_monitor_nodes_proc(V),
- {ok, H} = start_node(hidden_node, HArgs),
+ {ok, H} = start_node(DCfg, hidden_node, HArgs),
%% Connect visible_node -> hidden_node
connect_nodes(V, H),
test_nodes(V, H),
@@ -748,9 +766,9 @@ hidden_node(Config) when is_list(Config) ->
sleep(5),
check_monitor_nodes_res(VMN, H),
stop_node(V),
- {ok, H} = start_node(hidden_node, HArgs),
+ {ok, H} = start_node(DCfg, hidden_node, HArgs),
HMN = start_monitor_nodes_proc(H),
- {ok, V} = start_node(visible_node, VArgs),
+ {ok, V} = start_node(DCfg, visible_node),
%% Connect hidden_node -> visible_node
connect_nodes(H, V),
test_nodes(V, H),
@@ -850,9 +868,9 @@ do_inet_dist_options_options(Prio) ->
"-kernel inet_dist_connect_options "++PriorityString++" "
"-kernel inet_dist_listen_options "++PriorityString,
{ok,Node1} =
- start_node(inet_dist_options_1, InetDistOptions),
+ start_node("", inet_dist_options_1, InetDistOptions),
{ok,Node2} =
- start_node(inet_dist_options_2, InetDistOptions),
+ start_node("", inet_dist_options_2, InetDistOptions),
%%
pong =
rpc:call(Node1, net_adm, ping, [Node2]),
@@ -885,6 +903,9 @@ get_socket_priorities() ->
%%
monitor_nodes_nodedown_reason(Config) when is_list(Config) ->
+ run_dist_configs(fun monitor_nodes_nodedown_reason/2, Config).
+
+monitor_nodes_nodedown_reason(DCfg, _Config) ->
MonNodeState = monitor_node_state(),
ok = net_kernel:monitor_nodes(true),
ok = net_kernel:monitor_nodes(true, [nodedown_reason]),
@@ -892,10 +913,10 @@ monitor_nodes_nodedown_reason(Config) when is_list(Config) ->
Names = get_numbered_nodenames(5, node),
[NN1, NN2, NN3, NN4, NN5] = Names,
- {ok, N1} = start_node(NN1),
- {ok, N2} = start_node(NN2),
- {ok, N3} = start_node(NN3),
- {ok, N4} = start_node(NN4, "-hidden"),
+ {ok, N1} = start_node(DCfg, NN1),
+ {ok, N2} = start_node(DCfg, NN2),
+ {ok, N3} = start_node(DCfg, NN3),
+ {ok, N4} = start_node(DCfg, NN4, "-hidden"),
receive {nodeup, N1} -> ok end,
receive {nodeup, N2} -> ok end,
@@ -925,7 +946,7 @@ monitor_nodes_nodedown_reason(Config) when is_list(Config) ->
ok = net_kernel:monitor_nodes(false, [nodedown_reason]),
- {ok, N5} = start_node(NN5),
+ {ok, N5} = start_node(DCfg, NN5),
stop_node(N5),
receive {nodeup, N5} -> ok end,
@@ -938,11 +959,14 @@ monitor_nodes_nodedown_reason(Config) when is_list(Config) ->
monitor_nodes_complex_nodedown_reason(Config) when is_list(Config) ->
+ run_dist_configs(fun monitor_nodes_complex_nodedown_reason/2, Config).
+
+monitor_nodes_complex_nodedown_reason(DCfg, _Config) ->
MonNodeState = monitor_node_state(),
Me = self(),
ok = net_kernel:monitor_nodes(true, [nodedown_reason]),
[Name] = get_nodenames(1, monitor_nodes_complex_nodedown_reason),
- {ok, Node} = start_node(Name, ""),
+ {ok, Node} = start_node(DCfg, Name, ""),
Pid = spawn(Node,
fun() ->
Me ! {stuff,
@@ -981,16 +1005,19 @@ monitor_nodes_complex_nodedown_reason(Config) when is_list(Config) ->
%%
monitor_nodes_node_type(Config) when is_list(Config) ->
+ run_dist_configs(fun monitor_nodes_node_type/2, Config).
+
+monitor_nodes_node_type(DCfg, _Config) ->
MonNodeState = monitor_node_state(),
ok = net_kernel:monitor_nodes(true),
ok = net_kernel:monitor_nodes(true, [{node_type, all}]),
Names = get_numbered_nodenames(9, node),
[NN1, NN2, NN3, NN4, NN5, NN6, NN7, NN8, NN9] = Names,
- {ok, N1} = start_node(NN1),
- {ok, N2} = start_node(NN2),
- {ok, N3} = start_node(NN3, "-hidden"),
- {ok, N4} = start_node(NN4, "-hidden"),
+ {ok, N1} = start_node(DCfg, NN1),
+ {ok, N2} = start_node(DCfg, NN2),
+ {ok, N3} = start_node(DCfg, NN3, "-hidden"),
+ {ok, N4} = start_node(DCfg, NN4, "-hidden"),
receive {nodeup, N1} -> ok end,
receive {nodeup, N2} -> ok end,
@@ -1014,15 +1041,15 @@ monitor_nodes_node_type(Config) when is_list(Config) ->
receive {nodedown, N4, [{node_type, hidden}]} -> ok end,
ok = net_kernel:monitor_nodes(false, [{node_type, all}]),
- {ok, N5} = start_node(NN5),
+ {ok, N5} = start_node(DCfg, NN5),
receive {nodeup, N5} -> ok end,
stop_node(N5),
receive {nodedown, N5} -> ok end,
ok = net_kernel:monitor_nodes(true, [{node_type, hidden}]),
- {ok, N6} = start_node(NN6),
- {ok, N7} = start_node(NN7, "-hidden"),
+ {ok, N6} = start_node(DCfg, NN6),
+ {ok, N7} = start_node(DCfg, NN7, "-hidden"),
receive {nodeup, N6} -> ok end,
@@ -1037,8 +1064,8 @@ monitor_nodes_node_type(Config) when is_list(Config) ->
ok = net_kernel:monitor_nodes(false, [{node_type, hidden}]),
ok = net_kernel:monitor_nodes(false),
- {ok, N8} = start_node(NN8),
- {ok, N9} = start_node(NN9, "-hidden"),
+ {ok, N8} = start_node(DCfg, NN8),
+ {ok, N9} = start_node(DCfg, NN9, "-hidden"),
receive {nodeup, N8, [{node_type, visible}]} -> ok end,
stop_node(N8),
@@ -1058,6 +1085,9 @@ monitor_nodes_node_type(Config) when is_list(Config) ->
%%
monitor_nodes_misc(Config) when is_list(Config) ->
+ run_dist_configs(fun monitor_nodes_misc/2, Config).
+
+monitor_nodes_misc(DCfg, _Config) ->
MonNodeState = monitor_node_state(),
ok = net_kernel:monitor_nodes(true),
ok = net_kernel:monitor_nodes(true, [{node_type, all}, nodedown_reason]),
@@ -1065,8 +1095,8 @@ monitor_nodes_misc(Config) when is_list(Config) ->
Names = get_numbered_nodenames(3, node),
[NN1, NN2, NN3] = Names,
- {ok, N1} = start_node(NN1),
- {ok, N2} = start_node(NN2, "-hidden"),
+ {ok, N1} = start_node(DCfg, NN1),
+ {ok, N2} = start_node(DCfg, NN2, "-hidden"),
receive {nodeup, N1} -> ok end,
@@ -1092,7 +1122,7 @@ monitor_nodes_misc(Config) when is_list(Config) ->
ok = net_kernel:monitor_nodes(false, [{node_type, all}, nodedown_reason]),
- {ok, N3} = start_node(NN3),
+ {ok, N3} = start_node(DCfg, NN3),
receive {nodeup, N3} -> ok end,
stop_node(N3),
receive {nodedown, N3} -> ok end,
@@ -1107,15 +1137,18 @@ monitor_nodes_misc(Config) when is_list(Config) ->
%% messages from Node and that {nodedown, Node} messages are
%% received after messages from Node.
monitor_nodes_otp_6481(Config) when is_list(Config) ->
+ run_dist_configs(fun monitor_nodes_otp_6481/2, Config).
+
+monitor_nodes_otp_6481(DCfg, Config) ->
io:format("Testing nodedown...~n"),
- monitor_nodes_otp_6481_test(Config, nodedown),
+ monitor_nodes_otp_6481_test(DCfg, Config, nodedown),
io:format("ok~n"),
io:format("Testing nodeup...~n"),
- monitor_nodes_otp_6481_test(Config, nodeup),
+ monitor_nodes_otp_6481_test(DCfg, Config, nodeup),
io:format("ok~n"),
ok.
-monitor_nodes_otp_6481_test(Config, TestType) when is_list(Config) ->
+monitor_nodes_otp_6481_test(DCfg, Config, TestType) when is_list(Config) ->
MonNodeState = monitor_node_state(),
NodeMsg = make_ref(),
Me = self(),
@@ -1164,7 +1197,7 @@ monitor_nodes_otp_6481_test(Config, TestType) when is_list(Config) ->
end
++ MonNodeState,
- {ok, Node} = start_node(Name, "", this),
+ {ok, Node} = start_node(DCfg, Name, "", this),
receive {nodeup, Node} -> ok end,
RemotePid = spawn(Node,
@@ -1249,17 +1282,20 @@ monitor_nodes_errors(Config) when is_list(Config) ->
ok.
monitor_nodes_combinations(Config) when is_list(Config) ->
+ run_dist_configs(fun monitor_nodes_combinations/2, Config).
+
+monitor_nodes_combinations(DCfg, _Config) ->
MonNodeState = monitor_node_state(),
monitor_nodes_all_comb(true),
[VisibleName, HiddenName] = get_nodenames(2,
monitor_nodes_combinations),
- {ok, Visible} = start_node(VisibleName, ""),
+ {ok, Visible} = start_node(DCfg, VisibleName, ""),
receive_all_comb_nodeup_msgs(visible, Visible),
no_msgs(),
stop_node(Visible),
receive_all_comb_nodedown_msgs(visible, Visible, connection_closed),
no_msgs(),
- {ok, Hidden} = start_node(HiddenName, "-hidden"),
+ {ok, Hidden} = start_node(DCfg, HiddenName, "-hidden"),
receive_all_comb_nodeup_msgs(hidden, Hidden),
no_msgs(),
stop_node(Hidden),
@@ -1395,6 +1431,9 @@ monitor_nodes_cleanup(Config) when is_list(Config) ->
ok.
monitor_nodes_many(Config) when is_list(Config) ->
+ run_dist_configs(fun monitor_nodes_many/2, Config).
+
+monitor_nodes_many(DCfg, _Config) ->
MonNodeState = monitor_node_state(),
[Name] = get_nodenames(1, monitor_nodes_many),
%% We want to perform more than 2^16 net_kernel:monitor_nodes
@@ -1402,7 +1441,7 @@ monitor_nodes_many(Config) when is_list(Config) ->
No = (1 bsl 16) + 17,
repeat(fun () -> ok = net_kernel:monitor_nodes(true) end, No),
No = length(monitor_node_state()) - length(MonNodeState),
- {ok, Node} = start_node(Name),
+ {ok, Node} = start_node(DCfg, Name),
repeat(fun () -> receive {nodeup, Node} -> ok end end, No),
stop_node(Node),
repeat(fun () -> receive {nodedown, Node} -> ok end end, No),
@@ -1411,8 +1450,118 @@ monitor_nodes_many(Config) when is_list(Config) ->
MonNodeState = monitor_node_state(),
ok.
+dist_ctrl_proc_smoke(Config) when is_list(Config) ->
+ ThisNode = node(),
+ [Name1, Name2] = get_nodenames(2, dist_ctrl_proc_example_smoke),
+ GetSizeArg = " -gen_tcp_dist_output_loop "
+ ++ atom_to_list(?MODULE) ++ " "
+ ++ "dist_cntrlr_output_test",
+ {ok, Node1} = start_node("", Name1, "-proto_dist gen_tcp"),
+ {ok, Node2} = start_node("", Name2, "-proto_dist gen_tcp" ++ GetSizeArg),
+ pong = rpc:call(Node1, net_adm, ping, [Node2]),
+ NL1 = lists:sort([ThisNode, Node2]),
+ NL2 = lists:sort([ThisNode, Node1]),
+ NL1 = lists:sort(rpc:call(Node1, erlang, nodes, [])),
+ NL2 = lists:sort(rpc:call(Node2, erlang, nodes, [])),
+
+ %% Verify that we actually are executing the distribution
+ %% module we expect and also massage message passing over
+ %% it a bit...
+ Ps1 = rpc:call(Node1, erlang, processes, []),
+ try
+ lists:foreach(
+ fun (P) ->
+ case rpc:call(Node1, erlang, process_info, [P, current_stacktrace]) of
+ undefined ->
+ ok;
+ {current_stacktrace, StkTrace} ->
+ lists:foreach(fun ({gen_tcp_dist,
+ dist_cntrlr_output_loop,
+ 2, _}) ->
+ io:format("~p ~p~n", [P, StkTrace]),
+ throw(found_it);
+ (_) ->
+ ok
+ end, StkTrace)
+ end
+ end, Ps1),
+ exit({missing, dist_cntrlr_output_loop})
+ catch
+ throw:found_it -> ok
+ end,
+
+ Ps2 = rpc:call(Node2, erlang, processes, []),
+ try
+ lists:foreach(
+ fun (P) ->
+ case rpc:call(Node2, erlang, process_info, [P, current_stacktrace]) of
+ undefined ->
+ ok;
+ {current_stacktrace, StkTrace} ->
+ lists:foreach(fun ({erl_distribution_SUITE,
+ dist_cntrlr_output_loop,
+ 2, _}) ->
+ io:format("~p ~p~n", [P, StkTrace]),
+ throw(found_it);
+ (_) ->
+ ok
+ end, StkTrace)
+ end
+ end, Ps2),
+ exit({missing, dist_cntrlr_output_loop})
+ catch
+ throw:found_it -> ok
+ end,
+
+ stop_node(Node1),
+ stop_node(Node2),
+ ok.
+
%% Misc. functions
+run_dist_configs(Func, Config) ->
+ GetSizeArg = " -gen_tcp_dist_output_loop "
+ ++ atom_to_list(?MODULE) ++ " "
+ ++ "dist_cntrlr_output_test",
+ lists:map(fun ({DCfgName, DCfg}) ->
+ io:format("~n~n=== Running ~s configuration ===~n~n",
+ [DCfgName]),
+ Func(DCfg, Config)
+ end,
+ [{"default", ""},
+ {"gen_tcp_dist", "-proto_dist gen_tcp"},
+ {"gen_tcp_dist (get_size)", "-proto_dist gen_tcp" ++ GetSizeArg}]).
+
+dist_cntrlr_output_test(DHandle, Socket) ->
+ false = erlang:dist_ctrl_get_opt(DHandle, get_size),
+ false = erlang:dist_ctrl_set_opt(DHandle, get_size, true),
+ true = erlang:dist_ctrl_get_opt(DHandle, get_size),
+ true = erlang:dist_ctrl_set_opt(DHandle, get_size, false),
+ false = erlang:dist_ctrl_get_opt(DHandle, get_size),
+ false = erlang:dist_ctrl_set_opt(DHandle, get_size, true),
+ true = erlang:dist_ctrl_get_opt(DHandle, get_size),
+ dist_cntrlr_output_loop(DHandle, Socket).
+
+dist_cntrlr_send_data(DHandle, Socket) ->
+ case erlang:dist_ctrl_get_data(DHandle) of
+ none ->
+ erlang:dist_ctrl_get_data_notification(DHandle);
+ {Size, Data} ->
+ Size = erlang:iolist_size(Data),
+ ok = gen_tcp:send(Socket, Data),
+ dist_cntrlr_send_data(DHandle, Socket)
+ end.
+
+dist_cntrlr_output_loop(DHandle, Socket) ->
+ receive
+ dist_data ->
+ %% Outgoing data from this node...
+ dist_cntrlr_send_data(DHandle, Socket);
+ _ ->
+ ok %% Drop garbage message...
+ end,
+ dist_cntrlr_output_loop(DHandle, Socket).
+
monitor_node_state() ->
erts_debug:set_internal_state(available_internal_state, true),
MonitoringNodes = erts_debug:get_internal_state(monitoring_nodes),
@@ -1438,25 +1587,25 @@ print_my_messages() ->
sleep(T) -> receive after T * 1000 -> ok end.
-start_node(Name, Param, this) ->
+start_node(DCfg, Name, Param, this) ->
NewParam = Param ++ " -pa " ++ filename:dirname(code:which(?MODULE)),
test_server:start_node(Name, peer, [{args, NewParam}, {erl, [this]}]);
-start_node(Name, Param, "this") ->
- NewParam = Param ++ " -pa " ++ filename:dirname(code:which(?MODULE)),
+start_node(DCfg, Name, Param, "this") ->
+ NewParam = Param ++ " -pa " ++ filename:dirname(code:which(?MODULE)) ++ " " ++ DCfg,
test_server:start_node(Name, peer, [{args, NewParam}, {erl, [this]}]);
-start_node(Name, Param, Rel) when is_atom(Rel) ->
- NewParam = Param ++ " -pa " ++ filename:dirname(code:which(?MODULE)),
+start_node(DCfg, Name, Param, Rel) when is_atom(Rel) ->
+ NewParam = Param ++ " -pa " ++ filename:dirname(code:which(?MODULE)) ++ " " ++ DCfg,
test_server:start_node(Name, peer, [{args, NewParam}, {erl, [{release, atom_to_list(Rel)}]}]);
-start_node(Name, Param, Rel) when is_list(Rel) ->
- NewParam = Param ++ " -pa " ++ filename:dirname(code:which(?MODULE)),
+start_node(DCfg, Name, Param, Rel) when is_list(Rel) ->
+ NewParam = Param ++ " -pa " ++ filename:dirname(code:which(?MODULE)) ++ " " ++ DCfg,
test_server:start_node(Name, peer, [{args, NewParam}, {erl, [{release, Rel}]}]).
-start_node(Name, Param) ->
- NewParam = Param ++ " -pa " ++ filename:dirname(code:which(?MODULE)),
+start_node(DCfg, Name, Param) ->
+ NewParam = Param ++ " -pa " ++ filename:dirname(code:which(?MODULE)) ++ " " ++ DCfg,
test_server:start_node(Name, slave, [{args, NewParam}]).
-start_node(Name) ->
- start_node(Name, "").
+start_node(DCfg, Name) ->
+ start_node(DCfg, Name, "").
stop_node(Node) ->
test_server:stop_node(Node).
diff --git a/lib/kernel/test/gen_sctp_SUITE.erl b/lib/kernel/test/gen_sctp_SUITE.erl
index a0ae792ba9..e4c489bd10 100644
--- a/lib/kernel/test/gen_sctp_SUITE.erl
+++ b/lib/kernel/test/gen_sctp_SUITE.erl
@@ -1459,11 +1459,11 @@ do_open_and_connect(ServerAddresses, AddressToConnectTo) ->
do_open_and_connect(ServerAddresses, AddressToConnectTo, Fun).
%%
do_open_and_connect(ServerAddresses, AddressToConnectTo, Fun) ->
- ServerFamily = get_family_by_addrs(ServerAddresses),
+ {ServerFamily, ServerOpts} = get_family_by_addrs(ServerAddresses),
io:format("Serving ~p addresses: ~p~n",
[ServerFamily, ServerAddresses]),
S1 = ok(gen_sctp:open(0, [{ip,Addr} || Addr <- ServerAddresses] ++
- [ServerFamily])),
+ [ServerFamily|ServerOpts])),
ok = gen_sctp:listen(S1, true),
P1 = ok(inet:port(S1)),
ClientFamily = get_family_by_addr(AddressToConnectTo),
@@ -1493,9 +1493,9 @@ do_open_and_connect(ServerAddresses, AddressToConnectTo, Fun) ->
%% If at least one of the addresses is an ipv6 address, return inet6, else inet.
get_family_by_addrs(Addresses) ->
case lists:usort([get_family_by_addr(Addr) || Addr <- Addresses]) of
- [inet, inet6] -> inet6;
- [inet] -> inet;
- [inet6] -> inet6
+ [inet, inet6] -> {inet6, [{ipv6_v6only, false}]};
+ [inet] -> {inet, []};
+ [inet6] -> {inet6, []}
end.
get_family_by_addr(Addr) when tuple_size(Addr) =:= 4 -> inet;
diff --git a/lib/kernel/test/gen_tcp_api_SUITE_data/gen_tcp_api_SUITE.c b/lib/kernel/test/gen_tcp_api_SUITE_data/gen_tcp_api_SUITE.c
index b91dca61d4..96938f9071 100644
--- a/lib/kernel/test/gen_tcp_api_SUITE_data/gen_tcp_api_SUITE.c
+++ b/lib/kernel/test/gen_tcp_api_SUITE_data/gen_tcp_api_SUITE.c
@@ -30,6 +30,7 @@
#define sock_close(s) closesocket(s)
#else
#include <sys/socket.h>
+#include <unistd.h>
#define sock_close(s) close(s)
#endif
diff --git a/lib/kernel/test/gen_tcp_misc_SUITE.erl b/lib/kernel/test/gen_tcp_misc_SUITE.erl
index 52edfaee29..edf30448c4 100644
--- a/lib/kernel/test/gen_tcp_misc_SUITE.erl
+++ b/lib/kernel/test/gen_tcp_misc_SUITE.erl
@@ -2086,8 +2086,39 @@ test_pktoptions(Family, Spec, CheckConnect, OSType, OSVer) ->
%%% {ok,<<"hi">>} = gen_tcp:recv(S1, 2, Timeout),
%%
%% Verify returned remote options
- {ok,[{pktoptions,OptsVals1}]} = inet:getopts(S1, [pktoptions]),
- {ok,[{pktoptions,OptsVals2}]} = inet:getopts(S2, [pktoptions]),
+ VerifyRemOpts =
+ fun(S, Role) ->
+ case inet:getopts(S, [pktoptions]) of
+ {ok, [{pktoptions, PktOpts1}]} ->
+ PktOpts1;
+ {ok, UnexpOK1} ->
+ io:format("Unexpected OK (~w): "
+ "~n ~p"
+ "~n", [Role, UnexpOK1]),
+ exit({unexpected_getopts_ok,
+ Role,
+ Spec,
+ TrueRecvOpts,
+ OptsVals,
+ OptsValsDefault,
+ UnexpOK1});
+ {error, UnexpERR1} ->
+ io:format("Unexpected ERROR (~w): "
+ "~n ~p"
+ "~n", [Role, UnexpERR1]),
+ exit({unexpected_getopts_failure,
+ Role,
+ Spec,
+ TrueRecvOpts,
+ OptsVals,
+ OptsValsDefault,
+ UnexpERR1})
+ end
+ end,
+ OptsVals1 = VerifyRemOpts(S1, dest),
+ OptsVals2 = VerifyRemOpts(S2, orig),
+ %% {ok,[{pktoptions,OptsVals1}]} = inet:getopts(S1, [pktoptions]),
+ %% {ok,[{pktoptions,OptsVals2}]} = inet:getopts(S2, [pktoptions]),
(Result1 = sets_eq(OptsVals1, OptsVals))
orelse io:format(
"Accept differs: ~p neq ~p~n", [OptsVals1,OptsVals]),
@@ -3430,7 +3461,7 @@ wait(Mref) ->
%% OTP-15536
%% Test that send error works correctly for delay_send
-delay_send_error(Config) ->
+delay_send_error(_Config) ->
{ok, LS} = gen_tcp:listen(0, [{reuseaddr, true}, {packet, 1}, {active, false}]),
{ok,{{0,0,0,0},PortNum}}=inet:sockname(LS),
P = spawn_link(
diff --git a/lib/ssl/src/ssl_record.erl b/lib/ssl/src/ssl_record.erl
index 669626aefb..91f1876980 100644
--- a/lib/ssl/src/ssl_record.erl
+++ b/lib/ssl/src/ssl_record.erl
@@ -395,7 +395,12 @@ decipher_aead(Type, #cipher_state{key = Key} = CipherState, AAD0, CipherFragment
try
Nonce = decrypt_nonce(Type, CipherState, CipherFragment),
{AAD, CipherText, CipherTag} = aead_ciphertext_split(Type, CipherState, CipherFragment, AAD0),
- ssl_cipher:aead_decrypt(Type, Key, Nonce, CipherText, CipherTag, AAD)
+ case ssl_cipher:aead_decrypt(Type, Key, Nonce, CipherText, CipherTag, AAD) of
+ Content when is_binary(Content) ->
+ Content;
+ _ ->
+ ?ALERT_REC(?FATAL, ?BAD_RECORD_MAC, decryption_failed)
+ end
catch
_:_ ->
?ALERT_REC(?FATAL, ?BAD_RECORD_MAC, decryption_failed)
diff --git a/lib/ssl/src/tls_handshake_1_3.erl b/lib/ssl/src/tls_handshake_1_3.erl
index 1e8b046c1e..0efedf3400 100644
--- a/lib/ssl/src/tls_handshake_1_3.erl
+++ b/lib/ssl/src/tls_handshake_1_3.erl
@@ -1007,7 +1007,8 @@ update_start_state(#state{connection_states = ConnectionStates0,
session = Session#session{session_id = SessionId,
ecc = Group,
sign_alg = SelectedSignAlg,
- dh_public_value = ClientPubKey},
+ dh_public_value = ClientPubKey,
+ cipher_suite = Cipher},
connection_env = CEnv#connection_env{negotiated_version = {3,4}}}.
diff --git a/lib/ssl/src/tls_record_1_3.erl b/lib/ssl/src/tls_record_1_3.erl
index 5f1c64eae6..97331e1510 100644
--- a/lib/ssl/src/tls_record_1_3.erl
+++ b/lib/ssl/src/tls_record_1_3.erl
@@ -267,7 +267,12 @@ decipher_aead(CipherFragment, BulkCipherAlgo, Key, Seq, IV, TagLen) ->
AAD = additional_data(erlang:iolist_size(CipherFragment)),
Nonce = nonce(Seq, IV),
{CipherText, CipherTag} = aead_ciphertext_split(CipherFragment, TagLen),
- ssl_cipher:aead_decrypt(BulkCipherAlgo, Key, Nonce, CipherText, CipherTag, AAD)
+ case ssl_cipher:aead_decrypt(BulkCipherAlgo, Key, Nonce, CipherText, CipherTag, AAD) of
+ Content when is_binary(Content) ->
+ Content;
+ _ ->
+ ?ALERT_REC(?FATAL, ?BAD_RECORD_MAC, decryption_failed)
+ end
catch
_:_ ->
?ALERT_REC(?FATAL, ?BAD_RECORD_MAC, decryption_failed)
diff --git a/lib/ssl/test/ssl_basic_SUITE.erl b/lib/ssl/test/ssl_basic_SUITE.erl
index ff5638ff34..cbc0c2e70b 100644
--- a/lib/ssl/test/ssl_basic_SUITE.erl
+++ b/lib/ssl/test/ssl_basic_SUITE.erl
@@ -289,7 +289,8 @@ tls13_test_group() ->
tls13_hrr_client_auth_empty_cert_ssl_server_openssl_client,
tls13_hrr_client_auth_ssl_server_openssl_client,
tls13_unsupported_sign_algo_client_auth_ssl_server_openssl_client,
- tls13_unsupported_sign_algo_cert_client_auth_ssl_server_openssl_client].
+ tls13_unsupported_sign_algo_cert_client_auth_ssl_server_openssl_client,
+ tls13_connection_information].
%%--------------------------------------------------------------------
init_per_suite(Config0) ->
@@ -5849,6 +5850,29 @@ tls13_unsupported_sign_algo_cert_client_auth_ssl_server_openssl_client(Config) -
ssl_test_lib:close_port(Client).
+tls13_connection_information() ->
+ [{doc,"Test the API function ssl:connection_information/1 in a TLS 1.3 connection"}].
+
+tls13_connection_information(Config) ->
+ ClientOpts = ssl_test_lib:ssl_options(client_rsa_opts, Config),
+ ServerOpts0 = ssl_test_lib:ssl_options(server_rsa_opts, Config),
+ %% Set versions
+ ServerOpts = [{versions, ['tlsv1.2','tlsv1.3']}|ServerOpts0],
+ {_ClientNode, ServerNode, _Hostname} = ssl_test_lib:run_where(Config),
+
+ Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
+ {from, self()},
+ {mfa, {?MODULE, connection_information_result, []}},
+ {options, ServerOpts}]),
+ Port = ssl_test_lib:inet_port(Server),
+
+ Client = ssl_test_lib:start_basic_client(openssl, 'tlsv1.3', Port, ClientOpts),
+
+ ssl_test_lib:check_result(Server, ok),
+ ssl_test_lib:close(Server),
+ ssl_test_lib:close_port(Client).
+
+
%%--------------------------------------------------------------------
%% Internal functions ------------------------------------------------
%%--------------------------------------------------------------------
diff --git a/lib/stdlib/src/Makefile b/lib/stdlib/src/Makefile
index c95f7637f7..86003c953d 100644
--- a/lib/stdlib/src/Makefile
+++ b/lib/stdlib/src/Makefile
@@ -155,8 +155,10 @@ APPUP_TARGET= $(EBIN)/$(APPUP_FILE)
ifeq ($(NATIVE_LIBS_ENABLED),yes)
ERL_COMPILE_FLAGS += +native
+else
+ERL_COMPILE_FLAGS += -Werror
endif
-ERL_COMPILE_FLAGS += -I../include -I../../kernel/include -Werror
+ERL_COMPILE_FLAGS += -I../include -I../../kernel/include
# ----------------------------------------------------
# Targets
diff --git a/lib/tools/emacs/erlang.el b/lib/tools/emacs/erlang.el
index 3cbe9daa60..38c0eba92b 100644
--- a/lib/tools/emacs/erlang.el
+++ b/lib/tools/emacs/erlang.el
@@ -905,8 +905,10 @@ resulting regexp is surrounded by \\_< and \\_>."
"dist_get_stat"
"dist_ctrl_get_data"
"dist_ctrl_get_data_notification"
+ "dist_ctrl_get_opt"
"dist_ctrl_input_handler"
"dist_ctrl_put_data"
+ "dist_ctrl_set_opt"
"dmonitor_node"
"dt_append_vm_tag_data"
"dt_get_tag"
diff --git a/lib/xmerl/doc/src/notes.xml b/lib/xmerl/doc/src/notes.xml
index 7f6874e36b..d6b6dfdfb5 100644
--- a/lib/xmerl/doc/src/notes.xml
+++ b/lib/xmerl/doc/src/notes.xml
@@ -32,6 +32,28 @@
<p>This document describes the changes made to the Xmerl application.</p>
+<section><title>Xmerl 1.3.20</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ Handling of character references in attributes are fixed.</p>
+ <p>
+ Own Id: OTP-15684 Aux Id: ERL-837 </p>
+ </item>
+ <item>
+ <p>
+ Normalization of whitespace characters in attributes are
+ fixed so it works when character references are used.</p>
+ <p>
+ Own Id: OTP-15685 Aux Id: ERL-475 </p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
<section><title>Xmerl 1.3.19</title>
<section><title>Fixed Bugs and Malfunctions</title>
diff --git a/lib/xmerl/src/xmerl_scan.erl b/lib/xmerl/src/xmerl_scan.erl
index e543a5a11e..d76ed5c820 100644
--- a/lib/xmerl/src/xmerl_scan.erl
+++ b/lib/xmerl/src/xmerl_scan.erl
@@ -2410,15 +2410,22 @@ scan_att_chars("&" ++ T, S0, Delim, Acc, TmpAcc,AT,IsNorm) -> % Reference
true ->
scan_att_chars(T1,S1,Delim,[ExpRef|Acc],[ExpRef|TmpAcc],AT,IsNorm);
_ ->
- Ch = string_to_char_set(S#xmerl_scanner.encoding, ExpRef),
case T of
"#" ++ _ ->
%% normalization rules (sec 3.3.3) require that for
%% character references, the referenced character be
%% added directly to the normalized value
- scan_att_chars(T1, S1, Delim, Ch ++ Acc,TmpAcc, AT,IsNorm);
+ {T2,S2,IsNorm2} =
+ if
+ ?whitespace(hd(ExpRef)) ->
+ normalize(T1, S1, IsNorm);
+ true ->
+ {T1, S1, IsNorm}
+ end,
+ scan_att_chars(T2, S2, Delim, ExpRef ++ Acc, TmpAcc, AT, IsNorm2);
_ ->
- scan_att_chars(Ch ++ T1, S1, Delim, Acc,TmpAcc, AT,IsNorm)
+ Ch = string_to_char_set(S#xmerl_scanner.encoding, ExpRef),
+ scan_att_chars(Ch ++ T1, S1, Delim, Acc, TmpAcc, AT, IsNorm)
end
end;
scan_att_chars("<" ++ _T, S0, _Delim, _Acc,_, _,_) -> % Tags not allowed here
@@ -3964,7 +3971,7 @@ normalize(T,S,IsNorm) ->
{_,T,S} ->
{T,S,IsNorm};
{_,T1,S1} ->
- {T1,S1,true}
+ normalize(T1,S1,true)
end.
diff --git a/lib/xmerl/vsn.mk b/lib/xmerl/vsn.mk
index b6486681c2..31ffa6e749 100644
--- a/lib/xmerl/vsn.mk
+++ b/lib/xmerl/vsn.mk
@@ -1 +1 @@
-XMERL_VSN = 1.3.19
+XMERL_VSN = 1.3.20
diff --git a/make/otp_patch_solve_forward_merge_version b/make/otp_patch_solve_forward_merge_version
index 7f8f011eb7..45a4fb75db 100644
--- a/make/otp_patch_solve_forward_merge_version
+++ b/make/otp_patch_solve_forward_merge_version
@@ -1 +1 @@
-7
+8
diff --git a/otp_versions.table b/otp_versions.table
index a31759a8ef..cc5d331b06 100644
--- a/otp_versions.table
+++ b/otp_versions.table
@@ -1,3 +1,4 @@
+OTP-21.3.2 : erts-10.3.1 xmerl-1.3.20 # asn1-5.0.8 common_test-1.17 compiler-7.3.2 crypto-4.4.1 debugger-4.2.6 dialyzer-3.3.2 diameter-2.2 edoc-0.10 eldap-1.2.6 erl_docgen-0.9 erl_interface-3.11.1 et-1.6.4 eunit-2.3.7 ftp-1.0.2 hipe-3.18.3 inets-7.0.6 jinterface-1.9.1 kernel-6.3 megaco-3.18.4 mnesia-4.15.6 observer-2.9 odbc-2.12.3 os_mon-2.4.7 otp_mibs-1.2.1 parsetools-2.1.8 public_key-1.6.5 reltool-0.7.8 runtime_tools-1.13.2 sasl-3.3 snmp-5.2.12 ssh-4.7.4 ssl-9.2.1 stdlib-3.8 syntax_tools-2.1.7 tftp-1.0.1 tools-3.1 wx-1.8.7 :
OTP-21.3.1 : erl_interface-3.11.1 ssl-9.2.1 # asn1-5.0.8 common_test-1.17 compiler-7.3.2 crypto-4.4.1 debugger-4.2.6 dialyzer-3.3.2 diameter-2.2 edoc-0.10 eldap-1.2.6 erl_docgen-0.9 erts-10.3 et-1.6.4 eunit-2.3.7 ftp-1.0.2 hipe-3.18.3 inets-7.0.6 jinterface-1.9.1 kernel-6.3 megaco-3.18.4 mnesia-4.15.6 observer-2.9 odbc-2.12.3 os_mon-2.4.7 otp_mibs-1.2.1 parsetools-2.1.8 public_key-1.6.5 reltool-0.7.8 runtime_tools-1.13.2 sasl-3.3 snmp-5.2.12 ssh-4.7.4 stdlib-3.8 syntax_tools-2.1.7 tftp-1.0.1 tools-3.1 wx-1.8.7 xmerl-1.3.19 :
OTP-21.3 : common_test-1.17 compiler-7.3.2 crypto-4.4.1 dialyzer-3.3.2 diameter-2.2 edoc-0.10 erl_docgen-0.9 erl_interface-3.11 erts-10.3 ftp-1.0.2 hipe-3.18.3 inets-7.0.6 kernel-6.3 mnesia-4.15.6 observer-2.9 odbc-2.12.3 public_key-1.6.5 runtime_tools-1.13.2 ssh-4.7.4 ssl-9.2 stdlib-3.8 syntax_tools-2.1.7 tools-3.1 wx-1.8.7 # asn1-5.0.8 debugger-4.2.6 eldap-1.2.6 et-1.6.4 eunit-2.3.7 jinterface-1.9.1 megaco-3.18.4 os_mon-2.4.7 otp_mibs-1.2.1 parsetools-2.1.8 reltool-0.7.8 sasl-3.3 snmp-5.2.12 tftp-1.0.1 xmerl-1.3.19 :
OTP-21.2.7 : erts-10.2.5 kernel-6.2.1 # asn1-5.0.8 common_test-1.16.1 compiler-7.3.1 crypto-4.4 debugger-4.2.6 dialyzer-3.3.1 diameter-2.1.6 edoc-0.9.4 eldap-1.2.6 erl_docgen-0.8.1 erl_interface-3.10.4 et-1.6.4 eunit-2.3.7 ftp-1.0.1 hipe-3.18.2 inets-7.0.5 jinterface-1.9.1 megaco-3.18.4 mnesia-4.15.5 observer-2.8.2 odbc-2.12.2 os_mon-2.4.7 otp_mibs-1.2.1 parsetools-2.1.8 public_key-1.6.4 reltool-0.7.8 runtime_tools-1.13.1 sasl-3.3 snmp-5.2.12 ssh-4.7.3 ssl-9.1.2 stdlib-3.7.1 syntax_tools-2.1.6 tftp-1.0.1 tools-3.0.2 wx-1.8.6 xmerl-1.3.19 :