summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--erts/emulator/beam/erl_process.c2
-rw-r--r--erts/emulator/drivers/common/inet_drv.c7
-rw-r--r--erts/etc/win32/nsis/erlang20.nsi8
-rw-r--r--erts/etc/win32/wsl_tools/SetupWSLcross.bat10
-rw-r--r--lib/compiler/src/beam_ssa_bool.erl8
-rw-r--r--lib/compiler/test/guard_SUITE.erl25
-rw-r--r--lib/kernel/test/gen_sctp_SUITE.erl152
-rw-r--r--lib/kernel/test/gen_udp_SUITE.erl84
8 files changed, 265 insertions, 31 deletions
diff --git a/erts/emulator/beam/erl_process.c b/erts/emulator/beam/erl_process.c
index 0a1e274396..6c83693df8 100644
--- a/erts/emulator/beam/erl_process.c
+++ b/erts/emulator/beam/erl_process.c
@@ -11188,7 +11188,7 @@ erts_set_gc_state(Process *c_p, int enable)
first1 = dgc_tsk_qs->q[prio];
last1 = first1->prev;
first2 = stsk_qs->q[prio];
- last2 = first1->prev;
+ last2 = first2->prev;
last1->next = first2;
first2->prev = last1;
diff --git a/erts/emulator/drivers/common/inet_drv.c b/erts/emulator/drivers/common/inet_drv.c
index 42a5936513..6797b5d32f 100644
--- a/erts/emulator/drivers/common/inet_drv.c
+++ b/erts/emulator/drivers/common/inet_drv.c
@@ -12254,14 +12254,15 @@ static void packet_inet_stop(ErlDrvData e)
into "udp_descriptor*" or "inet_descriptor*":
*/
udp_descriptor * udesc = (udp_descriptor*) e;
- inet_descriptor* descr = INETP(udesc);
+ inet_descriptor* desc = INETP(udesc);
if (udesc->i_buf != NULL) {
release_buffer(udesc->i_buf);
udesc->i_buf = NULL;
}
- ASSERT(NO_SUBSCRIBERS(&(descr->empty_out_q_subs)));
- inet_stop(descr);
+ ASSERT(NO_SUBSCRIBERS(&(desc->empty_out_q_subs)));
+ async_error_am_all(desc, am_closed);
+ inet_stop(desc);
}
static int packet_error(udp_descriptor* udesc, int err)
diff --git a/erts/etc/win32/nsis/erlang20.nsi b/erts/etc/win32/nsis/erlang20.nsi
index 63e63a06cb..950f3ec0a3 100644
--- a/erts/etc/win32/nsis/erlang20.nsi
+++ b/erts/etc/win32/nsis/erlang20.nsi
@@ -52,7 +52,7 @@ Var STARTMENU_FOLDER
!define MY_STARTMENUPAGE_REGISTRY_VALUENAME "Start Menu Folder"
;General
- OutFile "${OUTFILEDIR}\otp_${WINTYPE}_${OTP_VERSION}.exe"
+ OutFile "${OUTFILEDIR}\otp_${WINTYPE}_${OTP_RELEASE_VERSION}.exe"
;Folder selection page
!if ${WINTYPE} == "win64"
@@ -68,7 +68,7 @@ Var STARTMENU_FOLDER
!if ${WINTYPE} == "win64"
!define MUI_STARTMENUPAGE_DEFAULTFOLDER "${OTP_PRODUCT} ${OTP_VERSION} (x64)"
!else
- !define MUI_STARTMENUPAGE_DEFAULTFOLDER "${OTP_PRODUCT} ${OTP_VERSION}"
+ !define MUI_STARTMENUPAGE_DEFAULTFOLDER "${OTP_PRODUCT} ${OTP_VERSION} (i386)"
!endif
;--------------------------------
@@ -201,7 +201,7 @@ done_startmenu:
WriteRegStr HKLM \
"SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\Erlang OTP ${OTP_VERSION} (${ERTS_VERSION})" \
- "DisplayName" "Erlang OTP ${OTP_VERSION} (${ERTS_VERSION})"
+ "DisplayName" "Erlang OTP ${OTP_RELEASE_VERSION} (${ERTS_VERSION})"
WriteRegStr HKLM \
"SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\Erlang OTP ${OTP_VERSION} (${ERTS_VERSION})" \
"UninstallString" "$INSTDIR\Uninstall.exe"
@@ -225,7 +225,7 @@ done_startmenu:
WriteRegStr HKCU \
"Software\Microsoft\Windows\CurrentVersion\Uninstall\Erlang OTP ${OTP_VERSION} (${ERTS_VERSION})" \
- "DisplayName" "Erlang OTP ${OTP_VERSION} (${ERTS_VERSION})"
+ "DisplayName" "Erlang OTP ${OTP_RELEASE_VERSION} (${ERTS_VERSION})"
WriteRegStr HKCU \
"Software\Microsoft\Windows\CurrentVersion\Uninstall\Erlang OTP ${OTP_VERSION} (${ERTS_VERSION})" \
"UninstallString" "$INSTDIR\Uninstall.exe"
diff --git a/erts/etc/win32/wsl_tools/SetupWSLcross.bat b/erts/etc/win32/wsl_tools/SetupWSLcross.bat
index 860a7d5e60..5de4cd8bb1 100644
--- a/erts/etc/win32/wsl_tools/SetupWSLcross.bat
+++ b/erts/etc/win32/wsl_tools/SetupWSLcross.bat
@@ -8,11 +8,6 @@ IF "%~1"=="x64" GOTO search
GOTO badarg
:search
-IF EXIST "C:\Program Files (x86)\Microsoft Visual Studio 12.0\VC\vcvarsall.bat". (
- call "C:\Program Files (x86)\Microsoft Visual Studio 12.0\VC\vcvarsall.bat" %~1 > nul
- goto continue
-)
-
IF EXIST "C:\Program Files (x86)\Microsoft Visual Studio\2019\BuildTools\VC\Auxiliary\Build\vcvarsall.bat". (
call "C:\Program Files (x86)\Microsoft Visual Studio\2019\BuildTools\VC\Auxiliary\Build\vcvarsall.bat" %~1 > nul
goto continue
@@ -33,6 +28,11 @@ IF EXIST "C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\vcvarsall.bat".
goto continue
)
+IF EXIST "C:\Program Files (x86)\Microsoft Visual Studio 12.0\VC\vcvarsall.bat". (
+ call "C:\Program Files (x86)\Microsoft Visual Studio 12.0\VC\vcvarsall.bat" %~1 > nul
+ goto continue
+)
+
GOTO no_vcvars
:continue
diff --git a/lib/compiler/src/beam_ssa_bool.erl b/lib/compiler/src/beam_ssa_bool.erl
index 2a3f093f14..5b81ca2be1 100644
--- a/lib/compiler/src/beam_ssa_bool.erl
+++ b/lib/compiler/src/beam_ssa_bool.erl
@@ -922,9 +922,11 @@ opt_digraph_instr(#b_set{dst=Dst}=I, G0, St) ->
%% Rewriting 'xor' is not practical. Fortunately,
%% 'xor' is almost never used in practice.
not_possible();
- #b_set{op={bif,'not'},args=[#b_var{}=Bool]} ->
- G = convert_to_br_node(I, Fail, G1, St),
- redirect_test(Bool, {fail,Succ}, G, St);
+ #b_set{op={bif,'not'}} ->
+ %% This is suprisingly rare. The previous attempt to
+ %% optimize it was broken, which wasn't noticed because
+ %% very few test cases triggered this code.
+ not_possible();
#b_set{op=phi,dst=Bool} ->
Vtx = get_vertex(Bool, St),
G2 = del_out_edges(Vtx, G1),
diff --git a/lib/compiler/test/guard_SUITE.erl b/lib/compiler/test/guard_SUITE.erl
index 178e74a3e8..2c935c1c57 100644
--- a/lib/compiler/test/guard_SUITE.erl
+++ b/lib/compiler/test/guard_SUITE.erl
@@ -2301,6 +2301,7 @@ beam_bool_SUITE(_Config) ->
recv_semi(),
andalso_repeated_var(),
erl1253(),
+ erl1246(),
ok.
before_and_inside_if() ->
@@ -2598,6 +2599,30 @@ andalso_repeated_var() ->
andalso_repeated_var(B) when B andalso B -> ok;
andalso_repeated_var(_) -> error.
+-record(erl1246, {tran_stat = 0}).
+
+erl1246() ->
+ false = erl1246(#erl1246{tran_stat = 0}, #{cid => 1131}),
+ false = erl1246(#erl1246{tran_stat = 12}, #{cid => 1131}),
+ false = erl1246(#erl1246{tran_stat = 12}, #{cid => 9502}),
+ true = erl1246(#erl1246{tran_stat = 0}, #{cid => 9502}),
+ ok.
+
+erl1246(Rec, #{cid := CollID}) ->
+ {GiftCollID, _} = erl1246_conf(gift_coll),
+ IsTranStat = Rec#erl1246.tran_stat =:= erl1246_conf(transform_id),
+ if
+ %% Optimization of 'not' in a guard was broken.
+ CollID =:= GiftCollID andalso not IsTranStat ->
+ true;
+ true ->
+ false
+ end.
+
+erl1246_conf(gift_coll) -> {9502, {112, 45}};
+erl1246_conf(transform_id) -> 12;
+erl1246_conf(_) -> undefined.
+
erl1253() ->
ok = erl1253_orelse_false(a, a, any),
ok = erl1253_orelse_false(a, a, true),
diff --git a/lib/kernel/test/gen_sctp_SUITE.erl b/lib/kernel/test/gen_sctp_SUITE.erl
index 65183d83cc..55109a5178 100644
--- a/lib/kernel/test/gen_sctp_SUITE.erl
+++ b/lib/kernel/test/gen_sctp_SUITE.erl
@@ -41,7 +41,8 @@
peeloff_active_once/1, peeloff_active_true/1, peeloff_active_n/1,
buffers/1,
names_unihoming_ipv4/1, names_unihoming_ipv6/1,
- names_multihoming_ipv4/1, names_multihoming_ipv6/1]).
+ names_multihoming_ipv4/1, names_multihoming_ipv6/1,
+ recv_close/1]).
suite() ->
[{ct_hooks,[ts_install_cth]},
@@ -56,10 +57,25 @@ all() ->
{group,G}].
groups() ->
- [{smoke,[],[basic,basic_stream]},
- {old_solaris,[],[skip_old_solaris]},
- {extensive,[],
- [api_open_close, api_listen, api_connect_init,
+ [
+ {smoke, [], smoke_cases()},
+ {old_solaris, [], old_solaris_cases()},
+ {extensive, [], extensive_cases()}
+ ].
+
+smoke_cases() ->
+ [
+ basic,
+ basic_stream
+ ].
+
+old_solaris_cases() ->
+ [
+ skip_old_solaris
+ ].
+
+extensive_cases() ->
+ [api_open_close, api_listen, api_connect_init,
api_opts, xfer_min, xfer_active, def_sndrcvinfo, implicit_inet6,
open_multihoming_ipv4_socket,
open_unihoming_ipv6_socket,
@@ -68,7 +84,8 @@ groups() ->
xfer_stream_min, peeloff_active_once,
peeloff_active_true, peeloff_active_n, buffers,
names_unihoming_ipv4, names_unihoming_ipv6,
- names_multihoming_ipv4, names_multihoming_ipv6]}].
+ names_multihoming_ipv4, names_multihoming_ipv6,
+ recv_close].
init_per_suite(_Config) ->
case gen_sctp:open() of
@@ -1511,6 +1528,111 @@ recv_comm_up_eventually(S) ->
recv_comm_up_eventually(S)
end.
+
+%%
+recv_close(Config) when is_list(Config) ->
+ p("create server socket (and listen)"),
+ {ok, S} = gen_sctp:open(),
+ gen_sctp:listen(S, true),
+ {ok, SPort} = inet:port(S),
+
+ p("create client socket (and connect)"),
+ {ok, C} = gen_sctp:open(),
+ {ok, _} = gen_sctp:connect(C, localhost, SPort, []),
+
+ TC = self(),
+ RECV = fun() ->
+ p("try setup recv(s)"),
+ ok = recv_close_setup_recv(S),
+ p("announce ready"),
+ TC ! {self(), ready},
+ p("try data recv"),
+ Res = gen_sctp:recv(S),
+ p("recv res: "
+ "~n ~p", [Res]),
+ exit(Res)
+ end,
+ p("spawn reader - then await reader ready"),
+ {Pid, MRef} = spawn_monitor(RECV),
+ receive
+ {'DOWN', MRef, process, Pid, PreReason} ->
+ %% Make sure it does not die for some other reason...
+ p("unexpected reader termination:"
+ "~n ~p", [PreReason]),
+ (catch gen_sctp:close(S)),
+ (catch gen_sctp:close(C)),
+ ?line ct:fail("Unexpected pre close from reader (~p): ~p",
+ [Pid, PreReason]);
+ {Pid, ready} ->
+ p("reader ready"),
+ ok
+ after 30000 -> % Just in case...
+ %% This is **extreme**, but there is no way to know
+ %% how long it will take to iterate through all the
+ %% addresses of a host...
+ p("reader ready timeout"),
+ (catch gen_sctp:close(S)),
+ (catch gen_sctp:close(C)),
+ ?line ct:fail("Unexpected pre close timeout (~p)", [Pid])
+ end,
+
+ p("\"ensure\" reader reading..."),
+ receive
+ Any ->
+ p("Received unexpected message: "
+ "~n ~p", [Any]),
+ (catch gen_sctp:close(S)),
+ (catch gen_sctp:close(C)),
+ ?line ct:fail("Unexpected message: ~p", [Any])
+ after 5000 ->
+ ok
+ end,
+
+ p("close server socket"),
+ ok = gen_sctp:close(S),
+ p("await reader termination"),
+ receive
+ {'DOWN', MRef, process, Pid, {error, closed}} ->
+ p("expected reader termination result"),
+ (catch gen_sctp:close(C)),
+ ok;
+ {'DOWN', MRef, process, Pid, PostReason} ->
+ p("unexpected reader termination: "
+ "~n ~p", [PostReason]),
+ (catch gen_sctp:close(C)),
+ ?line ct:fail("Unexpected post close from reader (~p): ~p",
+ [Pid, PostReason])
+ after 5000 ->
+ p("unexpected reader termination timeout"),
+ demonitor(MRef, [flush]),
+ (catch gen_sctp:close(C)),
+ exit(Pid, kill),
+ ?line ct:fail("Reader (~p) termination timeout", [Pid])
+ end,
+ p("close client socket"),
+ (catch gen_sctp:close(C)),
+ p("done"),
+ ok.
+
+
+recv_close_setup_recv(S) ->
+ recv_close_setup_recv(S, 1).
+
+recv_close_setup_recv(S, N) ->
+ p("try setup recv ~w", [N]),
+ case gen_sctp:recv(S, 5000) of
+ {ok, {Addr,
+ Port,
+ _AncData,
+ Data}} when is_tuple(Addr) andalso is_integer(Port) ->
+ p("setup recv ~w: "
+ "~n ~p", [N, Data]),
+ recv_close_setup_recv(S, N+1);
+ {error, timeout} ->
+ ok
+ end.
+
+
%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%% socket gen_server ultra light
@@ -1745,3 +1867,21 @@ match_unless_solaris(A, B) ->
timestamp() ->
erlang:monotonic_time().
+
+formated_timestamp() ->
+ format_timestamp(os:timestamp()).
+
+format_timestamp({_N1, _N2, N3} = TS) ->
+ {_Date, Time} = calendar:now_to_local_time(TS),
+ {Hour, Min, Sec} = Time,
+ FormatTS = io_lib:format("~.2.0w:~.2.0w:~.2.0w.~.3.0w",
+ [Hour, Min, Sec, N3 div 1000]),
+ lists:flatten(FormatTS).
+
+p(F) ->
+ p(F, []).
+
+p(F, A) ->
+ io:format("~s ~p " ++ F ++ "~n", [formated_timestamp(), self() | A]).
+
+
diff --git a/lib/kernel/test/gen_udp_SUITE.erl b/lib/kernel/test/gen_udp_SUITE.erl
index 2720d3cc77..7ec553ec51 100644
--- a/lib/kernel/test/gen_udp_SUITE.erl
+++ b/lib/kernel/test/gen_udp_SUITE.erl
@@ -40,25 +40,45 @@
recvtos/1, recvtosttl/1, recvttl/1, recvtclass/1,
sendtos/1, sendtosttl/1, sendttl/1, sendtclass/1,
local_basic/1, local_unbound/1,
- local_fdopen/1, local_fdopen_unbound/1, local_abstract/1]).
+ local_fdopen/1, local_fdopen_unbound/1, local_abstract/1,
+ recv_close/1]).
suite() ->
[{ct_hooks,[ts_install_cth]},
{timetrap,{minutes,1}}].
all() ->
- [send_to_closed, buffer_size, binary_passive_recv, max_buffer_size,
- bad_address, read_packets, recv_poll_after_active_once,
- open_fd, connect,
- implicit_inet6, active_n,
+ [
+ send_to_closed,
+ buffer_size,
+ binary_passive_recv,
+ max_buffer_size,
+ bad_address,
+ read_packets,
+ recv_poll_after_active_once,
+ open_fd,
+ connect,
+ implicit_inet6,
+ active_n,
recvtos, recvtosttl, recvttl, recvtclass,
sendtos, sendtosttl, sendttl, sendtclass,
- {group, local}].
+ {group, local},
+ recv_close
+ ].
groups() ->
- [{local, [],
- [local_basic, local_unbound,
- local_fdopen, local_fdopen_unbound, local_abstract]}].
+ [
+ {local, [], local_cases()}
+ ].
+
+local_cases() ->
+ [
+ local_basic,
+ local_unbound,
+ local_fdopen,
+ local_fdopen_unbound,
+ local_abstract
+ ].
init_per_suite(Config) ->
Config.
@@ -969,6 +989,52 @@ local_handshake(S, SAddr, C, CAddr) ->
end.
+
+
+%%-------------------------------------------------------------
+%% Open a passive socket. Create a socket that reads from it.
+%% Then close the socket.
+recv_close(Config) when is_list(Config) ->
+ {ok, Sock} = gen_udp:open(0, [{active, false}]),
+ RECV = fun() ->
+ io:format("~p try recv~n", [self()]),
+ Res = gen_udp:recv(Sock, 0),
+ io:format("~p recv res: ~p~n", [self(), Res]),
+ exit(Res)
+ end,
+ io:format("~p spawn reader", [self()]),
+ {Pid, MRef} = spawn_monitor(RECV),
+ receive
+ {'DOWN', MRef, process, Pid, PreReason} ->
+ %% Make sure id does not die for some other reason...
+ ?line ct:fail("Unexpected pre close from reader (~p): ~p",
+ [Pid, PreReason])
+ after 5000 -> % Just in case...
+ ok
+ end,
+ io:format("~p close socket", [self()]),
+ ok = gen_udp:close(Sock),
+ io:format("~p await reader termination", [self()]),
+ receive
+ {'DOWN', MRef, process, Pid, {error, closed}} ->
+ io:format("~p expected reader termination result", [self()]),
+ ok;
+ {'DOWN', MRef, process, Pid, PostReason} ->
+ io:format("~p unexpected reader termination: ~p",
+ [self(), PostReason]),
+ ?line ct:fail("Unexpected post close from reader (~p): ~p",
+ [Pid, PostReason])
+ after 5000 ->
+ io:format("~p unexpected reader termination timeout", [self()]),
+ demonitor(MRef, [flush]),
+ exit(Pid, kill),
+ ?line ct:fail("Reader (~p) termination timeout", [Pid])
+ end,
+ ok.
+
+
+
+
%%
%% Utils
%%