diff options
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 Binary files differindex b48d22fe41..5428e202e7 100644 --- a/bootstrap/bin/no_dot_erlang.boot +++ b/bootstrap/bin/no_dot_erlang.boot diff --git a/bootstrap/bin/start.boot b/bootstrap/bin/start.boot Binary files differindex b48d22fe41..5428e202e7 100644 --- a/bootstrap/bin/start.boot +++ b/bootstrap/bin/start.boot diff --git a/bootstrap/bin/start_clean.boot b/bootstrap/bin/start_clean.boot Binary files differindex b48d22fe41..5428e202e7 100644 --- a/bootstrap/bin/start_clean.boot +++ b/bootstrap/bin/start_clean.boot diff --git a/bootstrap/lib/compiler/ebin/beam_asm.beam b/bootstrap/lib/compiler/ebin/beam_asm.beam Binary files differindex 5c91f09b30..5dafb89f68 100644 --- a/bootstrap/lib/compiler/ebin/beam_asm.beam +++ b/bootstrap/lib/compiler/ebin/beam_asm.beam diff --git a/bootstrap/lib/compiler/ebin/beam_ssa_opt.beam b/bootstrap/lib/compiler/ebin/beam_ssa_opt.beam Binary files differindex 7b34cc5906..b1bd549a8a 100644 --- a/bootstrap/lib/compiler/ebin/beam_ssa_opt.beam +++ b/bootstrap/lib/compiler/ebin/beam_ssa_opt.beam diff --git a/bootstrap/lib/compiler/ebin/beam_validator.beam b/bootstrap/lib/compiler/ebin/beam_validator.beam Binary files differindex a5db96bdaf..71186a12cd 100644 --- a/bootstrap/lib/compiler/ebin/beam_validator.beam +++ b/bootstrap/lib/compiler/ebin/beam_validator.beam diff --git a/bootstrap/lib/compiler/ebin/compile.beam b/bootstrap/lib/compiler/ebin/compile.beam Binary files differindex 5829ab4867..57cfc6b932 100644 --- a/bootstrap/lib/compiler/ebin/compile.beam +++ b/bootstrap/lib/compiler/ebin/compile.beam 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 Binary files differindex 9db02f55fd..84c5b7636e 100644 --- a/bootstrap/lib/kernel/ebin/application.beam +++ b/bootstrap/lib/kernel/ebin/application.beam diff --git a/bootstrap/lib/kernel/ebin/application_controller.beam b/bootstrap/lib/kernel/ebin/application_controller.beam Binary files differindex 32612f1bf6..c33895a44e 100644 --- a/bootstrap/lib/kernel/ebin/application_controller.beam +++ b/bootstrap/lib/kernel/ebin/application_controller.beam diff --git a/bootstrap/lib/kernel/ebin/code_server.beam b/bootstrap/lib/kernel/ebin/code_server.beam Binary files differindex 6add687cf2..6cbda0c9bb 100644 --- a/bootstrap/lib/kernel/ebin/code_server.beam +++ b/bootstrap/lib/kernel/ebin/code_server.beam diff --git a/bootstrap/lib/kernel/ebin/global.beam b/bootstrap/lib/kernel/ebin/global.beam Binary files differindex f57cf03afd..f4ca5b8620 100644 --- a/bootstrap/lib/kernel/ebin/global.beam +++ b/bootstrap/lib/kernel/ebin/global.beam diff --git a/bootstrap/lib/kernel/ebin/hipe_unified_loader.beam b/bootstrap/lib/kernel/ebin/hipe_unified_loader.beam Binary files differindex fc80f2d1bd..9270358896 100644 --- a/bootstrap/lib/kernel/ebin/hipe_unified_loader.beam +++ b/bootstrap/lib/kernel/ebin/hipe_unified_loader.beam diff --git a/bootstrap/lib/kernel/ebin/inet_db.beam b/bootstrap/lib/kernel/ebin/inet_db.beam Binary files differindex 76d7ac2adb..e53e183312 100644 --- a/bootstrap/lib/kernel/ebin/inet_db.beam +++ b/bootstrap/lib/kernel/ebin/inet_db.beam 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 Binary files differindex 8f75029c0f..11be83a49e 100644 --- a/bootstrap/lib/kernel/ebin/kernel.beam +++ b/bootstrap/lib/kernel/ebin/kernel.beam diff --git a/bootstrap/lib/kernel/ebin/logger.beam b/bootstrap/lib/kernel/ebin/logger.beam Binary files differindex bd17885e22..1dc1c4fef4 100644 --- a/bootstrap/lib/kernel/ebin/logger.beam +++ b/bootstrap/lib/kernel/ebin/logger.beam diff --git a/bootstrap/lib/kernel/ebin/logger_formatter.beam b/bootstrap/lib/kernel/ebin/logger_formatter.beam Binary files differindex 83df11e66f..e3e40460f0 100644 --- a/bootstrap/lib/kernel/ebin/logger_formatter.beam +++ b/bootstrap/lib/kernel/ebin/logger_formatter.beam diff --git a/bootstrap/lib/kernel/ebin/logger_h_common.beam b/bootstrap/lib/kernel/ebin/logger_h_common.beam Binary files differindex 5e14216b5d..9e8c25b6b9 100644 --- a/bootstrap/lib/kernel/ebin/logger_h_common.beam +++ b/bootstrap/lib/kernel/ebin/logger_h_common.beam diff --git a/bootstrap/lib/kernel/ebin/logger_simple_h.beam b/bootstrap/lib/kernel/ebin/logger_simple_h.beam Binary files differindex 954bbdc071..583c77b290 100644 --- a/bootstrap/lib/kernel/ebin/logger_simple_h.beam +++ b/bootstrap/lib/kernel/ebin/logger_simple_h.beam diff --git a/bootstrap/lib/kernel/ebin/logger_std_h.beam b/bootstrap/lib/kernel/ebin/logger_std_h.beam Binary files differindex 3b5d3cd9f8..b0f56d9a62 100644 --- a/bootstrap/lib/kernel/ebin/logger_std_h.beam +++ b/bootstrap/lib/kernel/ebin/logger_std_h.beam diff --git a/bootstrap/lib/stdlib/ebin/array.beam b/bootstrap/lib/stdlib/ebin/array.beam Binary files differindex ac3193515c..9e783452f5 100644 --- a/bootstrap/lib/stdlib/ebin/array.beam +++ b/bootstrap/lib/stdlib/ebin/array.beam diff --git a/bootstrap/lib/stdlib/ebin/beam_lib.beam b/bootstrap/lib/stdlib/ebin/beam_lib.beam Binary files differindex c13a82a074..44d783a6d0 100644 --- a/bootstrap/lib/stdlib/ebin/beam_lib.beam +++ b/bootstrap/lib/stdlib/ebin/beam_lib.beam diff --git a/bootstrap/lib/stdlib/ebin/calendar.beam b/bootstrap/lib/stdlib/ebin/calendar.beam Binary files differindex d0abc17e48..89102adda8 100644 --- a/bootstrap/lib/stdlib/ebin/calendar.beam +++ b/bootstrap/lib/stdlib/ebin/calendar.beam diff --git a/bootstrap/lib/stdlib/ebin/io_lib_pretty.beam b/bootstrap/lib/stdlib/ebin/io_lib_pretty.beam Binary files differindex 7ffe569c60..ba644430da 100644 --- a/bootstrap/lib/stdlib/ebin/io_lib_pretty.beam +++ b/bootstrap/lib/stdlib/ebin/io_lib_pretty.beam 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 Binary files differindex da647da3ca..437f63357c 100644 --- a/bootstrap/lib/stdlib/ebin/string.beam +++ b/bootstrap/lib/stdlib/ebin/string.beam diff --git a/bootstrap/lib/stdlib/ebin/unicode_util.beam b/bootstrap/lib/stdlib/ebin/unicode_util.beam Binary files differindex 8ddf73ca26..c9db0483ca 100644 --- a/bootstrap/lib/stdlib/ebin/unicode_util.beam +++ b/bootstrap/lib/stdlib/ebin/unicode_util.beam 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 Binary files differindex 1b0cb5b50c..62dc8702e7 100644 --- a/erts/preloaded/ebin/erlang.beam +++ b/erts/preloaded/ebin/erlang.beam 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 : |